diff options
Diffstat (limited to 'kernel/trace/trace_unlikely.c')
| -rw-r--r-- | kernel/trace/trace_unlikely.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/kernel/trace/trace_unlikely.c b/kernel/trace/trace_unlikely.c index 94932696069f..7290e0e7b4e3 100644 --- a/kernel/trace/trace_unlikely.c +++ b/kernel/trace/trace_unlikely.c | |||
| @@ -15,8 +15,122 @@ | |||
| 15 | #include <asm/local.h> | 15 | #include <asm/local.h> |
| 16 | #include "trace.h" | 16 | #include "trace.h" |
| 17 | 17 | ||
| 18 | #ifdef CONFIG_UNLIKELY_TRACER | ||
| 19 | |||
| 20 | static int unlikely_tracing_enabled __read_mostly; | ||
| 21 | static DEFINE_MUTEX(unlikely_tracing_mutex); | ||
| 22 | static struct trace_array *unlikely_tracer; | ||
| 23 | |||
| 24 | static void | ||
| 25 | probe_likely_condition(struct ftrace_likely_data *f, int val, int expect) | ||
| 26 | { | ||
| 27 | struct trace_array *tr = unlikely_tracer; | ||
| 28 | struct ring_buffer_event *event; | ||
| 29 | struct trace_unlikely *entry; | ||
| 30 | unsigned long flags, irq_flags; | ||
| 31 | int cpu, pc; | ||
| 32 | const char *p; | ||
| 33 | |||
| 34 | /* | ||
| 35 | * I would love to save just the ftrace_likely_data pointer, but | ||
| 36 | * this code can also be used by modules. Ugly things can happen | ||
| 37 | * if the module is unloaded, and then we go and read the | ||
| 38 | * pointer. This is slower, but much safer. | ||
| 39 | */ | ||
| 40 | |||
| 41 | if (unlikely(!tr)) | ||
| 42 | return; | ||
| 43 | |||
| 44 | local_irq_save(flags); | ||
| 45 | cpu = raw_smp_processor_id(); | ||
| 46 | if (atomic_inc_return(&tr->data[cpu]->disabled) != 1) | ||
| 47 | goto out; | ||
| 48 | |||
| 49 | event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), | ||
| 50 | &irq_flags); | ||
| 51 | if (!event) | ||
| 52 | goto out; | ||
| 53 | |||
| 54 | pc = preempt_count(); | ||
| 55 | entry = ring_buffer_event_data(event); | ||
| 56 | tracing_generic_entry_update(&entry->ent, flags, pc); | ||
| 57 | entry->ent.type = TRACE_UNLIKELY; | ||
| 58 | |||
| 59 | /* Strip off the path, only save the file */ | ||
| 60 | p = f->file + strlen(f->file); | ||
| 61 | while (p >= f->file && *p != '/') | ||
| 62 | p--; | ||
| 63 | p++; | ||
| 64 | |||
| 65 | strncpy(entry->func, f->func, TRACE_FUNC_SIZE); | ||
| 66 | strncpy(entry->file, p, TRACE_FILE_SIZE); | ||
| 67 | entry->func[TRACE_FUNC_SIZE] = 0; | ||
| 68 | entry->file[TRACE_FILE_SIZE] = 0; | ||
| 69 | entry->line = f->line; | ||
| 70 | entry->correct = val == expect; | ||
| 71 | |||
| 72 | ring_buffer_unlock_commit(tr->buffer, event, irq_flags); | ||
| 73 | |||
| 74 | out: | ||
| 75 | atomic_dec(&tr->data[cpu]->disabled); | ||
| 76 | local_irq_restore(flags); | ||
| 77 | } | ||
| 78 | |||
| 79 | static inline | ||
| 80 | void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect) | ||
| 81 | { | ||
| 82 | if (!unlikely_tracing_enabled) | ||
| 83 | return; | ||
| 84 | |||
| 85 | probe_likely_condition(f, val, expect); | ||
| 86 | } | ||
| 87 | |||
| 88 | int enable_unlikely_tracing(struct trace_array *tr) | ||
| 89 | { | ||
| 90 | int ret = 0; | ||
| 91 | |||
| 92 | mutex_lock(&unlikely_tracing_mutex); | ||
| 93 | unlikely_tracer = tr; | ||
| 94 | /* | ||
| 95 | * Must be seen before enabling. The reader is a condition | ||
| 96 | * where we do not need a matching rmb() | ||
| 97 | */ | ||
| 98 | smp_wmb(); | ||
| 99 | unlikely_tracing_enabled++; | ||
| 100 | mutex_unlock(&unlikely_tracing_mutex); | ||
| 101 | |||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | void disable_unlikely_tracing(void) | ||
| 106 | { | ||
| 107 | mutex_lock(&unlikely_tracing_mutex); | ||
| 108 | |||
| 109 | if (!unlikely_tracing_enabled) | ||
| 110 | goto out_unlock; | ||
| 111 | |||
| 112 | unlikely_tracing_enabled--; | ||
| 113 | |||
| 114 | out_unlock: | ||
| 115 | mutex_unlock(&unlikely_tracing_mutex); | ||
| 116 | } | ||
| 117 | #else | ||
| 118 | static inline | ||
| 119 | void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect) | ||
| 120 | { | ||
| 121 | } | ||
| 122 | #endif /* CONFIG_UNLIKELY_TRACER */ | ||
| 123 | |||
| 18 | void ftrace_likely_update(struct ftrace_likely_data *f, int val, int expect) | 124 | void ftrace_likely_update(struct ftrace_likely_data *f, int val, int expect) |
| 19 | { | 125 | { |
| 126 | /* | ||
| 127 | * I would love to have a trace point here instead, but the | ||
| 128 | * trace point code is so inundated with unlikely and likely | ||
| 129 | * conditions that the recursive nightmare that exists is too | ||
| 130 | * much to try to get working. At least for now. | ||
| 131 | */ | ||
| 132 | trace_likely_condition(f, val, expect); | ||
| 133 | |||
| 20 | /* FIXME: Make this atomic! */ | 134 | /* FIXME: Make this atomic! */ |
| 21 | if (val == expect) | 135 | if (val == expect) |
| 22 | f->correct++; | 136 | f->correct++; |
