성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
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 4.5부터 추가된 CLR Profiler의 실행 시 Rejit 기능</h1> <p> 닷넷 프로파일러를 개발하는 입장에서, 가장 기다리던 기능이 바로 실행시 Rejit할 수 있는 것이었는데 드디어 .NET 4.5부터 가능하게 되었습니다. ^^<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ReJIT: A How-To Guide ; <a target='tab' href='https://docs.microsoft.com/en-us/archive/blogs/davbr/rejit-a-how-to-guide'>https://docs.microsoft.com/en-us/archive/blogs/davbr/rejit-a-how-to-guide</a> </pre> <br /> 자세한 것은 위의 글에 다 나오니 생략하고 ^^ 저는 시행 착오 부분을 설명할까 합니다.<br /> <br /> 우선, Rejit이 가능하도록 하려면 프로파일러가 CLR에게 <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo-seteventmask-method'>SetEventMask</a> 메서드를 통해 COR_PRF_ENABLE_REJIT을 설정해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > COR_PRF_MONITOR Enumeration - COR_PRF_ENABLE_REJIT ; <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/cor-prf-monitor-enumeration'>https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/cor-prf-monitor-enumeration</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > DWORD dwEventMask = ... | COR_PRF_ENABLE_REJIT; HRESULT hr = corProfilerInfo2->SetEventMask(m_dwEventMask); </pre> <br /> 그런데, 저렇게만 하는 경우 hr == 0x8013137C 오류 코드가 반환되는 경우가 있습니다. 이를 검색해 보면 다음의 도움말을 찾을 수 있는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0x8013137C ; <a target='tab' href='https://github.com/dotnet/coreclr/blob/master/src/inc/corerror.xml'>https://github.com/dotnet/coreclr/blob/master/src/inc/corerror.xml</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <HRESULT NumericValue="0x8013137C"> <SymbolicName>CORPROF_E_REJIT_NOT_ENABLED</SymbolicName> <Comment> This call is not supported unless ReJIT is first enabled during initialization by setting COR_PRF_ENABLE_REJIT via SetEventMask. </Comment> </HRESULT> </pre> <br /> 아쉽게도 오류 메시지에서는 별다른 해결의 힌트를 얻을 수 없었고, 대신 <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/cor-prf-monitor-enumeration'>COR_PRF_ENABLE_REJIT</a>의 도움말에서 찾을 수 있었습니다. 이를 자세히 보면 다음과 같은 설명이 나옵니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> Enables calls to the RequestReJIT and RequestRevert methods. The profiler must set this flag on startup. If the profiler specifies this flag, it must also specify <span style='color: blue; font-weight: bold'>COR_PRF_DISABLE_ALL_NGEN_IMAGES</span>. </div> <br /> <br /> 그렇습니다. SetEventMask에 설정할 때 "COR_PRF_ENABLE_REJIT | COR_PRF_DISABLE_ALL_NGEN_IMAGES"와 같이 함께 값을 설정해 주어야 하는 것입니다.<br /> <br /> 재미있는 것은, 저 문제는 .NET 4.5에서 발생하고 (정확한 버전은 테스트를 해봐야 하지만 확실하게는) .NET 4.6.1에서는 COR_PRF_DISABLE_ALL_NGEN_IMAGES 옵션을 주지 않아도 잘 됩니다. 즉 개선이 된 것입니다. 따라서, COR_PRF_DISABLE_ALL_NGEN_IMAGES에 대한 부하를 4.6.1에서 없애고 싶다면 다음과 같은 식으로 SetEventMask를 호출해 주시면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 일단 COR_PRF_ENABLE_REJIT 옵션만 설정해 보고, m_dwEventMask |= COR_PRF_ENABLE_REJIT; hr = m_pICorProfilerInfo2->SetEventMask(m_dwEventMask); if (hr != S_OK) { // 오류가 발생했을 때에 한해 COR_PRF_DISABLE_ALL_NGEN_IMAGES 옵션도 함께 설정 { DWORD dwEventMask = m_dwEventMask | COR_PRF_DISABLE_ALL_NGEN_IMAGES; hr = m_pICorProfilerInfo2->SetEventMask(dwEventMask); } } </pre> <br /> 물론, 프로파일러 스스로 .NET 4.5와 4.6.1 버전을 인식할 수 있다면 그에 맞게 처리해주셔도 됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 한 가지 더 설명할 것이 있는데, 바로 Rejit시킨 메서드를 다시 원본 메서드로 복원하고 싶을 때 호출하는 RequestRevert에 대해서입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ICorProfilerInfo4::RequestRevert 메서드 ; <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo4-requestrevert-method'>https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo4-requestrevert-method</a> </pre> <br /> 이를 호출한 경우, 0x8013137D 오류가 발생하는 경우가 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ICorProfilerInfo4 ptr = ...; HRESULT hr = ptr->RequestRevert(count, modIDs, methodDefIDs, hrArray); // hr == 0x8013137D </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;' > <HRESULT NumericValue="0x8013137D"> <SymbolicName>CORPROF_E_ACTIVE_REJIT_REQUEST_NOT_FOUND</SymbolicName> <Comment> Could not revert the specified method, <span style='color: blue; font-weight: bold'>because a corresponding active ReJIT request was not found.</span> Either the method was never requested to be reJITted OR the method was already reverted. </Comment> </HRESULT> </pre> <br /> 보시는 바와 같이, Revert를 시키려면 반드시 그 메서드가 이전에 한번 RequestReJIT으로 요청된 적이 있었어야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ICorProfilerInfo4::RequestReJIT 메서드 ; <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo4-requestrejit-method'>https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilerinfo4-requestrejit-method</a> </pre> <br /> 이게 일면 당연하게 생각될 수도 있는데요. 하지만 .NET Profiler가 IL 코드를 변경하는 시점을 이전의 버전에서 JITCompilationStarted로 제공했기 때문에,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ICorProfilerCallback::JITCompilationStarted 메서드 ; <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilercallback-jitcompilationstarted-method'>https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/profiling/icorprofilercallback-jitcompilationstarted-method</a> </pre> <br /> 이 때 변경한 메서드에 대해서는 RequestRevert가 0x8013137D 반환만 하게 되는 것입니다. 따라서, 기존 프로파일러 제작자라면 Rejit 및 Revert를 모두 구현하고 싶은 경우 JITCompilationStarted 시점의 IL 코드 변경을 재고해 봐야 합니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, <a target='tab' href='http://jennifersoft.com/ko/product/net/'>제니퍼 4 닷넷 에이전트</a>는 CLR Profiler 기능을 이용해 만든 것인데요. 새로운 메서드를 프로파일링하려고 하면 아쉽지만 설정 후 w3wp.exe를 재시작해야 했습니다. 하지만, 올해 신규 버전으로 새로 출시된 <a target='tab' href='http://jennifersoft.com/ko/product/net/'>제니퍼 5 닷넷 에이전트</a>부터는 Rejit과 Revert 기능이 추가되었기 때문에 실행 시에 새로운 메서드에 대한 프로파일링 추가/삭제가 가능해졌습니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
6295
(왼쪽의 숫자를 입력해야 합니다.)