Skip to content

Commit dcdbd63

Browse files
committed
Added initial code base.
1 parent 60d6f0d commit dcdbd63

File tree

3 files changed

+249
-0
lines changed

3 files changed

+249
-0
lines changed

Makefile

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#
2+
# libbenchtsc is a simple benchmarking library that uses the rdtsc
3+
# x86 instruction.
4+
# Copyright (c) 2014, Simon Gerber <[email protected]>
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+
CFLAGS=-Wall -O2 -std=gnu11
22+
PREFIX=/home/gerbesim/.local
23+
VERSION=1
24+
MINOR=0
25+
LIBFNAME=libbenchtsc.so.$(VERSION).$(MINOR)
26+
LIBSONAME=libbenchtsc.so.$(VERSION)
27+
28+
$(LIBFNAME): bench_rdtsc.o
29+
gcc $(CFLAGS) -shared -Wl,-soname,$(LIBSONAME) -o $(LIBFNAME) bench_rdtsc.o -lm
30+
31+
bench_rdtsc.o: bench_rdtsc.c
32+
gcc $(CFLAGS) -fpic -fPIC -c bench_rdtsc.c
33+
34+
install: $(LIBFNAME) bench_rdtsc.h
35+
install -m 644 -C $(LIBFNAME) -D $(PREFIX)/lib/$(LIBFNAME)
36+
ldconfig -l $(PREFIX)/lib/$(LIBFNAME)
37+
mkdir -p $(PREFIX)/include
38+
install -m 644 -C bench_rdtsc.h $(PREFIX)/include
39+

bench_rdtsc.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* libbenchtsc is a simple benchmarking library that uses the rdtsc
3+
* x86 instruction.
4+
* Copyright (c) 2014, Simon Gerber <[email protected]>
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+
#include "bench_rdtsc.h"
22+
#include <time.h>
23+
24+
double ticks_per_nano = 0.0;
25+
bool rdtscp_flag = false;
26+
27+
const int NANO_SECONDS_IN_SEC = 1000000000;
28+
/* returns a static buffer of struct timespec with the time difference of ts1 and ts2
29+
ts1 is assumed to be greater than ts2 */
30+
static struct timespec *TimeSpecDiff(struct timespec *ts1, struct timespec *ts2)
31+
{
32+
static struct timespec ts;
33+
ts.tv_sec = ts1->tv_sec - ts2->tv_sec;
34+
ts.tv_nsec = ts1->tv_nsec - ts2->tv_nsec;
35+
if (ts.tv_nsec < 0) {
36+
ts.tv_sec--;
37+
ts.tv_nsec += NANO_SECONDS_IN_SEC;
38+
}
39+
return &ts;
40+
}
41+
42+
static void calibrate_ticks(void)
43+
{
44+
struct timespec begints, endts;
45+
uint64_t begin = 0, end = 0;
46+
clock_gettime(CLOCK_MONOTONIC, &begints);
47+
begin = bench_tsc();
48+
uint64_t i;
49+
for (i = 0; i < 1000000; i++); /* must be CPU intensive */
50+
end = bench_tsc();
51+
clock_gettime(CLOCK_MONOTONIC, &endts);
52+
struct timespec *tmpts = TimeSpecDiff(&endts, &begints);
53+
uint64_t nsecElapsed = tmpts->tv_sec * 1000000000LL + tmpts->tv_nsec;
54+
ticks_per_nano = (double)(end - begin)/(double)nsecElapsed;
55+
}
56+
57+
void bench_init(void)
58+
{
59+
uint32_t eax, ebx, ecx, edx;
60+
// Check for rdtscp instruction
61+
cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
62+
if ((edx >> 27) & 1) {
63+
rdtscp_flag = true;
64+
} else {
65+
rdtscp_flag = false;
66+
}
67+
68+
calibrate_ticks();
69+
}
70+
71+
struct bench_calc_st {
72+
double *series;
73+
int runs;
74+
double avg;
75+
double sdev;
76+
};
77+
78+
static void calculate_(double *measurements, int runs, struct bench_calc_st *st)
79+
{
80+
double mean = 0.0, M2 = 0.0;
81+
for (int i = 0; i < runs; i++) {
82+
double delta = measurements[i] - mean;
83+
mean = mean + delta / (i+1);
84+
M2 = M2 + delta*(measurements[i]-mean);
85+
}
86+
87+
st->series = measurements;
88+
st->runs = runs;
89+
st->avg = mean;
90+
st->sdev = sqrt(M2/(runs-1));
91+
}
92+
93+
double bench_avg(double *measurements, int runs, struct bench_calc_st *st)
94+
{
95+
struct bench_calc_st tmp = { 0 };
96+
if (!st) {
97+
st = &tmp;
98+
}
99+
if (st->series != measurements || st->runs != runs) {
100+
calculate_(measurements, runs, st);
101+
}
102+
return st->avg;
103+
}
104+
105+
double bench_sdev(double *measurements, int runs, struct bench_calc_st *st)
106+
{
107+
struct bench_calc_st tmp = { 0 };
108+
if (!st) {
109+
st = &tmp;
110+
}
111+
if (st->series != measurements || st->runs != runs) {
112+
calculate_(measurements, runs, st);
113+
}
114+
return st->sdev;
115+
}
116+
117+
size_t bench_calc_st_sz(void)
118+
{
119+
return sizeof(struct bench_calc_st);
120+
}

bench_rdtsc.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* libbenchtsc is a simple benchmarking library that uses the rdtsc
3+
* x86 instruction.
4+
* Copyright (c) 2014, Simon Gerber <[email protected]>
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+
28+
extern bool rdtscp_flag;
29+
extern double ticks_per_nano;
30+
31+
static 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+
38+
static 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+
46+
static inline uint64_t bench_tsc()
47+
{
48+
if (rdtscp_flag) {
49+
return rdtscp();
50+
} else {
51+
return rdtsc();
52+
}
53+
}
54+
55+
static 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+
78+
static inline double bench_tsc_to_ms(uint64_t tsc)
79+
{
80+
return tsc / (ticks_per_nano * 1e6);
81+
}
82+
83+
void bench_init(void);
84+
85+
struct bench_calc_st;
86+
double bench_avg(double *measurements, int runs, struct bench_calc_st *st);
87+
double bench_sdev(double *measurements, int runs, struct bench_calc_st *st);
88+
size_t bench_calc_st_sz(void);
89+
90+
#endif // BENCH_RDTSC_H

0 commit comments

Comments
 (0)