Re: Allow tracepoints to use direct indexing for number->string translation

From: Steven Rostedt
Date: Fri Dec 16 2016 - 11:37:54 EST


On Fri, 16 Dec 2016 16:22:25 +0000
David Howells <dhowells@xxxxxxxxxx> wrote:

> Steven Rostedt <rostedt@xxxxxxxxxxx> wrote:
>
> > > Another feature that would be very nice to have is the ability to turn a
> > > number into a string by direct array index rather than by table search or
> > > serial ?: ternary operators.
> >
> > Which function are you talking about?
>
> See the attached patch that converts rxrpc's tracing from using string arrays
> to using TRACE_DEFINE_ENUM so that utilities like crash's trace buffer
> disassembler can find the string values.
>
> When __print_symbolic() is used, each set of strings is rendered as an array
> of trace_print_flag structs which trace_print_symbols_seq() then iterates
> over to find a match.
>

You mean to do something like this? (untested, not even compiled)

-- Steve

---
include/linux/trace_events.h | 6 ++++--
include/trace/trace_events.h | 10 ++++++----
kernel/trace/trace_output.c | 28 ++++++++++++++++++++++++----
3 files changed, 34 insertions(+), 10 deletions(-)

Index: linux-trace.git/include/linux/trace_events.h
===================================================================
--- linux-trace.git.orig/include/linux/trace_events.h 2016-11-15 17:27:19.397749523 -0500
+++ linux-trace.git/include/linux/trace_events.h 2016-12-16 11:34:38.783424430 -0500
@@ -20,13 +20,15 @@ const char *trace_print_flags_seq(struct
const struct trace_print_flags *flag_array);

const char *trace_print_symbols_seq(struct trace_seq *p, unsigned long val,
- const struct trace_print_flags *symbol_array);
+ const struct trace_print_flags *symbol_array,
+ unsigned long nr);

#if BITS_PER_LONG == 32
const char *trace_print_symbols_seq_u64(struct trace_seq *p,
unsigned long long val,
const struct trace_print_flags_u64
- *symbol_array);
+ *symbol_array,
+ unsigned long long nr);
#endif

const char *trace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr,
Index: linux-trace.git/include/trace/trace_events.h
===================================================================
--- linux-trace.git.orig/include/trace/trace_events.h 2016-12-16 11:29:39.599950900 -0500
+++ linux-trace.git/include/trace/trace_events.h 2016-12-16 11:30:39.927844742 -0500
@@ -279,8 +279,9 @@ TRACE_MAKE_SYSTEM_STR();
#define __print_symbolic(value, symbol_array...) \
({ \
static const struct trace_print_flags symbols[] = \
- { symbol_array, { -1, NULL }}; \
- trace_print_symbols_seq(p, value, symbols); \
+ { symbol_array}}; \
+ trace_print_symbols_seq(p, value, symbols, \
+ ARRAY_SIZE(symbols)); \
})

#undef __print_symbolic_u64
@@ -288,8 +289,9 @@ TRACE_MAKE_SYSTEM_STR();
#define __print_symbolic_u64(value, symbol_array...) \
({ \
static const struct trace_print_flags_u64 symbols[] = \
- { symbol_array, { -1, NULL } }; \
- trace_print_symbols_seq_u64(p, value, symbols); \
+ { symbol_array }; \
+ trace_print_symbols_seq_u64(p, value, symbols, \
+ ARRAY_SIZE(symbols)); \
})
#else
#define __print_symbolic_u64(value, symbol_array...) \
Index: linux-trace.git/kernel/trace/trace_output.c
===================================================================
--- linux-trace.git.orig/kernel/trace/trace_output.c 2016-12-14 10:33:28.581929129 -0500
+++ linux-trace.git/kernel/trace/trace_output.c 2016-12-16 11:36:41.695208145 -0500
@@ -99,12 +99,21 @@ EXPORT_SYMBOL(trace_print_flags_seq);

const char *
trace_print_symbols_seq(struct trace_seq *p, unsigned long val,
- const struct trace_print_flags *symbol_array)
+ const struct trace_print_flags *symbol_array,
+ unsigned long nr)
{
int i;
const char *ret = trace_seq_buffer_ptr(p);

- for (i = 0; symbol_array[i].name; i++) {
+ /* A lot of arrays are simply enums that map to the array index */
+ if (val < nr) {
+ if (val == symbol_array[val].mask) {
+ trace_seq_puts(p, symbol_array[val].name);
+ goto out;
+ }
+ }
+
+ for (i = 0; i < nr; i++) {

if (val != symbol_array[i].mask)
continue;
@@ -116,6 +125,7 @@ trace_print_symbols_seq(struct trace_seq
if (ret == (const char *)(trace_seq_buffer_ptr(p)))
trace_seq_printf(p, "0x%lx", val);

+ out:
trace_seq_putc(p, 0);

return ret;
@@ -125,12 +135,21 @@ EXPORT_SYMBOL(trace_print_symbols_seq);
#if BITS_PER_LONG == 32
const char *
trace_print_symbols_seq_u64(struct trace_seq *p, unsigned long long val,
- const struct trace_print_flags_u64 *symbol_array)
+ const struct trace_print_flags_u64 *symbol_array,
+ unsigned long long nr)
{
int i;
const char *ret = trace_seq_buffer_ptr(p);

- for (i = 0; symbol_array[i].name; i++) {
+ /* A lot of arrays are simply enums that map to the array index */
+ if (val < nr) {
+ if (val == symbol_array[val].mask) {
+ trace_seq_puts(p, symbol_array[val].name);
+ goto out;
+ }
+ }
+
+ for (i = 0; i < nr; i++) {

if (val != symbol_array[i].mask)
continue;
@@ -142,6 +161,7 @@ trace_print_symbols_seq_u64(struct trace
if (ret == (const char *)(trace_seq_buffer_ptr(p)))
trace_seq_printf(p, "0x%llx", val);

+ out:
trace_seq_putc(p, 0);

return ret;