diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index e1f8f7b06e3d..f3a7b4a6c2dd 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(clocksource_lock); @@ -246,6 +248,11 @@ void do_clocksource_switch(struct clocksource *cs) struct clocksource *old_clock; unsigned long flags; struct clocksource *old = curr_clocksource; + struct trace_point_data tp_data = { + .timestamp_switch = ktime_get_ns(), + .timestamp_baseline_recalc = 0, + .timestamp_read = 0, + }; if (!cs) return; @@ -320,6 +327,7 @@ void do_clocksource_switch(struct clocksource *cs) clocksource_stop_watchdog(old); clocksource_watchdog_lock(flags); + __clocksource_change_rating(cs, RATING_INTERNAL); clocksource_select(); @@ -343,6 +351,8 @@ void do_clocksource_switch(struct clocksource *cs) cs->flags &= ~CLOCK_SOURCE_SUSPENDED; cs->enable(cs); + tp_data.timestamp_baseline_recalc = ktime_get_ns(); + clocksource_start_watchdog(cs); if (old) @@ -352,11 +362,22 @@ void do_clocksource_switch(struct clocksource *cs) write_seqcount_begin(&clock->seq); clock->clocksource = cs; clock->cycle_last = curr_clocksource->read(curr_clocksource); + tp_data.timestamp_read = ktime_get_ns(); clock->mask = curr_clocksource->mask; clock->mult = curr_clocksource->mult; clock->shift = curr_clocksource->shift; write_seqcount_end(&clock->seq); raw_spin_unlock_irqrestore(&clock->lock, flags); + + if (!tp_data.timestamp_baseline_recalc) + tp_data.timestamp_baseline_recalc = tp_data.timestamp_switch; + + if (!tp_data.timestamp_read) + tp_data.timestamp_read = tp_data.timestamp_baseline_recalc; + + trace_clocksource_switch_latency(&tp_data); } diff --git a/include/trace/events/clocksource_switch.h b/include/trace/events/clocksource_switch.h new file mode 100644 index 000000000000..5e4c1a1d3c31 --- /dev/null +++ b/include/trace/events/clocksource_switch.h @@ -0,0 +1,53 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM clocksource_switch + +#if !defined(_TRACE_CLOCKSOURCE_SWITCH_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_CLOCKSOURCE_SWITCH_H + +#include +#include + +struct trace_point_data { + u64 timestamp_switch; + u64 timestamp_baseline_recalc; + u64 timestamp_read; +}; + +TRACE_EVENT(clocksource_switch_latency, + TP_PROTO(const struct trace_point_data *tp), + TP_ARGS(tp), + TP_STRUCT__entry( + __field(u64, timestamp_switch) + __field(u64, timestamp_baseline_recalc) + __field(u64, timestamp_read) + ), + TP_fast_assign( + __entry->timestamp_switch = tp->timestamp_switch; + __entry->timestamp_baseline_recalc = tp->timestamp_baseline_recalc; + __entry->timestamp_read = tp->timestamp_read; + ), + TP_printk("switch=%llu ns baseline=%llu ns read=%llu ns", + __entry->timestamp_switch, + __entry->timestamp_baseline_recalc, + __entry->timestamp_read) +); + +#endif /* _TRACE_CLOCKSOURCE_SWITCH_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH trace/events + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE clocksource_switch + +#include