Skip to content

Conversation

@stephentoub
Copy link
Member

  • It's commonly used with zero args; we can use Type.EmptyTypes rather than new Type[0]
  • It calls GetConstructors, which internally uses ListBuilder and then resizes if the created array isn't filled, but since we don't need the correctly sized array, we can just use the ListBuilder and avoid the resize
  • It creates a List and then ToArray's it, but if none of the constructors are filtered out, it's better to just use the array we built up directly.
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Reflection;

[MemoryDiagnoser]
public class Program
{
    static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);

    [Benchmark] public void OneZero() => Activator.CreateInstance(typeof(OneCtorZeroArgs), BindingFlags.NonPublic | BindingFlags.Instance, null, Array.Empty<object>(), null);
    [Benchmark] public void OneOne() => Activator.CreateInstance(typeof(OneCtorOneArg), BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { "hello" }, null);
    [Benchmark] public void TwoOne() => Activator.CreateInstance(typeof(TwoCtorOneArg), BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { "hello" }, null);

    internal class OneCtorZeroArgs
    {
        internal OneCtorZeroArgs() { }
    }

    internal class OneCtorOneArg
    {
        internal OneCtorOneArg(string s) { }
    }

    internal class TwoCtorOneArg
    {
        internal TwoCtorOneArg(string s) { }
        internal TwoCtorOneArg(object o) { }
    }
}
Method Toolchain Mean Ratio Allocated
OneZero \main\corerun.exe 181.2 ns 1.00 320 B
OneZero \pr\corerun.exe 148.0 ns 0.82 200 B
OneOne \main\corerun.exe 346.0 ns 1.00 376 B
OneOne \pr\corerun.exe 306.9 ns 0.88 280 B
TwoOne \main\corerun.exe 427.5 ns 1.00 456 B
TwoOne \pr\corerun.exe 414.7 ns 0.97 384 B

- It's commonly used with zero args; we can use Type.EmptyTypes rather than new Type[0]
- It calls GetConstructors, which internally uses ListBuilder and then resizes if the created array isn't filled, but since we don't need the correctly sized array, we can just use the ListBuilder and avoid the resize
- It creates a List and then ToArray's it, but if none of the constructors are filtered out, it's better to just use the array we built up directly.
@ghost ghost assigned stephentoub Mar 25, 2022
@ghost
Copy link

ghost commented Mar 25, 2022

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details
  • It's commonly used with zero args; we can use Type.EmptyTypes rather than new Type[0]
  • It calls GetConstructors, which internally uses ListBuilder and then resizes if the created array isn't filled, but since we don't need the correctly sized array, we can just use the ListBuilder and avoid the resize
  • It creates a List and then ToArray's it, but if none of the constructors are filtered out, it's better to just use the array we built up directly.
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Reflection;

[MemoryDiagnoser]
public class Program
{
    static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);

    [Benchmark] public void OneZero() => Activator.CreateInstance(typeof(OneCtorZeroArgs), BindingFlags.NonPublic | BindingFlags.Instance, null, Array.Empty<object>(), null);
    [Benchmark] public void OneOne() => Activator.CreateInstance(typeof(OneCtorOneArg), BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { "hello" }, null);
    [Benchmark] public void TwoOne() => Activator.CreateInstance(typeof(TwoCtorOneArg), BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { "hello" }, null);

    internal class OneCtorZeroArgs
    {
        internal OneCtorZeroArgs() { }
    }

    internal class OneCtorOneArg
    {
        internal OneCtorOneArg(string s) { }
    }

    internal class TwoCtorOneArg
    {
        internal TwoCtorOneArg(string s) { }
        internal TwoCtorOneArg(object o) { }
    }
}
Method Toolchain Mean Ratio Allocated
OneZero \main\corerun.exe 181.2 ns 1.00 320 B
OneZero \pr\corerun.exe 148.0 ns 0.82 200 B
OneOne \main\corerun.exe 346.0 ns 1.00 376 B
OneOne \pr\corerun.exe 306.9 ns 0.88 280 B
TwoOne \main\corerun.exe 427.5 ns 1.00 456 B
TwoOne \pr\corerun.exe 414.7 ns 0.97 384 B
Author: stephentoub
Assignees: stephentoub
Labels:

area-System.Reflection

Milestone: -

@stephentoub stephentoub added this to the 7.0.0 milestone Mar 25, 2022
@stephentoub stephentoub merged commit 0c0c7c6 into dotnet:main Mar 25, 2022
@stephentoub stephentoub deleted the createinstancealloc branch March 25, 2022 20:38
radekdoulik pushed a commit to radekdoulik/runtime that referenced this pull request Mar 30, 2022
…tnet#67148)

- It's commonly used with zero args; we can use Type.EmptyTypes rather than new Type[0]
- It calls GetConstructors, which internally uses ListBuilder and then resizes if the created array isn't filled, but since we don't need the correctly sized array, we can just use the ListBuilder and avoid the resize
- It creates a List and then ToArray's it, but if none of the constructors are filtered out, it's better to just use the array we built up directly.
@ghost ghost locked as resolved and limited conversation to collaborators Apr 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants