From: Mathieu Desnoyers Date: Sun, 12 Oct 2014 11:47:15 +0000 (+0200) Subject: Implement clock plugin support X-Git-Tag: v2.8.0-rc1~71 X-Git-Url: http://git.lttng.org/?p=lttng-modules.git;a=commitdiff_plain;h=2754583e7a52bb07e00d9c20f8f6790adb1bc503 Implement clock plugin support Signed-off-by: Mathieu Desnoyers --- diff --git a/Makefile b/Makefile index 7c878f05..f7aa23f6 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ obj-m += lttng-ring-buffer-metadata-client.o obj-m += lttng-ring-buffer-client-mmap-discard.o obj-m += lttng-ring-buffer-client-mmap-overwrite.o obj-m += lttng-ring-buffer-metadata-mmap-client.o +obj-m += lttng-clock.o obj-m += lttng-tracer.o lttng-tracer-objs := lttng-events.o lttng-abi.o \ diff --git a/lttng-abi.c b/lttng-abi.c index d47280f5..f6f30430 100644 --- a/lttng-abi.c +++ b/lttng-abi.c @@ -1676,6 +1676,7 @@ int __init lttng_abi_init(void) int ret = 0; wrapper_vmalloc_sync_all(); + lttng_clock_ref(); lttng_proc_dentry = proc_create_data("lttng", S_IRUSR | S_IWUSR, NULL, <tng_fops, NULL); @@ -1685,14 +1686,17 @@ int __init lttng_abi_init(void) goto error; } lttng_stream_override_ring_buffer_fops(); + return 0; error: + lttng_clock_unref(); return ret; } /* No __exit annotation because used by init error path too. */ void lttng_abi_exit(void) { + lttng_clock_unref(); if (lttng_proc_dentry) remove_proc_entry("lttng", NULL); } diff --git a/lttng-clock.c b/lttng-clock.c new file mode 100644 index 00000000..4296d6c1 --- /dev/null +++ b/lttng-clock.c @@ -0,0 +1,110 @@ +/* + * lttng-clock.c + * + * Copyright (C) 2014 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "wrapper/trace-clock.h" +#include "lttng-events.h" +#include "lttng-tracer.h" + +struct lttng_trace_clock *lttng_trace_clock; +EXPORT_SYMBOL_GPL(lttng_trace_clock); + +static DEFINE_MUTEX(clock_mutex); +static struct module *lttng_trace_clock_mod; /* plugin */ +static int clock_used; /* refcount */ + +int lttng_clock_register_plugin(struct lttng_trace_clock *ltc, + struct module *mod) +{ + int ret = 0; + + mutex_lock(&clock_mutex); + if (clock_used) { + ret = -EBUSY; + goto end; + } + if (lttng_trace_clock_mod) { + ret = -EEXIST; + goto end; + } + /* set clock */ + ACCESS_ONCE(lttng_trace_clock) = ltc; + lttng_trace_clock_mod = mod; +end: + mutex_unlock(&clock_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(lttng_clock_register_plugin); + +void lttng_clock_unregister_plugin(struct lttng_trace_clock *ltc, + struct module *mod) +{ + mutex_lock(&clock_mutex); + WARN_ON_ONCE(clock_used); + if (!lttng_trace_clock_mod) { + goto end; + } + WARN_ON_ONCE(lttng_trace_clock_mod != mod); + + ACCESS_ONCE(lttng_trace_clock) = NULL; + lttng_trace_clock_mod = NULL; +end: + mutex_unlock(&clock_mutex); +} +EXPORT_SYMBOL_GPL(lttng_clock_unregister_plugin); + +void lttng_clock_ref(void) +{ + mutex_lock(&clock_mutex); + clock_used++; + if (lttng_trace_clock_mod) { + int ret; + + ret = try_module_get(lttng_trace_clock_mod); + if (!ret) { + printk(KERN_ERR "LTTng-clock cannot get clock plugin module\n"); + ACCESS_ONCE(lttng_trace_clock) = NULL; + lttng_trace_clock_mod = NULL; + } + } + mutex_unlock(&clock_mutex); +} +EXPORT_SYMBOL_GPL(lttng_clock_ref); + +void lttng_clock_unref(void) +{ + mutex_lock(&clock_mutex); + clock_used--; + if (lttng_trace_clock_mod) + module_put(lttng_trace_clock_mod); + mutex_unlock(&clock_mutex); +} +EXPORT_SYMBOL_GPL(lttng_clock_unref); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers "); +MODULE_DESCRIPTION("LTTng Clock"); +MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "." + __stringify(LTTNG_MODULES_MINOR_VERSION) "." + __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION) + LTTNG_MODULES_EXTRAVERSION); diff --git a/lttng-clock.h b/lttng-clock.h new file mode 100644 index 00000000..5da4f0cb --- /dev/null +++ b/lttng-clock.h @@ -0,0 +1,41 @@ +#ifndef _LTTNG_CLOCK_H +#define _LTTNG_CLOCK_H + +/* + * lttng-clock.h + * + * Copyright (C) 2014 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#define LTTNG_MODULES_UUID_STR_LEN 37 + +struct lttng_trace_clock { + u64 (*read64)(void); + u64 (*freq)(void); + int (*uuid)(char *uuid); + const char *(*name)(void); + const char *(*description)(void); +}; + +int lttng_clock_register_plugin(struct lttng_trace_clock *ltc, + struct module *mod); +void lttng_clock_unregister_plugin(struct lttng_trace_clock *ltc, + struct module *mod); + +#endif /* _LTTNG_TRACE_CLOCK_H */ diff --git a/lttng-events.c b/lttng-events.c index f648feb6..c1dc1acb 100644 --- a/lttng-events.c +++ b/lttng-events.c @@ -2007,6 +2007,7 @@ static uint64_t measure_clock_offset(void) { uint64_t offset, monotonic[2], realtime; + uint64_t tcf = trace_clock_freq(); struct timespec rts = { 0, 0 }; unsigned long flags; @@ -2018,8 +2019,15 @@ uint64_t measure_clock_offset(void) local_irq_restore(flags); offset = (monotonic[0] + monotonic[1]) >> 1; - realtime = (uint64_t) rts.tv_sec * NSEC_PER_SEC; - realtime += rts.tv_nsec; + realtime = (uint64_t) rts.tv_sec * tcf; + if (tcf == NSEC_PER_SEC) { + realtime += rts.tv_nsec; + } else { + uint64_t n = rts.tv_nsec * tcf; + + do_div(n, NSEC_PER_SEC); + realtime += n; + } offset = realtime - offset; return offset; } @@ -2113,8 +2121,8 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) ret = lttng_metadata_printf(session, "clock {\n" - " name = %s;\n", - "monotonic" + " name = \"%s\";\n", + trace_clock_name() ); if (ret) goto end; @@ -2129,11 +2137,12 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) } ret = lttng_metadata_printf(session, - " description = \"Monotonic Clock\";\n" + " description = \"%s\";\n" " freq = %llu; /* Frequency, in Hz */\n" " /* clock value offset from Epoch is: offset * (1/freq) */\n" " offset = %llu;\n" "};\n\n", + trace_clock_description(), (unsigned long long) trace_clock_freq(), (unsigned long long) measure_clock_offset() ); @@ -2143,20 +2152,23 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) ret = lttng_metadata_printf(session, "typealias integer {\n" " size = 27; align = 1; signed = false;\n" - " map = clock.monotonic.value;\n" + " map = clock.%s.value;\n" "} := uint27_clock_monotonic_t;\n" "\n" "typealias integer {\n" " size = 32; align = %u; signed = false;\n" - " map = clock.monotonic.value;\n" + " map = clock.%s.value;\n" "} := uint32_clock_monotonic_t;\n" "\n" "typealias integer {\n" " size = 64; align = %u; signed = false;\n" - " map = clock.monotonic.value;\n" + " map = clock.%s.value;\n" "} := uint64_clock_monotonic_t;\n\n", + trace_clock_name(), lttng_alignof(uint32_t) * CHAR_BIT, - lttng_alignof(uint64_t) * CHAR_BIT + trace_clock_name(), + lttng_alignof(uint64_t) * CHAR_BIT, + trace_clock_name() ); if (ret) goto end; diff --git a/lttng-events.h b/lttng-events.h index 4bf8920f..921bc1fc 100644 --- a/lttng-events.h +++ b/lttng-events.h @@ -557,6 +557,9 @@ int lttng_session_untrack_pid(struct lttng_session *session, int pid); int lttng_session_list_tracker_pids(struct lttng_session *session); +void lttng_clock_ref(void); +void lttng_clock_unref(void); + #if defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS) int lttng_syscalls_register(struct lttng_channel *chan, void *filter); int lttng_syscalls_unregister(struct lttng_channel *chan); diff --git a/wrapper/random.h b/wrapper/random.h index 8f13c185..81d7995c 100644 --- a/wrapper/random.h +++ b/wrapper/random.h @@ -25,7 +25,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define BOOT_ID_LEN 37 +#include "../lttng-clock.h" + +#define BOOT_ID_LEN LTTNG_MODULES_UUID_STR_LEN int wrapper_get_bootid(char *bootid); diff --git a/wrapper/trace-clock.h b/wrapper/trace-clock.h index d7d18429..d2b7f19d 100644 --- a/wrapper/trace-clock.h +++ b/wrapper/trace-clock.h @@ -36,6 +36,7 @@ #include #include #include "../lttng-kernel-version.h" +#include "../lttng-clock.h" #include "percpu-defs.h" #include "random.h" @@ -44,6 +45,8 @@ #error "Linux kernels 3.10 and 3.11 introduce a deadlock in the timekeeping subsystem. Fixed by commit 7bd36014460f793c19e7d6c94dab67b0afcfcb7f \"timekeeping: Fix HRTICK related deadlock from ntp lock changes\" in Linux." #endif +extern struct lttng_trace_clock *lttng_trace_clock; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)) DECLARE_PER_CPU(local_t, lttng_last_tsc); @@ -142,21 +145,31 @@ static inline u64 trace_clock_monotonic_wrapper(void) } #endif /* #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)) */ -static inline u64 trace_clock_read64(void) +static inline u64 trace_clock_read64_monotonic(void) { return (u64) trace_clock_monotonic_wrapper(); } -static inline u64 trace_clock_freq(void) +static inline u64 trace_clock_freq_monotonic(void) { return (u64) NSEC_PER_SEC; } -static inline int trace_clock_uuid(char *uuid) +static inline int trace_clock_uuid_monotonic(char *uuid) { return wrapper_get_bootid(uuid); } +static inline const char *trace_clock_name_monotonic(void) +{ + return "monotonic"; +} + +static inline const char *trace_clock_description_monotonic(void) +{ + return "Monotonic Clock"; +} + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)) static inline int get_trace_clock(void) { @@ -175,6 +188,67 @@ static inline void put_trace_clock(void) { } +static inline u64 trace_clock_read64(void) +{ + struct lttng_trace_clock *ltc = ACCESS_ONCE(lttng_trace_clock); + + if (likely(!ltc)) { + return trace_clock_read64_monotonic(); + } else { + read_barrier_depends(); /* load ltc before content */ + return ltc->read64(); + } +} + +static inline u64 trace_clock_freq(void) +{ + struct lttng_trace_clock *ltc = ACCESS_ONCE(lttng_trace_clock); + + if (!ltc) { + return trace_clock_freq_monotonic(); + } else { + read_barrier_depends(); /* load ltc before content */ + return ltc->freq(); + } +} + +static inline int trace_clock_uuid(char *uuid) +{ + struct lttng_trace_clock *ltc = ACCESS_ONCE(lttng_trace_clock); + + read_barrier_depends(); /* load ltc before content */ + /* Use default UUID cb when NULL */ + if (!ltc || !ltc->uuid) { + return trace_clock_uuid_monotonic(uuid); + } else { + return ltc->uuid(uuid); + } +} + +static inline const char *trace_clock_name(void) +{ + struct lttng_trace_clock *ltc = ACCESS_ONCE(lttng_trace_clock); + + if (!ltc) { + return trace_clock_name_monotonic(); + } else { + read_barrier_depends(); /* load ltc before content */ + return ltc->name(); + } +} + +static inline const char *trace_clock_description(void) +{ + struct lttng_trace_clock *ltc = ACCESS_ONCE(lttng_trace_clock); + + if (!ltc) { + return trace_clock_description_monotonic(); + } else { + read_barrier_depends(); /* load ltc before content */ + return ltc->description(); + } +} + #endif /* CONFIG_HAVE_TRACE_CLOCK */ #endif /* _LTTNG_TRACE_CLOCK_H */