Home | History | Annotate | Download | only in perf
      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 
     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 
     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