Skip to content

Commit

Permalink
Apply NoOptimization instead of AggressiveOptimization to loop me…
Browse files Browse the repository at this point in the history
…thods.

Count down loops instead of count up.
Added IntroStringBuilder.
Added more return type test cases.
  • Loading branch information
timcassell committed Jan 12, 2025
1 parent 7080e63 commit f588b6c
Show file tree
Hide file tree
Showing 21 changed files with 235 additions and 620 deletions.
34 changes: 34 additions & 0 deletions samples/BenchmarkDotNet.Samples/IntroStringBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using BenchmarkDotNet.Attributes;
using System.Text;

namespace BenchmarkDotNet.Samples
{
[MemoryDiagnoser(false)]
public class IntroStringBuilder
{
[Benchmark]
[Arguments(1)]
[Arguments(1_000)]
public StringBuilder Append_Strings(int repeat)
{
StringBuilder builder = new StringBuilder();

// strings are not sorted by length to mimic real input
for (int i = 0; i < repeat; i++)
{
builder.Append("12345");
builder.Append("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN");
builder.Append("1234567890abcdefghijklmnopqrstuvwxy");
builder.Append("1234567890");
builder.Append("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHI");
builder.Append("1234567890abcde");
builder.Append("1234567890abcdefghijklmnopqrstuvwxyzABCD");
builder.Append("1234567890abcdefghijklmnopqrst");
builder.Append("1234567890abcdefghij");
builder.Append("1234567890abcdefghijklmno");
}

return builder;
}
}
}
25 changes: 5 additions & 20 deletions src/BenchmarkDotNet/Code/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,36 +146,21 @@ private static DeclarationsProvider GetDeclarationsProvider(Descriptor descripto

if (method.ReturnType == typeof(Task) || method.ReturnType == typeof(ValueTask))
{
return new TaskDeclarationsProvider(descriptor);
return new AsyncDeclarationsProvider(descriptor);
}
if (method.ReturnType.GetTypeInfo().IsGenericType
&& (method.ReturnType.GetTypeInfo().GetGenericTypeDefinition() == typeof(Task<>)
|| method.ReturnType.GetTypeInfo().GetGenericTypeDefinition() == typeof(ValueTask<>)))
{
return new GenericTaskDeclarationsProvider(descriptor);
return new AsyncDeclarationsProvider(descriptor);
}

if (method.ReturnType == typeof(void))
if (method.ReturnType == typeof(void) && method.HasAttribute<AsyncStateMachineAttribute>())
{
bool isUsingAsyncKeyword = method.HasAttribute<AsyncStateMachineAttribute>();
if (isUsingAsyncKeyword)
{
throw new NotSupportedException("async void is not supported by design");
}

return new VoidDeclarationsProvider(descriptor);
}

if (method.ReturnType.IsByRef)
{
// System.Runtime.CompilerServices.IsReadOnlyAttribute is part of .NET Standard 2.1, we can't use it here..
if (method.ReturnParameter.GetCustomAttributes().Any(attribute => attribute.GetType().Name == "IsReadOnlyAttribute"))
return new ByReadOnlyRefDeclarationsProvider(descriptor);
else
return new ByRefDeclarationsProvider(descriptor);
throw new NotSupportedException("async void is not supported by design");
}

return new NonVoidDeclarationsProvider(descriptor);
return new SyncDeclarationsProvider(descriptor);
}

// internal for tests
Expand Down
63 changes: 5 additions & 58 deletions src/BenchmarkDotNet/Code/DeclarationsProvider.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
using System;
using System.Linq;
using System.Reflection;
using System.Reflection;
using System.Threading.Tasks;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Helpers;
using BenchmarkDotNet.Running;

namespace BenchmarkDotNet.Code
Expand All @@ -30,14 +26,6 @@ internal abstract class DeclarationsProvider

public string IterationCleanupMethodName => Descriptor.IterationCleanupMethod?.Name ?? EmptyAction;

public abstract string ReturnsDefinition { get; }

protected virtual Type WorkloadMethodReturnType => Descriptor.WorkloadMethod.ReturnType;

public virtual string WorkloadMethodReturnTypeName => WorkloadMethodReturnType.GetCorrectCSharpTypeName();

public virtual string WorkloadMethodReturnTypeModifiers => null;

public virtual string GetWorkloadMethodCall(string passArguments) => $"{Descriptor.WorkloadMethod.Name}({passArguments})";

private string GetMethodName(MethodInfo method)
Expand All @@ -60,55 +48,14 @@ private string GetMethodName(MethodInfo method)
}
}

internal class VoidDeclarationsProvider : DeclarationsProvider
{
public VoidDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string ReturnsDefinition => "RETURNS_VOID";
}

internal class NonVoidDeclarationsProvider : DeclarationsProvider
{
public NonVoidDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string ReturnsDefinition => "RETURNS_NON_VOID";
}

internal class ByRefDeclarationsProvider : NonVoidDeclarationsProvider
{
public ByRefDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string WorkloadMethodReturnTypeName => base.WorkloadMethodReturnTypeName.Replace("&", string.Empty);

public override string ReturnsDefinition => "RETURNS_BYREF";

public override string WorkloadMethodReturnTypeModifiers => "ref";
}

internal class ByReadOnlyRefDeclarationsProvider : ByRefDeclarationsProvider
internal class SyncDeclarationsProvider : DeclarationsProvider
{
public ByReadOnlyRefDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string WorkloadMethodReturnTypeModifiers => "ref readonly";
public SyncDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }
}

internal class TaskDeclarationsProvider : VoidDeclarationsProvider
internal class AsyncDeclarationsProvider : DeclarationsProvider
{
public TaskDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string GetWorkloadMethodCall(string passArguments) => $"BenchmarkDotNet.Helpers.AwaitHelper.GetResult({Descriptor.WorkloadMethod.Name}({passArguments}))";

protected override Type WorkloadMethodReturnType => typeof(void);
}

/// <summary>
/// declarations provider for <see cref="Task{TResult}" /> and <see cref="ValueTask{TResult}" />
/// </summary>
internal class GenericTaskDeclarationsProvider : NonVoidDeclarationsProvider
{
public GenericTaskDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

protected override Type WorkloadMethodReturnType => Descriptor.WorkloadMethod.ReturnType.GetTypeInfo().GetGenericArguments().Single();
public AsyncDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string GetWorkloadMethodCall(string passArguments) => $"BenchmarkDotNet.Helpers.AwaitHelper.GetResult({Descriptor.WorkloadMethod.Name}({passArguments}))";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,6 @@ namespace BenchmarkDotNet.Helpers.Reflection.Emit
{
internal static class IlGeneratorCallExtensions
{
public static LocalBuilder DeclareOptionalLocalForInstanceCall(
this ILGenerator ilBuilder,
Type localType,
MethodInfo methodToCall)
{
if (methodToCall.DeclaringType == null)
throw new ArgumentException($"The {nameof(methodToCall)} should have non-null {nameof(methodToCall.DeclaringType)}.");

if (methodToCall.IsStatic)
return null;

if (!methodToCall.DeclaringType.IsAssignableFrom(localType))
throw new ArgumentException($"{methodToCall.DeclaringType} is not assignable from {localType}.");

return localType.IsValueType && localType != typeof(void)
? ilBuilder.DeclareLocal(localType)
: null;
}

public static void EmitStaticCall(
this ILGenerator ilBuilder,
MethodInfo methodToCall,
Expand Down

This file was deleted.

Loading

0 comments on commit f588b6c

Please sign in to comment.