다음을 통해 공유


프로파일링 개요

프로파일러는 다른 응용 프로그램의 실행 상태를 모니터링하는 도구입니다. CLR(공용 언어 런타임) 프로파일러는 프로파일링 API를 사용하여 CLR과 메시지를 주고받는 함수로 이루어진 DLL(동적 연결 라이브러리)입니다. 프로파일러 DLL은 런타임에 CLR에서 로드됩니다.

일반적인 프로파일링 도구에서는 주로 응용 프로그램 실행을 측정합니다. 즉 각 함수에 사용된 시간이나 응용 프로그램의 메모리 사용량을 시간 경과에 따라 측정합니다. 프로파일링 API에서는 코드 검사 유틸리티 및 고급 디버깅 지원과 같은 다양한 진단 도구를 대상으로 합니다. 이러한 도구는 기본적으로 모두 진단을 위해 사용됩니다. 프로파일링 API에서는 응용 프로그램의 실행을 측정할 뿐 아니라 모니터링하기도 합니다. 따라서 프로파일링 API를 응용 프로그램 자체에서 사용하면 안 되며 응용 프로그램의 실행이 프로파일러에 종속되거나 프로파일러의 영향을 받아서는 안 됩니다.

CLR 응용 프로그램을 프로파일링하려면 기존의 컴파일된 기계어 코드를 프로파일링하는 것 이상의 지원이 필요합니다. 이는 CLR에 응용 프로그램 도메인, 가비지 수집, 관리되는 예외 처리, 코드의 JIT(Just-In-Time ) 컴파일(MSIL(Microsoft Intermediate Language) 코드를 네이티브 기계어 코드로 변환) 등과 같은 개념이 새로 추가되었기 때문입니다. 기존의 프로파일링 메커니즘에서는 이러한 기능에 대한 유용한 정보를 식별하거나 제공할 수 없습니다. 프로파일링 API에서는 이러한 누락된 정보를 효율적으로 제공하면서도 CLR 및 프로파일링된 응용 프로그램의 성능에 미치는 영향을 최소화합니다.

런타임에 JIT 컴파일을 사용하면 프로파일링을 효율적으로 수행할 수 있습니다. 프로파일링 API를 사용하면 프로파일러에서 루틴이 JIT 컴파일되기 전에 루틴의 메모리 내 MSIL 코드 스트림을 변경할 수 있습니다. 이러한 방식으로 프로파일러는 더 세부적인 조사가 필요한 특정 루틴에 계측 코드를 동적으로 추가할 수 있습니다. 이러한 방법은 기존 시나리오에서도 가능하지만 CLR에서 프로파일링 API를 사용하여 구현하는 것이 훨씬 간단합니다.

이 개요는 다음과 같은 단원으로 구성됩니다.

  • 프로파일링 API

  • 지원되는 기능

  • 알림 스레드

  • 보안

  • 코드 프로파일러에서 관리 코드 및 비관리 코드 함께 사용

  • 비관리 코드 프로파일링

  • COM 사용

  • 호출 스택

  • 콜백 및 스택 수준

  • 관련 항목

프로파일링 API

일반적으로 프로파일링 API는 관리되는 응용 프로그램의 실행을 모니터링하는 프로그램인 코드 프로파일러를 작성하는 데 사용됩니다.

프로파일링 API는 프로파일링되는 응용 프로그램과 같은 프로세스로 로드되는 프로파일러 DLL에서 사용됩니다. 프로파일러 DLL에서는 콜백 인터페이스(.NET Framework 버전 1.0 및 1.1의 경우 ICorProfilerCallback, 버전 2.0 이상의 경우 ICorProfilerCallback2)를 구현합니다. CLR에서는 해당 인터페이스의 메서드를 호출하여 프로파일링된 프로세스의 이벤트에 대해 프로파일러에 알려 줍니다. 프로파일러는 ICorProfilerInfoICorProfilerInfo2 인터페이스의 메서드를 통해 런타임으로 다시 호출하여 프로파일링된 응용 프로그램의 상태에 대한 정보를 가져올 수 있습니다.

참고참고

프로파일러 솔루션의 데이터 수집 부분만 프로파일링된 응용 프로그램과 같은 프로세스에서 실행되고 있어야 합니다.모든 사용자 인터페이스 및 데이터 분석은 별도의 프로세스에서 수행되어야 합니다.

다음 그림에서는 프로파일러 DLL이 프로파일링되는 응용 프로그램 및 CLR과 상호 작용하는 방법을 보여 줍니다.

프로파일링 아키텍처

프로파일링 아키텍처

알림 인터페이스

ICorProfilerCallbackICorProfilerCallback2는 알림 인터페이스라고 할 수 있습니다. 이러한 인터페이스는 ClassLoadStarted, ClassLoadFinishedJITCompilationStarted와 같은 메서드로 구성됩니다. CLR에서는 클래스를 로드 또는 언로드하고 함수를 컴파일하는 등의 작업을 수행할 때마다 프로파일러의 ICorProfilerCallback 또는 ICorProfilerCallback2 인터페이스에서 해당하는 메서드를 호출합니다.

예를 들어 프로파일러에서는 FunctionEnter2FunctionLeave2라는 두 가지 알림 함수를 통해 코드 성능을 측정할 수 있습니다. 여기서는 단지 각 알림에 타임스탬프를 기록하고, 결과를 누적하며, 응용 프로그램 실행 동안 가장 많은 CPU 또는 벽 시계 시간(wall-clock time)을 사용한 함수를 나타내는 목록을 출력합니다.

정보 검색 인터페이스

프로파일링과 관련된 다른 주요 인터페이스는 ICorProfilerInfoICorProfilerInfo2입니다. 프로파일러에서는 필요에 따라 이러한 인터페이스를 호출하여 분석에 도움이 되는 추가 정보를 가져옵니다. 예를 들어 CLR에서는 FunctionEnter2 함수를 호출할 때마다 함수 식별자를 제공합니다. 프로파일러에서는 ICorProfilerInfo2::GetFunctionInfo2 메서드를 호출하여 함수의 부모 클래스, 이름 등을 검색함으로써 해당 함수에 대한 추가 정보를 가져올 수 있습니다.

맨 위로 이동

지원되는 기능

프로파일링 API에서는 공용 언어 런타임에서 발생하는 다양한 이벤트와 작업에 대한 정보를 제공합니다. 이 정보를 사용하여 프로세스의 내부 작업을 모니터링하고 .NET Framework 응용 프로그램의 성능을 분석할 수 있습니다.

프로파일링 API에서는 CLR에서 발생하는 다음 작업 및 이벤트에 대한 정보를 검색합니다.

  • CLR 시작 및 종료 이벤트

  • 응용 프로그램 도메인 작성 및 종료 이벤트

  • 어셈블리 로딩 및 언로딩 이벤트

  • 모듈 로딩 및 언로딩 이벤트

  • COM vtable 작성 및 소멸 이벤트

  • JIT(Just-In-Time) 컴파일 및 코드 피칭 이벤트

  • 클래스 로딩 및 언로딩 이벤트

  • 스레드 작성 및 소멸 이벤트

  • 함수 시작 및 종료 이벤트

  • 예외

  • 관리 코드 실행과 비관리 코드 실행 간의 전환

  • 다른 런타임 컨텍스트 간의 전환

  • 런타임 일시 중단에 대한 정보

  • 런타임 메모리 힙 및 가비지 수집 활동에 대한 정보

프로파일링 API는 모든 비관리 COM 호환 언어에서 호출할 수 있습니다.

이 API는 CPU 및 메모리 사용 면에서 효율적입니다. 프로파일링에서는 프로파일링된 응용 프로그램이 잘못된 결과를 초래할 만큼 크게 변경되지 않습니다.

프로파일링 API는 샘플링 및 비샘플링 프로파일러 모두에 유용합니다. 샘플링 프로파일러는 일정한 클록 틱(예: 5밀리초)마다 프로파일을 검사하고 비샘플링 프로파일러는 이벤트를 발생시키는 스레드와 동기적으로 해당 이벤트에 대한 알림을 받습니다.

지원되지 않는 기능

