philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame^] | 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 nr_mb = 0; // total nr of mb used by the program |
| 23 | static int nr_mb_ws = 0; // nr_mb in program working set |
| 24 | static int nr_loops = 0; // nr of loops reading or writing the ws |
| 25 | static int nr_thr; // nr of threads (hardcoded to 1 currently) |
| 26 | |
| 27 | // Note: the total nr of mb is what is explicitely allocated. |
| 28 | // On top of that, we have the stacks, local vars, lib vars, ... |
| 29 | // The working set is just the first nr_mb_ws of nr_mb. |
| 30 | |
| 31 | static int verbose = 0; |
| 32 | static unsigned char **mb; |
| 33 | |
| 34 | static void *memrw_fn(void *v) |
| 35 | { |
| 36 | int loops, m, b; |
| 37 | int write; |
| 38 | int differs = 0; |
| 39 | unsigned char prev = 0; |
| 40 | |
| 41 | for (loops = 0; loops < nr_loops; loops++) { |
| 42 | // printf("loop %d write %d\n", loops, write); |
| 43 | // Note: in case of multiple threads, we will have |
| 44 | // to add lock/unlock somewhere in the below, maybe to lock |
| 45 | // the MB we are reading or writing. |
| 46 | for (m = 0; m < nr_mb_ws; m++) { |
| 47 | for (b = 0; b < 1024 * 1024; b++) { |
| 48 | write = b % 5 == 0; |
| 49 | // Do some write or read operations. |
| 50 | if (write) { |
| 51 | if (mb[m][b] < 255) |
| 52 | mb[m][b] += differs; |
| 53 | else |
| 54 | mb[m][b] = 0; |
| 55 | } else { |
| 56 | differs = mb[m][b] != prev; |
| 57 | prev = mb[m][b]; |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | } |
| 62 | return NULL; |
| 63 | } |
| 64 | |
| 65 | int main (int argc, char *argv[]) |
| 66 | { |
| 67 | int a; |
| 68 | int ret; |
| 69 | int i; |
| 70 | pthread_t thr; |
| 71 | |
| 72 | // usage: memrw [-t nr_mb default 10] [-w nr_mb_ws default 10] |
| 73 | // [-l nr_loops_on_ws default 3] |
| 74 | // [-f fan_out default 0] |
| 75 | // [-v verbosity default 0] |
| 76 | nr_mb = 10; |
| 77 | nr_mb_ws = 10; |
| 78 | nr_loops = 3; |
| 79 | verbose = 0; |
| 80 | for (a = 1; a < argc; a+=2) { |
| 81 | if (strcmp(argv[a], "-t") == 0) { |
| 82 | nr_mb = atoi(argv[a+1]); |
| 83 | } else if (strcmp(argv[a], "-w") == 0) { |
| 84 | nr_mb_ws = atoi(argv[a+1]); |
| 85 | } else if (strcmp(argv[a], "-l") == 0) { |
| 86 | nr_loops = atoi(argv[a+1]); |
| 87 | } else if (strcmp(argv[a], "-v") == 0) { |
| 88 | verbose = atoi(argv[a+1]); |
| 89 | } else { |
| 90 | printf("unknown arg %s\n", argv[a]); |
| 91 | } |
| 92 | } |
| 93 | if (nr_mb_ws > nr_mb) |
| 94 | nr_mb_ws = nr_mb; // to make it easy to do loops combining values |
| 95 | |
| 96 | nr_thr = 1; |
| 97 | |
| 98 | printf ("total program memory -t %d MB" |
| 99 | " working set -w %d MB" |
| 100 | " working set R or W -l %d times" |
| 101 | "\n", |
| 102 | nr_mb, |
| 103 | nr_mb_ws, |
| 104 | nr_loops); |
| 105 | |
| 106 | printf ("creating and initialising the total program memory\n"); |
| 107 | mb = malloc(nr_mb * sizeof(char*)); |
| 108 | if (mb == NULL) |
| 109 | perror("malloc mb"); |
| 110 | for (i = 0; i < nr_mb; i++) { |
| 111 | mb[i] = calloc(1024*1024, 1); |
| 112 | if (mb[i] == NULL) |
| 113 | perror("malloc mb[i]"); |
| 114 | } |
| 115 | |
| 116 | printf("starting thread that will read or write the working set\n"); |
| 117 | ret = pthread_create(&thr, NULL, memrw_fn, &nr_thr); |
| 118 | if (ret != 0) |
| 119 | perror("pthread_create"); |
| 120 | printf("waiting for thread termination\n"); |
| 121 | |
| 122 | ret = pthread_join(thr, NULL); |
| 123 | if (ret != 0) |
| 124 | perror("pthread_join"); |
| 125 | printf("thread terminated\n"); |
| 126 | |
| 127 | return 0; |
| 128 | } |