1/**
2 * \file
3 * \brief Bench library initialization.
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <limits.h>
17#include <barrelfish/barrelfish.h>
18#include <bench/bench.h>
19#include <bench/bench_arch.h>
20
21static cycles_t tsc_overhead;
22
23static uint8_t bench_is_initialized = 0;
24
25/**
26 * \brief Measure overhead of taking timestamp
27 */
28static void measure_tsc(void)
29{
30    uint64_t begin;
31    uint64_t end;
32
33    begin = bench_tsc();
34    for(int i = 0; i < 1000; i++) {
35        end = bench_tsc();
36    }
37
38    tsc_overhead = (end - begin) / 1000;
39}
40
41/**
42 * \brief Initialize benchmarking library
43 *
44 * \bug x86 specific
45 */
46void bench_init(void)
47{
48    if (bench_is_initialized) {
49        return;
50    }
51
52    bench_arch_init();
53
54    /* Measure overhead of taking timestamps */
55    measure_tsc();
56
57    bench_is_initialized = 1;
58}
59
60/**
61 * Return the measured tsc overhead
62 */
63cycles_t bench_tscoverhead(void)
64{
65    if (!bench_is_initialized) {
66        bench_init();
67    }
68    return tsc_overhead;
69}
70
71/**
72 * \brief computes the differences of two time stamps with respecting overflow
73 *
74 * This function also accounts for the overhead when taking timestamps
75 *
76 * \param tsc_start timestamp of start
77 * \param tsc_end   timestamp of end
78 *
79 * \return elaped cycles
80 */
81cycles_t bench_time_diff(cycles_t tsc_start, cycles_t tsc_end)
82{
83    if (!bench_is_initialized) {
84        bench_init();
85    }
86
87    cycles_t result;
88    if (tsc_end < tsc_start) {
89        result = (LONG_MAX - tsc_start) + tsc_end - bench_tscoverhead();
90    } else {
91        result = (tsc_end - tsc_start - bench_tscoverhead());
92    }
93    return result;
94}
95
96/**
97 * \brief Compute averages
98 *
99 * If certain datapoints should be ignored, they should be marked with
100 * #BENCH_IGNORE_WATERMARK
101 */
102cycles_t bench_avg(cycles_t *array, size_t len)
103{
104    cycles_t sum = 0;
105    size_t count = 0;
106
107    // Discarding some initial observations
108    for (size_t i = len >> 3; i < len; i++) {
109        if (array[i] != BENCH_IGNORE_WATERMARK) {
110            sum += array[i];
111            count++;
112        }
113    }
114
115    return sum / count;
116}
117
118/**
119 * \brief Compute variance
120 *
121 * If certain datapoints should be ignored, they should be marked with
122 * #BENCH_IGNORE_WATERMARK
123 */
124cycles_t bench_variance(cycles_t *array, size_t len)
125{
126    cycles_t avg = bench_avg(array, len);
127
128    cycles_t sum = 0;
129    size_t count = 0;
130
131    // Discard some initial observations
132    for (size_t i = len >> 3; i < len; i++) {
133        if (array[i] != BENCH_IGNORE_WATERMARK) {
134            sum += array[i] * array[i];
135            count++;
136        }
137    }
138
139    return (sum / count) - (avg * avg);
140}
141
142/**
143 * \brief computes the standard deviation s^2 of the sample data
144 *
145 * \param array         array of data to analyze
146 * \param len           size of the array
147 * \param correction    apply Bessel's correction (using N-1 instead of N)
148 * \param ret_avg       returns the average of the sample
149 * \param ret_stddev    returns the standard deviation squared of the sample
150 */
151void bench_stddev(cycles_t *array, size_t len, uint8_t correction,
152                  cycles_t *ret_avg, cycles_t *ret_stddev)
153{
154    cycles_t avg = bench_avg(array, len);
155
156    cycles_t sum = 0;
157    size_t count = 0;
158    /// discard some initiali observations
159    for (size_t i = len >> 3; i < len; i++) {
160        if (array[i] != BENCH_IGNORE_WATERMARK) {
161            cycles_t subsum = array[i] - avg;
162            sum += (subsum * subsum);
163            count++;
164        }
165    }
166
167
168
169    cycles_t std_dev = 0;
170    if (correction && count > 1) {
171        std_dev = sum / (count - 1);
172    } else {
173        std_dev = sum / count;
174    }
175
176    if (ret_avg) {
177        *ret_avg = avg;
178    }
179
180    if (ret_stddev) {
181        *ret_stddev = std_dev;
182    }
183}
184
185
186
187/**
188 * \brief Compute minimum
189 *
190 * If certain datapoints should be ignored, they should be marked with
191 * #BENCH_IGNORE_WATERMARK
192 */
193cycles_t bench_min(cycles_t *array, size_t len)
194{
195    size_t i = len >> 3;
196    cycles_t min = (cycles_t) -1ULL;
197
198    for (; i < len; i++) {
199        if (array[i] != BENCH_IGNORE_WATERMARK && array[i] < min) {
200            min = array[i];
201        }
202    }
203
204    return min;
205}
206
207/**
208 * \brief Compute maximum
209 *
210 * If certain datapoints should be ignored, they should be marked with
211 * #BENCH_IGNORE_WATERMARK
212 */
213cycles_t bench_max(cycles_t *array, size_t len)
214{
215    size_t i = len >> 3;
216    cycles_t max = 0;
217
218    for (; i < len; i++) {
219        if (array[i] != BENCH_IGNORE_WATERMARK && array[i] > max) {
220            max = array[i];
221        }
222    }
223
224    return max;
225}
226