Ready. Set. Go!
This commit is contained in:
parent
64623ed417
commit
f72d334804
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
cbench
|
8
Makefile
Normal file
8
Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
cbench: cbench.c
|
||||
$(CC) -O2 -o cbench cbench.c -DNDEBUG
|
||||
|
||||
DESTDIR := $(if $(DESTDIR),$(DESTDIR),/usr/local)
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)/bin
|
||||
cp ./cbench $(DESTDIR)/bin/
|
142
cbench.c
Normal file
142
cbench.c
Normal file
@ -0,0 +1,142 @@
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
static inline uint64_t as_nanoseconds(struct timespec* ts) {
|
||||
return ts->tv_sec * (uint64_t)1000000000L + ts->tv_nsec;
|
||||
}
|
||||
|
||||
static void as_timespec(uint64_t ns, struct timespec* ts) {
|
||||
ts->tv_sec = ns / (uint64_t)1000000000L;
|
||||
ts->tv_nsec = ns % (uint64_t)1000000000L;
|
||||
}
|
||||
|
||||
uint64_t run_individual_benchmark(char** argv)
|
||||
{
|
||||
struct timespec start, end;
|
||||
|
||||
int fd = open("/dev/null", O_WRONLY);
|
||||
if(fd < 0)
|
||||
{
|
||||
perror("open");
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &start) != 0)
|
||||
{
|
||||
perror("clock_gettime");
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
pid_t child = fork();
|
||||
if(child < 0)
|
||||
{
|
||||
perror("fork");
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
if(child == 0)
|
||||
{
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
execvp(argv[0], argv);
|
||||
perror("execvp");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
int status;
|
||||
pid_t result = waitpid(child, &status, 0);
|
||||
|
||||
// We fetch the time before checking waitpid's status because we want to have a somewhat accurate result.
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &end) != 0)
|
||||
{
|
||||
perror("clock_gettime");
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
if(result != child)
|
||||
{
|
||||
perror("waitpid");
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
if(WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||
{
|
||||
fprintf(stderr, "Child exited with status %d\n", WEXITSTATUS(status));
|
||||
return (uint64_t)-1;
|
||||
}
|
||||
|
||||
return as_nanoseconds(&end) - as_nanoseconds(&start);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if(argc == 1)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [iterations:20] command\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
|
||||
{
|
||||
printf("Usage: %s [iterations:20] command\n"
|
||||
"\n"
|
||||
"Benchmarks a program by running it <iterations> times and reporting the \n"
|
||||
"average, fastest and slowest time it took to run.\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iterations = 20;
|
||||
|
||||
if(isdigit(*argv[1]))
|
||||
{
|
||||
if(argc == 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [iterations:20] command\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
iterations = atoi(argv[1]);
|
||||
|
||||
argv++;
|
||||
}
|
||||
|
||||
uint64_t total = 0;
|
||||
uint64_t min = UINT64_MAX;
|
||||
uint64_t max = 0;
|
||||
|
||||
for(int i = 0; i < iterations; i++)
|
||||
{
|
||||
uint64_t ns = run_individual_benchmark(argv+1);
|
||||
if(ns == (uint64_t)-1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
total += ns;
|
||||
if(ns < min) min = ns;
|
||||
if(ns > max) max = ns;
|
||||
}
|
||||
|
||||
uint64_t average = total / (uint64_t)iterations;
|
||||
|
||||
struct timespec tspec;
|
||||
as_timespec(total, &tspec);
|
||||
|
||||
printf("Results (over %d iterations): \n", iterations);
|
||||
|
||||
printf("Total time: %3ld.%.6lds\n", tspec.tv_sec, tspec.tv_nsec / 1000L);
|
||||
as_timespec(average, &tspec);
|
||||
printf("Average time: %3ld.%.6lds\n", tspec.tv_sec, tspec.tv_nsec / 1000L);
|
||||
as_timespec(min, &tspec);
|
||||
printf("Fastest time: %3ld.%.6lds\n", tspec.tv_sec, tspec.tv_nsec / 1000L);
|
||||
as_timespec(max, &tspec);
|
||||
printf("Slowest time: %3ld.%.6lds\n", tspec.tv_sec, tspec.tv_nsec / 1000L);
|
||||
}
|
Loading…
Reference in New Issue
Block a user