1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
#define _GNU_SOURCE
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
// memrw provides a simulation of an application
// reading and writing memory, for the sake of tuning helgrind.
// It is a very simple (simplistic) model:
// * only one thread
// * only one exe context reading or writing the memory
// * the working set of the application is unrealistically
// concentrated on a consecutive nr of MB.
// At this moment, it was just used to tune the EvM data structure
// of helgrind.
// It would be nice to enhance this program to cope with a richer
// model e.g. multiple threads, many different stack traces touching
// the memory, better working set distribution, ...
static int sz_b; // size of a block
static int nr_b; // total nr of blocks used by the program
static int nr_b_ws; // nr_b in program working set
static int nr_loops; // nr of loops reading or writing the ws
static int nr_thr; // nr of threads (hardcoded to 1 currently)
static int nr_repeat; // nr of times we will allocate, use, then free total+ws
// Note: the total nr of MB is what is explicitly allocated.
// On top of that, we have the stacks, local vars, lib vars, ...
// The working set is just the first nr_b_ws blocks of nr_b.
static int verbose = 0;
static unsigned char **t_b; // Pointers to all blocks
static void *memrw_fn(void *v)
{
int loops, m, b;
int dowrite;
int differs = 0;
unsigned char prev = 0;
for (loops = 0; loops < nr_loops; loops++) {
// printf("loop %d dowrite %d\n", loops, dowrite);
// Note: in case of multiple threads, we will have
// to add lock/unlock somewhere in the below, maybe to lock
// the MB we are reading or writing.
for (m = 0; m < nr_b_ws; m++) {
for (b = 0; b < sz_b; b++) {
dowrite = b % 5 == 0;
// Do some write or read operations.
if (dowrite) {
if (t_b[m][b] < 255)
t_b[m][b] += differs;
else
t_b[m][b] = 0;
} else {
differs = t_b[m][b] != prev;
prev = t_b[m][b];
}
}
}
}
return NULL;
}
int main (int argc, char *argv[])
{
int a;
int ret;
int i;
int r;
pthread_t thr;
// usage: memrw [-b blocksize default 1MB ]
// [-t nr_b default 10] [-w nr_b_ws default 10]
// [-l nr_loops_on_ws default 3]
// [-r nr_repeat default 1]
// [-f fan_out default 0]
// [-v verbosity default 0]
sz_b = 1024 * 1024;
nr_b = 10;
nr_b_ws = 10;
nr_loops = 3;
nr_repeat = 1;
verbose = 0;
for (a = 1; a < argc; a+=2) {
if (strcmp(argv[a], "-b") == 0) {
sz_b = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-t") == 0) {
nr_b = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-w") == 0) {
nr_b_ws = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-l") == 0) {
nr_loops = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-r") == 0) {
nr_repeat = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-v") == 0) {
verbose = atoi(argv[a+1]);
} else {
printf("unknown arg %s\n", argv[a]);
}
}
if (nr_b_ws > nr_b)
nr_b_ws = nr_b; // to make it easy to do loops combining values
nr_thr = 1;
printf ("total program memory -t %llu MB"
" working set -w %llu MB\n",
((unsigned long long)nr_b * sz_b)
/ (unsigned long long) (1024*1024),
((unsigned long long)nr_b_ws * sz_b)
/ (unsigned long long)(1024*1024));
printf (" working set R or W -l %d times"
" repeat the whole stuff -r %d times\n",
nr_loops,
nr_repeat);
for (r = 0; r < nr_repeat; r++) {
printf ("creating and initialising the total program memory\n");
t_b = malloc(nr_b * sizeof(char*));
if (t_b == NULL)
perror("malloc t_b");
for (i = 0; i < nr_b; i++) {
t_b[i] = calloc(sz_b, 1);
if (t_b[i] == NULL)
perror("malloc t_b[i]");
}
printf("starting thread that will read or write the working set\n");
ret = pthread_create(&thr, NULL, memrw_fn, &nr_thr);
if (ret != 0)
perror("pthread_create");
printf("waiting for thread termination\n");
ret = pthread_join(thr, NULL);
if (ret != 0)
perror("pthread_join");
printf("thread terminated\n");
/* Now, free the memory used, for the next repeat */
for (i = 0; i < nr_b; i++)
free (t_b[i]);
free (t_b);
printf("memory freed\n");
}
return 0;
}
|