aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/gensvm_timer.h5
-rw-r--r--src/gensvm_gridsearch.c22
-rw-r--r--src/gensvm_timer.c34
-rw-r--r--tests/src/test_gensvm_timer.c34
4 files changed, 76 insertions, 19 deletions
diff --git a/include/gensvm_timer.h b/include/gensvm_timer.h
index 563576b..5dd4dcb 100644
--- a/include/gensvm_timer.h
+++ b/include/gensvm_timer.h
@@ -15,7 +15,10 @@
// includes
#include "gensvm_globals.h"
+/// Timer macro for easily recording time
+#define Timer(spec) clock_gettime(CLOCK_MONOTONIC_RAW, &spec)
+
// function declarations
-double gensvm_elapsed_time(clock_t s_time, clock_t e_time);
+double gensvm_elapsed_time(struct timespec *start, struct timespec *stop);
#endif
diff --git a/src/gensvm_gridsearch.c b/src/gensvm_gridsearch.c
index 50b0020..a79c31e 100644
--- a/src/gensvm_gridsearch.c
+++ b/src/gensvm_gridsearch.c
@@ -283,7 +283,7 @@ void consistency_repeats(struct GenQueue *q, long repeats, TrainType traintype)
**test_folds = NULL;
struct GenModel *model = gensvm_init_model();
struct GenTask *task = NULL;
- clock_t loop_s, loop_e;
+ struct timespec loop_s, loop_e;
nq = create_top_queue(q);
N = nq->N;
@@ -328,11 +328,11 @@ void consistency_repeats(struct GenQueue *q, long repeats, TrainType traintype)
test_folds[f]);
}
- loop_s = clock();
+ Timer(loop_s);
p = gensvm_cross_validation(model, train_folds, test_folds,
task->folds, task->train_data->n);
- loop_e = clock();
- time[i] += gensvm_elapsed_time(loop_s, loop_e);
+ Timer(loop_e);
+ time[i] += gensvm_elapsed_time(&loop_s, &loop_e);
matrix_set(perf, repeats, i, r, p);
mean[i] += p/((double) repeats);
note("%3.3f\t", p);
@@ -476,7 +476,7 @@ void start_training(struct GenQueue *q)
struct GenTask *task = get_next_task(q);
struct GenTask *prevtask = NULL;
struct GenModel *model = gensvm_init_model();
- clock_t main_s, main_e, loop_s, loop_e;
+ struct timespec main_s, main_e, loop_s, loop_e;
// in principle this can change between tasks, but this shouldn't be
// the case TODO
@@ -500,7 +500,7 @@ void start_training(struct GenQueue *q)
test_folds[f], cv_idx, f);
}
- main_s = clock();
+ Timer(main_s);
while (task) {
make_model_from_task(task, model);
if (kernel_changed(task, prevtask)) {
@@ -519,24 +519,24 @@ void start_training(struct GenQueue *q)
}
print_progress_string(task, q->N);
- loop_s = clock();
+ Timer(loop_s);
perf = gensvm_cross_validation(model, train_folds, test_folds,
folds, task->train_data->n);
- loop_e = clock();
+ Timer(loop_e);
current_max = maximum(current_max, perf);
note("\t%3.3f%% (%3.3fs)\t(best = %3.3f%%)\n", perf,
- gensvm_elapsed_time(loop_s, loop_e),
+ gensvm_elapsed_time(&loop_s, &loop_e),
current_max);
q->tasks[task->ID]->performance = perf;
prevtask = task;
task = get_next_task(q);
}
- main_e = clock();
+ Timer(main_e);
note("\nTotal elapsed training time: %8.8f seconds\n",
- gensvm_elapsed_time(main_s, main_e));
+ gensvm_elapsed_time(&main_s, &main_e));
// make sure no double free occurs with the copied kernelparam
model->kernelparam = NULL;
diff --git a/src/gensvm_timer.c b/src/gensvm_timer.c
index 04d93b1..0e020fe 100644
--- a/src/gensvm_timer.c
+++ b/src/gensvm_timer.c
@@ -1,25 +1,45 @@
/**
- * @file timer.c
+ * @file gensvm_timer.c
* @author Gertjan van den Burg
* @date January, 2014
* @brief Utility functions relating to time
*
* @details
* This file contains a simple function for calculating the time in seconds
- * elapsed between two clock() calls.
+ * elapsed between two Timer() calls.
*
*/
#include "gensvm_timer.h"
/**
- * @brief Calculate the time between two clocks
+ * @brief Calculate the time between two time recordings
*
- * @param[in] s_time starting time
- * @param[in] e_time end time
+ * @detail
+ * This function should be used with time recordings done by clock_gettime()
+ * using CLOCK_MONOTONIC_RAW. For this, the Timer() macro has been defined in
+ * the header file. Example usage:
+ *
+ * @code
+ * struct timespec start, stop;
+ * Timer(start);
+ * // do some work //
+ * Timer(stop);
+ * double duration = gensvm_elapsed_time(&start, &stop);
+ * @endcode
+ *
+ * This approach to measuring time has been chosen since CLOCK_MONOTONIC_RAW
+ * is guaranteed to be monotonically increasing, and is not affected by leap
+ * seconds or other changes to the system clock. It is therefore thread-safe
+ * and can be used to accurately measure time intervals.
+ *
+ * @param[in] start starting time
+ * @param[in] stop end time
* @returns time elapsed in seconds
*/
-double gensvm_elapsed_time(clock_t s_time, clock_t e_time)
+double gensvm_elapsed_time(struct timespec *start, struct timespec *stop)
{
- return ((double) (e_time - s_time))/((double) CLOCKS_PER_SEC);
+ double delta_s = stop->tv_sec - start->tv_sec;
+ double delta_ns = stop->tv_nsec - start->tv_nsec;
+ return delta_s + delta_ns * 1e-9;
}
diff --git a/tests/src/test_gensvm_timer.c b/tests/src/test_gensvm_timer.c
new file mode 100644
index 0000000..78e968f
--- /dev/null
+++ b/tests/src/test_gensvm_timer.c
@@ -0,0 +1,34 @@
+/**
+ * @file test_gensvm_timer.c
+ * @author Gertjan van den Burg
+ * @date October, 2016
+ * @brief Unit tests for gensvm_timer.c functions
+ *
+ */
+
+#include "minunit.h"
+#include "gensvm_timer.h"
+
+char *test_timer()
+{
+ struct timespec start, stop;
+ Timer(start);
+
+ stop.tv_sec = start.tv_sec + 1;
+ stop.tv_nsec = start.tv_nsec;
+
+ mu_assert(gensvm_elapsed_time(&start, &stop) == 1.0,
+ "Incorrect time computed");
+
+ return NULL;
+}
+
+char *all_tests()
+{
+ mu_suite_start();
+ mu_run_test(test_timer);
+
+ return NULL;
+}
+
+RUN_TESTS(all_tests);