Chris Lattner | 23028e8 | 2003-05-09 03:49:51 +0000 | [diff] [blame] | 1 | /* |
| 2 | * LLUBENCHMARK |
| 3 | * Craig Zilles (zilles@cs.wisc.edu) |
| 4 | * http://www.cs.wisc.edu/~zilles/llubenchmark.html |
| 5 | * |
| 6 | * This program is a linked list traversal micro-benchmark, which can |
| 7 | * be used (among other things) to approximate the non-benchmark |
| 8 | * Health. |
| 9 | * |
| 10 | * The benchmark executes for a proscribed number of iterations (-i), |
| 11 | * and on every iteration the lists are traversed and potentially |
| 12 | * extended. The number of lists can be specified (-n) as well as the |
| 13 | * size of the elements in the list (-s). The initial length of the |
| 14 | * lists can be set (-l) as well as the growth rate (-g). The growth |
| 15 | * rate must be non-negative, but can be a floating point number, in |
| 16 | * which case random numbers are used to determine whether a list is |
| 17 | * extended on a particular cycle (all lists are extended |
| 18 | * independently). If the -t option is specified, the insertion |
| 19 | * occurs at the tail, otherwise at the head. If the -d option is |
| 20 | * specified, the elements are dirtied during the traversal (which |
| 21 | * will necessitate a write-back when the data is evicted from the |
| 22 | * cache). |
| 23 | * |
| 24 | * To approximate the non-benchmark Health, use the options: |
| 25 | * -i <num iterations> -g .333 -d -t -n 341 |
| 26 | * |
| 27 | * (the growth rate of the lists in health is different for different |
| 28 | * levels of the hierarchy and the constant .333 is just my |
| 29 | * approximation of the growth rate). |
| 30 | * |
| 31 | */ |
| 32 | |
| 33 | #include <stdio.h> |
| 34 | #include <stdlib.h> |
| 35 | #if 0 |
| 36 | #include <assert.h> |
| 37 | #else |
| 38 | #define assert(x) |
| 39 | #endif |
| 40 | |
| 41 | /* This file should compile stand alone */ |
| 42 | |
| 43 | struct element { |
| 44 | struct element *next; |
| 45 | int count; |
| 46 | }; |
| 47 | |
| 48 | void |
| 49 | usage(char *name) { |
| 50 | printf("%s:\n", name); |
| 51 | printf("-i <number of (I)terations>\n"); |
| 52 | printf("[-l <initial (L)ength of list, in elements>] (default 1)\n"); |
| 53 | printf("[-n <(N)umber of lists>] (default 1 list)\n"); |
| 54 | printf("[-s <(S)ize of element>] (default 32 bytes)\n"); |
| 55 | printf("[-g <(G)rowth rate per list, in elements per iteration>] (default 0)\n"); |
| 56 | printf("[-d] ((D)irty each element during traversal, default off)\n"); |
| 57 | printf("[-t] (insert at (T)ail of list, default off)\n"); |
| 58 | } |
| 59 | |
| 60 | #define ALLOC_SIZE 127 /* pick wierd num to break strides */ |
| 61 | struct element *free_list = NULL; |
| 62 | int next_free = ALLOC_SIZE; |
| 63 | int element_size = 32; |
| 64 | int num_allocated = 0; |
| 65 | |
Misha Brukman | b77f1f7 | 2004-03-11 01:09:32 +0000 | [diff] [blame^] | 66 | #if 0 |
Chris Lattner | 23028e8 | 2003-05-09 03:49:51 +0000 | [diff] [blame] | 67 | struct element * |
| 68 | allocate() { |
| 69 | if (next_free == ALLOC_SIZE) { |
| 70 | next_free = 0; |
| 71 | free_list = (struct element *) malloc (ALLOC_SIZE * element_size); |
| 72 | assert(free_list != 0); |
| 73 | } |
| 74 | num_allocated ++; |
| 75 | return (struct element *) |
| 76 | (((char *)free_list) + ((next_free ++) * element_size)); |
| 77 | } |
| 78 | #else |
| 79 | struct element * allocate() { |
| 80 | num_allocated ++; |
| 81 | return (struct element*)malloc(sizeof(struct element)); |
| 82 | } |
| 83 | #endif |
| 84 | |
| 85 | int |
| 86 | main(int argc, char *argv[]) { |
| 87 | int max_iterations = 1000, |
| 88 | dirty = 1, |
| 89 | num_lists = 196, |
| 90 | tail = 1, |
| 91 | initial_length = 1; |
| 92 | float growth_rate = 0.333; |
| 93 | char c = 0; |
| 94 | int i = 0, j = 0, k = 0; |
| 95 | int accumulate = 0; |
| 96 | |
| 97 | struct element **lists = NULL; |
| 98 | float growth = 0.0; |
| 99 | |
| 100 | int arg = 1; |
| 101 | |
| 102 | printf("This benchmark modified to not use hard coded pool allocation!\n"); |
| 103 | while (arg < argc) { |
| 104 | if ((argv[arg][0] != '-') || (argv[arg][2] != 0)) { |
| 105 | printf("parse error in %s\n", argv[arg]); |
| 106 | usage(argv[0]); |
| 107 | return(-1); |
| 108 | } |
| 109 | c = argv[arg][1]; |
| 110 | arg ++; |
| 111 | switch(c) { |
| 112 | case 'd': dirty = 1; break; |
| 113 | case 'g': growth_rate = atof(argv[arg++]); break; |
| 114 | case 'i': max_iterations = atoi(argv[arg++]); break; |
| 115 | case 'l': initial_length = atoi(argv[arg++]); break; |
| 116 | case 'n': num_lists = atoi(argv[arg++]); break; |
| 117 | case 's': element_size = atoi(argv[arg++]); break; |
| 118 | case 't': tail = 1; break; |
| 119 | default: |
| 120 | printf("unrecognized option: %c\n", c); |
| 121 | usage(argv[0]); |
| 122 | return(-1); |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | assert (element_size > sizeof(struct element)); |
| 127 | assert (initial_length > 0); |
| 128 | |
| 129 | /* build lists */ |
| 130 | lists = (struct element **) malloc (num_lists * sizeof(struct element *)); |
| 131 | assert(lists != 0); |
| 132 | |
| 133 | for (i = 0 ; i < num_lists ; i ++) { |
| 134 | lists[i] = NULL; |
| 135 | } |
| 136 | |
| 137 | |
| 138 | for (i = 0 ; i < initial_length ; i ++) { |
| 139 | for (j = 0 ; j < num_lists ; j ++) { |
| 140 | struct element *e = allocate(); |
| 141 | e->next = lists[j]; |
| 142 | lists[j] = e; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | /* iterate */ |
| 147 | for (i = 0 ; i < max_iterations ; i ++) { |
| 148 | if ((i % 10) == 0) { |
| 149 | printf("%d\n", i); |
| 150 | } |
| 151 | /* traverse lists */ |
| 152 | for (j = 0 ; j < num_lists ; j ++) { |
| 153 | struct element *trav = lists[j]; |
| 154 | while (trav != NULL) { |
| 155 | accumulate += trav->count; |
| 156 | if (dirty) { |
| 157 | trav->count ++; |
| 158 | } |
| 159 | trav = trav->next; |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | /* grow lists */ |
| 164 | growth += growth_rate; |
| 165 | j = growth; |
| 166 | growth -= j; |
| 167 | for ( ; j > 0 ; j --) { |
| 168 | for (k = 0 ; k < num_lists ; k ++) { |
| 169 | struct element *e = allocate(); |
| 170 | if (tail) { |
| 171 | struct element *trav = lists[k]; |
| 172 | while (trav->next != NULL) { |
| 173 | trav = trav->next; |
| 174 | } |
| 175 | trav->next = e; |
| 176 | e->next = NULL; |
| 177 | } else { |
| 178 | e->next = lists[k]; |
| 179 | lists[k] = e; |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | printf ("num allocated %d\n", num_allocated); |
| 185 | return 0; |
| 186 | } |
| 187 | |