mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-08 00:16:11 +00:00
151 lines
4.7 KiB
C
151 lines
4.7 KiB
C
#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 explicitely 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;
|
|
}
|