This commit is contained in:
Bernie White 2020-10-24 22:45:23 +10:00 коммит произвёл GitHub
Родитель 9fe6559d8e
Коммит d56b93842f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
35 изменённых файлов: 166 добавлений и 56 удалений

Просмотреть файл

@ -0,0 +1,24 @@
``` ini
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-1065G7 CPU 1.30GHz, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.403
[Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
DefaultJob : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
```
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|------------------------- |-------------:|------------:|------------:|-----------:|---------:|------:|------------:|
| Invoke | 41,409.3 μs | 743.11 μs | 1,089.24 μs | 3916.6667 | 500.0000 | - | 16124.02 KB |
| InvokeIf | 43,138.3 μs | 510.44 μs | 426.24 μs | 4416.6667 | 83.3333 | - | 18374.86 KB |
| InvokeType | 41,511.3 μs | 703.93 μs | 963.55 μs | 3923.0769 | 230.7692 | - | 16144.62 KB |
| InvokeSummary | 40,319.9 μs | 795.95 μs | 705.59 μs | 3900.0000 | 500.0000 | - | 16124.26 KB |
| Get | 9,873.7 μs | 392.08 μs | 1,149.89 μs | 46.8750 | - | - | 253.44 KB |
| GetHelp | 9,943.1 μs | 406.36 μs | 1,198.17 μs | 46.8750 | - | - | 251.84 KB |
| Within | 76,627.6 μs | 1,527.91 μs | 1,759.54 μs | 7800.0000 | - | - | 32460.47 KB |
| WithinBulk | 115,374.0 μs | 2,279.41 μs | 3,269.07 μs | 14333.3333 | - | - | 59488.54 KB |
| WithinLike | 102,684.3 μs | 1,482.11 μs | 1,313.85 μs | 11500.0000 | 750.0000 | - | 46983.1 KB |
| DefaultTargetNameBinding | 673.8 μs | 4.27 μs | 3.79 μs | 38.0859 | - | - | 156.25 KB |
| CustomTargetNameBinding | 888.9 μs | 15.31 μs | 12.78 μs | 85.9375 | - | - | 351.56 KB |
| NestedTargetNameBinding | 901.3 μs | 9.04 μs | 8.01 μs | 85.9375 | - | - | 351.56 KB |

Просмотреть файл

@ -0,0 +1,26 @@
``` ini
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
Intel Core i7-1065G7 CPU 1.30GHz, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.403
[Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
DefaultJob : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
```
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|------------------------- |-------------:|------------:|------------:|-----------:|---------:|------:|------------:|
| Invoke | 40,804.1 μs | 656.89 μs | 614.45 μs | 3916.6667 | 500.0000 | - | 16124.02 KB |
| InvokeIf | 42,768.8 μs | 843.79 μs | 704.61 μs | 4461.5385 | 76.9231 | - | 18374.92 KB |
| InvokeType | 40,487.0 μs | 609.33 μs | 1,034.69 μs | 3923.0769 | 538.4615 | - | 16124.02 KB |
| InvokeSummary | 40,403.1 μs | 806.53 μs | 714.97 μs | 3923.0769 | 538.4615 | - | 16124.26 KB |
| Assert | 41,551.0 μs | 684.23 μs | 640.03 μs | 4000.0000 | 153.8462 | - | 16538.36 KB |
| Get | 10,180.9 μs | 402.29 μs | 1,186.17 μs | 46.8750 | - | - | 231.12 KB |
| GetHelp | 9,941.1 μs | 409.65 μs | 1,207.87 μs | 46.8750 | - | - | 229.52 KB |
| Within | 75,818.3 μs | 1,504.74 μs | 2,297.90 μs | 7800.0000 | 600.0000 | - | 32468.28 KB |
| WithinBulk | 112,731.0 μs | 1,239.66 μs | 1,035.17 μs | 14333.3333 | 666.6667 | - | 59496.35 KB |
| WithinLike | 101,227.7 μs | 1,990.03 μs | 2,854.05 μs | 11333.3333 | - | - | 46623.62 KB |
| DefaultTargetNameBinding | 654.3 μs | 10.46 μs | 9.78 μs | 38.0859 | - | - | 156.25 KB |
| CustomTargetNameBinding | 854.3 μs | 16.30 μs | 15.25 μs | 85.9375 | - | - | 351.56 KB |
| NestedTargetNameBinding | 945.7 μs | 18.78 μs | 19.29 μs | 85.9375 | - | - | 351.57 KB |
| AssertHasFieldValue | 1,036.2 μs | 13.63 μs | 12.08 μs | 121.0938 | - | - | 500 KB |

