'C# 성능'에 해당되는 글 1건

  1. 2009.08.07 Visual Studio 프로파일러를 사용한 응용 프로그램 병목 지점 찾기
2009.08.07 13:09

Visual Studio 프로파일러를 사용한 응용 프로그램 병목 지점 찾기

Visual Studio 프로파일러를 사용한 응용 프로그램 병목 지점 찾기
Hari Pulapaka and Boris Vidolov

이 기사에서 다루는 내용:
  • 성능 병목 지점 파악
  • 응용 프로그램 코드 프로파일링
  • 프로파일링 데이터 비교
  • 성능 보고서
이 기사에서 사용하는 기술: 
Visual Studio 2008
지난 10년 동안 많은 새로운 소프트웨어 기술과 플랫폼이 개발되었습니다. 새로운 각각의 기술에는 뛰어난 성능의 응용 프로그램을 만들기 위한 특별한 지식이 필요합니다. 지금은 블로그와 같은 인터넷 기술 덕분에 응용 프로그램에 실망한 사용자들이 손쉽게 부정적인 의견을 퍼뜨릴 수 있으므로 성능을 가장 중요한 요소로 고려해야 합니다. 계획의 초기에 응답성에 대한 요구 사항을 추가하고 가능한 기술 제한 사항을 파악하기 위한 프로토타입을 만들어야 합니다. 또한 개발 과정 전반에 걸쳐 응용 프로그램 성능을 여러 측면에서 평가하여 잠재적인 성능 저하를 찾아내고, 테스터를 통해 성능 저하 시나리오에 대한 버그를 정리 및 추적해야 합니다.
계획을 아무리 잘 세웠더라도 제품을 개발하는 과정에서 성능 문제를 계속 조사해야 합니다. 이번 기사에서는 Visual Studio® Team System Development Edition이나 Visual Studio Team Suite를 사용하여 응용 프로그램에서 성능 병목 지점을 찾는 방법을 살펴보겠습니다. 또한 샘플 성능 조사 연습을 통해 Visual Studio 프로파일러에 대해 알아봅니다. 이 기사에서는 코드 샘플을 작성하는 데 C#을 사용했지만 여기에 나오는 대부분의 예는 네이티브 C/C++ 및 Visual Basic® 코드에서도 유효합니다.

