1/*
2 * libbenchtsc is a simple benchmarking library that uses the rdtsc
3 * x86 instruction.
4 * Copyright (c) 2014, Simon Gerber <gesimu@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19*/
20
21#ifndef BENCH_RDTSC_H
22#define BENCH_RDTSC_H
23#include <math.h>
24#include <stdbool.h>
25#include <inttypes.h>
26#include <stdlib.h>
27
28extern bool rdtscp_flag;
29extern double ticks_per_nano;
30
31static inline uint64_t rdtscp(void)
32{
33    uint32_t eax, edx;
34    __asm volatile ("rdtscp" : "=a" (eax), "=d" (edx) :: "ecx");
35    return ((uint64_t)edx << 32) | eax;
36}
37
38static inline uint64_t rdtsc(void)
39{
40    uint32_t eax, edx;
41    __asm volatile ("rdtsc" : "=a" (eax), "=d" (edx));
42    return ((uint64_t)edx << 32) | eax;
43}
44
45
46static inline uint64_t bench_tsc()
47{
48    if (rdtscp_flag) {
49        return rdtscp();
50    } else {
51        return rdtsc();
52    }
53}
54
55static inline void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx,
56                         uint32_t *ecx, uint32_t *edx)
57{
58    // make it possible to omit certain return registers
59    uint32_t a, b, c, d;
60    if (eax == NULL) {
61        eax = &a;
62    }
63    if (ebx == NULL) {
64        ebx = &b;
65    }
66    if (ecx == NULL) {
67        ecx = &c;
68    }
69    if (edx == NULL) {
70        edx = &d;
71    }
72    __asm volatile("cpuid"
73                   : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
74                   : "a" (function)
75                   );
76}
77
78static inline double bench_tsc_to_ms(uint64_t tsc)
79{
80    return tsc / (ticks_per_nano * 1e6);
81}
82
83void bench_init(void);
84
85struct bench_calc_st;
86double bench_avg(double *measurements, int runs, struct bench_calc_st *st);
87double bench_sdev(double *measurements, int runs, struct bench_calc_st *st);
88size_t bench_calc_st_sz(void);
89
90#endif // BENCH_RDTSC_H
91