BenchmarkDotNet으로 Span<T> 성능 측정
BenchmarkDotNet으로,
BenchmarkDotNet 라이브러리 소개
; https://www.sysnet.pe.kr/2/0/11547
(하다 보니 재미있어서) 이번에는 지난 글의 Span 타입의 성능을 다시 측정해 봤습니다. ^^
C# - System.Span<T> 성능
; https://www.sysnet.pe.kr/2/0/11535
Benchmark 소스 코드는 다음과 같은데,
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Runtime.InteropServices;
namespace spanBenchmark
{
class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<LoopTest>();
}
}
public class LoopTest
{
private byte[] data;
[Params(1000, 10000)]
public int N;
[GlobalSetup]
public void Setup()
{
data = new byte[N];
new Random(42).NextBytes(data);
}
[Benchmark]
public void ForLoopTest()
{
MyLoop.ForLoop(data);
}
[Benchmark]
public void SpanLoopTest()
{
MyLoop.SpanLoop(data);
}
[Benchmark]
public void PtrLoopTest()
{
MyLoop.PtrLoop(data);
}
}
class MyLoop
{
public static int ForLoop(byte[] buffer)
{
int sum = 0;
for (int i = 0; i < buffer.Length; i++)
{
sum += buffer[i];
}
return sum;
}
public static int SpanLoop(byte[] buffer)
{
Span<byte> span = buffer;
int sum = 0;
for (int i = 0; i < span.Length; i++)
{
sum += span[i];
}
return sum;
}
public static unsafe int PtrLoop(byte[] buffer)
{
int sum = 0;
fixed (byte* ptr = buffer)
{
for (int i = 0; i < buffer.Length; i++)
{
sum += *(ptr + i);
}
}
return sum;
}
}
}
보는 바와 같이 이번에는 Params와 GlobalSetup 특성도 사용해 봤습니다. ^^ 다음은 그 결과입니다.
// * Summary *
BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134
Intel Core i5-4670 CPU 3.40GHz (Haswell), 1 CPU, 4 logical and 4 physical cores
.NET Core SDK=2.2.0-preview1-007877
[Host] : .NET Core 2.1.0 (CoreCLR 4.6.26515.07, CoreFX 4.6.26515.06), 64bit RyuJIT
DefaultJob : .NET Core 2.1.0 (CoreCLR 4.6.26515.07, CoreFX 4.6.26515.06), 64bit RyuJIT
Method | N | Mean | Error | StdDev |
------------- |------ |-----------:|----------:|----------:|
ForLoopTest | 1000 | 435.1 ns | 7.530 ns | 8.370 ns |
SpanLoopTest | 1000 | 447.5 ns | 3.363 ns | 2.808 ns |
PtrLoopTest | 1000 | 435.2 ns | 3.598 ns | 3.004 ns |
ForLoopTest | 10000 | 4,300.5 ns | 37.432 ns | 35.013 ns |
SpanLoopTest | 10000 | 4,416.1 ns | 82.525 ns | 73.156 ns |
PtrLoopTest | 10000 | 4,296.7 ns | 28.328 ns | 26.498 ns |
Params 특성에 따라 N에 따른 배열의 크기가 1000, 10000인 경우로 나뉘어 측정이 되었습니다. 이번 결과에서도 확인이 되지만 공용 indexer 속성을 통해 제공하는 Span 타입의 액세스가,
Span<byte> span = buffer;
int sum = 0;
for (int i = 0; i < span.Length; i++)
{
sum += span[i];
}
배열 인스턴스로 다루는 것과 비교해도 밀리지 않는 성능을 보이고 있습니다.
참고로 BenchmarkDotNet은 테스트 이후의 결과물을 \bin\Release\ 폴더 하위에 \BenchmarkDotNet.Artifacts\results 폴더로 csv, html, md 파일 포맷으로 함께 출력해 줍니다.
또한 RPlotExporter 특성을 적용해 주면,
[RPlotExporter]
public class LoopTest
{
...[생략]...
}
다양한 그래픽 출력을 해주는 R 스크립트 파일을 \results 폴더에 생성해 줍니다. 이 파일을 실행해 보고 싶다면 다음의 글에 따라 구성을 하면 됩니다.
BenchmarkDotNet에서 생성한 BuildPlots.R 파일을 실행하는 방법
; https://www.sysnet.pe.kr/2/0/11549
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]