Как не оптимизировать прочь - механика глупости
Я искал технику программирования, которая позволила бы компилятору не оптимизировать переменные, используемые для бенчмаркинга (без видимых побочных эффектов)
Это дает некоторую информацию, но в итоге я использовал глупость и следующую функцию
/**
* Call doNotOptimizeAway(var) against variables that you use for
* benchmarking but otherwise are useless. The compiler tends to do a
* good job at eliminating unused variables, and this function fools
* it into thinking var is in fact needed.
*/
#ifdef _MSC_VER
#pragma optimize("", off)
template <class T>
void doNotOptimizeAway(T&& datum) {
datum = datum;
}
#pragma optimize("", on)
#else
template <class T>
void doNotOptimizeAway(T&& datum) {
asm volatile("" : "+r" (datum));
}
#endif
Я хочу использовать вышеизложенное, но у меня мало понимания его работы. Меня больше всего интересует не VC++ часть и почему / как строка
asm volatile("" : "+r" (datum));
создает неоптимизируемый контекст или почему это то, что можно выбрать для реализации такой вещи. Также было бы интересно сравнить два метода (не знаю как pragma optimize
работает, но выглядит как более чистое решение - хотя и не переносимое)
1 ответ
Не существует стандартного способа отключения оптимизаций, поэтому, если вам нужно отключить оптимизацию, вы ограничены тем, что может обеспечить ваша реализация. Нет смысла сравнивать два подхода, если вы не найдете компилятор, который поддерживает их оба.
Во всяком случае, в GCC,
asm volatile("" : "+r" (datum));
означает, что непроверенный код сборки, предоставленный пользователем, встроен в сборку, созданную GCC. Первый строковый литерал (""
) содержит код сборки для внедрения. Он пустой, так что на самом деле нет никакого кода, который будет генерироваться вообще.
Часть после :
информирует GCC о влиянии ассемблерного кода. "+r" (datum)
означает, что GCC должен предполагать, что код сборки читает и изменяет datum
, Хотя это не так. Причина в том, что любые более ранние вычисления, которые в конечном итоге сохраняют значение в datum
не может быть отброшен как ненужный. В то же время сам код сборки не может быть отброшен как ненужный из-за возможного изменения datum
, volatile
также помечает ассемблерный код как код, который нельзя оптимизировать, как описано здесь:
Оптимизаторы GCC иногда отбрасывают
asm
заявления, если они определяют, что нет необходимости в выходных переменных. Кроме того, оптимизаторы могут перемещать код из циклов, если они считают, что код всегда будет возвращать один и тот же результат (т.е. ни одно из его входных значений не изменяется между вызовами). С использованиемvolatile
квалификатор отключает эти оптимизации. [...]
На самом деле, кажется немного правдоподобным использование двух разных подходов для предотвращения удаления кода сборки, но я думаю, что лучше быть уверенным.
r
ограничение означает, что коду все равно, какой регистр GCC делает доступным для использования кодом сборки, и задокументирован здесь:
'р'
Операнд регистра допускается при условии, что он находится в общем регистре.
+
Модификатор означает, что код может читать и записывать в datum
и задокументировано здесь:
'+'
Означает, что этот операнд читается и записывается инструкцией. [...]