Как стать автором
Обновить

Комментарии 10

А можно раскрыть немного некоторый другой совет номер 1?
Предполагаем, что в данной рекомендации автор предлагает использовать < вместо <= в качестве низкоуровневой оптимизации, которая экономит одну процессорную инструкцию в некоторых менее распространённых или устаревших архитектурах. Существуют и противоположные точки зрения: например, для определённых версий компилятора Microsoft Visual C++ >= лучше чем > и <=, то есть итерироваться надо в обратном порядке и декрементить переменную цикла.

Если же мы посмотрим на ассемблерный код, выдаваемый современным компилятором С++ под платформу x86_64 (GCC 11.2), то окажется, что для обоих вариантов функции, выполняющих итерацию по массиву, выдаётся практически идентичный набор инструкций. Отличие лишь в инструкциях jl и jle:

1) godbolt.org/z/MKMM57EK6

2) godbolt.org/z/Kacd7xeEW

Вопрос в том, выполняются ли jl и jle за одно и то же время. Быстрый ответ — да. Но точный ответ весьма затруднён из-за огромного разнообразия процессорных архитектур и оптимизаций, применяемых в современных процессорах: конвейеризация и суперскалярность позволяет нескольким инструкциям процессора выполняться параллельно, а внеочередное исполнение может менять порядок исполнения инструкций. Поэтому для анализа производительности инструкций в основном применяются статистические подходы.

Но всё же есть специальные таблицы, позволяющие определить количество микроопераций, выполняемых процессором при проведении макроопераций, таких как jl и jle. Согласно этому документу на большинстве архитектур conditional jump в любом варианте «стоит» ровно одну микрооперацию — то есть между jl и jle разницы нет.

Что же касается сравнения операторов < и !=, то первый считается чуть более безопасным, точнее, располагающим к написанию более безопасного кода.

Картинки красивые, но статья, на мой взгляд, так себе.

  • Очень поверхностно пробежались по теме, вида "скопипасть вот это в код чтобы программа работала быстрее". Причём в 99% случаев это не поможет.

  • Не раскрыта тема авто-векторизации, почему компилятор может или не может её применять (в том числе не рассказано про диагностику таких случаев).

  • Не раскрыта тема SIMD инструкций, их семейства, доступность, что именно они могут делать, и.т.п. Словно бы это просто некий "волшебный ускоритель"

  • Нет вывода дизассемблера. Скопипастили в код, тык-мык, минус сколько-то миллисекунд, продолжаем пить смузи. Прямо stackoverflow programming.

  • Помимо захардкоживания intrinsics или танцами с бубном над компилятором есть кросс-платформенные библиотеки, где весь векторизованный код уже может быть написан.

Это уровень доклада на школьной (даже не студенческой) конференции, несерьёзно.

Спасибо за ваш отзыв. Данная статья действительно является в некотором смысле базовой – она позволяет тем программистам, кто ранее не сталкивался с векторными оптимизациями, в целом ознакомиться с этой темой. При необходимости всегда можно углубиться в отдельные моменты – с помощью более сложных и подробных материалов, предлагающих другие практические примеры.

Действительно как-то очень простенько.
Фактически всё ограничивается знакомством с некими магическими заклинаниями для ускорения кода, "но всемогущий маг лишь на бумаге я" - 18% это очень мало для успешной векторизации.
Я попытался восстановить полный код примера, правда на x86, c ARM/Neon я не знаком:
https://gcc.godbolt.org/z/99Yfd7Y9E
Видно, что векторизует, но масса вот этих vpinsrb, выдёргиваний по 1 байтику - это явно неэффективно.
Буферы U,V имеют в 2 раза меньшее разрешение - логично считать за одну итерацию квадрат 2*2 пикселя, чтобы не читать одни те же значения U,V по 4 раза:
https://gcc.godbolt.org/z/T68hdvTcs
Вроде бы стало лучше, во всяком случае махинаций с байтиками сходу не вижу. Но надо тестировать.
Также я заменил прагму assume_safety на модификатор __restrict для параметров, действует аналогично, но совместимо с gcc.

Ещё следует подумать, можно ли избавиться от плавающей точки с сохранением приемлемой точности, это уберёт лишние команды конверсии и может улучшить векторизацию (если обойтись int16, то их больше влезет в вектор, чем float32).

В общем, надо дописывать свою статью про высокоуровневую векторизацию (у меня на другом примере, но не суть).

С тестом:
https://gcc.godbolt.org/z/9n53e9588
Квадрат 2*2 оказался медленнее, видимо непоследовательная запись в память всё портила, поэтому переделал на 2 соседних пикселя по горизонтали, теперь в 2 раза быстрее. А простое дописывание vectorize(assume_safety) к циклу почти ничего не даёт (от 0 до 15%, но чаще 0).
Также в варианте с 2*2 я ошибся и не использовал y_pixel_stride, uv_row_stride, uv_pixel_stride - из-за этого и пропали vpinsrb. Все эти параметры дают гибкость, но с ними приходится брать по байтику, компилятор не может быть уверен, что данные лежат последовательно. Впрочем, по факту простыня vpinsrb не делает хуже, ускоряют именно 2 пикселя за итерацию.
Хотя 2 раза - тоже далеко не предел мечтаний, но больше не хочется тратить на это времени.

Полезная информация. Утащил в закладки.

Супер идея , вкрутите в "Редактор МойОфис Текст" рамочки по ГОСТ, и чтобы они работали не через неадекватные колонтитулы которые все ненавидят, и люди к вам потянутся, и студенты. и производственники с нашим всеми любимым ЕСКД.

Спасибо, что написали нам. Передали ваш запрос на добавление рамок ГОСТ ЕСКД в службу развития продукта. Постараемся учесть его при планировании обновлений.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий