Skip to content

Instantly share code, notes, and snippets.

@jhorneman
Created June 29, 2014 12:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jhorneman/d500c39465021db1e8df to your computer and use it in GitHub Desktop.
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
// 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