[profiling] gprof에 대한 대안 [닫기]

다른 프로그램은 gprof와 같은 기능을 수행합니까?



답변

Valgrind 에는 KCacheGrind 라는 매우 훌륭한 시각화 도구가 포함 된 명령어 수 프로파일 러가 있습니다. Mike Dunlavey가 권장 한 것처럼 Valgrind는 스택에 프로 시저가 존재하는 명령의 일부를 계산하지만 상호 재귀가있는 경우 혼란스러워하는 것은 유감입니다. 그러나 비주얼 라이저는 매우 훌륭하고 수년 앞서 gprof있습니다.


답변

역사적인 이유로 gprof (논문 읽기) 가 존재합니다. 성능 문제를 찾는 데 도움이 될 것이라고 생각되면 결코 광고되지 않았습니다. 논문의 내용은 다음과 같습니다.

이 프로파일을 사용하여 다양한 구현 비용을 비교하고 평가할 수 있습니다.

할 수 있습니다 말하지 않는다 식별 는 않지만, 평가 될 수있는 다양한 구현을 의미하는 특별한 상황에서, 그것은 수 :

특히 프로그램의 작은 부분이 실행 시간을 지배하는 것으로 밝혀진 경우.

현지화되지 않은 문제는 어떻습니까? 중요하지 않습니까? 결코 주장 하지 않은 gprof에 대한 기대를 두지 마십시오 . 그것은입니다 만 CPU 바인딩 작업, 측정 도구.

대신 사용해보십시오.
다음은 44 배 속도 향상의 예입니다.
속도는 730 배입니다.
다음은 8 분 비디오 데모입니다.
통계에 대한 설명은 다음과 같습니다.
비평에 대한 답변입니다.

프로그램에 대한 간단한 관찰이 있습니다. 주어진 실행에서 모든 명령은 전체 시간의 일부 (특히 call명령)에 책임 이 있으며, 그렇지 않은 경우 시간이 소비되지 않습니다. 이 시간 동안 명령은 스택 **에 있습니다. 그것이 이해되면, 당신은 그것을 볼 수 있습니다-