프로파일링 API에서는 다음 기능을 지원하지 않습니다.

  • 비관리 코드. 비관리 코드를 프로파일링하려면 기본 Win32 메서드를 사용해야 합니다. 그러나 CLR 프로파일러에는 관리 코드와 비관리 코드의 경계를 결정하는 전환 이벤트가 포함되어 있습니다.

  • 관점 지향 프로그래밍과 같은 목적을 위해 자체 코드를 수정하는 자체 수정 응용 프로그램

  • 범위 검사. 프로파일링 API에서는 이 정보를 제공하지 않습니다. CLR에서는 모든 관리 코드에 대한 범위 검사를 기본적으로 지원합니다.

  • 원격 프로파일링. 다음과 같은 이유 때문에 원격 프로파일링은 지원되지 않습니다.

    • 원격 프로파일링을 수행하면 실행 시간이 늘어나는데 프로파일링 인터페이스를 사용할 때는 프로파일링 결과에 과도한 영향을 주지 않도록 실행 시간을 최소화해야 합니다. 실행 성능을 모니터링하는 경우에는 특히 그렇습니다. 그러나 프로파일링 인터페이스를 사용하여 메모리 사용량을 모니터링하거나 스택 프레임, 개체 등에 대한 런타임 정보를 가져올 경우에는 원격 프로파일링을 사용할 수 있습니다.

    • CLR 코드 프로파일러에서는 프로파일링된 응용 프로그램이 실행되고 있는 로컬 컴퓨터의 런타임에 하나 이상의 콜백 인터페이스를 등록해야 합니다. 이 때문에 원격 코드 프로프일러를 만들 수 있는 기능이 제한됩니다.

  • 고가용성 요구 사항이 있는 프로덕션 환경에서의 프로파일링. 프로파일링 API는 개발 단계에서의 진단을 지원하기 위해 만들어졌으며 프로덕션 환경을 지원하는 데 필요한 엄격한 테스트는 받지 않았습니다.

맨 위로 이동

알림 스레드

대부분의 경우 이벤트를 생성하는 스레드는 알림도 실행합니다. FunctionEnterFunctionLeave와 같은 알림은 명시적인 ThreadID를 제공할 필요가 없습니다. 또한 프로파일러에서는 전역 저장소의 분석 블록을 인덱싱하는 대신, 영향을 받는 스레드의 ThreadID를 기반으로 분석 블록을 저장 및 업데이트할 스레드 로컬 저장소를 사용할 수 있습니다.

이러한 콜백은 serialize되지 않습니다. 스레드로부터 안전한 데이터 구조를 만들고, 여러 스레드의 병렬 액세스를 방지해야 하는 경우 프로파일러 코드를 잠가 코드를 보호해야 합니다. 그러므로 경우에 따라 순서가 평소와 다른 콜백을 받을 수 있습니다. 예를 들어 관리되는 응용 프로그램에서 같은 코드를 실행하는 두 개의 스레드를 생성하는 경우 한 스레드에서는 특정 함수에 대해 ICorProfilerCallback::JITCompilationStarted 이벤트를 받고, 다른 스레드에서는 FunctionEnter 콜백을 받은 다음 ICorProfilerCallback::JITCompilationFinished 콜백을 받을 수 있습니다. 이 경우 사용자는 아직 완전히 JIT(Just-In-Time) 컴파일되지 않은 함수에 대해 FunctionEnter 콜백을 받습니다.

맨 위로 이동

보안

프로파일러 DLL은 공용 언어 런타임 실행 엔진의 일부로 실행되는 관리되지 않는 DLL입니다. 따라서 프로파일러 DLL의 코드는 관리 코드 액세스 보안의 제한을 받지 않습니다. 프로파일러 DLL에는 프로파일링된 응용 프로그램을 실행하는 사용자의 운영 체제에 지정된 제한만 적용됩니다.

프로파일러 작성자는 보안 관련 문제가 발생하지 않도록 적절한 사전 조치를 취해야 합니다. 예를 들어 설치하는 동안 프로파일러 DLL을 ACL(액세스 제어 목록)에 추가하여 악의가 있는 사용자가 프로파일러 DLL을 수정할 수 없도록 해야 합니다.

맨 위로 이동

코드 프로파일러에서 관리 코드 및 비관리 코드 함께 사용

잘못 작성된 프로파일러에서는 자체가 순환 참조되어 예기치 않은 동작이 발생할 수 있습니다.

CLR 프로파일링 API를 검토해 보면 COM interop 또는 간접 호출을 통해 서로를 호출하는 관리되는 구성 요소와 관리되지 않는 구성 요소가 포함된 프로파일을 작성할 수 있는 것처럼 보입니다.

설계 측면에서는 이것이 가능할 수도 있지만 프로파일링 API에서는 관리되는 구성 요소를 지원하지 않습니다. CLR 프로파일러는 완전히 관리되지 않아야 합니다. CLR 프로파일러에서 관리 코드와 비관리 코드를 함께 사용하면 액세스 위반, 프로그램 오류 및 교착 상태가 발생할 수 있습니다. 프로파일러의 관리되는 구성 요소가 관리되지 않는 구성 요소로 다시 이벤트를 발생시키고, 이어서 관리되지 않는 구성 요소가 관리되는 구성 요소를 다시 호출하여 순환 참조가 발생합니다.

CLR 프로파일러가 관리 코드를 안전하게 호출할 수 있는 유일한 위치는 메서드의 MSIL(Microsoft Intermediate Language) 본문뿐입니다. 함수의 JIT(Just-In-Time) 컴파일이 완료되기 전에 프로파일러에서 관리되는 호출을 메서드의 MSIL 본문에 삽입한 다음 JIT 컴파일할 수 있습니다. ICorProfilerInfo::GetILFunctionBody 메서드를 참조하십시오. 이 기술은 관리 코드의 선택적 계측에 사용할 수 있으며 JIT에 대한 통계 및 성능 데이터를 수집하는 데에도 사용할 수 있습니다.

또는 코드 프로파일러에서 비관리 코드로 호출되는 관리되는 각 함수의 MSIL 본문에 네이티브 후크를 삽입할 수 있습니다. 이 기술은 계측 및 검사에 사용될 수 있습니다. 예를 들어 코드 프로파일러에서 각 MSIL 블록 다음에 계측 후크를 삽입하여 해당 블록이 실행되었는지 확인할 수 있습니다. 메서드의 MSIL 본문을 수정하는 일은 매우 정교한 작업이며 고려해야 하는 요소가 많습니다.

맨 위로 이동

비관리 코드 프로파일링

CLR(공용 언어 런타임) 프로파일링 API에서는 비관리 코드 프로파일링을 최소한으로 지원합니다. 다음과 같은 기능이 제공됩니다.

  • 스택 체인 열거. 이 기능을 사용하면 코드 프로파일러에서 관리 코드와 비관리 코드의 경계를 결정할 수 있습니다.

  • 스택 체인이 관리 코드 또는 네이티브 코드에 해당하는지 확인

.NET Framework 버전 1.0 및 1.1에서는 이러한 메서드를 CLR 디버깅 API의 in-process 하위 집합을 통해서 사용할 수 있습니다. 이러한 메서드는 CorDebug.idl 파일에 정의되어 있으며 CLR 디버깅 개요에 설명되어 있습니다.

.NET Framework 2.0 이상에서는 이 기능에 대해 ICorProfilerInfo2::DoStackSnapshot 메서드를 사용할 수 있습니다.

맨 위로 이동

COM 사용

COM 인터페이스로 프로파일링 인터페이스를 정의하여도 CLR(공용 언어 런타임)에서는 이러한 인터페이스를 사용하기 위해 COM를 실제로 초기화하지 않습니다. 그 이유는 관리되는 응용 프로그램이 해당 응용 프로그램에 필요한 스레딩 모델을 지정하기 전에 CoInitialize 함수를 사용하여 스레딩 모델을 설정하지 않도록 하기 위해서입니다. 마찬가지로 프로파일에서 프로파일링되고 있는 응용 프로그램과 호환되지 않는 스레딩 모델을 선택할 수도 있고 응용 프로그램에 오류를 발생시킬 수 있으므로 프로파일러 자체도 CoInitialize를 호출해서는 안됩니다.

맨 위로 이동

호출 스택

프로파일링 API는 호출 스택을 가져오기 위한 두 가지 방법, 즉 호출 스택을 간격을 두고 수집할 수 있는 스택 스냅숏 메서드와 매순간 호출 스택을 추적하는 섀도 스택 메서드를 제공합니다.

스택 스냅숏

