Created
March 31, 2018 03:02
-
-
Save ufcpp/79283511d2a10afb34f8c5c837dce1a6 to your computer and use it in GitHub Desktop.
Enum.HasFlag(Enum) のパフォーマンスの測定
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
using BenchmarkDotNet.Configs; | |
using BenchmarkDotNet.Jobs; | |
using BenchmarkDotNet.Toolchains.CsProj; | |
using BenchmarkDotNet.Columns; | |
using BenchmarkDotNet.Diagnosers; | |
using BenchmarkDotNet.Exporters; | |
using BenchmarkDotNet.Loggers; | |
using System; | |
[Flags] | |
enum X | |
{ | |
A = 1, | |
B = 2, | |
C = 3, | |
} | |
/// <summary> | |
/// <see cref="System.Enum.HasFlag(Enum)"/> のパフォーマンスの測定。 | |
/// | |
/// .NET では、「すべての enum は System.Enum クラスから派生している “かのようにふるまう”」という仕様があるものの。 | |
/// このために、単なる整数である enum が、Enum クラスにボックス化してる。 | |
/// <see cref="Enum.HasFlag(Enum)"/> も、x.HasFlag(y) って書くと、ボックス化が発生するし、 | |
/// 内部的にも実行型チェックが走ってるみたいでものすごい遅い。 | |
/// 遅かった。 | |
/// | |
/// .NET Core 2.1 では、これを、JIT 時特殊対応したらしくて、速くなってる。 | |
/// 「<see cref="Enum.HasFlag(Enum)"/> が呼ばれてたらそこを単なる比較演算に置き換える」っていう処理を入れたらしい。 | |
/// ボックス化とかの実行時処理が一切消えるので、余裕で1桁速くなる。 | |
/// 参考: https://github.com/dotnet/coreclr/blob/master/tests/src/JIT/opt/Enum/hasflag.cs#L7 | |
/// | |
/// ベンチマーク実行結果の一例: | |
/// Method | Toolchain | Mean | Error | StdDev | Gen 0 | Allocated | | |
/// -------- |-------------- |-----------:|----------:|----------:|-------:|----------:| | |
/// HasFlag | .NET Core 2.0 | 208.555 ns | 0.8816 ns | 0.7815 ns | 0.1371 | 576 B | | |
/// HasFlag | .NET Core 2.1 | 7.781 ns | 0.0831 ns | 0.0777 ns | - | 0 B | | |
/// | |
/// .NET Core 2.0 と 2.1 で20倍以上差がある。 | |
/// </summary> | |
public class HasFlagBenchmark | |
{ | |
[Benchmark] | |
public void HasFlag() | |
{ | |
Count(X.A); | |
Count(X.A | X.B); | |
Count(X.A | X.C); | |
Count(X.A | X.B | X.C); | |
} | |
private int Count(X x) | |
{ | |
var count = 0; | |
if (x.HasFlag(X.A)) count++; | |
if (x.HasFlag(X.B)) count++; | |
if (x.HasFlag(X.C)) count++; | |
return count; | |
} | |
} | |
class Program | |
{ | |
static void Main() | |
{ | |
BenchmarkRunner.Run<HasFlagBenchmark>(new MultipleRuntimesConfig()); | |
} | |
} | |
public class MultipleRuntimesConfig : ManualConfig | |
{ | |
public MultipleRuntimesConfig() | |
{ | |
Add(Job.Default.With(CsProjCoreToolchain.NetCoreApp20)); | |
Add(Job.Default.With(CsProjCoreToolchain.NetCoreApp21)); | |
Add(DefaultColumnProviders.Instance); | |
Add(MarkdownExporter.GitHub); | |
Add(new ConsoleLogger()); | |
Add(new HtmlExporter()); | |
Add(MemoryDiagnoser.Default); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment