Microsoft MVP성태의 닷넷 이야기
.NET Framework: 768. BenchmarkDotNet으로 Span<T> 성능 측정 [링크 복사], [링크+제목 복사]
조회: 13381
글쓴 사람
정성태 (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
정성태

... 31  [32]  33  34  35  36  37  38  39  40  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
12821정성태9/1/20217506.NET Framework: 1112. C# - .NET 6부터 공개된 ISpanFormattable 사용법
12820정성태9/1/20217811VC++: 147. Golang - try/catch에 대응하는 panic/recover [1]파일 다운로드1
12819정성태8/31/20217932.NET Framework: 1111. C# - FormattableString 타입
12818정성태8/31/20217155Windows: 198. 윈도우 - 작업 관리자에서 (tensorflow 등으로 인한) GPU 연산 부하 보는 방법
12817정성태8/31/20219688스크립트: 25. 파이썬 - 윈도우 환경에서 directml을 이용한 tensorflow의 AMD GPU 사용 방법
12816정성태8/30/202115112스크립트: 24. 파이썬 - tensorflow 2.6 NVidia GPU 사용 방법 [2]
12815정성태8/30/20218247개발 환경 구성: 602. WSL 2 - docker-desktop-data, docker-desktop (%LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx) 파일을 다른 디렉터리로 옮기는 방법
12814정성태8/30/202110530.NET Framework: 1110. C# 11 - 인터페이스 내에 정적 추상 메서드 정의 가능 (DIM for Static Members) [2]파일 다운로드1
12813정성태8/29/20218757.NET Framework: 1109. C# 10 - (11) Lambda 개선파일 다운로드1
12812정성태8/28/20218394.NET Framework: 1108. C# 10 - (10) 개선된 #line 지시자
12811정성태8/27/20218604Linux: 44. 윈도우 개발자를 위한 리눅스 fork 동작 방식 설명 (파이썬 코드)
12810정성태8/27/20217390.NET Framework: 1107. .NET Core/5+에서 동적 컴파일한 C# 코드를 (Breakpoint도 활용하며) 디버깅하는 방법 - #line 지시자파일 다운로드1
12809정성태8/26/20218042.NET Framework: 1106. .NET Core/5+에서 C# 코드를 동적으로 컴파일/사용하는 방법 [1]파일 다운로드1
12808정성태8/25/20219297오류 유형: 758. go: ...: missing go.sum entry; to add it: go mod download ...
12807정성태8/25/20219240.NET Framework: 1105. C# 10 - (9) 비동기 메서드가 사용할 AsyncMethodBuilder 선택 가능파일 다운로드1
12806정성태8/24/20216864개발 환경 구성: 601. PyCharm - 다중 프로세스 디버깅 방법
12805정성태8/24/20218108.NET Framework: 1104. C# 10 - (8) 분해 구문에서 기존 변수의 재사용 가능파일 다운로드1
12804정성태8/24/20218925.NET Framework: 1103. C# 10 - (7) Source Generator V2 APIs
12803정성태8/23/20218432개발 환경 구성: 600. pip cache 디렉터리 옮기는 방법
12802정성태8/23/20218786.NET Framework: 1102. .NET Conf Mini 21.08 - WinUI 3 따라해 보기 [1]
12801정성태8/23/20218289.NET Framework: 1101. C# 10 - (6) record class 타입의 ToString 메서드를 sealed 처리 허용파일 다운로드1
12800정성태8/22/20218510개발 환경 구성: 599. PyCharm - (반대로) 원격 프로세스가 PyCharm에 디버그 연결하는 방법
12799정성태8/22/20218604.NET Framework: 1100. C# 10 - (5) 속성 패턴의 개선파일 다운로드1
12798정성태8/21/20219886개발 환경 구성: 598. PyCharm - 원격 프로세스를 디버그하는 방법
12797정성태8/21/20217618Windows: 197. TCP의 MSS(Maximum Segment Size) 크기는 고정된 것일까요?
12796정성태8/21/20218298.NET Framework: 1099. C# 10 - (4) 상수 문자열에 포맷 식 사용 가능파일 다운로드1
... 31  [32]  33  34  35  36  37  38  39  40  41  42  43  44  45  ...