Ubuntu, как найти горячую точку программы с тяжелой работой ядра? Кажется, что функция в kernel.kallsyms не помечается как дочерняя функция пользовательского пространства

Многопоточная программа с тяжелой работой ядра (блокировка разблокировки), попробуйте найти горячую точку в моем коде, используя инструменты профилирования.

Я написал минимально воспроизводимую программу. Скомпилируйте это. Используйте инструмент профилирования, такой как perf, gprof, с записью стека вызовов. Никто из них не может сообщить о горячей точке в моем коде, но сообщит о функции ядра или libstdc ++. So.

#include <iostream>
#include <mutex>
#include <thread>
#include <memory>
#include <vector>

std::mutex mtx;
long long_val = 0;

void do_something(long &val)
{
    std::unique_lock<std::mutex> lck(mtx);
    for(int j=0; j<1000; ++j)
        val++;
}


void thread_func()
{
    for(int i=0; i<1000000L; ++i)
    {
        do_something(long_val);
    }
}


int main(int argc, char* argv[])
{
    std::vector<std::unique_ptr<std::thread>> threads;
    for(int i=0; i<100; ++i)
    {
        threads.push_back(std::move(std::unique_ptr<std::thread>(new std::thread(thread_func))));
    }
    for(int i=0; i<100; ++i)
    {
        threads[i]->join();
    }
    threads.clear();
    std::cout << long_val << std::endl;
    return 0;
}

Как мы видим, do_something() - горячая точка моей программы. потому что слишком много unique_lock требует много работы ядра, и 1000 раз inc работают с функцией.

Я хочу, чтобы инструмент профилирования сказал мне, что do_something () делает много блокировок, вызывая большую работу ядра. но из perf я могу обнаружить, что это блокировка замедляет мой код, но где эти блокировки работают в моем коде? это не понятно.

Скомпилировать:

g++ -o a.out -O3 -std=c++11 -fno-omit-frame-pointer -pthread -pg main.cpp

Запустите program./a.out, htop сообщит, что ядро ​​заняло половину ресурсов процессора.

Рекорд производительности:

perf record -g ./a.out

Отчет о производительности:

      Children      Self  Command  Shared Object        Symbol
    -   98.64%     0.00%  a.out    libstdc++.so.6.0.21  [.] 0x00000000000b8c80
       - 0xb8c80
          + 41.80% __lll_unlock_wake
          + 35.39% __lll_lock_wait
        12.77% pthread_mutex_lock
        7.69% pthread_mutex_unlock
        0.70% _Z11thread_funcv
    -   49.21%     0.88%  a.out    [kernel.kallsyms]    [k] entry_SYSCALL_64_after_hwframe
       + 48.33% entry_SYSCALL_64_after_hwframe
         0.88% 0xb8c80
    -   47.64%     1.06%  a.out    [kernel.kallsyms]    [k] do_syscall_64
       + 46.59% do_syscall_64
       + 1.06% 0xb8c80
    -   47.18%     1.44%  a.out    [kernel.kallsyms]    [k] sys_futex
       + 45.74% sys_futex
       + 1.44% 0xb8c80
    -   45.55%     1.65%  a.out    [kernel.kallsyms]    [k] do_futex
       + 43.90% do_futex
       + 1.65% 0xb8c80
    -   41.80%     1.30%  a.out    libpthread-2.23.so   [.] __lll_unlock_wake
       + 40.50% __lll_unlock_wake
       + 1.30% 0xb8c80
    -   35.39%     4.53%  a.out    libpthread-2.23.so   [.] __lll_lock_wait
       + 30.86% __lll_lock_wait
       + 4.53% 0xb8c80
    -   20.51%     5.40%  a.out    [kernel.kallsyms]    [k] futex_wake
       + 15.11% futex_wake
       + 5.40% 0xb8c80
    -   19.41%     0.88%  a.out    [kernel.kallsyms]    [k] futex_wait
       + 18.53% futex_wait
       + 0.88% 0xb8c80
    -   16.92%     6.25%  a.out    [kernel.kallsyms]    [k] _raw_spin_lock
       + 10.67% _raw_spin_lock
       + 6.25% 0xb8c80
    -   12.77%    12.73%  a.out    libpthread-2.23.so   [.] pthread_mutex_lock
         12.73% 0xb8c80
        pthread_mutex_lock
    +   11.80%     5.41%  a.out    [kernel.kallsyms]    [k] futex_wait_setup
    +   11.05%    11.05%  a.out    [kernel.kallsyms]    [k] syscall_return_via_sysret
    +   10.68%    10.67%  a.out    [kernel.kallsyms]    [k] native_queued_spin_lock_slowpath
    +    7.69%     7.65%  a.out    libpthread-2.23.so   [.] pthread_mutex_unlock
    +    7.36%     0.11%  a.out    [kernel.kallsyms]    [k] wake_up_q
    +    7.17%     1.27%  a.out    [kernel.kallsyms]    [k] try_to_wake_up
    +    4.42%     0.23%  a.out    [kernel.kallsyms]    [k] futex_wait_queue_me
    +    4.17%     0.08%  a.out    [kernel.kallsyms]    [k] schedule
    +    3.84%     0.75%  a.out    [kernel.kallsyms]    [k] __schedule
    +    2.70%     0.01%  a.out    [kernel.kallsyms]    [k] ttwu_do_activate
    +    2.49%     2.48%  a.out    [kernel.kallsyms]    [k] get_futex_value_locked
    +    2.38%     0.11%  a.out    [kernel.kallsyms]    [k] activate_task
    +    2.26%     0.15%  a.out    [kernel.kallsyms]    [k] enqueue_task_fair
    +    1.88%     1.88%  a.out    [unknown]            [k] 0xfffffe000000601b
    +    1.84%     0.15%  a.out    [kernel.kallsyms]    [k] __task_rq_lock
    +    1.78%     1.78%  a.out    [unknown]            [k] 0xfffffe000005e01b
    +    1.77%     1.77%  a.out    [unknown]            [k] 0xfffffe000003201b
    +    1.67%     0.02%  a.out    [kernel.kallsyms]    [k] deactivate_task
    +    1.66%     1.66%  a.out    [unknown]            [k] 0xfffffe000008a01b  

