Бит popcount для большого буфера, с ядром 2 CPU (SSSE3)

Я ищу самый быстрый способ popcount на большом буфере 512 или более байт. Я могу гарантировать любое требуемое выравнивание, а размер буфера всегда равен 2. Буфер соответствует распределениям блоков, поэтому обычно биты либо все установлены, либо не установлены, либо в основном установлены в пользу "левой" части буфера со случайными отверстиями.

некоторые решения, которые я рассмотрел:

меня интересует самое быстрое решение, оно должно работать на 32-битном чипсете x86, принадлежащем core2 или более позднему. SSE и SIMD представляют большой интерес. Я буду тестировать на следующем четырехъядерном процессоре:

matt@stanley:~/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:

4 ответов


см. 32-разрядную версию в руководство по оптимизации программного обеспечения AMD, стр. 195 для одной реализации. Это дает вам код сборки для x86 непосредственно.

см. вариант в Стэнфорд бит-twiddling хаки Стэнфордская версия кажется мне самой лучшей. Это выглядит очень легко кодировать как x86 asm.

ни один из них не использует инструкции филиала.

Они могут быть обобщены на 64-разрядные версии.

с 32 или 64 битовые версии, вы можете рассмотреть возможность создания версии SIMD. SSE2 будет делать 4 двойных слова или два квадворда (в любом случае 128 бит) однажды. Что вы хотите сделать, это реализовать popcount для 32 или 64 бита в каждом из 2 или 4 доступных регистров. Вы получите 2 или 4 набора popcounts в регистрах XMM когда вы закончите; последний шаг-сохранить и добавить их popcounts вместе, чтобы получить окончательный ответ. Угадывание, Я ожидал, что вы сделаете это немного лучше, делая 4 parallel 32 бит popcounts, а не 2 параллельных 64-битных popcounts, поскольку последний, вероятно, примет 1 или 2 дополнительные инструкции в каждой итерации, и его легко добавить 4, 32 бит вместе конец.



я описываю лучшие функции C / assembly, которые я нашел для количество населения / вес Хэмминга больших буферов ниже.

самая быстрая функция сборки -ssse3_popcount3, назвал здесь. Это требует SSSE3, доступный на Intel Core 2 и более поздних версиях, и чипсеты AMD, поступающие в 2011 году. Он использует SIMD инструкции для popcount в 16 байтовых кусках и разворачивает 4 итерации цикла за раз.

самый быстрый C функция popcount_24words, назвал здесь. Он использует алгоритм нарезки битов. Примечательно, что я нашел это лязгом может фактически генерировать соответствующие инструкции по сборке векторов, что дает впечатляющие повышения производительности. Кроме того, алгоритм очень быстро.


Я бы предложил реализовать одну из оптимизированных 32-битных подпрограмм popcnt из восторг хакера, но сделайте это для 4 x 32 битных целочисленных элементов в векторе SSE. Затем вы можете обрабатывать 128 бит на итерацию, что должно дать вам пропускную способность 4X по сравнению с оптимизированной 32-битной скалярной процедурой.