std::chrono неоднократно вызывает QueryPerformanceFrequency?

Всякий раз, когда я звоню:

std::chrono::high_resolution_clock::now().time_since_epoch().count();

Инструкция по сборке для него такая:

std::chrono::high_resolution_clock::now().time_since_epoch().count();
00007FF7D9E11840  call        qword ptr [__imp__Query_perf_frequency (07FF7D9E14090h)]  
00007FF7D9E11846  call        qword ptr [__imp__Query_perf_counter (07FF7D9E140A0h)] 

Раньше я использовал часы Windows API и думал, что правильный способ - один раз запросить частоту.

В документации Microsoft говорится:

QueryPerformanceFrequency Получает частоту счетчика производительности. Частота счетчика производительности фиксируется при загрузке системы и одинакова для всех процессоров. Поэтому частоту нужно запрашивать только при инициализации приложения, а результат можно кэшировать.

Это было в цикле, поэтому я думаю, что вызов QueryPerformanceFrequency выполняется неоднократно. Это строилось в режиме Release и с оптимизацией /O2.

Кроме того, если я создам в режиме отладки, он сделает следующую сборку:

std::chrono::high_resolution_clock::now().time_since_epoch().count();
00007FF774FC9D19  lea         rcx,[rbp+398h]  
00007FF774FC9D20  call        std::chrono::steady_clock::now (07FF774FB1226h)  
00007FF774FC9D25  lea         rdx,[rbp+3B8h]  
00007FF774FC9D2C  mov         rcx,rax  
00007FF774FC9D2F  call        std::chrono::time_point<std::chrono::steady_clock,std::chrono::duration<__int64,std::ratio<1,1000000000> > >::time_since_epoch (07FF774FB143Dh)  
00007FF774FC9D34  mov         rcx,rax  
00007FF774FC9D37  call        std::chrono::duration<__int64,std::ratio<1,1000000000> >::count (07FF774FB1361h) 

Я не разбираюсь в ассемблере и не знаю, почему в режиме Release есть вызовы Windows API, а в режиме Debug об этом не упоминается. Кроме того, я на Visual Studio.

Спасибо.


person Zebrafish    schedule 27.12.2016    source источник
comment
Но звонок на QueryPerformanceFrequency всего один, где второй?   -  person Rakete1111    schedule 27.12.2016
comment
Это больше похоже на проблему, специфичную для компилятора, чем на стандартную проблему С++. Я предлагаю вам отредактировать свои флаги и, возможно, указать, какой компилятор и версию вы используете (Visual Studio IDE может использовать разные компиляторы). Кроме того, поскольку я предполагаю, что библиотека C++, предоставляемая Visual C++, производится Microsoft, они могут знать передовые методы использования QueryPerformanceFrequency().   -  person roalz    schedule 27.12.2016
comment
@Rakete Это в цикле, я понимаю, что он вызывает его каждый раз в цикле.   -  person Zebrafish    schedule 27.12.2016
comment
@TitoneMaurice О, теперь я понял :) Спасибо.   -  person Rakete1111    schedule 27.12.2016
comment
Вы говорите: а я думал, что правильный способ - запросить частоту один раз, это не совсем то, что указано на странице MSDN для QueryPerformanceFrequency: частоту нужно запрашивать только при инициализации приложения, а результат можно кэшировать. МОЖЕТ быть кэшировано, не означает, что это ДОЛЖНО быть. В любом случае, я могу согласиться с вами, что это может быть неоптимальная реализация, вы можете сообщить об этом команде Microsoft Visual C++: msdn.microsoft.com/it-it/library/mt748084.aspx   -  person roalz    schedule 27.12.2016


Ответы (1)


Оптимизатор VS, похоже, не выводит вызов QueryPerformanceFrequency за пределы цикла. Он не распознает, что вывод всегда одинаков на каждой итерации после первой, и поэтому не может его оптимизировать, что сделал бы любой здравомыслящий оптимизатор :)

Я думаю, скорее, это отсутствующая функция или что-то в этом роде, а не ошибка, так как я бы сказал, что VS оптимизирует вызов foo здесь вне цикла (в данный момент у меня нет доступа к VS, поэтому я не могу проверить):

int value = 0;
void foo() { value = 2; }

for (int i = 0; i < 10; ++i) {
    foo();
    std::cout << i * value << '\n';
}

Причина, по которой нет вызова функций QueryPerformance*, заключается в том, что в Debug оптимизатору не разрешено оптимизировать. Оптимизатор видит, что вызов собственного API Windows выполняется быстрее, чем вызов реализации стандартной библиотеки, и поэтому заменяет соответствующие вызовы.

person Rakete1111    schedule 27.12.2016