Skip to content

Instantly share code, notes, and snippets.

@azat
Created January 26, 2024 08:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azat/88c7b19d15f10aceec3adad1c41accbc to your computer and use it in GitHub Desktop.
Save azat/88c7b19d15f10aceec3adad1c41accbc to your computer and use it in GitHub Desktop.
Test clocks (clock_gettime and RDTSC)
#include <cstdint>
#include <ctime>
#include <cerrno>
#include <iostream>
#include <utility>
uint64_t now_ns(clockid_t clock)
{
struct timespec ts;
clock_gettime(clock, &ts);
return ts.tv_sec * (uint64_t)1e9 + ts.tv_nsec;
}
__inline__ uint64_t rdtsc(void)
{
uint32_t lo, hi;
__asm__ __volatile__ ( // serialize
"xorl %%eax,%%eax \n cpuid"
::: "%rax", "%rbx", "%rcx", "%rdx");
/* We cannot use "=A", since this would use %rax on x86_64 and return only the lower 32bits of the TSC */
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
void sleepForNanoseconds(uint64_t nanoseconds)
{
constexpr auto clock_type = CLOCK_MONOTONIC;
struct timespec current_time;
clock_gettime(clock_type, &current_time);
constexpr uint64_t resolution = 1'000'000'000;
struct timespec finish_time = current_time;
finish_time.tv_nsec += nanoseconds % resolution;
const uint64_t extra_second = finish_time.tv_nsec / resolution;
finish_time.tv_nsec %= resolution;
finish_time.tv_sec += (nanoseconds / resolution) + extra_second;
while (clock_nanosleep(clock_type, TIMER_ABSTIME, &finish_time, nullptr) == EINTR);
}
template <class F, class ... Args>
uint64_t clock_elapsed(clockid_t clock, const F & f, Args && ... args)
{
uint64_t start = now_ns(clock);
f(std::forward<Args>(args)...);
uint64_t end = now_ns(clock);
return end - start;
}
template <class F, class ... Args>
uint64_t rdtsc_elapsed(const F & f, Args && ... args)
{
uint64_t start = rdtsc();
f(std::forward<Args>(args)...);
uint64_t end = rdtsc();
return end - start;
}
int main()
{
std::cout << "CLOCK_MONOTONIC_RAW: " << clock_elapsed(CLOCK_MONOTONIC_RAW, sleepForNanoseconds, 1'000'000) << " ns\n";
std::cout << "CLOCK_PROCESS_CPUTIME_ID: " << clock_elapsed(CLOCK_PROCESS_CPUTIME_ID, sleepForNanoseconds, 1'000'000) << " ns\n";
std::cout << "CLOCK_THREAD_CPUTIME_ID: " << clock_elapsed(CLOCK_THREAD_CPUTIME_ID, sleepForNanoseconds, 1'000'000) << " ns\n";
// Look at [1] to convert to seconds
// [1]: https://gist.github.com/Mic92/12063527bb6d6c5a636502300d2de446
std::cout << "rdtsc: " << rdtsc_elapsed(sleepForNanoseconds, 1'000'000) << " ticks\n";
return 0;
}
CLOCK_MONOTONIC_RAW: 1063965 ns
CLOCK_PROCESS_CPUTIME_ID: 2865 ns
CLOCK_THREAD_CPUTIME_ID: 5301 ns
rdtsc: 3882204 ticks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment