Comments 9
Занятно. Сколкьо давалось времени на код? Если день-два, то круто, если неделя, то уже менее интересно =)
PS: не знаю есть ли в Go интренсики, но после описания задачи выглядело так, что векторные инструкции хорошо ложаться на выдергивание одного байта из 4х.
Вообще было 5 дней, но по факту у меня было 3 вечера, я поздно увидел письмо о новой задаче и основную работу никто не отменял.
В Go можно использовать асскмблер, но быстрого решения как с помощью AVX команд вынуть каждый 3 байт я не нашёл, есть идеи как это сделать?
Там же RGBA? Значит каждый 4ый (да и в сорцах тоже берется каждый четвертый). Если есть AVX512, то какой-нибудь _mm512_mask_cvtepi32_epi8 должен прокатить. Если только SSE в наличии, то shuffle или puck, вероятно сработают.
Если пользоваться стандартным декодером, то RGBA, но в сыром виде в тестовых картинках - RGB.
В Си простые циклы векторизуются автоматически, интринсики вспоминать не надо.
https://gcc.godbolt.org/z/a9ecW4hx4
Для SIMD конечно лучше, если в исходнике 4 байта на пиксель, меньше команд понадобится (или менее "тяжёлых").
Но по моему опыту, копирование с извлечением синего канала не должно сильно влиять. В основном должно упираться в распаковку/упаковку png, потому что png вообще медленный. Как я слышал, zlib-овский inflate/deflate слабо (или вообще никак) ускоряется через SIMD. У вас получилось 20% на выборе оптимизированной библиотеки - ну вот примерно так, да, и это мало. Качественные библиотеки jpeg ускоряют в разы.
Поэтому главное - грамотное распараллеливание упаковки/распаковки. И у вас хороший результат, я не ожидал, что можно делать чтение 1000 картинок и упаковку одной огромной за 0.23 c.
Ну во флеймграфе только половина от процессинга входной картинки - распаковка png, остальное выглядит как раз как копирование байтиков туда/обратно.
А так да, достойный результат. Сам сейчас сижу профилирую всякие штуки, жаль что не приметил соревнование)
Надо было уточнить - мой опыт относится к Си/Дельфи, Go толком не знаю. Сейчас попытался переписать функцию на Go:
https://gcc.godbolt.org/z/ernMd4qE3
Без проверок диапазонов ассемблер похож, кстати, на Дельфи - векторизации нет, но в целом достаточно чистый код.
И так или иначе он работает гораздо быстрее ввода-вывода png. Я даже проверил:
Загрузка 24-битного png через GDI+: 22 мс
Извлечение канала на Дельфи (имитируем Go): 0.76 мс
Извлечение канала на Си: 0.19 мс
Отсюда и вывод, что не должно копирование байтиков заметно тормозить... не знаю, может автору тоже отключить проверки глобально директивой B-? Или это плохой тон?
Я нашёл способ как ещё в 2 раза ускорить копирование одной картинки в другую, пошёл статью писать
История победы в VK Cup'22/23:Go