From 084f56d4e35d9776f1fb998b846df92d083db88c Mon Sep 17 00:00:00 2001 From: compudj Date: Thu, 22 Mar 2007 06:53:01 +0000 Subject: [PATCH] add trace event git-svn-id: http://ltt.polymtl.ca/svn@2452 04897980-b3bd-0310-b5e0-8ef037075253 --- tests/kernel/trace-event.h | 270 +++++++++++++++++++++++++++++++++++-- 1 file changed, 256 insertions(+), 14 deletions(-) diff --git a/tests/kernel/trace-event.h b/tests/kernel/trace-event.h index c755503a..1f2eccac 100644 --- a/tests/kernel/trace-event.h +++ b/tests/kernel/trace-event.h @@ -17,6 +17,246 @@ #define LTT_FLAG_CHANNEL (1 << _LTT_FLAG_CHANNEL) #define LTT_FLAG_FORCE (1 << _LTT_FLAG_FORCE) + +char *(*ltt_serialize_cb)(char *buffer, const char *fmt, va_list args); + + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +/* Inspired from vsnprintf */ +/* New types : + * %r : serialized pointer. + */ +static inline __attribute__((no_instrument_function)) +char *ltt_serialize_data(char *buffer, const char *fmt, va_list args) +{ + int len; + const char *s; + int elem_size; /* Size of the integer for 'b' */ + /* Size of the data contained by 'r' */ + int elem_alignment; /* Element alignment for 'r' */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + /* 'z' support added 23/7/1999 S.H. */ + /* 'z' changed to 'Z' --davidm 1/25/99 */ + /* 't' added for ptrdiff_t */ + char *str; /* Pointer to write to */ + ltt_serialize_cb cb; + + str = buf; + + for (; *fmt ; ++fmt) { + if (*fmt != '%') { + /* Skip text */ + continue; + } + + /* process flags : ignore standard print formats for now. */ + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': + case '+': + case ' ': + case '#': + case '0': goto repeat; + } + + /* get element size */ + elem_size = -1; + if (isdigit(*fmt)) + elem_size = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + elem_size = va_arg(args, int); + } + + /* get the alignment */ + elem_alignment = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + elem_alignment = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + elem_alignment = va_arg(args, int); + } + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt =='Z' || *fmt == 'z' || *fmt == 't') { + qualifier = *fmt; + ++fmt; + if (qualifier == 'l' && *fmt == 'l') { + qualifier = 'L'; + ++fmt; + } + } + + switch (*fmt) { + case 'c': + if (buffer) + *str = (char) va_arg(args, int); + str += sizeof(char); + continue; + + case 's': + s = va_arg(args, char *); + if ((unsigned long)s < PAGE_SIZE) + s = ""; + if (buffer) + strcpy(str, s); + str += strlen(s); + continue; + + case 'p': + str += ltt_align(str, sizeof(void*)); + if (buffer) + *(void**)str = va_arg(args, void *); + continue; + + case 'r': + /* For array, struct, union */ + if (elem_alignment < 0) + elem_alignment = sizeof(void*); + str += ltt_align(str, elem_alignment); + if (elem_size > 0) { + const char *src = va_arg(args, + const char *); + if (buffer) + memcpy(str, src, elem_size); + str += elem_size; + } + continue; + + case 'v': + /* For sequence */ + str += ltt_align(str, sizeof(int)); + if (buffer) + *(int*)str = elem_size; + str += sizeof(int); + if (elem_alignment > 0) + str += ltt_align(str, elem_alignment); + if (elem_size > 0) { + const char *src = va_arg(args, + const char *); + if (buffer) + memcpy(str, src, elem_size); + str += elem_size; + } + continue; + + case 'k': + /* For callback */ + cb = va_arg(args, ltt_serialize_cb); + /* The callback will take as many arguments + * as it needs from args. They won't be + * type verified. */ + str = cb(str, fmt, args); + continue; + + case 'n': + /* FIXME: + * What does C99 say about the overflow case here? */ + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else if (qualifier == 'Z' || qualifier == 'z') { + size_t * ip = va_arg(args, size_t *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + continue; + + case 'o': + case 'X': + case 'x': + case 'd': + case 'i': + case 'u': + break; + + default: + if (!*fmt) + --fmt; + continue; + } + switch (qualifier) { + case 'L': + str += ltt_align(str, sizeof(long long)); + if (buffer) + *(long long*)str = va_arg(args, long long); + str += sizeof(long long); + break; + case 'l': + str += ltt_align(str, sizeof(long)); + if (buffer) + *(long*)str = va_arg(args, long); + str += sizeof(long); + break; + case 'Z': + case 'z': + str += ltt_align(str, sizeof(size_t)); + if (buffer) + *(size_t*)str = va_arg(args, size_t); + str += sizeof(size_t); + break; + case 't': + str += ltt_align(str, sizeof(ptrdiff_t)); + if (buffer) + *(ptrdiff_t*)str = va_arg(args, ptrdiff_t); + str += sizeof(ptrdiff_t); + break; + case 'h': + str += ltt_align(str, sizeof(short)); + if (buffer) + *(short*)str = (short) va_arg(args, int); + str += sizeof(short); + break; + case 'b': + if (elem_size > 0) + str += ltt_align(str, elem_size); + if (buffer) + switch (elem_size) { + case 1: + *(int8_t*)str = (int8_t)va_arg(args, int); + break; + case 2: + *(int16_t*)str = (int16_t)va_arg(args, int); + break; + case 4: + *(int32_t*)str = va_arg(args, int32_t); + break; + case 8: + *(int64_t*)str = va_arg(args, int64_t); + break; + } + str += elem_size; + default: + str += ltt_align(str, sizeof(int)); + if (buffer) + *(int*)str = va_arg(args, int); + str += sizeof(int); + } + } + return str; +} + /* Calculate data size */ /* Assume that the padding for alignment starts at a * sizeof(void *) address. */ @@ -24,50 +264,50 @@ static inline __attribute__((no_instrument_function)) size_t ltt_get_data_size(ltt_facility_t fID, uint8_t eID, const char *fmt, va_list args) { - - - + return (size_t)ltt_serialize_data(NULL, fmt, args); } static inline __attribute__((no_instrument_function)) -size_t ltt_write_event_data(char *buffer, +void ltt_write_event_data(char *buffer, ltt_facility_t fID, uint8_t eID, const char *fmt, va_list args) { - - - + ltt_serialize_data(buffer, fmt, args); } __attribute__((no_instrument_function)) -void vtrace(ltt_facility_t fID, uint8_t eID, long flags, +void _vtrace(ltt_facility_t fID, uint8_t eID, long flags, const char *fmt, va_list args) { size_t data_size, slot_size; - uint8_t channel_index; + int channel_index; struct ltt_channel_struct *channel; struct ltt_trace_struct *trace, *dest_trace; void *transport_data; uint64_t tsc; char *buffer; + va_list args_copy; /* This test is useful for quickly exiting static tracing when no * trace is active. */ if (likely(ltt_traces.num_active_traces == 0 && !(flags & LTT_FLAG_FORCE))) return; - data_size = ltt_get_data_size(fID, eID, fmt, args); preempt_disable(); ltt_nesting[smp_processor_id()]++; if (unlikely(flags & LTT_FLAG_TRACE)) dest_trace = va_arg(args, struct ltt_trace_struct *); if (unlikely(flags & LTT_FLAG_CHANNEL)) - channel_index = va_arg(args, uint8_t); + channel_index = va_arg(args, int); else channel_index = ltt_get_channel_index(fID, eID); + va_copy(args_copy, args); /* Check : skip 2 st args if trace/ch */ + data_size = ltt_get_data_size(fID, eID, fmt, args_copy); + va_end(args_copy); + /* Iterate on each traces */ list_for_each_entry_rcu(trace, <t_traces.head, list) { if (unlikely(!trace->active && !(flags & LTT_FLAG_FORCE))) @@ -83,7 +323,9 @@ void vtrace(ltt_facility_t fID, uint8_t eID, long flags, /* Out-of-order write : header and data */ buffer = ltt_write_event_header(trace, channel, buffer, fID, eID, data_size, tsc); - ltt_write_event_data(buffer, fID, eID, fmt, args); + va_copy(args_copy, args); + ltt_write_event_data(buffer, fID, eID, fmt, args_copy); + va_end(args_copy); /* Out-of-order commit */ ltt_commit_slot(channel, &transport_data, buffer, slot_size); } @@ -93,12 +335,12 @@ void vtrace(ltt_facility_t fID, uint8_t eID, long flags, } __attribute__((no_instrument_function)) -void trace(ltt_facility_t fID, uint8_t eID, const char *fmt, ...) +void _trace(ltt_facility_t fID, uint8_t eID, long flags, const char *fmt, ...) { va_list args; va_start(args, fmt); - vtrace(fmt, args); + _vtrace(fID, eID, flags, fmt, args); va_end(args); } -- 2.34.1