Contagem populacional mais rápida de 64 bits (peso de Hamming)
Eu tive que calcular o peso de Hamming para um fluxo contínuo muito rápido de dados de 64 bits e usando opopcnt
As instruções de montagem lançam uma exceção para o meu Intel Core i7-4650U.
Eu verifiquei o prazer da minha bíblia Hacker e examinei a Web em busca de todos os tipos de algoritmos (é um monte por aí desde que começaram a lidar com esse 'problema' no nascimento da computação).
Passei o fim de semana brincando com algumas idéias próprias e criei esses algoritmos, onde estou quase na velocidade em que posso mover dados para dentro e para fora da CPU.
//64-bit popcnt using BMI2
_popcnt_bmi2:
mov (%rdi),%r11
pext %r11,%r11,%r11
not %r11
tzcnt %r11,%r11
mov %r11,(%rdx)
add $8h,%rdi
add $8h,%rdx
dec %rsi
jnz _popcnt_bmi2
ret
No código acima eu usopext
(IMC2) onde os dados recebidos estão se usando como a máscara. Todos os bits existentes entrarão em colapso começando com o bit menos significativo no registro de resultados (ele próprio novamente). Então eu preciso calcular o número de bits recolhidos para inverter todos os bits e usartzcnt
para contar o número de, agora zera. Eu pensei que era uma boa idéia.
Então eu também tentei uma abordagem AVX2:
//64-bit popcnt using AVX2
_popcnt_avx2:
vmovdqa (%rcx),%ymm2
add $20h,%rcx
vmovdqa (%rcx),%ymm3
add $20h,%rcx
vmovdqa (%rcx),%ymm4
popcnt_avx2_loop:
vmovdqa (%rdi),%ymm0
vpand %ymm0, %ymm2, %ymm1
vpandn %ymm0, %ymm2, %ymm0
vpsrld $4h,%ymm0, %ymm0
vpshufb %ymm1, %ymm3, %ymm1
vpshufb %ymm0, %ymm3, %ymm0
vpaddb %ymm1,%ymm0,%ymm0 //popcnt (8-bits)
vpsadbw %ymm0,%ymm4,%ymm0 //popcnt (64-bits)
vmovdqa %ymm0,(%rdx)
add $20h,%rdi
add $20h,%rdx
dec %rsi
jnz popcnt_avx2_loop
No caso do AVX2, li 32 bytes e ocultei os petiscos (ymm2
), então eu usoymm3
como uma tabela de pesquisa para contar pouco os petiscos. Depois adiciono os resultados aos de 8 bits e depois uso o super condensadovpsadbw
para adicionar 8 bytes a um valor de 64 bits (ymm4
= 0).
Alguém conseguiu algo mais rápido nas mangas?
Editar:
A falhaPOPCNT
foi devido a um erro que cometi no meu código, essa função funciona no meu Intel Core i7-4650U. Por favor, veja o meu post abaixo exibindo os resultados do banco.