LCOV - code coverage report
Current view: top level - src - clock.cc (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 101 101 100.0 %
Date: 2022-06-15 20:16:21 Functions: 21 28 75.0 %
Branches: 22 30 73.3 %

           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

Generated by: LCOV version 1.16