응용 프로그램 프로파일링
지금부터는 앞서 언급한 두 가지 Visual Studio 버전에서 제공되는 프로파일러를 사용하겠습니다. 먼저 그림 1에서 볼 수 있듯이 Mandelbrot 프랙탈을 그리는 간단한 샘플 프로젝트부터 시작하겠습니다. 이 응용 프로그램은 그다지 효율적이지 않아서 프랙탈을 그리는 데 10초 정도가 걸립니다.
그림 1 성능 테스트를 위한 대상 프로그램 (더 크게 보려면 이미지를 클릭하십시오.)
조사를 시작하려면 Visual Studio 2008의 새 Analyze(분석) 메뉴에서 Performance Wizard(성능 마법사)를 실행합니다. Visual Studio 2005의 경우 이 기능은 도구 | 성능 도구 메뉴에 있습니다. 그러면 3단계 마법사가 실행됩니다. 첫 번째 단계에서는 대상 프로젝트나 웹 사이트를 지정하고 두 번째 단계에서는 두 가지 프로파일링 방법, 즉 샘플링 및 계측을 제공합니다. 이러한 프로파일링 방법에 대한 자세한 내용은 "성능 프로파일링 설명" 보충 기사를 참조하십시오. 여기에서는 기본값을 사용합니다.
마법사가 완료되면 Performance Explorer(성능 탐색기) 대화 상자가 나타나고 새 성능 세션이 만들어집니다. 이 세션에는 대상 응용 프로그램(이 경우 Mandel)은 있고 보고서는 없습니다. 프로파일링을 시작하려면 도구 창 도구 모음에서 Launch with Profiling(프로파일링하며 실행) 단추를 클릭합니다.
응용 프로그램에서 프랙탈을 그린 후 바로 폼을 닫아 프로파일링을 중지합니다. Visual Studio는 자동으로 새로 만든 보고서를 성능 세션에 추가하고 분석하기 시작합니다. 분석이 완료되면 Visual Studio 프로파일러에서 Performance Report Summary(성능 보고서 요약)를 표시합니다. 여기에는 리소스 소모가 가장 큰 함수들이 나열됩니다(그림 2 참조). 이러한 함수는 두 가지 방식으로 표시됩니다. 첫 번째 방식에서는 나열된 함수에 의해 직접 또는 간접적으로 수행된 작업을 측정합니다. 각 함수에서 숫자는 함수 본문과 모든 하위 호출에서 수집된 누적 샘플을 나타냅니다. 두 번째 방식에서는 하위 호출에서 수집된 샘플을 계산하지 않습니다. 요약 페이지에는 Visual Studio 프로파일러가 DrawMandel 메서드 실행 중에 샘플의 30.71%를 수집했다고 표시되어 있습니다. 나머지 69%의 샘플은 다른 함수에 분산되어 있으며 여기에는 표시되지 않습니다. 보고 옵션에 대한 자세한 내용은 "보고서 시각화 옵션" 보충 기사를 참조하십시오.
그림 2 성능 테스트에서 리소스 소모가 큰 함수 호출 표시 (더 크게 보려면 이미지를 클릭하십시오.)
보고서에서 Call Tree(호출 트리) 보기(그림 3)의 Inclusive Samples %(포함 샘플 %) 열은 함수 및 이 함수의 자식에서 수집된 샘플을 나타냅니다. Exclusive Samples %(비포함 샘플 %) 열은 이 함수 본문에서만 수집된 샘플을 나타냅니다. DrawMandel 메서드가 Bitmap.SetPixel을 직접 호출하는 것을 볼 수 있습니다. DrawMandel 자체는 총 샘플의 30.71%를 유발했으며 Visual Studio 프로파일러는 Bitmap.SetPixel 및 그 자식으로부터 64.54%를 수집했습니다. Bitmap.SetPixel의 본문은 0.68%만 유발하므로 요약 페이지에 표시되지 않았습니다. 그러나 Bitmap.SetPixel은 자식을 통해 대부분의 처리 작업을 유발합니다. 바로 여기가 응용 프로그램의 실질적인 병목 지점입니다.
그림 3 테스트한 응용 프로그램의 호출 트리 샘플 (더 크게 보려면 이미지를 클릭하십시오.)
확실히 Bitmap.SetPixel은 Mandel 프로젝트의 목적과 잘 맞지 않습니다. 현재 응용 프로그램에는 폼의 모든 픽셀에 액세스하는 더 빠른 방법이 필요합니다. 다행히 Bitmap 클래스는 다른 유용한 API인 Bitmap.LockBits를 제공합니다. 이 함수를 사용하면 프로그램에서 비트맵 메모리로 직접 쓰기가 가능하므로 개별 픽셀을 설정하는 오버헤드를 줄일 수 있습니다. 또한 여기에서는 그리기 작업을 최적화하도록 평면 정수 배열을 만들어 각 픽셀의 색상값으로 채웁니다. 그런 다음 이 배열의 값을 하나의 작업으로 비트맵에 복사합니다.

