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