gprof 는 다음과 같은 성능에 대한 신화를 구현합니다.

  1. 해당 프로그램 카운터 샘플링이 유용합니다.
    기포 종류의 스칼라 값 배열과 같은 불필요한 핫스팟 병목 현상이있는 경우에만 유용합니다. 예를 들어, 문자열 비교를 사용하여 정렬로 변경하면 여전히 병목 현상이 발생하지만 핫스팟이 문자열 비교이므로 프로그램 카운터 샘플링에서이를 볼 수 없습니다. 반면에 확장 프로그램 카운터 (호출 스택) 를 샘플링 하는 경우 문자열 비교가 호출되는 지점 인 정렬 루프가 명확하게 표시됩니다. 실제로 gprof 는 pc 전용 샘플링의 한계를 해결하려는 시도였습니다.

  2. 시간이 많이 걸리는 코드 라인을 캡처하는 것보다 타이밍 기능이 더 중요합니다.
    그 신화의 이유는 gprof 가 스택 샘플을 캡처 할 수 없었기 때문에 대신 함수 시간을 지정하고 호출을 계산하며 호출 그래프를 캡처하려고 시도하기 때문입니다. 그러나 비용이 많이 드는 기능이 식별 된 후에도 여전히 해당 기능을 담당하는 회선을 찾아야합니다. 스택 샘플이있는 경우 살펴볼 필요가없는 경우 해당 라인은 샘플에 있습니다. 일반적인 함수에는 100-1000 개의 명령어가있을 수 있습니다. 함수 호출 은 1 개의 명령어이므로 비용이 많이 드는 호출을 찾는 것은 2-3 배 더 정확합니다.

  3. 통화 그래프가 중요합니다.
    프로그램에 대해 알아야 할 것은 시간을 소비하는 이 아니라 . 함수에서 시간을 보낼 때 스택의 모든 코드 줄은 이유에 대한 추론 체인에서 하나의 링크를 제공합니다. 스택의 일부만 볼 수 있다면 이유의 일부만 볼 수 있으므로 해당 시간이 실제로 필요한지 확실하게 알 수 없습니다. 콜 그래프는 무엇을 알려줍니까? 각 호는 일부 함수 A가 일부 시간 동안 일부 함수 B를 호출하는 중임을 나타냅니다. A에 B를 호출하는 코드 줄이 하나만 있더라도 그 줄은 이유의 작은 부분만을 제공합니다. 당신이 충분히 운이 좋으면 아마도 그 라인에 나쁜 이유가있을 것입니다. 일반적으로 여러 개의 동시 회선을 확인하여 잘못된 이유가있는 경우이를 찾아야합니다. A가 둘 이상의 장소에서 B를 호출하면 덜 알려줍니다.

  4. 그 재귀는 까다로운 혼란스러운 문제입니다. gprof 및 기타 프로파일 러는 호출 그래프를 생성 한 다음 시간을 노드에 부여해야한다는 필요성을 인식
    하기 때문 입니다. 스택의 샘플이있는 경우 샘플에 나타나는 각 코드 줄의 시간 비용은 샘플의 일부인 매우 간단한 숫자입니다. 재귀가 있으면 주어진 줄이 샘플에 두 번 이상 나타날 수 있습니다.
    문제 없어. Nms마다 샘플을 채취하고 그 라인이 F %에 표시된다고 가정합니다. 해당 라인을 삭제하거나 주변으로 분기하는 등의 시간이 걸리지 않으면 해당 샘플이 사라지고 시간이 F % 감소합니다.

  5. 시간 측정 정확도 (따라서 많은 수의 샘플)가 중요합니다.
    잠깐 생각 해봐 한 줄의 코드가 5 개 중 3 개의 샘플에 있다면, 전구처럼 쏠 수 있다면 사용 시간이 약 60 % 단축됩니다. 이제 5 개의 다른 샘플을 채취 한 경우 2 회 또는 4 회만 보았을 것입니다. 따라서 60 % 측정은 40 %에서 80 %의 일반적인 범위와 비슷합니다. 40 %에 불과한 경우 문제를 해결할 가치가 없다고 말할 수 있습니까? 그래서 당신이 정말로 원하는 것이 문제찾는 것이라면 시간의 정확성은 무엇 입니까? 500 또는 5000 개의 샘플이 문제를 더 정밀하게 측정했지만 더 정확하게 발견하지는 못했습니다.

  6. 명령문 또는 함수 호출 수를 계산하는 것이 유용합니다.
    함수가 1000 번 호출되었다고 가정 해 봅시다. 비용의 몇 분의 시간을 알 수 있습니까? 또한 평균 실행 시간과 횟수를 곱한 후 총 시간으로 나누는 데 걸리는 시간을 알아야합니다. 평균 호출 시간은 나노초에서 초까지 다양 할 수 있으므로 카운트만으로는 많은 것을 알 수 없습니다. 스택 샘플이있는 경우 루틴 또는 명령문의 비용은 해당 샘플의 일부에 불과합니다. 루틴 또는 명령문이 시간을 소비하지 않으면 원칙적으로 전체 시간을 절약 할 수 있으므로 성능과 가장 직접적인 관계가있는 것입니다.

  7. 차단 될 때 샘플을 채취 할 필요가 없음
    이 신화의 이유는 1) 프로그램이 대기 중일 때 PC 샘플링이 의미가 없다는 것과 2) 타이밍 정확도가 높은 사전 점유입니다. 그러나 (1)의 경우 프로그램은 파일 I / O, 알아야 할 파일 및 어떤 스택 샘플이 표시 하는지 와 같이 요청한 내용을 매우 잘 기다리고있을 수 있습니다 . (물론 사용자 입력을 기다리는 동안 샘플을 제외하려고합니다.) (2) 프로그램이 다른 프로세스와의 경쟁 때문에 단순히 대기중인 경우, 실행되는 동안 상당히 임의의 방식으로 발생합니다. 따라서 프로그램이 오래 걸리더라도 통계에 큰 영향을 미치지는 않지만 명령문이 스택에있는 시간의 백분율입니다.

  8. “자체 시간”이 중요합니다.
    셀프 시간은 라인 레벨이 아닌 기능 레벨에서 측정하는 경우에만 의미가 있으며, 함수 시간이 순전히 로컬 계산과 호출 된 루틴 사이에 있는지 판단하는 데 도움이 필요하다고 생각합니다. 라인 레벨에서 요약 할 경우, 라인은 스택의 끝에있는 경우 자체 시간을 나타내며, 그렇지 않으면 포함 시간을 나타냅니다. 어느 쪽이든, 비용은 스택 샘플의 백분율이므로 어느 쪽이든 찾을 수 있습니다.

  9. 샘플을 고주파수로 가져와야합니다.
    이것은 성능 문제가 빠르게 작용할 수 있고, 샘플을 자주 치기 위해서는 샘플이 자주 있어야한다는 생각에서 비롯됩니다. 그러나 문제가 총 실행 시간 10 초 (또는 그 밖의 시간) 중 20 %를 차지하는 경우 문제가 발생하더라도 해당 총 시간의 각 샘플은 20 %의 확률로 적중 할 수 있습니다. 이와 같은 단일 조각
    .....XXXXXXXX...........................
    .^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^(20 샘플, 4 적중)
    또는 이와 같은 많은 작은 조각
    X...X...X.X..X.........X.....X....X.....
    .^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^.^(20 샘플, 3 적중)
    또는 적중 횟수는 샘플 수에 관계없이 평균 약 5 분의 1입니다. 얼마나 적은. (평균 = 20 * 0.2 = 4. 표준 편차 = +/- sqrt (20 * 0.2 * 0.8) = 1.8.)

  10. 병목 현상
    이 하나만있는 것처럼 찾으려고 합니다 . 다음과 같은 실행 타임 라인을 고려하십시오 .로 vxvWvzvWvxvWvYvWvxvWv.vWvxvWvYvW
    표시되는 유용한 작업으로 구성됩니다 .. 각각 vWxYz1/2, 1/4, 1/8, 1/16, 1/32의 성능 문제 가 있습니다. 샘플링은 v쉽게 찾을 수 있습니다. 프로그램이 제거 된 후 제거됩니다.
    xWzWxWYWxW.WxWYW
    이제 프로그램을 실행하는 W데 절반의 시간이 걸리고 이제 절반의 시간이 걸리며 쉽게 찾을 수 있습니다. 제거, 남겨두기
    xzxYx.xY
    제거 할 항목을 찾을 수 없을 때까지 성능 문제를 백분율별로 가장 크게 제거 할 때마다이 프로세스가 계속됩니다. 이제 실행되는 유일한 것은 .원래 프로그램에서 사용한 시간의 1/32로 실행됩니다. 이것이 확대 효과입니다분모가 줄어들 기 때문에 문제를 제거하면 나머지가 백분율로 더 커집니다.
    또 하나의 중요한 점은 모든 단일 문제를 찾아야한다는 것 입니다. 5 중 하나도 없습니다. 발견되지 않고 수정 된 문제는 최종 속도 향상 비율을 크게 줄입니다. 전부는 아니지만 일부를 찾는 것만으로는 충분하지 않습니다.

