Skip to content

Commit

Permalink
Allow customizing CultureInfo, fix #1295
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreyAkinshin committed Oct 30, 2019
1 parent 05df0eb commit e6a248b
Show file tree
Hide file tree
Showing 59 changed files with 302 additions and 184 deletions.
25 changes: 25 additions & 0 deletions samples/BenchmarkDotNet.Samples/IntroCultureInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Globalization;
using System.Threading;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;

namespace BenchmarkDotNet.Samples
{
[Config(typeof(Config))]
[ShortRunJob]
public class IntroCultureInfo
{
private class Config : ManualConfig
{
public Config()
{
var cultureInfo = (CultureInfo) CultureInfo.InvariantCulture.Clone();
cultureInfo.NumberFormat.NumberDecimalSeparator = "@";
FormatStyle = new FormatStyle(cultureInfo);
}
}

[Benchmark]
public void Foo() => Thread.Sleep(100);
}
}
2 changes: 1 addition & 1 deletion samples/BenchmarkDotNet.Samples/IntroEncoding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class IntroEncodingObjectStyle
{
private class Config : ManualConfig
{
public Config() => Encoding = Encoding.Unicode;
public Config() => FormatStyle = new FormatStyle(Encoding.Unicode);
}

[Benchmark]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Loggers;
Expand Down Expand Up @@ -184,12 +185,12 @@ public IEnumerable<Metric> Parse()
var memoryAllocatedPerOperation = totalAllocation / totalOperation;
var memoryLeakPerOperation = nativeLeakSize / totalOperation;

logger.WriteLine($"Native memory allocated per single operation: {memoryAllocatedPerOperation.ToSizeStr(SizeUnit.B)}");
logger.WriteLine($"Native memory allocated per single operation: {memoryAllocatedPerOperation.ToSizeStr(FormatStyle.DefaultCultureInfo, SizeUnit.B)}");
logger.WriteLine($"Count of allocated object: {countOfAllocatedObject / totalOperation}");

if (nativeLeakSize != 0)
{
logger.WriteLine($"Native memory leak per single operation: {memoryLeakPerOperation.ToSizeStr(SizeUnit.B)}");
logger.WriteLine($"Native memory leak per single operation: {memoryLeakPerOperation.ToSizeStr(FormatStyle.DefaultCultureInfo, SizeUnit.B)}");
}

var heapInfoList = heaps.Select(h => new { Address = h.Key, h.Value.Count, types = h.Value.Values });
Expand Down
11 changes: 6 additions & 5 deletions src/BenchmarkDotNet/Analysers/MultimodalDistributionAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Mathematics;
Expand All @@ -23,15 +24,15 @@ protected override IEnumerable<Conclusion> AnalyseReport(BenchmarkReport report,

double mValue = MathHelper.CalculateMValue(statistics);
if (mValue > 4.2)
yield return Create("is multimodal", mValue, report);
yield return Create("is multimodal", mValue, report, summary.Style.FormatStyle);
else if (mValue > 3.2)
yield return Create("is bimodal", mValue, report);
yield return Create("is bimodal", mValue, report, summary.Style.FormatStyle);
else if (mValue > 2.8)
yield return Create("can have several modes", mValue, report);
yield return Create("can have several modes", mValue, report, summary.Style.FormatStyle);
}

[NotNull]
private Conclusion Create([NotNull] string kind, double mValue, [CanBeNull] BenchmarkReport report)
=> CreateWarning($"It seems that the distribution {kind} (mValue = {mValue.ToStr()})", report);
private Conclusion Create([NotNull] string kind, double mValue, [CanBeNull] BenchmarkReport report, FormatStyle formatStyle)
=> CreateWarning($"It seems that the distribution {kind} (mValue = {mValue.ToStr(formatStyle)})", report);
}
}
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet/Code/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ internal static string Generate(BuildPartition buildPartition)
.Replace("$EngineFactoryType$", GetEngineFactoryTypeName(benchmark))
.Replace("$Ref$", provider.UseRefKeyword ? "ref" : null)
.Replace("$MeasureExtraStats$", buildInfo.Config.HasExtraStatsDiagnoser() ? "true" : "false")
.Replace("$Encoding$", buildInfo.Config.Encoding.ToTemplateString())
.Replace("$Encoding$", (buildInfo.Config.FormatStyle?.Encoding ?? FormatStyle.DefaultEncoding).ToTemplateString())
.Replace("$DisassemblerEntryMethodName$", DisassemblerConstants.DisassemblerEntryMethodName)
.Replace("$WorkloadMethodCall$", provider.GetWorkloadMethodCall(passArguments)).ToString();

Expand Down
5 changes: 3 additions & 2 deletions src/BenchmarkDotNet/Columns/BaselineRatioColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ internal override string GetValue(Summary summary, BenchmarkCase benchmarkCase,
if (ratio == null)
return "NA";

var formatStyle = summary.Style.FormatStyle;
switch (Metric)
{
case RatioMetric.Mean:
return IsNonBaselinesPrecise(summary, baseline, benchmarkCase) ? ratio.Mean.ToStr("N3") : ratio.Mean.ToStr("N2");
return IsNonBaselinesPrecise(summary, baseline, benchmarkCase) ? ratio.Mean.ToStr(formatStyle, "N3") : ratio.Mean.ToStr(formatStyle, "N2");
case RatioMetric.StdDev:
return ratio.StandardDeviation.ToStr("N2");
return ratio.StandardDeviation.ToStr(formatStyle, "N2");
default:
throw new NotSupportedException();
}
Expand Down
3 changes: 2 additions & 1 deletion src/BenchmarkDotNet/Columns/BaselineScaledColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ internal override string GetValue(Summary summary, BenchmarkCase benchmarkCase,
{
double mean = isBaseline ? 1 : Statistics.DivMean(current, baseline);

var formatStyle = summary.Style.FormatStyle;
switch (Kind)
{
case ScaledKind.Mean:
return IsNonBaselinesPrecise(summary, baseline, benchmarkCase) ? mean.ToStr("N3") : mean.ToStr("N2");
return IsNonBaselinesPrecise(summary, baseline, benchmarkCase) ? mean.ToStr(formatStyle, "N3") : mean.ToStr(formatStyle, "N2");
default:
throw new NotSupportedException();
}
Expand Down
5 changes: 3 additions & 2 deletions src/BenchmarkDotNet/Columns/MetricColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyl
if (!summary.HasReport(benchmarkCase) || !summary[benchmarkCase].Metrics.TryGetValue(descriptor.Id, out Metric metric) || (metric.Value == 0.0 && !style.PrintZeroValuesInContent))
return "-";

var formatStyle = summary.Style.FormatStyle;
if (style.PrintUnitsInContent && descriptor.UnitType == UnitType.Size)
return ((long)metric.Value).ToSizeStr(style.SizeUnit, 1, style.PrintUnitsInContent);
return ((long)metric.Value).ToSizeStr(formatStyle, style.SizeUnit, 1, style.PrintUnitsInContent);
if (style.PrintUnitsInContent && descriptor.UnitType == UnitType.Time)
return metric.Value.ToTimeStr(style.TimeUnit, 1, style.PrintUnitsInContent);

return metric.Value.ToStr(descriptor.NumberFormat);
return metric.Value.ToStr(formatStyle, descriptor.NumberFormat);
}

public override string ToString() => descriptor.DisplayName;
Expand Down
4 changes: 2 additions & 2 deletions src/BenchmarkDotNet/Columns/StatisticColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ private string Format(Summary summary, ImmutableConfig config, Statistics statis
if (double.IsNaN(value))
return "NA";
return UnitType == UnitType.Time
? value.ToTimeStr(style.TimeUnit, config.Encoding, format, 1, style.PrintUnitsInContent)
: value.ToStr(format);
? value.ToTimeStr(style.FormatStyle, style.TimeUnit, format, 1, style.PrintUnitsInContent)
: value.ToStr(style.FormatStyle, format);
}

public override string ToString() => ColumnName;
Expand Down
4 changes: 3 additions & 1 deletion src/BenchmarkDotNet/Configs/ConfigExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public static class ConfigExtensions
[PublicAPI] public static IConfig With(this IConfig config, IOrderer provider) => config.With(m => m.Orderer = provider);
[PublicAPI] public static IConfig With(this IConfig config, params HardwareCounter[] counters) => config.With(c => c.Add(counters));
[PublicAPI] public static IConfig With(this IConfig config, params IFilter[] filters) => config.With(c => c.Add(filters));
[PublicAPI] public static IConfig With(this IConfig config, Encoding encoding) => config.With(c => c.Encoding = encoding);
[Obsolete]
[PublicAPI] public static IConfig With(this IConfig config, Encoding encoding) => config.With(c => c.FormatStyle = new FormatStyle(config.FormatStyle?.CultureInfo ?? FormatStyle.DefaultCultureInfo, encoding));
[PublicAPI] public static IConfig With(this IConfig config, FormatStyle formatStyle) => config.With(c => c.FormatStyle = formatStyle);
[PublicAPI] public static IConfig With(this IConfig config, SummaryStyle summaryStyle) => config.With(c => c.SummaryStyle = summaryStyle);

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet/Configs/DebugConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public abstract class DebugConfig : IConfig
public SummaryStyle SummaryStyle => SummaryStyle.Default;
public ConfigUnionRule UnionRule => ConfigUnionRule.Union;
public string ArtifactsPath => Path.Combine(Directory.GetCurrentDirectory(), "BenchmarkDotNet.Artifacts");
public Encoding Encoding => Encoding.ASCII;
public FormatStyle FormatStyle => null;
public IEnumerable<BenchmarkLogicalGroupRule> GetLogicalGroupRules() => Array.Empty<BenchmarkLogicalGroupRule>();

public ConfigOptions Options => ConfigOptions.KeepBenchmarkFiles | ConfigOptions.DisableOptimizationsValidator;
Expand Down
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet/Configs/DefaultConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public IEnumerable<IValidator> GetValidators()

public ConfigUnionRule UnionRule => ConfigUnionRule.Union;

public Encoding Encoding => Encoding.ASCII;
public FormatStyle FormatStyle => null;

public ConfigOptions Options => ConfigOptions.Default;

Expand Down
45 changes: 45 additions & 0 deletions src/BenchmarkDotNet/Configs/FormatStyle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Globalization;
using System.Text;

namespace BenchmarkDotNet.Configs
{
public class FormatStyle : IEquatable<FormatStyle>
{
public static readonly CultureInfo DefaultCultureInfo;
public static readonly Encoding DefaultEncoding = Encoding.ASCII;
public static readonly FormatStyle DefaultStyle;

public CultureInfo CultureInfo { get; }
public Encoding Encoding { get; }

static FormatStyle()
{
DefaultCultureInfo = (CultureInfo) CultureInfo.InvariantCulture.Clone();
DefaultCultureInfo.NumberFormat.NumberDecimalSeparator = ".";
DefaultStyle = new FormatStyle(DefaultCultureInfo, DefaultEncoding);
}

public FormatStyle(CultureInfo cultureInfo, Encoding encoding)
{
CultureInfo = cultureInfo;
Encoding = encoding;
}

public FormatStyle(CultureInfo cultureInfo) : this(cultureInfo, DefaultEncoding) { }

public FormatStyle(Encoding encoding) : this(DefaultCultureInfo, encoding) { }

public bool Equals(FormatStyle other) => Equals(CultureInfo, other.CultureInfo) && Equals(Encoding, other.Encoding);

public override bool Equals(object obj) => obj is FormatStyle other && Equals(other);

public override int GetHashCode()
{
unchecked
{
return ((CultureInfo != null ? CultureInfo.GetHashCode() : 0) * 397) ^ (Encoding != null ? Encoding.GetHashCode() : 0);
}
}
}
}
7 changes: 2 additions & 5 deletions src/BenchmarkDotNet/Configs/IConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@ public interface IConfig
/// the default value is "./BenchmarkDotNet.Artifacts"
/// </summary>
string ArtifactsPath { get; }

/// <summary>
/// the default value is ASCII
/// </summary>
Encoding Encoding { get; }

FormatStyle FormatStyle { get; }

/// <summary>
/// a set of custom flags that can enable/disable various settings
Expand Down
6 changes: 3 additions & 3 deletions src/BenchmarkDotNet/Configs/ImmutableConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal ImmutableConfig(
ImmutableHashSet<Job> uniqueRunnableJobs,
ConfigUnionRule unionRule,
string artifactsPath,
Encoding encoding,
FormatStyle formatStyle,
IOrderer orderer,
SummaryStyle summaryStyle,
ConfigOptions options)
Expand All @@ -62,15 +62,15 @@ internal ImmutableConfig(
jobs = uniqueRunnableJobs;
UnionRule = unionRule;
ArtifactsPath = artifactsPath;
Encoding = encoding;
FormatStyle = formatStyle;
Orderer = orderer;
SummaryStyle = summaryStyle;
Options = options;
}

public ConfigUnionRule UnionRule { get; }
public string ArtifactsPath { get; }
public Encoding Encoding { get; }
public FormatStyle FormatStyle { get; }
public ConfigOptions Options { get; }
[NotNull] public IOrderer Orderer { get; }
public SummaryStyle SummaryStyle { get; }
Expand Down
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet/Configs/ImmutableConfigBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static ImmutableConfig Create(IConfig source)
uniqueRunnableJobs,
source.UnionRule,
source.ArtifactsPath ?? DefaultConfig.Instance.ArtifactsPath,
source.Encoding,
source.FormatStyle,
source.Orderer ?? DefaultOrderer.Instance,
source.SummaryStyle,
source.Options
Expand Down
4 changes: 2 additions & 2 deletions src/BenchmarkDotNet/Configs/ManualConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class ManualConfig : IConfig
[PublicAPI] public ConfigOptions Options { get; set; }
[PublicAPI] public ConfigUnionRule UnionRule { get; set; } = ConfigUnionRule.Union;
[PublicAPI] public string ArtifactsPath { get; set; }
[PublicAPI] public Encoding Encoding { get; set; }
[PublicAPI] public FormatStyle FormatStyle { get; set; }
[PublicAPI] public IOrderer Orderer { get; set; }
[PublicAPI] public SummaryStyle SummaryStyle { get; set; }

Expand Down Expand Up @@ -95,7 +95,7 @@ public void Add(IConfig config)
filters.AddRange(config.GetFilters());
Orderer = config.Orderer ?? Orderer;
ArtifactsPath = config.ArtifactsPath ?? ArtifactsPath;
Encoding = config.Encoding ?? Encoding;
FormatStyle = config.FormatStyle ?? FormatStyle;
SummaryStyle = config.SummaryStyle ?? SummaryStyle;
logicalGroupRules.AddRange(config.GetLogicalGroupRules());
Options |= config.Options;
Expand Down
9 changes: 5 additions & 4 deletions src/BenchmarkDotNet/Engines/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using BenchmarkDotNet.Characteristics;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Horology;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Portability;
Expand All @@ -29,7 +30,7 @@ public class Engine : IEngine
[PublicAPI] public Action IterationSetupAction { get; }
[PublicAPI] public Action IterationCleanupAction { get; }
[PublicAPI] public IResolver Resolver { get; }
[PublicAPI] public Encoding Encoding { get; }
[PublicAPI] public FormatStyle FormatStyle { get; }
[PublicAPI] public string BenchmarkName { get; }

private IClock Clock { get; }
Expand Down Expand Up @@ -68,7 +69,7 @@ internal Engine(
BenchmarkName = benchmarkName;

Resolver = resolver;
Encoding = encoding;
FormatStyle = new FormatStyle(encoding);

Clock = targetJob.ResolveValue(InfrastructureMode.ClockCharacteristic, Resolver);
ForceAllocations = targetJob.ResolveValue(GcMode.ForceCharacteristic, Resolver);
Expand Down Expand Up @@ -137,7 +138,7 @@ public RunResults Run()

var outlierMode = TargetJob.ResolveValue(AccuracyMode.OutlierModeCharacteristic, Resolver);

return new RunResults(idle, main, outlierMode, workGcHasDone, threadingStats, Encoding);
return new RunResults(idle, main, outlierMode, workGcHasDone, threadingStats, FormatStyle);
}

public Measurement RunIteration(IterationData data)
Expand Down Expand Up @@ -171,7 +172,7 @@ public Measurement RunIteration(IterationData data)
GcCollect();

// Results
var measurement = new Measurement(0, data.IterationMode, data.IterationStage, data.Index, totalOperations, clockSpan.GetNanoseconds(), Encoding);
var measurement = new Measurement(0, data.IterationMode, data.IterationStage, data.Index, totalOperations, clockSpan.GetNanoseconds(), FormatStyle);
WriteLine(measurement.ToOutputLine());

return measurement;
Expand Down
1 change: 1 addition & 0 deletions src/BenchmarkDotNet/Engines/EngineParameters.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Text;
using BenchmarkDotNet.Characteristics;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Horology;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
Expand Down
9 changes: 5 additions & 4 deletions src/BenchmarkDotNet/Engines/RunResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Text;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Mathematics;
using BenchmarkDotNet.Reports;
using JetBrains.Annotations;
Expand All @@ -12,7 +13,7 @@ namespace BenchmarkDotNet.Engines
public struct RunResults
{
private readonly OutlierMode outlierMode;
private readonly Encoding encoding;
private readonly FormatStyle formatStyle;

[CanBeNull, PublicAPI]
public IReadOnlyList<Measurement> Overhead { get; }
Expand All @@ -29,10 +30,10 @@ public RunResults([CanBeNull] IReadOnlyList<Measurement> overhead,
OutlierMode outlierMode,
GcStats gcStats,
ThreadingStats threadingStats,
Encoding encoding)
FormatStyle formatStyle)
{
this.outlierMode = outlierMode;
this.encoding = encoding;
this.formatStyle = formatStyle;
Overhead = overhead;
Workload = workload;
GCStats = gcStats;
Expand All @@ -59,7 +60,7 @@ public IEnumerable<Measurement> GetMeasurements()
++resultIndex,
measurement.Operations,
value,
encoding);
formatStyle);
}
}

Expand Down
Loading

0 comments on commit e6a248b

Please sign in to comment.