Microsoft MVP성태의 닷넷 이야기
.NET Framework: 768. BenchmarkDotNet으로 Span<T> 성능 측정 [링크 복사], [링크+제목 복사],
조회: 21189
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

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




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/13/2018]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2020-10-07 09시31분
[HelloWorld] 안녕하세요. 글 잘 읽고 갑니다. 해당 내용 기반으로 성능 테스트를 해보니 위와 같은 결과가 나오지 않아서요. 실행환경은 .Net Framework 4.7, WPF Proejct입니다.
저의 경우는 SpanLoopTest의 속도가 2배가까이 느린걸로 나왔네요. 코드는 위와 동일하게 사용했습니다.!

| Method | N | Mean | Error | StdDev |
|------------- |------ |-----------:|---------:|---------:|
| ForLoopTest | 1000 | 311.9 ns | 1.77 ns | 1.66 ns |
| SpanLoopTest | 1000 | 933.4 ns | 4.00 ns | 3.74 ns |
| PtrLoopTest | 1000 | 328.6 ns | 6.33 ns | 7.54 ns |
| ForLoopTest | 10000 | 3,061.8 ns | 15.41 ns | 13.66 ns |
| SpanLoopTest | 10000 | 9,336.1 ns | 72.35 ns | 67.67 ns |
| PtrLoopTest | 10000 | 3,233.0 ns | 41.69 ns | 38.99 ns |
[guest]
2020-10-07 09시56분
(본문에 언급해 두었던) 아래의 글에 이미 설명을 했었습니다.

C# - System.Span<T> 성능
; https://www.sysnet.pe.kr/2/0/11535
정성태

... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
13577정성태3/9/202411953닷넷: 2229. C# - 닷넷을 위한 난독화 도구 소개 (예: ConfuserEx)
13576정성태3/8/202411791닷넷: 2228. .NET Profiler - IMetaDataEmit2::DefineMethodSpec 사용법
13575정성태3/7/202412470닷넷: 2227. 최신 C# 문법을 .NET Framework 프로젝트에 쓸 수 있을까요?
13574정성태3/6/202411924닷넷: 2226. C# - "Docker Desktop for Windows" Container 환경에서의 IPv6 DualMode 소켓
13573정성태3/5/202410515닷넷: 2225. Windbg - dumasync로 분석하는 async/await 호출
13572정성태3/4/202410404닷넷: 2224. C# - WPF의 Dispatcher Queue로 알아보는 await 호출의 hang 현상파일 다운로드1
13571정성태3/1/202410370닷넷: 2223. C# - await 호출과 WPF의 Dispatcher Queue 동작 확인파일 다운로드1
13570정성태2/29/202411605닷넷: 2222. C# - WPF의 Dispatcher Queue 동작 확인파일 다운로드1
13569정성태2/28/202411362닷넷: 2221. C# - LoadContext, LoadFromContext 그리고 GAC파일 다운로드1
13568정성태2/27/202411189닷넷: 2220. C# - .NET Framework 프로세스의 LoaderOptimization 설정을 확인하는 방법파일 다운로드1
13567정성태2/27/202411113오류 유형: 898. .NET Framework 3.5 이하에서 mscoree.tlb 참조 시 System.BadImageFormatException파일 다운로드1
13566정성태2/27/202411071오류 유형: 897. Windows 7 SDK 설치 시 ".NET Development" 옵션이 비활성으로 선택이 안 되는 경우
13565정성태2/23/20249539닷넷: 2219. .NET CLR2 보안 모델에서의 개별 System.Security.Permissions 제어
13564정성태2/22/202411611Windows: 259. Hyper-V Generation 1 유형의 VM을 Generation 2 유형으로 바꾸는 방법
13563정성태2/21/202410999디버깅 기술: 196. windbg - async/await 비동기인 경우 메모리 덤프 분석의 어려움
13562정성태2/21/202410234오류 유형: 896. ASP.NET - .NET Framework 기본 예제에서 System.Web에 대한 System.IO.FileNotFoundException 예외 발생
13561정성태2/20/202411379닷넷: 2218. C# - (예를 들어, Socket) 비동기 I/O에 대한 await 호출 시 CancellationToken을 이용한 취소파일 다운로드1
13560정성태2/19/202411419디버깅 기술: 195. windbg 분석 사례 - Semaphore 잠금으로 인한 Hang 현상 (닷넷)
13559정성태2/19/202412567오류 유형: 895. ASP.NET - System.Security.SecurityException: 'Requested registry access is not allowed.'
13558정성태2/18/202411656닷넷: 2217. C# - 최댓값이 1인 SemaphoreSlim 보다 Mutex 또는 lock(obj)를 선택하는 것이 나은 이유
13557정성태2/18/20249788Windows: 258. Task Scheduler의 Author 속성 값을 변경하는 방법
13556정성태2/17/202410932Windows: 257. Windows - Symbolic (hard/soft) Link 및 Junction 차이점
13555정성태2/15/202411040닷넷: 2216. C# - SemaphoreSlim 사용 시 주의점
13554정성태2/15/202410350VS.NET IDE: 189. Visual Studio - 닷넷 소스코드 디컴파일 찾기가 안 될 때
13553정성태2/14/20249461닷넷: 2215. windbg - thin/fat lock 없이 동작하는 Monitor.Wait + Pulse
13552정성태2/13/20249635닷넷: 2214. windbg - Monitor.Enter의 thin lock과 fat lock
... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...