Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/BenchmarkDotNet/Code/ArrayParam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ internal static class ArrayParam
{
public static string GetDisplayString(Array array)
=> $"{array.GetType().GetElementType()?.GetDisplayName()}[{array.Length}]";

public static string GetValueString(Array array)
=> $"{GetDisplayString(array)} (rank {array.Rank}, hash {GetArrayValueHash(array)})";

private static int GetArrayValueHash(Array array)
{
var arrFlat = array.Cast<object>();

int hash = 0;

foreach (var elem in arrFlat)
{
hash = HashCode.Combine(hash, elem);
}

return hash;
}
}

public class ArrayParam<T> : IParam
Expand All @@ -28,6 +45,8 @@ private ArrayParam(T[] array, Func<T, string>? toSourceCode = null)

public string DisplayText => ArrayParam.GetDisplayString(array);

public string ValueText => ArrayParam.GetValueString(array);

public string ToSourceCode()
=> $"new {typeof(T).GetCorrectCSharpTypeName()}[] {{ {string.Join(", ", array.Select(item => toSourceCode?.Invoke(item) ?? SourceCodeHelper.ToSourceCode(item)))} }}";

Expand Down
2 changes: 2 additions & 0 deletions src/BenchmarkDotNet/Code/EnumParam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ private EnumParam(object value, Type type)

public string DisplayText => $"{Enum.ToObject(type, Value)}";

public string ValueText => DisplayText;

public string ToSourceCode() =>
$"({type.GetCorrectCSharpTypeName()})({ToInvariantCultureString()})";

Expand Down
5 changes: 5 additions & 0 deletions src/BenchmarkDotNet/Code/IParam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ public interface IParam
/// </summary>
string DisplayText { get; }

/// <summary>
/// used to group the value
/// </summary>
string ValueText { get; }

/// <summary>
/// this source code is used to create parameter for benchmark
/// in C# source code file
Expand Down
25 changes: 25 additions & 0 deletions src/BenchmarkDotNet/Parameters/ParameterInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,31 @@ public string ToDisplayText(SummaryStyle summary)

public string ToDisplayText() => ToDisplayText(CultureInfo.CurrentCulture, maxParameterColumnWidthFromConfig);

private string ToValueText(CultureInfo cultureInfo, int maxParameterColumnWidth)
{
switch (value)
{
case null:
return NullParameterTextRepresentation;
case IParam parameter:
return Trim(parameter.ValueText, maxParameterColumnWidth).EscapeSpecialCharacters(false);
case IFormattable formattable:
return Trim(formattable.ToString(null, cultureInfo), maxParameterColumnWidth).EscapeSpecialCharacters(false);
// no trimming for types!
case Type type:
return type.IsNullable() ? $"{Nullable.GetUnderlyingType(type).GetDisplayName()}?" : type.GetDisplayName();
default:
return Trim(value.ToString(), maxParameterColumnWidth).EscapeSpecialCharacters(false);
}
}

public string ToValueText(SummaryStyle summary)
{
return summary != null ? ToValueText(summary.CultureInfo, summary.MaxParameterColumnWidth) : ToValueText();
}

public string ToValueText() => ToValueText(CultureInfo.CurrentCulture, maxParameterColumnWidthFromConfig);

public override string ToString() => ToDisplayText();

private static string Trim(string value, int maxDisplayTextInnerLength)
Expand Down
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet/Parameters/ParameterInstances.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void Dispose()

public string DisplayInfo => Items.Any() ? "[" + string.Join(", ", Items.Select(p => $"{p.Name}={p.ToDisplayText()}")) + "]" : "";

public string ValueInfo => Items.Any() ? "[" + string.Join(", ", Items.Select(p => $"{p.Name}={p.Value?.ToString() ?? ParameterInstance.NullParameterTextRepresentation}")) + "]" : "";
public string ValueInfo => Items.Any() ? "[" + string.Join(", ", Items.Select(p => $"{p.Name}={p.ToValueText()}")) + "]" : "";

public string PrintInfo => printInfo ?? (printInfo = string.Join("&", Items.Select(p => $"{p.Name}={p.ToDisplayText()}")));

