Implement clock plugin support
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sun, 12 Oct 2014 11:47:15 +0000 (13:47 +0200)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 25 Sep 2015 17:09:58 +0000 (13:09 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Makefile
lttng-abi.c
lttng-clock.c [new file with mode: 0644]
lttng-clock.h [new file with mode: 0644]
lttng-events.c
lttng-events.h
wrapper/random.h
wrapper/trace-clock.h

index 7c878f0589209fa893b21a29709091e08e202380..f7aa23f6127959f0d3309790639b3f38fdf2d1c6 100644 (file)
--- 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 \
index d47280f502f61c3c4a5792752443030caeb58c2b..f6f30430b9e89c4547d55f4c705fc233379ffe53 100644 (file)
@@ -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,
                                        &lttng_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 (file)
index 0000000..4296d6c
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * lttng-clock.c
+ *
+ * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/mutex.h>
+
+#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 <mathieu.desnoyers@efficios.com>");
+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 (file)
index 0000000..5da4f0c
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _LTTNG_CLOCK_H
+#define _LTTNG_CLOCK_H
+
+/*
+ * lttng-clock.h
+ *
+ * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * 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 <linux/module.h>
+
+#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 */
index f648feb67a64c8ab180c429ec77db907e2ca5f8e..c1dc1acbc5124fde9369b6045adb0f3c12ffa01f 100644 (file)
@@ -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;
index 4bf8920f3fc18fe74b24704f7f45e1c4e244ec61..921bc1fc8342d9b7d2be1479cb8d50d07ef33e3c 100644 (file)
@@ -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);
index 8f13c185c37ec0f90967a0cf0f03e4e86e3f0f49..81d7995c573580c384ed7fe36d709b47ebb29944 100644 (file)
@@ -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);
 
index d7d18429ba1c1f17d22d35c4ce6ec8484aef422e..d2b7f19dba76e197738d055217250d38767bd816 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/version.h>
 #include <asm/local.h>
 #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 */
This page took 0.03627 seconds and 4 git commands to generate.