172 похожих чатов

А никто не знает как в libvips правильно бенчить скорость

ресайза изображения? Я нашёл только то, что надо отключить кеширование операций, иначе скорость ресайза улетает в бесконечность.
Но, очевидно, это не всё, т.к. у меня получается так что уменьшение картинки с фильтром lancsoz3 выполняется всего лишь в 4 раза медленнее чем nearest.
Такого просто не может быть в однопоточном режиме.

36 ответов

118 просмотров

почему не может быть?

Kirill-Kuzminykh Автор вопроса
Rustam
почему не может быть?

nearest - это никаких вычислений. В общем случае - это просто копирование байтиков с заданным шагом. А свёртка с адаптивным размером ядра - это вычисление коэффициентов и потом умножение каждого пикселя исходного изображения по нескольку раз на разные коэффициенты. Это не может быть медленнее всего лишь в 2-4 раза чем простейшее копирование

Kirill Kuzminykh
nearest - это никаких вычислений. В общем случае -...

Я думаю может, потому что ядро применяется локально

А на флеймграфе не будет видно, что отнимает у libvips много времени?

Kirill-Kuzminykh Автор вопроса
Rustam
Я думаю может, потому что ядро применяется локальн...

Судя по результату - ядро в libvips с адаптивным размером. Т.е. все пиксели исходного изображения учавствуют в формировании результата. Я сам на расте делаю аналогичный ресайзер с использованием AVX2 инструкций. Даже он не выдаёт таких волшебных результатов.

Kirill-Kuzminykh Автор вопроса
Traveller Kolsky
А на флеймграфе не будет видно, что отнимает у lib...

Так дело в том что не много, а очень мало. Пожалуй проверю не научным способом - измеряю время одного запуска ресайза через libvips, вместо 100500 запусков с последующим стат.анализом

Kirill Kuzminykh
nearest - это никаких вычислений. В общем случае -...

Основные тормоза это чтение и запись данных, умножение на ядро сейчас быстрое, а при копировании ты читаешь не сильно меньше чем свёртка на ядро

Kirill-Kuzminykh Автор вопроса
Sergey Makarov
Основные тормоза это чтение и запись данных, умнож...

Ну так в том и дело, что при nearest надо прочитать и записать только часть пикселей, а при свёртке с адаптивным ядром надо прочитать все пиксели исходного изображения. Ещё и по несколько раз.

Kirill Kuzminykh
Ну так в том и дело, что при nearest надо прочитат...

Вы читаете не байт, а строку кеша, т.е. по факту все изображение

Kirill-Kuzminykh Автор вопроса
Sergey Makarov
Вы читаете не байт, а строку кеша, т.е. по факту в...

Обычно там делается в два прохода. Сначала ресайзят по горизонтали, потом по вертикали (или наоборот). Т.е. тут мало того что два раза надо читать (при этом по вертикали приходится читать не подряд, а с шагом в размер строки), так ещё и надо выполнить доп. запись первого прохода во временный буфер.

Kirill Kuzminykh
Обычно там делается в два прохода. Сначала ресайзя...

А зачем? Что мешает за один проход делать горизонтальное вертикальное

Kirill-Kuzminykh Автор вопроса
Sergey Makarov
А зачем? Что мешает за один проход делать горизонт...

Можно конечно попробовать в один проход сделать, но тогда придётся вычитывать всю матрицу пикселей, которые сворачиваются в результирующий один пиксель. И эта "матрица" расположена в исходном изображении не последовательно. После чего умножать матрицу на все коэффициенты ядра, суммировать и записывать результат. После чего вычитывать матрицу для следующего пикселя, заменить в ядре набор коэффициентов (горизонтальный или вертикальный, в зависимости от того какой следующий пиксель взяли), который тоже лежит в памяти (ок, он в кеш влезает, но всё равно надо читать в регистры). При ресайзе очень большого изображения в очень маленькое размер матрицы может получиться очень большой, и ядро тоже будет очень большое. А значит целиком всё не влезет в регистры даже от AVX2. Придётся по несколько раз передёргивать данные из памяти в регистры. Потому и делают в два прохода, т.к. требуется меньше операций загрузки данных в SIMD регистры, как минимум для коэффициентов. Т.к., например, для сжатия по горизонтали, коэффициенты не меняются для одного столбца пикселей, т.е. можно прочитать в регистры пиксели из 2-4 соседних строк изображения и умножить их 1-2 командами на уже загруженные в регистры коэффициенты. В общем видимо два прохода оптимальнее для использования SIMD. Но это не я придумал - я честно украл это из Pillow-SIMD, про которую есть статья на хабре. В данный момент только libvips опережает эту реализацию по скорости в однопоточном режиме. Но делает он это слишком волшебно, я пока не разобрался как именно - очень запутанный у него код.

Kirill-Kuzminykh Автор вопроса
Sergey Makarov
На каком соотношение разрешений он быст?

Сейчас я уменьшаю картинку условно 5000px в 250px по одной стороне. Уменьшаю примерно в 20 раз. При таком раскладе libipv в один поток выдаёт у меня такие результаты (округлил до целых мс) nearest linear cubic lancsoz3 1 2 3 4 моя либа на тех же данных выдаёт вот такое 1 20 30 60

Kirill Kuzminykh
Сейчас я уменьшаю картинку условно 5000px в 250px...

Бегло посмотрел по чату. Понял что вы используете AVX. Для быстрого сжатия картинок он слишком медленный. У меня подобная проблема была. Решил через gpu

Kirill Kuzminykh
Сейчас я уменьшаю картинку условно 5000px в 250px...

А зачем при таком сжатии изображения вообще сложные методы? Просто усреднение не пойдет?

Kirill-Kuzminykh Автор вопроса
lego
Бегло посмотрел по чату. Понял что вы используете ...

У компании нет денег на сервера с GPU 😊 Либа в первую очередь делается для ресайза картинок в веб-сервисе.

Kirill Kuzminykh
У компании нет денег на сервера с GPU 😊 Либа в пе...

Разбей массив по ядрам. В каждом ядре вроде как свои регистры avx. Может поможет

Что мешает брать просто среднее по кускам?

lego
Ну это по сути интерполяция.

При таком сжатии это вполне норм

Kirill-Kuzminykh Автор вопроса
Sergey Makarov
Что мешает брать просто среднее по кускам?

Ну да, это стрёмная недо-интерполяция. Результат у неё будет так себе, т.к. при среднем будет получаться что дальние от требуемого пиксели оказывают такой же вклад в результат, как и самые ближние.

Kirill-Kuzminykh Автор вопроса
Sergey Makarov
Что мешает брать просто среднее по кускам?

В общем такой фильтр называется box - он у меня в либе тоже есть. Вопрос то был не про то что мне лучше использовать для ресайза, а про то мочему libvips такой волшебный в бенчмарках.

Kirill Kuzminykh
В общем такой фильтр называется box - он у меня в ...

Ну при таком коэффициенте он может просто делать бокс не сильно ошибаясь

Kirill Kuzminykh
Сейчас я уменьшаю картинку условно 5000px в 250px...

А сколько ядер в процессоре на котором делался тест ?

Kirill-Kuzminykh Автор вопроса
Sergey Makarov
Ну при таком коэффициенте он может просто делать б...

Да, box при таких масштабах просто выдаёт более мыльную картинку чем cubic или lancsoz3. Мелкие детали замыливаются, а в остальном вполне прилично.

Kirill Kuzminykh
Можно конечно попробовать в один проход сделать, н...

Вы читали Дреппера? У него хитрый обход матрицы в один проход.

Kirill-Kuzminykh Автор вопроса
Kirill Kuzminykh
Да, box при таких масштабах просто выдаёт более мы...

Хм, а в libvips нет box фильтра. Не получится делать бенчмарки адекватные для сравнения с моей либой 😞

Kirill-Kuzminykh Автор вопроса

Ааа, так и знал, что libvips "волшебный". У него ленивые вычисления используются. Он не выполняет над изображением ни каких операций, пока не понадобится доступ к пикселям этого изображения. Поэтому у меня бенчмарк и показывал офигительные цифры. Я добавил "применение" опреации ресайза и всё встало на свои места и моя либа подтвердила своё лидерство в однопоточном dawnscale-е картинок. Капец - nearest в libvips выполняется прям супер медленно. А с box-ом что-то чудесатое в нём случается - медленнее чем lancsoz3 в 2 раза. Время в таблице в миллисекундах. | | Nearest | |----------|:-------:| | libvips | 21.64 | | fir avx2 | 0.86 | | | Box | Linear | |----------|:------:|:------:| | libvips | 193.67 | 51.93 | | fir avx2 | 20.23 | 21.74 | | | Cubic | Lanczos3 | |----------|:-----:|:--------:| | libvips | 78.48 | 104.58 | | fir avx2 | 28.14 | 41.13 |

Kirill-Kuzminykh Автор вопроса
Kirill Kuzminykh
Ааа, так и знал, что libvips "волшебный". У него л...

Если libvips разрешить юзать 8 потоков, то он становится шустрее, хотя nearest и box всё равно в какой-то заднице

Kirill-Kuzminykh Автор вопроса
Kirill Kuzminykh
Ааа, так и знал, что libvips "волшебный". У него л...

Ооо, а если надо ресайзить картинку с учётом альфа-канала, то libvips превращается в самую медленную кобылу (в однопоточном режиме). У него, может быть, точность вычислений будет лучше из-за того, что при умножении и делении на альфа-канал он результат сохраняет в f32 на каждую компоненту пикселя, а не в u8/u16. Но скорость из-за этого страдает катастрофически.

Похожие вопросы

Обсуждают сегодня

Господа, а что сейчас вообще с рынком труда на делфи происходит? Какова ситуация?
Rꙮman Yankꙮvsky
29
А вообще, что может смущать в самой Julia - бы сказал, что нет единого стандартного подхода по многим моментам, поэтому многое выглядит как "хаки" и произвол. Короче говоря, с...
Viktor G.
2
30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Гайс, вопрос для разносторонее развитых: читаю стрим с юарта, нада выделять с него фреймы с определенной структурой, если ли чо готовое, или долбаться с ринг буффером? нада у...
Vitaly
9
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
14
Добрый день! Скажите пожалуйста, а какие программы вы бы рекомендовали написать для того, чтобы научиться управлять памятью? Можно написать динамический массив, можно связный ...
Филипп
7
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
длина пакета фиксированная, или меняется?
Okhsunrog
7
Карта сайта