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, Universitaetstrasse 6, 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    cycles_t avg, std_dev;
185    bench_stddev(array, len, 0, &avg, &std_dev);
186
187    cycles_t *final_array =  do_sorting(array, len);
188
189    size_t max99 = (size_t)((0.99 * len) + 0.5);
190#if BENCH_DUMP_OCTAVE
191
192     printf("%% [name]  [runs]  [avg]  [stdev]  [min]  [med]  [P99]  [max]\n");
193
194    printf("%% %s\n%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
195           ", %"PRIu64"; \n", prefix,(uint64_t)len, avg, std_dev, final_array[len/2],
196           final_array[0], final_array[max99-1], final_array[len-1]);
197
198    printf("%% %s\n%"PRIu64", %f, %f, %f, %f, %f, %f;\n",prefix, (uint64_t)len,
199           (avg /(float)tscperus), (std_dev / ((float)tscperus*(float)tscperus)),
200           (final_array[len/2]/(float)tscperus), (final_array[0]/(float)tscperus),
201           (final_array[max99-1]/(float)tscperus),(final_array[len-1]/(float)tscperus));
202#else
203    printf("run [%"PRIu64"], med_pos[%"PRIu64"], min_pos[%"PRIu64"], "
204           "P99[%"PRIu64"], max[%"PRIu64"]\n",
205           (uint64_t)len,
206           (uint64_t)(len/2),
207           (uint64_t)0,
208           (uint64_t)(max99-1),
209           (uint64_t)(len-1));
210
211    printf("run [%"PRIu64"], avg[%"PRIu64"], med[%"PRIu64"], min[%"PRIu64"], "
212           "P99[%"PRIu64"], max[%"PRIu64"], stdev[%"PRIu64"]\n",
213           (uint64_t)len,
214           (uint64_t)avg,
215           (uint64_t)final_array[len/2],
216           (uint64_t)final_array[0],
217           (uint64_t)final_array[max99-1],
218           (uint64_t)final_array[len-1],
219           (uint64_t)std_dev);
220
221    printf("run [%"PRIu64"], avg[%f], med[%f], min[%f], "
222           "P99[%f], max[%f], stdev[%f]\n",
223           (uint64_t)len,
224           avg / (float)tscperus,
225           (final_array[len/2]/(float)tscperus),
226           (final_array[0]/(float)tscperus),
227           (final_array[max99-1]/(float)tscperus),
228           (final_array[len-1]/(float)tscperus),
229           std_dev / (float)tscperus);
230
231    printf("%s, %"PRIu64" %f %f %f %f\n",
232           prefix,
233           (uint64_t)len,
234           (final_array[len/2]/(float)tscperus),
235           (final_array[0]/(float)tscperus),
236           (final_array[max99-1]/(float)tscperus),
237           (final_array[len-1]/(float)tscperus));
238#endif
239} // end function: bench_ctl_dump_analysis
240
241
242void bench_ctl_dump_csv_bincounting(bench_ctl_t *ctl,
243                                    size_t dimension,
244                                    size_t bin_count,
245                                    cycles_t min,
246                                    cycles_t max,
247                                    const char *prefix,
248                                    cycles_t tscperus)
249{
250    cycles_t *bins;
251    size_t i;
252    cycles_t val;
253
254    bins = do_bincounting(ctl, dimension, bin_count, min, max);
255
256    printf("%sbellow,%"PRIuCYCLES"\n", prefix, bins[bin_count]);
257    printf("%sabove,%"PRIuCYCLES"\n", prefix, bins[bin_count+1]);
258    for (i = 0; i < bin_count; i++) {
259        if (bins[i] > 0) {
260            val = bin2val(bin_count, min, max, i);
261            printf("%s%"PRIuCYCLES",%"PRIuCYCLES", %f\n", prefix, val, bins[i],
262                   val/ (float)tscperus);
263        }
264    }
265
266    free(bins);
267}
268
269