X-Git-Url: https://git.lttng.org/?p=ust.git;a=blobdiff_plain;f=libust%2Fserialize.c;h=8f393ed074d08ad98836db24e39ae729cd0f0122;hp=b8df1b3cd3538af4a75cd1bcd6aa955c5c7892f8;hb=bf0d695d692163edb23b8fbbbd976387dfef232d;hpb=4268fdcdcb96f72e945f52b9f94f6ad841e297c9 diff --git a/libust/serialize.c b/libust/serialize.c index b8df1b3..8f393ed 100644 --- a/libust/serialize.c +++ b/libust/serialize.c @@ -3,7 +3,20 @@ * * Copyright Mathieu Desnoyers, March 2007. * - * Licensed under the GPLv2. + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * * * See this discussion about weirdness about passing va_list and then va_list to * functions. (related to array argument passing). va_list seems to be @@ -11,23 +24,24 @@ * va_list * to ltt_vtrace. */ +#define _GNU_SOURCE +#include +#include #include -//ust// #include -//ust// #include -//ust// #include -//ust// #include #include #include +#include -#include "kernelcompat.h" +#include #define _LGPL_SOURCE -#include -#include +#include +#include -#include "relay.h" +#include "buffers.h" #include "tracer.h" //#include "list.h" #include "usterr.h" +#include "ust_snprintf.h" enum ltt_type { LTT_TYPE_SIGNED_INT, @@ -36,6 +50,11 @@ enum ltt_type { LTT_TYPE_NONE, }; +static int ust_get_cpu(void) +{ + return sched_getcpu(); +} + #define LTT_ATTRIBUTE_NETWORK_BYTE_ORDER (1<<1) /* @@ -238,8 +257,9 @@ parse_end: * Field width and precision are *not* supported. * %n not supported. */ -static inline const char *parse_c_type(const char *fmt, - char *c_size, enum ltt_type *c_type) +static inline +const char *parse_c_type(const char *fmt, char *c_size, enum ltt_type *c_type, + char *outfmt) { int qualifier; /* 'h', 'l', or 'L' for integer fields */ /* 'z' support added 23/7/1999 S.H. */ @@ -271,6 +291,13 @@ repeat: } } + if (outfmt) { + if (qualifier != -1) + *outfmt++ = (char)qualifier; + *outfmt++ = *fmt; + *outfmt = 0; + } + switch (*fmt) { case 'c': *c_type = LTT_TYPE_UNSIGNED_INT; @@ -323,7 +350,7 @@ parse_end: return fmt; } -static inline size_t serialize_trace_data(struct rchan_buf *buf, +static inline size_t serialize_trace_data(struct ust_buffer *buf, size_t buf_offset, char trace_size, enum ltt_type trace_type, char c_size, enum ltt_type c_type, @@ -364,16 +391,13 @@ static inline size_t serialize_trace_data(struct rchan_buf *buf, case LTT_TYPE_UNSIGNED_INT: switch (c_size) { case 1: - tmp.v_ulong = (unsigned long)(uint8_t) - va_arg(*args, unsigned int); + tmp.v_ulong = (unsigned long)(uint8_t)va_arg(*args, unsigned int); break; case 2: - tmp.v_ulong = (unsigned long)(uint16_t) - va_arg(*args, unsigned int); + tmp.v_ulong = (unsigned long)(uint16_t)va_arg(*args, unsigned int); break; case 4: - tmp.v_ulong = (unsigned long)(uint32_t) - va_arg(*args, unsigned int); + tmp.v_ulong = (unsigned long)(uint32_t)va_arg(*args, unsigned int); break; case 8: tmp.v_uint64 = va_arg(*args, uint64_t); @@ -388,7 +412,7 @@ static inline size_t serialize_trace_data(struct rchan_buf *buf, tmp.v_string.s = ""; tmp.v_string.len = strlen(tmp.v_string.s)+1; if (buf) - ltt_relay_write(buf, buf_offset, tmp.v_string.s, + ust_buffers_write(buf, buf_offset, tmp.v_string.s, tmp.v_string.len); buf_offset += tmp.v_string.len; goto copydone; @@ -416,31 +440,31 @@ static inline size_t serialize_trace_data(struct rchan_buf *buf, switch (trace_size) { case 1: if (c_size == 8) - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint8_t[]){ (uint8_t)tmp.v_uint64 }, sizeof(uint8_t)); else - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint8_t[]){ (uint8_t)tmp.v_ulong }, sizeof(uint8_t)); break; case 2: if (c_size == 8) - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint16_t[]){ (uint16_t)tmp.v_uint64 }, sizeof(uint16_t)); else - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint16_t[]){ (uint16_t)tmp.v_ulong }, sizeof(uint16_t)); break; case 4: if (c_size == 8) - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint32_t[]){ (uint32_t)tmp.v_uint64 }, sizeof(uint32_t)); else - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint32_t[]){ (uint32_t)tmp.v_ulong }, sizeof(uint32_t)); break; @@ -449,7 +473,7 @@ static inline size_t serialize_trace_data(struct rchan_buf *buf, * c_size cannot be other than 8 here because * trace_size > 4. */ - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint64_t[]){ (uint64_t)tmp.v_uint64 }, sizeof(uint64_t)); break; @@ -466,12 +490,12 @@ static inline size_t serialize_trace_data(struct rchan_buf *buf, if (buf) { switch (trace_type) { case LTT_TYPE_SIGNED_INT: - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (int64_t[]){ (int64_t)tmp.v_ulong }, sizeof(int64_t)); break; case LTT_TYPE_UNSIGNED_INT: - ltt_relay_write(buf, buf_offset, + ust_buffers_write(buf, buf_offset, (uint64_t[]){ (uint64_t)tmp.v_ulong }, sizeof(uint64_t)); break; @@ -487,7 +511,7 @@ copydone: return buf_offset; } -notrace size_t ltt_serialize_data(struct rchan_buf *buf, size_t buf_offset, +notrace size_t ltt_serialize_data(struct ust_buffer *buf, size_t buf_offset, struct ltt_serialize_closure *closure, void *serialize_private, int *largest_align, const char *fmt, va_list *args) @@ -514,7 +538,7 @@ notrace size_t ltt_serialize_data(struct rchan_buf *buf, size_t buf_offset, ++fmt; /* skip first '%' */ if (*fmt == '%') /* Escaped %% */ break; - fmt = parse_c_type(fmt, &c_size, &c_type); + fmt = parse_c_type(fmt, &c_size, &c_type, NULL); /* * Output c types if no trace types has been * specified. @@ -541,7 +565,6 @@ notrace size_t ltt_serialize_data(struct rchan_buf *buf, size_t buf_offset, } return buf_offset; } -EXPORT_SYMBOL_GPL(ltt_serialize_data); /* * Calculate data size @@ -558,7 +581,7 @@ static notrace size_t ltt_get_data_size(struct ltt_serialize_closure *closure, } static notrace -void ltt_write_event_data(struct rchan_buf *buf, size_t buf_offset, +void ltt_write_event_data(struct ust_buffer *buf, size_t buf_offset, struct ltt_serialize_closure *closure, void *serialize_private, int largest_align, const char *fmt, va_list *args) @@ -571,16 +594,17 @@ void ltt_write_event_data(struct rchan_buf *buf, size_t buf_offset, notrace void ltt_vtrace(const struct marker *mdata, void *probe_data, - void *call_data, const char *fmt, va_list *args) + struct registers *regs, void *call_data, + const char *fmt, va_list *args) { int largest_align, ret; struct ltt_active_marker *pdata; uint16_t eID; size_t data_size, slot_size; unsigned int chan_index; - struct ltt_channel_struct *channel; - struct ltt_trace_struct *trace, *dest_trace = NULL; - struct rchan_buf *buf; + struct ust_channel *channel; + struct ust_trace *trace, *dest_trace = NULL; + struct ust_buffer *buf; void *transport_data; u64 tsc; long buf_offset; @@ -588,7 +612,7 @@ notrace void ltt_vtrace(const struct marker *mdata, void *probe_data, struct ltt_serialize_closure closure; struct ltt_probe_private_data *private_data = call_data; void *serialize_private = NULL; -//ust// int cpu; + int cpu; unsigned int rflags; /* @@ -600,7 +624,9 @@ notrace void ltt_vtrace(const struct marker *mdata, void *probe_data, rcu_read_lock(); //ust// rcu_read_lock_sched_notrace(); //ust// cpu = smp_processor_id(); + cpu = ust_get_cpu(); //ust// __get_cpu_var(ltt_nesting)++; + /* FIXME: should nesting be per-cpu? */ ltt_nesting++; pdata = (struct ltt_active_marker *)probe_data; @@ -654,18 +680,26 @@ notrace void ltt_vtrace(const struct marker *mdata, void *probe_data, if (!channel->active) continue; + /* If a new cpu was plugged since the trace was started, we did + * not add it to the trace, and therefore we write the event to + * cpu 0. + */ + if(cpu >= channel->n_cpus) { + cpu = 0; + } + /* reserve space : header and data */ ret = ltt_reserve_slot(trace, channel, &transport_data, data_size, &slot_size, &buf_offset, &tsc, &rflags, - largest_align); + largest_align, cpu); if (unlikely(ret < 0)) continue; /* buffer full */ va_copy(args_copy, *args); /* FIXME : could probably encapsulate transport better. */ //ust// buf = ((struct rchan *)channel->trans_channel_data)->buf[cpu]; - buf = ((struct rchan *)channel->trans_channel_data)->buf; + buf = channel->buf[cpu]; /* Out-of-order write : header and data */ buf_offset = ltt_write_event_header(trace, channel, buf, buf_offset, @@ -675,27 +709,107 @@ notrace void ltt_vtrace(const struct marker *mdata, void *probe_data, largest_align, fmt, &args_copy); va_end(args_copy); /* Out-of-order commit */ - ltt_commit_slot(channel, &transport_data, buf_offset, - data_size, slot_size); - printf("just commited event at offset %ld and size %zd\n", buf_offset, slot_size); + ltt_commit_slot(channel, buf, buf_offset, data_size, slot_size); + DBG("just commited event at offset %ld and size %zd", buf_offset, slot_size); } //ust// __get_cpu_var(ltt_nesting)--; ltt_nesting--; rcu_read_unlock(); //ust// rcu_read_unlock_sched_notrace(); } -EXPORT_SYMBOL_GPL(ltt_vtrace); notrace void ltt_trace(const struct marker *mdata, void *probe_data, - void *call_data, const char *fmt, ...) + struct registers *regs, void *call_data, + const char *fmt, ...) { va_list args; va_start(args, fmt); - ltt_vtrace(mdata, probe_data, call_data, fmt, &args); + ltt_vtrace(mdata, probe_data, regs, call_data, fmt, &args); va_end(args); } -EXPORT_SYMBOL_GPL(ltt_trace); -//ust// MODULE_LICENSE("GPL"); -//ust// MODULE_AUTHOR("Mathieu Desnoyers"); -//ust// MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Serializer"); +static notrace void skip_space(const char **ps) +{ + while(**ps == ' ') + (*ps)++; +} + +static notrace void copy_token(char **out, const char **in) +{ + while(**in != ' ' && **in != '\0') { + **out = **in; + (*out)++; + (*in)++; + } +} + +/* serialize_to_text + * + * Given a format string and a va_list of arguments, convert them to a + * human-readable string. + * + * @outbuf: the buffer to output the string to + * @bufsize: the max size that can be used in outbuf + * @fmt: the marker format string + * @ap: a va_list that contains the arguments corresponding to fmt + * + * Return value: the number of chars that have been put in outbuf, excluding + * the final \0, or, if the buffer was too small, the number of chars that + * would have been written in outbuf if it had been large enough. + * + * outbuf may be NULL. The return value may then be used be allocate an + * appropriate outbuf. + * + */ + +notrace +int serialize_to_text(char *outbuf, int bufsize, const char *fmt, va_list ap) +{ + int fmt_len = strlen(fmt); + char *new_fmt = alloca(fmt_len + 1); + const char *orig_fmt_p = fmt; + char *new_fmt_p = new_fmt; + char false_buf; + int result; + enum { none, cfmt, tracefmt, argname } prev_token = none; + + while(*orig_fmt_p != '\0') { + if(*orig_fmt_p == '%') { + prev_token = cfmt; + copy_token(&new_fmt_p, &orig_fmt_p); + } + else if(*orig_fmt_p == '#') { + prev_token = tracefmt; + do { + orig_fmt_p++; + } while(*orig_fmt_p != ' ' && *orig_fmt_p != '\0'); + } + else if(*orig_fmt_p == ' ') { + if(prev_token == argname) { + *new_fmt_p = '='; + new_fmt_p++; + } + else if(prev_token == cfmt) { + *new_fmt_p = ' '; + new_fmt_p++; + } + + skip_space(&orig_fmt_p); + } + else { + prev_token = argname; + copy_token(&new_fmt_p, &orig_fmt_p); + } + } + + *new_fmt_p = '\0'; + + if(outbuf == NULL) { + /* use this false_buffer for compatibility with pre-C99 */ + outbuf = &false_buf; + bufsize = 1; + } + result = ust_safe_vsnprintf(outbuf, bufsize, new_fmt, ap); + + return result; +}