추가 : 나는 gprof 가 인기있는 이유 중 하나를 지적하고 싶습니다 -아마도 무료이며 가르치기 쉽고 오랫동안 사용되어 왔기 때문에 아마도 가르치고 있습니다. 빠른 Google 검색은 다음과 같은 교육 기관을 찾습니다 (또는 보이는 것처럼 보입니다).

버클리 부 clemson 콜로라도 듀크 백작 fsu 인디애나 mit msu ncsa.illinois ncsu nyu ou princeton ps stanford ucsd umd umich utah utexas utk wustl

** 작업 수행을 요청하는 다른 방법을 제외 하고 메시지 게시와 같은 이유를 알려주는 흔적을 남기지 않습니다 .


답변

perfLinux에서 커널 및 사용자 응용 프로그램을 프로파일 링하는 비교적 새로운 도구에 대한 내용은 여기에서 보지 않았 으므로이 정보를 추가하기로 결정했습니다.

우선-이것은 리눅스 프로파일 링 에 대한 튜토리얼 입니다perf

perfLinux 커널이 2.6.32보다 크거나 oprofile오래된 경우 사용할 수 있습니다 . 두 프로그램 모두 프로그램을 인스트루먼트 할 필요가 없습니다 (예 : gprof필요). 그러나 콜 그래프를 올바르게 얻으려면로 perf프로그램을 작성해야합니다 -fno-omit-frame-pointer. 예를 들면 다음과 같습니다 g++ -fno-omit-frame-pointer -O2 main.cpp..

다음을 통해 애플리케이션의 “실시간”분석을 볼 수 있습니다 perf top.

sudo perf top -p `pidof a.out` -K

또는 실행중인 응용 프로그램의 성능 데이터를 기록한 후 분석 할 수 있습니다.

1) 성능 데이터를 기록하려면 다음을 수행하십시오.

perf record -p `pidof a.out`

또는 10 초 동안 녹음하려면 :

perf record -p `pidof a.out` sleep 10

또는 호출 그래프로 기록 ()

perf record -g -p `pidof a.out`

2) 기록 된 데이터를 분석하려면

perf report --stdio
perf report --stdio --sort=dso -g none
perf report --stdio -g none
perf report --stdio -g

또는 애플리케이션의 성능 데이터를 기록한 후 애플리케이션을 이런 방식으로 시작하고 종료 될 때까지 기다린 후 분석 할 수 있습니다.

perf record ./a.out

이것은 테스트 프로그램을 프로파일 링하는 예입니다

테스트 프로그램은 main.cpp 파일에 있습니다 (메시지 하단에 main.cpp를 넣습니다).

이런 식으로 컴파일합니다.

g++ -m64 -fno-omit-frame-pointer -g main.cpp -L.  -ltcmalloc_minimal -o my_test

libc malloc 이이 옵션없이 컴파일 된 것처럼 보이는 동안 사용 libmalloc_minimial.so되므로 사용 합니다 -fno-omit-frame-pointer. 그런 다음 테스트 프로그램을 실행합니다

./my_test 100000000

그런 다음 실행중인 프로세스의 성능 데이터를 기록합니다.

perf record -g  -p `pidof my_test` -o ./my_test.perf.data sleep 30

그런 다음 모듈 당 부하를 분석합니다.

성능 보고서 –stdio -g 없음-정렬 통신, dso -i ./my_test.perf.data

# Overhead  Command                 Shared Object
# ........  .......  ............................
#
    70.06%  my_test  my_test
    28.33%  my_test  libtcmalloc_minimal.so.0.1.0
     1.61%  my_test  [kernel.kallsyms]

그런 다음 기능별로드가 분석됩니다.

perf report –stdio -g none -i ./my_test.perf.data | c ++ 여과

# Overhead  Command                 Shared Object                       Symbol
# ........  .......  ............................  ...........................
#
    29.30%  my_test  my_test                       [.] f2(long)
    29.14%  my_test  my_test                       [.] f1(long)
    15.17%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator new(unsigned long)
    13.16%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator delete(void*)
     9.44%  my_test  my_test                       [.] process_request(long)
     1.01%  my_test  my_test                       [.] operator delete(void*)@plt
     0.97%  my_test  my_test                       [.] operator new(unsigned long)@plt
     0.20%  my_test  my_test                       [.] main
     0.19%  my_test  [kernel.kallsyms]             [k] apic_timer_interrupt
     0.16%  my_test  [kernel.kallsyms]             [k] _spin_lock
     0.13%  my_test  [kernel.kallsyms]             [k] native_write_msr_safe

     and so on ...

그런 다음 콜 체인이 분석됩니다.

perf 보고서 –stdio -g 그래프 -i ./my_test.perf.data | c ++ 여과

