AVX(2) data load

Граждане, что-то вот отчаялся понять, отчего может быть так что

Вот так - хорошо, профайлер в этом месте особых тормозов не показывает:

                __m128 p0 = _mm_loadu_ps(source);
                __m128 p1 = _mm_loadu_ps(source + 4);
                __m128 p2 = _mm_loadu_ps(source + 8);

 

А вот так - нехорошо:

                __m256 i0008 = _mm256_loadu_ps(fsrcstart3);
                __m256 i0915 = _mm256_loadu_ps(fsrcstart3 + 8);
                __m256 i1623 = _mm256_loadu_ps(fsrcstart3 + 16);

То есть профайлер кажет в этом месте ~3 лишние секунды на загрузку (тех же самых) данных, общим объемом в ~1.2 гигапикселя (28 файлов по 40 Mpix). Это, конечно, 0.1 sec CPU time на файл, исполняется впараллель во все ядра, т.е. wall clock - ну может 20 миллисекунд лишних на файл, но обидно ж.

Пробовал совать префетч. И перед фетчем (для текущих данных) и после него (для данных следующего цикла) - толку мало. Попробую, конечно, еще размазать загрузку другими командами.

Или VTune Amplifier в таких делах доверять не стоит?

P.S. А то же самое (ну по сути), но с целыми данными, где целая пачка _mm_loadu_si128 - работает вроде неплохо. Ну с той поправкой, правда, что данных вдвое меньше (int16 вместо float32) и в тестовом наборе у меня таких файлов немного.

P.P.S. И с еще одним типом данных, где один _mm256_loadu_ps на цикл - AVX заметно быстрее SSE.

Comments

А ты учитываешь все спецэффекты от AVX2?

А какие именно спецэффекты то?
_mm256_zeroall() по выходу из AVX-кода - делаю.

Блок включается какие-то сотни тысяч тактов. потом довольно быстро (но не рсазу) выключается. Плюс после включения блока процессор снижает частоту если был в турбобусте. Причём, как я понимаю, существенно (но зависит от кокнретной модели).

Не, ну вот смотри, есть два набора файлов, примерно одинакового размера, 24 linear DNG в плавучке, 3 компонента на пиксель и еще 24 - таких же, но 4 компонента на пиксель. Отличаются деталями (fp16/fp24/fp32, черный вычтен/не вычтен, есть scale в 0-1 или нету), это я из двух исходников наклонировал.

И вот значит float4 во внутреннее представление (тоже float4) - AVX быстрее. float3->float4 - AVX медленнее. Ну ладно, я бы даже и согласился бы (там float3->float4 не такой простой код), но
а) Amplifier показывает тормоза на чтении данных (и вроде как не должен провираться)
б) int3 -> float4 - работает нормально, хотя там код еще сложнее и регистров надо еще больше (но, понятно входных данных самих меньше - и может быть потому оно не проявляется)

P.S. Оно там все слезы на фоне декодирования float-данных, но разобраться и понять очень бы хотелось конечно

А cache line splits amplifier не показывает во втором случае? (плюс выше уже написали про включение AVX и частоту.)

Я не очень понимаю где/как это там смотреть.

Вот зато там есть memory access профайлинг - и таки да, интересные мне инструкции 'memory bound' (еще, конечно, гистограмма сильно тормозит - но этим не удивить)

А SSE-случай - не memory bound.

Это на Haswell исполняется? split loads - в backend/cache/L1 колонке.

Kaby Lake.
В колонке - при каком анализе? Я все стандартные попробовал - нет колонки, надо вероятно настраивать.

Амплифаейр - свежий. 2018-й

general exploration analysis/bottom-up view/general exploration viewpoint: backend bound/memory bound/L1 bound.

Еще advisor/roofline может показать L1/L2/L3/DRAM throughput для обоих циклов.

Ага, я до этого места дошел.
L1 bound и DRAM bound (красным и большие проценты)

Почему то же самое не bound для примерно такого же 128-битного кода - ну хрен пойми.

L1 bound тоже разворачивается на 6 показателей.

Ага.
FB full (и немного 4k aliasing, но тут блин вообще ничего не сделаешь, какие дали данные снаружи, такие и есть)
Что неудивительно, фигачим то гигабайтами подряд.

Увы, ничего тут не поможет, кажется, MOVNTDQA для невыровненых данных нету, выровнять входные я не могу, значит вот тут такая неустроенность имеется: читать мимо кэша не выйдет.

Кстати, знакомый, который много профилирует с помощью PMC, недоумевает как Амплифаер показывает тормоза на загрузке. Он говорит, что PMC не позволяют такой результат получить достоверно.

Может статистически смотрит (а куды мы попали то)?

Это называется sampling, и он biased довольно здорово, причём biased по-разному в зависимости от команд и их последовательностей и как они поделились на пачки при сабмите в ядро процессора. Это большое исскуство читать вывод семплинг-профайлера.

Ну я вижу тотальное замедление (в 2 секунды CPU time на 24 примера, т.е. ~10msec wall time на файл) - и оставлю SSE вариант пока.

Но вообще вот результаты профайлинга amplifier у меня особых вопросов не вызывают как правило, похоже на правду ж все

Ну оно конечно при просмотре ассемблера - часто показывает тормоза на следующей инструкции, а не на той что тормозит.

Но мы же тоже понимаем что на паре
movups xmm0, [addr]
add rdx, 0x10

Если и показывает время на сложении - это оно на инструкцию промахнулось.

Да, и давай я всё же уточню: AVX-команд вдвое меньше чем SSE? Т.е. объём данных прокачивается строго одинаковый и разница в скорости между 2*N командами SSE (по 128 бит) и N командами AVX (по 256 бит)?

load/store - вдвое меньше, естественно.
Арифметики плавучей - ну тоже (4 операции на юнит из 1/2 пикселей соответственно)
reordering: SSE 7 команд на 4 выходных пикселя, AVX: 12 команд на 8 пикселей. Потому что float3->float4 не вполне тривиальная операция.