]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - kernel/trace/trace.c
tracing: likely/unlikely branch annotation tracer
[mv-sheeva.git] / kernel / trace / trace.c
index 216bbe7547a458e86ccfd030548a11c5cdaf690f..83d38634bc90b40643aa3dcd5a1a18aa713e377c 100644 (file)
@@ -244,13 +244,6 @@ unsigned long nsecs_to_usecs(unsigned long nsecs)
        return nsecs / 1000;
 }
 
-/*
- * TRACE_ITER_SYM_MASK masks the options in trace_flags that
- * control the output of kernel symbols.
- */
-#define TRACE_ITER_SYM_MASK \
-       (TRACE_ITER_PRINT_PARENT|TRACE_ITER_SYM_OFFSET|TRACE_ITER_SYM_ADDR)
-
 /* These must match the bit postions in trace_iterator_flags */
 static const char *trace_options[] = {
        "print-parent",
@@ -265,6 +258,9 @@ static const char *trace_options[] = {
        "sched-tree",
        "ftrace_printk",
        "ftrace_preempt",
+#ifdef CONFIG_UNLIKELY_TRACER
+       "unlikely",
+#endif
        NULL
 };
 
@@ -810,6 +806,35 @@ trace_function(struct trace_array *tr, struct trace_array_cpu *data,
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 }
 
+#ifdef CONFIG_FUNCTION_RET_TRACER
+static void __trace_function_return(struct trace_array *tr,
+                               struct trace_array_cpu *data,
+                               struct ftrace_retfunc *trace,
+                               unsigned long flags,
+                               int pc)
+{
+       struct ring_buffer_event *event;
+       struct ftrace_ret_entry *entry;
+       unsigned long irq_flags;
+
+       if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
+               return;
+
+       event = ring_buffer_lock_reserve(global_trace.buffer, sizeof(*entry),
+                                        &irq_flags);
+       if (!event)
+               return;
+       entry   = ring_buffer_event_data(event);
+       tracing_generic_entry_update(&entry->ent, flags, pc);
+       entry->ent.type                 = TRACE_FN_RET;
+       entry->ip                       = trace->func;
+       entry->parent_ip        = trace->ret;
+       entry->rettime          = trace->rettime;
+       entry->calltime         = trace->calltime;
+       ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
+}
+#endif
+
 void
 ftrace(struct trace_array *tr, struct trace_array_cpu *data,
        unsigned long ip, unsigned long parent_ip, unsigned long flags,
@@ -1038,6 +1063,29 @@ function_trace_call(unsigned long ip, unsigned long parent_ip)
        raw_local_irq_restore(flags);
 }
 
+#ifdef CONFIG_FUNCTION_RET_TRACER
+void trace_function_return(struct ftrace_retfunc *trace)
+{
+       struct trace_array *tr = &global_trace;
+       struct trace_array_cpu *data;
+       unsigned long flags;
+       long disabled;
+       int cpu;
+       int pc;
+
+       raw_local_irq_save(flags);
+       cpu = raw_smp_processor_id();
+       data = tr->data[cpu];
+       disabled = atomic_inc_return(&data->disabled);
+       if (likely(disabled == 1)) {
+               pc = preempt_count();
+               __trace_function_return(tr, data, trace, flags, pc);
+       }
+       atomic_dec(&data->disabled);
+       raw_local_irq_restore(flags);
+}
+#endif /* CONFIG_FUNCTION_RET_TRACER */
+
 static struct ftrace_ops trace_ops __read_mostly =
 {
        .func = function_trace_call,
@@ -1285,7 +1333,7 @@ seq_print_sym_offset(struct trace_seq *s, const char *fmt,
 # define IP_FMT "%016lx"
 #endif
 
-static int
+int
 seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
 {
        int ret;
@@ -1603,6 +1651,18 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
                        trace_seq_print_cont(s, iter);
                break;
        }
+       case TRACE_UNLIKELY: {
+               struct trace_unlikely *field;
+
+               trace_assign_type(field, entry);
+
+               trace_seq_printf(s, "[%s] %s:%s:%d\n",
+                                field->correct ? "correct" : "INCORRECT",
+                                field->func,
+                                field->file,
+                                field->line);
+               break;
+       }
        default:
                trace_seq_printf(s, "Unknown type %d\n", entry->type);
        }
@@ -1738,6 +1798,22 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
                        trace_seq_print_cont(s, iter);
                break;
        }
+       case TRACE_FN_RET: {
+               return print_return_function(iter);
+               break;
+       }
+       case TRACE_UNLIKELY: {
+               struct trace_unlikely *field;
+
+               trace_assign_type(field, entry);
+
+               trace_seq_printf(s, "[%s] %s:%s:%d\n",
+                                field->correct ? "correct" : "INCORRECT",
+                                field->func,
+                                field->file,
+                                field->line);
+               break;
+       }
        }
        return TRACE_TYPE_HANDLED;
 }
@@ -2543,6 +2619,7 @@ static int tracing_set_tracer(char *buf)
        if (t == current_trace)
                goto out;
 
+       trace_unlikely_disable();
        if (current_trace && current_trace->reset)
                current_trace->reset(tr);
 
@@ -2550,6 +2627,7 @@ static int tracing_set_tracer(char *buf)
        if (t->init)
                t->init(tr);
 
+       trace_unlikely_enable(tr);
  out:
        mutex_unlock(&trace_types_lock);