응용 프로그램 최적화
성능 프로파일링 설명
샘플링 방법을 사용하여 프로파일링을 수행하는 경우 프로파일러는 디버거와 비슷한 방식으로 실행 중인 프로세스에 연결됩니다. 그런 다음 프로파일러는 정기적으로 프로세스를 인터럽트하여 스택의 맨 위에 있는 함수와 이 함수로 이어지는 코드 경로를 검사합니다. 즉, Visual Studio 프로파일러는 현재 프로세스 상태의 샘플을 수집합니다. 샘플링은 작업을 방해하지 않는 통계적 프로파일링 접근 방식입니다. 함수에서 수집되는 샘플이 많을수록 함수가 수행하는 처리 작업이 많은 것입니다.
또한 Visual Studio 프로파일러는 이 실행으로 이어지는 호출 경로에 대한 정보를 수집합니다. 따라서 수집된 데이터를 분석한 후 전체 호출 스택을 표시할 수 있습니다. 기본적으로 Visual Studio 프로파일러는 1000만 CPU 사이클당 하나의 샘플을 수집합니다. CPU 사이클 외에도 페이지 오류, 시스템 호출, CPU 캐시 누락 등 다른 많은 이벤트에서 샘플링이 발생할 수 있습니다. 프로파일링 세션의 속성은 프로파일러가 샘플링하는 대상과 그 빈도를 제어합니다.
샘플링은 오버헤드가 낮은 솔루션으로 자주 권장되는 옵션입니다. 그러나 샘플링은 프로그램에서 CPU를 활발하게 사용하는 경우에만 정보를 수집한다는 점에 유의해야 합니다. 따라서 프로세스가 디스크, 네트워크 또는 기타 리소스를 대기 중인 경우 Visual Studio 프로파일러는 샘플을 수집하지 않습니다. 이러한 이유로 인해 응용 프로그램이 CPU를 활발하게 사용하지 않는 경우에는 계측 프로파일링을 사용하는 것이 좋습니다.
계측 모드에서 Visual Studio 프로파일러는 각 함수 시작과 끝에 특별한 명령(호출된 프로브)을 삽입하여 바이너리를 수정(계측)합니다. 프로브를 사용하면 각 함수를 실행하는 데 걸리는 시간을 측정할 수 있습니다. 또한 프로파일러는 각 외부 함수 호출에 한 쌍의 프로브를 추가하여 이러한 외부 호출의 리소스 소모 정도를 확인할 수 있습니다.
계측 프로파일링을 사용하면 함수 실행 시간(경과된 시간), 호출 횟수를 비롯해 CPU를 사용한 시간(응용 프로그램 시간)과 OS에 의해 교체되지 않은 시간 등의 데이터까지 정확히 측정할 수 있습니다. 이러한 계측의 단점은 많은 양의 데이터 수집으로 인한 긴 분석 시간입니다. 또한 이 프로파일링 모드는 런타임 오버헤드가 더 높습니다. 오버헤드가 높으면 프로파일링하는 응용 프로그램의 성능 특성이 의도하지 않게 바뀔 수 있습니다.
샘플링과 계측 방법 모두 Microsoft®.NET Framework를 기반으로 응용 프로그램에 대한 메모리 할당 데이터도 수집할 수 있습니다. 사용자는 성능 세션 속성 페이지를 통해 .NET 메모리 할당 데이터 수집 기능을 설정 및 조정할 수 있습니다. 이 기능은 보통 메모리 프로파일링이라고 하며, 이 주제에 대한 포괄적인 MSDN® 설명서가 있습니다. 메모리 프로파일링은 .NET Framework 호환 코드에서만 사용할 수 있는 프로파일러 기능입니다. Visual Studio 프로파일러의 나머지 기능은 네이티브 C/C++ 및 .NET 기반 응용 프로그램 간에 완전히 동일합니다.

SetPixel 대신 LockBits를 사용하도록 DrawMandel 메서드를 수정하고 이를 통해 어떤 성능 이점이 있는지 알아보겠습니다. 비트맵을 만든 후 다음 줄을 추가하여 비트맵 비트를 잠그고 비트맵 메모리에 대한 포인터를 가져옵니다.
BitmapData bmpData = 
    bitmap.LockBits(
        new Rectangle(0, 0, Width, Height), 
        ImageLockMode.ReadWrite, 
        bitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int pixels = bitmap.Width * bitmap.Height;
Int32[] rgbValues = new Int32[pixels];
그런 다음 픽셀을 설정한 안쪽 루프에서 다음과 같이 Bitmap.SetPixel 호출을 주석으로 처리하고 새로운 문으로 대체합니다.
//bitmap.SetPixel(column, row, colors[color]);
rgbValues[row * Width + column] = 
    colors[color].ToArgb();
다음 줄도 추가하여 비트맵 메모리에 배열을 복사합니다.
Marshal.Copy(rgbValues, 0, ptr, pixels);
bitmap.UnlockBits(bmpData);
이제 프로파일러에서 응용 프로그램을 다시 실행하면 프랙탈을 그리는 시간이 3배 정도 빨라졌음을 확인할 수 있습니다(그림 4 참조). 새 성능 보고서의 요약 페이지에서는 DrawMandel 본문이 총 샘플의 83.66%를 직접 유발하는 것을 볼 수 있습니다. 그리기 작업을 최적화했으므로 이제 프랙탈 계산이 병목 지점입니다.
그림 4 수정한 코드의 성능 프로필 (더 크게 보려면 이미지를 클릭하십시오.)
이제 한 단계 더 나아가 계산도 최적화하겠습니다. 하지만 이번에는 단일 함수에서 병목 지점을 찾아야 합니다. DrawMandel은 복잡한 메서드라서 초점을 맞출 계산을 알아내기가 어렵습니다. 다행히 Visual Studio 2008 샘플링 프로파일러는 기본적으로 줄 수준 데이터도 수집하므로 이를 통해 함수에서 리소스 소모가 가장 큰 줄을 찾을 수 있습니다.
줄 수준 데이터를 보기 위해 다른 관점에서 성능 보고서를 검사해 보겠습니다. Current View(현재 보기) 메뉴에서 Modules(모듈) 보기로 전환합니다. Call Tree(호출 트리) 보기와 달리 Modules(모듈) 보기에는 함수가 서로 호출하는 방식과 이러한 호출이 부모 함수의 컨텍스트에서 성능에 미치는 영향에 대한 정보가 표시되지 않습니다. 대신 Modules(모듈) 보기에는 실행 파일(어셈블리 또는 DLL)당, 그리고 해당 실행 파일의 함수당 누적된 총 샘플 수가 표시됩니다. Visual Studio 프로파일러는 모든 호출 스택에서 이 데이터를 누적합니다.
Modules(모듈) 보기는 보다 전체적인 관점에서 관찰하기 위한 용도로 적합합니다. 예를 들어 Exclusive Samples %(비포함 샘플 %) 열을 기준으로 정렬하면 Mandel.exe가 처리 자체의 87.57%를 수행한다는 사실을 볼 수 있습니다. 최적화 결과 GDI+가 차지하는 비율은 3% 미만입니다. 이러한 모듈을 확장하면 개별 메서드에 대해서도 동일한 정보를 볼 수 있습니다. 또한 Visual Studio 2008에서는 함수 수준 이상으로 트리를 확장하고 개별 줄 또는 이러한 줄의 개별 문에 대해서도 동일한 데이터를 확인할 수 있습니다(그림 5 참조).
그림 5 프로파일링한 코드 줄로 이동 (더 크게 보려면 이미지를 클릭하십시오.)
해당 소스로 이동하면 그림 6의 코드가 나타납니다. 이 코드에서는 가장 안쪽의 루프 조건에서 제곱근을 계산합니다. 이 작업은 리소스 소모가 커서 전체 응용 프로그램 처리 중 18%를 차지합니다. 그림 6에서 강조 표시된 줄은 최적화할 수 있는 코드입니다. 첫 번째 줄은 불필요한 제곱근을 사용하며 두 번째 줄은 while 루프에서 변하지 않습니다.


원래 코드 

for (int column = 1; column < Width; column++)
{
 y = yStart;
 for (int row = 1; row < Height; row++)
 {
  double x1 = 0;
  double y1 = 0;
  int color = 0;
  int dept = 0;
  while (dept < 100 && Math.Sqrt((x1 * x1) + (y1 * y1)) < 2)
  {
   dept++;
   double temp = (x1 * x1) - (y1 * y1) + x;
   y1 = 2 * x1 * y1 + y;
   x1 = temp;
   double percentFactor = dept / (100.0);
   color = ((int)(percentFactor * 255));
  }
  //Bitmap.SetPixel: 호출을 방지하기 위해 이 줄을 주석 처리
  //bitmap.SetPixel(column, row, colors[color]);
  //Bitmap.SetPixel: 호출을 방지하려면 아래 줄을 주석으로 처리해야 함
  rgbValues[row * Width + column] = colors[color].ToArgb();

  y += deltaY;
 }
 x += deltaX;
}


최적화된 코드 

for (int column = 1; column < this.Width; ++column)
{
 y = yStart;
 int index = column;
 for (int row = 1; row < Height; row++)
 {
  double x1 = 0;
  double y1 = 0;
  int dept = 0;
  double x1Sqr, y1Sqr;
  while (dept < 100 && ((x1Sqr = x1 * x1) + (y1Sqr = y1 * y1)) < 4)
  {
   dept++;
   double temp = x1Sqr - y1Sqr + x;
   y1 = 2 * x1 * y1 + y;
   x1 = temp;
  }
  rgbValues[index] = colors[((int)(dept * 2.55))].ToArgb();
  index += Width;

  y += deltaY;
 }
 x += deltaX;
}  
수정한 후 응용 프로그램을 다시 프로파일링하고 최적화된 코드 성능을 확인해 보겠습니다. 응용 프로그램을 빌드하고 실행하면 이제 프랙탈이 1 - 2초 만에 다시 그려집니다. 응용 프로그램 시작 시간이 눈에 띄게 줄었습니다.
Visual Studio 2008에는 두 가지 성능 보고서를 비교할 수 있는 새로운 기능이 있습니다. 이 기능의 작동을 확인하려면 프로파일러에서 응용 프로그램을 다시 실행하고 최신 성능 보고서를 캡처합니다. 두 응용 프로그램 버전 간의 차이를 보려면 Performance Explorer(성능 탐색기)에서 원래 보고서와 최신 보고서를 선택합니다. 보고서를 마우스 오른쪽 단추로 클릭하고 컨텍스트 메뉴에서 Compare Performance Reports(성능 보고서 비교) 옵션을 클릭합니다. 그러면 모든 함수의 기본 보기와 두 보고서에서 해당 함수의 Exclusive Samples %(비포함 샘플 %) 값 사이의 차이를 보여 주는 새 보고서가 나타납니다. 전체 실행 시간이 줄어들었기 때문에 DrawMandel의 상대적 비율도 31.76%에서 70.46%로 높아졌습니다.
실제 최적화를 더 잘 보려면 비교 옵션 창에서 열을 포함 샘플로 변경합니다(그림 7 참조). 사소한 변동은 표시되지 않도록 임계값을 1500개 샘플로 높입니다. 또한 이 보고서는 역행을 찾는 데 자주 사용되므로 기본적으로 음수(negative) 데이터 또는 최적화 정도가 가장 낮은 함수를 먼저 표시합니다. 여기에서는 최적화를 위해 Delta(변화량) 열을 반대로 정렬하여 가장 최적화 정도가 높은 함수를 맨 위에 표시합니다. DrawMandel 및 자식의 샘플이 2,064에서 175로 변경된 것을 알 수 있습니다. 10배 이상의 최적화입니다! 보고서에서 원하는 부분을 복사하고 붙여 넣어서 이러한 성능 향상을 다른 사람들에게 보여 줄 수 있습니다.
그림 7 DrawMandel의 최적화 결과 비교 (더 크게 보려면 이미지를 클릭하십시오.)

대상 프로파일링
보고서 시각화 옵션
Visual Studio에서는 호출 트리, 모듈, 함수 등의 다양한 성능 보고서 옵션을 사용하여 여러 가지 방식으로 성능 데이터를 볼 수 있습니다. 요약은 보고서를 열 때 기본적으로 사용되는 보기입니다. 예를 들어 Visual Studio 2008에서 가장 많은 처리를 유발한 호출 경로를 찾으려면 Current View(현재 보기) 메뉴에서 Call Tree(호출 트리)를 선택합니다. Visual Studio 2005에서는 보고서 맨 아래에 있는 호출 트리 탭을 선택합니다. Call Tree(호출 트리) 보기에는 모든 호출 스택의 집계된 트리가 포함됩니다. Inclusive Samples %(포함 샘플 %) 열에는 해당 코드 경로에 있는 각 분기의 집계된 리소스 소비량이 표시됩니다. 리소스 소모량이 가장 많은 분기를 따라가 보면 병목 지점을 찾을 수 있습니다.
프로파일러 팀은 Visual Studio 2008에 성능 보고서 사용을 간소화하는 두 가지 새로운 기능을 추가했습니다. 첫 번째 기능은 노이즈 감소 옵션입니다. 이제 기본적으로 보고서는 중요하지 않은 작은 함수를 잘라내므로 사용자는 보다 영향력이 큰 함수를 손쉽게 볼 수 있습니다. 일반적으로 이 옵션을 가지치기(trimming)라고 합니다. 또한 자체적으로는 아무 작업도 처리하지 않고 다른 함수를 호출하여 처리하는 함수를 한데 겹치는 방법으로 호출 트리의 깊이를 줄였습니다. Visual Studio 프로파일러에서는 이 기능을 접기(folding)라고 합니다.
성능 보고서에서 노이즈 감소 옵션은 가지치기와 접기에 대한 임계값을 제어합니다. 성능 보고서에서 특정 함수를 찾는 데 문제가 발생한 경우 노이즈 감소 옵션을 해제할 수 있습니다.
Visual Studio 2008의 호출 트리에서 크게 향상된 두 번째 기능은 Hot Path(실행 부하 과다 경로) 단추 및 관련 컨텍스트 메뉴입니다. Hot Path(실행 부하 과다 경로)는 프로그램에서 리소스 소모가 가장 큰 코드 경로를 강조 표시하고, 단일 함수에 의해 다량의 처리 작업이 수행되는 경우(위임 없이)를 발견할 때까지 이 경로를 따라갑니다. 이러한 경우를 발견하면 해당 함수를 강조 표시합니다. 중요한 코드 경로가 두 개 이상이면 Hot Path(실행 부하 과다 경로)는 분기가 발생하는 트리 위치에서 멈춥니다. Hot Path(실행 부하 과다 경로)가 응용 프로그램에 대해 두 개 이상의 분기를 제공하는 경우 원하는 분기를 선택하여 해당 분기에 대해 Hot Path(실행 부하 과다 경로)를 다시 적용할 수 있습니다.

지금까지 응용 프로그램 성능을 향상시키기 위해 Visual Studio 프로파일러를 사용하는 방법을 알아보았습니다. 그러나 실제 환경의 응용 프로그램에서는 여러 사용자 동작을 시도하면서 성능 문제를 찾아야 하는 경우가 많습니다. 일반적으로 시나리오를 시작하기 전에 수집한 데이터는 무시합니다. 또한 한 번 실행으로 여러 시나리오의 데이터를 수집해야 하는 경우가 있습니다.
이러한 경우 프로파일러를 사용하는 방법을 알아보기 위해 대상을 바꿔 샘플 전자 상거래 웹 사이트를 프로파일링하겠습니다. 여기에 사용된 웹 사이트는asp.net/downloads/starter-kits/the-beer-house에서 제공하는 TheBeerHouse 샘플을 수정한 버전입니다. 이 웹 사이트는 로드하는 데 오랜 시간이 걸리지만 로드는 한 번으로 끝나는 문제이므로 여기에서는 시작 시간보다는 제품 카탈로그를 로드하는 데 시간이 많이 소요되는 이유와 장바구니에 물품을 담는 작업의 속도가 느린 이유에 초점을 맞추겠습니다.
이 기사에서는 설명을 위해 첫 번째 시나리오에 대한 조사만 다룹니다. 그러나 두 시나리오에서 모두 데이터를 수집하고, 이 데이터를 필터링하여 특정 시나리오의 성능 문제에 초점을 맞추는 방법을 살펴봅니다.
먼저 새 프로파일링 세션을 만듭니다. 앞에서와 마찬가지로 Analyze(분석) 메뉴에서 Performance Wizard(성능 마법사)를 실행한 다음 마법사 페이지에서 모두 기본값을 선택합니다. 웹 사이트의 경우 계측 프로파일링이 기본 옵션입니다. 웹 사이트는 CPU에 묶이지 않는 경우가 많습니다. 일반적으로 웹 사이트는 데이터베이스 서버 응용 프로그램에 의존하여 무거운 작업을 처리합니다. 따라서 계측 방식이 더 바람직합니다.
성능 세션을 만든 후에 프로파일러에서 웹 사이트를 실행합니다. 단, 여기에서는 시작 시간 수집은 피하고 한 번에 하나의 시나리오에만 초점을 맞춥니다. Visual Studio 2008에서 이를 수행하려면 Performance Explorer(성능 탐색기)에서 Launch with Profiling Paused(프로파일링을 일시 중지하고 실행) 옵션을 사용하여 응용 프로그램을 시작합니다. 이때 Visual Studio 프로파일러는 응용 프로그램에 연결되지만 사용자가 프로파일링을 재개하지 않는 한 데이터를 수집하지 않습니다(그림 8 참조).
그림 8 실행 시 프로파일러 일시 중지 
웹 사이트가 로드되는 동안 Visual Studio로 다시 전환합니다. Visual Studio 프로파일러는 Data Collection Control(데이터 수집 제어)이라는 새 도구 창을 표시합니다. 이 창에서는 수집을 몇 번이고 일시 중지하고 재개할 수 있습니다. 이 제어에서 중요한 부분은 미리 정의된 표시 목록입니다. 이러한 표시는 책갈피 또는 레이블로, 프로파일링 데이터에 삽입하여 원하는 지점을 표시할 수 있습니다. 여기에서는 이러한 표시를 사용하여 각 사용자 시나리오의 시작과 끝을 구분합니다.
먼저 컨텍스트 메뉴의 Rename Mark(표시 이름 바꾸기) 명령을 사용하여 4개의 표시 이름을 바꿉니다. 또한 사용하지 않는 표시는 제거합니다(그림 9 참조). 지금까지 프로파일링을 일시 중지하여 시작 시간 수집을 피하고 시나리오를 준비했습니다. 웹 사이트가 로드된 후 프로파일링을 재개합니다.
그림 9 테스트 시나리오를 위한 프로필 표시 이름 지정 
첫 번째 시나리오를 시작할 준비가 되었습니다. Product Catalog Request(제품 카탈로그 요청) 표시를 선택하고 Insert Mark(표시 삽입) 단추를 클릭하여 이 시나리오의 시작을 표시합니다. 그런 다음 Internet Explorer®로 돌아와서 제품 카탈로그를 표시하여 첫 번째 시나리오를 완료합니다. 웹 사이트에 카탈로그가 표시된 후 Product Catalog Rendered(렌더링한 제품 카탈로그) 표시를 삽입하여 시나리오 끝을 표시합니다. 다음 시나리오로 전환하기 위해 Beer cap 제품을 선택합니다. 마찬가지로, 추가 항목 앞뒤에 각각의 표시를 삽입합니다. 이것으로 시나리오를 모두 마쳤으므로 응용 프로그램을 종료합니다.
데이터 분석이 완료되면 Visual Studio 프로파일러에서 Performance Report Summary(성능 보고서 요약)를 표시합니다. 이 보고서는 가장 많이 호출된 함수와 가장 긴 함수 지속 시간을 포함한다는 점에서 샘플링 보고서와는 조금 다릅니다. 이 데이터는 응용 프로그램 수명 주기에 걸쳐 집계되고 두 시나리오와 이전의 모든 활동을 포함한다는 점이 중요합니다.
확실히 성능 보고서에는 지정된 시나리오에 대한 데이터만 표시되고 나머지는 필터링을 통해 제외되는 편이 좋습니다. Visual Studio 2008의 프로파일러에는 삽입된 모든 표시를 보여 주는 새로운 Marks(표시) 보기가 있습니다. Visual Studio 프로파일러는 프로그램 시작과 끝에 추가 자동 표시를 삽입합니다. 첫 번째 시나리오에 대한 필터를 만들려면 해당 시나리오의 시작과 끝을 나타내는 표시를 선택하고 컨텍스트 메뉴에서 Add Filter on Marks(표시에 필터 추가)를 선택합니다. 그러면 필요한 필터가 자동으로 만들어집니다(그림 10 참조). 표시 이외에도 스레드, 프로세스 또는 시간 간격을 기준으로 필터링할 수 있습니다. 필터를 설정했으므로 이제 실행할 수 있습니다.
그림 10 성능 테스트를 위한 대상 프로그램 (더 크게 보려면 이미지를 클릭하십시오.)
이 필터링은 성능 보고서의 모든 보기에 적용됩니다. 이 부분이 Visual Studio 프로파일러가 필터링된 데이터에 대한 새 요약 페이지를 자동으로 표시하는 이유입니다. 이 요약 페이지는 제품 카탈로그 렌더링 시나리오에만 적용됩니다. 예를 들어 System.IDisposable.Dispose에는 시나리오 실행 시간의 61%에 해당하는 3.4초가 소요됨을 볼 수 있습니다(이전에는 41%). 필터링을 통해 이 함수가 특정 문제에 얼마나 중요한지 확실히 알 수 있게 되었습니다.
이제 이 성능 문제를 수정할 차례입니다. 코드에서 이러한 개체 처리를 유발한 함수를 찾아야 합니다. 가장 쉬운 방법은 그림 11과 같이 Hot Path(실행 부하 과다 경로) 기능과 함께 Call Tree(호출 트리)를 사용하는 것입니다. 그러면 바로 SetInputControlsHighlight 함수가 대부분의 IDisposable.Dispose 호출을 유발한다는 점을 알 수 있습니다.
그림 11 Hot Path(실행 부하 과다 경로)를 사용하여 문제 찾기 (더 크게 보려면 이미지를 클릭하십시오.)
다음과 같이 함수에 비효율적인 로깅 메커니즘이 있다는 사실이 드러납니다.
foreach (Control ctl in container.Controls) {
  log += "Setting up control: " + ctl.ClientID;
  string tempDir = 
    Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
  using (StreamWriter sw = new StreamWriter(
    Path.Combine(tempDir, "WebSite.log"), true)) {
    sw.WriteLine(log);
  }
 ...
이는 디버깅 중에 실수로 남겨 둔 포괄적인 로깅으로, 더 이상 특정 진단 기능을 수행하지 않으므로 제거해도 됩니다. 이번에도 Visual Studio 2008의 Hot Path(실행 부하 과다 경로) 기능을 사용하면 응용 프로그램의 병목 지점을 신속히 파악할 수 있습니다.
네이티브 C/C++, C# 또는 Visual Basic 중 어떤 언어로 응용 프로그램을 작성하든 Visual Studio 프로파일러는 성능 조사 과정을 대폭 간소화하여 보다 빠르고 효율적인 응용 프로그램을 작성하도록 도와 줍니다. Visual Studio 2008은 Visual Studio 프로파일러를 더욱 강화하여 프로그램의 성능 병목 지점을 훨씬 더 쉽게 찾을 수 있게 해 줍니다.



Trackback 0 Comment 0