Skip to content

Commit

Permalink
Removed Consumer from benchmark actions.
Browse files Browse the repository at this point in the history
Overhead always returns `void`.
  • Loading branch information
timcassell committed Jun 21, 2023
1 parent b262565 commit 24cdd34
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 951 deletions.
3 changes: 0 additions & 3 deletions src/BenchmarkDotNet/Code/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,10 @@ internal static string Generate(BuildPartition buildPartition)
.Replace("$WorkloadTypeName$", provider.WorkloadTypeName)
.Replace("$WorkloadMethodReturnType$", provider.WorkloadMethodReturnTypeName)
.Replace("$WorkloadMethodReturnTypeModifiers$", provider.WorkloadMethodReturnTypeModifiers)
.Replace("$OverheadMethodReturnTypeName$", provider.OverheadMethodReturnTypeName)
.Replace("$GlobalSetupMethodName$", provider.GlobalSetupMethodName)
.Replace("$GlobalCleanupMethodName$", provider.GlobalCleanupMethodName)
.Replace("$IterationSetupMethodName$", provider.IterationSetupMethodName)
.Replace("$IterationCleanupMethodName$", provider.IterationCleanupMethodName)
.Replace("$OverheadImplementation$", provider.OverheadImplementation)
.Replace("$ConsumeField$", provider.ConsumeField)
.Replace("$JobSetDefinition$", GetJobsSetDefinition(benchmark))
.Replace("$ParamsContent$", GetParamsContent(benchmark))
.Replace("$ArgumentsDefinition$", GetArgumentsDefinition(benchmark))
Expand Down
53 changes: 1 addition & 52 deletions src/BenchmarkDotNet/Code/DeclarationsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,6 @@ internal abstract class DeclarationsProvider

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

public virtual string ConsumeField => null;

protected abstract Type OverheadMethodReturnType { get; }

public string OverheadMethodReturnTypeName => OverheadMethodReturnType.GetCorrectCSharpTypeName();

public abstract string OverheadImplementation { get; }

private string GetMethodName(MethodInfo method)
{
if (method == null)
Expand All @@ -73,62 +65,21 @@ internal class VoidDeclarationsProvider : DeclarationsProvider
public VoidDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string ReturnsDefinition => "RETURNS_VOID";

protected override Type OverheadMethodReturnType => typeof(void);

public override string OverheadImplementation => string.Empty;
}

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

public override string ConsumeField
=> !Consumer.IsConsumable(WorkloadMethodReturnType) && Consumer.HasConsumableField(WorkloadMethodReturnType, out var field)
? $".{field.Name}"
: null;

protected override Type OverheadMethodReturnType
=> Consumer.IsConsumable(WorkloadMethodReturnType)
? WorkloadMethodReturnType
: (Consumer.HasConsumableField(WorkloadMethodReturnType, out var field)
? field.FieldType
: typeof(int)); // we return this simple type because creating bigger ValueType could take longer than benchmarked method itself

public override string OverheadImplementation
{
get
{
string value;
var type = OverheadMethodReturnType;
if (type.GetTypeInfo().IsPrimitive)
value = $"default({type.GetCorrectCSharpTypeName()})";
else if (type.GetTypeInfo().IsClass || type.GetTypeInfo().IsInterface)
value = "null";
else
value = SourceCodeHelper.ToSourceCode(Activator.CreateInstance(type)) + ";";
return $"return {value};";
}
}

public override string ReturnsDefinition
=> Consumer.IsConsumable(WorkloadMethodReturnType) || Consumer.HasConsumableField(WorkloadMethodReturnType, out _)
? "RETURNS_CONSUMABLE"
: "RETURNS_NON_CONSUMABLE_STRUCT";
public override string ReturnsDefinition => "RETURNS_NON_VOID";
}

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

protected override Type OverheadMethodReturnType => typeof(IntPtr);

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

public override string ConsumeField => null;

public override string OverheadImplementation => $"return default(System.{nameof(IntPtr)});";

public override string ReturnsDefinition => "RETURNS_BYREF";

public override string WorkloadMethodReturnTypeModifiers => "ref";
Expand All @@ -138,8 +89,6 @@ internal class ByReadOnlyRefDeclarationsProvider : ByRefDeclarationsProvider
{
public ByReadOnlyRefDeclarationsProvider(Descriptor descriptor) : base(descriptor) { }

public override string ReturnsDefinition => "RETURNS_BYREF_READONLY";

public override string WorkloadMethodReturnTypeModifiers => "ref readonly";
}

Expand Down
33 changes: 0 additions & 33 deletions src/BenchmarkDotNet/Engines/Consumer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using JetBrains.Annotations;
Expand All @@ -11,13 +8,6 @@ namespace BenchmarkDotNet.Engines
{
public class Consumer
{
private static readonly HashSet<Type> SupportedTypes
= new HashSet<Type>(
typeof(Consumer).GetTypeInfo()
.DeclaredFields
.Where(field => !field.IsStatic) // exclude this HashSet itself
.Select(field => field.FieldType));

#pragma warning disable IDE0052 // Remove unread private members
private volatile byte byteHolder;
private volatile sbyte sbyteHolder;
Expand Down Expand Up @@ -153,28 +143,5 @@ public void Consume<T>(in T value)
else
DeadCodeEliminationHelper.KeepAliveWithoutBoxingReadonly(value); // non-primitive and nullable value types
}

internal static bool IsConsumable(Type type)
=> SupportedTypes.Contains(type) || type.GetTypeInfo().IsClass || type.GetTypeInfo().IsInterface;

internal static bool HasConsumableField(Type type, out FieldInfo consumableField)
{
var typeInfo = type.GetTypeInfo();

if (typeInfo.IsEnum)
{
// Enums are tricky bastards which report "value__" field, which is public for reflection, but inaccessible via C#
consumableField = null;
return false;
}

var publicInstanceFields = typeInfo.DeclaredFields
.Where(field => field.IsPublic && !field.IsStatic)
.ToArray();

consumableField = publicInstanceFields.FirstOrDefault(field => IsConsumable(field.FieldType));

return consumableField != null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,20 @@ public static LocalBuilder DeclareOptionalLocalForReturnDefault(this ILGenerator
: null;
}

public static void EmitSetLocalToDefault(this ILGenerator ilBuilder, LocalBuilder local)
{
var resultType = local.LocalType;
switch (resultType)
{
case Type t when t == typeof(void):
break;
case Type t when t.IsClass || t.IsInterface:
ilBuilder.Emit(OpCodes.Ldnull);
ilBuilder.EmitStloc(local);
break;
case Type t when t.UseInitObjForInitLocal():
EmitInitObj(ilBuilder, resultType, local);
break;
default:
EmitLoadDefaultPrimitive(ilBuilder, resultType);
ilBuilder.EmitStloc(local);
break;
}
}

public static void EmitReturnDefault(this ILGenerator ilBuilder, Type resultType, LocalBuilder optionalLocalForInitobj)
{
switch (resultType)
{
case Type t when t == typeof(void):
break;
case Type t when t.IsPointer: // Type.IsClass returns true for pointers, so we have to check for pointer type first.
/*
IL_0000: ldc.i4.0
IL_0001: conv.u
*/
ilBuilder.Emit(OpCodes.Ldc_I4_0);
ilBuilder.Emit(OpCodes.Conv_U);
break;
case Type t when t.IsClass || t.IsInterface:
ilBuilder.Emit(OpCodes.Ldnull);
break;
Expand Down

0 comments on commit 24cdd34

Please sign in to comment.