mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-09 00:00:03 +01:00
add hourglass benchmark
- see http://static.usenix.org/publications/library/proceedings/usenix02/tech/freenix/regehr.html
This commit is contained in:
parent
2946296f75
commit
ac2c7ddf72
17 changed files with 1179 additions and 3 deletions
1
hermit/.gitignore
vendored
1
hermit/.gitignore
vendored
|
@ -20,5 +20,6 @@ usr/tests/hellof
|
|||
usr/tests/jacobi
|
||||
usr/tests/thr_hello
|
||||
usr/benchmarks/stream
|
||||
usr/benchmarks/hg
|
||||
usr/x86/
|
||||
usr/tmp/
|
||||
|
|
|
@ -43,7 +43,7 @@ endif
|
|||
|
||||
default: all
|
||||
|
||||
all: stream
|
||||
all: stream hg
|
||||
|
||||
stream.o: stream.c
|
||||
@echo [CC] $@
|
||||
|
@ -56,13 +56,20 @@ stream: stream.o
|
|||
$Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@
|
||||
$Qchmod a-x $@.sym
|
||||
|
||||
hg: hg.o hist.o rdtsc.o run.o init.o opt.o report.o setup.o
|
||||
@echo [LD] $@
|
||||
$Q$(CC_FOR_TARGET) $(LDFLAGS_FOR_TARGET) $(CFLAGS_FOR_TARGET) -o $@ $< hist.o rdtsc.o run.o init.o opt.o report.o setup.o
|
||||
$Q$(OBJCOPY_FOR_TARGET) $(KEEP_DEBUG) $@ $@.sym
|
||||
$Q$(OBJCOPY_FOR_TARGET) $(STRIP_DEBUG) $@
|
||||
$Qchmod a-x $@.sym
|
||||
|
||||
clean:
|
||||
@echo Cleaning benchmarks
|
||||
$Q$(RM) stream *.sym *.o *~
|
||||
$Q$(RM) stream hg *.sym *.o *~
|
||||
|
||||
veryclean:
|
||||
@echo Propper cleaning benchmarks
|
||||
$Q$(RM) stream *.sym *.o *~
|
||||
$Q$(RM) stream hg *.sym *.o *~
|
||||
|
||||
depend:
|
||||
$Q$(CC_FOR_TARGET) -MM $(CFLAGS_FOR_TARGET) *.c > Makefile.dep
|
||||
|
|
51
hermit/usr/benchmarks/hg.c
Normal file
51
hermit/usr/benchmarks/hg.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: main.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 14:59:20
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "opt.h"
|
||||
#include "init.h"
|
||||
#include "setup.h"
|
||||
#include "run.h"
|
||||
#include "report.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct opt opts = {0};
|
||||
struct result results = {0};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
printf("hourglass\n");
|
||||
|
||||
opt(argc, argv, &opts);
|
||||
init(&opts);
|
||||
|
||||
report_params(&opts);
|
||||
|
||||
setup(&opts);
|
||||
run(&opts, &results);
|
||||
setdown(&opts);
|
||||
|
||||
report(&opts, &results);
|
||||
|
||||
run_free(&opts, &results);
|
||||
|
||||
deinit(&opts);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
78
hermit/usr/benchmarks/hist.c
Normal file
78
hermit/usr/benchmarks/hist.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hist.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 26.07.2014 20:02:34
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "hist.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
static const struct opt *opts;
|
||||
static uint32_t *hists;
|
||||
|
||||
uint32_t *hist_alloc(const struct opt *opt)
|
||||
{
|
||||
opts = opt;
|
||||
hists = calloc(opt->hist_cnt, sizeof(uint32_t));
|
||||
hist_reset();
|
||||
return hists;
|
||||
}
|
||||
|
||||
int hist_reset(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i=0; i<opts->hist_cnt; i++) {
|
||||
hists[i] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hist_add(uint64_t t)
|
||||
{
|
||||
t /= opts->hist_width;
|
||||
if (t > opts->hist_cnt-1) t = opts->hist_cnt-1;
|
||||
hists[t]++;
|
||||
}
|
||||
|
||||
int hist_print(void)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned max=0;
|
||||
const size_t bar_width = 30;
|
||||
char bar[bar_width+1];
|
||||
|
||||
for (i=0; i<opts->hist_cnt; i++) {
|
||||
if (hists[i] > max) max = hists[i];
|
||||
}
|
||||
max = (unsigned)ceil(log10((double)max));
|
||||
if (max == 0) max = 1;
|
||||
memset(bar, '*', bar_width);
|
||||
bar[bar_width] = 0;
|
||||
|
||||
printf("Histogram (%u bins with %u ticks each)\n", opts->hist_cnt, opts->hist_width);
|
||||
for (i=0; i<opts->hist_cnt; i++) {
|
||||
printf(" %5u : %5u..%5u : %-10u %s\n", i,
|
||||
(unsigned)(i*opts->hist_width),
|
||||
(unsigned)((i+1)*opts->hist_width-1),
|
||||
(unsigned)(hists[i]),
|
||||
(char*)bar+(unsigned)(bar_width-((log10(hists[i]+1.)*bar_width)/max)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
31
hermit/usr/benchmarks/hist.h
Normal file
31
hermit/usr/benchmarks/hist.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: hist.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 26.07.2014 20:02:48
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HIST_H__
|
||||
#define __HIST_H__
|
||||
|
||||
#include "opt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t *hist_alloc(const struct opt *opt);
|
||||
int hist_reset(void);
|
||||
void hist_add(uint64_t t);
|
||||
int hist_print(void);
|
||||
|
||||
#endif // __HIST_H__
|
47
hermit/usr/benchmarks/init.c
Normal file
47
hermit/usr/benchmarks/init.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: init.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:06:05
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "init.h"
|
||||
#include "rdtsc.h"
|
||||
|
||||
|
||||
int init(struct opt *opt)
|
||||
{
|
||||
/*
|
||||
* initialize (if required)
|
||||
* e.g. read number of processors available or cache parameters
|
||||
*/
|
||||
|
||||
opt->tps = rdtsc_ticks_per_sec(); // does not work reliably...
|
||||
//opt->tps = 2530000000;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int deinit(struct opt *opt)
|
||||
{
|
||||
/*
|
||||
* de-initialize (if required)
|
||||
* e.g. free allocated resources
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
27
hermit/usr/benchmarks/init.h
Normal file
27
hermit/usr/benchmarks/init.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: init.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:05:13
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __INIT_H__
|
||||
#define __INIT_H__
|
||||
|
||||
#include "opt.h"
|
||||
|
||||
int init(struct opt *opt);
|
||||
int deinit(struct opt *opt);
|
||||
|
||||
#endif // __INIT_H__
|
124
hermit/usr/benchmarks/opt.c
Normal file
124
hermit/usr/benchmarks/opt.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: opt.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:01:32
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "opt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#ifdef __hermit__
|
||||
char *basename(char *path)
|
||||
{
|
||||
char *p;
|
||||
if( path == NULL || *path == '\0' )
|
||||
return ".";
|
||||
p = path + strlen(path) - 1;
|
||||
while( *p == '/' ) {
|
||||
if( p == path )
|
||||
return path;
|
||||
*p-- = '\0';
|
||||
}
|
||||
while( p >= path && *p != '/' )
|
||||
p--;
|
||||
return p + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int opt(int argc, char *argv[], struct opt *opt)
|
||||
{
|
||||
char c;
|
||||
char *p;
|
||||
|
||||
opt->secs = 4;
|
||||
opt->mode = stat;
|
||||
opt->threshold = 0;
|
||||
|
||||
opt->hist_cnt = 100;
|
||||
opt->hist_width = 50;
|
||||
|
||||
opt->list_cnt = 1000;
|
||||
|
||||
|
||||
/*
|
||||
* read command line arguments and store them in opt
|
||||
*/
|
||||
|
||||
while ((c = getopt(argc, argv, "b:c:d:hr:t:")) != -1) {
|
||||
switch (c) {
|
||||
case 'h' :
|
||||
printf("usage: %s <options>\n", basename(argv[0]));
|
||||
printf(" -h help \n");
|
||||
printf(" -d N duration (in sec or 1m, 1h) \n");
|
||||
printf(" -r R report: hist, list\n");
|
||||
printf(" -c N count (hist or list)\n");
|
||||
printf(" -b N hist bin width (in ticks)\n");
|
||||
printf(" -t N threshold (in ticks)\n");
|
||||
exit(1);
|
||||
break;
|
||||
case 'd' :
|
||||
opt->secs = (unsigned)strtoul(optarg, &p, 0);
|
||||
if (p[0] == 'm' || p[0] == 'M') opt->secs *= 60u;
|
||||
else if (p[0] == 'h' || p[0] == 'H') opt->secs *= (60u*60u);
|
||||
else if (strlen(p) > 0) {
|
||||
printf("ERROR: Parameter: unrecognized characters in time: '%s'\n", p);
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case 'r' :
|
||||
if (strncmp(optarg, "hist", 4) == 0) {
|
||||
opt->mode = hist;
|
||||
} else if (strncmp(optarg, "list", 4) == 0) {
|
||||
opt->mode = list;
|
||||
}
|
||||
break;
|
||||
case 'c' :
|
||||
if (opt->mode == hist) {
|
||||
opt->hist_cnt = (unsigned)strtoul(optarg, &p, 0);
|
||||
} else if (opt->mode == list) {
|
||||
opt->list_cnt = (unsigned)strtoul(optarg, &p, 0);
|
||||
}
|
||||
break;
|
||||
case 'b' :
|
||||
opt->hist_width = (unsigned)strtoul(optarg, &p, 0);
|
||||
break;
|
||||
case 't' :
|
||||
opt->threshold = (unsigned)strtoul(optarg, &p, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->mode == hist) {
|
||||
if (opt->hist_cnt == 0) {
|
||||
opt->hist_cnt = 1;
|
||||
}
|
||||
if (opt->hist_width == 0) {
|
||||
opt->hist_width = 1;
|
||||
}
|
||||
} else if (opt->mode == list) {
|
||||
if (opt->list_cnt == 0) {
|
||||
opt->list_cnt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
38
hermit/usr/benchmarks/opt.h
Normal file
38
hermit/usr/benchmarks/opt.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: opt.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:02:15
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __OPT_H__
|
||||
#define __OPT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct opt {
|
||||
unsigned secs;
|
||||
enum {stat, hist, list} mode;
|
||||
uint64_t tps;
|
||||
uint64_t threshold;
|
||||
|
||||
unsigned hist_cnt;
|
||||
unsigned hist_width;
|
||||
|
||||
unsigned list_cnt;
|
||||
};
|
||||
|
||||
int opt(int argc, char *argv[], struct opt *opt);
|
||||
|
||||
#endif // __OPT_H__
|
314
hermit/usr/benchmarks/rdtsc.c
Normal file
314
hermit/usr/benchmarks/rdtsc.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: rdtsc.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 31.01.2011 10:56:58
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#define _SVID_SOURCE
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include "rdtsc.h"
|
||||
|
||||
static inline void cpuid(unsigned func, unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) {
|
||||
__asm__ volatile ("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(func));
|
||||
}
|
||||
|
||||
static inline uint32_t cpuid_edx(uint32_t code) {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
cpuid(code, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
return edx;
|
||||
}
|
||||
|
||||
static uint64_t tps = 0;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* === FUNCTION ======================================================================
|
||||
* Name: second()
|
||||
* Description: returns a double representation of gettimeofday (seconds.microseconds)
|
||||
* =====================================================================================
|
||||
*/
|
||||
static inline double second()
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
return tv.tv_sec + 1e-6*tv.tv_usec;
|
||||
}
|
||||
|
||||
/*
|
||||
* === FUNCTION ======================================================================
|
||||
* Name: selectsleep(us)
|
||||
* Description: calls select() to sleep (wait) the given microseconds
|
||||
* =====================================================================================
|
||||
*/
|
||||
static inline void selectsleep(unsigned us)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = us;
|
||||
select(0,0,0,0,&tv); // portable way to sleep with subsecond precision
|
||||
}
|
||||
|
||||
/*
|
||||
* === FUNCTION ======================================================================
|
||||
* Name: rdtsc_ticks_per_sec()
|
||||
* Description: uses least squares regressen to measure the frequency of the TSC
|
||||
* =====================================================================================
|
||||
*/
|
||||
uint64_t rdtsc_ticks_per_sec(void)
|
||||
{
|
||||
double sumx = 0, sumy = 0;
|
||||
double sumxx = 0, sumxy = 0;
|
||||
double slope;
|
||||
// least squared linear regression taken from mcert/misc/realfeed/realfeel.c
|
||||
|
||||
const unsigned n = 30;
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
double breal, real, ticks;
|
||||
uint64_t bticks = 0, aticks = 0;
|
||||
rdtsc(&bticks);
|
||||
breal = second();
|
||||
|
||||
selectsleep((unsigned)(10000 + drand48() * 20000));
|
||||
|
||||
rdtsc(&aticks);
|
||||
real = second() -breal;
|
||||
ticks = (double)(aticks - bticks);
|
||||
|
||||
sumx += real;
|
||||
sumxx += real * real;
|
||||
sumxy += real * ticks;
|
||||
sumy += ticks;
|
||||
}
|
||||
slope = ((sumxy - (sumx*sumy) / n) / (sumxx - (sumx*sumx) / n));
|
||||
|
||||
tps = (uint64_t)slope;
|
||||
return tps;
|
||||
}
|
||||
#endif
|
||||
uint64_t rdtsc_ticks_per_sec(void)
|
||||
{
|
||||
#ifdef __hermit__
|
||||
uint64_t tps = (uint64_t) get_cpufreq() * 1000000ULL;
|
||||
|
||||
return tps;
|
||||
#else
|
||||
uint64_t t1, t2, t3, t4;
|
||||
struct timeval tv1, tv2;
|
||||
|
||||
uint64_t diff_tsc, diff_usec;
|
||||
|
||||
rdtsc(&t1);
|
||||
gettimeofday(&tv1, 0);
|
||||
rdtsc(&t2);
|
||||
|
||||
usleep(500000); // 0.5 sec
|
||||
|
||||
rdtsc(&t3);
|
||||
gettimeofday(&tv2, 0);
|
||||
rdtsc(&t4);
|
||||
|
||||
//printf("t2-t1 : %llu\n", (unsigned long long)t2-t1);
|
||||
//printf("t4-t3 : %llu\n", (unsigned long long)t4-t3);
|
||||
|
||||
t1 = (t1+t2)/2;
|
||||
t2 = (t3+t4)/2;
|
||||
|
||||
diff_tsc = t2-t1;
|
||||
|
||||
//printf("diff tsc: %llu\n", (unsigned long long)diff_tsc);
|
||||
|
||||
diff_usec = (tv2.tv_sec - tv1.tv_sec) * 1000000;
|
||||
if (tv2.tv_usec > tv1.tv_usec)
|
||||
diff_usec += tv2.tv_usec - tv1.tv_usec;
|
||||
else
|
||||
diff_usec += tv1.tv_usec - tv2.tv_usec;
|
||||
|
||||
//printf("diff usec: %llu\n",
|
||||
// (unsigned long long)diff_usec);
|
||||
|
||||
return (diff_tsc*1000000) / diff_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* === FUNCTION ======================================================================
|
||||
* Name: rdtsc_max_freq(id)
|
||||
* Description: reads the maximum frequency of given CPU-ID from /sys/.../cpuN/cpufreq
|
||||
* Changes: WASSEN, 24.5.2011: taken from hourglass via irqlab
|
||||
* =====================================================================================
|
||||
*/
|
||||
uint64_t rdtsc_max_freq(int id)
|
||||
{
|
||||
uint64_t mhz = -1;
|
||||
char fname[BUFSIZ];
|
||||
char processor[BUFSIZ];
|
||||
char *buffer, *loc;
|
||||
FILE *fp;
|
||||
double tmhz;
|
||||
int ret;
|
||||
|
||||
sprintf(fname, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", id);
|
||||
|
||||
if (NULL == (fp = fopen(fname, "r"))) {
|
||||
fprintf(stderr, "Can't open <%s>.\n", fname);
|
||||
fprintf(stderr, "Trying </proc/cpuinfo> (not as accurate)\n");
|
||||
|
||||
if(NULL == (fp = fopen("/proc/cpuinfo","r"))) {
|
||||
fprintf(stderr, "Can't open </proc/cpuinfo>.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
buffer = (void *) malloc(sizeof(char) * 1024 * 512);
|
||||
ret = fread(buffer, sizeof(char), 1024 * 512, fp);
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "fread() returned 0: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(processor, "processor\t: %d", id);
|
||||
if(NULL == (loc = strstr(buffer, processor))) {
|
||||
fprintf(stderr, "Unable to parse /proc/cpuinfo\n");
|
||||
return -1;
|
||||
}
|
||||
if(NULL == (loc = strstr(loc, "cpu MHz"))) {
|
||||
fprintf(stderr, "Unable to parse /proc/cpuinfo\n");
|
||||
return -1;
|
||||
}
|
||||
loc += strlen("cpu MHz");
|
||||
while(!isdigit(*loc))
|
||||
loc++;
|
||||
loc--;
|
||||
sscanf(loc, "%lf", &tmhz);
|
||||
mhz = (uint64_t)(tmhz);
|
||||
mhz*=1000;
|
||||
free(buffer);
|
||||
} else {
|
||||
ret = fscanf(fp, "%lld", (unsigned long long*)&mhz);
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "fscanf() returned 0: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return mhz*1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* === FUNCTION ======================================================================
|
||||
* Name: rdtsc_loop(ticks)
|
||||
* Description: waits actively for given TSC ticks
|
||||
* =====================================================================================
|
||||
*/
|
||||
void rdtsc_loop(uint64_t ticks)
|
||||
{
|
||||
uint64_t t_now = 0, t_end;
|
||||
rdtsc(&t_now);
|
||||
t_end = t_now + ticks;
|
||||
while (t_now < t_end) {
|
||||
rdtsc(&t_now);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* === FUNCTION ======================================================================
|
||||
* Name: rdtsc_loop_sec(ticks)
|
||||
* Description: waits actively for given seconds
|
||||
* ATTN: needs rdtsc_ticks_per_sec() unless that function was previously
|
||||
* called (this function MIGHT use syscalls!)
|
||||
* =====================================================================================
|
||||
*/
|
||||
void rdtsc_loop_sec(unsigned seconds)
|
||||
{
|
||||
uint64_t t_now = 0, t_end;
|
||||
rdtsc(&t_now);
|
||||
if (tps == 0) rdtsc_ticks_per_sec();
|
||||
t_end = t_now + (uint64_t)seconds * tps;
|
||||
while (t_now < t_end) {
|
||||
rdtsc(&t_now);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* test if TSC is invariant (return value 1)
|
||||
*/
|
||||
int rdtsc_is_invariant(void) {
|
||||
if (cpuid_edx(0x80000007) & (1 << 8)) { // TSC is invariant
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* measure overhead of *not* serialized rdtsc() (SHL, MOV, OR)
|
||||
*/
|
||||
uint64_t rdtsc_get_overhead(const uint64_t iterations) {
|
||||
uint64_t c;
|
||||
uint64_t tsc_overhead_notserial = 0;
|
||||
uint64_t tsc_start;
|
||||
uint64_t tsc_end;
|
||||
|
||||
if (iterations == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (c = 0; c < iterations; c++) {
|
||||
#if ! __MIC__
|
||||
__asm__ volatile("lfence");
|
||||
#else
|
||||
__asm__ volatile("lock; add $0, 0(%%rsp)" ::: "memory");
|
||||
#endif
|
||||
rdtsc(&tsc_start);
|
||||
rdtsc(&tsc_end);
|
||||
tsc_overhead_notserial += tsc_end - tsc_start;
|
||||
}
|
||||
|
||||
return tsc_overhead_notserial / iterations;
|
||||
}
|
||||
|
||||
/*
|
||||
* measure overhead of serialized rdtsc_serialized() (LFENCE, SHL, MOV, OR, LFENCE)
|
||||
*/
|
||||
uint64_t rdtsc_get_overhead_serialized(const uint64_t iterations) {
|
||||
uint64_t c;
|
||||
uint64_t tsc_overhead_serial = 0;
|
||||
uint64_t tsc_start;
|
||||
uint64_t tsc_end;
|
||||
|
||||
if (iterations == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (c = 0; c < iterations; c++) {
|
||||
rdtsc_serialized(&tsc_start);
|
||||
rdtsc_serialized(&tsc_end);
|
||||
tsc_overhead_serial += tsc_end - tsc_start;
|
||||
}
|
||||
|
||||
return tsc_overhead_serial / iterations;
|
||||
}
|
73
hermit/usr/benchmarks/rdtsc.h
Normal file
73
hermit/usr/benchmarks/rdtsc.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: rdtsc.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 24.01.2011 13:41:30
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef RDTSC_H
|
||||
#define RDTSC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* rdtsc_ticks_per_sec(): measure frequency. Takes below a second.
|
||||
*/
|
||||
uint64_t rdtsc_ticks_per_sec(void) __attribute__((optimize(3)));
|
||||
|
||||
|
||||
typedef union __attribute__((__transparent_union__))
|
||||
{
|
||||
uint64_t *__u64;
|
||||
struct {uint32_t __low; uint32_t __high;} *__u32;
|
||||
} tsc_t;
|
||||
|
||||
/*
|
||||
* rdtsc(): Register-save version (compiler may insert additional push/pop)
|
||||
* (clobbered-registers not given b/c compiler deduces from output-registers)
|
||||
*/
|
||||
static inline void __attribute__((__always_inline__, gnu_inline, optimize(3))) rdtsc(tsc_t tsc)
|
||||
{
|
||||
__asm__ volatile ("rdtsc" : "=a"(tsc.__u32->__low), "=d"(tsc.__u32->__high) );
|
||||
}
|
||||
|
||||
/*
|
||||
* rdtsc_serial(): get RDTSC with leading and rear serializing LFENCE instruction
|
||||
*/
|
||||
static inline void __attribute__((__always_inline__, gnu_inline, optimize(3))) rdtsc_serialized(tsc_t tsc)
|
||||
{
|
||||
#if ! __MIC__
|
||||
__asm__ volatile (
|
||||
"lfence\n\t" // serialize (needs SSE2, available since AMD Athlon64, Intel Core)
|
||||
"rdtsc\n\t"
|
||||
"lfence\n\t"
|
||||
: "=a"(tsc.__u32->__low), "=d"(tsc.__u32->__high) );
|
||||
#else
|
||||
__asm__ volatile (
|
||||
"lock; add $0, 0(%%rsp)\n\t" // serialize
|
||||
"rdtsc\n\t"
|
||||
"lock; add $0, 0(%%rsp)\n\t" // serialize
|
||||
: "=a"(tsc.__u32->__low), "=d"(tsc.__u32->__high) :: "memory" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void rdtsc_loop(uint64_t ticks);
|
||||
void rdtsc_loop_sec(unsigned seconds);
|
||||
uint64_t rdtsc_max_freq(int id);
|
||||
|
||||
int rdtsc_is_invariant(void);
|
||||
uint64_t rdtsc_get_overhead(uint64_t iterations);
|
||||
uint64_t rdtsc_get_overhead_serialized(uint64_t iterations);
|
||||
|
||||
#endif
|
79
hermit/usr/benchmarks/report.c
Normal file
79
hermit/usr/benchmarks/report.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: report.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:11:54
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "report.h"
|
||||
#include "hist.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int report_params(const struct opt *opt)
|
||||
{
|
||||
printf("init: tps = %llu\n", (unsigned long long)opt->tps);
|
||||
printf("secs : %u\n", opt->secs);
|
||||
printf("threshold : %llu\n", (unsigned long long)opt->threshold);
|
||||
if (opt->mode == hist) {
|
||||
printf("mode : histogram (cnt: %u, width: %u)\n", opt->hist_cnt, opt->hist_width);
|
||||
} else if (opt->mode == list) {
|
||||
printf("mode : list (cnt: %u)\n", opt->list_cnt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int report_stat(const struct result *result)
|
||||
{
|
||||
printf(" # loops : %15llu\n",
|
||||
(unsigned long long)result->cnt);
|
||||
printf(" Min. : %15llu (@loop #%llu)\n",
|
||||
(unsigned long long)result->min,
|
||||
(unsigned long long)result->t_min);
|
||||
printf(" Avg. : %18.2lf\n",
|
||||
(double)result->sum/(double)result->cnt);
|
||||
printf(" Max. : %15llu (@loop #%llu)\n",
|
||||
(unsigned long long)result->max,
|
||||
(unsigned long long)result->t_max);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int report(const struct opt *opt, const struct result *result)
|
||||
{
|
||||
/*
|
||||
* write results to stdout (or file)
|
||||
* depending on opt
|
||||
*/
|
||||
|
||||
printf("Dummy result: %llu \n", (unsigned long long)result->dummy);
|
||||
|
||||
report_stat(result);
|
||||
|
||||
if (opt->mode == hist) {
|
||||
hist_print();
|
||||
} else if (opt->mode == list) {
|
||||
unsigned i;
|
||||
for (i=0; i<opt->list_cnt; i++) {
|
||||
if (result->list[i].time > 0) {
|
||||
printf(" %15llu : %10llu\n",
|
||||
(unsigned long long)result->list[i].time,
|
||||
(unsigned long long)result->list[i].gap);
|
||||
} else break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
28
hermit/usr/benchmarks/report.h
Normal file
28
hermit/usr/benchmarks/report.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: report.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:11:07
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __REPORT_H__
|
||||
#define __REPORT_H__
|
||||
|
||||
#include "run.h"
|
||||
#include "opt.h"
|
||||
|
||||
int report_params(const struct opt *opt);
|
||||
int report(const struct opt *opt, const struct result *result);
|
||||
|
||||
#endif // __REPORT_H__
|
161
hermit/usr/benchmarks/run.c
Normal file
161
hermit/usr/benchmarks/run.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: run.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:10:30
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "run.h"
|
||||
#include "rdtsc.h"
|
||||
#include "hist.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static struct result *results;
|
||||
static const struct opt *opts;
|
||||
|
||||
|
||||
static void store_results_stat(uint64_t gap, uint64_t offset)
|
||||
{
|
||||
|
||||
if (gap < results->min) {
|
||||
results->min = gap;
|
||||
results->t_min = results->cnt;
|
||||
}
|
||||
if (gap > results->max) {
|
||||
results->max = gap;
|
||||
results->t_max = results->cnt;
|
||||
}
|
||||
results->sum += gap;
|
||||
results->cnt++; /* avg = sum/cnt */
|
||||
}
|
||||
|
||||
static void store_results_hist(uint64_t gap, uint64_t offset)
|
||||
{
|
||||
/*
|
||||
* create histogram
|
||||
*/
|
||||
store_results_stat(gap, offset);
|
||||
hist_add(gap);
|
||||
}
|
||||
|
||||
static unsigned list_cnt;
|
||||
static unsigned list_idx = 0;
|
||||
static void store_results_list(uint64_t gap, uint64_t offset)
|
||||
{
|
||||
/*
|
||||
* store all timestamps
|
||||
*/
|
||||
if (list_idx >= list_cnt) return;
|
||||
store_results_stat(gap, offset);
|
||||
results->list[list_idx].time = offset;
|
||||
results->list[list_idx].gap = gap;
|
||||
list_idx++;
|
||||
}
|
||||
|
||||
static void (*store_results)(uint64_t gap, uint64_t offset);
|
||||
|
||||
|
||||
static int reset_results(void)
|
||||
{
|
||||
results->min=UINT64_MAX;
|
||||
results->max=0;
|
||||
results->sum=0;
|
||||
results->cnt=0;
|
||||
results->t_min = 0;
|
||||
results->t_max = 0;
|
||||
if (opts->mode == hist) {
|
||||
hist_reset();
|
||||
} else if (opts->mode == list) {
|
||||
unsigned i;
|
||||
for (i=0; i<opts->list_cnt; i++) {
|
||||
results->list[i].time=0;
|
||||
results->list[i].gap=0;
|
||||
}
|
||||
list_idx = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hourglass(uint64_t duration, uint64_t threshold)
|
||||
{
|
||||
uint64_t t1, t2, t_end, diff; /* timestamps */
|
||||
|
||||
reset_results();
|
||||
|
||||
rdtsc(&t1); /* start-time */
|
||||
t_end = t1 + duration; /* calculate end-time */
|
||||
|
||||
while (t1 < t_end) { /* loop until end-time */
|
||||
t2 = t1;
|
||||
rdtsc(&t1);
|
||||
diff = t1 - t2;
|
||||
if (diff > threshold) {
|
||||
store_results(diff, t2);
|
||||
}
|
||||
/* Note: additional workload may be added here */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int run(const struct opt *opt, struct result *result)
|
||||
{
|
||||
unsigned i;
|
||||
results = result;
|
||||
opts = opt;
|
||||
|
||||
results->hist = NULL;
|
||||
|
||||
switch (opt->mode) {
|
||||
case stat :
|
||||
store_results = store_results_stat;
|
||||
break;
|
||||
case hist :
|
||||
store_results = store_results_hist;
|
||||
results->hist = hist_alloc(opt);
|
||||
hist_reset();
|
||||
break;
|
||||
case list :
|
||||
store_results = store_results_list;
|
||||
list_cnt = opt->list_cnt;
|
||||
results->list = calloc(opt->list_cnt, sizeof(struct res_list));
|
||||
for (i=0; i<opt->list_cnt; i++) {
|
||||
results->list[i].time=0;
|
||||
results->list[i].gap=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* execute hourglass routine
|
||||
*/
|
||||
hourglass(1 * opt->tps, opt->threshold); // 1 sec warmup
|
||||
|
||||
hourglass(opt->secs * opt->tps, opt->threshold);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int run_free(const struct opt *opt, struct result *result)
|
||||
{
|
||||
if (results->hist != NULL) {
|
||||
free(results->hist);
|
||||
results->hist = NULL;
|
||||
}
|
||||
if (results->list != NULL) {
|
||||
free(results->list);
|
||||
results->list = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
50
hermit/usr/benchmarks/run.h
Normal file
50
hermit/usr/benchmarks/run.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: run.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:08:43
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __RUN_H__
|
||||
#define __RUN_H__
|
||||
|
||||
#include "opt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
struct res_list {
|
||||
uint64_t time;
|
||||
uint64_t gap;
|
||||
};
|
||||
|
||||
struct result {
|
||||
uint64_t dummy;
|
||||
|
||||
uint64_t min;
|
||||
uint64_t max;
|
||||
uint64_t sum;
|
||||
uint64_t cnt;
|
||||
uint64_t t_min;
|
||||
uint64_t t_max;
|
||||
|
||||
uint32_t *hist;
|
||||
struct res_list *list;
|
||||
|
||||
};
|
||||
|
||||
int run(const struct opt *opt, struct result *result);
|
||||
int run_free(const struct opt *opt, struct result *result);
|
||||
|
||||
|
||||
#endif // __RUN_H__
|
||||
|
40
hermit/usr/benchmarks/setup.c
Normal file
40
hermit/usr/benchmarks/setup.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: setup.c
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:07:43
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
|
||||
int setup(struct opt *opt)
|
||||
{
|
||||
/*
|
||||
* set up run-time environment for benchmark
|
||||
* depending on opt
|
||||
* e.g. create cpu-set, move IRQs, etc.
|
||||
*/
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setdown(struct opt *opt)
|
||||
{
|
||||
/*
|
||||
* undo things from setup()
|
||||
*/
|
||||
return 0;
|
||||
}
|
27
hermit/usr/benchmarks/setup.h
Normal file
27
hermit/usr/benchmarks/setup.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: setup.h
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 25.07.2014 15:06:59
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Georg Wassen (gw) (),
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
|
||||
#ifndef __SETUP_H__
|
||||
#define __SETUP_H__
|
||||
|
||||
#include "opt.h"
|
||||
|
||||
int setup(struct opt *opt);
|
||||
int setdown(struct opt *opt);
|
||||
|
||||
#endif // __SETUP_H__
|
Loading…
Add table
Reference in a new issue