Changeset 4e41aa4 in mainline for uspace/app/rcubench/rcubench.c
- Timestamp:
- 2012-12-03T18:47:08Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 21b703f
- Parents:
- a440a0f
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/rcubench/rcubench.c
ra440a0f r4e41aa4 50 50 #include <rcu.h> 51 51 52 typedef struct bench { 53 enum { 54 T_KERN_FUTEX, 55 T_LIBC_FUTEX 56 } type; 57 size_t iters; 58 size_t nthreads; 59 size_t array_size; 60 size_t *array; 61 futex_t done_threads; 62 63 futex_t ke_bench_fut; 64 fibril_mutex_t libc_bench_mtx; 65 } bench_t; 66 67 68 /* Combats compiler optimizations. */ 69 static volatile size_t dummy = 0; 70 71 static size_t sum_array(size_t *array, size_t len) 72 { 73 size_t sum = 0; 74 75 for (size_t k = 0; k < len; ++k) 76 sum += array[k]; 77 78 return sum; 79 } 80 81 static void kernel_futex_bench(bench_t *bench) 82 { 83 futex_t * const fut = &bench->ke_bench_fut; 84 const size_t iters = bench->iters; 85 size_t sum = 0; 86 87 for (size_t i = 0; i < iters; ++i) { 88 /* Do some work with the futex locked to encourage contention. */ 89 futex_down(fut); 90 sum += sum_array(bench->array, bench->array_size); 91 futex_up(fut); 92 93 /* 94 * Do half as much work to give other threads a chance to acquire 95 * the futex. 96 */ 97 sum += sum_array(bench->array, bench->array_size / 2); 98 } 99 100 /* 101 * Writing to a global volatile variable separated with a cc-barrier 102 * should discourage the compiler from optimizing away sum_array()s. 103 */ 104 compiler_barrier(); 105 dummy = sum; 106 } 107 108 static void libc_futex_bench(bench_t *bench) 109 { 110 fibril_mutex_t * const mtx = &bench->libc_bench_mtx; 111 const size_t iters = bench->iters; 112 113 for (size_t i = 0; i < iters; ++i) { 114 fibril_mutex_lock(mtx); 115 /* no-op */ 116 compiler_barrier(); 117 fibril_mutex_unlock(mtx); 118 } 119 } 120 121 122 static void thread_func(void *arg) 123 { 124 bench_t *bench = (bench_t*)arg; 125 assert(bench->type == T_KERN_FUTEX || bench->type == T_LIBC_FUTEX); 126 127 if (bench->type == T_KERN_FUTEX) 128 kernel_futex_bench(bench); 129 else 130 libc_futex_bench(bench); 131 132 /* Signal another thread completed. */ 133 futex_up(&bench->done_threads); 134 } 135 136 static void run_threads_and_wait(bench_t *bench) 137 { 138 assert(1 <= bench->nthreads); 139 140 if (2 <= bench->nthreads) { 141 printf("Creating %zu additional threads...\n", bench->nthreads - 1); 142 } 143 144 /* Create and run the first nthreads - 1 threads.*/ 145 for (size_t k = 1; k < bench->nthreads; ++k) { 146 thread_id_t tid; 147 /* Also sets up a fibril for the thread. */ 148 int ret = thread_create(thread_func, bench, "rcubench-t", &tid); 149 if (ret != EOK) { 150 printf("Error: Failed to create benchmark thread.\n"); 151 abort(); 152 } 153 thread_detach(tid); 154 } 155 156 /* 157 * Run the last thread in place so that we create multiple threads 158 * only when needed. Otherwise libc would immediately upgrade 159 * single-threaded futexes to proper multithreaded futexes 160 */ 161 thread_func(bench); 162 163 printf("Waiting for remaining threads to complete.\n"); 164 165 /* Wait for threads to complete. */ 166 for (size_t k = 0; k < bench->nthreads; ++k) { 167 futex_down(&bench->done_threads); 168 } 169 } 170 171 static void print_usage(void) 172 { 173 printf("rcubench [test-name] [k-iterations] [n-threads] {work-size}\n"); 174 printf("eg:\n"); 175 printf(" rcubench ke 100000 3 4\n"); 176 printf(" rcubench libc 100000 2\n"); 177 printf(" rcubench def-ke \n"); 178 printf(" rcubench def-libc\n"); 179 } 180 181 static bool parse_cmd_line(int argc, char **argv, bench_t *bench, 182 const char **err) 183 { 184 if (argc < 2) { 185 *err = "Benchmark name not specified"; 186 return false; 187 } 188 189 futex_initialize(&bench->ke_bench_fut, 1); 190 fibril_mutex_initialize(&bench->libc_bench_mtx); 191 192 if (0 == str_cmp(argv[1], "def-ke")) { 193 bench->type = T_KERN_FUTEX; 194 bench->nthreads = 4; 195 bench->iters = 1000 * 1000; 196 bench->array_size = 10; 197 bench->array = malloc(bench->array_size * sizeof(size_t)); 198 return NULL != bench->array; 199 } else if (0 == str_cmp(argv[1], "def-libc")) { 200 bench->type = T_LIBC_FUTEX; 201 bench->nthreads = 4; 202 bench->iters = 1000 * 1000; 203 bench->array_size = 0; 204 bench->array = NULL; 205 return true; 206 } else if (0 == str_cmp(argv[1], "ke")) { 207 bench->type = T_KERN_FUTEX; 208 } else if (0 == str_cmp(argv[1], "libc")) { 209 bench->type = T_LIBC_FUTEX; 210 } else { 211 *err = "Unknown test name"; 212 return false; 213 } 214 215 if (argc < 4) { 216 *err = "Not enough parameters"; 217 return false; 218 } 219 220 uint32_t iter_cnt = 0; 221 int ret = str_uint32_t(argv[2], NULL, 0, true, &iter_cnt); 222 223 if (ret == EOK && 1 <= iter_cnt) { 224 bench->iters = iter_cnt; 225 } else { 226 *err = "Err: Invalid number of iterations"; 227 return false; 228 } 229 230 uint32_t thread_cnt = 0; 231 ret = str_uint32_t(argv[3], NULL, 0, true, &thread_cnt); 232 233 if (ret == EOK && 1 <= thread_cnt && thread_cnt <= 64) { 234 bench->nthreads = thread_cnt; 235 } else { 236 *err = "Err: Invalid number of threads"; 237 return false; 238 } 239 240 if (argc > 4) { 241 uint32_t work_size = 0; 242 ret = str_uint32_t(argv[4], NULL, 0, true, &work_size); 243 244 if (ret == EOK && work_size <= 10000) { 245 bench->array_size = work_size; 246 } else { 247 *err = "Err: Work size too large"; 248 return false; 249 } 250 } else { 251 bench->array_size = 0; 252 } 253 254 if (0 < bench->array_size) { 255 bench->array = malloc(bench->array_size * sizeof(size_t)); 256 if (!bench->array) { 257 *err = "Err: Failed to allocate work array"; 258 return false; 259 } 260 } else { 261 bench->array = NULL; 262 } 263 264 return true; 265 } 52 266 53 267 int main(int argc, char **argv) 54 268 { 55 printf("hello!\n"); 269 const char *err = "(error)"; 270 bench_t bench; 271 272 futex_initialize(&bench.done_threads, 0); 273 274 if (!parse_cmd_line(argc, argv, &bench, &err)) { 275 printf("%s\n", err); 276 print_usage(); 277 return -1; 278 } 279 280 printf("Running '%s' futex bench in '%zu' threads with '%zu' iterations.\n", 281 bench.type == T_KERN_FUTEX ? "kernel" : "libc", 282 bench.nthreads, bench.iters); 283 284 struct timeval start, end; 285 getuptime(&start); 286 287 run_threads_and_wait(&bench); 288 289 getuptime(&end); 290 int64_t duration = tv_sub(&end, &start); 291 292 uint64_t total_iters = (uint64_t)bench.iters * bench.nthreads; 293 uint64_t iters_per_sec = total_iters * 1000 * 1000 / duration; 294 uint64_t secs = (uint64_t)duration / 1000 / 1000; 295 296 printf("Completed %" PRIu64 " iterations in %" PRId64 " usecs (%" PRIu64 297 " secs); %" PRIu64 " iters/sec\n", 298 total_iters, duration, secs, iters_per_sec); 299 56 300 return 0; 57 301 }
Note:
See TracChangeset
for help on using the changeset viewer.