Added monotonic cross-platform timer

This commit is contained in:
Snaipe 2015-03-16 23:32:03 +01:00
parent c28cff39b8
commit 4a5c19a08c
7 changed files with 117 additions and 12 deletions

View file

@ -45,4 +45,5 @@ libcriterion_la_SOURCES = \
src/stats.h \
src/logging.c \
src/options.c \
src/timer.c \
src/main.c

View file

@ -50,8 +50,8 @@ struct event *read_event(int fd) {
return unique_ptr(struct event, ({ .kind = kind, .data = buf }), destroy_event);
}
case POST_TEST: {
float *elapsed_time = malloc(sizeof (float));
if (read(fd, elapsed_time, sizeof (float)) < (ssize_t) sizeof (float))
double *elapsed_time = malloc(sizeof (double));
if (read(fd, elapsed_time, sizeof (double)) < (ssize_t) sizeof (double))
return NULL;
return unique_ptr(struct event, ({ .kind = kind, .data = elapsed_time }), destroy_event);

View file

@ -27,6 +27,7 @@
#include "criterion/logging.h"
#include "criterion/options.h"
#include "report.h"
#include "timer.h"
#define IMPL_CALL_REPORT_HOOKS(Kind) \
IMPL_SECTION_LIMITS(f_report_hook, crit_ ## Kind); \
@ -57,11 +58,14 @@ ReportHook(PRE_INIT)(struct criterion_test *test) {
ReportHook(POST_TEST)(struct criterion_test_stats *stats) {
if (criterion_options.enable_tap_format) {
criterion_important("%s " SIZE_T_FORMAT " - %s::%s\n",
const char *format = can_measure_time() ? "%s " SIZE_T_FORMAT " - %s::%s (%3.2fs)\n"
: "%s " SIZE_T_FORMAT " - %s::%s\n";
criterion_important(format,
stats->failed ? "not ok" : "ok",
tap_test_index++,
stats->test->category,
stats->test->name);
stats->test->name,
stats->elapsed_time);
for (struct criterion_assert_stats *asrt = stats->asserts; asrt; asrt = asrt->next) {
if (!asrt->passed) {
char *dup = strdup(*asrt->message ? asrt->message : asrt->condition), *saveptr = NULL;
@ -76,11 +80,13 @@ ReportHook(POST_TEST)(struct criterion_test_stats *stats) {
}
}
} else {
const char *format = can_measure_time() ? "%s::%s: %s (%3.2fs)\n" : "%s::%s: %s\n";
criterion_log(stats->failed ? CRITERION_IMPORTANT : CRITERION_INFO,
"%s::%s: %s\n",
format,
stats->test->category,
stats->test->name,
stats->failed ? "FAILURE" : "SUCCESS");
stats->failed ? "FAILURE" : "SUCCESS",
stats->elapsed_time);
}
}

View file

@ -24,7 +24,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <csptr/smart_ptr.h>
#include "criterion/options.h"
#include "stats.h"
@ -32,6 +31,7 @@
#include "report.h"
#include "event.h"
#include "process.h"
#include "timer.h"
IMPL_SECTION_LIMITS(struct criterion_test, criterion_tests);
@ -89,11 +89,13 @@ static void run_test_child(struct criterion_test *test) {
(test->data->init ?: nothing)();
send_event(PRE_TEST, NULL, 0);
clock_t before = clock();
struct timespec_compat ts;
timer_start(&ts);
(test->test ?: nothing)();
clock_t after = clock();
double elapsed_time;
if (!timer_end(&elapsed_time, &ts))
elapsed_time = -1;
double elapsed_time = (double) (after - before) / CLOCKS_PER_SEC;
send_event(POST_TEST, &elapsed_time, sizeof (double));
(test->data->fini ?: nothing)();
send_event(POST_FINI, NULL, 0);
@ -135,7 +137,7 @@ static void run_test(struct criterion_global_stats *stats, struct criterion_test
stat_push_event(stats, test_stats, &ev);
report(POST_TEST, test_stats);
ev.kind = POST_FINI;
ev = (struct event) { .kind = POST_FINI, .data = NULL };
stat_push_event(stats, test_stats, &ev);
report(POST_FINI, test_stats);
}

View file

@ -114,7 +114,7 @@ static void push_assert(s_glob_stats *stats,
static void push_post_test(s_glob_stats *stats,
s_test_stats *test,
float *ptr) {
double *ptr) {
test->elapsed_time = *ptr;
if (test->failed_asserts > 0 || test->signal != test->test->data->signal) {
test->failed = 1;

79
src/timer.c Normal file
View file

@ -0,0 +1,79 @@
#include <errno.h>
#include "timer.h"
#define GIGA 1e9
#if defined(__unix__)
# ifdef CLOCK_MONOTONIC_RAW
# define CLOCK CLOCK_MONOTONIC_RAW
# else
# define CLOCK CLOCK_MONOTONIC
# endif
extern __attribute__ ((weak)) int clock_gettime(clockid_t, struct timespec *);
#elif defined(__APPLE__)
# include <mach/clock.h>
# include <mach/mach.h>
#elif defined(_WIN32)
# define VC_EXTRALEAN
# define WIN32_LEAN_AND_MEAN
# include <Windows.h>
#endif
bool can_measure_time(void) {
#ifdef __unix__
return clock_gettime != NULL;
#else
return true;
#endif
}
int gettime_compat(struct timespec_compat *ts) {
#if defined(__APPLE__)
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
int res = clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
*ts = (struct timespec_compat) { mts->tv_sec, mts->tv_nsec };
return res > 0 ? -1 : 0;
#elif defined(_WIN32)
LARGE_INTEGER freq, count;
if (!QueryPerformanceFrequency(&freq)
|| !QueryPerformanceCounter(&count))
return -1;
*ts = (struct timespec_compat) { count / freq, count * (GIGA - 1) / freq };
return 0;
#elif defined(__unix__)
if (!can_measure_time()) {
errno = ENOTSUP;
return -1;
}
struct timespec ts_;
int res = clock_gettime(CLOCK, &ts_);
*ts = (struct timespec_compat) { ts_.tv_sec, ts_.tv_nsec };
return res;
#else
return -1;
#endif
}
int timer_start(struct timespec_compat *state) {
return gettime_compat(state) == -1 ? 0 : 1;
}
int timer_end(double *time, struct timespec_compat *state) {
struct timespec_compat last;
if (gettime_compat(&last) == -1)
return 0;
*time = (last.tv_sec - state->tv_sec) + (last.tv_nsec - state->tv_nsec) / GIGA;
return 1;
}

17
src/timer.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef TIMER_H_
# define TIMER_H_
# include <time.h>
# include <inttypes.h>
# include <stdbool.h>
struct timespec_compat {
int64_t tv_sec;
int64_t tv_nsec;
};
bool can_measure_time(void);
int timer_start(struct timespec_compat *state);
int timer_end(double *time, struct timespec_compat *state);
#endif /* !TIMER_H_ */