Perf на руке Cortex-A7 не создает стеки вызовов

Я написал небольшую тестовую программу на C++, которую хочу профилировать с помощью perf на руке. Запуск и профилирование программы на моем x86 WSL дает ожидаемые результаты. Однако когда я профилирую программу в системе Arm, отчет о производительности не содержит стеков вызовов и показывает другие методы по сравнению с выходными данными x86. Я покажу свою программу, производительность x86 и производительность руки.

В моей программе есть функция main, которая непрерывно зацикливает короткий и длинный метод, оба из которых вызывают run.

#include <map>

int run(int loop, std::map<int,int> m)
{
    int x = 0;
    for(int i = 0; i < loop; i++)
    {
       x += i + i * x;
       m.insert({i,x});
    }
    return x;
}

int short_method(std::map<int,int> m)
{
    return run(100, m);
}

int long_method(std::map<int,int> m)
{
    return run(10000, m);
}

int main()
{
    while(true)
    {
        std::map<int,int> m;
        short_method(m);
        long_method(m);
    }
    return 0;
}

Сначала посмотрите на ожидаемое поведение под x86 WSL. Компиляция и профилирование:

g++ -g -O0 main.cpp

perf record -g -F 1000 -p$(pgrep -d, a.out) sleep 5
[ perf record: Woken up 3 times to write data ]
[ perf record: Captured and wrote 0.637 MB perf.data (5002 samples) ]

perf report -g

Выход:

+   97.84%     0.00%  a.out    [unknown]            [.] 0x41fd89415541f689                                                                 ▒
+   97.84%     0.00%  a.out    libc-2.28.so         [.] __libc_start_main                                                                  ▒
-   97.84%     0.02%  a.out    a.out                [.] main                                                                               ▒
   - 97.82% main                                                                                                                           ▒
      - 97.14% long_method                                                                                                                 ▒
         + 90.31% run                                                                                                                      ▒
         + 6.62% std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::~map                                     ▒
      - 0.64% short_method                                                                                                                 ◆
         + 0.54% run                                                                                                                       ▒
+   97.14%     0.00%  a.out    a.out                [.] long_method                                                                        ▒
+   90.85%     0.44%  a.out    a.out                [.] run                                                                                ▒
+   89.59%     0.30%  a.out    a.out                [.] std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::in▒

Вывод мне пригоден, так как основной метод явно находится сверху, и я могу открыть стек вызовов, чтобы идентифицировать методы, вызываемые внутри основного.

Теперь компиляция и профилирование на системе Arm:

arm-__-linux-gnueabi-g++  -mthumb -mfpu=neon-vfpv4 -mfloat-abi=hard -mcpu=cortex-a7   -O0  -Wformat -Wformat-security -Werror=format-security --sysroot=/opt/sdk/sysroots/cortexa7t2hf-neon-vfpv4-__-linux-gnueabi -g -fno-omit-frame-pointer main.cpp -o a_arm.out
perf record -g -F 1000 -p 405 sleep 5
[ perf record: Woken up 2 times to write data ]
[ perf record: Captured and wrote 0.346 MB perf.data (5005 samples) ]

perf report -g

Выход:

-   21.35%    21.12%  a_arm.out  a_arm.out            [.] std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_M_get_insert_unique_pos a
     std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_M_get_insert_unique_pos                                                      a
-   12.46%    12.40%  a_arm.out  a_arm.out            [.] std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_S_key                   a
     std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_S_key                                                                        a
-   11.15%    11.07%  a_arm.out  a_arm.out            [.] __gnu_cxx::__aligned_membuf<std::pair<int const, int> >::_M_ptr                                                                                                                   a
     __gnu_cxx::__aligned_membuf<std::pair<int const, int> >::_M_ptr                                                                                                                                                                        a
-    7.31%     7.31%  a_arm.out  a_arm.out            [.] std::_Rb_tree_node<std::pair<int const, int> >::_M_valptr                                                                                                                         a
     std::_Rb_tree_node<std::pair<int const, int> >::_M_valptr                                                                                                                                                                              a
-    4.86%     4.84%  a_arm.out  a_arm.out            [.] __gnu_cxx::__aligned_membuf<std::pair<int const, int> >::_M_addr                                                                                                                  a
     __gnu_cxx::__aligned_membuf<std::pair<int const, int> >::_M_addr                                                                                                                                                                       a
-    3.05%     3.03%  a_arm.out  a_arm.out            [.] std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_M_insert_<std::pair<int a
     std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >,

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

Интересно, почему у меня нет подходящего стека вызовов для моей программы Arm, есть идеи?

редактировать Кажется, у этого 12-летнего вопроса та же проблема: Как заставить профилирование графа вызовов работать с скомпилированным кодом gcc и целевым объектом ARM Cortex A8?

обновление: 04.07.24 та же проблема появляется здесь: https://lore.kernel.org/all/[email protected]/T/

Я сам попробовал свой пример программы на малине с ядром Linux 6.6.31 и версией perf 6.6.31. Та же проблема - плоские стеки вызовов. Кажется, проблема возникает в первую очередь на архитектурах ARM.

аналогично с 2016 года

Добро пожаловать в StackOverflow! Пожалуйста, посетите тур , чтобы узнать, как работает этот сайт, и прочитайте « Как спросить ». Затем вернитесь и отредактируйте свой вопрос, чтобы предоставить соответствующие части отчетов о производительности в виде текста. Используйте скриншоты только для нетекстового контента.

the busybee 27.06.2024 10:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Добавьте флаги -marm -fno-omit-frame-pointer -mapcs-frame в компиляцию, чтобы генерировать кадры стека, которые работают с perf.

Судя по этой ошибке llvm

В ARM для этого требуются кадры APCS (-fno-omit-frame-pointer -mapcs-frame), чтобы гарантировать, что указатели кадров хранятся в предсказуемых местах.

Добавление -mapcs-frame решило эту проблему для меня, так что я мог видеть стеки вызовов с опцией --call-graph fp. Опция dwarf по-прежнему не работает. Кроме того, необходимо отключить режим большого пальца, поэтому я удалил флаг -mthumb и заменил его на -marm, чтобы принудительно использовать набор инструкций руки. См. Символика графа вызовов Perf на большом пальце проблемы в Google, начиная с 2020 года и закрываясь в 2023 году, поскольку это не будет исправлено. Судя по всему, это связано с выпуском Arm 32 и больше не присутствует в Arm64.

Другие вопросы по теме

Stddef.h переопределяет size_t с неправильной шириной только в clang-tidy
Могу ли я создать файлы Docker для Arm32 с помощью DockerHub?
Устранение неполадок использования malloc и конфигурации heap_size в разработке STM32
Как изменить расширенные атрибуты файлов в образах Docker в разных архитектурах и сохранить изменения?
Статически загруженный C в сборку aarch64 для учебных целей
Как выполнить сборку docker buildx для ARM v6 на эмулируемых платформах QEMU, которые представляются в контейнере сборки как Arm7l?
Обеспечение рабочего процесса и подключения API для стандартного приложения логики с помощью шаблонов/скриптов Bicep
ARM GCC не удается создать рабочий двоичный файл для STM32F4, много отброшенного кода
Невозможно подключиться к серверу ASP.NET, работающему на Raspberry Pi
Реализация замыканий и влияние на производительность, например, относительного или абсолютного перехода