diff options
author | Cyril Hrubis <chrubis@suse.cz> | 2015-02-24 13:31:14 +0100 |
---|---|---|
committer | Cyril Hrubis <chrubis@suse.cz> | 2015-02-26 16:15:22 +0100 |
commit | 9dee40527b352ebbe386a178cea3a374673a00a2 (patch) | |
tree | a43b561f94a32d0e0872dbe7957365cac6a5211e | |
parent | 1188b252320f74451abbfede1acaf8be25ce3467 (diff) |
lib: Add tst_timer functions.
* Add struct timespec conversions and arithmetic
* Add timer functions simplify elapsed time measurement.
Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
-rw-r--r-- | doc/test-writing-guidelines.txt | 73 | ||||
-rw-r--r-- | include/test.h | 1 | ||||
-rw-r--r-- | include/tst_timer.h | 179 | ||||
-rw-r--r-- | lib/tst_timer.c | 87 |
4 files changed, 340 insertions, 0 deletions
diff --git a/doc/test-writing-guidelines.txt b/doc/test-writing-guidelines.txt index e2b455ec7..27041190d 100644 --- a/doc/test-writing-guidelines.txt +++ b/doc/test-writing-guidelines.txt @@ -1048,6 +1048,79 @@ const char *const cmd[] = { "ls", "-l", NULL }; ... ------------------------------------------------------------------------------- +2.2.21 Measuring elapsed time and helper functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +[source,c] +------------------------------------------------------------------------------- +#include "test.h" + +void tst_timer_check(clockid_t clk_id); + +void tst_timer_start(clockid_t clk_id); + +void tst_timer_stop(void); + +struct timespec tst_timer_elapsed(void); + +long long tst_timer_elapsed_ms(void); + +long long tst_timer_elapsed_us(void); +------------------------------------------------------------------------------- + +The 'tst_timer_check()' function checks if specified 'clk_id' is suppored and +exits the test with 'TCONF' otherwise. It's expected to be used in test +'setup()' before any resources that needs to be cleaned up are initialized, +hence it does not include a cleanup function parameter. + +The 'tst_timer_start()' marks start time and stores the 'clk_id' for further +use. + +The 'tst_timer_stop()' marks the stop time using the same 'clk_id' as last +call to 'tst_timer_start()'. + +The 'tst_timer_elapsed*()' returns time difference between the timer start and +last timer stop in serveral formats and units. + +IMPORTANT: The timer functions use 'clock_gettime()' internally which needs to + be linked with '-lrt' on older glibc. Please do not forget to add + 'LDLIBS+=-lrt' in Makefile. + +[source,c] +------------------------------------------------------------------------------- +long long tst_timespec_to_us(struct timespec t); +long long tst_timespec_to_ms(struct timespec t); + +int tst_timespec_lt(struct timespec t1, struct timespec t2); + +struct timespec tst_timespec_add_us(struct timespec t, long long us); + +struct timespec tst_timespec_diff(struct timespec t1, struct timespec t2); +long long tst_timespec_diff_us(struct timespec t1, struct timespec t2); +long long tst_timespec_diff_ms(struct timespec t1, struct timespec t2); + +struct timespec tst_timespec_abs_diff(struct timespec t1, struct timespec t2); +long long tst_timespec_abs_diff_us(struct timespec t1, struct timespec t2); +long long tst_timespec_abs_diff_ms(struct timespec t1, struct timespec t2); +------------------------------------------------------------------------------- + +The first two functions 'tst_timespec_to_us()' and 'tst_timespec_to_ms()' are +simple conversion inline functions. + +The 'tst_timespec_lt()' function returns non-zero if 't1' is earlier than +'t2'. + +The 'tst_timespec_add_us()' function adds 'us' microseconds to the timespec +'t'. The 'us' is expected to be positive. + +The 'tst_timespec_diff*()' functions returns difference between two times, the +'t1' is expected to be later than 't2'. + +The 'tst_timespec_abs_diff*()' functions returns absolute value of difference +between two times. + +NOTE: All conversions to ms and us rounds the value. + 2.3 Writing a testcase in shell ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/test.h b/include/test.h index cccd6dc83..f45bb3692 100644 --- a/include/test.h +++ b/include/test.h @@ -50,6 +50,7 @@ #include "tst_process_state.h" #include "tst_resource.h" #include "tst_res_flags.h" +#include "tst_timer.h" /* virt types for tst_is_virt() */ #define VIRT_XEN 1 /* xen dom0/domU */ diff --git a/include/tst_timer.h b/include/tst_timer.h new file mode 100644 index 000000000..f35b5ab90 --- /dev/null +++ b/include/tst_timer.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + /* + + Timer - struct timespec conversion runtimes and easy to use functions to + measure elapsed time. + + */ + +#ifndef TST_TIMER +#define TST_TIMER + +#include <time.h> + +/* + * Converts timespec to microseconds. + */ +static inline long long tst_timespec_to_us(struct timespec t) +{ + return t.tv_sec * 1000000 + (t.tv_nsec + 500) / 1000; +} + +/* + * Converts timespec to miliseconds. + */ +static inline long long tst_timespec_to_ms(struct timespec t) +{ + return t.tv_sec * 1000 + (t.tv_nsec + 500000) / 1000000; +} + +/* + * Comparsions + */ +static inline int tst_timespec_lt(struct timespec t1, struct timespec t2) +{ + if (t1.tv_sec == t2.tv_sec) + return t1.tv_nsec < t2.tv_nsec; + + return t1.tv_sec < t2.tv_sec; +} + +/* + * Adds us microseconds to t. + */ +static inline struct timespec tst_timespec_add_us(struct timespec t, + long long us) +{ + t.tv_sec += us / 1000000; + t.tv_nsec += (us % 1000000) * 1000; + + if (t.tv_nsec >= 1000000000) { + t.tv_sec++; + t.tv_nsec -= 1000000000; + } + + return t; +} + +/* + * Returns difference between two timespec structures. + */ +static inline struct timespec tst_timespec_diff(struct timespec t1, + struct timespec t2) +{ + struct timespec res; + + res.tv_sec = t1.tv_sec - t2.tv_sec; + + if (t1.tv_nsec < t2.tv_nsec) { + res.tv_sec--; + res.tv_nsec = 1000000000 - (t2.tv_nsec - t1.tv_nsec); + } else { + res.tv_nsec = t1.tv_nsec - t2.tv_nsec; + } + + return res; +} + +static inline long long tst_timespec_diff_us(struct timespec t1, + struct timespec t2) +{ + return tst_timespec_to_us(tst_timespec_diff(t1, t2)); +} + +static inline long long tst_timespec_diff_ms(struct timespec t1, + struct timespec t2) +{ + return tst_timespec_to_ms(tst_timespec_diff(t1, t2)); +} + +/* + * Returns absolute value of difference between two timespec structures. + */ +static inline struct timespec tst_timespec_abs_diff(struct timespec t1, + struct timespec t2) +{ + if (tst_timespec_lt(t1, t2)) + return tst_timespec_diff(t2, t1); + else + return tst_timespec_diff(t1, t2); +} + +static inline long long tst_timespec_abs_diff_us(struct timespec t1, + struct timespec t2) +{ + return tst_timespec_to_us(tst_timespec_abs_diff(t1, t2)); +} + +static inline long long tst_timespec_abs_diff_ms(struct timespec t1, + struct timespec t2) +{ + return tst_timespec_to_ms(tst_timespec_abs_diff(t1, t2)); +} + +/* + * Exits the test with TCONF if particular timer is not supported. This is + * intended to be used in test setup. There is no cleanup callback parameter as + * you are expected to call it before initializing any resources that has to be + * cleaned up later. + * + * @clk_id: Posix clock to use. + */ +void tst_timer_check(clockid_t clk_id); + +/* + * Marks a start time for given clock type. + * + * @clk_id: Posix clock to use. + */ +void tst_timer_start(clockid_t clk_id); + +/* + * Marks timer end time. + */ +void tst_timer_stop(void); + +/* + * Retuns elapsed time in struct timespec. + */ +struct timespec tst_timer_elapsed(void); + +/* + * Returns elapsed time in miliseconds. + */ +static inline long long tst_timer_elapsed_ms(void) +{ + return tst_timespec_to_ms(tst_timer_elapsed()); +} + +/* + * Returns elapsed time in microseconds. + */ +static inline long long tst_timer_elapsed_us(void) +{ + return tst_timespec_to_us(tst_timer_elapsed()); +} + +#endif /* TST_TIMER */ diff --git a/lib/tst_timer.c b/lib/tst_timer.c new file mode 100644 index 000000000..5f0cfc4b6 --- /dev/null +++ b/lib/tst_timer.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 Cyril Hrubis <chrubis@suse.cz> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <errno.h> + +#include "test.h" +#include "tst_timer.h" +#include "lapi/posix_clocks.h" + +static struct timespec start_time, stop_time; +static clockid_t clock_id; + +static const char *clock_name(clockid_t clk_id) +{ + switch (clk_id) { + case CLOCK_REALTIME: + return "CLOCK_REALTIME"; + case CLOCK_REALTIME_COARSE: + return "CLOCK_REALTIME_COARSE"; + case CLOCK_MONOTONIC: + return "CLOCK_MONOTONIC"; + case CLOCK_MONOTONIC_COARSE: + return "CLOCK_MONOTONIC_COARSE"; + case CLOCK_MONOTONIC_RAW: + return "CLOCK_MONOTONIC_RAW"; + case CLOCK_BOOTTIME: + return "CLOCK_BOOTTIME"; + case CLOCK_PROCESS_CPUTIME_ID: + return "CLOCK_PROCESS_CPUTIME_ID"; + case CLOCK_THREAD_CPUTIME_ID: + return "CLOCK_THREAD_CPUTIME_ID"; + default: + return "UNKNOWN/INVALID"; + } +} + +void tst_timer_check(clockid_t clk_id) +{ + if (clock_gettime(clk_id, &start_time)) { + if (errno == EINVAL) { + tst_brkm(TCONF, NULL, + "Clock id %s(%u) not supported by kernel", + clock_name(clk_id), clk_id); + } + + tst_brkm(TBROK | TERRNO, NULL, "clock_gettime() failed"); + } +} + +void tst_timer_start(clockid_t clk_id) +{ + clock_id = clk_id; + + if (clock_gettime(clock_id, &start_time)) + tst_resm(TWARN | TERRNO, "clock_gettime() failed"); +} + +void tst_timer_stop(void) +{ + if (clock_gettime(clock_id, &stop_time)) + tst_resm(TWARN | TERRNO, "clock_gettime() failed"); +} + +struct timespec tst_timer_elapsed(void) +{ + return tst_timespec_diff(stop_time, start_time); +} |