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