/* * Sequence count - we record it when starting a measurement and * skip the latency if the sequence has changed - some other section * did a maximum and could disturb our measurement with serial console * printouts, etc. Truly coinciding maximum latencies should be rare * and what happens together happens separately as well, so this doesn't * decrease the validity of the maximum found:
*/ static __cacheline_aligned_in_smp unsignedlong max_sequence;
#ifdef CONFIG_FUNCTION_TRACER /* * Prologue for the preempt and irqs off function tracers. * * Returns 1 if it is OK to continue, and data->disabled is * incremented. * 0 if the trace is to be ignored, and data->disabled * is kept the same. * * Note, this function is also used outside this ifdef but * inside the #ifdef of the function graph tracer below. * This is OK, since the function graph tracer is * dependent on the function tracer.
*/ staticint func_prolog_dec(struct trace_array *tr, struct trace_array_cpu **data, unsignedlong *flags)
{ long disabled; int cpu;
/* * Does not matter if we preempt. We test the flags * afterward, to see if irqs are disabled or not. * If we preempt and get a false positive, the flags * test will fail.
*/
cpu = raw_smp_processor_id(); if (likely(!per_cpu(tracing_cpu, cpu))) return 0;
local_save_flags(*flags); /* * Slight chance to get a false positive on tracing_cpu, * although I'm starting to think there isn't a chance. * Leave this for now just to be paranoid.
*/ if (!irqs_disabled_flags(*flags) && !preempt_count()) return 0;
if (ftrace_graph_ignore_func(gops, trace)) return 0; /* * Do not trace a function if it's filtered by set_graph_notrace. * Make the index of ret stack negative to indicate that it should * ignore further functions. But it needs its own ret stack entry * to recover the original index in order to continue tracing after * returning from the function.
*/ if (ftrace_graph_notrace_addr(trace->func)) return 1;
if (!func_prolog_dec(tr, &data, &flags)) return 0;
calltime = fgraph_reserve_data(gops->idx, sizeof(*calltime)); if (calltime) {
*calltime = trace_clock_local();
trace_ctx = tracing_gen_ctx_flags(flags);
ret = __trace_graph_entry(tr, trace, trace_ctx);
}
local_dec(&data->disabled);
/* * Should this new latency be reported/recorded?
*/ staticbool report_latency(struct trace_array *tr, u64 delta)
{ if (tracing_thresh) { if (delta < tracing_thresh) returnfalse;
} else { if (delta <= tr->max_latency) returnfalse;
} returntrue;
}
/* check if we are still the max latency */ if (!report_latency(tr, delta)) goto out_unlock;
__trace_function(tr, CALLER_ADDR0, parent_ip, trace_ctx); /* Skip 5 functions to get to the irq/preempt enable function */
__trace_stack(tr, trace_ctx, 5);
if (data->critical_sequence != max_sequence) goto out_unlock;
data->critical_end = parent_ip;
if (likely(!is_tracing_stopped())) {
tr->max_latency = delta;
update_max_tr_single(tr, current, cpu);
}
cpu = raw_smp_processor_id(); /* Always clear the tracing cpu on stopping the trace */ if (unlikely(per_cpu(tracing_cpu, cpu)))
per_cpu(tracing_cpu, cpu) = 0; else return;
if (!tracer_enabled || !tracing_is_enabled()) return;
data = per_cpu_ptr(tr->array_buffer.data, cpu);
if (unlikely(!data) ||
!data->critical_start || local_read(&data->disabled)) return;
/* start and stop critical timings used to for stoppage (in idle) */ void start_critical_timings(void)
{ if (preempt_trace(preempt_count()) || irq_trace())
start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
}
EXPORT_SYMBOL_GPL(start_critical_timings);
NOKPROBE_SYMBOL(start_critical_timings);
staticvoid stop_irqsoff_tracer(struct trace_array *tr, int graph)
{
tracer_enabled = 0;
unregister_irqsoff_function(tr, graph);
}
staticbool irqsoff_busy;
staticint __irqsoff_tracer_init(struct trace_array *tr)
{ if (irqsoff_busy) return -EBUSY;
save_flags = tr->trace_flags;
/* non overwrite screws up the latency tracers */
set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1); /* without pause, we will produce garbage if another latency occurs */
set_tracer_flag(tr, TRACE_ITER_PAUSE_ON_TRACE, 1);
tr->max_latency = 0;
irqsoff_trace = tr; /* make sure that the tracer is visible */
smp_wmb();
ftrace_init_array_ops(tr, irqsoff_tracer_call);
/* Only toplevel instance supports graph tracing */ if (start_irqsoff_tracer(tr, (tr->flags & TRACE_ARRAY_FL_GLOBAL &&
is_graph(tr))))
printk(KERN_ERR "failed to start irqsoff tracer\n");
irqsoff_busy = true; return 0;
}
staticvoid __irqsoff_tracer_reset(struct trace_array *tr)
{ int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT; int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE; int pause_flag = save_flags & TRACE_ITER_PAUSE_ON_TRACE;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.