# Overhead  Command                 Shared Object                       Symbol
# ........  .......  ............................  ...........................
#
    29.30%  my_test  my_test                       [.] f2(long)
            |
            --- f2(long)
               |
                --29.01%-- process_request(long)
                          main
                          __libc_start_main

    29.14%  my_test  my_test                       [.] f1(long)
            |
            --- f1(long)
               |
               |--15.05%-- process_request(long)
               |          main
               |          __libc_start_main
               |
                --13.79%-- f2(long)
                          process_request(long)
                          main
                          __libc_start_main

    15.17%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator new(unsigned long)
            |
            --- operator new(unsigned long)
               |
               |--11.44%-- f1(long)
               |          |
               |          |--5.75%-- process_request(long)
               |          |          main
               |          |          __libc_start_main
               |          |
               |           --5.69%-- f2(long)
               |                     process_request(long)
               |                     main
               |                     __libc_start_main
               |
                --3.01%-- process_request(long)
                          main
                          __libc_start_main

    13.16%  my_test  libtcmalloc_minimal.so.0.1.0  [.] operator delete(void*)
            |
            --- operator delete(void*)
               |
               |--9.13%-- f1(long)
               |          |
               |          |--4.63%-- f2(long)
               |          |          process_request(long)
               |          |          main
               |          |          __libc_start_main
               |          |
               |           --4.51%-- process_request(long)
               |                     main
               |                     __libc_start_main
               |
               |--3.05%-- process_request(long)
               |          main
               |          __libc_start_main
               |
                --0.80%-- f2(long)
                          process_request(long)
                          main
                          __libc_start_main

     9.44%  my_test  my_test                       [.] process_request(long)
            |
            --- process_request(long)
               |
                --9.39%-- main
                          __libc_start_main

     1.01%  my_test  my_test                       [.] operator delete(void*)@plt
            |
            --- operator delete(void*)@plt

     0.97%  my_test  my_test                       [.] operator new(unsigned long)@plt
            |
            --- operator new(unsigned long)@plt

     0.20%  my_test  my_test                       [.] main
     0.19%  my_test  [kernel.kallsyms]             [k] apic_timer_interrupt
     0.16%  my_test  [kernel.kallsyms]             [k] _spin_lock
     and so on ...

따라서이 시점에서 프로그램이 어디에 시간을 소비하는지 알 수 있습니다.

그리고 이것은 테스트를위한 main.cpp입니다 :

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

time_t f1(time_t time_value)
{
  for (int j =0; j < 10; ++j) {
    ++time_value;
    if (j%5 == 0) {
      double *p = new double;
      delete p;
    }
  }
  return time_value;
}

time_t f2(time_t time_value)
{
  for (int j =0; j < 40; ++j) {
    ++time_value;
  }
  time_value=f1(time_value);
  return time_value;
}

time_t process_request(time_t time_value)
{

  for (int j =0; j < 10; ++j) {
    int *p = new int;
    delete p;
    for (int m =0; m < 10; ++m) {
      ++time_value;
    }
  }
  for (int i =0; i < 10; ++i) {
    time_value=f1(time_value);
    time_value=f2(time_value);
  }
  return time_value;
}

int main(int argc, char* argv2[])
{
  int number_loops = argc > 1 ? atoi(argv2[1]) : 1;
  time_t time_value = time(0);
  printf("number loops %d\n", number_loops);
  printf("time_value: %d\n", time_value );

  for (int i =0; i < number_loops; ++i) {
    time_value = process_request(time_value);
  }
  printf("time_value: %ld\n", time_value );
  return 0;
}


답변

OProfile을 사용해보십시오 . 코드를 프로파일 링하는 데 훨씬 유용한 도구입니다. 나는 또한 Intel VTune을 제안 할 것이다 .

위의 두 도구는 특정 코드 행에 소요되는 시간을 좁히고 코드에 주석을 달며 어셈블리를 보여주고 특정 명령이 얼마나 걸리는지 보여줍니다. 시간 메트릭 외에도 캐시 카운터 등의 특정 카운터를 쿼리 할 수도 있습니다.

gprof와 달리 시스템에서 실행중인 모든 프로세스 / 이진을 프로파일 링 할 수 있습니다.


답변

Google 성능 도구 에는 사용하기 쉬운 프로파일 러가 포함되어 있습니다. CPU 및 힙 프로파일 러를 사용할 수 있습니다.


답변

Sysprof를 살펴 보십시오 .

배포판에 이미있을 수 있습니다.


답변

고성능 추적기를 원하면 http://lttng.org/