Существует ли быстрый способ проверить, является ли SIMD-вектор нулевым вектором (все компоненты равны + -zero). В настоящее время я использую алгоритм с использованием сдвигов, который выполняется в log2 (N) времени, где N - размерность вектора. Существует ли что-нибудь быстрее? Обратите внимание, что мой вопрос более широк (теги), чем предлагаемый ответ, и он относится к векторам всех типов (integer, float, double, ...).SIMD zero vector test
ответ
Как насчет этого простого кода avx? Я думаю, что это O (N) и не знаю, как вы могли бы сделать лучше, не делая предположений о входных данных - вы должны действительно читать каждое значение, чтобы знать, является ли его 0, поэтому он должен делать столько, сколько возможно за цикл ,
Вы должны иметь возможность массировать код в соответствии с вашими потребностями. Следует рассматривать как +0, так и -0 как ноль. Будет работать для неадминистративных адресов памяти, но выравнивание по 32-байтным адресам сделает загрузку быстрее. Вы можете добавить что-то, чтобы иметь дело с оставшимися байт, если размер не кратен 8.
uint64_t num_non_zero_floats(float *mem_address, int size) {
uint64_t num_non_zero = 0;
__m256 zeros _mm256_setzero_ps();
for(i = 0; i != size; i+=8) {
__m256 vec _mm256_loadu_ps (mem_addr + i);
__m256 comparison_out _mm256_cmp_ps (zeros, vec, _CMP_EQ_OQ); //3 cycles latency, throughput 1
uint64_t bits_non_zero = _mm256_movemask_ps(comparison_out); //2-3 cycles latency
num_non_zero += __builtin_popcountll(bits_non_zero);
}
return num_non_zero;
}
Я думаю, что __builtin_popcountll не имеет значения для определения нуля. – user1095108
yep, просто проверьте bits_non_zero и, кроме того, конечно, выйдите из цикла, останавливая ненужную обработку, если она не равна нулю, если вы хотите эту оптимизацию. В коде фактически учитывается количество поплавков в векторе, которые не равны нулю, как следует из названия, поэтому «вы должны иметь возможность массировать код в соответствии с вашими потребностями» – Hal
@Hal Это вряд ли будет быстрее, чем просто загрузка данных как '__m256i', ORing на два отдельных аккумулятора, затем в конце, ORing аккумуляторов вместе, отбрасывая' __m256', делая '_mm256_cmp_ps()' и выполняя '_mm256_movemask_ps()' или 'vptest'. При этом аккуратный трюк, который вы могли бы использовать, чтобы избежать перемещения маски и popcount во внутреннем цикле, заключается в том, чтобы придать результат сравнения целому числу и _subtract_ из аккумулятора. Если результатом сравнения является все ('== -1'), вычитая его из аккумулятора, добавляя к нему' + 1'. Если это 0, вычитание не будет иметь эффекта. –
Если вы хотите проверить, поплавки для +/- 0,0, то вы можете проверить все биты, равным нулю , за исключением знакового бита. Любые биты в любом месте, кроме знакового бита, означают, что поплавок отличен от нуля. (http://www.h-schmidt.net/FloatConverter/IEEE754.html)
Agner Туман-х asm optimization guide указывает на то, что вы можете проверить поплавок или дважды за ноль с помощью инструкции целочисленных:
; Example 17.4b
mov eax, [rsi]
add eax, eax ; shift out the sign bit
jz IsZero
Для векторов, хотя, используя ptest
с знаком-битной маски лучше, чем использование paddd
, чтобы избавиться от бита знака. На самом деле, test [rsi], $0x7fffffff
может быть более эффективным, чем последовательность загрузки/добавления Agner Fog, но 32-битное мгновенно, вероятно, останавливает нагрузку от микро-плавки на Intel и, возможно, имеет больший размер кода.
x86 PTEST
(SSE4.1) делает побитовое И и устанавливает флаги на основании результата.
movdqa xmm0, [mask]
.loop:
ptest xmm0, [rsi+rcx]
jnz nonzero
add rcx, 16 # count up towards zero
jl .loop # with rsi pointing to past the end of the array
...
nonzero:
Или cmov
может быть полезно потреблять флаги, установленные ptest
.
IDK, если можно было бы использовать инструкцию loop-counter, которая не устанавливала флаг нуля, поэтому вы могли бы выполнить оба теста с помощью одной команды перехода или чего-то еще. Возможно нет. И дополнительный uop для объединения флагов (или срыв частичных флагов на более ранние процессоры) сэкономит преимущество.
@Iwillnotexist Idonotexist: повторите один из комментариев к OP: вы не можете просто movemask, не делая сначала pcmpeq
, или cmpps
. Необязательный бит может быть не в бит! Вы, наверное, знали об этом, но один из ваших комментариев, похоже, оставил его.
Мне нравится идея объединить несколько значений перед фактическим тестированием. Вы правы, что знаковые биты будут ИЛИ с другими знаками, а затем вы игнорируете их так же, как если бы вы тестировали один за раз. Цикл, который POR
s 4 или 8 векторов перед каждым PTEST
, вероятно, будет быстрее. (PTEST
- это 2 устройства и не может использовать макро-предохранитель с jcc
.)
- 1. SIMD vs Vector architecture
- 2. C++ Vector Size is Zero
- 3. load vector from large vector with simd на основе маски
- 4. Динамически выделять SIMD Vector как массив удвоений
- 5. vector push_back zero в пустой вектор
- 6. Zero pad a vector in matlab
- 7. Почему std :: vector zero инициализирует свою память?
- 8. SIMD Sony Vector Math Library в OS X с C++
- 9. Производительность std :: vector <Test> vs std :: vector <Test*>
- 10. C++ Array vs Vector performance test explain
- 11. CPU SIMD vs GPU SIMD?
- 12. Почему OpenMP 'simd' имеет лучшую производительность, чем 'parallel for simd'?
- 13. SIMD или нет SIMD - кросс-платформа
- 14. Инструкции SIMD с условием копирования
- 15. SIMD Реализация std :: nth_element
- 16. SIMD выпуск программы компиляция
- 17. C++ Централизация использования SIMD
- 18. реализовать SIMD в C++
- 19. как сгенерировать код для инициализации std :: vector с пользовательским значением Zero, если он существует как T :: Zero?
- 20. Capture SIGFPE из инструкции SIMD
- 21. SIMD-8, SIMD-16 или SIMD-32 в opencl на gpgpu
- 22. Divide By Zero Oddities
- 23. Прагма SIMD от Intel против Прагма OMP SIMD OpenMP в
- 24. Почему loaderInfo.bytesTotal is Zero
- 25. Отправка инструкций SIMD + SIMDPP + qmake
- 26. Ruby SIMD & SSE
- 27. SIMD (AVX) Сравнить
- 28. расчет детерминанта с SIMD
- 29. Языки программирования SIMD
- 30. Хорошая портативная SIMD-библиотека
Возможный дубликат [Самый эффективный способ проверить, все ли компоненты \ _ \ _ m128i равны 0 \ [с использованием свойств SSE \]] (http: //переполнение стека.com/questions/27905677/most-efficient-way-to-check-if-all-m128i-components-are-0-using-sse-intrinsic) –
Зависит от инструкций, которые доступны, с тегами neon и avx together Я не знаю, что вы делаете. – harold
@harold список/таблица свойств или идей для выполнения этой очень общей операции. Если вопрос слишком широк, я удалю его. – user1095108