Снижение производительности при включенном PTI= в Linux-4.4.0
Я запускаю Java-тест на Ubuntu 16.04 и обнаружил разницу в производительности при включенном и выключенном PTI.
Моя хост-система использует процессор Ivybridge (2 ядра, 4 HT) 1,6 ГГц, с памятью 16 ГБ.
Я попытался использовать perf, чтобы проанализировать, откуда взялась разница, следующим образом.
С pti=off в grub.cfg,
# perf stat -e bus-cycles,cache-misses,cache-references,L1-dcache-load-misses,dTLB-load-misses,L1-dcache-prefetch-misses,LLC-prefetches ./test.sh
Performance counter stats for './test.sh':
774,986,827 bus-cycles (59.13%)
24,044,906 cache-misses # 12.803 % of all cache refs (58.17%)
187,799,652 cache-references (57.51%)
207,345,039 L1-dcache-load-misses (57.65%)
13,081,612 dTLB-load-misses (58.85%)
22,678,453 L1-dcache-prefetch-misses (59.62%)
24,089,506 LLC-prefetches (59.99%)
6.210151360 seconds time elapsed
и, с pti=on (настройки по умолчанию в ядре Linux), я получил,
# perf stat -e bus-cycles,cache-misses,cache-references,L1-dcache-load-misses,dTLB-load-misses,L1-dcache-prefetch-misses,LLC-prefetches ./test.sh
Статистика счетчика производительности для './test.sh':
1,205,903,578 bus-cycles (57.92%)
23,877,107 cache-misses # 13.167 % of all cache refs (57.31%)
181,340,147 cache-references (57.46%)
206,177,901 L1-dcache-load-misses (58.42%)
63,285,591 dTLB-load-misses (59.06%)
24,012,988 L1-dcache-prefetch-misses (58.65%)
24,928,410 LLC-prefetches (58.23%)
10.344839116 seconds time elapsed
test.sh - это программа, которая должна быть профилирована, из вышеприведенного вывода perf, test.sh занял больше времени с pti = on, чем с pti=off, но вывод события НЕ ясен, откуда берется разница.
Есть ли какое-нибудь другое перф событие, которое может помочь в этом случае?
Обновлено с большим количеством перф события.
PTI = выкл
# perf stat --repeat 5 -e cache-references,cache-misses,cpu-cycles,ref-cycles,faults,L1-dcache-loads,L1-dcache-load-misses,L1-icache-load-misses,branches,branch-misses,node-loads,node-load-misses,instructions,cs java mytest
Performance counter stats for 'java mytest' (5 runs):
8,711,306 cache-references ( +- 4.13% ) (48.49%)
1,290,234 cache-misses # 14.811 % of all cache refs ( +- 4.04% ) (49.44%)
709,587,381 cpu-cycles ( +- 1.44% ) (48.91%)
671,299,480 ref-cycles ( +- 1.95% ) (58.09%)
5,918 faults ( +- 0.12% )
185,928,475 L1-dcache-loads ( +- 4.29% ) (35.90%)
9,249,983 L1-dcache-load-misses # 4.98% of all L1-dcache hits ( +- 5.91% ) (27.84%)
4,718,632 L1-icache-load-misses ( +- 5.47% ) (20.83%)
106,021,866 branches ( +- 1.98% ) (31.56%)
4,487,091 branch-misses # 4.23% of all branches ( +- 5.35% ) (40.34%)
450,170 node-loads ( +- 9.18% ) (38.32%)
0 node-load-misses (40.62%)
509,344,631 instructions # 0.72 insns per cycle ( +- 5.59% ) (49.64%)
458 cs ( +- 2.05% )
0.216794242 seconds time elapsed ( +- 3.44% )
PTI=ON
# perf stat --repeat 5 -e cache-references,cache-misses,cpu-cycles,ref-cycles,faults,L1-dcache-loads,L1-dcache-load-misses,L1-icache-load-misses,branches,branch-misses,node-loads,node-load-misses,instructions,cs java mytest
Performance counter stats for 'java mytest' (5 runs):
10,109,469 cache-references ( +- 4.10% ) (44.67%)
1,360,012 cache-misses # 13.453 % of all cache refs ( +- 2.16% ) (45.28%)
1,199,960,141 cpu-cycles ( +- 2.44% ) (46.13%)
1,086,243,141 ref-cycles ( +- 1.28% ) (54.64%)
5,923 faults ( +- 0.24% )
163,902,394 L1-dcache-loads ( +- 3.46% ) (41.91%)
8,588,505 L1-dcache-load-misses # 5.24% of all L1-dcache hits ( +- 5.59% ) (27.82%)
5,576,811 L1-icache-load-misses ( +- 3.87% ) (18.41%)
117,508,300 branches ( +- 3.98% ) (27.34%)
4,878,640 branch-misses # 4.15% of all branches ( +- 2.28% ) (35.55%)
585,464 node-loads ( +- 9.05% ) (34.55%)
0 node-load-misses (36.68%)
614,773,322 instructions # 0.51 insns per cycle ( +- 4.11% ) (46.10%)
476 cs ( +- 2.75% )
0.375871969 seconds time elapsed ( +- 0.81% )
1 ответ
Понятия не имею, какое событие "автобусные циклы" фактически измеряет. тактовые частоты ядра обычно более актуальны.
Но в любом случае, PTI=on делает каждый системный вызов (и другую запись в ядре) более дорогим, потому что он должен изменить управляющий регистр x86 CR3 (установив новый указатель верхнего уровня таблицы страниц). Это буквально то, как он изолирует пространство пользователя от доступа к таблицам страниц ядра.
Обратите внимание на большое увеличение dTLB-load-misses
, Благодаря поддержке идентификаторов контекста процесса (PCID) PTI может избежать полной очистки TLB при каждом входе в ядро. Но я не знаю деталей. (Без PCID замена таблиц страниц делает недействительным весь TLB.)
Вы могли бы использовать strace -c
время системных вызовов.
С perf record
(с достаточными привилегиями) вы можете записывать примеры, содержащие код ядра, чтобы вы могли увидеть, какие инструкции в ядре действительно занимали много времени. (Перемещение к CR3 также требует времени, и то же самое относится и к смягчению Спектра, которое отделено от смягчения Meltdown (PTI). Но я думаю, что большая часть стоимости смягчения Meltdown заключается в том, что TLB пропускается со временем внутри ядра и снова после возвращения пользователю -пространство, а не из реальных таблиц подкачки.)