timekeeping: Introduce a fast boot clock derived from fast monotonic clock
Subsystems (2)
PATCH v2 1/2 timekeeping: Introduce a fast boot clock derived from fast monotonic clock
Introduce a fast boot clock. It accounts for suspend time and is based on the fast monotonic clock so that its safe to use for tracing. Next patch adds the clock to trace clock.
--- kernel/time/timekeeping.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-)
kernel/time/timekeeping.c +30 -6
@@ -56,6 +56,12 @@ static struct timekeeper shadow_timekeeper;struct tk_fast {seqcount_t seq;struct tk_read_base base[2 ]; + +/* +* first dimension is based on lower seq bit, +* second dimension is for offset type (real, boot, tai) +*/ +ktime_t offsets[2 ][TK_OFFS_MAX ]; };static struct tk_fast tk_fast_mono____cacheline_aligned ;
@@ -350,14 +356,20 @@ static void update_fast_timekeeper(struct tk_read_base *tkr, struct tk_fast *tkf/* Force readers off to base[1] */ raw_write_seqcount_latch (&tkf->seq); -/* Update base[0] */ +/* Update base[0] and offsets*/ memcpy (base, tkr,sizeof (*base)); + tkf->offsets[0 ][TK_OFFS_REAL ] = tk_core.timekeeper.offs_real; + tkf->offsets[0 ][TK_OFFS_BOOT ] = tk_core.timekeeper.offs_boot; + tkf->offsets[0 ][TK_OFFS_TAI ] = tk_core.timekeeper.offs_tai;/* Force readers back to base[0] */ raw_write_seqcount_latch (&tkf->seq); -/* Update base[1] */ +/* Update base[1] and offsets*/ memcpy (base +1 , base,sizeof (*base)); + tkf->offsets[1 ][TK_OFFS_REAL ] = tk_core.timekeeper.offs_real; + tkf->offsets[1 ][TK_OFFS_BOOT ] = tk_core.timekeeper.offs_boot; + tkf->offsets[1 ][TK_OFFS_TAI ] = tk_core.timekeeper.offs_tai; }/**
@@ -392,16 +404,23 @@ static void update_fast_timekeeper(struct tk_read_base *tkr, struct tk_fast *tkf* of the following timestamps. Callers need to be aware of that and * deal with it. */ -static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf) +static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf, int offset) { struct tk_read_base *tkr; unsigned int seq; u64 now; + ktime_t *off; do { seq = raw_read_seqcount_latch(&tkf->seq); tkr = tkf->base + (seq & 0x01); - now = ktime_to_ns(tkr->base); + + if (unlikely((offset >= 0))) { + off = tkf->offsets[seq & 0x01]; + now = ktime_to_ns(ktime_add(tkr->base, off[offset])); + } else { + now = ktime_to_ns(tkr->base); + } now += timekeeping_delta_to_ns(tkr, clocksource_delta(
@@ -415,16 +434,21 @@ static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)u64 ktime_get_mono_fast_ns (void ) { -return __ktime_get_fast_ns (&tk_fast_mono); +return __ktime_get_fast_ns (&tk_fast_mono,-1 ); }EXPORT_SYMBOL_GPL (ktime_get_mono_fast_ns);u64 ktime_get_raw_fast_ns (void ) { -return __ktime_get_fast_ns (&tk_fast_raw); +return __ktime_get_fast_ns (&tk_fast_raw,-1 ); }EXPORT_SYMBOL_GPL (ktime_get_raw_fast_ns); +u64 ktime_get_boot_fast_ns (void ) +{ +return __ktime_get_fast_ns (&tk_fast_mono,TK_OFFS_BOOT ); +} +/* Suspend-time cycles value for halted fast timekeeper. */ static cycle_t cycles_at_suspend;
Signature · 1 line
2.8.0.rc3.226.g39d4020
PATCH v2 2/2 trace: Add an option for boot clock as trace clock
Unlike monotonic clock, boot clock as a trace clock will account for time spent in suspend useful for tracing suspend/resume. This uses earlier introduced infrastructure for using the fast boot clock.
--- kernel/trace/trace.c | 1 + 1 file changed, 1 insertion(+)
kernel/trace/trace.c +1 -0
@@ -1125,6 +1125,7 @@ static struct { { trace_clock, "perf", 1 }, { ktime_get_mono_fast_ns, "mono", 1 }, { ktime_get_raw_fast_ns, "mono_raw", 1 }, + { ktime_get_boot_fast_ns, "boot", 1 },ARCH_TRACE_CLOCKS };
Signature · 1 line
2.8.0.rc3.226.g39d4020
Steven Rostedt
maintainerRe: [PATCH v2 2/2] trace: Add an option for boot clock as trace clock
Quoted 18 lines · On Mon, 21 Nov 2016 14:12:50 -0800 Joel Fernandes <[email protected]> wrote:
Unlike monotonic clock, boot clock as a trace clock will account for time spent in suspend useful for tracing suspend/resume. This uses earlier introduced infrastructure for using the fast boot clock.
Cc Steven Rostedt <[email protected]>Cc Thomas Gleixner <[email protected]>Cc John Stultz <[email protected]>Cc Ingo Molnar <[email protected]>Signed-off-by Joel Fernandes <[email protected]>--- kernel/trace/trace.c | 1 + 1 file changed, 1 insertion(+)kernel/trace/trace.c +0
-0
kernel/trace/trace.c static struct { · line 1131
Quoted 7 lines
kernel/trace/trace.c +1
-0@@ -1125,6 +1125,7 @@ static struct { { trace_clock, "perf", 1 }, { ktime_get_mono_fast_ns, "mono", 1 }, { ktime_get_raw_fast_ns, "mono_raw", 1 }, + { ktime_get_boot_fast_ns, "boot", 1 },ARCH_TRACE_CLOCKS };
I'm fine with this change, but can you please update Documentation/trace/ftrace.txt under trace_clock. I notice that mono and mono_raw are missing too.
-- Steve
kbuild test robot
build botRe: [PATCH v2 2/2] trace: Add an option for boot clock as trace clock
In reply to Joel Fernandesurl: https://github.com/0day-ci/linux/commits/Joel-Fernandes/timekeeping-Introduce-a-fast-boot-clock-derived-from-fast-monotonic-clock/20161122-071652 config: x86_64-rhel (attached as .config)…
Hi Joel,
[auto build test ERROR on tip/timers/core]
[also build test ERROR on v4.9-rc6 next-20161117]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Joel-Fernandes/timekeeping-Introduce-a-fast-boot-clock-derived-from-fast-monotonic-clock/20161122-071652
config: x86_64-rhel (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 All errors (new ones prefixed by >>):
>> kernel/trace/trace.c:1128:4: error: 'ktime_get_boot_fast_ns' undeclared here (not in a function)
{ ktime_get_boot_fast_ns, "boot", 1 },
^~~~~~~~~~~~~~~~~~~~~~vim +/ktime_get_boot_fast_ns +1128 kernel/trace/trace.c
1122 { trace_clock_global, "global", 1 },
1123 { trace_clock_counter, "counter", 0 },
1124 { trace_clock_jiffies, "uptime", 0 },
1125 { trace_clock, "perf", 1 },
1126 { ktime_get_mono_fast_ns, "mono", 1 },
1127 { ktime_get_raw_fast_ns, "mono_raw", 1 },
> 1128 { ktime_get_boot_fast_ns, "boot", 1 }, 1129 ARCH_TRACE_CLOCKS
1130 };
1131
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
kernel/time/timekeeping.c static struct timekeeper shadow_timekeeper; · line 63
Quoted 9 lines · Joel Fernandes
kernel/time/timekeeping.c +5
-0@@ -56,6 +56,12 @@ static struct timekeeper shadow_timekeeper;struct tk_fast {seqcount_t seq;struct tk_read_base base[2 ]; + +/* +* first dimension is based on lower seq bit, +* second dimension is for offset type (real, boot, tai) +*/
Can you figure out why there are comments above the struct which explain the members in Kernel Doc format and not randomly formatted comments inside the struct definition?
kernel/time/timekeeping.c static struct timekeeper shadow_timekeeper; · line 64
Quoted 1 line
kernel/time/timekeeping.c +1
-0+ktime_t offsets[2 ][TK_OFFS_MAX ];
This bloats fast_tk_raw for no value, along with the extra stores in the update function for fast_tk_raw which will never use that offset stuff.
Aside of that, I really have to ask the question whether it's really necessary to add this extra bloat in storage, update and readout code for something which is not used by most people.
What's wrong with adding a tracepoint into the boot offset update function and let perf or the tracer inject the value of the boot offset into the trace data when starting. The time adjustment can be done in postprocessing.
That should be sufficient for tracing suspend/resume behaviour. If there is not a really convincing reason for having that as a real trace clock then I prefer to avoid that extra stuff.
Thanks,
tglx
Hi Thomas,
Quoted 15 lines · Thomas Gleixner
kernel/time/timekeeping.c static struct timekeeper shadow_timekeeper; · line 63
Quoted 9 lines · Joel Fernandes
kernel/time/timekeeping.c +5
-0@@ -56,6 +56,12 @@ static struct timekeeper shadow_timekeeper;struct tk_fast {seqcount_t seq;struct tk_read_base base[2 ]; + +/* +* first dimension is based on lower seq bit, +* second dimension is for offset type (real, boot, tai) +*/ Can you figure out why there are comments above the struct which explain the members in Kernel Doc format and not randomly formatted comments inside the struct definition?
Ok sorry. I can move the comments before the function in the prescribed format.
Quoted 5 lines
kernel/time/timekeeping.c static struct timekeeper shadow_timekeeper; · line 64
Quoted 1 line
kernel/time/timekeeping.c +1
-0+ktime_t offsets[2 ][TK_OFFS_MAX ];This bloats
fast_tk_rawfor no value, along with the extra stores in the update function forfast_tk_rawwhich will never use that offset stuff.
Quoted 8 lines
Aside of that, I really have to ask the question whether it's really necessary to add this extra bloat in storage, update and readout code for something which is not used by most people.
What's wrong with adding a tracepoint into the boot offset update function and let perf or the tracer inject the value of the boot offset into the trace data when starting. The time adjustment can be done in postprocessing.
I agree we're bloating this and probably not very acceptable. tracepoint adds additional complexity and out of tree patches which we'd like to avoid. Would you be Ok if we added a relatively simple function like below that could do the job and not bloat the optimal case?
/*
* Fast and NMI safe access to boot time. It may be slightly out of date
* as we're accessing offset without seqcount writes, but is safe to access. */
u64 ktime_get_boot_fast_ns(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
return __ktime_get_fast_ns(&tk_fast_mono) + tk->offs_boot;
}EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);
Quoted 3 lines
That should be sufficient for tracing suspend/resume behaviour. If there is not a really convincing reason for having that as a real trace clock then I prefer to avoid that extra stuff.
Several clocks are accessible just by simple writing of clock name to trace_clock in debugfs. This is really cool and doesn't require any out of tree patches or post processing complexity.
Thanks,
Joel
Quoted 41 lines · Joel Fernandes
Hi Thomas,
Quoted 15 lines · Thomas Gleixner
kernel/time/timekeeping.c static struct timekeeper shadow_timekeeper; · line 63
Quoted 9 lines · Joel Fernandes
kernel/time/timekeeping.c +5
-0@@ -56,6 +56,12 @@ static struct timekeeper shadow_timekeeper;struct tk_fast {seqcount_t seq;struct tk_read_base base[2 ]; + +/* +* first dimension is based on lower seq bit, +* second dimension is for offset type (real, boot, tai) +*/ Can you figure out why there are comments above the struct which explain the members in Kernel Doc format and not randomly formatted comments inside the struct definition?
Ok sorry. I can move the comments before the function in the prescribed format.
Quoted 5 lines
kernel/time/timekeeping.c static struct timekeeper shadow_timekeeper; · line 64
Quoted 1 line
kernel/time/timekeeping.c +1
-0+ktime_t offsets[2 ][TK_OFFS_MAX ];This bloats
fast_tk_rawfor no value, along with the extra stores in the update function forfast_tk_rawwhich will never use that offset stuff.Quoted 8 lines
Aside of that, I really have to ask the question whether it's really necessary to add this extra bloat in storage, update and readout code for something which is not used by most people.
What's wrong with adding a tracepoint into the boot offset update function and let perf or the tracer inject the value of the boot offset into the trace data when starting. The time adjustment can be done in postprocessing.
I agree we're bloating this and probably not very acceptable. tracepoint adds additional complexity and out of tree patches which we'd like to avoid. Would you be Ok if we added a relatively simple function like below that could do the job and not bloat the optimal case?
Quoted 3 lines
/*
* Fast and NMI safe access to boot time. It may be slightly out of date
* as we're accessing offset without seqcount writes, but is safe to access.
s/writes/reads/
Quoted 5 lines
*/
u64ktime_get_boot_fast_ns(void){ struct timekeeper *tk = &tk_core.timekeeper; return __ktime_get_fast_ns(&tk_fast_mono) + tk->offs_boot;
I meant, __ktime_get_fast_ns(&tk_fast_mono) + ktime_to_ns(tk->offs_boot). Was just showing the idea...
Joel
Quoted 14 lines
}
EXPORT_SYMBOL_GPL(ktime_get_boot_fast_ns);Quoted 3 lines
That should be sufficient for tracing suspend/resume behaviour. If there is not a really convincing reason for having that as a real trace clock then I prefer to avoid that extra stuff.
Several clocks are accessible just by simple writing of clock name to
trace_clockin debugfs. This is really cool and doesn't require any out of tree patches or post processing complexity.Thanks,
Joel
Quoted 8 lines · Joel Fernandes
Quoted 4 lines · Thomas Gleixner
What's wrong with adding a tracepoint into the boot offset update function and let perf or the tracer inject the value of the boot offset into the trace data when starting. The time adjustment can be done in postprocessing.
I agree we're bloating this and probably not very acceptable. tracepoint adds additional complexity and out of tree patches which
Why are tracepoints a problem and adding complexity? Also why would they cause out of tree patches?
Quoted 4 lines
we'd like to avoid. Would you be Ok if we added a relatively simple function like below that could do the job and not bloat the optimal case?
Quoted 8 lines
/*
* Fast and NMI safe access to boot time. It may be slightly out of date
* as we're accessing offset without seqcount writes, but is safe to access. */
u64ktime_get_boot_fast_ns(void){ struct timekeeper *tk = &tk_core.timekeeper; return __ktime_get_fast_ns(&tk_fast_mono) + tk->offs_boot;
This needs a big fat comment and documentation of the possible side effects of this:
1) The timestamp might be off due:
CPU 0 CPU 1
timekeeping_inject_sleeptime64()
__timekeeping_inject_sleeptime(tk, delta); timestamp();
timekeeping_update(tk, TK_CLEAR_NTP...);
2) On 32bit machines the timestamp might see a half updated boot offset value. On 64bit machines it either sees the old or the new value.
I don't think this is a big issue, because the event of updating boot offset is really, really rare, so postprocessing should be able to handle this. But at least it must be documented so people wont get surprised.
Quoted 7 lines
Quoted 3 lines
That should be sufficient for tracing suspend/resume behaviour. If there is not a really convincing reason for having that as a real trace clock then I prefer to avoid that extra stuff.
Several clocks are accessible just by simple writing of clock name to
trace_clockin debugfs. This is really cool and doesn't require any out of tree patches or post processing complexity.
I know that it's nice to have :)
Thanks,
tglx