#include #include #include #include #include enum : size_t { KB = 1024, MB = 1024 * KB, DFL_MAXSZ = 64 * MB, DFL_STRIDE = 256, NUM_ACCESS = 1ull << 24, }; static inline uint64_t rdtsc() { uint32_t eax, edx; asm volatile("rdtsc" : "=a"(eax), "=d"(edx)); return ((uint64_t)edx << 32) | eax; } uint64_t run_one_walk(size_t size, size_t stride) { // Check size is power of two. assert((size & (size -1)) == 0); assert((size / stride) <= NUM_ACCESS); unsigned char *mem = (unsigned char *)malloc(size); memset(mem, 0x55, size); const uint64_t start = rdtsc(); for (size_t it = 0; it < NUM_ACCESS; it++) { ((volatile unsigned char *)mem)[(it * stride) & (size - 1)]++; } const uint64_t stop = rdtsc(); free(mem); return stop - start; } int main(int argc, char *argv[]) { size_t max_sz = DFL_MAXSZ; size_t stride = DFL_STRIDE; if (argc > 1) { max_sz = strtoll(argv[1], 0, 10); max_sz *= MB; } if (argc > 2) { stride = strtoll(argv[2], 0, 10); } fprintf(stderr, "max_sz=%zuK stride=%zu access=%zu\n", max_sz / KB, stride, NUM_ACCESS); size_t size = 2048; while (size <= max_sz) { uint64_t cycles = 0; for (size_t loop = 0; loop < 10; ++loop) { cycles += run_one_walk(size, stride); } printf("%6zuK %f\n", size / KB, (double)cycles / NUM_ACCESS / 10.0); size *= 2; } return 0; }