Added monotonic cross-platform timer
This commit is contained in:
parent
c28cff39b8
commit
4a5c19a08c
7 changed files with 117 additions and 12 deletions
|
@ -45,4 +45,5 @@ libcriterion_la_SOURCES = \
|
|||
src/stats.h \
|
||||
src/logging.c \
|
||||
src/options.c \
|
||||
src/timer.c \
|
||||
src/main.c
|
||||
|
|
|
@ -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);
|
||||
|
|
14
src/report.c
14
src/report.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
src/runner.c
12
src/runner.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
79
src/timer.c
Normal 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
17
src/timer.h
Normal 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_ */
|
Loading…
Add table
Reference in a new issue