Branch data Line data Source code
1 : : #ifdef RUN_TESTS 2 : : # include <gtest/gtest.h> 3 : : #endif 4 : : /**@file clock.cc 5 : : * @brief Time handling interface 6 : : */ 7 : : 8 : : #include <chrono> 9 : : #include <mutex> 10 : : #include <condition_variable> 11 : : #include <thread> 12 : : 13 : : /** Gets real starting time of the program, effective when this function is first called. */ 14 : 16 : static auto& GetRealStartTime() 15 : : { 16 [ + + + - ]: 16 : static auto start = std::chrono::system_clock::now(); 17 : 16 : return start; 18 : : } 19 : : 20 : : /** Gets real elapsed time, without any scaling. */ 21 : 16 : static double GetRealElapsed() 22 : : { 23 : 16 : auto start = GetRealStartTime(); 24 : 16 : auto now = std::chrono::system_clock::now(); 25 : 16 : std::chrono::duration<double> dur = (now - start); 26 : 16 : return dur.count(); 27 : : } 28 : : 29 : : /** Current settings of this module. */ 30 : : static struct 31 : : { 32 : : double TimeFactor = 1.0; 33 : : double FakeTime = 0.0; 34 : : std::mutex lk; 35 : : std::condition_variable updated; 36 : : double Waiting = 0; 37 : : bool Terminated = false; 38 : : } data; 39 : : 40 : : /** Last time read in this thread. */ 41 : : static thread_local double LastTime = 0.0; 42 : : 43 : 336764 : double GetTime() 44 : : { 45 [ + + ]: 336764 : if(data.TimeFactor != 0.0) 46 : : { 47 : 14 : return GetRealElapsed() * data.TimeFactor; 48 : : } 49 : 336750 : return data.FakeTime; 50 : : } 51 : : 52 : 3683 : void AdvanceTime(double seconds) 53 : : { 54 : 3683 : data.FakeTime += seconds; 55 [ + + ]: 3683 : if(data.TimeFactor == 0.0) 56 : : { 57 [ + + + - ]: 3681 : if(data.Waiting != 0 && data.Waiting <= data.FakeTime) 58 : : { 59 : 1 : {std::unique_lock<std::mutex> lock(data.lk);} 60 : 1 : data.updated.notify_all(); 61 : : } 62 : 3681 : LastTime = data.FakeTime; 63 : : } 64 : 3683 : } 65 : : 66 : 8590 : void SleepFor(double seconds) 67 : : { 68 [ + + ]: 8590 : if(data.TimeFactor != 0.0) 69 : : { 70 : 1 : std::this_thread::sleep_for(std::chrono::duration<double>(seconds / data.TimeFactor)); 71 : : } 72 : : else 73 : : { 74 : 8589 : double until = LastTime+seconds; 75 [ + + ]: 8589 : if(data.FakeTime < until) 76 : : { 77 : 1 : std::unique_lock<std::mutex> lock(data.lk); 78 : 1 : data.Waiting = until; 79 [ + - ]: 1 : if(data.FakeTime < until) 80 : : { 81 [ + + + - ]: 3 : data.updated.wait(lock, [&]{ return data.FakeTime >= until || data.Terminated; }); 82 : : } 83 [ + - ]: 1 : data.Waiting = 0; 84 : 1 : } 85 : 8589 : LastTime = until; 86 : : } 87 : 8590 : } 88 : : 89 : 8 : void SetTimeFactor(double factor) 90 : : { 91 : 8 : data.TimeFactor = factor; 92 : 8 : } 93 : : 94 : 1 : void TimeTerminate() 95 : : { 96 : 1 : data.Terminated = true; 97 : 1 : {std::unique_lock<std::mutex> lock(data.lk);} 98 : 1 : data.updated.notify_all(); 99 : 1 : } 100 : : 101 : : #ifdef RUN_TESTS 102 : 3 : TEST(clock, elapsed_time_looks_realistic) 103 : : { 104 : 1 : auto a = GetRealElapsed(); 105 : 1 : usleep(100000); 106 : 1 : auto b = GetRealElapsed(); 107 : 1 : auto diff = b-a; 108 : 1 : EXPECT_TRUE(diff >= 0.098 && diff <= 0.12); 109 : 1 : } 110 : : 111 : 3 : TEST(clock, regular_time_works) 112 : : { 113 : 1 : data.TimeFactor = 1; 114 : : 115 : 1 : auto a = GetTime(); 116 : 1 : usleep(100000); 117 : 1 : AdvanceTime(100); 118 : 1 : auto b = GetTime(); 119 : 1 : auto diff = b-a; 120 : 1 : EXPECT_TRUE(diff >= 0.098 && diff <= 0.12); 121 : 1 : } 122 : : 123 : 3 : TEST(clock, double_time_works) 124 : : { 125 : 1 : data.TimeFactor = 2; 126 : : 127 : 1 : auto a = GetTime(); 128 : 1 : usleep(100000); 129 : 1 : AdvanceTime(100); 130 : 1 : auto b = GetTime(); 131 : 1 : auto diff = b-a; 132 : 1 : EXPECT_TRUE(diff >= 2*0.098 && diff <= 2*0.12); 133 : 1 : } 134 : : 135 : 3 : TEST(clock, sleep_works) 136 : : { 137 : 1 : data.TimeFactor = 1; 138 : : 139 : 1 : auto a = GetTime(); 140 : 1 : SleepFor(0.2); 141 : 1 : auto b = GetTime(); 142 : 1 : auto diff = b-a; 143 : 1 : EXPECT_TRUE(diff >= 0.194 && diff <= 0.208); 144 : 1 : } 145 : : 146 : 3 : TEST(clock, manual_time_works) 147 : : { 148 : 1 : data.TimeFactor = 0; 149 : : 150 : 1 : auto a = GetTime(); 151 : 1 : AdvanceTime(100); 152 : 1 : auto b = GetTime(); 153 : 1 : auto diff = b-a; 154 : 1 : EXPECT_TRUE(diff == 100); 155 : 1 : } 156 : : 157 : 3 : TEST(clock, manual_and_sleep) 158 : : { 159 : 1 : data.FakeTime = 0; 160 : 1 : data.TimeFactor = 0; 161 : 1 : volatile bool step = false; 162 : 2 : std::thread test{[&] 163 : : { 164 : 1 : SleepFor(100); 165 : 1 : step = true; 166 : 1 : }}; 167 [ + - ]: 1 : AdvanceTime(50); 168 : 1 : usleep(100000); 169 : 1 : EXPECT_FALSE(step); 170 [ + - ]: 1 : AdvanceTime(52); 171 [ + - ]: 1 : test.join(); 172 : 1 : EXPECT_TRUE(step); 173 : 1 : } 174 : : 175 : 3 : TEST(clock, terminate) 176 : : { 177 : 1 : TimeTerminate(); 178 : 1 : data.Terminated = false; 179 : 1 : } 180 : : #endif