#include #include #include int errno; _syscall0(int,getpid) #define rdtscp(low,high,aux) \ asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (low), "=d" (high), "=c" (aux)) #define rdtscpll(val, aux) do { \ unsigned long __a, __d; \ asm volatile (".byte 0x0f,0x01,0xf9" : "=a" (__a), "=d" (__d), "=c" (aux)); \ (val) = (__d << 32) | __a; \ } while (0) enum { ITER = 100000, }; long __jiffies; enum { VGETCPU_RDTSCP = 1, } __vgetcpu_mode; unsigned char __cpu_to_node[32]; long do_vgetcpu(int *cpu, int *node, unsigned long *tcache) { unsigned int dummy, p; unsigned long j = __jiffies; /* Fast cache - only recompute value once per jiffies and avoid relatively costly rdtscp/cpuid otherwise. This works because the scheduler usually keeps the process on the same CPU and this syscall doesn't guarantee its results anyways. We do this here because otherwise user space would do it on its own in a likely inferior way (no access to jiffies). If you don't like it pass NULL. */ if (tcache && tcache[0] == j) { p = tcache[1]; } else if (__vgetcpu_mode == VGETCPU_RDTSCP) { rdtscp(dummy, dummy, p); } else { #if 1 asm("lsl %1,%0" : "=r" (p) : "r" (15 * 8)); #else cpuid(1, &dummy, &p, &dummy, &dummy); p >>= 24; p |= (__cpu_to_node[p] << 16); #endif } if (tcache) { tcache[0] = j; tcache[1] = p; } if (cpu) *cpu = p & 0xffff; if (node) *node = p >> 16; return 0; } long (*vgetcpu)(int *cpu, int *node, unsigned long *tcache) = do_vgetcpu; int main(void) { unsigned long start, end; int i; int rdtscp = 0; #if 0 rdtscp = 1; #endif rdtscll(start); for (i = 0; i < ITER; i++) getpid(); rdtscll(end); printf("getpid %lu cycles\n", (end-start)/ITER); int cpu, node; rdtscll(start); for (i = 0; i < ITER; i++) vgetcpu(&cpu, &node, NULL); rdtscll(end); printf("vgetcpu lsl %lu cycles\n", (end-start)/ITER); if (rdtscp) { __vgetcpu_mode = VGETCPU_RDTSCP; rdtscll(start); for (i = 0; i < ITER; i++) vgetcpu(&cpu, &node, NULL); rdtscll(end); printf("vgetcpu rdtscp %lu cycles\n", (end-start)/ITER); } unsigned long cache[2]; rdtscll(start); for (i = 0; i < ITER; i++) vgetcpu(&cpu,&node,cache); rdtscll(end); printf("vgetcpu cached %lu cycles\n", (end-start)/ITER); return 0; }