1 // Copyright (C) 2011 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_TImING_Hh_ 4 #define DLIB_TImING_Hh_ 5 6 #include <chrono> 7 #include <atomic> 8 #include <cstring> 9 #include "string.h" 10 11 #include <iostream> 12 13 // ---------------------------------------------------------------------------------------- 14 15 /*!A timing 16 17 This set of functions is useful for determining how much time is spent 18 executing blocks of code. Consider the following example: 19 20 int main() 21 { 22 using namespace dlib::timing; 23 for (int i = 0; i < 10; ++i) 24 { 25 // timing block #1 26 start(1,"block #1"); 27 dlib::sleep(500); 28 stop(1); 29 30 // timing block #2 31 start(2,"block #2"); 32 dlib::sleep(1000); 33 stop(2); 34 } 35 36 print(); 37 } 38 39 This program would output: 40 Timing report: 41 block #1: 5.0 seconds 42 block #2: 10.0 seconds 43 44 So we spent 5 seconds in block #1 and 10 seconds in block #2 45 46 47 48 Additionally, note that you can use an RAII style timing block object. For 49 example, if we wanted to find out how much time we spent in a loop a convenient 50 way to do this would be as follows: 51 52 int main() 53 { 54 using namespace dlib::timing; 55 for (int i = 0; i < 10; ++i) 56 { 57 block tb(1, "main loop"); 58 59 dlib::sleep(1500); 60 } 61 62 print(); 63 } 64 65 This program would output: 66 Timing report: 67 block main loop: 15.0 seconds 68 69 !*/ 70 71 // ---------------------------------------------------------------------------------------- 72 73 namespace dlib 74 { 75 namespace timing 76 { 77 const int TIME_SLOTS = 500; 78 const int NAME_LENGTH = 40; 79 time_buf()80 inline std::atomic<uint64_t>* time_buf() 81 { 82 static std::atomic<uint64_t> buf[TIME_SLOTS]; 83 return buf; 84 } 85 name_buf(int i,const char * name)86 inline char* name_buf(int i, const char* name) 87 { 88 static char buf[TIME_SLOTS][NAME_LENGTH] = {{0}}; 89 // if this name buffer is empty then copy name into it 90 if (buf[i][0] == '\0') 91 { 92 using namespace std; 93 strncpy(buf[i], name, NAME_LENGTH-1); 94 buf[i][NAME_LENGTH-1] = '\0'; 95 } 96 // return the name buffer 97 return buf[i]; 98 } 99 ts()100 inline uint64_t ts() 101 { 102 using namespace std::chrono; 103 return duration_cast<duration<double,std::nano>>(high_resolution_clock::now().time_since_epoch()).count(); 104 } 105 start(int i)106 inline void start(int i) 107 { 108 time_buf()[i] -= ts(); 109 } 110 start(int i,const char * name)111 inline void start(int i, const char* name) 112 { 113 time_buf()[i] -= ts(); 114 name_buf(i,name); 115 } 116 stop(int i)117 inline void stop(int i) 118 { 119 time_buf()[i] += ts(); 120 } 121 print()122 inline void print() 123 { 124 using namespace std; 125 cout << "Timing report: " << endl; 126 127 // figure out how long the longest name is going to be. 128 unsigned long max_name_length = 0; 129 for (int i = 0; i < TIME_SLOTS; ++i) 130 { 131 string name; 132 // Check if the name buffer is empty. Use the name it contains if it isn't. 133 if (name_buf(i,"")[0] != '\0') 134 name = cast_to_string(i) + ": " + name_buf(i,""); 135 else 136 name = cast_to_string(i); 137 max_name_length = std::max<unsigned long>(max_name_length, name.size()); 138 } 139 140 for (int i = 0; i < TIME_SLOTS; ++i) 141 { 142 if (time_buf()[i] != 0) 143 { 144 double time = time_buf()[i]/1000.0/1000.0; 145 string name; 146 // Check if the name buffer is empty. Use the name it contains if it isn't. 147 if (name_buf(i,"")[0] != '\0') 148 name = cast_to_string(i) + ": " + name_buf(i,""); 149 else 150 name = cast_to_string(i); 151 152 // make sure the name is always the same length. Do so by padding with spaces 153 if (name.size() < max_name_length) 154 name += string(max_name_length-name.size(),' '); 155 156 if (time < 1000) 157 cout << " " << name << ": " << time << " milliseconds" << endl; 158 else if (time < 1000*60) 159 cout << " " << name << ": " << time/1000.0 << " seconds" << endl; 160 else if (time < 1000*60*60) 161 cout << " " << name << ": " << time/1000.0/60.0 << " minutes" << endl; 162 else 163 cout << " " << name << ": " << time/1000.0/60.0/60.0 << " hours" << endl; 164 } 165 } 166 } 167 clear()168 inline void clear() 169 { 170 for (int i = 0; i < TIME_SLOTS; ++i) 171 { 172 // clear timing buffer 173 time_buf()[i] = 0; 174 // clear name buffer 175 name_buf(i,"")[0] = '\0'; 176 } 177 } 178 179 struct block 180 { 181 /*! 182 WHAT THIS OBJECT REPRESENTS 183 This is an RAII tool for calling start() and stop() 184 !*/ 185 blockblock186 block(int i):idx(i) {start(idx);} blockblock187 block(int i, const char* str):idx(i) {start(idx,str);} ~blockblock188 ~block() { stop(idx); } 189 const int idx; 190 }; 191 } 192 } 193 194 195 #endif // DLIB_TImING_Hh_ 196 197