Expand Down
4 changes: 4 additions & 0 deletions src/BenchmarkDotNet/Parameters/SmartParamBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public SmartArgument(ParameterDefinition[] parameterDefinitions, object value, M

public string DisplayText => Value is Array array ? ArrayParam.GetDisplayString(array) : Value?.ToString() ?? ParameterInstance.NullParameterTextRepresentation;

public string ValueText => Value is Array array ? ArrayParam.GetValueString(array) : DisplayText;

public string ToSourceCode()
{
Type paramType = parameterDefinitions[argumentIndex].ParameterType;
Expand Down Expand Up @@ -153,6 +155,8 @@ public SmartParameter(Type parameterType, MemberInfo source, object value, int i

public string DisplayText => Value is Array array ? ArrayParam.GetDisplayString(array) : Value?.ToString() ?? ParameterInstance.NullParameterTextRepresentation;

public string ValueText => Value is Array array ? ArrayParam.GetValueString(array) : DisplayText;

public string ToSourceCode()
{
string cast = $"({parameterType.GetCorrectCSharpTypeName()})"; // it's an object so we need to cast it to the right type
Expand Down
59 changes: 55 additions & 4 deletions tests/BenchmarkDotNet.IntegrationTests/ArgumentsTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Tests.XUnit;
using BenchmarkDotNet.Toolchains;
Expand Down Expand Up @@ -311,9 +312,9 @@ public void Test(int[][] array)
throw new ArgumentNullException(nameof(array));

for (int i = 0; i < 10; i++)
for (int j = 0; j < i; j++)
if (array[i][j] != i)
throw new ArgumentException("Invalid value");
for (int j = 0; j < i; j++)
if (array[i][j] != i)
throw new ArgumentException("Invalid value");
}

public IEnumerable<object> CreateMatrix()
Expand Down Expand Up @@ -543,6 +544,46 @@ public void AcceptsArrays(int[] even, int[] notEven)
}
}

[Theory, MemberData(nameof(GetToolchains), DisableDiscoveryEnumeration = true)]
public void ArrayArgumentsCanBeGrouped(IToolchain toolchain)
{
var summary = CanExecute<ArrayOnDifferentMethods>(toolchain, (config) => config.AddLogicalGroupRules(BenchmarkLogicalGroupRule.ByParams)); // We must group by params to test array argument grouping

// There should be two logical groups, one for the first argument and one for the second argument
// (thus there should be two pairs per descriptor, and each pair should be distinct because it belongs to a different group)

var descriptorGroupPairs = summary.BenchmarksCases.Select(benchmarkCase => (benchmarkCase.Descriptor, summary.GetLogicalGroupKey(benchmarkCase))).GroupBy(benchmarkCase => benchmarkCase.Descriptor);

Assert.True(
descriptorGroupPairs.All(group => group.Select(pair => pair.Item2).Distinct().Count() == 2)
);
}

public class ArrayOnDifferentMethods
{
public IEnumerable<int[]> GetArrays()
{
yield return new int[] { 1, 2, 3 };
yield return new int[] { 2, 3, 4 };
}

[Benchmark(Baseline = true)]
[ArgumentsSource(nameof(GetArrays))]
public void AcceptsArrays(int[] arr)
{
if (arr.Length != 3)
throw new ArgumentException("Incorrect length");
}

[Benchmark]
[ArgumentsSource(nameof(GetArrays))]
public void AcceptsArrays2(int[] arr)
{
if (arr.Length != 3)
throw new ArgumentException("Incorrect length");
}
}

[Theory, MemberData(nameof(GetToolchains), DisableDiscoveryEnumeration = true)]
public void VeryBigIntegersAreSupported(IToolchain toolchain) => CanExecute<WithVeryBigInteger>(toolchain);

Expand Down Expand Up @@ -1026,6 +1067,16 @@ public Disposable(int id)
}
}

private void CanExecute<T>(IToolchain toolchain) => CanExecute<T>(CreateSimpleConfig(job: Job.Dry.WithToolchain(toolchain)));
private Reports.Summary CanExecute<T>(IToolchain toolchain, Func<IConfig, IConfig> furtherConfigure = null)
{
var config = CreateSimpleConfig(job: Job.Dry.WithToolchain(toolchain));

if (furtherConfigure is not null)
{
config = furtherConfigure(config);
}

return CanExecute<T>(config);
}
}
}