aboutsummaryrefslogblamecommitdiffhomepage
path: root/tools/gnuplot/mem_lat.c
blob: b85a08f389b4ba90ab03d1d862d407796eb6a120 (plain) (tree)


































































                                                                        
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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;
}