Как профилировать время, затрачиваемое на доступ к памяти в приложениях C/С++?

Общее время, затрачиваемое функцией в приложении, можно разделить на два компонента:

  • Время, затраченное на фактическое вычисление (Tcomp)
  • Время, затрачиваемое на доступ к памяти (Tmem)

Обычно профилировщики дают оценку общего времени, затрачиваемого функцией. Можно ли получить оценку времени, проведенного в терминах двух вышеуказанных компонентов (Tcomp и Tmem)?

Ответ 1

Понятие модели Арифметическая интенсивность было предложено моделью Roofline: https://crd.lbl.gov/departments/computer-science/PAR/research/roofline/. Просто сказано, что он определяет количество арифметических команд, выполняемых для каждого доступа к памяти.

Вычисление арифметической интенсивности обычно осуществляется с помощью счетчиков производительности.

Ответ 2

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

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

Ответ 3

Брендан Грегг в своем недавнем сообщении в блоге Использование процессора неверно предлагает использовать инструкции за цикл PMC. Короче, если IPC является < 1.0, чем приложение можно считать привязанным к памяти. В противном случае это можно считать обязательным. Вот соответствующий отрывок из его поста:

Если ваш IPC равен < 1.0, вы, вероятно, застопорились, и программное обеспечение стратегии настройки включают в себя сокращение ввода-вывода памяти и улучшение ЦП кеширования и локализации памяти, особенно в системах NUMA. аппаратные средства настройка включает использование процессоров с большими кэшами процессора и более быстрое памяти, шин и межсоединений.

Если ваш IPC равен > 1.0, вы, вероятно, связаны с инструкциями. Ищите способы уменьшить выполнение кода: устранить ненужную работу, кеш операций и т.д. Графики пламени CPU - отличный инструмент для этого расследование. Для аппаратной настройки, попробуйте более быструю тактовую частоту и более Ядра /hyperthreads.

Для моих приведенных выше правил я разделился на IPC 1.0. Где я получил это из? Я сделал это, основываясь на моей предыдущей работе с PMC. Вот как вы может получить значение, которое настраивается для вашей системы и времени выполнения: напишите два фиктивные рабочие нагрузки, которые связаны с процессором, и одна граница памяти. Мера их IPC, а затем вычислить их среднюю точку.

Вот несколько примеров фиктивных рабочих нагрузок, созданных инструмент стресса и их IPC.
Тест с привязкой к памяти, IPC низкий (0,02):

$ perf stat stress --vm 4 -t 3
stress: info: [4520] dispatching hogs: 0 cpu, 0 io, 4 vm, 0 hdd
stress: info: [4520] successful run completed in 3s

 Performance counter stats for 'stress --vm 4 -t 3':

      10767,074968      task-clock:u (msec)       #    3,560 CPUs utilized          
                 0      context-switches:u        #    0,000 K/sec                  
                 0      cpu-migrations:u          #    0,000 K/sec                  
         4 555 919      page-faults:u             #    0,423 M/sec                  
     4 290 929 426      cycles:u                  #    0,399 GHz                    
        67 779 143      instructions:u            #    0,02  insn per cycle         
        18 074 114      branches:u                #    1,679 M/sec                  
             5 398      branch-misses:u           #    0,03% of all branches        

       3,024851934 seconds time elapsed

Тест с привязкой к ЦП, высокий уровень IPC (1,44):

$ perf stat stress --cpu 4 -t 3
stress: info: [4465] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
stress: info: [4465] successful run completed in 3s

 Performance counter stats for 'stress --cpu 4 -t 3':

      11419,683671      task-clock:u (msec)       #    3,805 CPUs utilized          
                 0      context-switches:u        #    0,000 K/sec                  
                 0      cpu-migrations:u          #    0,000 K/sec                  
               108      page-faults:u             #    0,009 K/sec                  
    30 562 187 954      cycles:u                  #    2,676 GHz                    
    43 995 290 836      instructions:u            #    1,44  insn per cycle         
    13 043 425 872      branches:u                # 1142,188 M/sec                  
        26 312 747      branch-misses:u           #    0,20% of all branches        

       3,001218526 seconds time elapsed

Ответ 4

если вы ищете функцию для получения цикла процессора, тогда повышение будет очень полезно. Я использовал утилиту Boost Timer для вычисления циклов процессора при системном вызове.

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

Надеюсь, это то, что вы ищете. -Vijay