gpt4 book ai didi

c++ - C++稳定时钟返回0时间过去了,有时候吗?

转载 作者:行者123 更新时间:2023-12-02 10:12:30 24 4
gpt4 key购买 nike

我正在尝试使用稳定的时钟来对我的代码部分进行基准测试,在这里我做了一些努力。似乎有时返回2次之间的差,有时仅返回0。
我有以下代码。这不是我的编中的真实代码,但可以说明问题

typedef std::chrono::steady_clock::time_point clock_point;

for ( int i = 0; i < 2; i++ ) {

clock_point start_overall = std::chrono::steady_clock::now();

for ( int j = 0; j < 10000000; j++ ) {
int q = 4;
}

clock_point end_phase_1 = std::chrono::steady_clock::now();

std::cout << "DIFF=" << std::chrono::duration_cast<std::chrono::microseconds>( end_phase_1 - start_overall ).count() << "\n";

}
这使我从运行prog 4次获得以下输出:
DIFF=15622
DIFF=0

DIFF=12968
DIFF=13001

DIFF=12966
DIFF=13997

DIFF=0
DIFF=0
非常令人沮丧!我需要一些一致的时间。而且,与循环10,000,000次所需的时间完全无关紧要。在我的实际程序中,循环中发生了更多事情,并且需要花费更长的时间,但是有时我仍然会因时差而得到0 vals。
这是怎么回事?如何解决此问题,以便获得可靠的时差?谢谢
编辑:好的,因为我得到的解释是编译器正在简化循环,因为其中实际上没有发生任何事情,因此,我将向您展示在2个时钟点之间运行的实际循环中的实际代码
    // need to reset some variables with each situation
// these are global vars so can access throughout (ewww)
this_sit_phase_1_complete = dataVars.phase_1_complete;
this_sit_on_the_play = dataVars.on_the_play;
this_sit_start_drawing_cards = dataVars.start_drawing_cards;
this_sit_current_turn = dataVars.current_turn;
this_sit_max_turn = dataVars.max_turn;


// note: do i want a separate split count for each scenario?
// mmm yeah.. THIS IS WHAT I SHOULD DO INSTEAD OF GLOBAL VARS....
dataVars.scen_active_index = i;


// point to the split count we want to use
// dataVars.use_scen_split_count = &dataVars.scen_phase_1and2_split_counts[i];
dataVars.split_count[i] += 1;


// PHASE 1:
// if we're on the play, we execute first turn without drawing a card
// just a single split to start in a single que
// phase 1 won't be complete until we draw a card tho
// create the all_splits_phase_1 for each situation
all_splits_que all_splits_phase_1;


// SPLIT STRUCT
// create the first split in the scenario
split_struct first_split_struct;
// set vars to track splits
first_split_struct.split_id = dataVars.split_count[i];
// first_split_struct.split_trail = std::to_string(dataVars.split_count[i]);
// set remaining vars
first_split_struct.cards_in_hand_numbs = dataVars.scen_hand_card_numbs[i];
first_split_struct.cards_in_deck_numbs = dataVars.scen_initial_decks[i];
first_split_struct.cards_bf_numbs = dataVars.scen_bf_card_numbs[i];
first_split_struct.played_a_land = false;



// store the split struct as the initial split
all_splits_phase_1 = { first_split_struct };


// if we're on the play, execute first turn without
// drawing any cards
if ( this_sit_on_the_play ) {

// execute the turn on the play before drawing anything
execute_turn(all_splits_phase_1);

// move to next turn
this_sit_current_turn += 1;
}


// ok so now, regardless of if we were on the play or not, we have to draw
// a card for every remaining card in each split, and then execute a turn
// once these splits are done, we can convert over to phase 2
do_draw_every_card( all_splits_phase_1 );


// execute another turn after drawing one of everything,
// we wont actually draw anything within the turn
execute_turn( all_splits_phase_1 );


// next turn
this_sit_current_turn += 1;


clock_point end_phase_1 = std::chrono::steady_clock::now();
benchmarker[dataVars.scen_active_index].phase_1_t = std::chrono::duration_cast<std::chrono::microseconds>( end_phase_1 - start_overall ).count();
这里有很多很多东西发生,编译器永远不会简化这个块。但是正如我所解释的,我得到0。

最佳答案

操作码外:

    for ( int j = 0; j < 10000000; j++ ) {
int q = 4;
}
这是对未在任何地方使用的局部变量的重复分配。
我强烈认为编译器足够聪明,可以识别出循环没有副作用。因此,它不会为循环发出任何代码-进行适当的(合法的)优化。
为了检查这一点,我完成了以下MCVE的OPs代码片段:
#include <chrono>
#include <iostream>

typedef std::chrono::steady_clock::time_point clock_point;

int main()
{
for ( int i = 0; i < 2; i++ ) {

clock_point start_overall = std::chrono::steady_clock::now();

for ( int j = 0; j < 10000000; j++ ) {
int q = 4;
}

clock_point end_phase_1 = std::chrono::steady_clock::now();

std::cout << "DIFF=" << std::chrono::duration_cast<std::chrono::microseconds>( end_phase_1 - start_overall ).count() << "\n";

}
}
并在CompilerExplorer上使用 -O2 -Wall -std=c++17进行编译:
snapshot of godbolt.org
Live Demo on CompilerExplorer
请注意,循环的行未着色。
原因是(按照我的假设): 没有为for -loop发出代码。
因此,OP会测量 std::chrono::steady_clock::now();的两个连续调用,这些调用可能会(或可能不会)出现在一个子时钟周期内。因此,检查这些调用之间是否没有经过任何时间。

为了防止此类优化,代码必须包含一些会导致编译器在编译期间无法预见的副作用的内容。输入/输出操作是一个选项。因此,循环可以包含来自由输入确定的变量的赋值,并将结果赋给为输出确定的容器。
将变量标记为 volatile也是一种选择,因为即使在无法“看到”副作用的情况下,它都会强制编译器分配变量。

关于c++ - C++稳定时钟返回0时间过去了,有时候吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62989913/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com