diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkAction.cs b/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkAction.cs deleted file mode 100644 index 2cc2363f49..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkAction.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /// Common API to run the Setup/Clean/Idle/Run methods - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - public abstract class BenchmarkAction - { - /// Gets or sets invoke single callback. - /// Invoke single callback. - public Action InvokeSingle { get; protected set; } - - /// Gets or sets invoke multiple times callback. - /// Invoke multiple times callback. - public Action InvokeMultiple { get; protected set; } - - /// Gets the last run result. - /// The last run result. - public virtual object LastRunResult => null; - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionCodegen.cs b/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionCodegen.cs deleted file mode 100644 index b77b2cfdc2..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionCodegen.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /// - /// How benchmark action code is generated - /// - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - public enum BenchmarkActionCodegen - { - /// - /// The unroll feature is implemented using dynamic method codegen (Reflection.Emit). - /// Provides most accurate results but may not work as expected on some platforms (e.g. .Net Native). - /// - ReflectionEmit, - - /// - /// Fallback option: the unroll feature is implemented using - /// method. - /// Has additional overhead (+1 delegate call) but should work on all platforms. - /// - DelegateCombine - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory.cs b/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory.cs deleted file mode 100644 index 8def323161..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -using BenchmarkDotNet.Extensions; -using BenchmarkDotNet.Running; - -using JetBrains.Annotations; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /// Helper class that creates instances. - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - public static partial class BenchmarkActionFactory - { - /// - /// Dispatch method that creates using - /// or to find correct implementation. - /// Either or should be not null. - /// - private static BenchmarkAction CreateCore( - object instance, - MethodInfo? targetMethod, - MethodInfo? fallbackIdleSignature, - BenchmarkActionCodegen codegenMode, - int unrollFactor) - { - PrepareInstanceAndResultType(instance, targetMethod, fallbackIdleSignature, out var resultInstance, out var resultType); - - if (resultType == typeof(void)) - return new BenchmarkActionVoid(resultInstance, targetMethod, codegenMode, unrollFactor); - - if (resultType == typeof(Task)) - return new BenchmarkActionTask(resultInstance, targetMethod, codegenMode, unrollFactor); - - if (resultType.GetTypeInfo().IsGenericType) - { - var genericType = resultType.GetGenericTypeDefinition(); - var argType = resultType.GenericTypeArguments[0]; - if (typeof(Task<>) == genericType) - return Create( - typeof(BenchmarkActionTask<>).MakeGenericType(argType), - resultInstance, targetMethod, - codegenMode, unrollFactor); - - if (typeof(ValueTask<>).IsAssignableFrom(genericType)) - return Create( - typeof(BenchmarkActionValueTask<>).MakeGenericType(argType), - resultInstance, targetMethod, - codegenMode, unrollFactor); - } - - if (targetMethod == null && resultType.GetTypeInfo().IsValueType) - // for Idle: we return int because creating bigger ValueType could take longer than benchmarked method itself. - resultType = typeof(int); - - return Create( - typeof(BenchmarkAction<>).MakeGenericType(resultType), - resultInstance, targetMethod, - codegenMode, unrollFactor); - } - - private static void PrepareInstanceAndResultType( - object instance, MethodInfo targetMethod, MethodInfo fallbackIdleSignature, - out object resultInstance, out Type resultType) - { - var signature = targetMethod ?? fallbackIdleSignature; - if (signature == null) - throw new ArgumentNullException( - nameof(fallbackIdleSignature), - $"Either {nameof(targetMethod)} or {nameof(fallbackIdleSignature)} should be not null."); - - if (!signature.IsStatic && instance == null) - throw new ArgumentNullException( - nameof(instance), - $"The {nameof(instance)} parameter should be not null as invocation method is instance method."); - - resultInstance = signature.IsStatic ? null : instance; - resultType = signature.ReturnType; - - if (resultType == typeof(void)) - { - // DONTTOUCH: async should be checked for target method - // as fallbackIdleSignature used for result type detection only. - bool isUsingAsyncKeyword = targetMethod?.HasAttribute() ?? false; - if (isUsingAsyncKeyword) - throw new NotSupportedException("Async void is not supported by design."); - } - } - - /// Helper to enforce .ctor signature. - private static BenchmarkActionBase Create(Type actionType, object instance, MethodInfo method, BenchmarkActionCodegen codegenMode, int unrollFactor) => - (BenchmarkActionBase)Activator.CreateInstance(actionType, instance, method, codegenMode, unrollFactor); - - private static void FallbackMethod() { } - private static readonly MethodInfo FallbackSignature = new Action(FallbackMethod).GetMethodInfo(); - private static readonly MethodInfo DummyMethod = typeof(DummyInstance).GetMethod(nameof(DummyInstance.Dummy)); - - /// Creates run benchmark action. - /// Descriptor info. - /// Instance of target. - /// Describes how benchmark action code is generated. - /// Unroll factor. - /// Run benchmark action. - public static BenchmarkAction CreateWorkload(Descriptor descriptor, object instance, BenchmarkActionCodegen codegenMode, int unrollFactor) => - CreateCore(instance, descriptor.WorkloadMethod, null, codegenMode, unrollFactor); - - /// Creates idle benchmark action. - /// Descriptor info. - /// Instance of target. - /// Describes how benchmark action code is generated. - /// Unroll factor. - /// Idle benchmark action. - public static BenchmarkAction CreateOverhead(Descriptor descriptor, object instance, BenchmarkActionCodegen codegenMode, int unrollFactor) => - CreateCore(instance, null, descriptor.WorkloadMethod, codegenMode, unrollFactor); - - /// Creates global setup benchmark action. - /// Descriptor info. - /// Instance of target. - /// Setup benchmark action. - public static BenchmarkAction CreateGlobalSetup(Descriptor descriptor, object instance) => - CreateCore(instance, descriptor.GlobalSetupMethod, FallbackSignature, BenchmarkActionCodegen.DelegateCombine, 1); - - /// Creates global cleanup benchmark action. - /// Descriptor info. - /// Instance of target. - /// Cleanup benchmark action. - public static BenchmarkAction CreateGlobalCleanup(Descriptor descriptor, object instance) => - CreateCore(instance, descriptor.GlobalCleanupMethod, FallbackSignature, BenchmarkActionCodegen.DelegateCombine, 1); - - /// Creates global setup benchmark action. - /// Descriptor info. - /// Instance of target. - /// Setup benchmark action. - public static BenchmarkAction CreateIterationSetup(Descriptor descriptor, object instance) => - CreateCore(instance, descriptor.IterationSetupMethod, FallbackSignature, BenchmarkActionCodegen.DelegateCombine, 1); - - /// Creates global cleanup benchmark action. - /// Descriptor info. - /// Instance of target. - /// Cleanup benchmark action. - public static BenchmarkAction CreateIterationCleanup(Descriptor descriptor, object instance) => - CreateCore(instance, descriptor.IterationCleanupMethod, FallbackSignature, BenchmarkActionCodegen.DelegateCombine, 1); - - /// Creates a dummy benchmark action. - /// Dummy benchmark action. - public static BenchmarkAction CreateDummy() => - CreateCore(new DummyInstance(), DummyMethod, null, BenchmarkActionCodegen.DelegateCombine, 1); - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Base.cs b/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Base.cs deleted file mode 100644 index ba1fe75060..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Base.cs +++ /dev/null @@ -1,229 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /* - Design goals of the whole stuff: - 0. Reusable API to call Setup/Clean/Overhead/Workload actions with arbitrary return value and store the result. - Supported ones are: void, T, Task, Task, ValueTask. No input args, same as for outofproc benchmarks. - 1. Overhead signature should match to the benchmark method signature (including static/instance modifier). - 2. Should work under .Net native. There's CodegenMode option to use Delegate.Combine instead of emitting the code. - 3. High data locality and no additional allocations / JIT where possible. - This means NO closures allowed, no allocations but in .ctor and for LastCallResult boxing, - all state should be stored explicitly as BenchmarkAction's fields. - 4. There can be multiple benchmark actions per single target instance (workload, globalSetup, globalCleanup methods), - so target instantiation is not a responsibility of the benchmark action. - 5. Implementation should match to the code in BenchmarkProgram.txt. - As example, this code emits loop unroll only, task waiting is implemented as a delegate call. - Outofproc code uses TaskMethodInvoker.ExecuteBlocking callback for this. - */ - - // DONTTOUCH: Be VERY CAREFUL when changing the code. - // Please, ensure that the implementation is in sync with content of BenchmarkProgram.txt - - /// Helper class that creates instances. - public static partial class BenchmarkActionFactory - { - /// Base class that provides reusable API for final implementations. - internal abstract class BenchmarkActionBase : BenchmarkAction - { - protected static TDelegate CreateWorkload(object? targetInstance, MethodInfo workloadMethod) - { - if (workloadMethod.IsStatic) - return (TDelegate)(object)workloadMethod.CreateDelegate(typeof(TDelegate)); - - return (TDelegate)(object)workloadMethod.CreateDelegate(typeof(TDelegate), targetInstance); - } - - protected static TDelegate CreateWorkloadOrOverhead( - object? targetInstance, MethodInfo? workloadMethod, - TDelegate overheadStaticCallback, TDelegate overheadInstanceCallback) where TDelegate : notnull - { - if (workloadMethod == null) - return targetInstance == null ? overheadStaticCallback : overheadInstanceCallback; - - if (workloadMethod.IsStatic) - return (TDelegate)(object)workloadMethod.CreateDelegate(typeof(TDelegate)); - - return (TDelegate)(object)workloadMethod.CreateDelegate(typeof(TDelegate), targetInstance); - } - - protected static bool UseFallbackCode(BenchmarkActionCodegen codegenMode, int unrollFactor) => - unrollFactor <= 1 || codegenMode == BenchmarkActionCodegen.DelegateCombine; - - protected static TDelegate Unroll(TDelegate callback, int unrollFactor) - { - if (callback == null) - throw new ArgumentNullException(nameof(callback)); - - if (unrollFactor <= 1) - return callback; - - return (TDelegate)(object)Delegate.Combine( - Enumerable.Repeat((Delegate)(object)callback, unrollFactor).ToArray()); - } - - private const BindingFlags GetFieldFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; - - protected static Action EmitInvokeMultiple( - BenchmarkActionBase instance, - string callbackFieldName, - string storeResultFieldName, - int unrollFactor) - { - if (instance == null) - throw new ArgumentNullException(nameof(instance)); - - if (callbackFieldName == null) - throw new ArgumentNullException(nameof(callbackFieldName)); - - var instanceType = instance.GetType(); - var callbackField = GetCallbackField(instanceType, callbackFieldName); - var callbackInvokeMethod = callbackField.FieldType.GetTypeInfo().GetMethod(nameof(Action.Invoke)) - ?? throw new NullReferenceException($"{nameof(Action.Invoke)} not found"); - var storeResultField = GetStoreResultField(instanceType, storeResultFieldName, callbackInvokeMethod.ReturnType); - - // void InvokeMultipleEmitted(long x) // instance method associated with instanceType - var m = new DynamicMethod("InvokeMultipleEmitted", typeof(void), new[] { instanceType, typeof(long) }, instanceType) - { - InitLocals = true - }; - - EmitInvokeMultipleBody(m, callbackField, callbackInvokeMethod, storeResultField, unrollFactor); - - return (Action)m.CreateDelegate(typeof(Action), instance); - } - - private static FieldInfo GetCallbackField(Type instanceType, string callbackFieldName) - { - var callbackField = instanceType.GetTypeInfo().GetField(callbackFieldName, GetFieldFlags); - if (callbackField == null) - throw new ArgumentException($"Field {callbackFieldName} not found.", nameof(callbackFieldName)); - - var callbackFieldType = callbackField.FieldType; - if (callbackFieldType != typeof(Action) && - (!callbackFieldType.GetTypeInfo().IsGenericType || callbackFieldType.GetGenericTypeDefinition() != typeof(Func<>))) - throw new ArgumentException( - $"Type of {callbackFieldName} field should be either Action or Func.", - nameof(callbackFieldName)); - - return callbackField; - } - - private static FieldInfo GetStoreResultField( - Type instanceType, string storeResultFieldName, Type expectedFieldType) - { - if (expectedFieldType == typeof(void) || storeResultFieldName == null) - return null; - - var storeResultField = instanceType.GetTypeInfo().GetField(storeResultFieldName, GetFieldFlags); - - if (expectedFieldType != storeResultField?.FieldType) - throw new ArgumentException( - $"Type of {storeResultFieldName} field should be equal to {expectedFieldType}.", - nameof(storeResultFieldName)); - - return storeResultField; - } - - private static void EmitInvokeMultipleBody( - DynamicMethod dynamicMethod, - FieldInfo callbackField, - MethodInfo callbackInvokeMethod, - FieldInfo storeResultField, int unrollFactor) - { - /* - // for long i = 0 - IL_0000: ldc.i4.0 - IL_0001: conv.i8 - IL_0002: stloc.0 - - // jump to i < invokeCount - IL_0003: br IL_0041 - // loop start (head: IL_0041) - IL_0005: ... // loop body - - // i++; - IL_003d: ldc.i4.1 - IL_003e: conv.i8 - IL_003f: add - IL_0040: stloc.0 - - // i < invokeCount - IL_0041: ldloc.0 - IL_0042: ldarg.1 - IL_0043: blt IL_0005 // jump to loop start - // end loop - - IL_0045: ret - */ - - bool noReturnValue = callbackInvokeMethod.ReturnType == typeof(void); - bool hasStoreField = !noReturnValue && storeResultField != null; - - var g = dynamicMethod.GetILGenerator(); - g.DeclareLocal(typeof(long)); - - var loopStart = g.DefineLabel(); - var loopCondition = g.DefineLabel(); - - // for i = 0 - g.Emit(OpCodes.Ldc_I4_0); - g.Emit(OpCodes.Conv_I8); - g.Emit(OpCodes.Stloc_0); - - // jump to i < invokeCount - g.Emit(OpCodes.Br, loopCondition); - - g.MarkLabel(loopStart); - { - // loop body: callback(); unroll - for (int j = 0; j < unrollFactor; j++) - { - if (noReturnValue) - { - g.Emit(OpCodes.Ldarg_0); // this - g.Emit(OpCodes.Ldfld, callbackField); - g.Emit(OpCodes.Callvirt, callbackInvokeMethod); - } - else if (hasStoreField) - { - g.Emit(OpCodes.Ldarg_0); // this - g.Emit(OpCodes.Dup); // this (copy will be used to store the field) - g.Emit(OpCodes.Ldfld, callbackField); - g.Emit(OpCodes.Callvirt, callbackInvokeMethod); - g.Emit(OpCodes.Stfld, storeResultField); - } - else - { - g.Emit(OpCodes.Ldarg_0); // this - g.Emit(OpCodes.Ldfld, callbackField); - g.Emit(OpCodes.Callvirt, callbackInvokeMethod); - g.Emit(OpCodes.Pop); // ignore the return value - } - } - - // i++; - g.Emit(OpCodes.Ldloc_0); - g.Emit(OpCodes.Ldc_I4_1); - g.Emit(OpCodes.Conv_I8); - g.Emit(OpCodes.Add); - g.Emit(OpCodes.Stloc_0); - - // i < invokeCount - g.MarkLabel(loopCondition); - { - g.Emit(OpCodes.Ldloc_0); - g.Emit(OpCodes.Ldarg_1); - g.Emit(OpCodes.Blt, loopStart); // jump to loop start - } - } - - g.Emit(OpCodes.Ret); - } - } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Dummy.cs b/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Dummy.cs deleted file mode 100644 index dd067d37ae..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Dummy.cs +++ /dev/null @@ -1,83 +0,0 @@ -using JetBrains.Annotations; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /// Helper class that creates instances. - public static partial class BenchmarkActionFactory - { - private class DummyInstance - { - [UsedImplicitly] - private int dummyField; - - public void Dummy() - { - // copy-pasted as emit is not supported across all platforms - dummyField++; // 0 - dummyField++; // 1 - dummyField++; // 2 - dummyField++; // 3 - dummyField++; // 4 - dummyField++; // 5 - dummyField++; // 6 - dummyField++; // 7 - dummyField++; // 8 - dummyField++; // 9 - dummyField++; // 10 - dummyField++; // 11 - dummyField++; // 12 - dummyField++; // 13 - dummyField++; // 14 - dummyField++; // 15 - dummyField++; // 16 - dummyField++; // 17 - dummyField++; // 18 - dummyField++; // 19 - dummyField++; // 20 - dummyField++; // 21 - dummyField++; // 22 - dummyField++; // 23 - dummyField++; // 24 - dummyField++; // 25 - dummyField++; // 26 - dummyField++; // 27 - dummyField++; // 28 - dummyField++; // 29 - dummyField++; // 30 - dummyField++; // 31 - dummyField++; // 32 - dummyField++; // 33 - dummyField++; // 34 - dummyField++; // 35 - dummyField++; // 36 - dummyField++; // 37 - dummyField++; // 38 - dummyField++; // 39 - dummyField++; // 40 - dummyField++; // 41 - dummyField++; // 42 - dummyField++; // 43 - dummyField++; // 44 - dummyField++; // 45 - dummyField++; // 46 - dummyField++; // 47 - dummyField++; // 48 - dummyField++; // 49 - dummyField++; // 50 - dummyField++; // 51 - dummyField++; // 52 - dummyField++; // 53 - dummyField++; // 54 - dummyField++; // 55 - dummyField++; // 56 - dummyField++; // 57 - dummyField++; // 58 - dummyField++; // 59 - dummyField++; // 60 - dummyField++; // 61 - dummyField++; // 62 - dummyField++; // 63 - } - } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Implementations.cs b/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Implementations.cs deleted file mode 100644 index 5ca5592e1e..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/BenchmarkActionFactory_Implementations.cs +++ /dev/null @@ -1,227 +0,0 @@ -using System; -using System.Reflection; -using System.Threading.Tasks; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /* - Design goals of the whole stuff: check the comments for BenchmarkActionBase. - */ - - // DONTTOUCH: Be VERY CAREFUL when changing the code. - // Please, ensure that the implementation is in sync with content of BenchmarkProgram.txt - - /// Helper class that creates instances. - public static partial class BenchmarkActionFactory - { - internal class BenchmarkActionVoid : BenchmarkActionBase - { - private readonly Action callback; - private readonly Action unrolledCallback; - - public BenchmarkActionVoid(object instance, MethodInfo method, BenchmarkActionCodegen codegenMode, int unrollFactor) - { - callback = CreateWorkloadOrOverhead(instance, method, OverheadStatic, OverheadInstance); - InvokeSingle = callback; - - if (UseFallbackCode(codegenMode, unrollFactor)) - { - unrolledCallback = Unroll(callback, unrollFactor); - InvokeMultiple = InvokeMultipleHardcoded; - } - else - { - InvokeMultiple = EmitInvokeMultiple(this, nameof(callback), null, unrollFactor); - } - } - - private static void OverheadStatic() { } - private void OverheadInstance() { } - - private void InvokeMultipleHardcoded(long repeatCount) - { - for (long i = 0; i < repeatCount; i++) - unrolledCallback(); - } - } - - internal class BenchmarkAction : BenchmarkActionBase - { - private readonly Func callback; - private readonly Func unrolledCallback; - private T result; - - public BenchmarkAction(object instance, MethodInfo method, BenchmarkActionCodegen codegenMode, int unrollFactor) - { - callback = CreateWorkloadOrOverhead>(instance, method, OverheadStatic, OverheadInstance); - InvokeSingle = InvokeSingleHardcoded; - - if (UseFallbackCode(codegenMode, unrollFactor)) - { - unrolledCallback = Unroll(callback, unrollFactor); - InvokeMultiple = InvokeMultipleHardcoded; - } - else - { - InvokeMultiple = EmitInvokeMultiple(this, nameof(callback), nameof(result), unrollFactor); - } - } - - private static T OverheadStatic() => default; - private T OverheadInstance() => default; - - private void InvokeSingleHardcoded() => result = callback(); - - private void InvokeMultipleHardcoded(long repeatCount) - { - for (long i = 0; i < repeatCount; i++) - result = unrolledCallback(); - } - - public override object LastRunResult => result; - } - - internal class BenchmarkActionTask : BenchmarkActionBase - { - private readonly Func startTaskCallback; - private readonly Action callback; - private readonly Action unrolledCallback; - - public BenchmarkActionTask(object instance, MethodInfo method, BenchmarkActionCodegen codegenMode, int unrollFactor) - { - bool isIdle = method == null; - if (!isIdle) - { - startTaskCallback = CreateWorkload>(instance, method); - callback = ExecuteBlocking; - } - else - { - callback = Overhead; - } - - InvokeSingle = callback; - - if (UseFallbackCode(codegenMode, unrollFactor)) - { - unrolledCallback = Unroll(callback, unrollFactor); - InvokeMultiple = InvokeMultipleHardcoded; - } - else - { - InvokeMultiple = EmitInvokeMultiple(this, nameof(callback), null, unrollFactor); - } - } - - // must be kept in sync with VoidDeclarationsProvider.IdleImplementation - private void Overhead() { } - - // must be kept in sync with TaskDeclarationsProvider.TargetMethodDelegate - private void ExecuteBlocking() => startTaskCallback.Invoke().GetAwaiter().GetResult(); - - private void InvokeMultipleHardcoded(long repeatCount) - { - for (long i = 0; i < repeatCount; i++) - unrolledCallback(); - } - } - - internal class BenchmarkActionTask : BenchmarkActionBase - { - private readonly Func> startTaskCallback; - private readonly Func callback; - private readonly Func unrolledCallback; - private T result; - - public BenchmarkActionTask(object instance, MethodInfo method, BenchmarkActionCodegen codegenMode, int unrollFactor) - { - bool isOverhead = method == null; - if (!isOverhead) - { - startTaskCallback = CreateWorkload>>(instance, method); - callback = ExecuteBlocking; - } - else - { - callback = Overhead; - } - - InvokeSingle = InvokeSingleHardcoded; - - if (UseFallbackCode(codegenMode, unrollFactor)) - { - unrolledCallback = Unroll(callback, unrollFactor); - InvokeMultiple = InvokeMultipleHardcoded; - } - else - { - InvokeMultiple = EmitInvokeMultiple(this, nameof(callback), nameof(result), unrollFactor); - } - } - - private T Overhead() => default; - - // must be kept in sync with GenericTaskDeclarationsProvider.TargetMethodDelegate - private T ExecuteBlocking() => startTaskCallback().GetAwaiter().GetResult(); - - private void InvokeSingleHardcoded() => result = callback(); - - private void InvokeMultipleHardcoded(long repeatCount) - { - for (long i = 0; i < repeatCount; i++) - result = unrolledCallback(); - } - - public override object LastRunResult => result; - } - - internal class BenchmarkActionValueTask : BenchmarkActionBase - { - private readonly Func> startTaskCallback; - private readonly Func callback; - private readonly Func unrolledCallback; - private T result; - - public BenchmarkActionValueTask(object instance, MethodInfo method, BenchmarkActionCodegen codegenMode, int unrollFactor) - { - bool isOverhead = method == null; - if (!isOverhead) - { - startTaskCallback = CreateWorkload>>(instance, method); - callback = ExecuteBlocking; - } - else - { - callback = Overhead; - } - - InvokeSingle = InvokeSingleHardcoded; - - if (UseFallbackCode(codegenMode, unrollFactor)) - { - unrolledCallback = Unroll(callback, unrollFactor); - InvokeMultiple = InvokeMultipleHardcoded; - } - else - { - InvokeMultiple = EmitInvokeMultiple(this, nameof(callback), nameof(result), unrollFactor); - } - } - - private T Overhead() => default; - - // must be kept in sync with GenericTaskDeclarationsProvider.TargetMethodDelegate - private T ExecuteBlocking() => startTaskCallback().GetAwaiter().GetResult(); - - private void InvokeSingleHardcoded() => result = callback(); - - private void InvokeMultipleHardcoded(long repeatCount) - { - for (long i = 0; i < repeatCount; i++) - result = unrolledCallback(); - } - - public override object LastRunResult => result; - } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/ConsumableTypeInfo.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/ConsumableTypeInfo.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/ConsumableTypeInfo.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/ConsumableTypeInfo.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/ByRefConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ByRefConsumeEmitter.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/ByRefConsumeEmitter.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ByRefConsumeEmitter.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/ConsumableConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumableConsumeEmitter.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/ConsumableConsumeEmitter.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumableConsumeEmitter.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/ConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumeEmitter.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/ConsumeEmitter.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/ConsumeEmitter.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/EmitExtensions.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/EmitExtensions.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/EmitExtensions.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/EmitExtensions.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/NonConsumableConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/NonConsumableConsumeEmitter.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/NonConsumableConsumeEmitter.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/NonConsumableConsumeEmitter.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/RunnableEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/RunnableEmitter.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/RunnableEmitter.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/RunnableEmitter.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/VoidConsumeEmitter.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/VoidConsumeEmitter.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Emitters/VoidConsumeEmitter.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Emitters/VoidConsumeEmitter.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableConstants.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableConstants.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableConstants.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableConstants.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableProgram.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableProgram.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableProgram.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableProgram.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableReflectionHelpers.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableReflectionHelpers.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableReflectionHelpers.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableReflectionHelpers.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableReuse.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableReuse.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/Runnable/RunnableReuse.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/Runnable/RunnableReuse.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/RunnableActionKind.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/RunnableActionKind.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit.Implementation/RunnableActionKind.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/Implementation/RunnableActionKind.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitArtifactsPath.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitArtifactsPath.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitArtifactsPath.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitArtifactsPath.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitBuilder.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitBuilder.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitBuilder.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitBuilder.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitExecutor.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitExecutor.cs similarity index 99% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitExecutor.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitExecutor.cs index 9d2cc3466b..d1aad700e6 100644 --- a/src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitExecutor.cs +++ b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitExecutor.cs @@ -24,7 +24,7 @@ public class InProcessEmitExecutor : IExecutor /// Default timeout for in-process benchmarks. public static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(5); - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// Timeout for the run. /// true if the output should be logged. public InProcessEmitExecutor(TimeSpan timeout, bool logOutput) diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitGenerator.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitGenerator.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitGenerator.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitGenerator.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitToolchain.cs b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitToolchain.cs similarity index 93% rename from src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitToolchain.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitToolchain.cs index 8ca8f77897..4e63d417a2 100644 --- a/src/BenchmarkDotNet/Toolchains/InProcess.Emit/InProcessEmitToolchain.cs +++ b/src/BenchmarkDotNet/Toolchains/InProcess/Emit/InProcessEmitToolchain.cs @@ -12,13 +12,13 @@ public class InProcessEmitToolchain : Toolchain /// The toolchain instance without output logging. public static readonly IToolchain DontLogOutput = new InProcessEmitToolchain(false); - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// true if the output should be logged. public InProcessEmitToolchain(bool logOutput) : this(TimeSpan.Zero, logOutput) { } - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// Timeout for the run. /// true if the output should be logged. public InProcessEmitToolchain(TimeSpan timeout, bool logOutput) : diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessBuilder.cs b/src/BenchmarkDotNet/Toolchains/InProcess/InProcessBuilder.cs deleted file mode 100644 index d487b43da6..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessBuilder.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using BenchmarkDotNet.Loggers; -using BenchmarkDotNet.Running; -using BenchmarkDotNet.Toolchains.Results; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - public class InProcessBuilder : IBuilder - { - /// always returns success - public BuildResult Build(GenerateResult generateResult, BuildPartition buildPartition, ILogger logger) - => BuildResult.Success(generateResult); - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessExecutor.cs b/src/BenchmarkDotNet/Toolchains/InProcess/InProcessExecutor.cs deleted file mode 100644 index ebb4bf9281..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessExecutor.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; -using System.Threading; -using BenchmarkDotNet.Engines; -using BenchmarkDotNet.Environments; -using BenchmarkDotNet.Extensions; -using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Loggers; -using BenchmarkDotNet.Toolchains.Parameters; -using BenchmarkDotNet.Toolchains.Results; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /// - /// Implementation of for in-process benchmarks. - /// - [SuppressMessage("ReSharper", "ArrangeBraces_using")] - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - public class InProcessExecutor : IExecutor - { - private static readonly TimeSpan UnderDebuggerTimeout = TimeSpan.FromDays(1); - - /// Default timeout for in-process benchmarks. - public static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(5); - - /// Initializes a new instance of the class. - /// Timeout for the run. - /// Describes how benchmark action code is generated. - /// true if the output should be logged. - public InProcessExecutor(TimeSpan timeout, BenchmarkActionCodegen codegenMode, bool logOutput) - { - if (timeout == TimeSpan.Zero) - timeout = DefaultTimeout; - - ExecutionTimeout = timeout; - CodegenMode = codegenMode; - LogOutput = logOutput; - } - - /// Timeout for the run. - /// The timeout for the run. - public TimeSpan ExecutionTimeout { get; } - - /// Describes how benchmark action code is generated. - /// Benchmark action code generation mode. - public BenchmarkActionCodegen CodegenMode { get; } - - /// Gets a value indicating whether the output should be logged. - /// true if the output should be logged; otherwise, false. - public bool LogOutput { get; } - - /// Executes the specified benchmark. - public ExecuteResult Execute(ExecuteParameters executeParameters) - { - // TODO: preallocate buffer for output (no direct logging)? - var hostLogger = LogOutput ? executeParameters.Logger : NullLogger.Instance; - var host = new InProcessHost(executeParameters.BenchmarkCase, hostLogger, executeParameters.Diagnoser); - - int exitCode = -1; - var runThread = new Thread(() => exitCode = ExecuteCore(host, executeParameters)); - - if (executeParameters.BenchmarkCase.Descriptor.WorkloadMethod.GetCustomAttributes(false).Any() && - Portability.RuntimeInformation.IsWindows()) - { - runThread.SetApartmentState(ApartmentState.STA); - } - - runThread.IsBackground = true; - - var timeout = HostEnvironmentInfo.GetCurrent().HasAttachedDebugger ? UnderDebuggerTimeout : ExecutionTimeout; - - runThread.Start(); - - if (!runThread.Join((int)timeout.TotalMilliseconds)) - throw new InvalidOperationException( - $"Benchmark {executeParameters.BenchmarkCase.DisplayInfo} takes too long to run. " + - "Prefer to use out-of-process toolchains for long-running benchmarks."); - - return ExecuteResult.FromRunResults(host.RunResults, exitCode); - } - - private int ExecuteCore(IHost host, ExecuteParameters parameters) - { - int exitCode = -1; - var process = Process.GetCurrentProcess(); - var oldPriority = process.PriorityClass; - var oldAffinity = process.TryGetAffinity(); - var thread = Thread.CurrentThread; - var oldThreadPriority = thread.Priority; - - var affinity = parameters.BenchmarkCase.Job.ResolveValueAsNullable(EnvironmentMode.AffinityCharacteristic); - try - { - process.TrySetPriority(ProcessPriorityClass.High, parameters.Logger); - thread.TrySetPriority(ThreadPriority.Highest, parameters.Logger); - - if (affinity != null) - { - process.TrySetAffinity(affinity.Value, parameters.Logger); - } - - exitCode = InProcessRunner.Run(host, parameters.BenchmarkCase, CodegenMode); - } - catch (Exception ex) - { - parameters.Logger.WriteLineError($"// ! {GetType().Name}, exception: {ex}"); - } - finally - { - process.TrySetPriority(oldPriority, parameters.Logger); - thread.TrySetPriority(oldThreadPriority, parameters.Logger); - - if (affinity != null && oldAffinity != null) - { - process.TrySetAffinity(oldAffinity.Value, parameters.Logger); - } - } - - return exitCode; - } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessGenerator.cs b/src/BenchmarkDotNet/Toolchains/InProcess/InProcessGenerator.cs deleted file mode 100644 index ca9803df55..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessGenerator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using BenchmarkDotNet.Loggers; -using BenchmarkDotNet.Running; -using BenchmarkDotNet.Toolchains.Results; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /// - /// Implementation of for in-process benchmarks. - /// - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - public class InProcessGenerator : IGenerator - { - /// returns a success - public GenerateResult GenerateProject(BuildPartition buildPartition, ILogger logger, string rootArtifactsFolderPath) - => GenerateResult.Success(null, Array.Empty()); - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessRunner.cs b/src/BenchmarkDotNet/Toolchains/InProcess/InProcessRunner.cs deleted file mode 100644 index aedd8f6788..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessRunner.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using System.Reflection; - -using BenchmarkDotNet.Engines; -using BenchmarkDotNet.Environments; -using BenchmarkDotNet.Exporters; -using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Running; - -using JetBrains.Annotations; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - internal class InProcessRunner - { - public static int Run(IHost host, BenchmarkCase benchmarkCase, BenchmarkActionCodegen codegenMode) - { - // the first thing to do is to let diagnosers hook in before anything happens - // so all jit-related diagnosers can catch first jit compilation! - host.BeforeAnythingElse(); - - try - { - // we are not using Runnable here in any direct way in order to avoid strong dependency Main<=>Runnable - // which could cause the jitting/assembly loading to happen before we do anything - // we have some jitting diagnosers and we want them to catch all the informations!! - - string inProcessRunnableTypeName = $"{typeof(InProcessRunner).FullName}+{nameof(Runnable)}"; - var type = typeof(InProcessRunner).GetTypeInfo().Assembly.GetType(inProcessRunnableTypeName) - ?? throw new InvalidOperationException($"Bug: type {inProcessRunnableTypeName} not found."); - - var methodInfo = type.GetMethod(nameof(Runnable.RunCore), BindingFlags.Public | BindingFlags.Static) - ?? throw new InvalidOperationException($"Bug: method {nameof(Runnable.RunCore)} in {inProcessRunnableTypeName} not found."); - methodInfo.Invoke(null, new object[] { host, benchmarkCase, codegenMode }); - - return 0; - } - catch (Exception oom) when (oom is OutOfMemoryException || oom is TargetInvocationException reflection && reflection.InnerException is OutOfMemoryException) - { - host.WriteLine(); - host.WriteLine("OutOfMemoryException!"); - host.WriteLine("BenchmarkDotNet continues to run additional iterations until desired accuracy level is achieved. It's possible only if the benchmark method doesn't have any side-effects."); - host.WriteLine("If your benchmark allocates memory and keeps it alive, you are creating a memory leak."); - host.WriteLine("You should redesign your benchmark and remove the side-effects. You can use `OperationsPerInvoke`, `IterationSetup` and `IterationCleanup` to do that."); - host.WriteLine(); - host.WriteLine(oom.ToString()); - - return -1; - } - catch (Exception ex) - { - host.WriteLine(); - host.WriteLine(ex.ToString()); - return -1; - } - finally - { - host.AfterAll(); - } - } - - /// Fills the properties of the instance of the object used to run the benchmark. - /// The instance. - /// The benchmark. - internal static void FillMembers(object instance, BenchmarkCase benchmarkCase) - { - foreach (var parameter in benchmarkCase.Parameters.Items) - { - var flags = BindingFlags.Public; - flags |= parameter.IsStatic ? BindingFlags.Static : BindingFlags.Instance; - - var targetType = benchmarkCase.Descriptor.Type; - var paramProperty = targetType.GetProperty(parameter.Name, flags); - - if (paramProperty == null) - { - var paramField = targetType.GetField(parameter.Name, flags); - if (paramField == null) - throw new InvalidOperationException( - $"Type {targetType.FullName}: no property or field {parameter.Name} found."); - - var callInstance = paramField.IsStatic ? null : instance; - paramField.SetValue(callInstance, parameter.Value); - } - else - { - var setter = paramProperty.GetSetMethod(); - if (setter == null) - throw new InvalidOperationException( - $"Type {targetType.FullName}: no settable property {parameter.Name} found."); - - var callInstance = setter.IsStatic ? null : instance; - setter.Invoke(callInstance, new[] { parameter.Value }); - } - } - } - - [UsedImplicitly] - private static class Runnable - { - public static void RunCore(IHost host, BenchmarkCase benchmarkCase, BenchmarkActionCodegen codegenMode) - { - var target = benchmarkCase.Descriptor; - var job = benchmarkCase.Job; // TODO: filter job (same as SourceCodePresenter does)? - int unrollFactor = benchmarkCase.Job.ResolveValue(RunMode.UnrollFactorCharacteristic, EnvironmentResolver.Instance); - - // DONTTOUCH: these should be allocated together - var instance = Activator.CreateInstance(benchmarkCase.Descriptor.Type); - var workloadAction = BenchmarkActionFactory.CreateWorkload(target, instance, codegenMode, unrollFactor); - var overheadAction = BenchmarkActionFactory.CreateOverhead(target, instance, codegenMode, unrollFactor); - var globalSetupAction = BenchmarkActionFactory.CreateGlobalSetup(target, instance); - var globalCleanupAction = BenchmarkActionFactory.CreateGlobalCleanup(target, instance); - var iterationSetupAction = BenchmarkActionFactory.CreateIterationSetup(target, instance); - var iterationCleanupAction = BenchmarkActionFactory.CreateIterationCleanup(target, instance); - var dummy1 = BenchmarkActionFactory.CreateDummy(); - var dummy2 = BenchmarkActionFactory.CreateDummy(); - var dummy3 = BenchmarkActionFactory.CreateDummy(); - - FillMembers(instance, benchmarkCase); - - host.WriteLine(); - foreach (string infoLine in BenchmarkEnvironmentInfo.GetCurrent().ToFormattedString()) - host.WriteLine("// {0}", infoLine); - host.WriteLine("// Job: {0}", job.DisplayInfo); - host.WriteLine(); - - var engineParameters = new EngineParameters - { - Host = host, - WorkloadActionNoUnroll = invocationCount => - { - for (int i = 0; i < invocationCount; i++) - workloadAction.InvokeSingle(); - }, - WorkloadActionUnroll = workloadAction.InvokeMultiple, - Dummy1Action = dummy1.InvokeSingle, - Dummy2Action = dummy2.InvokeSingle, - Dummy3Action = dummy3.InvokeSingle, - OverheadActionNoUnroll = invocationCount => - { - for (int i = 0; i < invocationCount; i++) - overheadAction.InvokeSingle(); - }, - OverheadActionUnroll = overheadAction.InvokeMultiple, - GlobalSetupAction = globalSetupAction.InvokeSingle, - GlobalCleanupAction = globalCleanupAction.InvokeSingle, - IterationSetupAction = iterationSetupAction.InvokeSingle, - IterationCleanupAction = iterationCleanupAction.InvokeSingle, - TargetJob = job, - OperationsPerInvoke = target.OperationsPerInvoke, - MeasureExtraStats = benchmarkCase.Config.HasExtraStatsDiagnoser(), - BenchmarkName = FullNameProvider.GetBenchmarkName(benchmarkCase) - }; - - using (var engine = job - .ResolveValue(InfrastructureMode.EngineFactoryCharacteristic, InfrastructureResolver.Instance) - .CreateReadyToRun(engineParameters)) - { - var results = engine.Run(); - - host.ReportResults(results); // printing costs memory, do this after runs - } - } - } - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessToolchain.cs b/src/BenchmarkDotNet/Toolchains/InProcess/InProcessToolchain.cs deleted file mode 100644 index 9dd55eed99..0000000000 --- a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessToolchain.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using BenchmarkDotNet.Characteristics; -using BenchmarkDotNet.Running; -using BenchmarkDotNet.Validators; - -namespace BenchmarkDotNet.Toolchains.InProcess -{ - /// - /// A toolchain to run the benchmarks in-process. - /// - /// - [Obsolete("Please use BenchmarkDotNet.Toolchains.InProcess.NoEmit.* classes")] - public sealed class InProcessToolchain : IToolchain - { - /// The default toolchain instance. - public static readonly IToolchain Instance = new InProcessToolchain(true); - - /// The toolchain instance without output logging. - public static readonly IToolchain DontLogOutput = new InProcessToolchain(false); - - /// Initializes a new instance of the class. - /// true if the output should be logged. - public InProcessToolchain(bool logOutput) : this( - InProcessExecutor.DefaultTimeout, - BenchmarkActionCodegen.ReflectionEmit, - logOutput) - { - } - - /// Initializes a new instance of the class. - /// Timeout for the run. - /// Describes how benchmark action code is generated. - /// true if the output should be logged. - public InProcessToolchain(TimeSpan timeout, BenchmarkActionCodegen codegenMode, bool logOutput) - { - Generator = new InProcessGenerator(); - Builder = new InProcessBuilder(); - Executor = new InProcessExecutor(timeout, codegenMode, logOutput); - } - - /// Validates the specified benchmark. - /// The benchmark. - /// The resolver. - /// Collection of validation errors, when not empty means that toolchain does not support provided benchmark. - public IEnumerable Validate(BenchmarkCase benchmarkCase, IResolver resolver) => - InProcessValidator.Validate(benchmarkCase); - - /// Name of the toolchain. - /// The name of the toolchain. - public string Name => nameof(InProcessToolchain); - - /// The generator. - /// The generator. - public IGenerator Generator { get; } - - /// The builder. - /// The builder. - public IBuilder Builder { get; } - - /// The executor. - /// The executor. - public IExecutor Executor { get; } - - public bool IsInProcess => true; - - /// Returns a that represents this instance. - /// A that represents this instance. - public override string ToString() => GetType().Name; - } -} \ No newline at end of file diff --git a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessValidator.cs b/src/BenchmarkDotNet/Toolchains/InProcess/InProcessValidator.cs index 77cdcfe135..2e4f349b7f 100644 --- a/src/BenchmarkDotNet/Toolchains/InProcess/InProcessValidator.cs +++ b/src/BenchmarkDotNet/Toolchains/InProcess/InProcessValidator.cs @@ -14,7 +14,7 @@ namespace BenchmarkDotNet.Toolchains.InProcess { /// - /// Validator to be used together with + /// Validator to be used together with or /// to proof that the config matches the environment. /// /// @@ -81,9 +81,6 @@ private static string ValidatePlatform(Job job, Characteristic characteristic) private static string ValidateToolchain(Job job, Characteristic characteristic) => job.Infrastructure.Toolchain is InProcessEmitToolchain || job.Infrastructure.Toolchain is InProcessNoEmitToolchain -#pragma warning disable 618 - || job.Infrastructure.Toolchain is InProcessToolchain -#pragma warning restore 618 ? null : $"should be instance of {nameof(InProcessEmitToolchain)} or {nameof(InProcessNoEmitToolchain)}."; @@ -156,8 +153,8 @@ public IEnumerable Validate(ValidationParameters validationPara $"Target {target} has {nameof(target.AdditionalLogic)} filled. AdditionalLogic is not supported by in-process toolchain."); } - foreach (var benchmarkWithArguments in validationParameters.Benchmarks.Where(benchmark => benchmark.HasArguments)) - yield return new ValidationError(true, "Arguments are not supported by the InProcessToolchain yet, see #687 for more details", benchmarkWithArguments); + foreach (var benchmarkWithArguments in validationParameters.Benchmarks.Where(benchmark => benchmark.HasArguments && benchmark.GetToolchain() is InProcessNoEmitToolchain)) + yield return new ValidationError(true, "Arguments are not supported by the InProcessNoEmitToolchain, see #687 for more details", benchmarkWithArguments); foreach (var validationError in validationParameters.Config.GetJobs().SelectMany(job => ValidateJob(job, TreatsWarningsAsErrors))) yield return validationError; diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkAction.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkAction.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkAction.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkAction.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory_Base.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory_Base.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory_Base.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory_Base.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory_Dummy.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory_Dummy.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory_Dummy.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory_Dummy.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory_Implementations.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory_Implementations.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/BenchmarkActionFactory_Implementations.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/BenchmarkActionFactory_Implementations.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitBuilder.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitBuilder.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitBuilder.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitBuilder.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitExecutor.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitExecutor.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitExecutor.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitExecutor.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitGenerator.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitGenerator.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitGenerator.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitGenerator.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitRunner.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitRunner.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs diff --git a/src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitToolchain.cs b/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitToolchain.cs similarity index 100% rename from src/BenchmarkDotNet/Toolchains/InProcess.NoEmit/InProcessNoEmitToolchain.cs rename to src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitToolchain.cs diff --git a/tests/BenchmarkDotNet.IntegrationTests/InProcessTest.cs b/tests/BenchmarkDotNet.IntegrationTests/InProcessTest.cs index a5de2462f6..a06870ad5e 100644 --- a/tests/BenchmarkDotNet.IntegrationTests/InProcessTest.cs +++ b/tests/BenchmarkDotNet.IntegrationTests/InProcessTest.cs @@ -7,14 +7,13 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Columns; using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Engines; using BenchmarkDotNet.Environments; using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Loggers; using BenchmarkDotNet.Running; using BenchmarkDotNet.Tests.Loggers; -using BenchmarkDotNet.Toolchains.InProcess; +using BenchmarkDotNet.Toolchains.InProcess.NoEmit; using JetBrains.Annotations; using Xunit; using Xunit.Abstractions; @@ -66,7 +65,7 @@ public void BenchmarkDifferentPlatformReturnsValidationError() : Platform.X64; var otherPlatformConfig = new ManualConfig() - .With(Job.Dry.With(InProcessToolchain.Instance).With(otherPlatform)) + .With(Job.Dry.With(InProcessNoEmitToolchain.Instance).With(otherPlatform)) .With(new OutputLogger(Output)) .With(DefaultColumnProviders.Instance); @@ -83,15 +82,11 @@ private void TestInvoke(Expression> methodCall, int un var descriptor = new Descriptor(typeof(BenchmarkAllCases), targetMethod, targetMethod, targetMethod); // Run mode - var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.ReflectionEmit, unrollFactor); - TestInvoke(action, unrollFactor, false, null); - action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.DelegateCombine, unrollFactor); + var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), unrollFactor); TestInvoke(action, unrollFactor, false, null); // Idle mode - action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.ReflectionEmit, unrollFactor); - TestInvoke(action, unrollFactor, true, null); - action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.DelegateCombine, unrollFactor); + action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), unrollFactor); TestInvoke(action, unrollFactor, true, null); // GlobalSetup/GlobalCleanup @@ -121,9 +116,7 @@ private void TestInvoke(Expression> methodCall, in var descriptor = new Descriptor(typeof(BenchmarkAllCases), targetMethod); // Run mode - var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.ReflectionEmit, unrollFactor); - TestInvoke(action, unrollFactor, false, expectedResult); - action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.DelegateCombine, unrollFactor); + var action = BenchmarkActionFactory.CreateWorkload(descriptor, new BenchmarkAllCases(), unrollFactor); TestInvoke(action, unrollFactor, false, expectedResult); // Idle mode @@ -140,9 +133,7 @@ private void TestInvoke(Expression> methodCall, in else idleExpected = GetDefault(expectedResult.GetType()); - action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.ReflectionEmit, unrollFactor); - TestInvoke(action, unrollFactor, true, idleExpected); - action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), BenchmarkActionCodegen.DelegateCombine, unrollFactor); + action = BenchmarkActionFactory.CreateOverhead(descriptor, new BenchmarkAllCases(), unrollFactor); TestInvoke(action, unrollFactor, true, idleExpected); } @@ -189,48 +180,19 @@ private void TestInvoke(BenchmarkAction benchmarkAction, int unrollFactor, bool } } - private IConfig CreateInProcessConfig(BenchmarkActionCodegen codegenMode, OutputLogger logger = null, IDiagnoser diagnoser = null) + private IConfig CreateInProcessConfig(OutputLogger logger = null) { return new ManualConfig() - .AddJob(Job.Dry.WithToolchain(new InProcessToolchain(TimeSpan.Zero, codegenMode, true)).WithInvocationCount(UnrollFactor).WithUnrollFactor(UnrollFactor)) + .AddJob(Job.Dry.WithToolchain(new InProcessNoEmitToolchain(TimeSpan.Zero, true)).WithInvocationCount(UnrollFactor).WithUnrollFactor(UnrollFactor)) .AddLogger(logger ?? (Output != null ? new OutputLogger(Output) : ConsoleLogger.Default)) .AddColumnProvider(DefaultColumnProviders.Instance); } [Fact] - public void InProcessBenchmarkAllCasesReflectionEmitSupported() - { - var logger = new OutputLogger(Output); - var config = CreateInProcessConfig(BenchmarkActionCodegen.ReflectionEmit, logger); - - try - { - BenchmarkAllCases.Counter = 0; - - var summary = CanExecute(config); - - var testLog = logger.GetLog(); - Assert.Contains("// Benchmark: BenchmarkAllCases.InvokeOnceVoid:", testLog); - Assert.DoesNotContain("No benchmarks found", logger.GetLog()); - - // Operations + GlobalSetup + GlobalCleanup - long expectedCount = summary.Reports - .SelectMany(r => r.AllMeasurements) - .Where(m => m.IterationStage != IterationStage.Result) - .Sum(m => m.Operations + 2); - Assert.Equal(expectedCount, BenchmarkAllCases.Counter); - } - finally - { - BenchmarkAllCases.Counter = 0; - } - } - - [Fact] - public void InProcessBenchmarkAllCasesDelegateCombineSupported() + public void InProcessBenchmarkAllCasesSupported() { var logger = new OutputLogger(Output); - var config = CreateInProcessConfig(BenchmarkActionCodegen.DelegateCombine, logger); + var config = CreateInProcessConfig(logger); try {