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 \
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);
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);
}
--- /dev/null
+/*
+ * 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);
--- /dev/null
+#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 */
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;
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;
}
ret = lttng_metadata_printf(session,
"clock {\n"
- " name = %s;\n",
- "monotonic"
+ " name = \"%s\";\n",
+ trace_clock_name()
);
if (ret)
goto end;
}
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()
);
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;
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);
* 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);
#include <linux/version.h>
#include <asm/local.h>
#include "../lttng-kernel-version.h"
+#include "../lttng-clock.h"
#include "percpu-defs.h"
#include "random.h"
#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);
}
#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)
{
{
}
+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 */