1/* 2 * Copyright (c) 2007-2012, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <string.h> 13#include <assert.h> 14#include <barrelfish/barrelfish.h> 15#include <bench/bench.h> 16 17bench_ctl_t *bench_ctl_init(enum bench_ctl_mode mode, 18 size_t dimensions, 19 size_t min_runs) 20{ 21 bench_ctl_t *ctl; 22 23 ctl = calloc(1, sizeof(*ctl)); 24 ctl->mode = mode; 25 ctl->result_dimensions = dimensions; 26 ctl->min_runs = min_runs; 27 28 if (mode == BENCH_MODE_FIXEDRUNS) { 29 ctl->data = calloc(min_runs * dimensions, sizeof(*ctl->data)); 30 } else { 31 assert(!"NYI"); 32 } 33 34 return ctl; 35} 36 37void bench_ctl_destroy(bench_ctl_t *ctl) 38{ 39 free(ctl->data); 40 free(ctl); 41} 42 43void bench_ctl_dry_runs(bench_ctl_t *ctl, 44 size_t dry_runs) 45{ 46 ctl->dry_runs = dry_runs; 47} 48 49bool bench_ctl_add_run(bench_ctl_t *ctl, 50 cycles_t* result) 51{ 52 cycles_t *dst; 53 54 if (ctl->result_count == ctl->min_runs) { 55 return true; 56 } 57 58 dst = ctl->data + ctl->result_count * ctl->result_dimensions; 59 memcpy(dst, result, sizeof(dst) * ctl->result_dimensions); 60 61 ctl->result_count++; 62 63 return ctl->result_count == ctl->min_runs; 64} 65 66void bench_ctl_dump_csv(bench_ctl_t *ctl, 67 const char *prefix, 68 uint64_t tscperus) 69{ 70 size_t i, j; 71 cycles_t *v; 72 size_t dim = ctl->result_dimensions; 73 74 for (i = 0; i < ctl->result_count; i++) { 75 printf("%s", prefix); 76 77 v = ctl->data + i * dim; 78 for (j = 0; j < dim; j++) { 79 printf("%"PRIuCYCLES", %f", v[j], v[j]/(float)tscperus); 80 if (j != dim - 1) { 81 printf(","); 82 } 83 } 84 printf("\n"); 85 } 86 fflush(stdout); 87} 88 89 90/** 91 * Return bin index for this value. We keep two more bins than bin count, one 92 * for the values below min (bin_count), and one for those above (bin_count + 1) 93 */ 94static inline size_t val2bin(size_t bin_count, cycles_t min, cycles_t max, 95 cycles_t value) 96{ 97 cycles_t bin_width = (max - min) / bin_count; 98 99 if (value < min) { 100 return bin_count; 101 } else if (value >= max) { 102 return bin_count + 1; 103 } 104 105 return (value - min) / bin_width; 106} 107 108/** Return the lower value for a bin */ 109static inline cycles_t bin2val(size_t bin_count, cycles_t min, cycles_t max, 110 size_t idx) 111{ 112 cycles_t bin_width = (max - min) / bin_count; 113 return min + idx * bin_width; 114} 115 116/** 117 * Returns a newly allocated array of bins, filled with the desired values. 118 * The array has bin_count + 2 elements. result[bin_count] contains the number 119 * of values below the minium, result[bin_count + 1] those above the maximum. 120 * The caller is responsible for freeing the array. 121 */ 122static cycles_t *do_bincounting(bench_ctl_t *ctl, 123 size_t dimension, 124 size_t bin_count, 125 cycles_t min, 126 cycles_t max) 127{ 128 cycles_t *bins; 129 size_t i; 130 cycles_t *v; 131 132 bins = calloc(bin_count + 2, sizeof(size_t)); 133 134 for (i = 0; i < ctl->result_count; i++) { 135 v = ctl->data + (ctl->result_dimensions * i + dimension); 136 bins[val2bin(bin_count, min, max, *v)]++; 137 } 138 139 return bins; 140} 141 142static cycles_t *get_array(bench_ctl_t *ctl, 143 size_t dimension) 144{ 145 cycles_t *array = calloc(ctl->result_count, sizeof(cycles_t)); 146 assert(array != NULL); 147 148 for (size_t i = 0; i < ctl->result_count; i++) { 149 array[i] = *(ctl->data + (ctl->result_dimensions * i 150 + dimension)); 151 } 152 return array; 153} 154 155static cycles_t *do_sorting(cycles_t *array, 156 size_t len) 157{ 158 size_t i, j; 159 cycles_t *sorted_array = array; 160 cycles_t temp_holder; 161 162 163 // sort the array 164 for (i = 0; i < len; ++i) { 165 for (j = i; j < len; ++j) { 166 if (sorted_array[i] > sorted_array[j]) { 167 temp_holder = sorted_array[i]; 168 sorted_array[i] = sorted_array[j]; 169 sorted_array[j] = temp_holder; 170 } 171 } // end for: j 172 } // end for: i 173 return sorted_array; 174} // end function: do_sorting 175 176void bench_ctl_dump_analysis(bench_ctl_t *ctl, 177 size_t dimension, 178 const char *prefix, 179 cycles_t tscperus) 180{ 181 size_t len = ctl->result_count; 182 cycles_t *array = get_array(ctl, dimension); 183 184#if BENCH_DUMP_OCTAVE 185 cycles_t avg, std_dev; 186 bench_stddev(array, len, 0, &avg, &std_dev); 187#endif 188 189 cycles_t *final_array = do_sorting(array, len); 190 191 size_t max99 = (size_t)((0.99 * len) + 0.5); 192#if BENCH_DUMP_OCTAVE 193 194 // printf("\% [name] [runs] [avg] [stdev] [min] [med] [P99] [max]\n"); 195 196 printf("%% %s\n%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64 197 ", %"PRIu64"; \n", prefix,(uint64_t)len, avg, std_dev, final_array[len/2], 198 final_array[0], final_array[max99-1], final_array[len-1]); 199 200 printf("%% %s\n%"PRIu64", %f, %f, %f, %f, %f, %f;\n",prefix, (uint64_t)len, 201 (avg /(float)tscperus), (std_dev / ((float)tscperus*(float)tscperus)), 202 (final_array[len/2]/(float)tscperus), (final_array[0]/(float)tscperus), 203 (final_array[max99-1]/(float)tscperus),(final_array[len-1]/(float)tscperus)); 204#else 205 printf("run [%"PRIu64"], med_pos[%"PRIu64"], min_pos[%"PRIu64"], " 206 "P99[%"PRIu64"], max[%"PRIu64"]\n", 207 (uint64_t)len, 208 (uint64_t)(len/2), 209 (uint64_t)0, 210 (uint64_t)(max99-1), 211 (uint64_t)(len-1)); 212 213 printf("run [%"PRIu64"], med[%"PRIu64"], min[%"PRIu64"], " 214 "P99[%"PRIu64"], max[%"PRIu64"]\n", 215 (uint64_t)len, 216 (uint64_t)final_array[len/2], 217 (uint64_t)final_array[0], 218 (uint64_t)final_array[max99-1], 219 (uint64_t)final_array[len-1]); 220 221 printf("run [%"PRIu64"], med[%f], min[%f], " 222 "P99[%f], max[%f]\n", 223 (uint64_t)len, 224 (final_array[len/2]/(float)tscperus), 225 (final_array[0]/(float)tscperus), 226 (final_array[max99-1]/(float)tscperus), 227 (final_array[len-1]/(float)tscperus)); 228 229 printf("%s, %"PRIu64" %f %f %f %f\n", 230 prefix, 231 (uint64_t)len, 232 (final_array[len/2]/(float)tscperus), 233 (final_array[0]/(float)tscperus), 234 (final_array[max99-1]/(float)tscperus), 235 (final_array[len-1]/(float)tscperus)); 236#endif 237} // end function: bench_ctl_dump_analysis 238 239 240void bench_ctl_dump_csv_bincounting(bench_ctl_t *ctl, 241 size_t dimension, 242 size_t bin_count, 243 cycles_t min, 244 cycles_t max, 245 const char *prefix, 246 cycles_t tscperus) 247{ 248 cycles_t *bins; 249 size_t i; 250 cycles_t val; 251 252 bins = do_bincounting(ctl, dimension, bin_count, min, max); 253 254 printf("%sbellow,%"PRIuCYCLES"\n", prefix, bins[bin_count]); 255 printf("%sabove,%"PRIuCYCLES"\n", prefix, bins[bin_count+1]); 256 for (i = 0; i < bin_count; i++) { 257 if (bins[i] > 0) { 258 val = bin2val(bin_count, min, max, i); 259 printf("%s%"PRIuCYCLES",%"PRIuCYCLES", %f\n", prefix, val, bins[i], 260 val/ (float)tscperus); 261 } 262 } 263 264 free(bins); 265} 266 267