Довелось недавно столкнуться с задачей проверки корректности UTF-8 представления. И в рамках этой задачи вышел вот на это замечательное описание с примерами двух реализаций: Flexible and Economical UTF-8 Decoder.
Очень мне понравились оба тамошних решения (для простоты буду называть их "решение от 2009-го" и "решение от 2010-го" годов, по датам в копирайтах). Просто и лаконично. Да еще и гибко, можно затачивать хоть под проверку, хоть про декодирование с восстановлением после ошибок.
Поскольку у нас в RESTinio есть что-то аналогичное, но гораздо более объемное по числу строк, то подумалось, что можно было бы заменить наш многострочный utf8_checker на более компактный.
Но прежде чем сделать это попробовал провести простейшие сравнения производительности. И вот тут-то меня ждал сюрприз...
На основном рабочем Windows-ноутбуке с i7-8550U и VisualStudio 2022 (17.10.3) примитивный бенчмарк показывает следующие результаты:
*** restinio: 1240136us ***
*** decode_2009: 1784796us ***
*** decode_2010: 1774765us ***
Компиляция выполнялась так: cl -EHsc -O2 -DNDEBUG -utf-8 -std:c++20
На этом же Windows-ноутбуке под GCC-13.2.0 (из MinGW-w64) получаются следующие числа:
*** restinio: 435519us ***
*** decode_2009: 977052us ***
*** decode_2010: 566962us ***
Компиляция выполнялась так: g++ -O2 -std=c++20
На резервном Linux-ноутбуке с i7-6600U и GCC-13.1 этот же бенчмарк дает следующие числа:
*** restinio: 915891us ***
*** decode_2009: 873742us ***
*** decode_2010: 809853us ***
Но еще интереснее оказывается с GCC-11 на том же Linux-ноутбуке:
*** restinio: 941621us ***
*** decode_2009: 1857220us ***
*** decode_2010: 2047872us ***
Т.е., похоже, в GCC-13 оптимизатор серьезно прокачали, отсюда и гораздо лучшие результаты для решений от 2009-го и 2010-го годов под GCC-13.
Но намного больше пищи для размышлений дал clang-18:
*** restinio: 2108439us ***
*** decode_2009: 1775339us ***
*** decode_2010: 2012727us ***
Т.е. оптимизатор в clang-е с решениями 2009-го и 2010-го годов справился на уровне GCC-11, но вот наш код из RESTinio он настолько же сильно, как GCC-13, оптимизировать не смог.
Ну и для полноты картины результаты clang-16 с того же Linux-ноутбука:
*** restinio: 2379565us ***
*** decode_2009: 3222073us ***
*** decode_2010: 1839321us ***
Сразу скажу, что не являюсь специалистом по низкоуровневым оптимизации (да и не любитель я этого занятия). Так что разбираться с тем, что и как оптимизируется, можно ли что-то еще ускорить или нет, не стал.
Меня удивило другое: насколько разные результаты можно получить на одной и той же платформе с разными версиями одного и того же компилятора (не говоря уже о разных компиляторах).
Если взять специфику наших открытых библиотек, которые распространяются в исходниках, а затем компилируются на неизвестно каких платформах неизвестно какими компиляторами, то насколько уместно заниматься низкоуровневыми оптимизациями? Типа отшлифуешь все до последней микросекунды на Windows с VC++, а на Linux-е и 11-ом GCC, напротив, получишь просадку производительности.
PS. Я понимаю, что это негодный бенчмарк. Всего один набор тестовых данных. Весь код в одном файле, что не есть хорошо, если разнести функции по разным .cpp-файлам результаты могут отличаться, например, когда каждая функция декодирования помещается в отдельный C++ файл, то результы с GCC-13 под Linux-ом на i7-6600U меняются в пользу реализации от RESTinio:
*** restinio: 612732us ***
*** decode_2010: 820765us ***
*** decode_2009: 855889us ***
Но для осознания глубины кроличьей норы, имхо, сойдет даже такое примитивное сравнение 🙂
5 комментариев:
В моей практике были случаи, когда оптимизацию приходилось отключать, потому что с оптимизацией программа могла падать. Или, вот например, "загадка дыры" - std::replace не делал замену символов в одном случае из двадцати.
> В моей практике были случаи, когда оптимизацию приходилось отключать, потому что с оптимизацией программа могла падать.
Если исключить баги компилятора, то это запросто могло быть проявление UB в программе.
Я, кстати, всегда предпочитаю работать сразу в release режиме, с оптимизацией, без колупания в debug-mode. Гораздо меньше сюрпризов потом.
Смутило отсутствие флагов векторизации. Возможно, какойто компилятор их автоматом приписывает, если не указано.
@sv
Там вроде как ключик -O2 всей этой магией должен заведовать.
Мне кажется, что нет, хотя могу ошибаться. Лучше всеже попробовать явно передать
Отправить комментарий