From 1c25284c690cd38b71789c4024089d28de21caea Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 7 Dec 2010 17:22:20 -0500 Subject: [PATCH] LTTng modules now builds again Signed-off-by: Mathieu Desnoyers --- Makefile | 6 +- discard/ltt-ascii.c | 583 ++++++++++++++++++ discard/ltt-channels.c | 397 ++++++++++++ discard/ltt-channels.h | 83 +++ .../ltt-marker-control.c | 1 - ltt-serialize.c => discard/ltt-serialize.c | 1 - ltt-tracer.c => discard/ltt-tracer.c | 0 discard/ltt-type-serializer.c | 94 +++ .../ltt-type-serializer.h | 7 +- ltt-core.c | 76 +-- ltt-debugfs-abi.c | 20 +- ltt-event-header.c | 12 +- ltt-events.c | 9 + ltt-events.h | 8 +- ltt-ring-buffer-client.h | 84 ++- ltt-tracer-core.h | 33 +- ltt-tracer.h | 130 +--- ltt-type-serializer.c | 113 ---- 18 files changed, 1291 insertions(+), 366 deletions(-) create mode 100644 discard/ltt-ascii.c create mode 100644 discard/ltt-channels.c create mode 100644 discard/ltt-channels.h rename ltt-marker-control.c => discard/ltt-marker-control.c (99%) rename ltt-serialize.c => discard/ltt-serialize.c (99%) rename ltt-tracer.c => discard/ltt-tracer.c (100%) create mode 100644 discard/ltt-type-serializer.c rename ltt-type-serializer.h => discard/ltt-type-serializer.h (94%) delete mode 100644 ltt-type-serializer.c diff --git a/Makefile b/Makefile index 6e4da6c9..109b8060 100644 --- a/Makefile +++ b/Makefile @@ -6,14 +6,14 @@ ifneq ($(KERNELRELEASE),) ifneq ($(CONFIG_TRACEPOINTS),) obj-m += ltt-core.o -obj-m += ltt-debugfs-abi.o -obj-m += ltt-events.o obj-m += ltt-ring-buffer-client-discard.o obj-m += ltt-ring-buffer-client-overwrite.o obj-m += ltt-relay.o -ltt-relay-objs := ltt-event-header.o ltt-serialize.o ltt-type-serializer.o +ltt-relay-objs := ltt-events.o ltt-event-header.o ltt-debugfs-abi.o +#ltt-type-serializer.o +#ltt-serialize.o #obj-m += ltt-marker-control.o #obj-m += ltt-trace-control.o #ltt-ascii.o diff --git a/discard/ltt-ascii.c b/discard/ltt-ascii.c new file mode 100644 index 00000000..b020fedb --- /dev/null +++ b/discard/ltt-ascii.c @@ -0,0 +1,583 @@ +/* + * LTT ascii binary buffer to ascii converter. + * + * Copyright 2008 - 2009 Lai Jiangshan (laijs@cn.fujitsu.com) + * Copyright 2009 - Mathieu Desnoyers mathieu.desnoyers@polymtl.ca + * + * Dual LGPL v2.1/GPL v2 license. + */ + +/* + * TODO + * + * Move to new switch behavior: Wait for data for the duration of the + * timer interval + safety, if none is coming, consider that no activity occured + * in the buffer. + * + * Fix case when having a text file open and destroying trace. + * + * - Automate periodical switch: + * + * The debugfs file "switch_timer" receives a timer period as parameter + * (e.g. echo 100 > switch_timer) to activate the timer per channel. This can + * also be accessed through the internal API _before the trace session starts_. + * This timer will insure that we periodically have subbuffers to read, and + * therefore that the merge-sort does not wait endlessly for a subbuffer. + * + * - If a channel is switched and read without data, make sure it is still + * considered afterward (not removed from the queue). + * + * - Create a ascii/tracename/ALL file to merge-sort all active channels. + * - Create a ascii/tracename/README file to contain the text output legend. + * - Remove leading zeroes from timestamps. + * - Enhance pretty-printing to make sure all types used for addesses output in + * the form 0xAB00000000 (not decimal). This is true for %p and 0x%...X. + * - Hotplug support + */ + + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ltt-tracer.h" +#include "ltt-relay.h" +#include "ltt-relay-lockless.h" + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt , a...) +#endif + +struct dentry *ltt_ascii_dir_dentry; +EXPORT_SYMBOL_GPL(ltt_ascii_dir_dentry); + +struct ltt_relay_iter; + +struct ltt_relay_cpu_iter { + /* cpu buffer information */ + struct ltt_chanbuf *buf; + struct ltt_relay_iter *iter; + int sb_ref; /* holding a reference to a subbuffer */ + long read_sb_offset; /* offset of the subbuffer read */ + + /* current event information */ + struct ltt_subbuffer_header *header; + long hdr_offset; /* event header offset */ + long payload_offset; /* event payload offset */ + u64 tsc; /* full 64-bits timestamp value */ + u32 data_size; + u16 chID; /* channel ID, const */ + u16 eID; +}; + +struct ltt_relay_iter { + struct ltt_relay_cpu_iter iter_cpu[NR_CPUS]; + struct ltt_chan *chan; + loff_t pos; + int cpu; + int nr_refs; +}; + +/* + * offset of 0 in subbuffer means "subbuf size" (filled subbuffer). + */ +static int is_subbuffer_offset_end(struct ltt_relay_cpu_iter *citer, + long offset) +{ + struct ltt_chan *chan = container_of(citer->buf->a.chan, + struct ltt_chan, a); + long sub_offset = SUBBUF_OFFSET(offset - 1, chan) + 1; + + return (sub_offset <= citer->header->data_size); +} + +static u64 calculate_tsc(u64 pre_tsc, u64 read_tsc, unsigned int rflags) +{ + u64 new_tsc = read_tsc; + + if (rflags != LTT_RFLAG_ID_SIZE_TSC) { + BUG_ON(read_tsc >> LTT_TSC_BITS); + + new_tsc = (pre_tsc & ~LTT_TSC_MASK) + read_tsc; + if (read_tsc < (pre_tsc & LTT_TSC_MASK)) + new_tsc += 1UL << LTT_TSC_BITS; + } + + return new_tsc; +} + +/* + * calculate payload offset */ +static inline long calculate_payload_offset(long offset, u16 chID, u16 eID) +{ + const char *fmt; + + if (!ltt_get_alignment()) + return offset; + + fmt = marker_get_fmt_from_id(chID, eID); + BUG_ON(!fmt); + + return offset + ltt_fmt_largest_align(offset, fmt); +} + +static void update_new_event(struct ltt_relay_cpu_iter *citer, long hdr_offset) +{ + u64 read_tsc; + unsigned int rflags; + long tmp_offset; + + WARN_ON_ONCE(hdr_offset != citer->hdr_offset); + + tmp_offset = ltt_read_event_header(&citer->buf->a, hdr_offset, + &read_tsc, &citer->data_size, + &citer->eID, &rflags); + citer->payload_offset = calculate_payload_offset(tmp_offset, + citer->chID, + citer->eID); + + citer->tsc = calculate_tsc(citer->tsc, read_tsc, rflags); +} + +static void update_event_size(struct ltt_relay_cpu_iter *citer, long hdr_offset) +{ + char output[1]; + const char *fmt; + size_t data_size; + + if (citer->data_size != INT_MAX) + return; + + fmt = marker_get_fmt_from_id(citer->chID, citer->eID); + BUG_ON(!fmt); + ltt_serialize_printf(citer->buf, citer->payload_offset, + &data_size, output, 0, fmt); + citer->data_size = data_size; +} + +static void update_cpu_iter(struct ltt_relay_cpu_iter *citer, long hdr_offset) +{ + if (unlikely((!citer->sb_ref) + || is_subbuffer_offset_end(citer, hdr_offset))) { + citer->header = NULL; + return; + } + update_new_event(citer, hdr_offset); + update_event_size(citer, hdr_offset); +} + +/* + * returns 0 if we get a subbuffer reference. + * else, the buffer has not available data, try again later. + */ +static int subbuffer_start(struct ltt_relay_cpu_iter *citer, long *offset) +{ + int ret; + struct ltt_relay_iter *iter = citer->iter; + + ret = ltt_chanbuf_get_subbuf(citer->buf, offset); + if (!ret) { + citer->header = ltt_relay_read_offset_address(&citer->buf->a, + *offset); + citer->hdr_offset = (*offset) + ltt_sb_header_size(); + citer->tsc = citer->header->cycle_count_begin; + iter->nr_refs++; + citer->sb_ref = 1; + return 0; + } else { + if (ltt_chanbuf_is_finalized(citer->buf)) + return -ENODATA; + else + return -EAGAIN; + } +} + +static void subbuffer_stop(struct ltt_relay_cpu_iter *citer, + long offset) +{ + int ret; + struct ltt_relay_iter *iter = citer->iter; + + WARN_ON_ONCE(!citer->sb_ref); + ret = ltt_chanbuf_put_subbuf(citer->buf, offset); + WARN_ON_ONCE(ret); + citer->sb_ref = 0; + iter->nr_refs--; +} + +static void ltt_relay_advance_cpu_iter(struct ltt_relay_cpu_iter *citer) +{ + long old_offset = citer->payload_offset; + long new_offset = citer->payload_offset; + int ret; + + /* find that whether we read all data in this subbuffer */ + if (unlikely(is_subbuffer_offset_end(citer, + old_offset + citer->data_size))) { + DEBUGP(KERN_DEBUG "LTT ASCII stop cpu %d offset %lX\n", + citer->buf->a.cpu, citer->read_sb_offset); + subbuffer_stop(citer, citer->read_sb_offset); + for (;;) { + ret = subbuffer_start(citer, &citer->read_sb_offset); + DEBUGP(KERN_DEBUG + "LTT ASCII start cpu %d ret %d offset %lX\n", + citer->buf->a.cpu, ret, citer->read_sb_offset); + if (!ret || ret == -ENODATA) { + break; /* got data, or finalized */ + } else { /* -EAGAIN */ + if (signal_pending(current)) + break; + schedule_timeout_interruptible(1); + //TODO: check for no-data delay. take ref. break + } + } + } else { + new_offset += citer->data_size; + citer->hdr_offset = new_offset + ltt_align(new_offset, sizeof(struct ltt_event_header)); + DEBUGP(KERN_DEBUG + "LTT ASCII old_offset %lX new_offset %lX cpu %d\n", + old_offset, new_offset, citer->buf->a.cpu); + } + + update_cpu_iter(citer, citer->hdr_offset); +} + +static int cpu_iter_eof(struct ltt_relay_cpu_iter *citer) +{ + return !citer->sb_ref; +} + +static int ltt_relay_iter_eof(struct ltt_relay_iter *iter) +{ + return iter->nr_refs == 0; +} + +static void ltt_relay_advance_iter(struct ltt_relay_iter *iter) +{ + int i; + struct ltt_relay_cpu_iter *curr, *min = NULL; + iter->cpu = -1; + + /* + * find the event with the minimum tsc. + * TODO: use min-heep for 4096CPUS + */ + for_each_possible_cpu(i) { + curr = &iter->iter_cpu[i]; + + if (!curr->buf->a.allocated || !curr->header) + continue; + + if (cpu_iter_eof(curr)) + continue; + + if (!min || curr->tsc < min->tsc) { + min = curr; + iter->cpu = i; + } + } + + /* update cpu_iter for next ltt_relay_advance_iter() */ + if (min) + ltt_relay_advance_cpu_iter(min); +} + +static void *ascii_next(struct seq_file *m, void *v, loff_t *ppos) +{ + struct ltt_relay_iter *iter = m->private; + + WARN_ON_ONCE(!iter->nr_refs); + BUG_ON(v != iter); + + ltt_relay_advance_iter(iter); + return (ltt_relay_iter_eof(iter) || signal_pending(current)) + ? NULL : iter; +} + +static void *ascii_start(struct seq_file *m, loff_t *ppos) +{ + struct ltt_relay_iter *iter = m->private; + + ltt_relay_advance_iter(iter); + return (ltt_relay_iter_eof(iter) || signal_pending(current)) + ? NULL : iter; +} + +static void ascii_stop(struct seq_file *m, void *v) +{ +} + +static +int seq_serialize(struct seq_file *m, struct ltt_chanbuf *buf, + size_t buf_offset, const char *fmt, size_t *data_size) +{ + int len; + + if (m->count < m->size) { + len = ltt_serialize_printf(buf, buf_offset, data_size, + m->buf + m->count, + m->size - m->count, fmt); + if (m->count + len < m->size) { + m->count += len; + return 0; + } + } + + m->count = m->size; + return -1; +} + +static int ascii_show(struct seq_file *m, void *v) +{ + struct ltt_relay_iter *iter = v; + struct ltt_relay_cpu_iter *citer; + const char *name; + const char *fmt; + unsigned long long tsc; + size_t data_size; + + if (iter->cpu == -1) + return 0; + + citer = &iter->iter_cpu[iter->cpu]; + WARN_ON_ONCE(!citer->sb_ref); + /* + * Nothing to show, we are at the end of the last subbuffer currently + * having data. + */ + if (!citer->header) + return 0; + + tsc = citer->tsc; + name = marker_get_name_from_id(citer->chID, citer->eID); + fmt = marker_get_fmt_from_id(citer->chID, citer->eID); + + if (!name || !fmt) + return 0; + + seq_printf(m, "event:%16.16s: cpu:%2d time:%20.20llu ", + name, iter->cpu, tsc); + seq_serialize(m, citer->buf, citer->payload_offset, fmt, &data_size); + seq_puts(m, "\n"); + if (citer->data_size == INT_MAX) + citer->data_size = data_size; + + return 0; +} + +static struct seq_operations ascii_seq_ops = { + .start = ascii_start, + .next = ascii_next, + .stop = ascii_stop, + .show = ascii_show, +}; + +/* FIXME : cpu hotplug support */ +static int ltt_relay_iter_open_channel(struct ltt_relay_iter *iter, + struct ltt_chan *chan) +{ + int i, ret; + u16 chID = ltt_channels_get_index_from_name(chan->a.filename); + + /* we don't need lock relay_channels_mutex */ + for_each_possible_cpu(i) { + struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i]; + + citer->buf = per_cpu_ptr(chan->a.buf, i); + if (!citer->buf->a.allocated) + continue; + + citer->iter = iter; /* easy lazy parent info */ + citer->chID = chID; + + ret = ltt_chanbuf_open_read(citer->buf); + if (ret) { + /* Failed to open a percpu buffer, close everything. */ + citer->buf = NULL; + goto error; + } + + for (;;) { + ret = subbuffer_start(citer, + &citer->read_sb_offset); + DEBUGP(KERN_DEBUG + "LTT ASCII open start " + "cpu %d ret %d offset %lX\n", + citer->buf->a.cpu, ret, citer->read_sb_offset); + if (!ret || ret == -ENODATA) { + break; /* got data, or finalized */ + } else { /* -EAGAIN */ + if (signal_pending(current)) + break; + schedule_timeout_interruptible(1); + } + } + update_cpu_iter(citer, citer->hdr_offset); + } + if (!iter->nr_refs) { + ret = -ENODATA; + goto error; + } + + return 0; + +error: + for_each_possible_cpu(i) { + struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i]; + + if (!citer->buf) + break; + + if (citer->buf->a.allocated) + ltt_chanbuf_release_read(citer->buf); + } + return ret; +} + +/* FIXME : cpu hotplug support */ +static int ltt_relay_iter_release_channel(struct ltt_relay_iter *iter) +{ + int i; + + for_each_possible_cpu(i) { + struct ltt_relay_cpu_iter *citer = &iter->iter_cpu[i]; + + if (citer->sb_ref) { + WARN_ON_ONCE(!citer->buf->a.allocated); + DEBUGP(KERN_DEBUG + "LTT ASCII release stop cpu %d offset %lX\n", + citer->buf->a.cpu, citer->read_sb_offset); + subbuffer_stop(&iter->iter_cpu[i], + citer->read_sb_offset); + } + if (citer->buf->a.allocated) + ltt_chanbuf_release_read(citer->buf); + } + WARN_ON_ONCE(iter->nr_refs); + return 0; +} + +static int ltt_relay_ascii_open(struct inode *inode, struct file *file) +{ + int ret; + struct ltt_chan *chan = inode->i_private; + struct ltt_relay_iter *iter = kzalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + + iter->chan = chan; + ret = ltt_relay_iter_open_channel(iter, chan); + if (ret) + goto error_free_alloc; + + ret = seq_open(file, &ascii_seq_ops); + if (ret) + goto error_release_channel; + ((struct seq_file *)file->private_data)->private = iter; + return 0; + +error_release_channel: + ltt_relay_iter_release_channel(iter); +error_free_alloc: + kfree(iter); + return ret; +} + +static int ltt_relay_ascii_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct ltt_relay_iter *iter = seq->private; + + ltt_relay_iter_release_channel(iter); + kfree(iter); + return 0; +} + +static struct file_operations ltt_ascii_fops = +{ + .read = seq_read, + .open = ltt_relay_ascii_open, + .release = ltt_relay_ascii_release, + .llseek = no_llseek, + .owner = THIS_MODULE, +}; + +int ltt_ascii_create(struct ltt_chan *chan) +{ + struct dentry *dentry; + + dentry = debugfs_create_file(chan->a.filename, + S_IRUSR | S_IRGRP, + chan->a.trace->dentry.ascii_root, + chan, <t_ascii_fops); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + if (!dentry) + return -EEXIST; + + chan->a.ascii_dentry = dentry; + dentry->d_inode->i_private = chan; + return 0; +} +EXPORT_SYMBOL_GPL(ltt_ascii_create); + +void ltt_ascii_remove(struct ltt_chan *chan) +{ + struct dentry *dentry; + + dentry = dget(chan->a.ascii_dentry); + debugfs_remove(dentry); + /* TODO: wait / wakeup instead */ + /* + * Wait for every reference to the dentry to be gone, + * except us. + */ + while (atomic_read(&dentry->d_count) != 1) + msleep(100); + dput(dentry); +} +EXPORT_SYMBOL_GPL(ltt_ascii_remove); + +int ltt_ascii_create_dir(struct ltt_trace *new_trace) +{ + new_trace->dentry.ascii_root = debugfs_create_dir(new_trace->trace_name, + ltt_ascii_dir_dentry); + if (!new_trace->dentry.ascii_root) + return -EEXIST; + return 0; +} +EXPORT_SYMBOL_GPL(ltt_ascii_create_dir); + +void ltt_ascii_remove_dir(struct ltt_trace *trace) +{ + debugfs_remove(trace->dentry.ascii_root); +} +EXPORT_SYMBOL_GPL(ltt_ascii_remove_dir); + +__init int ltt_ascii_init(void) +{ + ltt_ascii_dir_dentry = debugfs_create_dir(LTT_ASCII, get_ltt_root()); + + return ltt_ascii_dir_dentry ? 0 : -EFAULT; +} + +__exit void ltt_ascii_exit(void) +{ + debugfs_remove(ltt_ascii_dir_dentry); + put_ltt_root(); +} + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Lai Jiangshan@FNST and Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Ascii Converter"); diff --git a/discard/ltt-channels.c b/discard/ltt-channels.c new file mode 100644 index 00000000..962c81a8 --- /dev/null +++ b/discard/ltt-channels.c @@ -0,0 +1,397 @@ +/* + * ltt/ltt-channels.c + * + * (C) Copyright 2008 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) + * + * LTTng channel management. + * + * Author: + * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) + * + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include "ltt-channels.h" + +/* + * ltt_channel_mutex may be nested inside the LTT trace mutex. + * ltt_channel_mutex mutex may be nested inside markers mutex. + */ +static DEFINE_MUTEX(ltt_channel_mutex); +static LIST_HEAD(ltt_channels); +/* + * Index of next channel in array. Makes sure that as long as a trace channel is + * allocated, no array index will be re-used when a channel is freed and then + * another channel is allocated. This index is cleared and the array indexeds + * get reassigned when the index_kref goes back to 0, which indicates that no + * more trace channels are allocated. + */ +static unsigned int free_index; +/* index_kref is protected by both ltt_channel_mutex and lock_markers */ +static struct kref index_kref; /* Keeps track of allocated trace channels */ + +static struct ltt_channel_setting *lookup_channel(const char *name) +{ + struct ltt_channel_setting *iter; + + list_for_each_entry(iter, <t_channels, list) + if (strcmp(name, iter->name) == 0) + return iter; + return NULL; +} + +/* + * Must be called when channel refcount falls to 0 _and_ also when the last + * trace is freed. This function is responsible for compacting the channel and + * event IDs when no users are active. + * + * Called with lock_markers() and channels mutex held. + */ +static void release_channel_setting(struct kref *kref) +{ + struct ltt_channel_setting *setting = container_of(kref, + struct ltt_channel_setting, kref); + struct ltt_channel_setting *iter; + + if (atomic_read(&index_kref.refcount) == 0 + && atomic_read(&setting->kref.refcount) == 0) { + list_del(&setting->list); + kfree(setting); + + free_index = 0; + list_for_each_entry(iter, <t_channels, list) { + iter->index = free_index++; + iter->free_event_id = 0; + } + } +} + +/* + * Perform channel index compaction when the last trace channel is freed. + * + * Called with lock_markers() and channels mutex held. + */ +static void release_trace_channel(struct kref *kref) +{ + struct ltt_channel_setting *iter, *n; + + list_for_each_entry_safe(iter, n, <t_channels, list) + release_channel_setting(&iter->kref); + if (atomic_read(&index_kref.refcount) == 0) + markers_compact_event_ids(); +} + +/* + * ltt_channel_trace_ref : Is there an existing trace session ? + * + * Must be called with lock_markers() held. + */ +int ltt_channels_trace_ref(void) +{ + return !!atomic_read(&index_kref.refcount); +} +EXPORT_SYMBOL_GPL(ltt_channels_trace_ref); + +/** + * ltt_channels_register - Register a trace channel. + * @name: channel name + * + * Uses refcounting. + */ +int ltt_channels_register(const char *name) +{ + struct ltt_channel_setting *setting; + int ret = 0; + + mutex_lock(<t_channel_mutex); + setting = lookup_channel(name); + if (setting) { + if (atomic_read(&setting->kref.refcount) == 0) + goto init_kref; + else { + kref_get(&setting->kref); + goto end; + } + } + setting = kzalloc(sizeof(*setting), GFP_KERNEL); + if (!setting) { + ret = -ENOMEM; + goto end; + } + list_add(&setting->list, <t_channels); + strncpy(setting->name, name, PATH_MAX-1); + setting->index = free_index++; +init_kref: + kref_init(&setting->kref); +end: + mutex_unlock(<t_channel_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(ltt_channels_register); + +/** + * ltt_channels_unregister - Unregister a trace channel. + * @name: channel name + * @compacting: performing compaction + * + * Must be called with markers mutex held. + */ +int ltt_channels_unregister(const char *name, int compacting) +{ + struct ltt_channel_setting *setting; + int ret = 0; + + if (!compacting) + mutex_lock(<t_channel_mutex); + setting = lookup_channel(name); + if (!setting || atomic_read(&setting->kref.refcount) == 0) { + ret = -ENOENT; + goto end; + } + kref_put(&setting->kref, release_channel_setting); + if (!compacting && atomic_read(&index_kref.refcount) == 0) + markers_compact_event_ids(); +end: + if (!compacting) + mutex_unlock(<t_channel_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(ltt_channels_unregister); + +/** + * ltt_channels_set_default - Set channel default behavior. + * @name: default channel name + * @sb_size: size of the subbuffers + * @n_sb: number of subbuffers + */ +int ltt_channels_set_default(const char *name, + unsigned int sb_size, + unsigned int n_sb) +{ + struct ltt_channel_setting *setting; + int ret = 0; + + mutex_lock(<t_channel_mutex); + setting = lookup_channel(name); + if (!setting || atomic_read(&setting->kref.refcount) == 0) { + ret = -ENOENT; + goto end; + } + setting->sb_size = sb_size; + setting->n_sb = n_sb; +end: + mutex_unlock(<t_channel_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(ltt_channels_set_default); + +/** + * ltt_channels_get_name_from_index - get channel name from channel index + * @index: channel index + * + * Allows to lookup the channel name given its index. Done to keep the name + * information outside of each trace channel instance. + */ +const char *ltt_channels_get_name_from_index(unsigned int index) +{ + struct ltt_channel_setting *iter; + + list_for_each_entry(iter, <t_channels, list) + if (iter->index == index && atomic_read(&iter->kref.refcount)) + return iter->name; + return NULL; +} +EXPORT_SYMBOL_GPL(ltt_channels_get_name_from_index); + +static struct ltt_channel_setting * +ltt_channels_get_setting_from_name(const char *name) +{ + struct ltt_channel_setting *iter; + + list_for_each_entry(iter, <t_channels, list) + if (!strcmp(iter->name, name) + && atomic_read(&iter->kref.refcount)) + return iter; + return NULL; +} + +/** + * ltt_channels_get_index_from_name - get channel index from channel name + * @name: channel name + * + * Allows to lookup the channel index given its name. Done to keep the name + * information outside of each trace channel instance. + * Returns -1 if not found. + */ +int ltt_channels_get_index_from_name(const char *name) +{ + struct ltt_channel_setting *setting; + + setting = ltt_channels_get_setting_from_name(name); + if (setting) + return setting->index; + else + return -1; +} +EXPORT_SYMBOL_GPL(ltt_channels_get_index_from_name); + +/** + * ltt_channels_trace_alloc - Allocate channel structures for a trace + * + * Use the current channel list to allocate the channels for a trace. + * Called with trace lock held. Does not perform the trace buffer allocation, + * because we must let the user overwrite specific channel sizes. + */ +int ltt_channels_trace_alloc(struct ltt_trace *trace, int overwrite) +{ + struct channel **chan = NULL; + struct ltt_channel_setting *chans, *iter; + int ret = 0; + + lock_markers(); + mutex_lock(<t_channel_mutex); + if (!free_index) + goto end; + if (!atomic_read(&index_kref.refcount)) + kref_init(&index_kref); + else + kref_get(&index_kref); + trace->nr_channels = free_index; + chan = kzalloc(sizeof(struct channel *) * free_index, GFP_KERNEL); + if (!chan) + goto end; + chans = kzalloc(sizeof(struct ltt_channel_setting) * free_index, + GFP_KERNEL); + if (!chan_settings) + goto free_chan; + list_for_each_entry(iter, <t_channels, list) { + if (!atomic_read(&iter->kref.refcount)) + continue; + chans[iter->index].sb_size = iter->sb_size; + chans[iter->index].n_sb = iter->n_sb; + chans[iter->index].overwrite = overwrite; + strncpy(chans[iter->index].filename, iter->name, + NAME_MAX - 1); + chans[iter->index].switch_timer_interval = 0; + chans[iter->index].read_timer_interval = LTT_READ_TIMER_INTERVAL; + } + trace->channels = chan; + trace->settings = chans; +end: + mutex_unlock(<t_channel_mutex); + unlock_markers(); + return ret; + +free_chan: + kfree(chan); + ret = -ENOMEM; + goto end; +} +EXPORT_SYMBOL_GPL(ltt_channels_trace_alloc); + +/** + * ltt_channels_trace_free - Free one trace's channels + * @channels: channels to free + * + * Called with trace lock held. The actual channel buffers must be freed before + * this function is called. + */ +void ltt_channels_trace_free(struct ltt_trace *trace) +{ + lock_markers(); + mutex_lock(<t_channel_mutex); + kfree(trace->settings); + kfree(trace->channels); + kref_put(&index_kref, release_trace_channel); + mutex_unlock(<t_channel_mutex); + unlock_markers(); + marker_update_probes(); +} +EXPORT_SYMBOL_GPL(ltt_channels_trace_free); + +/** + * ltt_channels_trace_set_timer - set switch timer + * @channel: channel + * @interval: interval of timer interrupt, in jiffies. 0 inhibits timer. + */ + +void ltt_channels_trace_set_timer(struct ltt_chan *chan, + unsigned long interval) +{ + chan->switch_timer_interval = interval; +} +EXPORT_SYMBOL_GPL(ltt_channels_trace_set_timer); + +/** + * _ltt_channels_get_event_id - get next event ID for a marker + * @channel: channel name + * @name: event name + * + * Returns a unique event ID (for this channel) or < 0 on error. + * Must be called with channels mutex held. + */ +int _ltt_channels_get_event_id(const char *channel, const char *name) +{ + struct ltt_channel_setting *setting; + int ret; + + setting = ltt_channels_get_setting_from_name(channel); + if (!setting) { + ret = -ENOENT; + goto end; + } + if (strcmp(channel, "metadata") == 0) { + if (strcmp(name, "core_marker_id") == 0) + ret = 0; + else if (strcmp(name, "core_marker_format") == 0) + ret = 1; + else + ret = -ENOENT; + goto end; + } + if (setting->free_event_id == EVENTS_PER_CHANNEL - 1) { + ret = -ENOSPC; + goto end; + } + ret = setting->free_event_id++; +end: + return ret; +} + +/** + * ltt_channels_get_event_id - get next event ID for a marker + * @channel: channel name + * @name: event name + * + * Returns a unique event ID (for this channel) or < 0 on error. + */ +int ltt_channels_get_event_id(const char *channel, const char *name) +{ + int ret; + + mutex_lock(<t_channel_mutex); + ret = _ltt_channels_get_event_id(channel, name); + mutex_unlock(<t_channel_mutex); + return ret; +} + +/** + * ltt_channels_reset_event_ids - reset event IDs at compaction + * + * Called with lock marker and channel mutex held. + */ +void _ltt_channels_reset_event_ids(void) +{ + struct ltt_channel_setting *iter; + + list_for_each_entry(iter, <t_channels, list) + iter->free_event_id = 0; +} + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Channel Management"); diff --git a/discard/ltt-channels.h b/discard/ltt-channels.h new file mode 100644 index 00000000..9eb604ba --- /dev/null +++ b/discard/ltt-channels.h @@ -0,0 +1,83 @@ +#ifndef _LTT_CHANNELS_H +#define _LTT_CHANNELS_H + +/* + * Copyright (C) 2008 Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) + * + * Dynamic tracer channel allocation. + + * Dual LGPL v2.1/GPL v2 license. + */ + +#include +#include +#include +#include +#include + +#define EVENTS_PER_CHANNEL 65536 + +#define LTT_READ_TIMER_INTERVAL 10000 /* us */ + +/* + * Forward declaration of locking-specific per-cpu buffer structure. + */ +struct ltt_trace; +struct ltt_serialize_closure; +struct ltt_probe_private_data; + +/* Serialization callback '%k' */ +typedef size_t (*ltt_serialize_cb)(struct ltt_chanbuf *buf, size_t buf_offset, + struct ltt_serialize_closure *closure, + void *serialize_private, + unsigned int stack_pos_ctx, + int *largest_align, + const char *fmt, va_list *args); + +struct ltt_probe_private_data { + struct ltt_trace *trace; /* + * Target trace, for metadata + * or statedump. + */ + ltt_serialize_cb serializer; /* + * Serialization function override. + */ + void *serialize_private; /* + * Private data for serialization + * functions. + */ +}; + +struct ltt_channel_setting { + unsigned int sb_size; + unsigned int n_sb; + int overwrite; + unsigned long switch_timer_interval; + unsigned long read_timer_interval; + struct kref kref; /* Number of references to structure content */ + struct list_head list; + unsigned int index; /* index of channel in trace channel array */ + u16 free_event_id; /* Next event ID to allocate */ + char name[PATH_MAX]; +}; + +int ltt_channels_register(const char *name); +int ltt_channels_unregister(const char *name, int compacting); +int ltt_channels_set_default(const char *name, + unsigned int subbuf_size, + unsigned int subbuf_cnt); +const char *ltt_channels_get_name_from_index(unsigned int index); +int ltt_channels_get_index_from_name(const char *name); +int ltt_channels_trace_ref(void); +struct ltt_chan *ltt_channels_trace_alloc(unsigned int *nr_channels, + int overwrite, int active); +void ltt_channels_trace_free(struct ltt_chan *channels, + unsigned int nr_channels); +void ltt_channels_trace_set_timer(struct ltt_channel_setting *chan, + unsigned long interval); + +int _ltt_channels_get_event_id(const char *channel, const char *name); +int ltt_channels_get_event_id(const char *channel, const char *name); +void _ltt_channels_reset_event_ids(void); + +#endif /* _LTT_CHANNELS_H */ diff --git a/ltt-marker-control.c b/discard/ltt-marker-control.c similarity index 99% rename from ltt-marker-control.c rename to discard/ltt-marker-control.c index 61424308..2db5c4e9 100644 --- a/ltt-marker-control.c +++ b/discard/ltt-marker-control.c @@ -121,7 +121,6 @@ EXPORT_SYMBOL_GPL(ltt_probe_unregister); */ int ltt_marker_connect(const char *channel, const char *mname, const char *pname) - { int ret; struct ltt_active_marker *pdata; diff --git a/ltt-serialize.c b/discard/ltt-serialize.c similarity index 99% rename from ltt-serialize.c rename to discard/ltt-serialize.c index 1d5a5dfb..50d7132c 100644 --- a/ltt-serialize.c +++ b/discard/ltt-serialize.c @@ -17,7 +17,6 @@ #include #include "ltt-tracer.h" -#include "ltt-relay-lockless.h" enum ltt_type { LTT_TYPE_SIGNED_INT, diff --git a/ltt-tracer.c b/discard/ltt-tracer.c similarity index 100% rename from ltt-tracer.c rename to discard/ltt-tracer.c diff --git a/discard/ltt-type-serializer.c b/discard/ltt-type-serializer.c new file mode 100644 index 00000000..ed589c73 --- /dev/null +++ b/discard/ltt-type-serializer.c @@ -0,0 +1,94 @@ +/** + * ltt-type-serializer.c + * + * LTTng specialized type serializer. + * + * Copyright Mathieu Desnoyers, 2008. + * + * Dual LGPL v2.1/GPL v2 license. + */ +#include + +#include "ltt-type-serializer.h" +#include "ltt-relay-lockless.h" + +notrace +void _ltt_specialized_trace(void *probe_data, + void *serialize_private, unsigned int data_size, + unsigned int largest_align) +{ + struct ltt_event *event = probe_data; + int ret; + uint16_t eID; + size_t slot_size; + struct ltt_chanbuf *buf; + struct ltt_channel *chan; + struct ltt_session *session; + uint64_t tsc; + long buf_offset; + int cpu; + unsigned int rflags; + + /* disabled from tracepoints rcu_read_lock_sched_notrace(); */ + cpu = smp_processor_id(); + __get_cpu_var(ltt_nesting)++; + /* + * asm volatile and "memory" clobber prevent the compiler from moving + * instructions out of the ltt nesting count. This is required to ensure + * that probe side-effects which can cause recursion (e.g. unforeseen + * traps, divisions by 0, ...) are triggered within the incremented + * nesting count section. + */ + barrier(); + eID = event->id; + chan = event->chan; + session = chan->session; + + if (unlikely(!session->active)) + goto skip; + if (unlikely(!ltt_run_filter(session, chan, event))) + goto skip; +#ifdef LTT_DEBUG_EVENT_SIZE + rflags = LTT_RFLAG_ID_SIZE; +#else + if (unlikely(eID >= LTT_FREE_EVENTS)) + rflags = LTT_RFLAG_ID; + else + rflags = 0; +#endif + /* reserve space : header and data */ + ret = ltt_reserve_slot(chan, trace, data_size, largest_align, + cpu, &buf, &slot_size, &buf_offset, &tsc, + &rflags); + if (unlikely(ret < 0)) + goto skip; /* buffer full */ + + /* Out-of-order write : header and data */ + buf_offset = ltt_write_event_header(&buf->a, &chan->a, + buf_offset, eID, data_size, + tsc, rflags); + if (data_size) { + buf_offset += ltt_align(buf_offset, largest_align); + ltt_relay_write(&buf->a, &chan->a, buf_offset, + serialize_private, data_size); + buf_offset += data_size; + } + /* Out-of-order commit */ + ltt_commit_slot(buf, chan, buf_offset, data_size, slot_size); +skip: + /* + * asm volatile and "memory" clobber prevent the compiler from moving + * instructions out of the ltt nesting count. This is required to ensure + * that probe side-effects which can cause recursion (e.g. unforeseen + * traps, divisions by 0, ...) are triggered within the incremented + * nesting count section. + */ + barrier(); + __get_cpu_var(ltt_nesting)--; + /* disabled from tracepoints rcu_read_unlock_sched_notrace(); */ +} +EXPORT_SYMBOL_GPL(_ltt_specialized_trace); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("LTT type serializer"); diff --git a/ltt-type-serializer.h b/discard/ltt-type-serializer.h similarity index 94% rename from ltt-type-serializer.h rename to discard/ltt-type-serializer.h index 49712c82..fb870c8f 100644 --- a/ltt-type-serializer.h +++ b/discard/ltt-type-serializer.h @@ -9,7 +9,7 @@ * largest_align must be non-zero, equal to the minimum between the largest type * and sizeof(void *). */ -extern void _ltt_specialized_trace(const struct marker *mdata, void *probe_data, +extern void _ltt_specialized_trace(void *probe_data, void *serialize_private, unsigned int data_size, unsigned int largest_align); @@ -18,14 +18,13 @@ extern void _ltt_specialized_trace(const struct marker *mdata, void *probe_data, * dumb-proof. It will make sure 0 is changed into 1 and unsigned long long is * changed into sizeof(void *) on 32-bit architectures. */ -static inline void ltt_specialized_trace(const struct marker *mdata, - void *probe_data, +static inline void ltt_specialized_trace(void *probe_data, void *serialize_private, unsigned int data_size, unsigned int largest_align) { largest_align = min_t(unsigned int, largest_align, sizeof(void *)); largest_align = max_t(unsigned int, largest_align, 1); - _ltt_specialized_trace(mdata, probe_data, serialize_private, data_size, + _ltt_specialized_trace(probe_data, serialize_private, data_size, largest_align); } diff --git a/ltt-core.c b/ltt-core.c index 1a0424e9..fc55bdff 100644 --- a/ltt-core.c +++ b/ltt-core.c @@ -14,79 +14,9 @@ #include "ltt-tracer-core.h" -/* Traces structures */ -struct ltt_traces ltt_traces = { - .setup_head = LIST_HEAD_INIT(ltt_traces.setup_head), - .head = LIST_HEAD_INIT(ltt_traces.head), -}; -EXPORT_SYMBOL(ltt_traces); - -/* Traces list writer locking */ -static DEFINE_MUTEX(ltt_traces_mutex); - -/* root dentry mutex */ -static DEFINE_MUTEX(ltt_root_mutex); -/* dentry of ltt's root dir */ -static struct dentry *ltt_root_dentry; -static struct kref ltt_root_kref = { - .refcount = ATOMIC_INIT(0), -}; - -static void ltt_root_release(struct kref *ref) -{ - debugfs_remove(ltt_root_dentry); - ltt_root_dentry = NULL; -} - -void put_ltt_root(void) -{ - mutex_lock(<t_root_mutex); - if (ltt_root_dentry) - kref_put(<t_root_kref, ltt_root_release); - mutex_unlock(<t_root_mutex); -} -EXPORT_SYMBOL_GPL(put_ltt_root); - -struct dentry *get_ltt_root(void) -{ - mutex_lock(<t_root_mutex); - if (!ltt_root_dentry) { - ltt_root_dentry = debugfs_create_dir(LTT_ROOT, NULL); - if (!ltt_root_dentry) { - printk(KERN_ERR "LTT : create ltt root dir failed\n"); - goto out; - } - kref_init(<t_root_kref); - goto out; - } - kref_get(<t_root_kref); -out: - mutex_unlock(<t_root_mutex); - return ltt_root_dentry; -} -EXPORT_SYMBOL_GPL(get_ltt_root); - -/* - * ltt_lock_traces/ltt_unlock_traces also disables cpu hotplug. - */ -void ltt_lock_traces(void) -{ - mutex_lock(<t_traces_mutex); - get_online_cpus(); -} -EXPORT_SYMBOL_GPL(ltt_lock_traces); - -void ltt_unlock_traces(void) -{ - put_online_cpus(); - mutex_unlock(<t_traces_mutex); -} -EXPORT_SYMBOL_GPL(ltt_unlock_traces); - -DEFINE_PER_CPU(unsigned int, ltt_nesting); -EXPORT_PER_CPU_SYMBOL(ltt_nesting); - -int ltt_run_filter_default(void *trace, uint16_t eID) +int ltt_run_filter_default(struct ltt_session *session, + struct ltt_channel *chan, + struct ltt_event *event) { return 1; } diff --git a/ltt-debugfs-abi.c b/ltt-debugfs-abi.c index a1023613..7fb73392 100644 --- a/ltt-debugfs-abi.c +++ b/ltt-debugfs-abi.c @@ -53,7 +53,7 @@ int lttng_abi_create_session(void) session = ltt_session_create(); if (!session) return -ENOMEM; - session_fd = get_unused_fd_flags(O_RDWR); + session_fd = get_unused_fd(); if (session_fd < 0) { ret = session_fd; goto fd_error; @@ -119,7 +119,7 @@ int lttng_abi_create_channel(struct file *session_file, if (copy_from_user(&chan_param, uchan_param, sizeof(chan_param))) return -EFAULT; - chan_fd = get_unused_fd_flags(O_RDWR); + chan_fd = get_unused_fd(); if (chan_fd < 0) { ret = chan_fd; goto fd_error; @@ -226,7 +226,7 @@ int lttng_abi_open_stream(struct file *channel_file) if (!buf) return -ENOENT; - stream_fd = get_unused_fd_flags(O_RDWR); + stream_fd = get_unused_fd(); if (stream_fd < 0) { ret = stream_fd; goto fd_error; @@ -271,7 +271,7 @@ int lttng_abi_create_event(struct file *channel_file, goto name_error; } event_name[PATH_MAX - 1] = '\0'; - event_fd = get_unused_fd_flags(O_RDWR); + event_fd = get_unused_fd(); if (event_fd < 0) { ret = event_fd; goto fd_error; @@ -401,7 +401,7 @@ static const struct file_operations lttng_event_fops = { .release = lttng_event_release, }; -static int __init ltt_debugfs_abi_init(void) +int __init ltt_debugfs_abi_init(void) { int ret = 0; @@ -416,15 +416,7 @@ error: return ret; } -module_init(ltt_debugfs_abi_init); - -static void __exit ltt_debugfs_abi_exit(void) +void __exit ltt_debugfs_abi_exit(void) { debugfs_remove(lttng_dentry); } - -module_exit(ltt_debugfs_abi_exit); - -MODULE_LICENSE("GPL and additional rights"); -MODULE_AUTHOR("Mathieu Desnoyers"); -MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation DebugFS ABI"); diff --git a/ltt-event-header.c b/ltt-event-header.c index 94e29cbc..d2739fcb 100644 --- a/ltt-event-header.c +++ b/ltt-event-header.c @@ -14,14 +14,14 @@ #include #include "ltt-tracer.h" -size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config, +void ltt_write_event_header_slow(const struct lib_ring_buffer_config *config, struct lib_ring_buffer_ctx *ctx, u16 eID, u32 event_size) { struct event_header header; u16 small_size; - switch (rflags) { + switch (ctx->rflags) { case LTT_RFLAG_ID_SIZE_TSC: header.id_time = 29 << LTT_TSC_BITS; break; @@ -36,10 +36,10 @@ size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config, header.id_time = 0; } - header.id_time |= (u32)tsc & LTT_TSC_MASK; + header.id_time |= (u32)ctx->tsc & LTT_TSC_MASK; lib_ring_buffer_write(config, ctx, &header, sizeof(header)); - switch (rflags) { + switch (ctx->rflags) { case LTT_RFLAG_ID_SIZE_TSC: small_size = (u16)min_t(u32, event_size, LTT_MAX_SMALL_SIZE); lib_ring_buffer_write(config, ctx, &eID, sizeof(u16)); @@ -64,7 +64,3 @@ size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config, } } EXPORT_SYMBOL_GPL(ltt_write_event_header_slow); - -MODULE_LICENSE("GPL and additional rights"); -MODULE_AUTHOR("Mathieu Desnoyers"); -MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Event Header"); diff --git a/ltt-events.c b/ltt-events.c index 7c7cda65..f3f7ab78 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -263,10 +263,18 @@ EXPORT_SYMBOL_GPL(ltt_transport_unregister); static int __init ltt_events_init(void) { + int ret; + event_cache = KMEM_CACHE(ltt_event, 0); if (!event_cache) return -ENOMEM; + ret = ltt_debugfs_abi_init(); + if (ret) + goto error; return 0; +error: + kmem_cache_destroy(event_cache); + return ret; } module_init(ltt_events_init); @@ -275,6 +283,7 @@ static void __exit ltt_events_exit(void) { struct ltt_session *session, *tmpsession; + ltt_debugfs_abi_exit(); list_for_each_entry_safe(session, tmpsession, &sessions, list) ltt_session_destroy(session); kmem_cache_destroy(event_cache); diff --git a/ltt-events.h b/ltt-events.h index 6711341c..0d68e16a 100644 --- a/ltt-events.h +++ b/ltt-events.h @@ -14,6 +14,7 @@ struct ltt_channel; struct ltt_session; +struct lib_ring_buffer_ctx; /* * ltt_event structure is referred to by the tracing fast path. It must be @@ -38,7 +39,9 @@ struct ltt_channel_ops { unsigned int read_timer_interval); void (*channel_destroy)(struct channel *chan); struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan); - struct lib_ring_buffer *(*buffer_read_close)(struct lib_ring_buffer *buf); + void (*buffer_read_close)(struct lib_ring_buffer *buf); + int (*event_reserve)(struct lib_ring_buffer_ctx *ctx); + void (*event_commit)(struct lib_ring_buffer_ctx *ctx); }; struct ltt_channel { @@ -88,4 +91,7 @@ int _ltt_event_destroy(struct ltt_event *event); void ltt_transport_register(struct ltt_transport *transport); void ltt_transport_unregister(struct ltt_transport *transport); +int ltt_debugfs_abi_init(void); +void ltt_debugfs_abi_exit(void); + #endif /* _LTT_EVENTS_H */ diff --git a/ltt-ring-buffer-client.h b/ltt-ring-buffer-client.h index 93c793ff..229c06aa 100644 --- a/ltt-ring-buffer-client.h +++ b/ltt-ring-buffer-client.h @@ -34,29 +34,29 @@ size_t client_record_header_size(const struct lib_ring_buffer_config *config, } /** - * client_subbuffer_header_size - called on buffer-switch to a new sub-buffer + * client_packet_header_size - called on buffer-switch to a new sub-buffer * * Return header size without padding after the structure. Don't use packed * structure because gcc generates inefficient code on some architectures * (powerpc, mips..) */ -static size_t client_subbuffer_header_size(void) +static size_t client_packet_header_size(void) { - return offsetof(struct subbuffer_header, header_end); + return offsetof(struct packet_header, header_end); } static void client_buffer_begin(struct lib_ring_buffer *buf, u64 tsc, unsigned int subbuf_idx) { struct channel *chan = buf->backend.chan; - struct subbuffer_header *header = - (struct subbuffer_header *) + struct packet_header *header = + (struct packet_header *) lib_ring_buffer_offset_address(&buf->backend, subbuf_idx * chan->backend.subbuf_size); - header->cycle_count_begin = tsc; - header->data_size = 0xFFFFFFFF; /* for debugging */ - write_trace_header(chan->backend.priv, header); + header->timestamp_begin = tsc; + header->content_size = 0xFFFFFFFF; /* for debugging */ + write_trace_header(&client_config, header); } /* @@ -67,25 +67,25 @@ static void client_buffer_end(struct lib_ring_buffer *buf, u64 tsc, unsigned int subbuf_idx, unsigned long data_size) { struct channel *chan = buf->backend.chan; - struct subbuffer_header *header = - (struct subbuffer_header *) + struct packet_header *header = + (struct packet_header *) lib_ring_buffer_offset_address(&buf->backend, subbuf_idx * chan->backend.subbuf_size); unsigned long records_lost = 0; - header->data_size = data_size; - header->subbuf_size = PAGE_ALIGN(data_size); - header->cycle_count_end = tsc; + header->content_size = data_size; + header->packet_size = PAGE_ALIGN(data_size); + header->timestamp_end = tsc; records_lost += lib_ring_buffer_get_records_lost_full(&client_config, buf); records_lost += lib_ring_buffer_get_records_lost_wrap(&client_config, buf); records_lost += lib_ring_buffer_get_records_lost_big(&client_config, buf); header->events_lost = records_lost; - header->subbuf_corrupt = 0; /* deprecated */ } static int client_buffer_create(struct lib_ring_buffer *buf, void *priv, int cpu, const char *name) { + return 0; } static void client_buffer_finalize(struct lib_ring_buffer *buf, void *priv, int cpu) @@ -95,7 +95,7 @@ static void client_buffer_finalize(struct lib_ring_buffer *buf, void *priv, int static const struct lib_ring_buffer_config client_config = { .cb.ring_buffer_clock_read = client_ring_buffer_clock_read, .cb.record_header_size = client_record_header_size, - .cb.subbuffer_header_size = client_subbuffer_header_size, + .cb.subbuffer_header_size = client_packet_header_size, .cb.buffer_begin = client_buffer_begin, .cb.buffer_end = client_buffer_end, .cb.buffer_create = client_buffer_create, @@ -118,12 +118,13 @@ static const struct lib_ring_buffer_config client_config = { }; static -struct channel *ltt_channel_create(struct ltt_session *session, void *buf_addr, - size_t subbuf_size, size_t num_subbuf, - unsigned int switch_timer_interval, - unsigned int read_timer_interval) +struct channel *_channel_create(const char *name, + struct ltt_session *session, void *buf_addr, + size_t subbuf_size, size_t num_subbuf, + unsigned int switch_timer_interval, + unsigned int read_timer_interval) { - return channel_create(&client_config, "[lttng]", session, buf_addr, + return channel_create(&client_config, name, session, buf_addr, subbuf_size, num_subbuf, switch_timer_interval, read_timer_interval); } @@ -140,8 +141,8 @@ struct lib_ring_buffer *ltt_buffer_read_open(struct channel *chan) struct lib_ring_buffer *buf; int cpu; - for_each_channel_cpu(cpu, chan->chan) { - buf = channel_get_ring_buffer(&config_config, chan, cpu); + for_each_channel_cpu(cpu, chan) { + buf = channel_get_ring_buffer(&client_config, chan, cpu); if (!lib_ring_buffer_open_read(buf)) return buf; } @@ -149,19 +150,48 @@ struct lib_ring_buffer *ltt_buffer_read_open(struct channel *chan) } static -struct lib_ring_buffer *ltt_buffer_read_close(struct lib_ring_buffer *buf) +void ltt_buffer_read_close(struct lib_ring_buffer *buf) { lib_ring_buffer_release_read(buf); + +} + +int ltt_event_reserve(struct lib_ring_buffer_ctx *ctx) +{ + int ret, cpu; + + cpu = lib_ring_buffer_get_cpu(&client_config); + if (cpu < 0) + return -EPERM; + ctx->cpu = cpu; + + ret = lib_ring_buffer_reserve(&client_config, ctx); + if (ret) + goto put; + return ret; + +put: + lib_ring_buffer_put_cpu(&client_config); + return ret; } +void ltt_event_commit(struct lib_ring_buffer_ctx *ctx) +{ + lib_ring_buffer_commit(&client_config, ctx); + lib_ring_buffer_put_cpu(&client_config); +} + + static struct ltt_transport ltt_relay_transport = { .name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING, .owner = THIS_MODULE, .ops = { - .create_channel = ltt_channel_create, - .destroy_channel = ltt_channel_destroy, + .channel_create = _channel_create, + .channel_destroy = ltt_channel_destroy, .buffer_read_open = ltt_buffer_read_open, .buffer_read_close = ltt_buffer_read_close, + .event_reserve = ltt_event_reserve, + .event_commit = ltt_event_commit, }, }; @@ -172,12 +202,16 @@ static int __init ltt_ring_buffer_client_init(void) return 0; } +module_init(ltt_ring_buffer_client_init); + static void __exit ltt_ring_buffer_client_exit(void) { printk(KERN_INFO "LTT : ltt ring buffer client exit\n"); ltt_transport_unregister(<t_relay_transport); } +module_exit(ltt_ring_buffer_client_exit); + MODULE_LICENSE("GPL and additional rights"); MODULE_AUTHOR("Mathieu Desnoyers"); MODULE_DESCRIPTION("LTTng ring buffer " RING_BUFFER_MODE_TEMPLATE_STRING diff --git a/ltt-tracer-core.h b/ltt-tracer-core.h index 1ac8c5b3..cb82658b 100644 --- a/ltt-tracer-core.h +++ b/ltt-tracer-core.h @@ -13,34 +13,13 @@ #include #include -/* ltt's root dir in debugfs */ -#define LTT_ROOT "ltt" +struct ltt_session; +struct ltt_channel; +struct ltt_event; -/* - * All modifications of ltt_traces must be done by ltt-tracer.c, while holding - * the semaphore. Only reading of this information can be done elsewhere, with - * the RCU mechanism : the preemption must be disabled while reading the - * list. - */ -struct ltt_traces { - struct list_head setup_head; /* Pre-allocated traces list */ - struct list_head head; /* Allocated Traces list */ - unsigned int num_active_traces; /* Number of active traces */ -} ____cacheline_aligned; - -extern struct ltt_traces ltt_traces; - -/* - * get dentry of ltt's root dir - */ -struct dentry *get_ltt_root(void); - -void put_ltt_root(void); - -/* Keep track of trap nesting inside LTT */ -DECLARE_PER_CPU(unsigned int, ltt_nesting); - -typedef int (*ltt_run_filter_functor)(void *trace, uint16_t eID); +typedef int (*ltt_run_filter_functor)(struct ltt_session *session, + struct ltt_channel *chan, + struct ltt_event *event); extern ltt_run_filter_functor ltt_run_filter; diff --git a/ltt-tracer.h b/ltt-tracer.h index 6ed4fa94..3b5c3605 100644 --- a/ltt-tracer.h +++ b/ltt-tracer.h @@ -29,6 +29,7 @@ #include #include "ltt-tracer-core.h" +#include "ltt-events.h" /* Number of bytes to log with a read/write event */ #define LTT_LOG_RW_SIZE 32L @@ -193,13 +194,24 @@ struct event_header { * because gcc generates poor code on at least powerpc and mips. Don't ever * let gcc add padding between the structure elements. */ -struct subbuffer_header { - uint64_t cycle_count_begin; /* Cycle count at subbuffer start */ - uint64_t cycle_count_end; /* Cycle count at subbuffer end */ - uint32_t magic_number; /* +struct packet_header { + uint32_t magic; /* * Trace magic number. * contains endianness information. */ + uint8_t trace_uuid[16]; + uint32_t stream_id; + uint64_t timestamp_begin; /* Cycle count at subbuffer start */ + uint64_t timestamp_end; /* Cycle count at subbuffer end */ + uint32_t content_size; /* Size of data in subbuffer */ + uint32_t packet_size; /* Subbuffer size (include padding) */ + uint32_t events_lost; /* + * Events lost in this subbuffer since + * the beginning of the trace. + * (may overflow) + */ + /* TODO: move to metadata */ +#if 0 uint8_t major_version; uint8_t minor_version; uint8_t arch_size; /* Architecture pointer size */ @@ -211,18 +223,7 @@ struct subbuffer_header { * used all along the trace. */ uint32_t freq_scale; /* Frequency scaling (divisor) */ - uint32_t data_size; /* Size of data in subbuffer */ - uint32_t sb_size; /* Subbuffer size (include padding) */ - uint32_t events_lost; /* - * Events lost in this subbuffer since - * the beginning of the trace. - * (may overflow) - */ - uint32_t subbuf_corrupt; /* - * Corrupted (lost) subbuffers since - * the begginig of the trace. - * (may overflow) - */ +#endif //0 uint8_t header_end[0]; /* End of header */ }; @@ -301,9 +302,9 @@ unsigned char record_header_size(const struct lib_ring_buffer_config *config, #include extern -size_t ltt_write_event_header_slow(const struct lib_ring_buffer_config *config, - struct lib_ring_buffer_ctx *ctx, - u16 eID, u32 event_size); +void ltt_write_event_header_slow(const struct lib_ring_buffer_config *config, + struct lib_ring_buffer_ctx *ctx, + u16 eID, u32 event_size); /* * ltt_write_event_header @@ -397,49 +398,10 @@ size_t ltt_read_event_header(struct ltt_chanbuf_alloc *bufa, long buf_offset, } #endif //0 -/* - * Control channels : - * control/metadata - * control/interrupts - * control/... - * - * cpu channel : - * cpu - */ -#define LTT_RELAY_ROOT "ltt" - -#define LTT_METADATA_CHANNEL "metadata_state" -#define LTT_FD_STATE_CHANNEL "fd_state" -#define LTT_GLOBAL_STATE_CHANNEL "global_state" -#define LTT_IRQ_STATE_CHANNEL "irq_state" -#define LTT_MODULE_STATE_CHANNEL "module_state" -#define LTT_NETIF_STATE_CHANNEL "netif_state" -#define LTT_SOFTIRQ_STATE_CHANNEL "softirq_state" -#define LTT_SWAP_STATE_CHANNEL "swap_state" -#define LTT_SYSCALL_STATE_CHANNEL "syscall_state" -#define LTT_TASK_STATE_CHANNEL "task_state" -#define LTT_VM_STATE_CHANNEL "vm_state" -#define LTT_FS_CHANNEL "fs" -#define LTT_INPUT_CHANNEL "input" -#define LTT_IPC_CHANNEL "ipc" -#define LTT_KERNEL_CHANNEL "kernel" -#define LTT_MM_CHANNEL "mm" -#define LTT_RCU_CHANNEL "rcu" - -#define LTT_FLIGHT_PREFIX "flight-" - -#define LTT_ASCII "ascii" - /* Tracer properties */ -#define LTT_DEFAULT_SUBBUF_SIZE_LOW 65536 -#define LTT_DEFAULT_N_SUBBUFS_LOW 2 -#define LTT_DEFAULT_SUBBUF_SIZE_MED 262144 -#define LTT_DEFAULT_N_SUBBUFS_MED 2 -#define LTT_DEFAULT_SUBBUF_SIZE_HIGH 1048576 -#define LTT_DEFAULT_N_SUBBUFS_HIGH 2 -#define LTT_TRACER_MAGIC_NUMBER 0x00D6B7ED -#define LTT_TRACER_VERSION_MAJOR 2 -#define LTT_TRACER_VERSION_MINOR 6 +#define CTF_MAGIC_NUMBER 0xC1FC1FC1 +#define LTT_TRACER_VERSION_MAJOR 3 +#define LTT_TRACER_VERSION_MINOR 0 /** * ltt_write_trace_header - Write trace header @@ -447,20 +409,21 @@ size_t ltt_read_event_header(struct ltt_chanbuf_alloc *bufa, long buf_offset, * @header: Memory address where the information must be written to */ static __inline__ -void ltt_write_trace_header(void *priv, - struct subbuffer_header *header) +void write_trace_header(const struct lib_ring_buffer_config *config, + struct packet_header *header) { - struct ltt_session *session = priv; - - header->magic_number = LTT_TRACER_MAGIC_NUMBER; + header->magic = CTF_MAGIC_NUMBER; +#if 0 + /* TODO: move start time to metadata */ header->major_version = LTT_TRACER_VERSION_MAJOR; header->minor_version = LTT_TRACER_VERSION_MINOR; header->arch_size = sizeof(void *); - header->alignment = lib_ring_buffer_get_alignment(); - header->start_time_sec = session->start_time.tv_sec; - header->start_time_usec = session->start_time.tv_usec; - header->start_freq = session->start_freq; - header->freq_scale = session->freq_scale; + header->alignment = lib_ring_buffer_get_alignment(config); + header->start_time_sec = ltt_chan->session->start_time.tv_sec; + header->start_time_usec = ltt_chan->session->start_time.tv_usec; + header->start_freq = ltt_chan->session->start_freq; + header->freq_scale = ltt_chan->session->freq_scale; +#endif //0 } /* @@ -485,35 +448,10 @@ extern void ltt_module_unregister(enum ltt_module_function name); /* Exported control function */ -enum ltt_control_msg { - LTT_CONTROL_START, - LTT_CONTROL_STOP, - LTT_CONTROL_CREATE_TRACE, - LTT_CONTROL_DESTROY_TRACE -}; - -union ltt_control_args { - struct { - enum trace_mode mode; - unsigned int subbuf_size_low; - unsigned int n_subbufs_low; - unsigned int subbuf_size_med; - unsigned int n_subbufs_med; - unsigned int subbuf_size_high; - unsigned int n_subbufs_high; - } new_trace; -}; - void ltt_core_register(int (*function)(u8, void *)); void ltt_core_unregister(void); -extern int ltt_marker_connect(const char *channel, const char *mname, - const char *pname); -extern int ltt_marker_disconnect(const char *channel, const char *mname, - const char *pname); -extern void ltt_dump_marker_state(struct ltt_trace *trace); - extern void ltt_statedump_register_kprobes_dump(void (*callback)(void *call_data)); extern diff --git a/ltt-type-serializer.c b/ltt-type-serializer.c deleted file mode 100644 index 7d06490c..00000000 --- a/ltt-type-serializer.c +++ /dev/null @@ -1,113 +0,0 @@ -/** - * ltt-type-serializer.c - * - * LTTng specialized type serializer. - * - * Copyright Mathieu Desnoyers, 2008. - * - * Dual LGPL v2.1/GPL v2 license. - */ -#include - -#include "ltt-type-serializer.h" -#include "ltt-relay-lockless.h" - -notrace -void _ltt_specialized_trace(const struct marker *mdata, void *probe_data, - void *serialize_private, unsigned int data_size, - unsigned int largest_align) -{ - int ret; - uint16_t eID; - size_t slot_size; - unsigned int chan_index; - struct ltt_chanbuf *buf; - struct ltt_chan *chan; - struct ltt_trace *trace; - uint64_t tsc; - long buf_offset; - int cpu; - unsigned int rflags; - - /* - * If we get here, it's probably because we have useful work to do. - */ - if (unlikely(ltt_traces.num_active_traces == 0)) - return; - - rcu_read_lock_sched_notrace(); - cpu = smp_processor_id(); - __get_cpu_var(ltt_nesting)++; - /* - * asm volatile and "memory" clobber prevent the compiler from moving - * instructions out of the ltt nesting count. This is required to ensure - * that probe side-effects which can cause recursion (e.g. unforeseen - * traps, divisions by 0, ...) are triggered within the incremented - * nesting count section. - */ - barrier(); - eID = mdata->event_id; - chan_index = mdata->channel_id; - - /* - * Iterate on each trace, typically small number of active traces, - * list iteration with prefetch is usually slower. - */ - __list_for_each_entry_rcu(trace, <t_traces.head, list) { - if (unlikely(!trace->active)) - continue; - if (unlikely(!ltt_run_filter(trace, eID))) - continue; -#ifdef LTT_DEBUG_EVENT_SIZE - rflags = LTT_RFLAG_ID_SIZE; -#else - if (unlikely(eID >= LTT_FREE_EVENTS)) - rflags = LTT_RFLAG_ID; - else - rflags = 0; -#endif - /* - * Skip channels added after trace creation. - */ - if (unlikely(chan_index >= trace->nr_channels)) - continue; - chan = &trace->channels[chan_index]; - if (!chan->active) - continue; - - /* reserve space : header and data */ - ret = ltt_reserve_slot(chan, trace, data_size, largest_align, - cpu, &buf, &slot_size, &buf_offset, &tsc, - &rflags); - if (unlikely(ret < 0)) - continue; /* buffer full */ - - /* Out-of-order write : header and data */ - buf_offset = ltt_write_event_header(&buf->a, &chan->a, - buf_offset, eID, data_size, - tsc, rflags); - if (data_size) { - buf_offset += ltt_align(buf_offset, largest_align); - ltt_relay_write(&buf->a, &chan->a, buf_offset, - serialize_private, data_size); - buf_offset += data_size; - } - /* Out-of-order commit */ - ltt_commit_slot(buf, chan, buf_offset, data_size, slot_size); - } - /* - * asm volatile and "memory" clobber prevent the compiler from moving - * instructions out of the ltt nesting count. This is required to ensure - * that probe side-effects which can cause recursion (e.g. unforeseen - * traps, divisions by 0, ...) are triggered within the incremented - * nesting count section. - */ - barrier(); - __get_cpu_var(ltt_nesting)--; - rcu_read_unlock_sched_notrace(); -} -EXPORT_SYMBOL_GPL(_ltt_specialized_trace); - -MODULE_LICENSE("GPL and additional rights"); -MODULE_AUTHOR("Mathieu Desnoyers"); -MODULE_DESCRIPTION("LTT type serializer"); -- 2.34.1