성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>BenchmarkDotNet 사용 시 주의 사항</h1> <p> BenchmarkDotNet으로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > BenchmarkDotNet 라이브러리 소개 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11547'>http://www.sysnet.pe.kr/2/0/11547</a> </pre> <br /> struct 타입을 좀 더 테스트해봤습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# 7.2의 특징 - GC 및 메모리 복사 방지를 위한 struct 타입 개선 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11546'>http://www.sysnet.pe.kr/2/0/11546</a> </pre> <br /> 성능 비교를 위해 다음의 타입들을 생성하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ClassVector : class로 구현 StructVector : struct로 구현 InStructVector : StructVector이고, op_Addition 메서드의 인자를 in 처리 ReadonlyInStructVector : InStructVector이고, readonly struct로 정의 ReadonlyInlineStructVector : ReadonlyInStructVector이고, op_Addition에 AggressiveInlining 특성 부여 </pre> <br /> 각각의 타입에 대해 op_Addition을 테스트하는 코드만을 Benchmark에 추가했습니다.<br /> <br /> <pre style='height: 400px; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public class VectorBenchmark { [Benchmark] public void ClassVectorTest() { var player = new ClassVector(10.0, 20.0, 30.0); var speed = new ClassVector(10.0, 20.0, 30.0); var result = player + speed; } [Benchmark] public void StructVectorTest() { var player = new StructVector(10.0, 20.0, 30.0); var speed = new StructVector(10.0, 20.0, 30.0); var result = player + speed; } [Benchmark] public void InStructVectorTest() { var player = new InStructVector(10.0, 20.0, 30.0); var speed = new InStructVector(10.0, 20.0, 30.0); var result = player + speed; } [Benchmark] public void ReadonlyInStructVectorTest() { var player = new ReadonlyInStructVector(10.0, 20.0, 30.0); var speed = new ReadonlyInStructVector(10.0, 20.0, 30.0); var result = player + speed; } [Benchmark] public void ReadonlyInlineStructVectorTest() { var player = new ReadonlyInlineStructVector(10.0, 20.0, 30.0); var speed = new ReadonlyInlineStructVector(10.0, 20.0, 30.0); var result = player + speed; } } </pre> <br /> 결과는 이렇습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // * 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 [Host] : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3101.0 DefaultJob : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3101.0 Method | Mean | Error | StdDev | ----------------------------------- |-----------:|----------:|----------:| ClassVectorTest | 13.7698 ns | 0.1722 ns | 0.1611 ns | StructVectorTest | 2.5874 ns | 0.0320 ns | 0.0299 ns | InStructVectorTest | 10.5442 ns | 0.0892 ns | 0.0834 ns | ReadonlyInStructVectorTest | 10.2489 ns | 0.0843 ns | 0.0788 ns | ReadonlyInlineStructVectorTest | 0.5599 ns | 0.0106 ns | 0.0099 ns | </pre> <br /> 메서드가 inline 처리된 StructVectorTest, ReadonlyInlineStructVectorTest의 성능이 우세한 것은 당연해 보이고, 또한 그 둘 중에서도 복사가 발생하지 않는 ReadonlyInlineStructVectorTest의 성능이 좀 더 높게 나옵니다.<br /> <br /> 이 상태에서 테스트 코드마다 GetHashCode 호출을 추가했더니,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public void ...VectorTest() { var player = new ...Vector(10.0, 20.0, 30.0); var speed = new ...Vector(10.0, 20.0, 30.0); var result = player + speed; <span style='color: blue; font-weight: bold'>result.GetHashCode();</span> } </pre> <br /> 단지 하나의 코드를 추가했을 뿐인데 이제 결과가 완전히 달라집니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Method | Mean | Error | StdDev | ----------------------------------- |-----------:|----------:|----------:| ClassVectorTest | 34.8412 ns | 0.2300 ns | 0.2151 ns | StructVectorTest | 47.8031 ns | 0.3171 ns | 0.2966 ns | InStructVectorTest | 53.4127 ns | 1.2505 ns | 1.4401 ns | ReadonlyInStructVectorTest | 52.1917 ns | 0.3648 ns | 0.3412 ns | ReadonlyInlineStructVectorTest | 39.5150 ns | 0.2622 ns | 0.2452 ns | </pre> <br /> 확인은 해보지 않았지만, GetHashCode 시 값 형식에서 object.GetHashCode 호출로 인한 내부 박싱이 발생해 힙을 사용하도록 변경된 것이 아닌가 예상됩니다. 일단 그건 그렇다 치고, 문제는 모든 Vector 코드에 GetHashCode를 다음과 같이 직접 구현했을 때 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public override int GetHashCode() { return (int)(_x + _y + _z); } </pre> <br /> 그럼, 각각의 결과물들이 다음과 같이 바뀝니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // GetHashCode() 추가 Method | Mean | Error | StdDev | ----------------------------------- |-----------:|----------:|----------:| ClassVectorTest | 15.7360 ns | 0.1863 ns | 0.1651 ns | StructVectorTest | 10.0317 ns | 0.0746 ns | 0.0623 ns | InStructVectorTest | 12.0021 ns | 0.0687 ns | 0.0643 ns | ReadonlyInStructVectorTest | 11.8757 ns | 0.1092 ns | 0.1022 ns | ReadonlyInlineStructVectorTest | 0.0000 ns | 0.0000 ns | 0.0000 ns | </pre> <br /> ReadonlyInlineStructVectorTest의 결과가 놀라운데요, 어떻게 저럴 수 있을까요? 저 때의 JIT 코드를 windbg로 살펴보면 다음과 같이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>!DumpMD /d</span> 00007ffa11f47790 Method Name: ConsoleApp1.VectorBenchmark.ReadonlyInlineStructVectorTest() Class: 00007ffa11f54858 MethodTable: 00007ffa11f477a8 mdToken: 0000000006000007 Module: 00007ffa11f470d0 IsJitted: yes <span style='color: blue; font-weight: bold'>CodeAddr: 00007ffa11ea6450</span> Transparency: Critical 0:000> <span style='color: blue; font-weight: bold'>!U /d 00007ffa11ea6450</span> Normal JIT generated code ConsoleApp1.VectorBenchmark.ReadonlyInlineStructVectorTest() <span style='color: blue; font-weight: bold'>Begin 00007ffa11ea6450, size 1 >>> 00007ffa`11ea6450 c3 ret</span> </pre> <br /> 보는 바와 같이 정상적인 테스트 코드를 생성하지 못하고 ret만 포함하는 메서드로 테스트하고 있는 것입니다. 따라서 BenchmarkDotNet으로 성능 측정을 할 때는 그 자체의 버그나 Release 모드에서의 최적화에 따른 의도치 않은 코드 삭제를 주의해야 합니다.<br /> <br /> 게다가 전통적인 Stopwatch를 이용할 때는 Visual Studio 내에서 disassembly 코드를 보며 곧바로 확인할 수 있는 여지가 있는데, BenchmarkDotNet으로 하게 되면 ConsoleApp1.exe의 자식 프로세스로 임시 exe 프로세스를 생성시켜 성능 측정을 하기 때문에 그런 부분을 파헤치기가 불편한 점도 있습니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1225
(왼쪽의 숫자를 입력해야 합니다.)