Skip to content

Instantly share code, notes, and snippets.

@Tillsunset
Created December 15, 2022 04:48
Show Gist options
  • Save Tillsunset/61d8681c7b681b8f0922fca068db6ca1 to your computer and use it in GitHub Desktop.
Save Tillsunset/61d8681c7b681b8f0922fca068db6ca1 to your computer and use it in GitHub Desktop.
#include <chrono>
#include <ctime>
#include <cpuid.h>
#include <iostream>
#include <unistd.h>
int iterations = 10000000;
#define approxMono CLOCK_MONOTONIC_RAW_APPROX
inline void cpuid(int cpuInfo[4], int functionId) {
__cpuid(functionId, cpuInfo[0], cpuInfo[1], cpuInfo[2], cpuInfo[3]);
}
int main()
{
// start of dummy run for first time slowdown
for (int i = 0; i < iterations; ++i) {
std::chrono::steady_clock::time_point(std::chrono::nanoseconds(clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)));
}
struct timespec tpMonoAprDummy;
for (int i = 0; i < iterations; ++i) {
clock_gettime(approxMono, &tpMonoAprDummy);
std::chrono::steady_clock::time_point(
std::chrono::seconds(tpMonoAprDummy.tv_sec) + std::chrono::nanoseconds(tpMonoAprDummy.tv_nsec));
}
struct timespec tpMonoRawDummy;
for (int i = 0; i < iterations; ++i) {
clock_gettime(CLOCK_MONOTONIC_RAW, &tpMonoRawDummy);
std::chrono::steady_clock::time_point(
std::chrono::seconds(tpMonoRawDummy.tv_sec) + std::chrono::nanoseconds(tpMonoRawDummy.tv_nsec));
}
struct timespec tpMonoDummy;
for (int i = 0; i < iterations; ++i) {
clock_gettime(CLOCK_MONOTONIC, &tpMonoDummy);
std::chrono::steady_clock::time_point(
std::chrono::seconds(tpMonoDummy.tv_sec) + std::chrono::nanoseconds(tpMonoDummy.tv_nsec));
}
for (int i = 0; i < iterations; ++i) {
std::chrono::steady_clock::now();
}
for (int i = 0; i < iterations; ++i) {
std::chrono::system_clock::now();
}
for (int i = 0; i < iterations; ++i) {
std::chrono::high_resolution_clock::now();
}
for (int i = 0; i < iterations; ++i) {
std::chrono::steady_clock::time_point(
std::chrono::nanoseconds(__rdtsc()));
}
// end of dummy run
auto startGetN = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
std::chrono::steady_clock::time_point(std::chrono::nanoseconds(clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)));
}
auto stopGetN = std::chrono::high_resolution_clock::now();
auto startMonoApx = std::chrono::high_resolution_clock::now();
struct timespec tpMonoApr;
for (int i = 0; i < iterations; ++i) {
clock_gettime(approxMono, &tpMonoApr);
std::chrono::steady_clock::time_point(
std::chrono::seconds(tpMonoApr.tv_sec) + std::chrono::nanoseconds(tpMonoApr.tv_nsec));
}
auto stopMonoApx = std::chrono::high_resolution_clock::now();
auto startMonoRaw = std::chrono::high_resolution_clock::now();
struct timespec tpMonoRaw;
for (int i = 0; i < iterations; ++i) {
clock_gettime(CLOCK_MONOTONIC_RAW, &tpMonoRaw);
std::chrono::steady_clock::time_point(
std::chrono::seconds(tpMonoRaw.tv_sec) + std::chrono::nanoseconds(tpMonoRaw.tv_nsec));
}
auto stopMonoRaw = std::chrono::high_resolution_clock::now();
auto startMono = std::chrono::high_resolution_clock::now();
struct timespec tpMono;
for (int i = 0; i < iterations; ++i) {
clock_gettime(CLOCK_MONOTONIC, &tpMono);
std::chrono::steady_clock::time_point(
std::chrono::seconds(tpMono.tv_sec) + std::chrono::nanoseconds(tpMono.tv_nsec));
}
auto stopMono = std::chrono::high_resolution_clock::now();
auto startSteadyNow = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
std::chrono::steady_clock::now();
}
auto stopSteadyNow = std::chrono::high_resolution_clock::now();
auto startSystemNow = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
std::chrono::system_clock::now();
}
auto stopSystemNow = std::chrono::high_resolution_clock::now();
auto startHighResNow = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
std::chrono::high_resolution_clock::now();
}
auto stopHighResNow = std::chrono::high_resolution_clock::now();
auto startRDTSC = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
std::chrono::steady_clock::time_point(
std::chrono::nanoseconds(__rdtsc()));
}
auto stopRDTSC = std::chrono::high_resolution_clock::now();
auto durationRDTSC = duration_cast<std::chrono::milliseconds>(stopRDTSC - startRDTSC);
auto durationGetN = duration_cast<std::chrono::milliseconds>(stopGetN - startGetN);
auto durationMono = duration_cast<std::chrono::milliseconds>(stopMono - startMono);
auto durationMonoRaw = duration_cast<std::chrono::milliseconds>(stopMonoRaw - startMonoRaw);
auto durationMonoApx = duration_cast<std::chrono::milliseconds>(stopMonoApx - startMonoApx);
auto durationSteadyNow = duration_cast<std::chrono::milliseconds>(stopSteadyNow - startSteadyNow);
auto durationSystemNow = duration_cast<std::chrono::milliseconds>(stopSystemNow - startSystemNow);
auto durationHighResNow = duration_cast<std::chrono::milliseconds>(stopHighResNow - startHighResNow);
int cpuInfo[4];
cpuid(cpuInfo, 0x80000007);
printf("********** Testing different clock sources **********\n");
std::cout << "Time taken by RDTSC: " << durationRDTSC.count() << " milliseconds, is Steady " << ((cpuInfo[3] >> 8) & 1) << std::endl;
std::cout << "Time taken by MonoApx: " << durationMonoApx.count() << " milliseconds, is Steady: " << true << std::endl; // cached MonoRaw
std::cout << "Time taken by gettime_nsec: " << durationGetN.count() << " milliseconds, is Steady: " << true << std::endl; // optimized clock_gettime, probably macos only
std::cout << "Time taken by MonoRaw: " << durationMonoRaw.count() << " milliseconds, is Steady: " << true << std::endl;
std::cout << "Time taken by Mono: " << durationMono.count() << " milliseconds, is Steady: " << false << std::endl;
std::cout << "Time taken by system_clock: " << durationSystemNow.count() << " milliseconds, is Steady " << std::chrono::system_clock::is_steady << std::endl;
std::cout << "Time taken by steady_clock: " << durationSteadyNow.count() << " milliseconds, is Steady " << std::chrono::steady_clock::is_steady << std::endl;
std::cout << "Time taken by highres: " << durationHighResNow.count() << " milliseconds, is Steady " << std::chrono::high_resolution_clock::is_steady << std::endl; //typically alias of steady_ or system_clock
signed long long max = 0;
signed long long min = 1000000;
signed long long avgDist = 0;
signed long long avgDiff = 0;
signed long long temp = 0;
for (int i = 0; i < iterations; ++i) {
temp = ((signed long long)(clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW) - clock_gettime_nsec_np(approxMono)));
avgDiff += temp;
max = temp > max ? temp : max;
min = temp < min ? temp : min;
avgDist += temp > 0 ? temp : -temp;
}
avgDist /= iterations;
avgDiff /= iterations;
printf("\n********** Testing CLOCK_MONOTONIC_RAW and approxMono **********\n");
printf("max behind between raw and approx: %lld nanoseconds\n", min);
printf("max ahead between raw and approx: %lld nanoseconds\n", max);
printf("avg distance between raw and approx: %lld nanoseconds\n", avgDist);
printf("avg difference between raw and approx: %lld nanoseconds\n", avgDiff);
unsigned long long lastApx = clock_gettime_nsec_np(approxMono);
unsigned long long BeforeRaw = 0;
unsigned long long totalRawDiff = 0;
unsigned long long maxRawDiff = 0;
unsigned long long minRawDiff = 1000000;
unsigned long long tempDiff = 0;
int updateCounts = 0;
for (int i = 0; i < iterations * 5;) {
BeforeRaw = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW);
while (clock_gettime_nsec_np(approxMono) == lastApx) {
i++;
}
lastApx = clock_gettime_nsec_np(approxMono);
tempDiff = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW) - BeforeRaw;
totalRawDiff += tempDiff;
maxRawDiff = tempDiff > maxRawDiff ? tempDiff : maxRawDiff;
minRawDiff = tempDiff < minRawDiff ? tempDiff : minRawDiff;
updateCounts++;
}
printf("\n********** Testing approxMono update intervals **********\n");
printf("max time to change: %lld nanoseconds\n", maxRawDiff);
printf("min time to change: %lld nanoseconds\n", minRawDiff);
printf("avg time to change: %lld nanoseconds\n", totalRawDiff/updateCounts);
printf("updateCounts: %d\n", updateCounts);
printf("total: %lld nanoseconds\n", totalRawDiff);
unsigned long long before = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW);
unsigned long long beforeRDTSC = __rdtsc();
sleep(1);
unsigned long long after = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW);
unsigned long long afterRDTSC = __rdtsc();
printf("\none sec gettime_nsec: %llu nanoseconds\n", after - before);
printf("\none sec rdtsc: %llu nanoseconds\n", afterRDTSC - beforeRDTSC);
return 0;
}
@Tillsunset
Copy link
Author

********** Testing different clock sources **********
Time taken by RDTSC: 68 milliseconds, is Steady 1
Time taken by MonoApx: 170 milliseconds, is Steady: 1
Time taken by gettime_nsec: 366 milliseconds, is Steady: 1
Time taken by MonoRaw: 413 milliseconds, is Steady: 1
Time taken by Mono: 737 milliseconds, is Steady: 0
Time taken by system_clock: 263 milliseconds, is Steady 0
Time taken by steady_clock: 424 milliseconds, is Steady 1
Time taken by highres: 426 milliseconds, is Steady 1

********** Testing CLOCK_MONOTONIC_RAW and approxMono **********
max behind between raw and approx: -57726 nanoseconds
max ahead between raw and approx: 1022797 nanoseconds
avg distance between raw and approx: 293859 nanoseconds
avg difference between raw and approx: 293858 nanoseconds

********** Testing approxMono update intervals **********
max time to change: 1021101 nanoseconds
min time to change: 61 nanoseconds
avg time to change: 36711 nanoseconds
updateCounts: 19446
total: 713886635 nanoseconds

one sec gettime_nsec: 1003264331 nanoseconds

one sec rdtsc: 1396543980 nanoseconds

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment