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