blob: c368f26f23840578f00fe3faa0b4c306ba5e27cf [file] [log] [blame]
#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 nr_mb = 0; // total nr of mb used by the program
static int nr_mb_ws = 0; // nr_mb in program working set
static int nr_loops = 0; // nr of loops reading or writing the ws
static int nr_thr; // nr of threads (hardcoded to 1 currently)
// Note: the total nr of mb is what is explicitely allocated.
// On top of that, we have the stacks, local vars, lib vars, ...
// The working set is just the first nr_mb_ws of nr_mb.
static int verbose = 0;
static unsigned char **mb;
static void *memrw_fn(void *v)
{
int loops, m, b;
int write;
int differs = 0;
unsigned char prev = 0;
for (loops = 0; loops < nr_loops; loops++) {
// printf("loop %d write %d\n", loops, write);
// 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_mb_ws; m++) {
for (b = 0; b < 1024 * 1024; b++) {
write = b % 5 == 0;
// Do some write or read operations.
if (write) {
if (mb[m][b] < 255)
mb[m][b] += differs;
else
mb[m][b] = 0;
} else {
differs = mb[m][b] != prev;
prev = mb[m][b];
}
}
}
}
return NULL;
}
int main (int argc, char *argv[])
{
int a;
int ret;
int i;
pthread_t thr;
// usage: memrw [-t nr_mb default 10] [-w nr_mb_ws default 10]
// [-l nr_loops_on_ws default 3]
// [-f fan_out default 0]
// [-v verbosity default 0]
nr_mb = 10;
nr_mb_ws = 10;
nr_loops = 3;
verbose = 0;
for (a = 1; a < argc; a+=2) {
if (strcmp(argv[a], "-t") == 0) {
nr_mb = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-w") == 0) {
nr_mb_ws = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-l") == 0) {
nr_loops = 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_mb_ws > nr_mb)
nr_mb_ws = nr_mb; // to make it easy to do loops combining values
nr_thr = 1;
printf ("total program memory -t %d MB"
" working set -w %d MB"
" working set R or W -l %d times"
"\n",
nr_mb,
nr_mb_ws,
nr_loops);
printf ("creating and initialising the total program memory\n");
mb = malloc(nr_mb * sizeof(char*));
if (mb == NULL)
perror("malloc mb");
for (i = 0; i < nr_mb; i++) {
mb[i] = calloc(1024*1024, 1);
if (mb[i] == NULL)
perror("malloc mb[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");
return 0;
}