From 8070f5c01e8e64ce52912dd4f27021c5d9e3dce2 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 25 May 2011 19:06:53 -0400 Subject: [PATCH] Add context support with metadata description Signed-off-by: Mathieu Desnoyers --- ltt-context.c | 2 + ltt-debugfs-abi.c | 72 ++++++++++ ltt-debugfs-abi.h | 25 ++++ ltt-events.c | 264 +++++++++++++++++++++-------------- ltt-events.h | 6 +- ltt-ring-buffer-client.h | 3 - probes/lttng-context-pid.c | 17 +-- probes/lttng-perf-counters.c | 16 +-- 8 files changed, 277 insertions(+), 128 deletions(-) diff --git a/ltt-context.c b/ltt-context.c index 89e54bf8..ff1ba2e1 100644 --- a/ltt-context.c +++ b/ltt-context.c @@ -47,6 +47,8 @@ void lttng_destroy_context(struct lttng_ctx *ctx) { int i; + if (!ctx) + return; for (i = 0; i < ctx->nr_fields; i++) { if (ctx->fields[i].destroy) ctx->fields[i].destroy(&ctx->fields[i]); diff --git a/ltt-debugfs-abi.c b/ltt-debugfs-abi.c index 5bfd1d68..d8164ffc 100644 --- a/ltt-debugfs-abi.c +++ b/ltt-debugfs-abi.c @@ -136,6 +136,29 @@ long lttng_abi_tracer_version(struct file *file, return 0; } +static +long lttng_abi_add_context(struct file *file, + struct lttng_kernel_context __user *ucontext_param, + struct lttng_ctx **ctx, struct ltt_session *session) +{ + struct lttng_kernel_context context_param; + + if (session->been_active) + return -EPERM; + + if (copy_from_user(&context_param, ucontext_param, sizeof(context_param))) + return -EFAULT; + + switch (context_param.ctx) { + case LTTNG_CONTEXT_PID: + return lttng_add_pid_to_ctx(ctx); + case LTTNG_CONTEXT_PERF_COUNTER: + return -ENOSYS; + default: + return -EINVAL; + } +} + /** * lttng_ioctl - lttng syscall through ioctl * @@ -294,6 +317,12 @@ fd_error: * This ioctl implements lttng commands: * LTTNG_KERNEL_CHANNEL * Returns a LTTng channel file descriptor + * LTTNG_KERNEL_SESSION_START + * Starts tracing session + * LTTNG_KERNEL_SESSION_STOP + * Stops tracing session + * LTTNG_KERNEL_METADATA + * Returns a LTTng metadata file descriptor * * The returned channel will be deleted when its file descriptor is closed. */ @@ -462,17 +491,25 @@ fd_error: * (typically, one event stream records events from one CPU) * LTTNG_KERNEL_EVENT * Returns an event file descriptor or failure. + * LTTNG_KERNEL_CONTEXT + * Prepend a context field to each event in the channel * * Channel and event file descriptors also hold a reference on the session. */ static long lttng_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + struct ltt_channel *channel = file->private_data; + switch (cmd) { case LTTNG_KERNEL_STREAM: return lttng_abi_open_stream(file); case LTTNG_KERNEL_EVENT: return lttng_abi_create_event(file, (struct lttng_kernel_event __user *) arg); + case LTTNG_KERNEL_CONTEXT: + return lttng_abi_add_context(file, + (struct lttng_kernel_context __user *) arg, + &channel->ctx, channel->session); default: return -ENOIOCTLCMD; } @@ -560,6 +597,37 @@ static const struct file_operations lttng_metadata_fops = { #endif }; +/** + * lttng_event_ioctl - lttng syscall through ioctl + * + * @file: the file + * @cmd: the command + * @arg: command arg + * + * This ioctl implements lttng commands: + * LTTNG_KERNEL_STREAM + * Returns an event stream file descriptor or failure. + * (typically, one event stream records events from one CPU) + * LTTNG_KERNEL_EVENT + * Returns an event file descriptor or failure. + * LTTNG_KERNEL_CONTEXT + * Prepend a context field to each record of this event + */ +static +long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct ltt_event *event = file->private_data; + + switch (cmd) { + case LTTNG_KERNEL_CONTEXT: + return lttng_abi_add_context(file, + (struct lttng_kernel_context __user *) arg, + &event->ctx, event->chan->session); + default: + return -ENOIOCTLCMD; + } +} + static int lttng_event_release(struct inode *inode, struct file *file) { @@ -573,6 +641,10 @@ int lttng_event_release(struct inode *inode, struct file *file) /* TODO: filter control ioctl */ static const struct file_operations lttng_event_fops = { .release = lttng_event_release, + .unlocked_ioctl = lttng_event_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = lttng_event_ioctl, +#endif }; int __init ltt_debugfs_abi_init(void) diff --git a/ltt-debugfs-abi.h b/ltt-debugfs-abi.h index d0c2dd1a..a0299967 100644 --- a/ltt-debugfs-abi.h +++ b/ltt-debugfs-abi.h @@ -65,6 +65,27 @@ struct lttng_kernel_tracer_version { uint32_t sublevel; }; +enum lttng_context { + LTTNG_CONTEXT_PID, + LTTNG_CONTEXT_PERF_COUNTER, +}; + +struct lttng_kernel_pid_ctx { +}; + +struct lttng_kernel_perf_counter_ctx { + uint32_t type; + uint64_t config; +}; + +struct lttng_kernel_context { + enum lttng_context ctx; + union { + struct lttng_kernel_pid_ctx pid; + struct lttng_kernel_perf_counter_ctx perf_counter; + } u; +}; + /* LTTng file descriptor ioctl */ #define LTTNG_KERNEL_SESSION _IO(0xF6, 0x40) #define LTTNG_KERNEL_TRACER_VERSION \ @@ -84,4 +105,8 @@ struct lttng_kernel_tracer_version { #define LTTNG_KERNEL_EVENT \ _IOW(0xF6, 0x61, struct lttng_kernel_event) +/* Event and Channel FD ioctl */ +#define LTTNG_KERNEL_CONTEXT \ + _IOW(0xF6, 0x70, struct lttng_kernel_context) + #endif /* _LTT_DEBUGFS_ABI_H */ diff --git a/ltt-events.c b/ltt-events.c index 84ad1de5..6171c1c5 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -105,6 +105,7 @@ int ltt_session_start(struct ltt_session *session) } ACCESS_ONCE(session->active) = 1; + ACCESS_ONCE(session->been_active) = 1; synchronize_trace(); /* Wait for in-flight events to complete */ ret = _ltt_session_metadata_statedump(session); if (ret) { @@ -154,10 +155,8 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, struct ltt_transport *transport; mutex_lock(&sessions_mutex); - if (session->active) { - printk(KERN_WARNING "LTTng refusing to add channel to active session\n"); + if (session->been_active) goto active; /* Refuse to add channel to active session */ - } transport = ltt_transport_find(transport_name); if (!transport) { printk(KERN_WARNING "LTTng transport %s not found\n", @@ -202,6 +201,7 @@ void _ltt_channel_destroy(struct ltt_channel *chan) { chan->ops->channel_destroy(chan->chan); list_del(&chan->list); + lttng_destroy_context(chan->ctx); kfree(chan); } @@ -340,6 +340,7 @@ void _ltt_event_destroy(struct ltt_event *event) WARN_ON_ONCE(1); } list_del(&event->list); + lttng_destroy_context(event->ctx); kmem_cache_free(event_cache, event); } @@ -405,124 +406,155 @@ end: } static -int _ltt_fields_metadata_statedump(struct ltt_session *session, - struct ltt_event *event) +int _ltt_field_statedump(struct ltt_session *session, + const struct lttng_event_field *field) { - const struct lttng_event_desc *desc = event->desc; int ret = 0; - int i; - - for (i = 0; i < desc->nr_fields; i++) { - const struct lttng_event_field *field = &desc->fields[i]; - switch (field->type.atype) { - case atype_integer: - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s;\n", - field->type.u.basic.integer.size, - field->type.u.basic.integer.alignment, - field->type.u.basic.integer.signedness, - (field->type.u.basic.integer.encoding == lttng_encode_none) - ? "none" - : (field->type.u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII", - field->type.u.basic.integer.base, + switch (field->type.atype) { + case atype_integer: + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s;\n", + field->type.u.basic.integer.size, + field->type.u.basic.integer.alignment, + field->type.u.basic.integer.signedness, + (field->type.u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (field->type.u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + field->type.u.basic.integer.base, #ifdef __BIG_ENDIAN - field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", + field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name); - break; - case atype_enum: - ret = lttng_metadata_printf(session, - " %s %s;\n", - field->type.u.basic.enumeration.name, - field->name); - break; - case atype_array: - { - const struct lttng_basic_type *elem_type; - - elem_type = &field->type.u.array.elem_type; - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[%u];\n", - elem_type->u.basic.integer.size, - elem_type->u.basic.integer.alignment, - elem_type->u.basic.integer.signedness, - (elem_type->u.basic.integer.encoding == lttng_encode_none) - ? "none" - : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII", - elem_type->u.basic.integer.base, + field->name); + break; + case atype_enum: + ret = lttng_metadata_printf(session, + " %s %s;\n", + field->type.u.basic.enumeration.name, + field->name); + break; + case atype_array: + { + const struct lttng_basic_type *elem_type; + + elem_type = &field->type.u.array.elem_type; + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[%u];\n", + elem_type->u.basic.integer.size, + elem_type->u.basic.integer.alignment, + elem_type->u.basic.integer.signedness, + (elem_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + elem_type->u.basic.integer.base, #ifdef __BIG_ENDIAN - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name, field->type.u.array.length); - break; - } - case atype_sequence: - { - const struct lttng_basic_type *elem_type; - const struct lttng_basic_type *length_type; - - elem_type = &field->type.u.sequence.elem_type; - length_type = &field->type.u.sequence.length_type; - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n", - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n", - length_type->u.basic.integer.size, - length_type->u.basic.integer.alignment, - length_type->u.basic.integer.signedness, - (length_type->u.basic.integer.encoding == lttng_encode_none) - ? "none" - : (length_type->u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII", - length_type->u.basic.integer.base, + field->name, field->type.u.array.length); + break; + } + case atype_sequence: + { + const struct lttng_basic_type *elem_type; + const struct lttng_basic_type *length_type; + + elem_type = &field->type.u.sequence.elem_type; + length_type = &field->type.u.sequence.length_type; + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n", + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n", + length_type->u.basic.integer.size, + length_type->u.basic.integer.alignment, + length_type->u.basic.integer.signedness, + (length_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (length_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + length_type->u.basic.integer.base, #ifdef __BIG_ENDIAN - length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - length_type->u.basic.integer.reverse_byte_order + length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name, - elem_type->u.basic.integer.size, - elem_type->u.basic.integer.alignment, - elem_type->u.basic.integer.signedness, - (elem_type->u.basic.integer.encoding == lttng_encode_none) - ? "none" - : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) - ? "UTF8" - : "ASCII", - elem_type->u.basic.integer.base, + field->name, + elem_type->u.basic.integer.size, + elem_type->u.basic.integer.alignment, + elem_type->u.basic.integer.signedness, + (elem_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + elem_type->u.basic.integer.base, #ifdef __BIG_ENDIAN - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name, - field->name - ); - break; - } + field->name, + field->name + ); + break; + } - case atype_string: - /* Default encoding is UTF8 */ - ret = lttng_metadata_printf(session, - " string%s %s;\n", - field->type.u.basic.string.encoding == lttng_encode_ASCII ? - " { encoding = ASCII; }" : "", - field->name); - break; - default: - WARN_ON_ONCE(1); - return -EINVAL; - } + case atype_string: + /* Default encoding is UTF8 */ + ret = lttng_metadata_printf(session, + " string%s %s;\n", + field->type.u.basic.string.encoding == lttng_encode_ASCII ? + " { encoding = ASCII; }" : "", + field->name); + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + return ret; +} + +static +int _ltt_context_metadata_statedump(struct ltt_session *session, + struct lttng_ctx *ctx) +{ + int ret = 0; + int i; + + if (!ctx) + return 0; + for (i = 0; i < ctx->nr_fields; i++) { + const struct lttng_ctx_field *field = &ctx->fields[i]; + + ret = _ltt_field_statedump(session, &field->event_field); + if (ret) + return ret; + } + return ret; +} + +static +int _ltt_fields_metadata_statedump(struct ltt_session *session, + struct ltt_event *event) +{ + const struct lttng_event_desc *desc = event->desc; + int ret = 0; + int i; + + for (i = 0; i < desc->nr_fields; i++) { + const struct lttng_event_field *field = &desc->fields[i]; + + ret = _ltt_field_statedump(session, field); + if (ret) + return ret; } return ret; } @@ -544,13 +576,24 @@ int _ltt_event_metadata_statedump(struct ltt_session *session, " name = %s;\n" " id = %u;\n" " stream_id = %u;\n" - " fields := struct {\n", + " context := struct {\n", event->desc->name, event->id, event->chan->id); if (ret) goto end; + ret = _ltt_context_metadata_statedump(session, event->ctx); + if (ret) + goto end; + + ret = lttng_metadata_printf(session, + " };\n" + " fields := struct {\n" + ); + if (ret) + goto end; + ret = _ltt_fields_metadata_statedump(session, event); if (ret) goto end; @@ -588,13 +631,22 @@ int _ltt_channel_metadata_statedump(struct ltt_session *session, " id = %u;\n" " event.header := %s;\n" " packet.context := struct packet_context;\n" - "};\n\n", + " event.context := {\n", chan->id, chan->header_type == 1 ? "struct event_header_compact" : "struct event_header_large"); if (ret) goto end; + ret = _ltt_context_metadata_statedump(session, chan->ctx); + if (ret) + goto end; + + ret = lttng_metadata_printf(session, + " };\n" + "};\n\n" + ); + chan->metadata_dumped = 1; end: return ret; diff --git a/ltt-events.h b/ltt-events.h index bea5af1c..a5a57fcd 100644 --- a/ltt-events.h +++ b/ltt-events.h @@ -118,8 +118,7 @@ struct lttng_event_field { }; struct lttng_ctx_field { - const char *name; - struct lttng_type type; + struct lttng_event_field event_field; size_t (*get_size)(size_t offset); void (*record)(struct lttng_ctx_field *field, struct lib_ring_buffer_ctx *ctx, @@ -220,7 +219,7 @@ struct ltt_channel { struct ltt_session { int active; /* Is trace session active ? */ - struct lttng_ctx *ctx; + int been_active; /* Has trace session been active ? */ struct file *file; /* File associated to session */ struct ltt_channel *metadata; /* Metadata channel */ struct list_head chan; /* Channel list head */ @@ -273,6 +272,7 @@ int ltt_probes_init(void); void ltt_probes_exit(void); struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx); void lttng_destroy_context(struct lttng_ctx *ctx); +int lttng_add_pid_to_ctx(struct lttng_ctx **ctx); #ifdef CONFIG_KPROBES int lttng_kprobes_register(const char *name, diff --git a/ltt-ring-buffer-client.h b/ltt-ring-buffer-client.h index 8095eb6e..733a800c 100644 --- a/ltt-ring-buffer-client.h +++ b/ltt-ring-buffer-client.h @@ -142,7 +142,6 @@ unsigned char record_header_size(const struct lib_ring_buffer_config *config, } offset += ctx_get_size(offset, event->ctx); offset += ctx_get_size(offset, ltt_chan->ctx); - offset += ctx_get_size(offset, ltt_chan->session->ctx); *pre_header_padding = padding; return offset - orig_offset; @@ -200,7 +199,6 @@ void ltt_write_event_header(const struct lib_ring_buffer_config *config, ctx_record(ctx, ltt_chan, event->ctx); ctx_record(ctx, ltt_chan, ltt_chan->ctx); - ctx_record(ctx, ltt_chan, ltt_chan->session->ctx); return; @@ -262,7 +260,6 @@ void ltt_write_event_header_slow(const struct lib_ring_buffer_config *config, } ctx_record(ctx, ltt_chan, event->ctx); ctx_record(ctx, ltt_chan, ltt_chan->ctx); - ctx_record(ctx, ltt_chan, ltt_chan->session->ctx); } static const struct lib_ring_buffer_config client_config; diff --git a/probes/lttng-context-pid.c b/probes/lttng-context-pid.c index adb14c36..81dbe4a6 100644 --- a/probes/lttng-context-pid.c +++ b/probes/lttng-context-pid.c @@ -45,19 +45,20 @@ int lttng_add_pid_to_ctx(struct lttng_ctx **ctx) field = lttng_append_context(ctx); if (!field) return ret; - field->name = "pid"; - field->type.atype = atype_integer; - field->type.u.basic.integer.size = sizeof(pid_t) * CHAR_BIT; - field->type.u.basic.integer.alignment = ltt_alignof(pid_t) * CHAR_BIT; - field->type.u.basic.integer.signedness = is_signed_type(pid_t); - field->type.u.basic.integer.reverse_byte_order = 0; - field->type.u.basic.integer.base = 10; - field->type.u.basic.integer.encoding = lttng_encode_none; + field->event_field.name = "pid"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(pid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = ltt_alignof(pid_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = is_signed_type(pid_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; field->get_size = pid_get_size; field->record = pid_record; wrapper_vmalloc_sync_all(); return 0; } +EXPORT_SYMBOL_GPL(lttng_add_pid_to_ctx); MODULE_LICENSE("GPL and additional rights"); MODULE_AUTHOR("Mathieu Desnoyers"); diff --git a/probes/lttng-perf-counters.c b/probes/lttng-perf-counters.c index 06a4a7ce..cb0bdfc6 100644 --- a/probes/lttng-perf-counters.c +++ b/probes/lttng-perf-counters.c @@ -114,14 +114,14 @@ int lttng_add_perf_counter_to_ctx(uint32_t type, } field->destroy = lttng_destroy_perf_counter_field; - field->name = "dummyname";//TODO: lookup_counter_name(type, config); - field->type.atype = atype_integer; - field->type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT; - field->type.u.basic.integer.alignment = ltt_alignof(unsigned long) * CHAR_BIT; - field->type.u.basic.integer.signedness = is_signed_type(unsigned long); - field->type.u.basic.integer.reverse_byte_order = 0; - field->type.u.basic.integer.base = 10; - field->type.u.basic.integer.encoding = lttng_encode_none; + field->event_field.name = "dummyname";//TODO: lookup_counter_name(type, config); + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = ltt_alignof(unsigned long) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = is_signed_type(unsigned long); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; field->get_size = perf_counter_get_size; field->record = perf_counter_record; field->u.perf_counter.e = events; -- 2.34.1