Introdução
Eu tenho dois conjuntos de máquinas, conjunto A e conjunto B , aparentemente com a mesma configuração de hardware / software, mas com uma diferença significativa no desempenho. Máquinas no conjunto B são x4 mais rápidas que as máquinas no conjunto A. No entanto, se eu reinicializar uma máquina no conjunto A , ela é inexplicavelmente iniciada funcionando como esperado, como máquinas no conjunto B. Não consigo encontrar uma explicação para esse comportamento.
Configuração de hardware
- Intel
S2600KP
platform
- Processador duplo
E5-2630v3
, 8 núcleos físicos, frequência base de 2,4 GHz, frequência Turbo de 3,2 GHz.
-
8x8GB RAM DDR4
, 2133Mhz, um módulo por canal
- Nenhuma das máquinas possui eventos SEL registrados pelo BMC que podem apontar para problemas de hardware.
- Nenhum da máquina está acionando qualquer Exceção de Checagem de Máquina durante toda a duração dos benchmarks.
Todos os componentes de hardware são idênticos em Model / Part Number.
Configurações e software
-
A versão do BIOS e as configurações do BIOS são idênticas, por exemplo, HT
está ativado, Turbo Boost
está ativado. Veja o link para detalhes.
-
As máquinas estão executando a mesma 64 bits
versão de Red Hat 6
com o kernel 2.6.32-504
.
O problema
As máquinas em ambos os conjuntos estão inativas, mas, seja qual for a carga que eu tente executar, obtenho resultados muito diferentes em termos de desempenho. Por uma questão de simplicidade, vou executar todos os benchmarks no núcleo 0. O resultado é reproduzível em todos os núcleos (ambos processadores).
Defina A
[root@SET_A ~]# uptime
11:48:40 up 51 days, 19:34, 2 users, load average: 0.00, 0.00, 0.00
[root@SET_A ~]# taskset -c 0 sh -c 'time echo "scale=5000; a(1)*4" | bc -l > /dev/null'
real 0m43.751s
user 0m43.742s
sys 0m0.005s
Conjunto B
[root@SET_B ~]# uptime
11:50:00 up 15 days, 19:43, 1 user, load average: 0.00, 0.00, 0.00
[root@SET_B ~]# taskset -c 0 sh -c 'time echo "scale=5000; a(1)*4" | bc -l > /dev/null'
real 0m18.648s
user 0m18.646s
sys 0m0.004s
Observações
turbostatos
reporta o núcleo 0 como estando no estado C0 Consumption
e no estado P0 Performance
com a Freqüência Turbo habilitada para toda a duração do benchmark.
Defina A
[root@SET_A ~]# turbostat -i 5
pk cor CPU %c0 GHz TSC SMI %c1 %c3 %c6 %c7 CTMP PTMP %pc2 %pc3 %pc6 %pc7 Pkg_W RAM_W PKG_% RAM_%
3.15 3.18 2.39 0 3.26 0.00 93.59 0.00 40 46 49.77 0.00 0.00 0.00 46.45 22.41 0.00 0.00
0 0 0 99.99 3.19 2.39 0 0.01 0.00 0.00 0.00 40 46 0.00 0.00 0.00 0.00 29.29 12.75 0.00 0.00
Conjunto B
[root@SET_B ~]# turbostat -i 5
pk cor CPU %c0 GHz TSC SMI %c1 %c3 %c6 %c7 CTMP PTMP %pc2 %pc3 %pc6 %pc7 Pkg_W RAM_W PKG_% RAM_%
3.14 3.18 2.39 0 3.27 0.00 93.59 0.00 38 40 49.81 0.00 0.00 0.00 46.12 21.49 0.00 0.00
0 0 0 99.99 3.19 2.39 0 0.01 0.00 0.00 0.00 38 40 0.00 0.00 0.00 0.00 32.27 13.51 0.00 0.00
Referência de referência simplificada
Para simplificar o benchmark o máximo possível (sem FP, com menos acessos à memória possível), escrevi o seguinte código de 32 bits.
.text
.global _start
_start:
movl $0x0, %ecx
oloop:
cmp $0x2, %ecx
je end
inc %ecx
movl $0xFFFFFFFF,%eax
movl $0x0, %ebx
loop: cmp %eax, %ebx
je oloop
inc %ebx
jmp loop
end:
mov $1, %eax
int $0x80
.data
value:
.long 0
Ele simplesmente incrementa um registro de 0 a 0xFFFFFFFF
duas vezes, nada mais.
Defina A
[root@SET_A ~]# md5sum simple.out
30fb3a645a8a0088ff303cf34cadea37 simple.out
[root@SET_A ~]# time taskset -c 0 ./simple.out
real 0m10.801s
user 0m10.804s
sys 0m0.001s
Conjunto B
[root@SET_B ~]# md5sum simple.out
30fb3a645a8a0088ff303cf34cadea37 simple.out
[root@SET_B ~]# time taskset -c 0 ./simple.out
real 0m2.722s
user 0m2.724s
sys 0m0.000s
x4 diferença para incrementar um registro.
Mais observações com o benchmark simplificado
Durante o benchmark, o número de interrupções é o mesmo em ambas as máquinas, ~1100 intr/s
(reportado com mpstat). Estas são principalmente Interrupções do Temporizador Local em CPU0
, então basicamente não há diferença na fonte de interrupção.
Defina A
[root@SET_A ~]# mpstat -P ALL -I SUM 1
01:00:35 PM CPU intr/s
01:00:36 PM all 1117.00
Conjunto B
[root@SET_B ~]# mpstat -P ALL -I SUM 1
01:04:50 PM CPU intr/s
01:04:51 PM all 1112.00
Para P-States
e C-States
tem o mesmo que acima.
análise perf
Defina A
Performance counter stats for 'taskset -c 0 ./simple.out':
41,383,515 instructions:k # 0.00 insns per cycle [71.42%]
34,360,528,207 instructions:u # 1.00 insns per cycle [71.42%]
63,675 cache-references [71.42%]
6,365 cache-misses # 9.996 % of all cache refs [71.43%]
34,439,207,904 cycles # 0.000 GHz [71.44%]
34,400,748,829 instructions # 1.00 insns per cycle [71.44%]
17,186,890,732 branches [71.44%]
143 page-faults
0 migrations
1,117 context-switches
10.905973410 seconds time elapsed
Conjunto B
Performance counter stats for 'taskset -c 0 ./simple.out':
11,112,919 instructions:k # 0.00 insns per cycle [71.41%]
34,351,189,050 instructions:u # 3.99 insns per cycle [71.44%]
32,765 cache-references [71.46%]
3,266 cache-misses # 9.968 % of all cache refs [71.47%]
8,600,461,054 cycles # 0.000 GHz [71.46%]
34,378,806,261 instructions # 4.00 insns per cycle [71.41%]
17,192,017,836 branches [71.37%]
143 faults
2 migrations
281 context-switches
2.740606064 seconds time elapsed
Observações
- O número de instruções de espaço do kernel é diferente devido aos caminhos de controle que levam a uma reprogramação. Não há chamadas do sistema envolvidas além de um% final% co_de. Claramente, o número de opções de contexto é maior para o Conjunto A.
- Há também uma pequena diferença nas instruções de espaço do usuário (
sys_exit
). Isso pode ser causado pela mesma razão acima? Instruções que levam a um reagendamento que são contabilizadas como espaço do usuário. Ou instruções em contexto de interrupção?
- O número total de instruções para o Conjunto A é
~10M
maior, mas o número de 0.06%
é o dobro. Isso é esperado? Uma verificação rápida na configuração do cache leva ao mesmo resultado. O cache está habilitado corretamente ( L3 cache references
, CD é 0) e a configuração CR0: 0x80050033
é idêntica.
- Provavelmente, o valor mais interessante é o instr por ciclo. 1 inst por ciclo no Conjunto A, 4 inst por ciclo no Conjunto B .
Perguntas finais
-
Existe um motivo óbvio que pode explicar essa diferença no desempenho?
-
Por que as máquinas no Conjunto A estão sendo executadas a 1 instr por ciclo, enquanto as máquinas no Conjunto B estão sendo executadas a 4 instr por ciclo, considerando o fato de que a configuração de hardware / software é idêntica?
-
Por que reinicializar uma máquina parece corrigir esse comportamento? Como explicado na introdução, se eu reinicializar uma máquina no Conjunto A, ela será executada conforme o esperado.
A causa aqui é ou muito trivial que eu senti falta ou muito complexa que realmente não pode ser explicada. Espero que seja o primeiro, qualquer sugestão / ajuda / sugestão seja apreciada.