Бит popcount для большого буфера, желательно сборка
Я ищу самый быстрый способ popcount на большой буфер размером 512 или более байт. Я могу гарантировать любое требуемое выравнивание, а размер буфера всегда равен 2. Буфер соответствует распределению блоков, так что обычно бит либо установлен, ни установлен, либо в основном установлен в сторону "левого" буфера, случайные отверстия.
Некоторые из рассмотренных мной решений:
Меня интересует самое быстрое решение, оно должно работать на 32-битном чипсете x86, принадлежащем Core2 или более позднем. SSE и SIMD представляют большой интерес. Я буду тестировать следующий четырехъядерный процессор:
[email protected]:~/anacrolix/public/stackoverflow$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz
stepping : 11
cpu MHz : 1600.000
cache size : 4096 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 4
apicid : 0
initial apicid : 0
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm lahf_lm tpr_shadow vnmi flexpriority
bogomips : 4800.21
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
Ответы
Ответ 1
Я излагаю лучшие функции C/assembly, которые я нашел для подсчет популяции/вес Хэмминга больших буферов ниже.
Самая быстрая функция сборки ssse3_popcount3
описана здесь. Он требует SSSE3, доступного на Intel Core 2 и более поздних версиях, и чипсеты AMD, поступившие в 2011 году. Он использует SIMD инструкции для popcount в 16 байтовых кусках и разворачивает 4 итерации цикла за раз.
Самая быстрая функция C popcount_24words
, описана здесь. Он использует алгоритм разрезания бит. Следует отметить, что clang может фактически генерировать соответствующие инструкции по сборке векторов, что давало впечатляющие результаты. В остальном алгоритм все еще очень быстрый.
Ответ 2
См. 32-разрядную версию в Руководство по оптимизации программного обеспечения AMD, стр. 195 для одной реализации.
Это дает вам код сборки для x86 напрямую.
См. вариант в Стэнфордские бит-скручивающиеся хаки
Версия Стэнфорда выглядит как лучшая для меня.
Это очень легко кодировать как x86 asm.
Ни один из них не использует инструкции ветвления.
Они могут быть обобщены на 64-битные версии.
В версиях с 32 или 64 битами вы можете рассмотреть возможность использования SIMD-версии.
SSE2 будет делать 4 двойных слова или два квад-слова (в любом случае 128 бит)
однажды. То, что вы хотите сделать, это реализовать popcount для 32
или 64 бита в каждом из 2 или 4 регистров.
Вы получите 2 или 4 набора popcounts в регистрах XMM
когда вы закончите; Последний шаг - сохранить и добавить эти
собирать вместе, чтобы получить окончательный ответ. Гадание,
Я ожидаю, что вы сделаете это немного лучше, сделав 4 параллельных 32
бит popcounts, а не 2 параллельных 64 бит popcounts,
поскольку последний, вероятно, примет 1 или 2 дополнительных инструкции
на каждой итерации, и ее легко добавить 4, 32-битные значения вместе
конец.
Ответ 3
Если у вас есть popcnt:
http://kent-vandervelden.blogspot.com/2009/10/counting-bits-population-count-and.html
http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_sse42_ATA.htm
Ответ 4
Я бы предложил реализовать одну из оптимизированных 32-битных подпрограмм popcnt из Hacker Delight, но сделать это для 4 x 32-битных целых элементов в вектор SSE. Затем вы можете обработать 128 бит на итерацию, что должно дать вам пропускную способность 4x по сравнению с оптимизированной 32-разрядной скалярной процедурой.