source

리눅스 Perf 리포트 출력 이해

lovecheck 2023. 10. 14. 10:19
반응형

리눅스 Perf 리포트 출력 이해

대부분의 결과를 직관적으로 얻을 수 있지만, 결과를 완전히 이해하는 데 어려움을 겪고 있습니다.perf report특히 통화 그래프와 관련된 것에 대해 명령을 내리기 때문에, 저는 이 문제를 모두 해결하기 위해 바보 같은 테스트를 작성했습니다.

바보같은 시험.

다음 내용을 정리했습니다.

gcc -Wall -pedantic -lm perf-test.c -o perf-test

인라인 등을 피하기 위한 적극적인 최적화는 없습니다.

#include <math.h>

#define N 10000000UL

#define USELESSNESS(n)                          \
    do {                                        \
        unsigned long i;                        \
        double x = 42;                          \
        for (i = 0; i < (n); i++) x = sin(x);   \
    } while (0)

void baz()
{
    USELESSNESS(N);
}

void bar()
{
    USELESSNESS(2 * N);
    baz();
}

void foo()
{
    USELESSNESS(3 * N);
    bar();
    baz();
}

int main()
{
    foo();
    return 0;
}

플랫 프로파일링

perf record ./perf-test
perf report

이를 통해 다음을 얻을 수 있습니다.

  94,44%  perf-test  libm-2.19.so       [.] __sin_sse2
   2,09%  perf-test  perf-test          [.] sin@plt
   1,24%  perf-test  perf-test          [.] foo
   0,85%  perf-test  perf-test          [.] baz
   0,83%  perf-test  perf-test          [.] bar

과중한 작업이 실제로 수행되기 때문에 합리적인 것 같습니다.__sin_sse2그리고.sin@plt제 기능의 오버헤드는 루프만을 고려하는 반면, 아마도 래퍼일 것입니다.3*N에 대한 반복.foo,2*N나머지 둘은.

계층 프로파일링

perf record -g ./perf-test
perf report -G
perf report

이제 오버헤드 열은 두 개입니다.Children(출력은 기본적으로 이 값으로 정렬됩니다) 및Self(평판 프로파일의 동일한 오버헤드).

여기서 제가 뭔가 그립다는 느낌을 받기 시작합니다. 제가 사용하는 사실에 상관없이.-G예를 들어 "x calls y" 또는 "y는 x에 의해 호출된다"는 식으로 계층 구조를 설명할 수 없습니다.

  • 없이.-G("y"는 x로 부름):

    -   94,34%    94,06%  perf-test  libm-2.19.so       [.] __sin_sse2
       - __sin_sse2
          + 43,67% foo
          + 41,45% main
          + 14,88% bar
    -   37,73%     0,00%  perf-test  perf-test          [.] main
         main
         __libc_start_main
    -   23,41%     1,35%  perf-test  perf-test          [.] foo
         foo
         main
         __libc_start_main
    -    6,43%     0,83%  perf-test  perf-test          [.] bar
         bar
         foo
         main
         __libc_start_main
    -    0,98%     0,98%  perf-test  perf-test          [.] baz
       - baz
          + 54,71% foo
          + 45,29% bar
    
    1. 왜죠__sin_sse2부름을 받습니다.main(indirect적으로?)foo그리고.bar하지만 그렇지는baz?
    2. 함수들이 때때로 백분율과 계층을 첨부하는 이유(예: 마지막 인스턴스)baz) 및 때로는 그렇지 않습니다(예: 마지막 사례).bar)?
  • 와 함께-G("x call y"):

    -   94,34%    94,06%  perf-test  libm-2.19.so       [.] __sin_sse2
       + __sin_sse2
       + __libc_start_main
       + main
    -   37,73%     0,00%  perf-test  perf-test          [.] main
       - main
          + 62,05% foo
          + 35,73% __sin_sse2
            2,23% sin@plt
    -   23,41%     1,35%  perf-test  perf-test          [.] foo
       - foo
          + 64,40% __sin_sse2
          + 29,18% bar
          + 3,98% sin@plt
            2,44% baz
         __libc_start_main
         main
         foo
    
    1. 아래의 처음 3개 항목을 어떻게 해석해야 합니까?__sin_sse2?
    2. main부름foo그리고 그건 괜찮아요, 하지만 만약 전화가 온다면 왜요?__sin_sse2그리고.sin@plt(indirect적으로?)그것은 또한 부르지 않습니다.bar그리고.baz?
    3. 왜 그럴까요?__libc_start_main그리고.main의 밑에 나타나다foo? 그 이유는foo두 번이나 나타나나요?

두 번째 단계는 실제로 "x calls y"/"y"를 나타내는 두 단계의 계층 구조가 있는 것으로 의심되지만, 추측하는 데 지쳐서 여기에 묻습니다.그리고 그 문서는 도움이 되지 않는 것 같습니다.


글이 길어서 미안하지만 이 모든 맥락이 다른 사람에게도 도움이 되거나 참고가 되기를 바랍니다.

좋아요, 그럼 발신자와 발신자 통화 그래프 사이의 차이를 잠시 무시해 봅시다. 대부분 제 기계에서 이 두 옵션 사이의 결과를 비교할 때 내부에서만 효과가 나타나기 때문입니다.kernel.kallsyms제가 이해할 수 없는 이유로 DSO를 사용합니다. 저 자신은 비교적 이 일을 처음 접합니다.

예를 들어, 나무 전체를 읽는 것이 좀 더 쉽다는 것을 알았습니다.그래서 사용.--stdio에 대해 나무 __sin_sse2:

# Overhead    Command      Shared Object                  Symbol
# ........  .........  .................  ......................
#
    94.72%  perf-test  libm-2.19.so       [.] __sin_sse2
            |
            --- __sin_sse2
               |
               |--44.20%-- foo
               |          |
               |           --100.00%-- main
               |                     __libc_start_main
               |                     _start
               |                     0x0
               |
               |--27.95%-- baz
               |          |
               |          |--51.78%-- bar
               |          |          foo
               |          |          main
               |          |          __libc_start_main
               |          |          _start
               |          |          0x0
               |          |
               |           --48.22%-- foo
               |                     main
               |                     __libc_start_main
               |                     _start
               |                     0x0
               |
                --27.84%-- bar
                          |
                           --100.00%-- foo
                                     main
                                     __libc_start_main
                                     _start
                                     0x0

가 이걸 은 44%입니다sin됩니다에서 됩니다.foo전화를 27%는 를 받습니다.baz 27%는 는에서.

-g에 대한 설명서는 유용합니다.

 -g [type,min[,limit],order[,key]], --call-graph
       Display call chains using type, min percent threshold, optional print limit and order. type can be either:

       ·   flat: single column, linear exposure of call chains.

       ·   graph: use a graph tree, displaying absolute overhead rates.

       ·   fractal: like graph, but displays relative rates. Each branch of the tree is considered as a new profiled object.

               order can be either:
               - callee: callee based call graph.
               - caller: inverted caller based call graph.

               key can be:
               - function: compare on functions
               - address: compare on individual code addresses

               Default: fractal,0.5,callee,function.

여기서 중요한 점은 기본값이 프랙탈이고 프랙탈 모드에서는 각 분기가 새로운 개체라는 것입니다.

를 하는 baz고에서bar, 그리고 나머지 50%의 사람들은 그들로부터 전화를 받습니다.foo.

한 척도는 를 를 살펴보는 -g graph:

94.72%  perf-test  libm-2.19.so       [.] __sin_sse2
        |
        --- __sin_sse2
           |
           |--41.87%-- foo
           |          |
           |           --41.48%-- main
           |                     __libc_start_main
           |                     _start
           |                     0x0
           |
           |--26.48%-- baz
           |          |
           |          |--13.50%-- bar
           |          |          foo
           |          |          main
           |          |          __libc_start_main
           |          |          _start
           |          |          0x0
           |          |
           |           --12.57%-- foo
           |                     main
           |                     __libc_start_main
           |                     _start
           |                     0x0
           |
            --26.38%-- bar
                      |
                       --26.17%-- foo
                                 main
                                 __libc_start_main
                                 _start
                                 0x0

이는 해당 콜 체인에 대해 각 시간 비율이 보고되는 절대 비율을 사용하는 것으로 바뀝니다.foo->bar는 는 다시의 26%다됨)를 호출됩니다.baz및 ).foo->baz(직접)은 전체 눈금의 12%입니다.

발신자 사이에 가 없는를 아직도 .__sin_sse2.

갱신하다

당신의 명령 줄에서 제가 바꾼 한가지는 통화 그래프가 어떻게 모였는지 입니다.Linux perf는 기본적으로 호출 스택을 재구성하는 프레임 포인터 방법을 사용합니다.다를 때 이 가 발생할 수 .-fomit-frame-pointer채무 불이행으로그래서 제가.

perf record --call-graph dwarf ./perf-test

언급URL : https://stackoverflow.com/questions/27742462/understanding-linux-perf-report-output

반응형