Интерпретация вывода perf stat


Я разработал код, который получает в качестве входного сигнала большое 2-D изображение (до 64MPixels) и:

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

Хотя это ничего не меняет, для полноты моего вопроса, фильтрация применяется дискретное вейвлет-преобразование и код записывается в C.

Моя конечная цель - сделать этот пробег как можно быстрее. Ускорение, которое я имею до сих пор, более чем в 10 раз за счет использования блокирующей матрицы транспонирования, векторизации, многопоточности, дружественного компилятору кода и т. д.

Переходя к моему вопросу: последние профилирующие статистики кода, которые у меня есть (с использованием perf stat -e), обеспокоили меня.

        76,321,873 cache-references                                            
     8,647,026,694 cycles                    #    0.000 GHz                    
     7,050,257,995 instructions              #    0.82  insns per cycle        
        49,739,417 cache-misses              #   65.171 % of all cache refs    

       0.910437338 seconds time elapsed

(#пропусков кэша)/(# инструкций) является низким на уровне ~0,7%. здесь это упоминается, что это число хорошо иметь в виду, чтобы проверить эффективность памяти.

С другой стороны, процент пропусков кэша по ссылкам на кэш значительно высок (65%!) что, как я вижу, может указывать на то, что что-то идет не так с выполнением с точки зрения эффективности кэша.

Подробная статистика из perf stat -d такова:

   2711.191150 task-clock                #    2.978 CPUs utilized          
         1,421 context-switches          #    0.524 K/sec                  
            50 cpu-migrations            #    0.018 K/sec                  
       362,533 page-faults               #    0.134 M/sec                  
 8,518,897,738 cycles                    #    3.142 GHz                     [40.13%]
 6,089,067,266 stalled-cycles-frontend   #   71.48% frontend cycles idle    [39.76%]
 4,419,565,197 stalled-cycles-backend    #   51.88% backend  cycles idle    [39.37%]
 7,095,514,317 instructions              #    0.83  insns per cycle        
                                         #    0.86  stalled cycles per insn [49.66%]
   858,812,708 branches                  #  316.766 M/sec                   [49.77%]
     3,282,725 branch-misses             #    0.38% of all branches         [50.19%]
 1,899,797,603 L1-dcache-loads           #  700.724 M/sec                   [50.66%]
   153,927,756 L1-dcache-load-misses     #    8.10% of all L1-dcache hits   [50.94%]
    45,287,408 LLC-loads                 #   16.704 M/sec                   [40.70%]
    26,011,069 LLC-load-misses           #   57.44% of all LL-cache hits    [40.45%]

   0.910380914 seconds time elapsed

Здесь frontend и backend stalled циклы также высоки, и кэши нижнего уровня, похоже, страдают от высокой скорости промахов. 57,5%.

Какая метрика наиболее подходит для этого сценария? Одна идея, о которой я думал, заключается в том, что рабочая нагрузка больше не требует дальнейшего "прикосновения" к кэшам LL после начальной загрузки изображения (загружает значения один раз, и после этого это делается - рабочая нагрузка больше связана с процессором, чем с памятью, поскольку алгоритм фильтрации изображений).

Машина, на которой я это делаю, - это Xeon E5-2680 (20M интеллектуального кэша, из которых 256KB L2 кэша на ядро, 8 начинка).

1 5

1 ответ:

Первое, что вы хотите сделать, это убедиться, что никакой другой вычислительный процесс не запущен на вашей машине. Это серверный процессор, поэтому я подумал, что это может быть проблемой.

Если вы используете многопоточность в своей программе и распределяете равный объем работы между потоками, вас может заинтересовать сбор метрик только на одном процессоре.

Я предлагаю отключить гиперпоточность на этапе оптимизации, поскольку это может привести к путанице при интерпретации показатели профилирования. (например, увеличенные циклы#, проведенные в бэк-энде). Кроме того, если вы распределите работу на 3 потока, у вас есть высокий шанс, что 2 потока будут совместно использовать ресурсы одного ядра, а 3 - й будет иметь все ядро для себя-и это будет быстрее.

Perf никогда не был очень хорош в объяснении метрик. Судя по порядку величины, ссылки на кэш - это промахи L2, которые попали в LLC. Высокое число ООО Мисс по сравнению с ООО ссылок не всегда плохо вещь, если количество ссылок LLC / # инструкций невелико. В вашем случае у вас есть 0.018, так что это означает, что большая часть ваших данных используется из L2. Высокий коэффициент промаха LLC означает, что вам все еще нужно получить данные из оперативной памяти и записать их обратно.

Что касается # Cycles BE и Fe bound, я немного обеспокоен значениями, потому что они не суммируются до 100% и до общего числа циклов. У вас есть 8G, но вы остаетесь 6G циклами в FE и 4G циклами в BE. Что-то не очень похоже правильный.

Если циклы FE высоки, это означает, что у вас есть промахи в кэше команд или плохая спекуляция ветвями. Если циклы BE высоки, это означает, что вы ждете данных.

Во всяком случае, относительно вашего вопроса. Наиболее подходящей метрикой для оценки производительности вашего кода являетсяInstructions / Cycle (IPC) . Ваш процессор может выполнять до 4 команд / цикл. Вы только выполняете 0.8. Это означает, что ресурсы используются недостаточно, за исключением случая, когда у вас много векторов инструкции. После IPC вам нужно проверить промахи ветвей и промахи L1 (данные и код), потому что они генерируют большинство штрафов.

Последнее предложение: возможно, Вам будет интересно попробовать усилитель Intel vTune. Это дает гораздо лучшее объяснение метрик и указывает на возможные проблемы в вашем коде.