Как я могу использовать инструмент профилирования, чтобы определить горячую точку этого типа в моей реальной программе. Я не хочу использовать "двоичный комментарий" для решения этой проблемы каждый раз. Спасибо!


person Bin Zhou    schedule 21.01.2019    source источник
comment
Вы пробовали графический интерфейс поверх perf? Или VTune?   -  person Matthieu Brucher    schedule 21.01.2019
comment
@MatthieuBrucher I профилирующая программа на удаленном сервере без X через ssh. У нас нет лицензии на VTune, не пробовал.   -  person Bin Zhou    schedule 21.01.2019
comment
Попробуйте использовать perf с FlameGraph (да, это исключительно уродливая тарабарщина perl, но она дает хорошие визуализации) .   -  person user7860670    schedule 21.01.2019
comment
@VTT, но кажется, что perf не вызывает функцию ядра как дочернюю функцию пользовательского пространства. Пробовал hotspot gui, не помогает.   -  person Bin Zhou    schedule 21.01.2019
comment
Разве их пример не показывает именно это - стеки с вызовами функций ядра из функций пользовательского пространства?   -  person user7860670    schedule 21.01.2019
comment
Кажется, кто-то нашел решение, позволяющее заставить gprof работать с многопоточными приложениями: sam.zoy.org /writings/programming/gprof.html   -  person Oliv    schedule 21.01.2019
comment
Это решение уже дано так: stackoverflow.com/a/922478/5632316   -  person Oliv    schedule 21.01.2019
comment
Возможный дубликат Использование gprof с pthreads   -  person Oliv    schedule 21.01.2019
comment
@Oliv hook функция pthread не приемлема. И gprof не является моим ключевым моментом, но как сделать perf report пометить функцию ядра как дочернюю функцию пользовательского пространства.   -  person Bin Zhou    schedule 21.01.2019
comment
@VTT Спасибо, попробую.   -  person Bin Zhou    schedule 21.01.2019
comment
@BinZhou Я смог получить нужную информацию. Вы должны изменить командную строку perf perf record --call-graph dwarf ./a.out (вам может потребоваться передать -g в компиляторе или не получать отладочную информацию в объектном файле), затем perf report --call-graph --stdio -G.   -  person Oliv    schedule 21.01.2019
comment
@BinZhou удачи?   -  person hudac    schedule 16.12.2019


Ответы (1)


perf по умолчанию использует раскрутку указателя кадра, что быстро, но ненадежно. Даже если ваше приложение не пропускает указатели фреймов, библиотеки могут.

В качестве альтернативы вы можете использовать --call-graph с dwarf или lbr.

dwarf записывает фрагменты стека во время выборки, которые позже оцениваются. Он может дать больше деталей, но создает огромные следы и может иметь больше возмущений.

lbr требуется аппаратная поддержка, доступная на более новых процессорах Intel.

Это будет примерно так:

99.25%     2.61%  a.out    a.out                [.] thread_func
        |          
        |--97.67%--thread_func
        |          |          
        |          |--45.33%--pthread_mutex_lock@plt
        |          |          
        |          |--28.65%--pthread_mutex_unlock@plt
        |          |          
        |          |--18.88%--__pthread_mutex_lock
        |          |          __lll_lock_wait
        |          |          
        |           --4.75%--__pthread_mutex_unlock_usercnt
        |                     __lll_unlock_wake
        |          
         --0.72%--__pthread_mutex_lock
person Zulan    schedule 21.01.2019
comment
g++ -o a.out -O3 -std=c++11 -pthread -g main.cpp perf record --call-graph lbr ./a.out perf report top3: entry_SYSCALL_64_after_hwframe% 48.81 do_syscall_64% 47.25 sys_futex% 47.01 - person Bin Zhou; 22.01.2019
comment
Но если компилировать с g++ -o a.out -O2 -std=c++11 -pthread -g main.cpp, то top3 Children будет _Z11thread_funcv% 79.18 pthread_mutex_unlock% 57.51 entry_SYSCALL_64_after_hwframe% 49.56. Не могли бы вы помочь мне понять, почему это произошло. - person Bin Zhou; 22.01.2019
comment
результат uname -a: Linux PC 4.15.0-43-generic # 46 ~ 16.04.1-Ubuntu SMP Пт 7 декабря 13:31:08 UTC 2018 x86_64 x86_64 x86_64 GNU / Linux ` - person Bin Zhou; 22.01.2019