diff options
author | Petri Savolainen <petri.savolainen@linaro.org> | 2017-04-28 15:09:56 +0300 |
---|---|---|
committer | Maxim Uvarov <maxim.uvarov@linaro.org> | 2017-06-16 16:51:11 +0300 |
commit | fbe34c754b7abe15100779ce9833a7f200517d9f (patch) | |
tree | 1cfcd9524cd017876cd1124b34728eedacb90065 /platform/linux-generic/arch/x86 | |
parent | 62f95a564b7b3e08a32e6e72d234eb86292021d0 (diff) |
linux-gen: time: use hw time counter when available
Use 64 bit HW time counter when available. It is used on
x86 when invariant TSC CPU flag indicates that TSC frequency
is constant. Otherwise, the system time is used as before. Direct
HW time counter usage avoids system call, and related latency
and performance issues.
Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>
Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org>
Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'platform/linux-generic/arch/x86')
-rw-r--r-- | platform/linux-generic/arch/x86/cpu_flags.c | 9 | ||||
-rw-r--r-- | platform/linux-generic/arch/x86/odp_cpu_arch.c | 59 |
2 files changed, 68 insertions, 0 deletions
diff --git a/platform/linux-generic/arch/x86/cpu_flags.c b/platform/linux-generic/arch/x86/cpu_flags.c index 954dac272..a492a35bf 100644 --- a/platform/linux-generic/arch/x86/cpu_flags.c +++ b/platform/linux-generic/arch/x86/cpu_flags.c @@ -39,6 +39,7 @@ #include <arch/x86/cpu_flags.h> #include <odp_debug_internal.h> +#include <odp_time_internal.h> #include <stdio.h> #include <stdint.h> @@ -357,3 +358,11 @@ void cpu_flags_print_all(void) str[len] = '\0'; ODP_PRINT("%s", str); } + +int cpu_has_global_time(void) +{ + if (cpu_get_flag_enabled(RTE_CPUFLAG_INVTSC) > 0) + return 1; + + return 0; +} diff --git a/platform/linux-generic/arch/x86/odp_cpu_arch.c b/platform/linux-generic/arch/x86/odp_cpu_arch.c index c8cf27b65..9ba601a32 100644 --- a/platform/linux-generic/arch/x86/odp_cpu_arch.c +++ b/platform/linux-generic/arch/x86/odp_cpu_arch.c @@ -3,7 +3,14 @@ * * SPDX-License-Identifier: BSD-3-Clause */ + +#include <odp_posix_extensions.h> + #include <odp/api/cpu.h> +#include <odp_time_internal.h> +#include <odp_debug_internal.h> + +#include <time.h> uint64_t odp_cpu_cycles(void) { @@ -31,3 +38,55 @@ uint64_t odp_cpu_cycles_resolution(void) { return 1; } + +uint64_t cpu_global_time(void) +{ + return odp_cpu_cycles(); +} + +#define SEC_IN_NS 1000000000ULL + +/* Measure TSC frequency. Frequency information registers are defined for x86, + * but those are often not enumerated. */ +uint64_t cpu_global_time_freq(void) +{ + struct timespec sleep, ts1, ts2; + uint64_t t1, t2, ts_nsec, cycles, hz; + int i; + uint64_t avg = 0; + int rounds = 4; + + for (i = 0; i < rounds; i++) { + sleep.tv_sec = 0; + sleep.tv_nsec = SEC_IN_NS / 10; + + if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts1)) { + ODP_DBG("clock_gettime failed\n"); + return 0; + } + + t1 = cpu_global_time(); + + if (nanosleep(&sleep, NULL) < 0) { + ODP_DBG("nanosleep failed\n"); + return 0; + } + + if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts2)) { + ODP_DBG("clock_gettime failed\n"); + return 0; + } + + t2 = cpu_global_time(); + + ts_nsec = (ts2.tv_sec - ts1.tv_sec) * SEC_IN_NS; + ts_nsec += ts2.tv_nsec - ts1.tv_nsec; + + cycles = t2 - t1; + + hz = (cycles * SEC_IN_NS) / ts_nsec; + avg += hz; + } + + return avg / rounds; +} |