Created
June 29, 2014 12:41
-
-
Save jhorneman/d500c39465021db1e8df to your computer and use it in GitHub Desktop.
Adaption of Edouard Alligand's portable high-resolution timestamp in C++ for OS X
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// main.cpp | |
// timestamp_test | |
// Created by Jurie Horneman on 29/06/14. | |
#include <assert.h> | |
#include <iostream> | |
// Adapted from "A portable high-resolution timestamp in C++" by Edouard Alligand | |
// https://blogea.bureau14.fr/index.php/2014/06/a-portable-high-resolution-timestamp-in-c/ | |
// "consider the code to be bsd licensed." | |
// https://twitter.com/edouarda14/status/483221452561600513 | |
#ifdef __APPLE__ | |
#include <mach/mach_time.h> | |
#endif | |
template <typename T> | |
class HiResClock | |
{ | |
public: | |
HiResClock(void) : _zero_time(T::zero_time()), | |
_offset(T::timestamp()), | |
_frequency(T::update_frequency()) | |
{ | |
assert(_offset > 0u); | |
assert(_frequency > 0u); | |
assert(_zero_time > 0u); | |
} | |
// A function that returns the number of 10/th microseconds (or 100-nanoseconds intervals if you will) | |
// since epoch (UTC). This function will be sub-microsecond-precise which is enough to prevent collisions. | |
// We could try to reach higher precisions, but this would come at the cost of precious bits in our | |
// 64-bit timestamps. With 100-nanoseconds interval, we can represent time for ten thousands of years. | |
std::uint64_t now(void) const | |
{ | |
assert(_offset > 0u); | |
assert(_frequency > 0u); | |
const std::uint64_t delta = T::timestamp() - _offset; | |
// because the frequency is in update per seconds, we have to multiply the delta by 10,000,000 | |
const std::uint64_t delta_in_us = delta * 10000000u / _frequency; | |
return delta_in_us + _zero_time; | |
} | |
private: | |
std::uint64_t _zero_time; | |
std::uint64_t _offset; | |
std::uint64_t _frequency; | |
}; | |
#ifdef __APPLE__ | |
// Based on Technical Q&A QA1398: "Mach Absolute Time Units" | |
// at https://developer.apple.com/library/mac/qa/qa1398/_index.html | |
std::uint64_t GetTimeInNanoseconds(void) | |
{ | |
static mach_timebase_info_data_t sTimebaseInfo; | |
std::uint64_t time; | |
// If this is the first time we've run, get the timebase. | |
// We can use denom == 0 to indicate that sTimebaseInfo is | |
// uninitialised because it makes no sense to have a zero | |
// denominator in a fraction. | |
if (sTimebaseInfo.denom == 0) | |
{ | |
mach_timebase_info(&sTimebaseInfo); | |
} | |
time = mach_absolute_time(); | |
// Convert to nanoseconds. | |
// Do the maths. We hope that the multiplication doesn't | |
// overflow; the price you pay for working in fixed point. | |
return time * sTimebaseInfo.numer / sTimebaseInfo.denom; | |
} | |
class OSXClock | |
{ | |
public: | |
static std::uint64_t zero_time(void) | |
{ | |
// in 100-ns intervals | |
return GetTimeInNanoseconds() / 100u; | |
} | |
static std::uint64_t timestamp(void) | |
{ | |
return GetTimeInNanoseconds(); | |
} | |
static std::uint64_t update_frequency(void) | |
{ | |
return 1u; | |
} | |
}; | |
#endif | |
int main(int argc, const char * argv[]) | |
{ | |
static const HiResClock<OSXClock> clock; | |
std::cout << "Timestamp:" << clock.now() << "\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment