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 | |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 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 |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 26 | static int nr_thr; // nr of threads (hardcoded to 1 currently) |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 27 | static int nr_repeat; // nr of times we will allocate, use, then free total+ws |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 28 | |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 29 | // Note: the total nr of MB is what is explicitely allocated. |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 30 | // On top of that, we have the stacks, local vars, lib vars, ... |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 31 | // The working set is just the first nr_b_ws blocks of nr_b. |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 32 | |
| 33 | static int verbose = 0; |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 34 | static unsigned char **t_b; // Pointers to all blocks |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 35 | |
| 36 | static void *memrw_fn(void *v) |
| 37 | { |
| 38 | int loops, m, b; |
philippe | 71a04ea | 2015-04-30 20:30:12 +0000 | [diff] [blame] | 39 | int dowrite; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 40 | int differs = 0; |
| 41 | unsigned char prev = 0; |
| 42 | |
| 43 | for (loops = 0; loops < nr_loops; loops++) { |
philippe | 71a04ea | 2015-04-30 20:30:12 +0000 | [diff] [blame] | 44 | // printf("loop %d dowrite %d\n", loops, dowrite); |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 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. |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 48 | for (m = 0; m < nr_b_ws; m++) { |
| 49 | for (b = 0; b < sz_b; b++) { |
philippe | 71a04ea | 2015-04-30 20:30:12 +0000 | [diff] [blame] | 50 | dowrite = b % 5 == 0; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 51 | // Do some write or read operations. |
philippe | 71a04ea | 2015-04-30 20:30:12 +0000 | [diff] [blame] | 52 | if (dowrite) { |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 53 | if (t_b[m][b] < 255) |
| 54 | t_b[m][b] += differs; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 55 | else |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 56 | t_b[m][b] = 0; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 57 | } else { |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 58 | differs = t_b[m][b] != prev; |
| 59 | prev = t_b[m][b]; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 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; |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 72 | int r; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 73 | pthread_t thr; |
| 74 | |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 75 | // usage: memrw [-b blocksize default 1MB ] |
| 76 | // [-t nr_b default 10] [-w nr_b_ws default 10] |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 77 | // [-l nr_loops_on_ws default 3] |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 78 | // [-r nr_repeat default 1] |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 79 | // [-f fan_out default 0] |
| 80 | // [-v verbosity default 0] |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 81 | sz_b = 1024 * 1024; |
| 82 | nr_b = 10; |
| 83 | nr_b_ws = 10; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 84 | nr_loops = 3; |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 85 | nr_repeat = 1; |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 86 | verbose = 0; |
| 87 | for (a = 1; a < argc; a+=2) { |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 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]); |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 92 | } else if (strcmp(argv[a], "-w") == 0) { |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 93 | nr_b_ws = atoi(argv[a+1]); |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 94 | } else if (strcmp(argv[a], "-l") == 0) { |
| 95 | nr_loops = atoi(argv[a+1]); |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 96 | } else if (strcmp(argv[a], "-r") == 0) { |
| 97 | nr_repeat = atoi(argv[a+1]); |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 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 | } |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 104 | if (nr_b_ws > nr_b) |
| 105 | nr_b_ws = nr_b; // to make it easy to do loops combining values |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 106 | |
| 107 | nr_thr = 1; |
| 108 | |
philippe | 016f2ee | 2015-05-06 21:24:23 +0000 | [diff] [blame] | 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)); |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 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); |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 119 | |
philippe | a1ac2f4 | 2015-05-01 17:12:00 +0000 | [diff] [blame] | 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"); |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 147 | } |
| 148 | |
philippe | cabdbb5 | 2015-04-20 21:33:16 +0000 | [diff] [blame] | 149 | return 0; |
| 150 | } |