├── LICENSE.md ├── README.md └── plf_nanotimer.h /LICENSE.md: -------------------------------------------------------------------------------- 1 | zlib License 2 | 3 | (C) 2019 mattreecebentley 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # plf::nanotimer 2 | A simple C++ 03/11/etc timer class for ~microsecond-precision cross-platform benchmarking. The implementation is as limited and simple as possible to afford the lowest amount of overhead. 3 | 4 | 5 | Use as follows: 6 | 7 | plf::nanotimer timer; 8 | 9 | 10 | timer.start() 11 | 12 | // Do something here 13 | 14 | double results = timer.get_elapsed_ns(); 15 | std::cout << "Timing: " << results << " nanoseconds." << std::endl; 16 | 17 | 18 | timer.start(); // "start" has the same semantics as "restart". 19 | 20 | // Do something else 21 | 22 | results = timer.get_elapsed_ms(); 23 | std::cout << "Timing: " << results << " milliseconds." << std::endl; 24 | 25 | 26 | timer.start() 27 | 28 | plf::microsecond_delay(15); // Delay program for 15 microseconds 29 | 30 | results = timer.get_elapsed_us(); 31 | std::cout << "Timing: " << results << " microseconds." << std::endl; 32 | 33 | 34 | 35 | Timer member functions: 36 | ======================= 37 | 38 | void start(): start or restart timer 39 | 40 | double get_elapsed_ns(): get elapsed time in nanoseconds 41 | 42 | double get_elapsed_us(): get elapsed time in microseconds 43 | 44 | double get_elapsed_ms(): get elapsed time in milliseconds 45 | 46 | 47 | 48 | Non-member functions: 49 | ===================== 50 | 51 | void plf::millisecond_delay(double x): delay the program until x milliseconds have passed 52 | 53 | void plf::microsecond_delay(double x): delay the program until x microseconds have passed 54 | 55 | void plf::nanosecond_delay(double x): delay the program until x nanoseconds have passed 56 | 57 | 58 | 59 | Timer 'pausing': 60 | ================ 61 | 62 | I determined that a 'pause'-style function would add too much complexity to the class for simple benchmarking, which in turn might interfere with performance analysis, so if you need a 'pause' function do something like this: 63 | 64 | plf::nanotimer timer; 65 | 66 | 67 | timer.start() 68 | // Do something here 69 | double results = timer.get_elapsed_ns(); 70 | 71 | // Do something else - timer 'paused' 72 | 73 | timer.start() 74 | 75 | // Do stuff 76 | 77 | results += timer.get_elapsed_ns(); 78 | 79 | std::cout << "Timing: " << results << " nanoseconds." << std::endl; 80 | -------------------------------------------------------------------------------- /plf_nanotimer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022, Matthew Bentley (mattreecebentley@gmail.com) www.plflib.org 2 | 3 | // This software is provided 'as-is', without any express or implied 4 | // warranty. In no event will the authors be held liable for any damages 5 | // arising from the use of this software. 6 | // 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 11 | // 1. The origin of this software must not be misrepresented; you must not 12 | // claim that you wrote the original software. If you use this software 13 | // in a product, an acknowledgement in the product documentation would be 14 | // appreciated but is not required. 15 | // 2. Altered source versions must be plainly marked as such, and must not be 16 | // misrepresented as being the original software. 17 | // 3. This notice may not be removed or altered from any source distribution. 18 | 19 | 20 | #ifndef PLF_NANOTIMER_H 21 | #define PLF_NANOTIMER_H 22 | 23 | 24 | // Compiler-specific defines: 25 | 26 | #define PLF_NOEXCEPT throw() // default before potential redefine 27 | 28 | #if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) 29 | #if _MSC_VER >= 1900 30 | #undef PLF_NOEXCEPT 31 | #define PLF_NOEXCEPT noexcept 32 | #endif 33 | #elif defined(__cplusplus) && __cplusplus >= 201103L // C++11 support, at least 34 | #if defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__clang__) // If compiler is GCC/G++ 35 | #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 36 | #undef PLF_NOEXCEPT 37 | #define PLF_NOEXCEPT noexcept 38 | #endif 39 | #elif defined(__clang__) 40 | #if __has_feature(cxx_noexcept) 41 | #undef PLF_NOEXCEPT 42 | #define PLF_NOEXCEPT noexcept 43 | #endif 44 | #else // Assume type traits and initializer support for other compilers and standard libraries 45 | #undef PLF_NOEXCEPT 46 | #define PLF_NOEXCEPT noexcept 47 | #endif 48 | #endif 49 | 50 | 51 | 52 | // ~Nanosecond-precision cross-platform (linux/bsd/mac/windows, C++03/C++11) simple timer class: 53 | 54 | // Mac OSX implementation: 55 | #if defined(__MACH__) 56 | #include 57 | #include 58 | 59 | namespace plf 60 | { 61 | 62 | class nanotimer 63 | { 64 | private: 65 | clock_serv_t system_clock; 66 | mach_timespec_t time1, time2; 67 | public: 68 | nanotimer() PLF_NOEXCEPT 69 | { 70 | host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &system_clock); 71 | } 72 | 73 | ~nanotimer() PLF_NOEXCEPT 74 | { 75 | mach_port_deallocate(mach_task_self(), system_clock); 76 | } 77 | 78 | void start() PLF_NOEXCEPT 79 | { 80 | clock_get_time(system_clock, &time1); 81 | } 82 | 83 | double get_elapsed_ms() PLF_NOEXCEPT 84 | { 85 | return static_cast(get_elapsed_ns()) / 1000000.0; 86 | } 87 | 88 | double get_elapsed_us() PLF_NOEXCEPT 89 | { 90 | return static_cast(get_elapsed_ns()) / 1000.0; 91 | } 92 | 93 | double get_elapsed_ns() PLF_NOEXCEPT 94 | { 95 | clock_get_time(system_clock, &time2); 96 | return ((1000000000.0 * static_cast(time2.tv_sec - time1.tv_sec)) + static_cast(time2.tv_nsec - time1.tv_nsec)); 97 | } 98 | }; 99 | 100 | 101 | 102 | 103 | // Linux/BSD implementation: 104 | #elif (defined(linux) || defined(__linux__) || defined(__linux)) || (defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) 105 | #include 106 | #include 107 | 108 | namespace plf 109 | { 110 | 111 | class nanotimer 112 | { 113 | private: 114 | struct timespec time1, time2; 115 | public: 116 | nanotimer() PLF_NOEXCEPT {} 117 | 118 | void start() PLF_NOEXCEPT 119 | { 120 | clock_gettime(CLOCK_MONOTONIC, &time1); 121 | } 122 | 123 | double get_elapsed_ms() PLF_NOEXCEPT 124 | { 125 | return get_elapsed_ns() / 1000000.0; 126 | } 127 | 128 | double get_elapsed_us() PLF_NOEXCEPT 129 | { 130 | return get_elapsed_ns() / 1000.0; 131 | } 132 | 133 | double get_elapsed_ns() PLF_NOEXCEPT 134 | { 135 | clock_gettime(CLOCK_MONOTONIC, &time2); 136 | return ((1000000000.0 * static_cast(time2.tv_sec - time1.tv_sec)) + static_cast(time2.tv_nsec - time1.tv_nsec)); 137 | } 138 | }; 139 | 140 | 141 | 142 | 143 | // Windows implementation: 144 | #elif defined(_WIN32) 145 | #if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) && !defined(NOMINMAX) 146 | #define NOMINMAX // Otherwise MS compilers act like idiots when using std::numeric_limits<>::max() and including windows.h 147 | #endif 148 | 149 | #ifndef WIN32_LEAN_AND_MEAN 150 | #define WIN32_LEAN_AND_MEAN 151 | #include 152 | #undef WIN32_LEAN_AND_MEAN 153 | #else 154 | #include 155 | #endif 156 | 157 | namespace plf 158 | { 159 | 160 | class nanotimer 161 | { 162 | private: 163 | LARGE_INTEGER ticks1, ticks2; 164 | double frequency; 165 | public: 166 | nanotimer() PLF_NOEXCEPT 167 | { 168 | LARGE_INTEGER freq; 169 | QueryPerformanceFrequency(&freq); 170 | frequency = static_cast(freq.QuadPart); 171 | } 172 | 173 | void start() PLF_NOEXCEPT 174 | { 175 | QueryPerformanceCounter(&ticks1); 176 | } 177 | 178 | double get_elapsed_ms() PLF_NOEXCEPT 179 | { 180 | QueryPerformanceCounter(&ticks2); 181 | return (static_cast(ticks2.QuadPart - ticks1.QuadPart) * 1000.0) / frequency; 182 | } 183 | 184 | double get_elapsed_us() PLF_NOEXCEPT 185 | { 186 | return get_elapsed_ms() * 1000.0; 187 | } 188 | 189 | double get_elapsed_ns() PLF_NOEXCEPT 190 | { 191 | return get_elapsed_ms() * 1000000.0; 192 | } 193 | }; 194 | #endif 195 | // Else: failure warning - your OS is not supported 196 | 197 | 198 | 199 | #if defined(__MACH__) || (defined(linux) || defined(__linux__) || defined(__linux)) || (defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)) || defined(_WIN32) 200 | inline void nanosecond_delay(const double delay_ns) PLF_NOEXCEPT 201 | { 202 | nanotimer timer; 203 | timer.start(); 204 | 205 | while(timer.get_elapsed_ns() < delay_ns) 206 | {}; 207 | } 208 | 209 | 210 | inline void microsecond_delay(const double delay_us) PLF_NOEXCEPT 211 | { 212 | nanosecond_delay(delay_us * 1000.0); 213 | } 214 | 215 | 216 | inline void millisecond_delay(const double delay_ms) PLF_NOEXCEPT 217 | { 218 | nanosecond_delay(delay_ms * 1000000.0); 219 | } 220 | 221 | 222 | } // namespace 223 | #endif 224 | 225 | #undef PLF_NOEXCEPT 226 | 227 | #endif // PLF_NANOTIMER_H 228 | --------------------------------------------------------------------------------