1#include "perf_index.h"
2#include "fail.h"
3#include <stdlib.h>
4#include <unistd.h>
5#include <string.h>
6#include <sys/sysctl.h>
7
8static char *memblock;
9static size_t memsize;
10
11size_t hw_memsize(void) {
12  int mib[2];
13  size_t len;
14  size_t my_memsize;
15  int retval;
16
17  mib[0] = CTL_HW;
18  mib[1] = HW_MEMSIZE;
19  len = sizeof(my_memsize);
20
21  retval = sysctl(mib, 2, &my_memsize, &len, NULL, 0);
22
23  if(retval != 0)
24      return 0;
25
26  return my_memsize;
27}
28
29DECL_SETUP {
30  char *memblockfiller;
31  long long i;
32  int pgsz = getpagesize();
33
34  /* Heuristic: use half the physical memory, hopefully this should work on all
35   * devices. We use the amount of physical memory, rather than some softer
36   * metric, like amount of free memory, so that the memory allocated is always
37   * consistent for a given device.
38   */
39  memsize = hw_memsize();
40  VERIFY(memsize > 0, "hw_memsize failed");
41  memsize = memsize/2;
42
43  memblock = (char*)malloc(memsize);
44  VERIFY(memblock != NULL, "malloc failed");
45
46  memblockfiller = memblock;
47
48  /* Do this manually, to make sure everything is paged in */
49  for(i=0; i<memsize; i+=pgsz) {
50    memblockfiller[i] = 1;
51  }
52
53  return PERFINDEX_SUCCESS;
54}
55
56/* figures out what region of memory to copy, so it does interfere with other
57threads,  */
58DECL_TEST {
59  long long left = length;
60  long long region_len = memsize / num_threads / 2;
61  long long region_start = memsize / num_threads * thread_id / 2;
62  long long copy_len;
63
64  if(thread_id < memsize / 2 % num_threads) {
65    region_start += thread_id;
66    region_len++;
67  }
68  else {
69    region_start += memsize / 2 % num_threads;
70  }
71
72  while(left>0) {
73    copy_len = region_len < left ? region_len : left;
74    memcpy(memblock+region_start+memsize/2, memblock+region_start, copy_len);
75    left -= copy_len;
76  }
77
78  return PERFINDEX_SUCCESS;
79}
80
81DECL_CLEANUP {
82    free(memblock);
83    return PERFINDEX_SUCCESS;
84}
85