xref: /linux-6.15/kernel/trace/trace_clock.c (revision eb887c45)
1bcea3f96SSteven Rostedt (VMware) // SPDX-License-Identifier: GPL-2.0
214131f2fSIngo Molnar /*
314131f2fSIngo Molnar  * tracing clocks
414131f2fSIngo Molnar  *
514131f2fSIngo Molnar  *  Copyright (C) 2009 Red Hat, Inc., Ingo Molnar <[email protected]>
614131f2fSIngo Molnar  *
714131f2fSIngo Molnar  * Implements 3 trace clock variants, with differing scalability/precision
814131f2fSIngo Molnar  * tradeoffs:
914131f2fSIngo Molnar  *
1014131f2fSIngo Molnar  *  -   local: CPU-local trace clock
1114131f2fSIngo Molnar  *  -  medium: scalable global clock with some jitter
1214131f2fSIngo Molnar  *  -  global: globally monotonic, serialized clock
1314131f2fSIngo Molnar  *
1414131f2fSIngo Molnar  * Tracer plugins will chose a default from these clocks.
1514131f2fSIngo Molnar  */
1614131f2fSIngo Molnar #include <linux/spinlock.h>
17ae1f3038SFrederic Weisbecker #include <linux/irqflags.h>
1814131f2fSIngo Molnar #include <linux/hardirq.h>
1914131f2fSIngo Molnar #include <linux/module.h>
2014131f2fSIngo Molnar #include <linux/percpu.h>
2114131f2fSIngo Molnar #include <linux/sched.h>
22e6017571SIngo Molnar #include <linux/sched/clock.h>
2314131f2fSIngo Molnar #include <linux/ktime.h>
24b8b94265SDmitri Vorobiev #include <linux/trace_clock.h>
2514131f2fSIngo Molnar 
2614131f2fSIngo Molnar /*
2714131f2fSIngo Molnar  * trace_clock_local(): the simplest and least coherent tracing clock.
2814131f2fSIngo Molnar  *
2914131f2fSIngo Molnar  * Useful for tracing that does not cross to other CPUs nor
3014131f2fSIngo Molnar  * does it go through idle events.
3114131f2fSIngo Molnar  */
trace_clock_local(void)3214131f2fSIngo Molnar u64 notrace trace_clock_local(void)
3314131f2fSIngo Molnar {
346cc3c6e1SPeter Zijlstra 	u64 clock;
356cc3c6e1SPeter Zijlstra 
3614131f2fSIngo Molnar 	/*
3714131f2fSIngo Molnar 	 * sched_clock() is an architecture implemented, fast, scalable,
3814131f2fSIngo Molnar 	 * lockless clock. It is not guaranteed to be coherent across
3914131f2fSIngo Molnar 	 * CPUs, nor across CPU idle events.
4014131f2fSIngo Molnar 	 */
415168ae50SSteven Rostedt 	preempt_disable_notrace();
426cc3c6e1SPeter Zijlstra 	clock = sched_clock();
435168ae50SSteven Rostedt 	preempt_enable_notrace();
446cc3c6e1SPeter Zijlstra 
456cc3c6e1SPeter Zijlstra 	return clock;
4614131f2fSIngo Molnar }
47dc975e94SPaul E. McKenney EXPORT_SYMBOL_GPL(trace_clock_local);
4814131f2fSIngo Molnar 
4914131f2fSIngo Molnar /*
5025985edcSLucas De Marchi  * trace_clock(): 'between' trace clock. Not completely serialized,
5114131f2fSIngo Molnar  * but not completely incorrect when crossing CPUs either.
5214131f2fSIngo Molnar  *
5314131f2fSIngo Molnar  * This is based on cpu_clock(), which will allow at most ~1 jiffy of
5414131f2fSIngo Molnar  * jitter between CPUs. So it's a pretty scalable clock, but there
5514131f2fSIngo Molnar  * can be offsets in the trace data.
5614131f2fSIngo Molnar  */
trace_clock(void)5714131f2fSIngo Molnar u64 notrace trace_clock(void)
5814131f2fSIngo Molnar {
59c676329aSPeter Zijlstra 	return local_clock();
6014131f2fSIngo Molnar }
617e255d34SJerry Snitselaar EXPORT_SYMBOL_GPL(trace_clock);
6214131f2fSIngo Molnar 
638aacf017SSteven Rostedt (Red Hat) /*
648aacf017SSteven Rostedt (Red Hat)  * trace_jiffy_clock(): Simply use jiffies as a clock counter.
6558d4e21eSTony Luck  * Note that this use of jiffies_64 is not completely safe on
6658d4e21eSTony Luck  * 32-bit systems. But the window is tiny, and the effect if
6758d4e21eSTony Luck  * we are affected is that we will have an obviously bogus
6858d4e21eSTony Luck  * timestamp on a trace event - i.e. not life threatening.
698aacf017SSteven Rostedt (Red Hat)  */
trace_clock_jiffies(void)708aacf017SSteven Rostedt (Red Hat) u64 notrace trace_clock_jiffies(void)
718aacf017SSteven Rostedt (Red Hat) {
7258d4e21eSTony Luck 	return jiffies_64_to_clock_t(jiffies_64 - INITIAL_JIFFIES);
738aacf017SSteven Rostedt (Red Hat) }
747e255d34SJerry Snitselaar EXPORT_SYMBOL_GPL(trace_clock_jiffies);
7514131f2fSIngo Molnar 
7614131f2fSIngo Molnar /*
7714131f2fSIngo Molnar  * trace_clock_global(): special globally coherent trace clock
7814131f2fSIngo Molnar  *
7914131f2fSIngo Molnar  * It has higher overhead than the other trace clocks but is still
8014131f2fSIngo Molnar  * an order of magnitude faster than GTOD derived hardware clocks.
8114131f2fSIngo Molnar  *
8214131f2fSIngo Molnar  * Used by plugins that need globally coherent timestamps.
8314131f2fSIngo Molnar  */
8414131f2fSIngo Molnar 
856ca6cca3SSteven Rostedt /* keep prev_time and lock in the same cacheline. */
866ca6cca3SSteven Rostedt static struct {
876ca6cca3SSteven Rostedt 	u64 prev_time;
88445c8951SThomas Gleixner 	arch_spinlock_t lock;
896ca6cca3SSteven Rostedt } trace_clock_struct ____cacheline_aligned_in_smp =
906ca6cca3SSteven Rostedt 	{
91edc35bd7SThomas Gleixner 		.lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED,
926ca6cca3SSteven Rostedt 	};
9314131f2fSIngo Molnar 
trace_clock_global(void)9414131f2fSIngo Molnar u64 notrace trace_clock_global(void)
9514131f2fSIngo Molnar {
9614131f2fSIngo Molnar 	unsigned long flags;
9714131f2fSIngo Molnar 	int this_cpu;
98aafe104aSSteven Rostedt (VMware) 	u64 now, prev_time;
9914131f2fSIngo Molnar 
100f7a1570dSSteven Rostedt (VMware) 	raw_local_irq_save(flags);
10114131f2fSIngo Molnar 
10214131f2fSIngo Molnar 	this_cpu = raw_smp_processor_id();
103aafe104aSSteven Rostedt (VMware) 
10414131f2fSIngo Molnar 	/*
105aafe104aSSteven Rostedt (VMware) 	 * The global clock "guarantees" that the events are ordered
106aafe104aSSteven Rostedt (VMware) 	 * between CPUs. But if two events on two different CPUS call
107aafe104aSSteven Rostedt (VMware) 	 * trace_clock_global at roughly the same time, it really does
108aafe104aSSteven Rostedt (VMware) 	 * not matter which one gets the earlier time. Just make sure
109aafe104aSSteven Rostedt (VMware) 	 * that the same CPU will always show a monotonic clock.
110aafe104aSSteven Rostedt (VMware) 	 *
111aafe104aSSteven Rostedt (VMware) 	 * Use a read memory barrier to get the latest written
112aafe104aSSteven Rostedt (VMware) 	 * time that was recorded.
113aafe104aSSteven Rostedt (VMware) 	 */
114aafe104aSSteven Rostedt (VMware) 	smp_rmb();
115aafe104aSSteven Rostedt (VMware) 	prev_time = READ_ONCE(trace_clock_struct.prev_time);
116aafe104aSSteven Rostedt (VMware) 	now = sched_clock_cpu(this_cpu);
117aafe104aSSteven Rostedt (VMware) 
11889529d8bSSteven Rostedt (VMware) 	/* Make sure that now is always greater than or equal to prev_time */
119aafe104aSSteven Rostedt (VMware) 	if ((s64)(now - prev_time) < 0)
12089529d8bSSteven Rostedt (VMware) 		now = prev_time;
121aafe104aSSteven Rostedt (VMware) 
122aafe104aSSteven Rostedt (VMware) 	/*
123aafe104aSSteven Rostedt (VMware) 	 * If in an NMI context then dont risk lockups and simply return
124aafe104aSSteven Rostedt (VMware) 	 * the current time.
12514131f2fSIngo Molnar 	 */
12614131f2fSIngo Molnar 	if (unlikely(in_nmi()))
12714131f2fSIngo Molnar 		goto out;
12814131f2fSIngo Molnar 
129aafe104aSSteven Rostedt (VMware) 	/* Tracing can cause strange recursion, always use a try lock */
130aafe104aSSteven Rostedt (VMware) 	if (arch_spin_trylock(&trace_clock_struct.lock)) {
131aafe104aSSteven Rostedt (VMware) 		/* Reread prev_time in case it was already updated */
132aafe104aSSteven Rostedt (VMware) 		prev_time = READ_ONCE(trace_clock_struct.prev_time);
133aafe104aSSteven Rostedt (VMware) 		if ((s64)(now - prev_time) < 0)
13489529d8bSSteven Rostedt (VMware) 			now = prev_time;
13514131f2fSIngo Molnar 
1366ca6cca3SSteven Rostedt 		trace_clock_struct.prev_time = now;
13714131f2fSIngo Molnar 
138aafe104aSSteven Rostedt (VMware) 		/* The unlock acts as the wmb for the above rmb */
1390199c4e6SThomas Gleixner 		arch_spin_unlock(&trace_clock_struct.lock);
140aafe104aSSteven Rostedt (VMware) 	}
14114131f2fSIngo Molnar  out:
142f7a1570dSSteven Rostedt (VMware) 	raw_local_irq_restore(flags);
14314131f2fSIngo Molnar 
14414131f2fSIngo Molnar 	return now;
14514131f2fSIngo Molnar }
1467e255d34SJerry Snitselaar EXPORT_SYMBOL_GPL(trace_clock_global);
1476249687fSSteven Rostedt 
1486249687fSSteven Rostedt static atomic64_t trace_counter;
1496249687fSSteven Rostedt 
1506249687fSSteven Rostedt /*
1516249687fSSteven Rostedt  * trace_clock_counter(): simply an atomic counter.
1526249687fSSteven Rostedt  * Use the trace_counter "counter" for cases where you do not care
1536249687fSSteven Rostedt  * about timings, but are interested in strict ordering.
1546249687fSSteven Rostedt  */
trace_clock_counter(void)1556249687fSSteven Rostedt u64 notrace trace_clock_counter(void)
1566249687fSSteven Rostedt {
157*eb887c45SUros Bizjak 	return atomic64_inc_return(&trace_counter);
1586249687fSSteven Rostedt }
159