Даже после исправления опечатки uint16_t
вместо uint64_t
, которая делает ваш l oop бесконечным, фактическая работа все равно будет оптимизирована, потому что результат ничем не используется.
Вы можете использовать Google Benchmark's DoNotOptimize, чтобы предотвратить оптимизацию неиспользованного результата ans
. например, такие функции, как «Escape» и «Clobber», которые в этом Q&A спрашивают о . Это работает в G CC, и этот вопрос связан с релевантным видео на YouTube из выступления разработчика clang CppCon.
Другой худший способ - присвоить результат переменной volatile
. Но имейте в виду, что исключение общих подвыражений может по-прежнему оптимизировать более ранние части вычисления, независимо от того, используете ли вы volatile
или встроенный asm-макрос, чтобы убедиться, что компилятор где-то материализует фактический конечный результат. Микробенчмаркинг - это сложно. Вам нужен компилятор, чтобы выполнять точно такой же объем работы, который мог бы произойти в реальном сценарии использования, но не больше.
См. Идиоматия c способ оценки производительности? за это и многое другое.
Помните, что именно вы здесь измеряете.
Вероятно, куча l oop накладные расходы и, возможно, переадресация хранилища в зависимости от того, векторизует компилятор эти инициализаторы или нет , но даже если это так; преобразование целого числа в FP и добавление 2x SIMD FP сопоставимы по стоимости dpps
с точки зрения стоимости пропускной способности. (Это то, что вы измеряете, а не задержку; разница имеет большое значение для ЦП с выполнением вне очереди, в зависимости от контекста вашего реального варианта использования).
Производительность не равна 1 -размерный в масштабе пары инструкций. Привязка повторения l oop к некоторой работе может измерять пропускную способность или задержку, в зависимости от того, делаете ли вы ввод зависимым от предыдущего вывода (цепочка зависимостей al oop). Но если ваша работа ограничивается пропускной способностью внешнего интерфейса, то важной частью являются накладные расходы l oop. Кроме того, вы можете столкнуться с эффектами из-за того, что машинный код вашего l oop совпадает с 32-байтовыми границами для кэша uop.
Для чего-то такого короткого и простого анализа stati c является обычно хорошо. Подсчитайте количество мопов для внешнего интерфейса и порты в серверной части и проанализируйте задержку. Какие соображения go при прогнозировании задержки для операций на современных суперскалярных процессорах и как я могу рассчитать их вручную? . LLVM-MCA может сделать это за вас, так же как и IACA. Вы также можете выполнять измерения как часть своего реального l oop, в котором используются скалярные произведения.
См. Также RDTSCP в NASM всегда возвращает одно и то же значение для обсуждения того, что вы можете измерить в одна инструкция.
Мне нужно выполнить инструкции триллионы раз, чтобы это заняло больше, чем крошечную долю секунды
Текущие процессоры x86 могут l oop в лучшем случае одна итерация за такт для крошечного l oop. Невозможно написать al oop, который работает быстрее этого. 4 миллиарда итераций (в asm) займут как минимум целую секунду на процессоре с тактовой частотой 4 ГГц.
Конечно, оптимизирующий C компилятор может развернуть ваш l oop и выполнять столько итераций исходного кода, сколько он хочет за прыжок в асм.