성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] 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...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
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'>.NET 8 - Dynamic PGO를 결합한 성능 향상</h1> <p> 이번 .NET Conf 2023의 내용을 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Dynamic PGO (개요) ; <a target='tab' href='https://youtu.be/xEFO1sQ2bUc?t=14689'>https://youtu.be/xEFO1sQ2bUc?t=14689</a> Dynamic PGO (상세) ; <a target='tab' href='https://www.youtube.com/watch?v=WrpYcGic9b8'>https://www.youtube.com/watch?v=WrpYcGic9b8</a> </pre> <br /> Dynamic PGO(Profile Guided Optimization)를 결합한 성능 향상을 소개하고 있습니다. 사실 이 글에서 소개하는 모든 옵션은 .NET 7에서도 쓸 수 있으니, <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Performance Improvements in .NET 7 ; <a target='tab' href='https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/'>https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/</a> </pre> <br /> 단지 성능을 더 높인 정도라고 봐야 합니다. 정말 그런지 한번 실습해 볼까요? ^^<br /> <br /> <hr style='width: 50%' /><br /> <br /> 성능 비교를 위해 아래의 예제 코드로 각각 .NET 7, .NET 8 프로젝트를 만들고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET Conf 2023 예제 코드 - Dynamic PGO // <a target='tab' href='https://youtu.be/xEFO1sQ2bUc?t=14689'>https://youtu.be/xEFO1sQ2bUc?t=14689</a> using System.Diagnostics; using System.Runtime.CompilerServices; namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { var list = new List<int>(); Stopwatch sw = Stopwatch.StartNew(); for (int loop = 0; loop < 3; loop++) { sw.Restart(); <span style='color: blue; font-weight: bold'>for (int i = 0; i < 1_000_000_000; i++)</span> { <span style='color: blue; font-weight: bold'>IsEmpty(list);</span> } Console.WriteLine(sw.Elapsed.TotalSeconds); } } [MethodImpl(MethodImplOptions.NoInlining)] static bool IsEmpty(List<int> list) => list.Count != 0; } } </pre> <br /> <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/core/runtime-config/compilation#profile-guided-optimization'>Dynamic PGO 옵션</a>을 활성화한 다음, (혹은 csproj에 <TieredPGO>true</TieredPGO> 설정)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp\ConsoleApp1> <span style='color: blue; font-weight: bold'>set DOTNET_TieredPGO=1</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;' > // [.NET 7 + PGO] c:\temp\ConsoleApp1> <span style='color: blue; font-weight: bold'>dotnet .\ConsoleApp7\bin\Release\net7.0\ConsoleApp7.dll</span> 1.5479958 1.4894338 1.5124722 1.5047404 1.5001046 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // [.NET 8 + PGO] c:\temp\ConsoleApp1> <span style='color: blue; font-weight: bold'>dotnet .\ConsoleApp8\bin\Release\net8.0\ConsoleApp8.dll</span> 1.0941596 1.0035034 1.0044089 1.0028159 1.0046821 </pre> <br /> "<a target='tab' href='https://youtu.be/xEFO1sQ2bUc?t=14689'>.NET Conf 세미나</a>" 화면에서도 .NET 7의 경우 3.4 정도, .NET 8의 경우에는 1.6 정도로 절반 가까이 성능 차이가 났는데, 제 컴퓨터(Intel i9-12900K)에서는 1.5에서 1.0으로 약 33% 정도 향상되었습니다.<br /> <br /> JIT 컴파일링이 어떻게 달라졌는지 DOTNET_JitDisasmSummary 환경 변수로 확인할 수 있다고 하는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp\ConsoleApp1> <span style='color: blue; font-weight: bold'>set DOTNET_JitDisasmSummary=1</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;' > // [.NET 7 + PGO + DOTNET_JitDisasmSummary] 1: JIT compiled System.Runtime.CompilerServices.CastHelpers:StelemRef(System.Array,long,System.Object) [Tier1, IL size=88, code size=93] 2: JIT compiled System.Runtime.CompilerServices.CastHelpers:LdelemaRef(System.Array,long,ulong) [Tier1, IL size=44, code size=44] 3: JIT compiled System.SpanHelpers:IndexOfNullCharacter(byref) [Tier1, IL size=792, code size=388] 4: JIT compiled ConsoleApp1.Program:Main(<unnamed>) [Instrumented Tier0, IL size=74, code size=320] 5: JIT compiled ConsoleApp1.Program:<span style='color: blue; font-weight: bold'>IsEmpty</span>(System.Collections.Generic.List`1[int]) [<span style='color: blue; font-weight: bold'>Instrumented Tier0</span>, IL size=10, code size=40] 6: JIT compiled ConsoleApp1.Program:Main(<unnamed>) [Instrumented Tier1-OSR @0x25 with Dynamic PGO, IL size=74, code size=253] 7: JIT compiled ConsoleApp1.Program:<span style='color: blue; font-weight: bold'>IsEmpty</span>(System.Collections.Generic.List`1[int]) [<span style='color: blue; font-weight: bold'>Tier1</span>, IL size=10, code size=10] 8: JIT compiled System.Collections.Generic.List`1[int]:get_Count() [Tier1, IL size=7, code size=4] 9: JIT compiled System.Text.ASCIIUtility:NarrowUtf16ToAscii(ulong,ulong,ulong) [Instrumented Tier0, IL size=490, code size=1373] 10: JIT compiled System.SpanHelpers:SequenceCompareTo(byref,int,byref,int) [Tier1, IL size=632, code size=329] 1.5190925 1.4906073 1.4788726 1.4834886 1.4853625 11: JIT compiled System.Buffer:Memmove(byref,byref,ulong) [Tier1 with Static PGO, IL size=480, code size=270] </pre> <br /> .NET 7에서는 저렇게 2번의 "Instrumented Tier0", "Tier 1" 컴파일이 발생하지만, .NET 8에서는,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // [.NET 8 + PGO + DOTNET_JitDisasmSummary] 1: JIT compiled System.Runtime.CompilerServices.CastHelpers:StelemRef(System.Array,long,System.Object) [Tier1, IL size=88, code size=93] 2: JIT compiled System.Runtime.CompilerServices.CastHelpers:LdelemaRef(System.Array,long,ulong) [Tier1, IL size=44, code size=44] 3: JIT compiled ConsoleApp1.Program:Main(System.String[]) [Instrumented Tier0, IL size=74, code size=324] 4: JIT compiled ConsoleApp1.Program:<span style='color: blue; font-weight: bold'>IsEmpty</span>(System.Collections.Generic.List`1[int]) [<span style='color: blue; font-weight: bold'>Tier0</span>, IL size=10, code size=40] 5: JIT compiled ConsoleApp1.Program:Main(System.String[]) [Tier1-OSR @0x25 with Dynamic PGO, IL size=74, code size=220] 6: JIT compiled ConsoleApp1.Program:<span style='color: blue; font-weight: bold'>IsEmpty</span>(System.Collections.Generic.List`1[int]) [<span style='color: blue; font-weight: bold'>Instrumented Tier0</span>, IL size=10, code size=40] 7: JIT compiled System.Collections.Generic.List`1[int]:get_Count() [Instrumented Tier1, IL size=7, code size=4] 8: JIT compiled ConsoleApp1.Program:<span style='color: blue; font-weight: bold'>IsEmpty</span>(System.Collections.Generic.List`1[int]) [<span style='color: blue; font-weight: bold'>Tier1</span>, IL size=10, code size=10] 9: JIT compiled System.Collections.Generic.List`1[int]:get_Count() [Tier1, IL size=7, code size=4] 1.0763641 1.0003451 0.9969336 0.9980177 10: JIT compiled System.Buffer:Memmove(byref,byref,ulong) [Instrumented Tier1 with Static PGO, IL size=480, code size=581] 0.9961069 </pre> <br /> "Tier 0", "Instrumented Tier 0", "Tier 1" 총 3번의 JIT 컴파일 최적화가 이뤄집니다. 그런데, 위의 출력 결과를 다시 보면 2개 모두 다음과 같이,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET 7 + PGO + DOTNET_JitDisasmSummary ...[생략]... 6: JIT compiled ConsoleApp1.Program:Main(<unnamed>) [Instrumented Tier1-OSR @0x25 <span style='color: blue; font-weight: bold'>with Dynamic PGO</span>, IL size=74, code size=253] ...[생략]... // .NET 8 + PGO + DOTNET_JitDisasmSummary ...[생략]... 5: JIT compiled ConsoleApp1.Program:Main(System.String[]) [Tier1-OSR @0x25 <span style='color: blue; font-weight: bold'>with Dynamic PGO</span>, IL size=74, code size=220] ...[생략]... </pre> <br /> (동영상과는 달리 Main 메서드에만) "Dynamic PGO" 문구가 있습니다. 그런데, 재미있는 것은, ^^; "DOTNET_TieredPGO" 옵션을 제거하고 다시 실행해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET 7 + DOTNET_JitDisasmSummary 6: JIT compiled ConsoleApp1.Program:Main(<unnamed>) [<span style='color: blue; font-weight: bold'>Tier1-OSR</span> @0x25, IL size=74, code size=445] // .NET 8 + DOTNET_JitDisasmSummary 5: JIT compiled ConsoleApp1.Program:Main(System.String[]) [<span style='color: blue; font-weight: bold'>Tier1-OSR @0x25 with Dynamic PGO</span>, IL size=74, code size=220] </pre> <br /> 저렇게 .NET 7의 경우 "Dynamic PGO"가 빠지지만, .NET 8은 여전히 남아 있습니다. 즉, 저 결과로만 본다면 PGO 옵션이 .NET 8에서는 기본적으로 활성화된 것입니다. 실제로 "set DOTNET_TieredPGO=0"이라고 명시적인 비활성화 옵션을 주고 실행해야만 .NET 8에서 다음과 같은 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET 8 + PGO 비활성 + DOTNET_JitDisasmSummary 5: JIT compiled ConsoleApp1.Program:Main(System.String[]) [<span style='color: blue; font-weight: bold'>Tier1-OSR</span> @0x25, IL size=74, code size=475] </pre> <br /> <hr style='width: 50%' /><br /> <br /> 개인적으로 흥미 있는 건 DOTNET_JitDisasm 옵션입니다. 이 옵션이 있는 줄 몰랐을 때는, 기계어로 번역된 코드를 얻으려면 <a target='tab' href='https://www.sysnet.pe.kr/2/0/1023#unassemble'>windbg + sos 확장을 이용한 번거로운 절차를 거쳐야</a> 했기 때문입니다. 어쨌든, 이것으로 원하는 메서드에 대해 JIT 컴파일 결과를 출력한다고 하는데요,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // <a target='tab' href='https://youtu.be/xEFO1sQ2bUc?t=14689'>동영상</a>에서는 콤마로 감싸는데, set DOTNET_JitDisasm="IsEmpty" // 제가 테스트한 바로는 콤마를 빼고 지정해야 합니다. set DOTNET_JitDisasm=IsEmpty </pre> <br /> .NET 7에서는 다음과 같이 2번의 JIT 컴파일 결과가 나오고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // [.NET 7 + PGO + DOTNET_JitDisasm] ; Assembly listing for method ConsoleApp1.Program:IsEmpty(System.Collections.Generic.List`1[int]):bool ; Emitting BLENDED_CODE for X64 CPU with AVX - Windows <span style='color: blue; font-weight: bold'>; Tier-0 compilation</span> ; MinOpts code ; instrumented for collecting profile data ; rbp based frame ; partially interruptible G_M000_IG01: ;; offset=0000H 55 push rbp 4883EC20 sub rsp, 32 488D6C2420 lea rbp, [rsp+20H] 48894D10 mov gword ptr [rbp+10H], rcx G_M000_IG02: ;; offset=000EH 488B4D10 mov rcx, gword ptr [rbp+10H] 3909 cmp dword ptr [rcx], ecx FF15369F0F00 call [System.Collections.Generic.List`1[int]:get_Count():int:this] 85C0 test eax, eax 0F95C0 setne al 0FB6C0 movzx rax, al G_M000_IG03: ;; offset=0022H 4883C420 add rsp, 32 5D pop rbp C3 ret ; Total bytes of code 40 ; Assembly listing for method ConsoleApp1.Program:IsEmpty(System.Collections.Generic.List`1[int]):bool ; Emitting BLENDED_CODE for X64 CPU with AVX - Windows <span style='color: blue; font-weight: bold'>; Tier-1 compilation</span> ; optimized code ; rsp based frame ; partially interruptible ; No PGO data ; 0 inlinees with PGO data; 1 single block inlinees; 0 inlinees without PGO data G_M000_IG01: ;; offset=0000H G_M000_IG02: ;; offset=0000H 33C0 xor eax, eax 83791000 cmp dword ptr [rcx+10H], 0 0F95C0 setne al G_M000_IG03: ;; offset=0009H C3 ret ; Total bytes of code 10 </pre> <br /> .NET 8에서는 3번의 JIT 컴파일 결과가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // [.NET 8 + PGO + DOTNET_JitDisasm] ; Assembly listing for method ConsoleApp1.Program:IsEmpty(System.Collections.Generic.List`1[int]):bool (Tier0) ; Emitting BLENDED_CODE for X64 with AVX - Windows <span style='color: blue; font-weight: bold'>; Tier0 code</span> ; rbp based frame ; partially interruptible G_M000_IG01: ;; offset=0x0000 push rbp sub rsp, 32 lea rbp, [rsp+0x20] mov gword ptr [rbp+0x10], rcx G_M000_IG02: ;; offset=0x000E mov rcx, gword ptr [rbp+0x10] cmp dword ptr [rcx], ecx call [System.Collections.Generic.List`1[int]:get_Count():int:this] test eax, eax setne al movzx rax, al G_M000_IG03: ;; offset=0x0022 add rsp, 32 pop rbp ret ; Total bytes of code 40 ; Assembly listing for method ConsoleApp1.Program:IsEmpty(System.Collections.Generic.List`1[int]):bool (Instrumented Tier0) ; Emitting BLENDED_CODE for X64 with AVX - Windows <span style='color: blue; font-weight: bold'>; Instrumented Tier0 code</span> ; rbp based frame ; partially interruptible G_M000_IG01: ;; offset=0x0000 push rbp sub rsp, 32 lea rbp, [rsp+0x20] mov gword ptr [rbp+0x10], rcx G_M000_IG02: ;; offset=0x000E mov rcx, gword ptr [rbp+0x10] cmp dword ptr [rcx], ecx call [System.Collections.Generic.List`1[int]:get_Count():int:this] test eax, eax setne al movzx rax, al G_M000_IG03: ;; offset=0x0022 add rsp, 32 pop rbp ret ; Total bytes of code 40 ; Assembly listing for method ConsoleApp1.Program:IsEmpty(System.Collections.Generic.List`1[int]):bool (Tier1) ; Emitting BLENDED_CODE for X64 with AVX - Windows <span style='color: blue; font-weight: bold'>; Tier1 code</span> ; optimized code ; rsp based frame ; partially interruptible ; No PGO data ; 0 inlinees with PGO data; 1 single block inlinees; 0 inlinees without PGO data G_M000_IG01: ;; offset=0x0000 G_M000_IG02: ;; offset=0x0000 xor eax, eax cmp dword ptr [rcx+0x10], 0 setne al G_M000_IG03: ;; offset=0x0009 ret ; Total bytes of code 10 </pre> <br /> 그런데, .NET 8의 "Tier 0", "Instrumented Tier 0" 컴파일 결과는 동일한데다가 3번째 "Tier 1"의 컴파일 결과는 .NET 7의 두 번째 "Tier 1" 컴파일 결과와 같습니다. 즉, 저 결과로만 보면 쓸데없는 작업이 .NET 8에 들어간 것인데, 그래도 성능이 저렇게 빠른 거 보면 원래 .NET 8 런타임 자체가 빠른 건지도 모르겠습니다. ^^;<br /> <br /> 참고로, 아래의 도구들을 사용하면 더 쉽게 JIT 컴파일 결과를 알 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Disasmo ; <a target='tab' href='https://marketplace.visualstudio.com/items?itemName=EgorBogatov.Disasmo'>https://marketplace.visualstudio.com/items?itemName=EgorBogatov.Disasmo</a> Sharplab ; <a target='tab' href='https://sharplab.io/'>https://sharplab.io/</a> </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그렇다면, 아예 기본값이 활성 상태인 <a target='tab' href='https://www.sysnet.pe.kr/2/0/11539'>TieredCompilation 옵션</a> 자체를 끄고 실행하면 어떨까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET Core 2 이하의 환경에서 기본값이 비활성 // .NET Core 3 이상의 환경에서 기본값이 활성 상태 SET DOTNET_TieredCompilation=0 </pre> <br /> 그럼, PGO를 사용했던 것보다 더 빠르게 실행이 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET 7 + Tiered Compilation 없이 실행 (PGO도 함께 자동으로 비활성) 0.8113732 0.7983001 0.8145982 0.8106876 0.799827 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET 8 + Tiered Compilation 없이 실행 (PGO도 함께 자동으로 비활성) 0.7899068 0.7979388 0.7953996 0.7973212 0.7974282 </pre> <br /> 여기서 한 가지 오해하지 말아야 할 것이 있습니다. "Tiered Compilation" 기능은 프로그램의 "성능"을 높이는 목적이 아닌, "초기 JIT 컴파일 속도"를 높이기 위해 만들어졌다는 사실입니다.<br /> <br /> 즉, 시간이 많이 걸리는 최적화 JIT 빌드를 모든 코드에 대해 수행해 초기 로딩 속도를 늦추기보다는, 몇 번 실행되지도 않는 코드들은 (최적화 단계 없이) 일단 실행만 되게 고속으로 JIT 컴파일 시키고, 이후에 천천히 최적화를 하는 것이 "Tiered Compilation"입니다.<br /> <br /> 따라서, 저런 결과가 나오는 것이 정상입니다.<br /> <br /> 그런 관점에서 .NET 8의 PGO를 다시 바라볼 필요가 있습니다. 이것 역시, 오히려 DOTNET_TieredPGO=0으로 옵션을 명시적으로 비활성화시키고 실행하면 .NET 7에서 .NET 8보다 빠른 결과를 보입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET 7 + PGO 없이 실행 (DOTNET_TieredPGO=0, 기본값이므로 설정 유무에 상관없음) 1.1310844 1.016918 1.0223791 1.0211129 1.0194825 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .NET 8 + PGO 없이 실행 (DOTNET_TieredPGO=0, 반드시 설정해야 비활성화됨) 1.4378975 1.3701194 1.3651987 1.3690431 1.3692595 </pre> <br /> 저걸 굳이 해석해 보자면, .NET 7은 Tiered Compilation이 2단계로 단순하게 나누어져 있는 반면, .NET 8은 Tiered Compilation을 좀 더 세분화해서 3단계로 나뉘었다고 보면 될 듯합니다. 아마도 저렇기 때문에 .NET 8은 PGO를 기본 옵션으로 활성화시켰다는 것으로 해석할 수 있습니다.<br /> <br /> 하지만, 이렇게 3단계로 나뉜 .NET 8의 초기 로딩 속도가 얼마나 효율적인지는 테스트로 확인하는 것이 좀 애매합니다. 왜냐하면, RAM/Disk Cache나 Cold/Warm 실행에 따른 성능 변수가 오히려 더 클 수 있기 때문입니다.<br /> <br /> 암튼, 그냥 긍정적인 방향으로 정리해 보면, .NET 8은 초기 (JIT 컴파일을 포함하는) 로딩 속도를 보완하기 위해 3단계 Tiered Compilation을 적절한 수준으로 구현했다... 정도로 보면 되겠습니다. ^^<br /><br /> (2023-11-23 업데이트) 위의 예제만으로는 실망스러울 수 있지만, "<a target='tab' href='https://www.youtube.com/watch?v=WrpYcGic9b8'>Dynamic PGO (상세)</a>" 영상에 나오는 GDV, Profile-Guided Inlining 등의 예제를 보면 분명히 성능 향상이 될 수 있는 여지가 많습니다. </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1149
(왼쪽의 숫자를 입력해야 합니다.)