Последнее изменение файла: 2022.03.28
Скопировано с www.bog.pp.ru: 2023.10.02
Bog BOS: oprofile - исследование особенностей вычислительной производительности с использованием аппаратных счётчиков событий
oprofile - исследование особенностей вычислительной производительности на уровне системы
с использованием встроенных в ЦП счётчиков событий: такты ядра, такты шины, обращений к шине, промахи кеша и т.п.
(количество счётчиков, поддерживаемые типы событий и маски событий зависят от архитектуры и модели ЦП).
Можно подсчитывать события, происходящие в режиме ядра, в режиме пользователя или обоих режимах.
При достижении заданного числа событий проиcходит прерывание (NMI, non-maskable interrupts), обработчик прерывания
записывает сообщение о событии (счётчик адреса и номер процесса) в буфер ядра,
сервис oprofiled переносит накопленные данные из буфера ядра в файл.
Сохранённый счётчик адреса и стек вызовов позволяет привязывать события к программам (модулям ядра), операторам ЯВУ и командам.
Позволяет определить "узкое горло", включая подсистемы ядра (модули и обработчики прерываний).
В качестве прообраза использовалась система DCPI (DEC Continuous Profiling Infrastructure).
Не оказывает воздействия на исполняемые программмы ни в поведении, ни в производительности (счётчики обновляются аппаратно).
Пакет oprofile (oprofile-gui, oprofile-jit, oprofile-devel) версии 0.9.4 в RHEL5.4
(для Nehalem (i7, Xeon 55xx) требуется 0.9.5).
Для IBS (Instruction-Based Sampling) для AMD K10 требуется ядро 2.6.28.
Используется модуль ядра oprofile, демон oprofiled, утилита управления opcontrol
и утилиты генерации отчётов opreport (возможна фильтрация по программам) и opannotate (с точностью до строки ЯВУ или команды).
Перед запуском мониторинга блокируется NMI watchdog, для разблокировки требуется выгрузить модуль ядра.
Внеочередное исполнение инструкций в современных ЦП не позволяет привязать данные с точностью до команды.
Записывается не каждое событие, а одно из N событий (каждый счётчик имеет ограничение на N снизу).
При уменьшении N увеличивается побочная нагрузка на систему вплоть до зависания
(при уменьшении N с 30000 до 3000 время расчёта увеличилось вдвое (на 20%), доля потерь отсчётов в 1.5 раза (в 8 раз);
при увеличении - уменьшается точность (потери отсчётов из-за переполнения буфера пропали при увеличении до 50000
на AMD K10 с частотой 2800MHz при нагрузке на все 24 ядра).
Заброшена в пользу perf.
Модуль ядра oprofile
Модуль ядра oprofile имеет параметры: p4force, timer (использовать только прерывания от таймера).
По умолчанию, счётчик 0 отслеживает событие CPU_CLK_UNHALTED (для Core2/K10).
Для управления используется файловая система в каталоге /dev/oprofile/, в котором можно посмотреть текущее состояние,
задать параметры мониторинга и взять результаты (почему он в /dev, а не в /proc или /sys?).
Максимальное количество одновременно используемых счётчиков определяется моделью ЦП, нумеруются с 0,
каждый счётчик имеет подкаталог в /dev/oprofile/ (отсюда можно определить их число):
/dev/oprofile/cpu_type - тип ЦП с точки зрения модуля
/dev/oprofile/cpu_buffer_size - размер буфера ядра
/dev/oprofile/buffer_size - размер буфера
/dev/oprofile/stats/ - статистика сбора информации (количество потерянных отсчётов)
/dev/oprofile/0/enabled - счётчик включён
/dev/oprofile/0/count - количество событий между прерываниями
/dev/oprofile/0/event - тип событий
/dev/oprofile/0/unit_mask - маска
/dev/oprofile/0/kernel - учитывать события в режиме ядра
/dev/oprofile/0/user - учитывать события в режиме пользователя
ophelp с указанием имени счётчика выдаёт его номер.
ophelp без параметров выдаёт список допустимых счётчиков и масок, например,
для Intel Xeon 55xx (Nehalem, i7; 5 счётчиков, 31 bit? не получается задать больше 1 счётчика):
счётчики тактов
CPU_CLK_UNHALTED - такты, в которых ЦП не был в состоянии останова
(по умолчанию, маска 0x00 - циклы ядра; 0x01 - циклы шины, 0x02 - при остановленных остальных ядрах)
счётчики инструкций, микроопераций, прерываний
INST_RETIRED_ANY_P - количество выполненных инструкций
SEGMENT_REG_LOADS
FLOPS - микрокоманд плавающей арифметики
MUL - число умножений
DIV - число делений
EIST_TRANS_ALL - количество переходов Intel Enhanced SpeedStep Technology
THERMAL_TRIP - количество температурных переходов
RS_UOPS_DISPATCHED - количество микрокоманд, запланированных к выполнению
RS_UOPS_DISPATCHED_NONE - количество пустых микрокоманд, запланированных к выполнению
MACRO_INSTS - количество декодированных команд (по умолчанию, маска 0x9; 1 - команд, 8 - команд CISC)
SIMD_UOPS_EXEC - количество выполненных SIMD команд
SIMD_SAT_UOP_EXEC - количество выполненных "насыщающих" (saturating?) SIMD команд
SIMD_UOP_TYPE_EXEC - количество пакованных SIMD команд (по умолчанию, маска 0x3f;
1 - умножений, 2 - сдвигов, 4 - паковок, 8 - распаковок, 0x10 - логических, 0x20 - арифметических)
SIMD_SAT_INSTR_RET - количество "насыщающих" (saturating?) SIMD команд
INST_RETIRED - количество выполненных инструкций (по умолчанию, маска 0x00 - любых;
0x01 - команд загрузки, 0x02 - команд записи,
0x04 - других)
X87_OPS_RETIRED - количество команд с плавающей точкой
UOPS_RETIRED - количество микрокоманд (по умолчанию, маска 0xf;
1 - слитых "загрузка и операция" или "загрузка и косвенный переход";
2 - слитых "запись адреса и адреса";
4 - пара команд слитых в одну микрокоманду;
8 - неслитых микрокоманд)
FP_MMX_TRANS - преобразований между FP и MMX (по умолчанию, маска 3; 1 - из FP в MMX, 2 - из MMX в FP)
MMX_ASSIST - количество команд EMMS
HW_INT_RCV - количество аппаратных прерываний
CYCLES_INT_MASKED - количество циклов с замаскированными прерываниями (по умолчанию, маска 2;
1 - с замаскированными прерываниями; 2 - с замаскированными прерываниями при наличии прерываний0
BR_INST_DECODED - декодированных команд перехода
BR_BOGUS - количество фиктивных переходов
BR_INST_EXEC - выполненных команд перехода
BR_MISSP_EXEC - неправильно предсказанных выполненных команд перехода
BR_BAC_MISSP_EXEC - неправильно предсказанных на входе (at Front End, BAC) выполненных команд перехода
BR_CND_EXEC и BR_CND_MISSP_EXEC - условных переходов и неправильно предсказанных условных переходов
BR_IND_EXEC и BR_IND_MISSP_EXEC - косвенных переходов и неправильно предсказанных косвенных переходов
BR_RET_EXEC, BR_RET_MISSP_EXEC, BR_RET_BAC_MISSP_EXEC - команд возврата, неправильно предсканных, непраильно
предсказанных на входе
BR_CALL_EXEC, BR_CALL_MISSP_EXEC - вызовов функций и неправильно предсказанных вызовов функций
DATA_CACHE_REFILLS_FROM_L2_OR_NORTHBRIDGE (по умолчанию, маска 0x1e - All cache states except refill from northbridge;
1 - Refill from northbridge; 2 - Shared-state line from L2, 4 - Exclusive-state line from L2,
8 - Owner-state line from L2, 0x10 - Modified-state line from L2)
DATA_CACHE_REFILLS_FROM_NORTHBRIDGE (по умолчанию, маска 0x1f - All cache states)
DATA_CACHE_LINES_EVICTED (по умолчанию, маска 0x1f)
INEFFECTIVE_SW_PREFETCHES (по умолчанию, маска 0x9)
DATA_PREFETCHES (аппаратные; по умолчанию, маска 0x3)
REQUESTS_TO_L2 (по умолчанию, маска 0x3f)
L2_CACHE_MISS (по умолчанию, маска 0xf)
L2_CACHE_FILL_WRITEBACK (по умолчанию, маска 0x3)
INSTRUCTION_CACHE_FETCHES
INSTRUCTION_CACHE_MISSES
INSTRUCTION_CACHE_REFILLS_FROM_L2
INSTRUCTION_CACHE_REFILLS_FROM_SYSTEM
INSTRUCTION_CACHE_VICTIMS
INSTRUCTION_CACHE_INVALIDATED (по умолчанию, маска 0xf)
CACHE_BLOCK_COMMANDS (по умолчанию, маска 0x3d)
READ_REQUEST_L3_CACHE (по умолчанию, маска 0xf7)
L3_CACHE_MISSES (по умолчанию, маска 0xf7)
L3_FILLS_CAUSED_BY_L2_EVICTIONS (по умолчанию, маска 0xff)
L3_EVICTIONS (по умолчанию, маска 0xf)
TLB
L1_DTLB_MISS_AND_L2_DTLB_HIT
L1_DTLB_AND_L2_DTLB_MISS
L1_DTLB_HIT
L1_ITLB_MISS_AND_L2_ITLB_HIT
L1_ITLB_MISS_AND_L2_ITLB_MISS
GLOBAL_TLB_FLUSHES
ITLB_RELOADS
ITLB_RELOADS_ABORTED
проблемы
PIPELINE_RESTART_DUE_TO_SELF_MODIFYING_CODE
PIPELINE_RESTART_DUE_TO_PROBE_HIT
LOCKED_OPS (маска 1 - locked instructions, 2 - Cycles in speculative phase,
4 - Cycles in non-speculative phase (including cache miss penalty), 8 - Cache miss penalty in cycles)
MISALIGNED_ACCESSES
1_BIT_ECC_ERRORS (по умолчанию, маска 0xf)
PIPELINE_RESTART_DUE_TO_INSTRUCTION_STREAM_PROBE
INSTRUCTION_FETCH_STALL
RETURN_STACK_HITS
RETURN_STACK_OVERFLOWS
DECODER_EMPTY
DISPATCH_STALLS
DISPATCH_STALL_FOR_BRANCH_ABORT
DISPATCH_STALL_FOR_SERIALIZATION
DISPATCH_STALL_FOR_SEGMENT_LOAD
DISPATCH_STALL_FOR_REORDER_BUFFER_FULL
DISPATCH_STALL_FOR_RESERVATION_STATION_FULL
DISPATCH_STALL_FOR_FPU_FULL
DISPATCH_STALL_FOR_LS_FULL
DISPATCH_STALL_WAITING_FOR_ALL_QUIET
DISPATCH_STALL_FOR_FAR_TRANSFER_OR_RESYNC
FPU_EXCEPTIONS (по умолчанию, маска 0xf)
THERMAL_STATUS (по умолчанию, маска 0x7c)
запросы к памяти, в/в и другим ЦП
MEMORY_REQUESTS (по умолчанию, маска 0x83)
NORTHBRIDGE_READ_RESPONSES (по умолчанию, маска 0x17)
CPU_IO_REQUESTS_TO_MEMORY_IO (по умолчанию, маска 0xa2 - Local I/O to Local Memory;
0xa8 - Local CPU to Local Memory; 0x98 - Local CPU to Remote Memory; ...)
PROBE_RESPONSES_AND_UPSTREAM_REQUESTS (по умолчанию, маска 0xff)
GART_EVENTS (по умолчанию, маска 0xff)
MEMORY_CONTROLLER_REQUESTS (по умолчанию, маска 0x78 - чтение или запись 32 или 64 байт)
CPU_DRAM_REQUEST_TO_NODE (зпрос к памяти определённого узла; по умолчанию, маска 0xff;
1 - к узлу 0; 2 - к узлу 1, 4 - к узлу 2, 8 - к узлу 3)
IO_DRAM_REQUEST_TO_NODE
CPU_READ_COMMAND_LATENCY_NODE_0_3 (задержка между локальным и удалённым узлом; по умолчанию, маска 0xff)
CPU_READ_COMMAND_REQUEST_NODE_0_3 (число запросов, задержка которых подсчитывается; по умолчанию, маска 0xff)
CPU_READ_COMMAND_LATENCY_NODE_4_7 (задержка между локальным и удалённым узлом; по умолчанию, маска 0xff)
CPU_READ_COMMAND_REQUEST_NODE_4_7 (число запросов, задержка которых подсчитывается; по умолчанию, маска 0xff)
CPU_COMMAND_LATENCY_TARGET
CPU_REQUEST_TARGET
HYPERTRANSPORT_LINK0_TRANSMIT_BANDWIDTH (по умолчанию, маска 0xbf)
HYPERTRANSPORT_LINK1_TRANSMIT_BANDWIDTH (по умолчанию, маска 0xbf)
HYPERTRANSPORT_LINK2_TRANSMIT_BANDWIDTH (по умолчанию, маска 0xbf)
HYPERTRANSPORT_LINK3_TRANSMIT_BANDWIDTH (по умолчанию, маска 0xbf)
Демон oprofiled
Демон oprofiled запускается и останавливается утилитой opcontrol,
периодически считывает собранные данные из аппаратных счётчиков
(/dev/oprofile/) и сохраняет их в файлах (/var/lib/oprofile/samples/current).
Журнал - /var/lib/oprofile/samples/oprofile.log (обратить внимание на количество потерь отсчётов в связи
с переполнением буфера).
opcontrol - управление демоном
Утилита opcontrol позволяет управлять сбором данных. Требуются права суперпользователя.
Загрузка модуля и прочая инициализация:
opcontrol --init
--vmlinux=/usr/lib/debug/lib/modules/2.6.18-164.15.1.el5/vmlinux (для профилирования ядра
требуется несжатое ядро, которое можно взять из пакетов
kernel-debuginfo и kernel-debuginfo-common (файл /usr/lib/debug/lib/modules/версия-ядра/vmlinux) -
для CentOS с http://debuginfo.centos.org/5/x86_64/)
--no-vmlinux (профилирование ядра не требуется)
--buffer-size=отсчётов (размер буфера ядра)
--buffer-watershed=отсчётов (рекомендуется от 0.25 до 0.5 размера буфера)
--cpu-buffer-size=отсчётов (буферизация отсчётов для каждого ЦП, увеличение уменьшает потери отсчётов)
)
--event={описание-регистрируемого-события|default} (чтобы задействовать несколько счётчиков необходимо описать
несколько событий в одной строке; после изменений необходимо перезапустить сервис oprofiled;
формат описания - имя-счётчика:число-событий:маска:считать-в-ядре:считать-в-пространстве-пользователя;
не могу поставить более одного счётчика для Xeon 55xx в RHEL 5.4
("ophelp --check-events" проходит;
пересборка пользовательской части 0.9.5 не помогла - модуль ядра возвращает i386/core_2;
в /dev/oprofile только 1 счётчик)
--separate=тип-разделения-отсчётов (список через запятую; рекомендуется lib)
none (по умолчанию, все отсчёты, для которых счётчик адреса указывает на определённую программу, записываются в один
файл для каждой программы)
lib (отсчёты, попавшие в динамическую библиотеку, распределяются по приложениям)
kernel (отсчёты, попавшие в ядро и модули ядра, распределяются по приложениям; подразумевает lib;
асинхронные события (обработка прерываний) приписывается текущему процессу)
thread (отсчёты распределяются по потокам и процессам; не стоит оставлять надолго; приходится сливать в opreport?)
cpu (отсчёты распределяются по ЦП; приходится сливать в opreport?)
Утилита opreport считывает собранные в /var/lib/oprofile/samples/ данные, фильтрует, сливает,
анализирует их и выводит в человеколюбивом формате. Не требуются права суперпользователя.
Необходимо задать спецификацию профиля для фильтрации (по умолчанию - пустая спецификация,
т.е. использовать все накопленные данные) и опции вывода:
--accumulated | -a (нарастающим итогом)
--debug-info | -g (выводить имя исходного файла и номер строки, если есть отладочная информация)
--demangle | -D {none|smart|normal} (приводить имена функций C++ к человеческому виду)
--callgraph | -c (выводить граф вызовов функций, если собрана необходимая информация
--details | -d (выводить не только суммарную информацию для прошраммы/библиотеки/модуля целиком,
но и детализированную информацию для интервалов адресов)
--exclude-dependent | -x (не включать данные о связанных с программой библиотеках и модулях ядра)
--exclude-symbols | -e список-символов (не включать данные о перечисленных символах, требуется --symbols)
--global-percent | -% (все процентные данные выводить относительно общей суммы)
--image-path | -p пути (список путей поиска для программ и модулей ядра - /lib/modules/2.6.18-164.15.1.el5/kernel/)
--root | -r путь
--include-symbols | -i список-символов (включать данные только о перечисленных символах, требуется --symbols)
--long-filenames | -f (выводить полные пути)
--merge | -m {lib,cpu,tid,tgid,unitmask,all} (слить данные, собранные с ключом --separate;
tgid - по задачам, tid - по нитям)
--no-header
--reverse-sort | -r
--session-dir имя-каталога (по умолчанию - /var/lib/oprofile)
--show-address | -w (показать виртуальные адреса; требуется --symbols)
--sort | -s {vma,sample,symbol,debug,image}
--symbols | -l (вывести посимвольную информацию)
--threshold | -t процентов (не выводить малозначимые данные)
--xml | -X (в формате XML; opreport.xsd)
Спецификация профиля (фильтр отбора данных) состоит из комбинации следующих параметров через пробел:
archive:имя-архива (см. утилиту oparchive)
session:список-сессий (по умолчанию - current)
session-exclude:список-сессий
image:список-программ (можно использовать полные имена, относительные имена, шаблоны)
image-exclude:список-программ
lib-image:список-программ
lib-image-exclude:список-программ
event:имя-события
count:количество-отсчётов
unit-mask:маска
cpu:список-ЦП (нумерация с нуля; требуется сбор данных с --separate=cpu)
tgid:список-номеров-процессов (tgid - task group id; требуется сбор данных с --separate=thread)
tid:список-номеров-потоков (требуется сбор данных с --separate=thread)
opreport позволяет сравнить 2 профиля (не забывайте пробелы и экранировку от bash):
opannotate создаёт размеченный (аннотированный) листинг исходного кода программы
(приложение должны быть скомпилировано с отладочной информацией - "gcc -g") и/или
листинг дизассемблера, в который добавляется информация о значении счётчиков.
Спецификация профиля задаётся аналогично команде opreport.
Ключи: