/* * Program to measure TSC register jitter between two CPUs * * Copyright (C) 2006 Nikolai Joukov and Erez Zadok * Copyright (C) 2006 Stony Brook University */ #include #include #include #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) #define RDTSC(qp) \ do { \ unsigned long lowPart, highPart; \ __asm__ __volatile__("rdtsc" : "=a" (lowPart), "=d" (highPart)); \ qp = (((unsigned long long) highPart) << 32) | lowPart; \ } while (0); //#define AFFINITY int TSC_reader(void *arg) { #ifdef AFFINITY int cpumask = 2; #endif long long * ll = (long long*)arg; #ifdef AFFINITY if (sched_setaffinity(getpid(), 2, &cpumask) != 0) printf("child setaffinity failed\n"); #endif while (ll[1]) RDTSC(ll[0]); return 0; } #define STACK_SIZE 512 #define BUCKETS_NUM (sizeof(long long)*8) int main(int argc, char* argv[]) { void *stack[STACK_SIZE]; int err = 0; unsigned long long ll, delay, TSC[2]; unsigned long long aggregate_stats[BUCKETS_NUM]; int bucket, idelay, it; #ifdef AFFINITY int cpumask = 1; #endif TSC[0] = 0; TSC[1] = 1; if (argc != 2) { printf("usage: %s iterations\n", argv[0]); return 2; } it = atoi(argv[1]); err = clone(TSC_reader, stack + STACK_SIZE, CLONE_VM, (void*)TSC); if (!err) { perror("clone:"); return 2; } memset(aggregate_stats, 0, sizeof(aggregate_stats)); #ifdef AFFINITY if (sched_setaffinity(getpid(), 2, &cpumask) != 0) printf("parent setaffinity failed\n"); #endif /* wait for the TSC reader to start */ while (TSC[0] == 0) {}; /* sched_yield();*/ /* slow but it is ok here */ for (; it; it--) { RDTSC(ll); if (ll > TSC[0]) delay = ll - TSC[0]; else delay = TSC[0] - ll; delay = delay >> 5; idelay = delay >> 32; if (idelay) { bucket = 31; } else { bucket = 0; idelay = (unsigned int)delay; } for (; idelay && (bucket + 1) < BUCKETS_NUM; bucket++) { idelay = idelay >> 1; } aggregate_stats[bucket]++; } TSC[1] = 0; printf("OP_TSC_JITTER ? ? "); for (bucket = 0; bucket < BUCKETS_NUM; bucket++) printf("%lld ", aggregate_stats[bucket]); printf("\n"); return 1; }