스택 스냅숏은 특정 순간의 스레드 스택을 추적한 것입니다. 프로파일링 API를 사용하면 스택에서 관리되는 함수를 추적할 수 있지만 관리되지 않는 함수는 프로파일러의 자체 스택 워커에서 추적합니다.

관리되는 스택 워크를 수행하도록 프로파일러를 프로그래밍하는 방법에 대한 자세한 내용은 이 설명서의 ICorProfilerInfo2::DoStackSnapshot 메서드 및 MSDN Library의 Profiler Stack Walking in the .NET Framework 2.0: Basics and Beyond를 참조하십시오.

섀도 스택

스냅숏 메서드를 너무 자주 사용하면 성능 문제가 발생할 수 있습니다. 스택 추적을 자주 수행하려면 스냅숏 메서드를 사용하는 대신 프로파일러에서 FunctionEnter2, FunctionLeave2, FunctionTailcall2ICorProfilerCallback2 예외 콜백을 사용하여 섀도 스택을 빌드해야 합니다. 섀도 스택은 항상 현재 상태이며 스택 스냅숏이 필요할 때마다 저장소에 빨리 복사할 수 있습니다.

섀도 스택은 제네릭 인스턴스화에 대한 함수 인수, 반환 값 및 정보를 가져올 수 있습니다. 이 정보는 섀도 스택을 통해서만 사용할 수 있으며 함수로 제어가 전달될 때 가져올 수 있지만, 나중에 함수가 실행되는 동안에는 사용할 수 없습니다.

맨 위로 이동

콜백 및 스택 수준

프로파일러 콜백은 스택이 매우 제한된 환경에서 호출될 수 있으며 프로파일러 콜백에서 스택 오버플로가 발생하면 프로세스가 즉시 종료됩니다. 프로파일러는 콜백에 대한 응답으로 가능한 한 적은 스택을 사용해야 합니다. 프로파일러를 스택 오버플로에 대해 안전한 프로세스에 사용하려는 경우에는 프로파일러 자체에서도 스택 오버플로를 트리거하지 않도록 해야 합니다.

맨 위로 이동

관련 항목

제목

설명

.NET Framework 2.0의 프로파일링

.NET Framework 버전 2.0 이상의 프로파일링에서 변경되거나 향상된 기능에 대해 설명합니다.

프로파일링 환경 설정

프로파일러를 초기화하고 이벤트 알림을 설정하며 Windows 서비스를 프로파일링하는 방법에 대해 설명합니다.

프로파일링 API의 로더 콜백

응용 프로그램 도메인, 어셈블리, 모듈 및 클래스를 로드하기 위해 발생하는 콜백을 설명합니다.

프로파일링 API의 가비지 수집

가비지 수집이 트리거, 감지 및 차단되는 방법을 설명합니다.

프로파일링 API의 개체 추적

가비지 수집 도중에 이동한 개체를 추적하는 방법을 설명합니다.

프로파일링 API의 개체 검사

프로파일러에서 메타데이터를 사용하여 개체에 대한 정보를 가져오는 방법을 설명합니다.

프로파일링 API의 예외 처리

프로파일러에서 예외 이벤트를 모니터링하는 방법을 설명합니다.

프로파일링 API의 코드 생성

프로파일러에서 자동 및 수동 코드 생성을 제어하는 방법을 설명합니다.

프로파일링 및 런타임 알림 ID

공용 언어 런타임에 의해 프로파일러로 전달되는 클래스, 스레드 및 응용 프로그램 도메인 ID에 대해 설명합니다.

프로파일링 API 메서드 규칙

HRESULT 반환 값, 프로파일링 API에서 사용할 반환 버퍼를 할당하는 방법 및 선택적 출력 매개 변수의 용도에 대해 설명합니다.

프로파일링 인터페이스

프로파일링 API에 사용되는 관리되지 않는 인터페이스를 설명합니다.

프로파일링 전역 정적 함수

프로파일링 API에 사용되는 관리되지 않는 전역 정적 함수를 설명합니다.

프로파일링 열거형

프로파일링 API에 사용되는 관리되지 않는 열거형을 설명합니다.

프로파일링 구조체

프로파일링 API에 사용되는 관리되지 않는 구조체를 설명합니다.

맨 위로 이동