perfindex-memory.c   [plain text]


#include "perf_index.h"
#include "fail.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sysctl.h>

static char *memblock;
static size_t memsize;

size_t hw_memsize(void) {
  int mib[2];
  size_t len;
  size_t my_memsize;
  int retval;

  mib[0] = CTL_HW;
  mib[1] = HW_MEMSIZE;
  len = sizeof(my_memsize);

  retval = sysctl(mib, 2, &my_memsize, &len, NULL, 0);

  if(retval != 0)
      return 0;

  return my_memsize;
}

DECL_SETUP {
  char *memblockfiller;
  long long i;
  int pgsz = getpagesize();

  /* Heuristic: use half the physical memory, hopefully this should work on all
   * devices. We use the amount of physical memory, rather than some softer
   * metric, like amount of free memory, so that the memory allocated is always
   * consistent for a given device.
   */
  memsize = hw_memsize();
  VERIFY(memsize > 0, "hw_memsize failed");
  memsize = memsize/2;

  memblock = (char*)malloc(memsize);
  VERIFY(memblock != NULL, "malloc failed");

  memblockfiller = memblock;

  /* Do this manually, to make sure everything is paged in */
  for(i=0; i<memsize; i+=pgsz) {
    memblockfiller[i] = 1;
  }

  return PERFINDEX_SUCCESS;
}

/* figures out what region of memory to copy, so it does interfere with other
threads,  */
DECL_TEST {
  long long left = length;
  long long region_len = memsize / num_threads / 2;
  long long region_start = memsize / num_threads * thread_id / 2;
  long long copy_len;

  if(thread_id < memsize / 2 % num_threads) {
    region_start += thread_id;
    region_len++;
  }
  else {
    region_start += memsize / 2 % num_threads;
  }

  while(left>0) {
    copy_len = region_len < left ? region_len : left;
    memcpy(memblock+region_start+memsize/2, memblock+region_start, copy_len);
    left -= copy_len;
  }

  return PERFINDEX_SUCCESS;
}

DECL_CLEANUP {
    free(memblock);
    return PERFINDEX_SUCCESS;
}