Я решаю, что хочу протестировать конкретную функцию, поэтому наивно пишу такой код:
#include <ctime>
#include <iostream>
int SlowCalculation(int input) { ... }
int main() {
std::cout << "Benchmark running..." << std::endl;
std::clock_t start = std::clock();
int answer = SlowCalculation(42);
std::clock_t stop = std::clock();
double delta = (stop - start) * 1.0 / CLOCKS_PER_SEC;
std::cout << "Benchmark took " << delta << " seconds, and the answer was "
<< answer << '.' << std::endl;
return 0;
}
Коллега указал, что я должен объявить переменные start
и stop
как volatile
, чтобы избежать переупорядочения кода. Он предположил, что оптимизатор может, например, эффективно изменить порядок кода следующим образом:
std::clock_t start = std::clock();
std::clock_t stop = std::clock();
int answer = SlowCalculation(42);
Сначала я скептически отнесся к тому, что такая крайняя переупорядоченность разрешена, но после некоторых исследований и экспериментов я узнал, что это так.
Но volatile не казалось правильным решением; не является ли изменчивым только для ввода-вывода с отображением памяти?
Тем не менее, я добавил volatile
и обнаружил, что эталонный тест не только занимает значительно больше времени, но и крайне непостоянен от запуска к запуску. Без volatile (и если вам повезло убедиться, что код не был переупорядочен), эталонный тест постоянно занимал 600-700 мс. С volatile это часто занимало 1200 мс, а иногда и более 5000 мс. Листинги дизассемблирования для двух версий не показали практически никакой разницы, кроме разного выбора регистров. Это заставляет меня задаться вопросом, есть ли другой способ избежать переупорядочения кода, который не имеет таких подавляющих побочных эффектов.
Мой вопрос:
Каков наилучший способ предотвратить переупорядочивание кода в таком коде бенчмаркинга?
Мой вопрос похож на этот вопрос (который был об использовании volatile, чтобы избежать исключения, а не переупорядочения), этот (который не не отвечаю, как предотвратить изменение порядка), и этот (которые обсуждали, была ли проблема переупорядочением кода или устранением мертвого кода). Хотя все три посвящены именно этой теме, ни один из них не отвечает на мой вопрос.
Обновление: похоже, ответ заключается в том, что мой коллега ошибся и такое изменение порядка не соответствует стандарту. Я проголосовал за всех, кто так сказал, и присуждаю награду Максиму.
Я видел один случай (на основе кода в этот вопрос ), где Visual Studio 2010 переупорядочил вызовы часов, как я проиллюстрировал (только в 64-разрядных сборках). Я пытаюсь сделать минимальный случай, чтобы проиллюстрировать это, чтобы я мог зарегистрировать ошибку в Microsoft Connect.
Для тех, кто сказал, что volatile должен быть намного медленнее, потому что он принудительно читает и записывает в память, это не совсем согласуется с испускаемым кодом. В моем ответе на этот вопрос я показываю разборку для код с и без volatile. Внутри цикла все хранится в регистрах. Единственным существенным отличием является выбор регистра. Я недостаточно хорошо разбираюсь в ассемблере x86, чтобы понять, почему производительность энергонезависимой версии стабильно высока, а энергозависимая версия нестабильно (а иногда и значительно) медленнее.
SlowCalculation
не имеет побочных эффектов? - person Oliver Charlesworth   schedule 23.02.2013volatile
просто означает, что доступ к памяти не может быть оптимизирован, и он не может быть переупорядочен в отношении других наблюдаемых побочных эффектов вашего кода (включая другие изменчивые доступы). ЕслиSlowCalculation
не имеет побочных эффектов, то я не уверен, чтоvolatile
сделает это безопаснее. - person Oliver Charlesworth   schedule 23.02.2013volatile
. - person Kerrek SB   schedule 23.02.2013volatile
обрабатываются как операции ввода-вывода ЦП и никогда не исключаются, не переупорядочиваются и не предполагаются. - person Maxim Egorushkin   schedule 25.02.2013asm volatile ("":::"memory");
? - person jmetcalfe   schedule 25.02.2013volatile
связано с тем, что ЦП вынужден фактически читать память, когда что-то помечено какvolatile
, и то, что вы наблюдаете, не имеет ничего общего с переупорядочением. - person Jack Aidley   schedule 25.02.2013