Microsoft MVP성태의 닷넷 이야기
디버깅 기술: 1. 디버깅 방법 - CLR 프로파일러 [링크 복사], [링크+제목 복사],
조회: 29359
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 2개 있습니다.)

저 같은 경우, 해당 응용 프로그램을 개발하기 쉬운지, 어려운지에 대한 기준으로 얼마나 쉽게 "디버거" 환경에서 구동시킬 수 있느냐로 판단합니다. 쉽게 말해서, IDE 환경에서 "F5"를 통한 디버깅이 되느냐/안되느냐에 따른 것인데요.

그러한 디버깅이 다소 어려운 Windows Shell, ISAPI Filter, API 후킹 등은 "어려운 분야"라고 저는 판단합니다. 사실 어려운 분야죠. ^^; 어려울수록 디버깅은 더욱 힘들어지는 것이 정석인가 봅니다.

다행스러운 것은, 최근 들어 전체적으로 개발환경이 .NET으로 넘어오면서, "F5 디버깅"의 영역이 넓어지고 있다는 것입니다. 단적인 예로, ASP.NET 디버깅이 그렇죠.



이런저런 이유로, 어떤 응용 프로그램을 개발할 때에 저는 최대한 "F5 디버깅"이 가능하게 하려고 노력을 합니다. 이번 글은, 최근에 제가 노력했었던 "F5 디버깅" 환경 구성 중에서 "CLR 프로파일러"를 위한 것을 설명하겠습니다.

CLR 프로파일러 자체는 Unamaged C/C++로 개발이 되고, Managed 환경으로부터의 접점을 Environment Variable을 통해서 하고 있습니다. 얼핏 디버깅 방법이 실행 중에 attach 시키는 것뿐이 없는 것 같은데요. 그런 식으로 디버깅하는 것과 "F5 디버깅"의 생산성 차이는 엄청나기 때문에 조금 살펴보게 되었습니다.

일단, 시작 예제 프로젝트는 7차 MMS 모임 때 발표 자료였던 "High-Level .NET Profiling API"를 이용한 프로젝트로 하겠습니다.어차피 Low-Level CLR Profiling API도 마찬가지일거라 봅니다. 관련 자료는 다음의 URL에서 찾아 볼 수 있습니다.

.NET Profiling
Write Profilers With Ease Using High-Level Wrapper Classes
; https://docs.microsoft.com/en-us/archive/msdn-magazine/2006/april/write-profilers-with-ease-using-high-level-wrapper-classes

이제부터, .NET Profiler 프로젝트를 위한 디버깅 환경 설정을 설명해 보겠습니다.

1. 우선, 프로젝트 설정 / "General" 범주에서 "Output Directory"를 CLR Profiling 대상이 되는 .NET 프로그램이 있는 폴더로 지정합니다. 당연하겠지요. ^^

다음은 실제 예제 프로젝트의 솔루션 구조와, 대상 Output Directory에 모여진 파일들의 모습입니다.
Output Directory

2. "Debugging" 범주에서 아래와 같이 적절한 값으로 Command, Working Directory, Debugger Type을 지정합니다. Command Arguments가 있는 경우에는 역시 입력해 주면 되겠고, 각자 자신이 맞는 환경에 맞게 값을 채워주시면 됩니다. 주의할 것은 Working Directory도 반드시 명시를 해주셔야 합니다.

  Command : .NET 프로파일링 대상이 되는 EXE 프로그램 경로
  Working Directory : 대상 EXE 프로그램이 있는 디렉터리
  Debugger Type : 반드시 Native Only 값을 주어야 합니다. Mixed 방식을 주면 CLR로부터의 Call back API들에서 Break Point가 동작하지 않습니다.

프로젝트 설정 화면

3. 이미 말씀드린 것처럼, CLR Profiling의 동작 방식은 CLR이 로딩시에 환경 변수에 특정 변수로 등록된 COM 개체의 CLSID를 얻어서 해당 COM 개체를 활성화시킨 다음 정해진 interface 규칙에 맞게 callback을 해주는 구조입니다. 따라서, "F5 디버깅"을 위해서는 해당 디버깅 세션 동안에 유효할 수 있는 환경 변수 설정을 적절하게 해주어야 합니다. 사실 VS.NET 2003까지는 디버깅 세션에 환경 변수를 설정할 수 있는 방법이 없었습니다. "My Computer"의 전역 환경 설정 변수를 이용할 수도 있었겠지만, 그런 경우 전체 응용 프로그램 모두에 프로파일링 API가 동작하게 되는 부작용이 있으므로 사용하기에는 현실성이 없어 보입니다.

다행히도, VS.NET 2005에서는 디버깅 세션에 환경 변수를 설정할 수 있는 방법을 명시적으로 제공하고 있습니다. 아래의 화면에서 보는 것처럼, CLR 프로파일링 동작을 위한 환경 변수를 설정해 주시면 됩니다.

환경 변수 설정

4. 자, 이제 모든 준비는 끝났습니다. 평상시처럼, 자신이 구현한 CLR 프로파일러 내부의 로직에 break point를 설정한 후, "F5" 키를 누르면 아래 화면과 같이 정상적으로 디버깅이 가능한 것을 볼 수 있습니다.

CLR 프로파일러 디버깅 화면 **** 첨부 파일은 이 글에서 설명한 예제 프로젝트입니다.
[연관 글]






[최초 등록일: ]
[최종 수정일: 6/25/2021]

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

비밀번호

댓글 작성자
 



2012-09-20 12시39분
본문과는 상관없지만! 프로파일러와 관련이 있어서 기록을 남깁니다.

ICorProfilerInfo2::DoStackSnapshot 호출의 반환값(hr)으로 E_INVALIDARG (-2147024809, 0x80070057) 값이 나왔다면? DoStackSnapshot API가 동작하기 위해서는 ICorProfilerInfo2::SetEventMask에 COR_PRF_ENABLE_STACK_SNAPSHOT 옵션을 주어야 하기 때문입니다.
정성태

... 136  137  138  139  140  141  142  143  [144]  145  146  147  148  149  150  ...
NoWriterDateCnt.TitleFile(s)
1485정성태8/26/201333756.NET Framework: 380. 프로세스 스스로 풀 덤프 남기는 방법 [3]파일 다운로드1
1484정성태8/23/201328114제니퍼 .NET: 24. 제니퍼 닷넷 적용 사례 (4) - GZIP 인코딩으로 인한 성능 하락
1483정성태8/23/201328174.NET Framework: 379. System.IO.MemoryStream, ArraySegment<T> 의 효율적인 사용법 [1]
1482정성태8/23/201321614.NET Framework: 378. Java / C# - 정수의 부호 유무에 따른 16진수 문자열 변환
1481정성태8/22/201322572오류 유형: 184. PaaS 유형(Cloud Services)의 Azure VM에 연결할 때 계정 만료 에러가 발생하는 경우
1480정성태8/22/201338829개발 환경 구성: 194. 윈도우 서버의 80 포트에 대한 port forwarding 설정 방법파일 다운로드1
1479정성태8/14/201326415오류 유형: 183. IIS - 바인딩 추가 시 Object reference not set to an instance of an object 오류 [5]
1478정성태8/14/201329709오류 유형: 182. 윈도우 정품 활성화 오류 - 0x80070426
1477정성태8/14/201328627VC++: 71. codeplex의 Project Austin - 실감나게 책장 넘기는 표현
1476정성태8/13/201336973디버깅 기술: 55. Windbg - 윈도우 핸들 테이블 (2)
1475정성태8/12/201335506.NET Framework: 377. 프로세스가 종료된 후에도 소켓이 살아있다면?파일 다운로드1
1474정성태8/10/201332354오류 유형: 181. 윈도우 8 - WmiPrvSE.exe 프로세스가 CPU 소비하는 현상
1473정성태8/8/201329108VC++: 70. Win32 socket이 Thread-safe할까? [1]파일 다운로드1
1472정성태8/7/201327514.NET Framework: 376. .NET 2.0의 유니코드 관련 문자열 비교 오류
1471정성태8/7/201331654개발 환경 구성: 193. .aspx 확장자 대신 .html 확장자를 사용하는 방법
1470정성태8/6/201328445오류 유형: 180. DISM.exe 0xc1510111 실행 오류
1469정성태8/6/201325325.NET Framework: 375. System.Net.Sockets.Socket이 Thread-safe할까? [2]파일 다운로드1
1468정성태8/6/201323331오류 유형: 179. IIS - No connection could be made because the target machine actively refused it 127.0.0.1:80
1467정성태8/5/201326793Java: 16. IE에 로드된 Java Applet의 다운로드 위치를 확인하는 방법
1466정성태7/27/201332465.NET Framework: 374. C#과 비교한 C++ STL vector 성능 [7]파일 다운로드1
1465정성태7/18/201335801기타: 33. C:\Windows\Installer 폴더의 용량 줄이기 [3]
1464정성태7/15/201323930오류 유형: 178. Visual Studio 2012 Express - ImportCardinalityMismatchException
1463정성태7/15/201324695오류 유형: 177. [DBNETLIB][ConnectionOpen (Connect()).]SQL Server does not exist or access denied.
1462정성태7/5/201328098VC++: 69. geek스러운 C/C++ 퀴즈 문제 [2]
1461정성태6/27/201344706.NET Framework: 373. C# 문자열의 인코딩이란?
1460정성태6/17/201326505.NET Framework: 372. PerformanceCounter - Category does not exist. [1]
... 136  137  138  139  140  141  142  143  [144]  145  146  147  148  149  150  ...