Closed4
ModuleInitializerとstaticコンストラクターで性能比較
モジュール初期化子 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C
(静的コンストラクターは「マルチスレッド実行時でも1回限り呼ぶ」という処理が必要で、通常のメソッド呼び出しよりも少し負担が大きい。モジュール初期化子はその負担が1回だけで済む)
Benchmark.cs
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using System;
using System.Runtime.CompilerServices;
namespace StaticCtorBenchMark
{
internal class BenchmarkConfig : ManualConfig
{
public BenchmarkConfig()
{
AddJob(Job.ShortRun.WithRuntime(ClrRuntime.Net48));
AddJob(Job.ShortRun.WithRuntime(CoreRuntime.Core31));
AddJob(Job.ShortRun.WithRuntime(CoreRuntime.Core50));
}
}
class Program
{
static void Main(string[] args)
{
_ = BenchmarkSwitcher.FromTypes(new[] { typeof(StaticCtorVsModuleInit) }).Run();
}
}
[Config(typeof(BenchmarkConfig))]
[DisassemblyDiagnoser]
public unsafe class StaticCtorVsModuleInit
{
internal class StaticCtor
{
public static Random r;
static StaticCtor()
{
r = new Random();
}
public static int NextInt() => r.Next();
}
internal class ModuleInit
{
public static Random r;
[ModuleInitializer]
internal static void Init()
{
r = new Random();
}
public static int NextInt() => r.Next();
}
[Benchmark()]
public int ModuleInitAccess() => ModuleInit.NextInt();
[Benchmark(Baseline = true)]
public int StaticCtorAccess() => StaticCtor.NextInt();
}
}
#if !NET5_0
namespace System.Runtime.CompilerServices
{
[System.AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class ModuleInitializerAttribute : System.Attribute
{
}
}
#endif
StaticCtorBenchMark.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net48;netcoreapp3.1;net5.0</TargetFrameworks>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>
</Project>
あんまり変わらない。
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19042
AMD Ryzen 7 3700X, 1 CPU, 8 logical and 8 physical cores
.NET Core SDK=6.0.100-preview.1.21103.13
[Host] : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
ShortRun : .NET Framework 4.8 (4.8.4341.0), X64 RyuJIT
Job=ShortRun IterationCount=3 LaunchCount=1
WarmupCount=3
| Method | Runtime | Mean | Error | StdDev | Ratio | Code Size |
|----------------- |-------------- |---------:|----------:|----------:|------:|----------:|
| ModuleInitAccess | .NET 4.8 | 6.992 ns | 0.7303 ns | 0.0400 ns | 0.97 | 33 B |
| StaticCtorAccess | .NET 4.8 | 7.203 ns | 0.4652 ns | 0.0255 ns | 1.00 | 40 B |
| | | | | | | |
| ModuleInitAccess | .NET Core 3.1 | 6.898 ns | 0.7025 ns | 0.0385 ns | 1.05 | 27 B |
| StaticCtorAccess | .NET Core 3.1 | 6.545 ns | 0.5424 ns | 0.0297 ns | 1.00 | 27 B |
| | | | | | | |
| ModuleInitAccess | .NET Core 5.0 | 6.618 ns | 0.2620 ns | 0.0144 ns | 1.00 | 27 B |
| StaticCtorAccess | .NET Core 5.0 | 6.628 ns | 0.3717 ns | 0.0204 ns | 1.00 | 27 B |
.NET Framework 4.8 (4.8.4341.0), X64 RyuJIT
; StaticCtorBenchMark.StaticCtorVsModuleInit.ModuleInitAccess()
sub rsp,28
mov rcx,254B0339F38
mov rcx,[rcx]
mov rax,[rcx]
mov rax,[rax+40]
call qword ptr [rax+28]
nop
add rsp,28
ret
; Total bytes of code 33
.NET Framework 4.8 (4.8.4341.0), X64 RyuJIT
; StaticCtorBenchMark.StaticCtorVsModuleInit.StaticCtorAccess()
mov rax,offset StaticCtorBenchMark.StaticCtorVsModuleInit+StaticCtor.NextInt()
jmp rax
; Total bytes of code 13
; StaticCtorBenchMark.StaticCtorVsModuleInit+StaticCtor.NextInt()
mov rcx,1E672CA9F30
mov rcx,[rcx]
mov rax,[rcx]
mov rax,[rax+40]
mov rax,[rax+28]
jmp rax
; Total bytes of code 27
.NET Core 3.1.12 (CoreCLR 4.700.21.6504, CoreFX 4.700.21.6905), X64 RyuJIT
; StaticCtorBenchMark.StaticCtorVsModuleInit.ModuleInitAccess()
mov rcx,1902B387398
mov rcx,[rcx]
mov rax,[rcx]
mov rax,[rax+40]
mov rax,[rax+28]
jmp rax
; Total bytes of code 27
.NET Core 3.1.12 (CoreCLR 4.700.21.6504, CoreFX 4.700.21.6905), X64 RyuJIT
; StaticCtorBenchMark.StaticCtorVsModuleInit.StaticCtorAccess()
mov rcx,22090007390
mov rcx,[rcx]
mov rax,[rcx]
mov rax,[rax+40]
mov rax,[rax+28]
jmp rax
; Total bytes of code 27
.NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
; StaticCtorBenchMark.StaticCtorVsModuleInit.ModuleInitAccess()
mov rcx,17A10007328
mov rcx,[rcx]
mov rax,[rcx]
mov rax,[rax+40]
mov rax,[rax+28]
jmp rax
; Total bytes of code 27
.NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
; StaticCtorBenchMark.StaticCtorVsModuleInit.StaticCtorAccess()
mov rcx,1A94F9C7320
mov rcx,[rcx]
mov rax,[rcx]
mov rax,[rax+40]
mov rax,[rax+28]
jmp rax
; Total bytes of code 27
このスクラップは2021/03/07にクローズされました