Просмотреть файл

@ -0,0 +1,11 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# A set of benchmark rules for testing PSRule performance
#
# Synopsis: A rule for testing PSRule performance
Rule 'Assert.HasFieldValue' {
$Assert.HasFieldValue($TargetObject, 'value', 'Microsoft.Compute/virtualMachines');
}

Просмотреть файл

@ -7,12 +7,12 @@
# Description: A rule for testing PSRule performance
Rule 'BenchmarkWithin' {
Within 'Value' 'Microsoft.Compute/virtualMachines', 'Microsoft.Sql/servers/databases'
Within 'Value' 'Microsoft.Compute/virtualMachines', 'Microsoft.Sql/servers/databases'
}
Rule 'BenchmarkWithinBulk' {
Within 'Value' @(
# Compute: Virtual machines
Within 'Value' @(
# Compute: Virtual machines
'Microsoft.Compute/virtualMachines'
'Microsoft.Compute/virtualMachineScaleSets'
'Microsoft.Compute/virtualMachineScaleSets/virtualmachines'
@ -105,12 +105,12 @@ Rule 'BenchmarkWithinBulk' {
'Microsoft.Sql/servers/databases/backupShortTermRetentionPolicies'
'Microsoft.Sql/servers/databases/connectionPolicies'
'Microsoft.Sql/servers/databases/dataMaskingPolicies'
)
)
}
Rule 'BenchmarkWithinLike' {
Within 'Value' -Like @(
# Compute: Virtual machines
Within 'Value' -Like @(
# Compute: Virtual machines
'Microsoft.Compute/virtualMachines'
'Microsoft.Compute/virtualMachineScaleSets'
'Microsoft.Compute/virtualMachineScaleSets/virtualmachines'
@ -162,5 +162,5 @@ Rule 'BenchmarkWithinLike' {
# Databases: SQL Database
'Microsoft.Sql/servers'
'Microsoft.Sql/servers/*'
)
)
}

Просмотреть файл

@ -33,6 +33,9 @@
</ItemGroup>
<ItemGroup>
<None Update="Benchmark.Assert.Rule.ps1">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Benchmark.Rule.ps1">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Просмотреть файл

@ -37,6 +37,8 @@ namespace PSRule.Benchmark
public class PSRule
{
private PSObject[] _TargetObject;
private IPipeline _AssertPipeline;
private IPipeline _AssertHasFieldValuePipeline;
private IPipeline _GetPipeline;
private IPipeline _GetHelpPipeline;
private IPipeline _InvokePipeline;
@ -56,10 +58,12 @@ namespace PSRule.Benchmark
PrepareInvokeIfPipeline();
PrepareInvokeTypePipeline();
PrepareInvokeSummaryPipeline();
PrepareAssertPipeline();
PrepareInvokeWithinPipeline();
PrepareInvokeWithinBulkPipeline();
PrepareInvokeWithinLikePipeline();
PrepareTargetObjects();
PrepareAssertHasFieldValuePipeline();
}
private void PrepareGetPipeline()
@ -112,6 +116,14 @@ namespace PSRule.Benchmark
_InvokeSummaryPipeline = builder.Build();
}
private void PrepareAssertPipeline()
{
var option = new PSRuleOption();
option.Rule.Include = new string[] { "Benchmark" };
var builder = PipelineBuilder.Assert(GetSource(), option, null, null);
_AssertPipeline = builder.Build();
}
private void PrepareInvokeWithinPipeline()
{
var option = new PSRuleOption();
@ -136,6 +148,14 @@ namespace PSRule.Benchmark
_InvokeWithinLikePipeline = builder.Build();
}
private void PrepareAssertHasFieldValuePipeline()
{
var option = new PSRuleOption();
option.Rule.Include = new string[] { "Assert.HasFieldValue" };
var builder = PipelineBuilder.Invoke(GetSource(), option, null, null);
_AssertHasFieldValuePipeline = builder.Build();
}
private Source[] GetSource()
{
var builder = new RuleSourceBuilder(null);
@ -167,7 +187,6 @@ namespace PSRule.Benchmark
var o = new TargetObject(name: targetObjects.Count.ToString(), message: Convert.ToBase64String(randomBuffer), value: value);
targetObjects.Add(PSObject.AsPSObject(o));
}
_TargetObject = targetObjects.ToArray();
}
@ -183,6 +202,9 @@ namespace PSRule.Benchmark
[Benchmark]
public void InvokeSummary() => RunPipelineTargets(_InvokeSummaryPipeline);
[Benchmark]
public void Assert() => RunPipelineTargets(_AssertPipeline);
[Benchmark]
public void Get() => RunPipelineNull(_GetPipeline);
@ -233,6 +255,9 @@ namespace PSRule.Benchmark
}
}
[Benchmark]
public void AssertHasFieldValue() => RunPipelineTargets(_AssertHasFieldValuePipeline);
private void RunPipelineNull(IPipeline pipeline)
{
pipeline.Begin();

Просмотреть файл

@ -111,6 +111,10 @@ namespace PSRule.Benchmark
for (var i = 0; i < DebugIterations; i++)
profile.InvokeSummary();
ProfileBlock();
for (var i = 0; i < DebugIterations; i++)
profile.Assert();
ProfileBlock();
for (var i = 0; i < DebugIterations; i++)
profile.Get();
@ -126,6 +130,10 @@ namespace PSRule.Benchmark
ProfileBlock();
for (var i = 0; i < DebugIterations; i++)
profile.NestedTargetNameBinding();
ProfileBlock();
for (var i = 0; i < DebugIterations; i++)
profile.AssertHasFieldValue();
}
[DebuggerStepThrough]

Просмотреть файл

@ -61,7 +61,7 @@ namespace PSRule
private static T ConvertValue<T>(object value)
{
if (value == null)
return default(T);
return default;
return typeof(T).IsValueType ? (T)Convert.ChangeType(value, typeof(T)) : (T)value;
}

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Configuration
/// The formats to convert input from.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum InputFormat : byte
public enum InputFormat
{
None = 0,

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Configuration
/// The PowerShell informational stream to log specific outcomes to.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum OutcomeLogStream : byte
public enum OutcomeLogStream
{
/// <summary>
/// Outcomes will not be logged to an informational stream.

Просмотреть файл

@ -7,7 +7,7 @@ using Newtonsoft.Json.Converters;
namespace PSRule.Configuration
{
[JsonConverter(typeof(StringEnumConverter))]
public enum OutputEncoding : byte
public enum OutputEncoding
{
Default = 0,

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Configuration
/// The formats to return results in.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum OutputFormat : byte
public enum OutputFormat
{
None = 0,

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Configuration
/// The style to present assert output in.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum OutputStyle : byte
public enum OutputStyle
{
/// <summary>
/// Formatted text written to host.

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Configuration
/// The format to return to the pipeline after executing rules.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum ResultFormat : byte
public enum ResultFormat
{
Detail = 1,

Просмотреть файл

@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace PSRule.Definitions
{
public enum ResourceKind : byte
public enum ResourceKind
{
None = 0,

Просмотреть файл

@ -84,10 +84,10 @@ namespace PSRule.Definitions
if (i > 0)
sb.Append(Environment.NewLine);
sb.Append(kv.Key.ToString());
sb.Append(kv.Key);
sb.Append('=');
sb.Append('\'');
sb.Append(kv.Value.ToString());
sb.Append(kv.Value);
sb.Append('\'');
i++;
}

Просмотреть файл

@ -29,7 +29,7 @@ namespace PSRule.Host
}
}
public enum DependencyTargetState : byte
public enum DependencyTargetState
{
None = 0,

Просмотреть файл

@ -3,7 +3,7 @@
namespace PSRule.Host
{
public enum LanguageBlockKind : byte
public enum LanguageBlockKind
{
Unknown = 0,

Просмотреть файл

@ -8,6 +8,8 @@ namespace PSRule.Parser
{
internal abstract class MarkdownLexer
{
protected MarkdownLexer() { }
protected static bool IsHeading(MarkdownToken token, int level)
{
return token.Type == MarkdownTokenType.Header &&

Просмотреть файл

@ -6,7 +6,7 @@ using System.Diagnostics;
namespace PSRule.Parser
{
public enum MarkdownTokenType : byte
public enum MarkdownTokenType
{
None = 0,

Просмотреть файл

@ -7,6 +7,8 @@ namespace PSRule.Parser
{
internal sealed class MetadataLexer : MarkdownLexer
{
public MetadataLexer() { }
public Dictionary<string, string> Process(TokenStream stream)
{
// Look for yaml header

Просмотреть файл

@ -20,10 +20,7 @@ namespace PSRule.Parser
private const string Space = " ";
public RuleLexer()
{
// Do nothing
}
public RuleLexer() { }
public RuleDocument Process(TokenStream stream)
{

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Parser
/// Define options that determine how markdown will be rendered.
/// </summary>
[Flags()]
internal enum FormatOptions : byte
internal enum FormatOptions
{
None = 0,

Просмотреть файл

@ -132,7 +132,9 @@ namespace PSRule.Pipeline
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null) throw new ArgumentNullException("info");
if (info == null)
throw new ArgumentNullException(nameof(info));
base.GetObjectData(info, context);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace PSRule.Pipeline
{
internal enum ExecutionScope : byte
internal enum ExecutionScope
{
None = 0,

Просмотреть файл

@ -8,6 +8,7 @@ using PSRule.Rules;
using System;
using System.Diagnostics;
using System.Management.Automation;
using System.Threading;
namespace PSRule.Pipeline
{
@ -99,7 +100,7 @@ namespace PSRule.Pipeline
private bool TryConstrained(string uri)
{
base.WriteObject(string.Format(PSRuleResources.LaunchBrowser, uri), false);
base.WriteObject(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.LaunchBrowser, uri), false);
return true;
}
@ -109,9 +110,16 @@ namespace PSRule.Pipeline
return false;
var browser = new Process();
browser.StartInfo.FileName = uri;
browser.StartInfo.UseShellExecute = true;
return browser.Start();
try
{
browser.StartInfo.FileName = uri;
browser.StartInfo.UseShellExecute = true;
return browser.Start();
}
finally
{
browser.Dispose();
}
}
private void WriteHelpInfo(object o, string typeName)

Просмотреть файл

@ -52,7 +52,7 @@ namespace PSRule.Pipeline
_DefaultCulture = GetDefaultCulture();
}
internal enum ScopeType : byte
internal enum ScopeType
{
Parameter = 0,
Explicit = 1,

Просмотреть файл

@ -351,7 +351,7 @@ namespace PSRule.Pipeline
category: category,
positionMessage: GetPositionMessage(errorRecord),
scriptExtent: GetErrorScriptExtent(errorRecord)
); ;
);
}
public void Error(ErrorRecord error)
@ -370,7 +370,7 @@ namespace PSRule.Pipeline
category: error.CategoryInfo.Category,
positionMessage: GetPositionMessage(error),
scriptExtent: GetErrorScriptExtent(error)
); ;
);
}
private string GetStackTrace(ErrorRecord record)
@ -444,7 +444,7 @@ namespace PSRule.Pipeline
internal SourceScope EnterSourceScope(SourceFile source)
{
if (!File.Exists(source.Path))
if (!source.Exists())
throw new FileNotFoundException(PSRuleResources.ScriptNotFound, source.Path);
if (Source != null && Source.File == source)

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Rules
/// The outcome of a rule.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum RuleOutcome : byte
public enum RuleOutcome
{
/// <summary>
/// The rule was not evaluated.

Просмотреть файл

@ -10,7 +10,7 @@ namespace PSRule.Rules
/// The reason for the outcome of a rule.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum RuleOutcomeReason : byte
public enum RuleOutcomeReason
{
/// <summary>
/// A reason was not specified.

Просмотреть файл

@ -13,7 +13,7 @@ using System.Threading;
namespace PSRule.Rules
{
public enum RuleSourceType : byte
public enum RuleSourceType
{
Script = 1,
@ -26,6 +26,8 @@ namespace PSRule.Rules
[DebuggerDisplay("{Type}: {Path}")]
public sealed class SourceFile
{
private bool? _Exists;
public readonly string Path;
public readonly string ModuleName;
public readonly RuleSourceType Type;
@ -38,6 +40,14 @@ namespace PSRule.Rules
Type = type;
HelpPath = helpPath;
}
internal bool Exists()
{
if (!_Exists.HasValue)
_Exists = File.Exists(Path);
return _Exists.Value;
}
}
public sealed class Source

Просмотреть файл

@ -5,6 +5,7 @@ using PSRule.Configuration;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace PSRule.Rules
{
@ -37,9 +38,7 @@ namespace PSRule.Rules
public SuppressionKey(string ruleName, string targetName)
{
if (string.IsNullOrEmpty(ruleName) || string.IsNullOrEmpty(targetName))
{
throw new ArgumentNullException();
}
RuleName = ruleName;
TargetName = targetName;
@ -57,7 +56,6 @@ namespace PSRule.Rules
return false;
var k2 = obj as SuppressionKey;
return HashCode == k2.HashCode &&
StringComparer.OrdinalIgnoreCase.Equals(TargetName, k2.TargetName) &&
StringComparer.OrdinalIgnoreCase.Equals(RuleName, k2.RuleName);
@ -65,9 +63,8 @@ namespace PSRule.Rules
private int CombineHashCode()
{
var h1 = RuleName.ToUpper().GetHashCode();
var h2 = TargetName.ToUpper().GetHashCode();
var h1 = RuleName.ToUpper(Thread.CurrentThread.CurrentCulture).GetHashCode();
var h2 = TargetName.ToUpper(Thread.CurrentThread.CurrentCulture).GetHashCode();
unchecked
{
// Get combined hash code for key
@ -80,9 +77,7 @@ namespace PSRule.Rules
public bool Match(string ruleName, string targetName)
{
if (_IsEmpty || string.IsNullOrEmpty(ruleName) || string.IsNullOrEmpty(targetName))
{
return false;
}
return _Index.Contains(new SuppressionKey(ruleName, targetName));
}
@ -95,11 +90,8 @@ namespace PSRule.Rules
foreach (var targetName in rule.Value.TargetName)
{
var key = new SuppressionKey(rule.Key, targetName);
if (!_Index.Contains(key))
{
_Index.Add(key);
}
}
}
}

Просмотреть файл

@ -34,7 +34,7 @@ namespace PSRule.Runtime
internal AssertResult Create(bool condition, string reason, object[] args)
{
if (!(PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Condition || PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Precondition))
throw new RuleException(string.Format(PSRuleResources.VariableConditionScope, "Assert"));
throw new RuleException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.VariableConditionScope, "Assert"));
return new AssertResult(this, condition, reason, args);
}
@ -401,7 +401,7 @@ namespace PSRule.Runtime
for (var i = 0; i < values.Length; i++)
{
if (AnyValue(fieldValue, values.GetValue(i), caseSensitive, out object foundValue))
if (AnyValue(fieldValue, values.GetValue(i), caseSensitive, out object _))
return Pass();
}
return Fail(ReasonStrings.In, fieldValue);
@ -818,7 +818,7 @@ namespace PSRule.Runtime
/// </summary>
private static bool TryPipelineCache<T>(string prefix, string key, out T value)
{
value = default(T);
value = default;
if (PipelineContext.CurrentThread.ExpressionCache.TryGetValue(string.Concat(prefix, key), out object ovalue))
{
value = (T)ovalue;

Просмотреть файл

@ -25,8 +25,8 @@ namespace PSRule.Runtime
private readonly string Name;
private readonly int Last;
private bool inQuote = false;
private bool inIndex = false;
private bool inQuote;
private bool inIndex;
public int Position = -1;
public char Current;

Просмотреть файл

@ -25,7 +25,7 @@ namespace PSRule.Runtime
private const char ZERO = '0';
[Flags]
internal enum CompareFlag : byte
internal enum CompareFlag
{
None = 0,