perf: add two new features
Subsystems (2)
Adrian Hunter
reviewercover perf: add two new features
Hi
Please consider these two new perf features:
x86: add ability to calculate TSC from perf sample timestamps
perf: add 'keep tracking' flag to PERF_EVENT_IOC_DISABLE
This is also a minor fix:
perf: fix broken union in perf_event_mmap_page
And tests in perf tools:
perf tools: add test for converting perf time to/from TSC perf tools: add 'keep tracking' test
Adrian Hunter (5):
perf: fix broken union in perf_event_mmap_page
x86: add ability to calculate TSC from perf sample timestamps perf tools: add test for converting perf time to/from TSC
perf: add 'keep tracking' flag to PERF_EVENT_IOC_DISABLE perf tools: add 'keep tracking' test
arch/x86/include/asm/tsc.h | 1 + arch/x86/kernel/cpu/perf_event.c | 6 ++ arch/x86/kernel/tsc.c | 6 ++ include/linux/perf_event.h | 1 + include/uapi/linux/perf_event.h | 29 +++++- kernel/events/core.c | 21 ++++- tools/perf/Makefile | 4 + tools/perf/arch/x86/Makefile | 2 + tools/perf/arch/x86/util/tsc.c | 59 ++++++++++++ tools/perf/arch/x86/util/tsc.h | 20 ++++ tools/perf/tests/builtin-test.c | 10 ++ tools/perf/tests/keep-tracking.c | 168 ++++++++++++++++++++++++++++++++++ tools/perf/tests/perf-time-to-tsc.c | 177 ++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 2 + tools/perf/util/evlist.c | 32 +++++++ tools/perf/util/evlist.h | 5 + 16 files changed, 537 insertions(+), 6 deletions(-) create mode 100644 tools/perf/arch/x86/util/tsc.c create mode 100644 tools/perf/arch/x86/util/tsc.h create mode 100644 tools/perf/tests/keep-tracking.c create mode 100644 tools/perf/tests/perf-time-to-tsc.c
Regards
Adrian
Adrian Hunter
reviewerPATCH 1/5 perf: fix broken union in perf_event_mmap_page
The capabilities bits must not be "union'ed" together. Put them in a separate struct.
--- include/uapi/linux/perf_event.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
include/uapi/linux/perf_event.h +5 -3
@@ -375,9 +375,11 @@ struct perf_event_mmap_page {__u64 time_running;/* time event on cpu */ union {__u64 capabilities; -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_____res :62 ; +struct { +__u64 cap_usr_time :1 , + cap_usr_rdpmc :1 , + cap_____res :62 ; + }; };/*
Signature · 1 line
1.7.11.7
Peter Zijlstra
maintainerRe: [PATCH 1/5] perf: fix broken union in perf_event_mmap_page
Quoted 15 lines · Adrian Hunter
The capabilities bits must not be "union'ed" together. Put them in a separate struct.
Signed-off-by Adrian Hunter <[email protected]>--- include/uapi/linux/perf_event.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)include/uapi/linux/perf_event.h +0
-0@@ -375,9 +375,11 @@ struct perf_event_mmap_page {__u64 time_running;/* time event on cpu */ union {
include/uapi/linux/perf_event.h struct perf_event_mmap_page { · line 383
Quoted 10 lines
include/uapi/linux/perf_event.h +5
-3__u64 capabilities; - __u64 cap_usr_time : 1, - cap_usr_rdpmc : 1, - cap_____res : 62; +struct { +__u64 cap_usr_time :1 , + cap_usr_rdpmc :1 , + cap_____res :62 ; + }; };
Ick, it did that!? and here I thought there was a difference between:
int foo:1,
bar:1;
and
int foo:1;
int bar:1;
That made all the difference in this particular case. I guess I should go read the language spec more carefully next time.
H. Peter Anvin
reviewerRe: [PATCH 1/5] perf: fix broken union in perf_event_mmap_page
Quoted 6 lines · Peter Zijlstra
Ick, it did that!? and here I thought there was a difference between:
int foo:1,
bar:1;
Quoted 8 lines
and
int foo:1;
int bar:1;That made all the difference in this particular case. I guess I should go read the language spec more carefully next time.
There is absolutely no difference there...
-hpa
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
In reply to Adrian Hunterperf: Fix broken union in 'struct perf_event_mmap_page'
Commit-ID: 860f085b74e9f0075de8140ed3a1e5b5e3e39aa8 Gitweb: http://git.kernel.org/tip/860f085b74e9f0075de8140ed3a1e5b5e3e39aa8 Author: Adrian Hunter <[email protected]> AuthorDate: Fri, 28 Jun 2013 16:22:17 +0300 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 23 Jul 2013 12:17:10 +0200
perf: Fix broken union in 'struct perf_event_mmap_page'
The capabilities bits must not be "union'ed" together. Put them in a separate struct.
--- include/uapi/linux/perf_event.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
include/uapi/linux/perf_event.h +5 -3
@@ -375,9 +375,11 @@ struct perf_event_mmap_page {__u64 time_running;/* time event on cpu */ union {__u64 capabilities; -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_____res :62 ; +struct { +__u64 cap_usr_time :1 , + cap_usr_rdpmc :1 , + cap_____res :62 ; + }; };/*
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
This patch somehow breaks the perf-ABI.
If I take a program that reads "mmap->cap_usr_rdpmc" and compile it against the new header with this change (say from 3.12-rc1) and then run it on an old kernel (say 3.11) then I get "0" for cap_usr_rdpmc.
If I take the same program and recompile against the old (without this patch) header and run it on 3.11, I get the expected "1" value.
So something about this changed the bit pattern in an incompatible fashion.
Vince
Quoted 40 lines · tip-bot for Adrian Hunter
Commit-ID: 860f085b74e9f0075de8140ed3a1e5b5e3e39aa8 Gitweb: http://git.kernel.org/tip/860f085b74e9f0075de8140ed3a1e5b5e3e39aa8 Author: Adrian Hunter <[email protected]> AuthorDate: Fri, 28 Jun 2013 16:22:17 +0300 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 23 Jul 2013 12:17:10 +0200perf: Fix broken union in 'struct
perf_event_mmap_page'The capabilities bits must not be "union'ed" together. Put them in a separate struct.
Signed-off-by Adrian Hunter <[email protected]>Signed-off-by Peter Zijlstra <[email protected]>Signed-off-by Ingo Molnar <[email protected]>--- include/uapi/linux/perf_event.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)include/uapi/linux/perf_event.h +5
-4@@ -375,9 +375,11 @@ struct perf_event_mmap_page {__u64 time_running;/* time event on cpu */ union {__u64 capabilities; -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_____res :62 ; +struct { +__u64 cap_usr_time :1 , + cap_usr_rdpmc :1 , + cap_____res :62 ; + }; };/* --
Quoted 5 lines
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
k
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 10 lines · Vince Weaver
This patch somehow breaks the perf-ABI.
If I take a program that reads "
mmap->cap_usr_rdpmc" and compile it against the new header with this change (say from 3.12-rc1) and then run it on an old kernel (say 3.11) then I get "0" forcap_usr_rdpmc.If I take the same program and recompile against the old (without this patch) header and run it on 3.11, I get the expected "1" value.
To follow up, the original case:
union {
__u64 capabilities;
__u64 cap_usr_time : 1,
cap_usr_rdpmc : 1,
cap_____res : 62;
};
Then mmap->usr_rdpmc=1; gets assembled as
400420: 80 0d 11 05 20 00 02 orb $0x2,0x200511(%rip) The new version
union {
__u64 capabilities;
struct {
__u64 cap_usr_time : 1,
cap_usr_rdpmc : 1,
cap_usr_time_zero : 1,
cap_____res : 61;
};
};
mmap->usr_rdpmc=1; gets assembled as
400427: 80 0d 02 05 20 00 01 orb $0x1,0x200502(%rip) note the difference in the or value.
Vince
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 15 lines · Vince Weaver
Quoted 10 lines · Vince Weaver
This patch somehow breaks the perf-ABI.
If I take a program that reads "
mmap->cap_usr_rdpmc" and compile it against the new header with this change (say from 3.12-rc1) and then run it on an old kernel (say 3.11) then I get "0" forcap_usr_rdpmc.If I take the same program and recompile against the old (without this patch) header and run it on 3.11, I get the expected "1" value.
To follow up, the original case:
Quoted 10 lines
union {
__u64 capabilities;
__u64 cap_usr_time : 1,
cap_usr_rdpmc : 1,
cap_____res : 62;
};
Then mmap->usr_rdpmc=1; gets assembled as
400420: 80 0d 11 05 20 00 02 orb $0x2,0x200511(%rip) Hm, how can it be 0x2? Didn't you mix up the two assemblies accidentally?
Quoted 18 lines
The new version
union { __u64 capabilities; struct { __u64 cap_usr_time : 1, cap_usr_rdpmc : 1, cap_usr_time_zero : 1, cap_____res : 61; }; }; mmap->usr_rdpmc=1; gets assembled as 400427: 80 0d 02 05 20 00 01 orb $0x1,0x200502(%rip)
Quoted 1 line
note the difference in the or value.
Here the value should be 0x2, as cap_usr_rdpmc move to the second bit.
Right?
Ingo
Peter Zijlstra
maintainerRe: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
In reply to Vince WeaverQuoted 14 lines · Vince Weaver
Quoted 14 lines
include/uapi/linux/perf_event.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)include/uapi/linux/perf_event.h +0
-3@@ -375,9 +375,11 @@ struct perf_event_mmap_page {__u64 time_running;/* time event on cpu */ union {__u64 capabilities; -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_____res :62 ;
Quoted 8 lines
include/uapi/linux/perf_event.h struct perf_event_mmap_page { · line 383
Quoted 6 lines
include/uapi/linux/perf_event.h +5
-0+struct { +__u64 cap_usr_time :1 , + cap_usr_rdpmc :1 , + cap_____res :62 ; + }; };This patch somehow breaks the perf-ABI.
Difficult call that..
Quoted 10 lines
If I take a program that reads "
mmap->cap_usr_rdpmc" and compile it against the new header with this change (say from 3.12-rc1) and then run it on an old kernel (say 3.11) then I get "0" forcap_usr_rdpmc.If I take the same program and recompile against the old (without this patch) header and run it on 3.11, I get the expected "1" value.
So something about this changed the bit pattern in an incompatible fashion.
Which was the entire point of the change. Previously cap_usr_time and cap_usr_rdpmc were the same bit which clearly cannot be right.
With the change they're consecutive bits in the capabilities word.
Should we preserve completely broken things that don't work?
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 3 lines · Peter Zijlstra
Quoted 1 line
This patch somehow breaks the perf-ABI.
Difficult call that..
OK, let me rephrase.
This change broke existing working code.
Can you point to any code that is fixed by the commit?
If not, I think the rule is you revert the changeset.
Or you can just mark the bug "Won't fix, perf tool doesn't use it" I guess
You guys told me to start running my tests in -rc1 so I can catch bugs early enough to fix things. So here I am, finding a problem in -rc1. If no one cares I'll stop bothering and go back to just documenting the problems after the fact in complaining webpages.
Vince
Peter Zijlstra
maintainerRe: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 1 line · Vince Weaver
Can you point to any code that is fixed by the commit?
I have some, but I don't think a lot of people use it.
Would you be ok with something like the below? It should preserve functionality for code that only cares about cap_usr_rdpmc (PAPI).
Stephane, does libpfm use any of these?
include/uapi/linux/perf_event.h +2 -2
@@ -380,8 +380,8 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , +__u64 cap_usr_rdpmc :1 , + cap_usr_time :1 , cap_usr_time_zero :1 , cap_____res :61 ; };
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 10 lines · Peter Zijlstra
Quoted 1 line · Vince Weaver
Can you point to any code that is fixed by the commit?
I have some, but I don't think a lot of people use it.
Would you be ok with something like the below? It should preserve functionality for code that only cares about
cap_usr_rdpmc(PAPI).Stephane, does libpfm use any of these?
Yes, there is an example using this. Need to verify it is not broken currently (self_count.c).
Quoted 13 lines
include/uapi/linux/perf_event.h +2
-2@@ -380,8 +380,8 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , +__u64 cap_usr_rdpmc :1 , + cap_usr_time :1 , cap_usr_time_zero :1 , cap_____res :61 ; };
Peter Zijlstra
maintainerRe: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 6 lines · Stephane Eranian
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Vince Weaver
Can you point to any code that is fixed by the commit?
I have some, but I don't think a lot of people use it.
Quoted 7 lines
Quoted 5 lines
Would you be ok with something like the below? It should preserve functionality for code that only cares about
cap_usr_rdpmc(PAPI).Stephane, does libpfm use any of these?
Yes, there is an example using this. Need to verify it is not broken currently (
self_count.c).
So if that only uses cap_usr_rdpmc, you have the same issue as Vince and the proposed solutions would work for you too.
If you also use cap_usr_time we've a bit of a problem.
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 12 lines · Peter Zijlstra
Quoted 11 lines · Stephane Eranian
Quoted 10 lines · Peter Zijlstra
Quoted 1 line · Vince Weaver
Can you point to any code that is fixed by the commit?
I have some, but I don't think a lot of people use it.
Would you be ok with something like the below? It should preserve functionality for code that only cares about
cap_usr_rdpmc(PAPI).Stephane, does libpfm use any of these?
Quoted 7 lines
Quoted 2 lines
Yes, there is an example using this. Need to verify it is not broken currently (
self_count.c).So if that only uses
cap_usr_rdpmc, you have the same issue as Vince and the proposed solutions would work for you too.If you also use
cap_usr_timewe've a bit of a problem.
I need to look at this program again, was written a long time ago. It does not use cap_usr_rdpmc nor cap_use_time for sure. So which one(s) are okay to use?
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 16 lines · Stephane Eranian
Quoted 15 lines · Peter Zijlstra
Quoted 13 lines · Stephane Eranian
Quoted 10 lines · Peter Zijlstra
Quoted 1 line · Vince Weaver
Can you point to any code that is fixed by the commit?
I have some, but I don't think a lot of people use it.
Would you be ok with something like the below? It should preserve functionality for code that only cares about
cap_usr_rdpmc(PAPI).Stephane, does libpfm use any of these?
Yes, there is an example using this. Need to verify it is not broken currently (
self_count.c).
Quoted 7 lines
Quoted 4 lines
So if that only uses
cap_usr_rdpmc, you have the same issue as Vince and the proposed solutions would work for you too.If you also use
cap_usr_timewe've a bit of a problem.I need to look at this program again, was written a long time ago. It does not use
cap_usr_rdpmcnorcap_use_timefor sure.
If it does not use either flag (which in released kernels is really a single flag ABI-wise) then it should be fine.
Thanks,
Ingo
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
In reply to Peter ZijlstraQuoted 14 lines · Peter Zijlstra
Quoted 1 line · Vince Weaver
Can you point to any code that is fixed by the commit?
I have some, but I don't think a lot of people use it.
Would you be ok with something like the below? It should preserve functionality for code that only cares about
cap_usr_rdpmc(PAPI).Stephane, does libpfm use any of these?
include/uapi/linux/perf_event.h struct perf_event_mmap_page { · line 387
Quoted 10 lines
include/uapi/linux/perf_event.h +2
-2@@ -380,8 +380,8 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , +__u64 cap_usr_rdpmc :1 , + cap_usr_time :1 , cap_usr_time_zero :1 , cap_____res :61 ; };
It would be nice if there was some way to detect this change; I liked the idea of a "cap_usr_fixed" bit.
Even with your change you can't have code that can reliably detect both cap_usr_time and cap_usr_rdpmc unless you can guarantee that both perf_event.h and the kernel are 3.12 or newer, and it gets more complicated if distros backport this patch.
Tools like PAPI often carry around their own copy of perf_event.h and people like to move around binaries between machines with different kernel versions so things get complicated quickly.
Vince
Peter Zijlstra
maintainerRe: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 2 lines · Vince Weaver
It would be nice if there was some way to detect this change; I liked the idea of a "
cap_usr_fixed" bit.
How about we start using the version field for this? Arguably we should have incremented that value every time we changed the thing but we might as well start now.
---
kernel/events/core.c +20 -0
@@ -3660,6 +3660,25 @@ static void calc_timer_values(struct perf_event *event, *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; + +rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + + userpg->version =1 ; + userpg->compat_version =0 ; + +unlock: +rcu_read_unlock (); +} +void __weak arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { }
@@ -4044,6 +4063,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)ring_buffer_attach (event, rb);rcu_assign_pointer (event->rb, rb); +perf_event_init_userpage (event);perf_event_update_userpage (event); unlock:
PATCH 1/1 perf: Always set bit 0 in the capabilities field of 'struct perf_event_mmap_page' to 0, to maintain the ABI
Quoted 8 lines · Peter Zijlstra
Quoted 2 lines · Vince Weaver
It would be nice if there was some way to detect this change; I liked the idea of a "
cap_usr_fixed" bit.How about we start using the version field for this? Arguably we should have incremented that value every time we changed the thing but we might as well start now.
But version fields are really fragile, the way we usually iterate ABIs is a self-maintaining size field - which is missing here.
So I think the best solution would be to make it all explicit and self-contained:
- always clear bit 0, and rename it to usrpage->cap_bit0, to at least not confuse old user-space binaries. RDPMC will be marked as unavailable to old binaries but that's within the ABI.
- rename bit 1 to ->cap_bit0_is_deprecated and always set it to 1, so new libraries can reliably detect that bit 0 is deprecated and perma-zero without having to check the kernel version.
- use bits 2, 3, 4 for the newly defined, correct functionality.
- rename all the bitfield names in perf_event.h to be different from the old names, to make sure it's not possible to mis-compile it accidentally with old assumptions.
I.e. something like the patch below. (untested)
The 'size' field can then be used in the future to add new fields and it will act as a natural ABI version indicator as well.
Thanks,
Ingo
arch/x86/kernel/cpu/perf_event.c +5 -5
@@ -1883,9 +1883,9 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { - userpg->cap_usr_time =0 ; - userpg->cap_usr_time_zero =0 ; - userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; + userpg->cap_usr_time_used =0 ; + userpg->cap_usr_time_zero_used =0 ; + userpg->cap_usr_rdpmc_available = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;if (!boot_cpu_has (X86_FEATURE_CONSTANT_TSC ))
@@ -1894,13 +1894,13 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)if (!boot_cpu_has (X86_FEATURE_NONSTOP_TSC ))return ; - userpg->cap_usr_time =1 ; + userpg->cap_usr_time_used =1 ; userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now;if (sched_clock_stable && !check_tsc_disabled ()) { - userpg->cap_usr_time_zero =1 ; + userpg->cap_usr_time_zero_used =1 ; userpg->time_zero =this_cpu_read (cyc2ns_offset); } }
include/uapi/linux/perf_event.h +10 -5
@@ -380,10 +380,13 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_usr_time_zero :1 , - cap_____res :61 ; +__u64 cap_bit0 :1 ,/* Deprecated, always zero, see commit 860f085b74e9 */ + cap_bit0_is_deprecated :1 ,/* Always 1, signals that bit 0 is zero */ + + cap_usr_rdpmc_available :1 ,/* The RDPMC instruction can be used to read counts */ + cap_usr_time_used :1 ,/* The time_* fields are uses */ + cap_usr_time_zero_used :1 ,/* The time_zero field is used */ + cap_____res :59 ; }; };
@@ -442,12 +445,14 @@ struct perf_event_mmap_page {* ((rem * time_mult) >> time_shift); */ __u64 time_zero; +__u32 size;/* Header size up to this point */ +__u32 __reserved0;/* 4 byte hole */ /* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[119 ];/* align to 1k */ +__u64 __reserved[118 ];/* align to 1k */ /* * Control data for the mmap() data buffer.
kernel/events/core.c +21 -0
@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct perf_event *event, *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; + +rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + +/* Allow new userspace to detect that bit 0 is deprecated */ + userpg->cap_bit0_is_deprecated =1 ; + userpg->size = offsetof(struct perf_event_mmap_page , size); + +unlock: +rcu_read_unlock (); +} +void __weak arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { }
@@ -4044,6 +4064,7 @@ again:ring_buffer_attach (event, rb);rcu_assign_pointer (event->rb, rb); +perf_event_init_userpage (event);perf_event_update_userpage (event); unlock:
Peter Zijlstra
maintainerRe: [PATCH] perf: Always set bit 0 in the capabilities field of 'struct perf_event_mmap_page' to 0, to maintain the ABI
Quoted 29 lines · Ingo Molnar
include/uapi/linux/perf_event.h +3
-1@@ -442,12 +445,14 @@ struct perf_event_mmap_page {* ((rem * time_mult) >> time_shift); */ __u64 time_zero; +__u32 size;/* Header size up to this point */ +__u32 __reserved0;/* 4 byte hole */ /* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[119 ];/* align to 1k */ +__u64 __reserved[118 ];/* align to 1k */ /* * Control data for the mmap() data buffer. kernel/events/core.c +5
-0@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct perf_event *event, *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; +
kernel/events/core.c static void calc_timer_values(struct perf_event *event, · line 3677
Quoted 10 lines
kernel/events/core.c +10
-0+rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + +/* Allow new userspace to detect that bit 0 is deprecated */ + userpg->cap_bit0_is_deprecated =1 ; + userpg->size = offsetof(struct perf_event_mmap_page , size);
This is fragile and I'm 100% sure we'll forget to update it.
userpg->size = offsetof(struct perf_event_mmap_page, __reserved);
Will auto update and mostly do the right thing.
Also, how will userspace know there's a valid size field way out there? Shouldn't we bump the version field to indicate so? :-) After all, running on old userspace this field will be 0.
Quoted 4 lines
kernel/events/core.c +4
-0+ +unlock: +rcu_read_unlock (); +}
Re: [PATCH] perf: Always set bit 0 in the capabilities field of 'struct perf_event_mmap_page' to 0, to maintain the ABI
Quoted 43 lines · Peter Zijlstra
Quoted 29 lines · Ingo Molnar
(quoted diff) +3
-1@@ -442,12 +445,14 @@ struct perf_event_mmap_page { * ((rem * time_mult) >> time_shift); */ __u64 time_zero; + __u32 size; /* Header size up to this point */ + __u32 __reserved0; /* 4 byte hole */ /* * Hole for extension of the self monitor capabilities */ - __u64 __reserved[119]; /* align to 1k */ + __u64 __reserved[118]; /* align to 1k */ /* * Control data for the mmap() data buffer.kernel/events/core.c +5
-0@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct perf_event *event, *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; +kernel/events/core.c static void calc_timer_values(struct perf_event *event, · line 3677
Quoted 10 lines
kernel/events/core.c +10
-0+rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + +/* Allow new userspace to detect that bit 0 is deprecated */ + userpg->cap_bit0_is_deprecated =1 ; + userpg->size = offsetof(struct perf_event_mmap_page , size);This is fragile and I'm 100% sure we'll forget to update it.
Quoted 3 lines
userpg->size = offsetof(struct perf_event_mmap_page, __reserved);Will auto update and mostly do the right thing.
Ah, yes, agreed 100% - that was my intention, just implemented it badly.
One detail: I think we want to track size with u8 granularity, to be able to detect when a new u32 (or u16) field gets added, right? Updated patch attached below.
Note that this way of writing the array size:
+ __u8 __reserved[118*8+4]; /* align to 1k. */
Makes it sure that we are aware of the current word alignment situation and makes it harder to break alignment in the future.
Quoted 1 line
Also, how will userspace know there's a valid size field way out there?
The current value of the size field on old kernels is 0 so it easily detected by being nonzero.
Quoted 2 lines
Shouldn't we bump the version field to indicate so? :-) After all, running on old userspace this field will be 0.
Well, on old kernel this will be 0, right?
Thanks,
Ingo
arch/x86/kernel/cpu/perf_event.c +5 -5
@@ -1883,9 +1883,9 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { - userpg->cap_usr_time =0 ; - userpg->cap_usr_time_zero =0 ; - userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; + userpg->cap_usr_time_used =0 ; + userpg->cap_usr_time_zero_used =0 ; + userpg->cap_usr_rdpmc_available = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;if (!boot_cpu_has (X86_FEATURE_CONSTANT_TSC ))
@@ -1894,13 +1894,13 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)if (!boot_cpu_has (X86_FEATURE_NONSTOP_TSC ))return ; - userpg->cap_usr_time =1 ; + userpg->cap_usr_time_used =1 ; userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now;if (sched_clock_stable && !check_tsc_disabled ()) { - userpg->cap_usr_time_zero =1 ; + userpg->cap_usr_time_zero_used =1 ; userpg->time_zero =this_cpu_read (cyc2ns_offset); } }
include/uapi/linux/perf_event.h +9 -5
@@ -380,10 +380,13 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_usr_time_zero :1 , - cap_____res :61 ; +__u64 cap_bit0 :1 ,/* Deprecated, always zero, see commit 860f085b74e9 */ + cap_bit0_is_deprecated :1 ,/* Always 1, signals that bit 0 is zero */ + + cap_usr_rdpmc_available :1 ,/* The RDPMC instruction can be used to read counts */ + cap_usr_time_used :1 ,/* The time_* fields are uses */ + cap_usr_time_zero_used :1 ,/* The time_zero field is used */ + cap_____res :59 ; }; };
@@ -442,12 +445,13 @@ struct perf_event_mmap_page {* ((rem * time_mult) >> time_shift); */ __u64 time_zero; +__u32 size;/* Header size up to __reserved[] fields. */ /* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[119 ];/* align to 1k */ +__u8 __reserved[118 *8 +4 ];/* align to 1k. */ /* * Control data for the mmap() data buffer.
kernel/events/core.c +21 -0
@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct perf_event *event, *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; + +rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + +/* Allow new userspace to detect that bit 0 is deprecated */ + userpg->cap_bit0_is_deprecated =1 ; + userpg->size = offsetof(struct perf_event_mmap_page , __reserved); + +unlock: +rcu_read_unlock (); +} +void __weak arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { }
@@ -4044,6 +4064,7 @@ again:ring_buffer_attach (event, rb);rcu_assign_pointer (event->rb, rb); +perf_event_init_userpage (event);perf_event_update_userpage (event); unlock:
Peter Zijlstra
maintainerRe: [PATCH] perf: Always set bit 0 in the capabilities field of 'struct perf_event_mmap_page' to 0, to maintain the ABI
On Thu, Sep 19, 2013 at 12:28:18PM +0200, Ingo Molnar wrote:
You really don't like version fields do you ;-)
Quoted 44 lines
arch/x86/kernel/cpu/perf_event.c +5
-5@@ -1883,9 +1883,9 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { - userpg->cap_usr_time =0 ; - userpg->cap_usr_time_zero =0 ; - userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; + userpg->cap_usr_time_used =0 ; + userpg->cap_usr_time_zero_used =0 ; + userpg->cap_usr_rdpmc_available = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;if (!boot_cpu_has (X86_FEATURE_CONSTANT_TSC ))@@ -1894,13 +1894,13 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)if (!boot_cpu_has (X86_FEATURE_NONSTOP_TSC ))return ; - userpg->cap_usr_time =1 ; + userpg->cap_usr_time_used =1 ; userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now;if (sched_clock_stable && !check_tsc_disabled ()) { - userpg->cap_usr_time_zero =1 ; + userpg->cap_usr_time_zero_used =1 ; userpg->time_zero =this_cpu_read (cyc2ns_offset); } }include/uapi/linux/perf_event.h +0
-3@@ -380,10 +380,13 @@ struct perf_event_mmap_page { union { __u64 capabilities; struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_usr_time_zero : 1,
include/uapi/linux/perf_event.h struct perf_event_mmap_page { · line 391
Quoted 10 lines
include/uapi/linux/perf_event.h +7
-1- cap_____res :61 ; + __u64 cap_bit0 : 1, /* Deprecated, always zero, see commit 860f085b74e9 */ + cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */ + + cap_usr_rdpmc_available : 1, /* The RDPMC instruction can be used to read counts */ + cap_usr_time_used : 1, /* The time_* fields are uses */ + cap_usr_time_zero_used : 1, /* The time_zero field is used */ + cap_____res : 59; }; };
Would it make sense to do something like s/cap_usr/cap_user/ and drop the _available, _used postfixes? It results in different names but avoids these terribly long ones.
PATCH v3 1/1 perf: Always set bit 0 in the capabilities field of 'struct perf_event_mmap_page' to 0, to maintain the ABI
Quoted 3 lines · Peter Zijlstra
On Thu, Sep 19, 2013 at 12:28:18PM +0200, Ingo Molnar wrote:
You really don't like version fields do you ;-)
Indeed they are a horrible concept.
Quoted 3 lines
Would it make sense to do something like s/cap_usr/cap_user/ and drop the
_available,_usedpostfixes? It results in different names but avoids these terribly long ones.
Absolutely! Find updated patch below.
Thanks,
Ingo
arch/x86/kernel/cpu/perf_event.c +5 -5
@@ -1883,9 +1883,9 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { - userpg->cap_usr_time =0 ; - userpg->cap_usr_time_zero =0 ; - userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; + userpg->cap_user_time =0 ; + userpg->cap_user_time_zero =0 ; + userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;if (!boot_cpu_has (X86_FEATURE_CONSTANT_TSC ))
@@ -1894,13 +1894,13 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)if (!boot_cpu_has (X86_FEATURE_NONSTOP_TSC ))return ; - userpg->cap_usr_time =1 ; + userpg->cap_user_time =1 ; userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now;if (sched_clock_stable && !check_tsc_disabled ()) { - userpg->cap_usr_time_zero =1 ; + userpg->cap_user_time_zero =1 ; userpg->time_zero =this_cpu_read (cyc2ns_offset); } }
include/uapi/linux/perf_event.h +9 -5
@@ -380,10 +380,13 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_usr_time_zero :1 , - cap_____res :61 ; +__u64 cap_bit0 :1 ,/* Always 0, deprecated, see commit 860f085b74e9 */ + cap_bit0_is_deprecated :1 ,/* Always 1, signals that bit 0 is zero */ + + cap_user_rdpmc :1 ,/* The RDPMC instruction can be used to read counts */ + cap_user_time :1 ,/* The time_* fields are used */ + cap_user_time_zero :1 ,/* The time_zero field is used */ + cap_____res :59 ; }; };
@@ -442,12 +445,13 @@ struct perf_event_mmap_page {* ((rem * time_mult) >> time_shift); */ __u64 time_zero; +__u32 size;/* Header size up to __reserved[] fields. */ /* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[119 ];/* align to 1k */ +__u8 __reserved[118 *8 +4 ];/* align to 1k. */ /* * Control data for the mmap() data buffer.
kernel/events/core.c +21 -0
@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct perf_event *event, *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; + +rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + +/* Allow new userspace to detect that bit 0 is deprecated */ + userpg->cap_bit0_is_deprecated =1 ; + userpg->size = offsetof(struct perf_event_mmap_page , __reserved); + +unlock: +rcu_read_unlock (); +} +void __weak arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { }
@@ -4044,6 +4064,7 @@ again:ring_buffer_attach (event, rb);rcu_assign_pointer (event->rb, rb); +perf_event_init_userpage (event);perf_event_update_userpage (event); unlock:
Adrian Hunter
reviewerRe: [PATCH, v3] perf: Always set bit 0 in the capabilities field of 'struct perf_event_mmap_page' to 0, to maintain the ABI
Quoted 123 lines · Ingo Molnar
Quoted 3 lines · Peter Zijlstra
On Thu, Sep 19, 2013 at 12:28:18PM +0200, Ingo Molnar wrote:
You really don't like version fields do you ;-)
Indeed they are a horrible concept.
Quoted 3 lines
Would it make sense to do something like s/cap_usr/cap_user/ and drop the
_available,_usedpostfixes? It results in different names but avoids these terribly long ones.Absolutely! Find updated patch below.
Thanks,
Ingo
arch/x86/kernel/cpu/perf_event.c +5
-5@@ -1883,9 +1883,9 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { - userpg->cap_usr_time =0 ; - userpg->cap_usr_time_zero =0 ; - userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; + userpg->cap_user_time =0 ; + userpg->cap_user_time_zero =0 ; + userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;if (!boot_cpu_has (X86_FEATURE_CONSTANT_TSC ))@@ -1894,13 +1894,13 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)if (!boot_cpu_has (X86_FEATURE_NONSTOP_TSC ))return ; - userpg->cap_usr_time =1 ; + userpg->cap_user_time =1 ; userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now;if (sched_clock_stable && !check_tsc_disabled ()) { - userpg->cap_usr_time_zero =1 ; + userpg->cap_user_time_zero =1 ; userpg->time_zero =this_cpu_read (cyc2ns_offset); } }include/uapi/linux/perf_event.h +9
-5@@ -380,10 +380,13 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_usr_time_zero :1 , - cap_____res :61 ; +__u64 cap_bit0 :1 ,/* Always 0, deprecated, see commit 860f085b74e9 */ + cap_bit0_is_deprecated :1 ,/* Always 1, signals that bit 0 is zero */ + + cap_user_rdpmc :1 ,/* The RDPMC instruction can be used to read counts */ + cap_user_time :1 ,/* The time_* fields are used */ + cap_user_time_zero :1 ,/* The time_zero field is used */ + cap_____res :59 ; }; };@@ -442,12 +445,13 @@ struct perf_event_mmap_page {* ((rem * time_mult) >> time_shift); */ __u64 time_zero; +__u32 size;/* Header size up to __reserved[] fields. */ /* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[119 ];/* align to 1k */ +__u8 __reserved[118 *8 +4 ];/* align to 1k. */ /* * Control data for the mmap() data buffer. kernel/events/core.c +20
-0@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct perf_event *event, *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; + +rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + +/* Allow new userspace to detect that bit 0 is deprecated */ + userpg->cap_bit0_is_deprecated =1 ; + userpg->size = offsetof(struct perf_event_mmap_page , __reserved); + +unlock: +rcu_read_unlock (); +} +void __weak arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { }
kernel/events/core.c again: · line 4070
Quoted 7 lines
kernel/events/core.c +1
-0@@ -4044,6 +4064,7 @@ again:ring_buffer_attach (event, rb);rcu_assign_pointer (event->rb, rb); +perf_event_init_userpage (event);perf_event_update_userpage (event); unlock:
Please consider adding:
tools/perf/arch/x86/util/tsc.c +1 -1
@@ -32,7 +32,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc) { -bool cap_usr_time_zero; +bool cap_user_time_zero;u32 seq;int i =0 ;
@@ -42,7 +42,7 @@ int perf_read_tsc_conversion(const struct
perf_event_mmap_page *pc,
tc->time_mult = pc->time_mult; tc->time_shift = pc->time_shift; tc->time_zero = pc->time_zero;
- cap_usr_time_zero = pc->cap_usr_time_zero;
+ cap_user_time_zero = pc->cap_user_time_zero;
rmb();
if (pc->lock == seq && !(seq & 1))
break;
@@ -52,7 +52,7 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
}
}
- if (!cap_usr_time_zero)
+ if (!cap_user_time_zero)
return -EOPNOTSUPP;
return 0;
PATCH v4 1/1 perf: Fix capabilities bitfield compatibility in 'struct perf_event_mmap_page'
Quoted 7 lines · Adrian Hunter
Quoted 7 lines
(quoted diff) +2
-4struct { - __u64 cap_usr_time : 1, - cap_usr_rdpmc : 1, - cap_usr_time_zero : 1, - cap_____res : 61; + __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */ + cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
Quoted 8 lines
Review
Quoted 6 lines
(quoted diff) +5
-0+ + cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */ + cap_user_time : 1, /* The time_* fields are used */ + cap_user_time_zero : 1, /* The time_zero field is used */ + cap_____res : 59; };Please consider adding:
indeed - added. I also build-tested it all and added a changelog - see the updated patch below.
Thanks,
Ingo
--------------------->
Subject: perf: Fix capabilities bitfield compatibility in 'struct perf_event_mmap_page'
From: Peter Zijlstra <[email protected]>
Date: Thu, 19 Sep 2013 10:16:42 +0200
Solve the problems around the broken definition of perf_event_mmap_page::cap_usr_time and cap_usr_rdpmc fields which used to overlap, partially fixed by:
860f085b74e9 ("perf: Fix broken union in 'struct perf_event_mmap_page'")
The problem with the fix (merged in v3.12-rc1 and not yet released officially), noticed by Vince Weaver is that the new behavior is not detectable by new user-space, and that due to the reuse of the field names it's easy to mis-compile a binary if old headers are used on a new kernel or new headers are used on an old kernel.
To solve all that make this change explicit, detectable and self-contained, by iterating the ABI the following way:
- Always clear bit 0, and rename it to usrpage->cap_bit0, to at least not confuse old user-space binaries. RDPMC will be marked as unavailable to old binaries but that's within the ABI, this is a capability bit.
- Rename bit 1 to ->cap_bit0_is_deprecated and always set it to 1, so new libraries can reliably detect that bit 0 is deprecated and perma-zero without having to check the kernel version.
- Use bits 2, 3, 4 for the newly defined, correct functionality:
cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
cap_user_time : 1, /* The time_* fields are used */
cap_user_time_zero : 1, /* The time_zero field is used */
- Rename all the bitfield names in perf_event.h to be different from the old names, to make sure it's not possible to mis-compile it accidentally with old assumptions.
The 'size' field can then be used in the future to add new fields and it will act as a natural ABI version indicator as well.
Also adjust tools/perf/ userspace for the new definitions, noticed by Adrian Hunter.
--- arch/x86/kernel/cpu/perf_event.c | 10 +++++----- include/uapi/linux/perf_event.h | 14 +++++++++----- kernel/events/core.c | 21 +++++++++++++++++++++ tools/perf/arch/x86/util/tsc.c | 6 +++--- 4 files changed, 38 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/perf_event.c +5 -5
@@ -1883,9 +1883,9 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { - userpg->cap_usr_time =0 ; - userpg->cap_usr_time_zero =0 ; - userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; + userpg->cap_user_time =0 ; + userpg->cap_user_time_zero =0 ; + userpg->cap_user_rdpmc = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;if (!boot_cpu_has (X86_FEATURE_CONSTANT_TSC ))
@@ -1894,13 +1894,13 @@ void arch_perf_update_userpage(struct peif (!boot_cpu_has (X86_FEATURE_NONSTOP_TSC ))return ; - userpg->cap_usr_time =1 ; + userpg->cap_user_time =1 ; userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now;if (sched_clock_stable && !check_tsc_disabled ()) { - userpg->cap_usr_time_zero =1 ; + userpg->cap_user_time_zero =1 ; userpg->time_zero =this_cpu_read (cyc2ns_offset); } }
include/uapi/linux/perf_event.h +9 -5
@@ -380,10 +380,13 @@ struct perf_event_mmap_page {union {__u64 capabilities;struct { -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_usr_time_zero :1 , - cap_____res :61 ; +__u64 cap_bit0 :1 ,/* Always 0, deprecated, see commit 860f085b74e9 */ + cap_bit0_is_deprecated :1 ,/* Always 1, signals that bit 0 is zero */ + + cap_user_rdpmc :1 ,/* The RDPMC instruction can be used to read counts */ + cap_user_time :1 ,/* The time_* fields are used */ + cap_user_time_zero :1 ,/* The time_zero field is used */ + cap_____res :59 ; }; };
@@ -442,12 +445,13 @@ struct perf_event_mmap_page {* ((rem * time_mult) >> time_shift); */ __u64 time_zero; +__u32 size;/* Header size up to __reserved[] fields. */ /* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[119 ];/* align to 1k */ +__u8 __reserved[118 *8 +4 ];/* align to 1k. */ /* * Control data for the mmap() data buffer.
kernel/events/core.c +21 -0
@@ -3660,6 +3660,26 @@ static void calc_timer_values(struct per *running = ctx_time - event->tstamp_running; } +static void perf_event_init_userpage (struct perf_event *event) +{ +struct perf_event_mmap_page *userpg; +struct ring_buffer *rb; + +rcu_read_lock (); + rb =rcu_dereference (event->rb); +if (!rb) + goto unlock; + + userpg = rb->user_page; + +/* Allow new userspace to detect that bit 0 is deprecated */ + userpg->cap_bit0_is_deprecated =1 ; + userpg->size = offsetof(struct perf_event_mmap_page , __reserved); + +unlock: +rcu_read_unlock (); +} +void __weak arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { }
@@ -4044,6 +4064,7 @@ again:ring_buffer_attach (event, rb);rcu_assign_pointer (event->rb, rb); +perf_event_init_userpage (event);perf_event_update_userpage (event); unlock:
tools/perf/arch/x86/util/tsc.c +3 -3
@@ -32,7 +32,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perint perf_read_tsc_conversion (const struct perf_event_mmap_page *pc,struct perf_tsc_conversion *tc) { -bool cap_usr_time_zero; +bool cap_user_time_zero;u32 seq;int i =0 ;
@@ -42,7 +42,7 @@ int perf_read_tsc_conversion(const struc tc->time_mult = pc->time_mult; tc->time_shift = pc->time_shift; tc->time_zero = pc->time_zero; - cap_usr_time_zero = pc->cap_usr_time_zero; + cap_user_time_zero = pc->cap_user_time_zero;rmb ();if (pc->lock == seq && !(seq &1 ))break ;
@@ -52,7 +52,7 @@ int perf_read_tsc_conversion(const struc } } -if (!cap_usr_time_zero) +if (!cap_user_time_zero)return -EOPNOTSUPP ;return 0 ;
Re: [PATCH, v4] perf: Fix capabilities bitfield compatibility in 'struct perf_event_mmap_page'
Quoted 11 lines · Ingo Molnar
To solve all that make this change explicit, detectable and self-contained, by iterating the ABI the following way:
- Always clear bit 0, and rename it to
usrpage->cap_bit0, to at least not confuse old user-space binaries. RDPMC will be marked as unavailable to old binaries but that's within the ABI, this is a capability bit.- Rename bit 1 to ->cap_bit0_is_deprecated and always set it to 1, so new libraries can reliably detect that bit 0 is deprecated and perma-zero without having to check the kernel version.
Quoted 6 lines
- Use bits 2, 3, 4 for the newly defined, correct functionality:
cap_user_rdpmc: 1, /* The RDPMC instruction can be used to read counts */
cap_user_time: 1, /* The time_* fields are used */
cap_user_time_zero: 1, /* Thetime_zerofield is used */
So let me think through the possible combinations:
OLD-KERNEL OLD-HEADER
+ cap_usr_rdpmc and cap_usr_time map to the same bit
+ In general for kernels from 3.4 to 3.11 the bit will be set for all x86
NEW-KERNEL OLD-HEADER
+ cap_usr_rdpmc (cap_bit0) and cap_usr_time (cap_bit0) both are 0
+ code detecting cap_usr_rdpmc will probably fall back to non-rdpmc even through rdpmc code is probably there and functioning
OLD-KERNEL NEW-HEADER
+ cap_user_rdpmc and cap_user_time both set to 0
+ cap_bit0_is_deprecated can be read; if it is 0 you can read cap_bit0, and if it is 1, assume rdpmc is available with the same likelyhood you could with the old header
NEW-KERNEL NEW-HEADER
+ Use cap_user_rdpmc and cap_user_time and everything is OK
Quoted 3 lines
- Rename all the bitfield names in
perf_event.hto be different from the old names, to make sure it's not possible to mis-compile it accidentally with old assumptions.
Well this breaks that API, though I guess there are no guarantees there. I guess that's intentional since it will force
users to fix their code, but a pain if you aren't expecting it and suddenly your project doesn't compile anymore after a kernel-headers update. Most of my code carries around its own perf_event.h so I guess I'll be unaffected.
In any case this seems to be about as reasonable a solution to this problem as we can get.
Vince
Re: [PATCH, v4] perf: Fix capabilities bitfield compatibility in 'struct perf_event_mmap_page'
Quoted 32 lines · Vince Weaver
Quoted 11 lines · Ingo Molnar
To solve all that make this change explicit, detectable and self-contained, by iterating the ABI the following way:
- Always clear bit 0, and rename it to
usrpage->cap_bit0, to at least not confuse old user-space binaries. RDPMC will be marked as unavailable to old binaries but that's within the ABI, this is a capability bit.- Rename bit 1 to ->cap_bit0_is_deprecated and always set it to 1, so new libraries can reliably detect that bit 0 is deprecated and perma-zero without having to check the kernel version.
Quoted 6 lines
- Use bits 2, 3, 4 for the newly defined, correct functionality:
cap_user_rdpmc: 1, /* The RDPMC instruction can be used to read counts */
cap_user_time: 1, /* The time_* fields are used */
cap_user_time_zero: 1, /* Thetime_zerofield is used */So let me think through the possible combinations:
OLD-KERNEL OLD-HEADER
+cap_usr_rdpmcandcap_usr_timemap to the same bit
+ In general for kernels from 3.4 to 3.11 the bit will be set for all x86NEW-KERNEL OLD-HEADER
+cap_usr_rdpmc(cap_bit0) andcap_usr_time(cap_bit0) both are 0
+ code detectingcap_usr_rdpmcwill probably fall back to non-rdpmc even through rdpmc code is probably there and functioning
Quoted 5 lines
OLD-KERNEL NEW-HEADER
+cap_user_rdpmcandcap_user_timeboth set to 0
+cap_bit0_is_deprecatedcan be read; if it is 0 you can readcap_bit0, and if it is 1, assume rdpmc is available with the same likelyhood you could with the old header
Yes - this is the enabling vector to support old kernels (to the extent it's possible), in newly built libraries - without having to test for some explicit kernel version in the quirk code. (which is really a fragile concept when features/fixes get backported.)
Quoted 2 lines
NEW-KERNEL NEW-HEADER
+ Usecap_user_rdpmcandcap_user_timeand everything is OK
Yes.
Quoted 5 lines
Quoted 3 lines
- Rename all the bitfield names in
perf_event.hto be different from the old names, to make sure it's not possible to mis-compile it accidentally with old assumptions.Well this breaks that API, though I guess there are no guarantees there.
Not just that there are no guarantees, but without the rename old code with new headers could also result in hard to debug "it seems to work but is really broken" code.
Quoted 4 lines
I guess that's intentional since it will force users to fix their code, but a pain if you aren't expecting it and suddenly your project doesn't compile anymore after a kernel-headers update. Most of my code carries around its own
perf_event.hso I guess I'll be unaffected.
I'd expect mainly libraries to ever run into the build failure, not end users.
Quoted 2 lines
In any case this seems to be about as reasonable a solution to this problem as we can get.
Great, thanks for the review!
Ingo
Adrian Hunter
reviewerRe: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
In reply to Vince WeaverQuoted 8 lines · Vince Weaver
This patch somehow breaks the perf-ABI.
If I take a program that reads "
mmap->cap_usr_rdpmc" and compile it against the new header with this change (say from 3.12-rc1) and then run it on an old kernel (say 3.11) then I get "0" forcap_usr_rdpmc.
Quoted 5 lines
If I take the same program and recompile against the old (without this patch) header and run it on 3.11, I get the expected "1" value.
So something about this changed the bit pattern in an incompatible fashion.
cap_usr_time and cap_usr_rdpmc were occupying the same bit position i.e. bit 0
That means that cap_usr_time and cap_usr_rdpmc were both unreliable.
If you look at the logic:
void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
{
userpg->cap_usr_time = 0;
userpg->cap_usr_time_zero = 0;
userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc;
userpg->pmc_width = x86_pmu.cntval_bits;
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
return;
if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
return;
userpg->cap_usr_time = 1;
userpg->time_mult = this_cpu_read(cyc2ns);
userpg->time_shift = CYC2NS_SCALE_FACTOR;
userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
if (sched_clock_stable && !check_tsc_disabled()) {
userpg->cap_usr_time_zero = 1;
userpg->time_zero = this_cpu_read(cyc2ns_offset);
}
}The incorrect union caused 2 bugs:
1. On hardware with constant, non-stop TSC cap_usr_rdpmc was always 1.
2. On hardware without constant, non-stop TSC cap_usr_time was still 1 if rdpmc was allowed in userspace.
Possible improvements are one or both of:
1. Add cap_usr_fixed to identify kernels that have the capabilities bits fixed
2. Swap the positions of cap_usr_time and cap_usr_rdpmc so that cap_usr_rdpmc remains in bit 0
Quoted 56 lines
Vince
Quoted 40 lines · tip-bot for Adrian Hunter
Commit-ID: 860f085b74e9f0075de8140ed3a1e5b5e3e39aa8 Gitweb: http://git.kernel.org/tip/860f085b74e9f0075de8140ed3a1e5b5e3e39aa8 Author: Adrian Hunter <[email protected]> AuthorDate: Fri, 28 Jun 2013 16:22:17 +0300 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 23 Jul 2013 12:17:10 +0200perf: Fix broken union in 'struct
perf_event_mmap_page'The capabilities bits must not be "union'ed" together. Put them in a separate struct.
Signed-off-by Adrian Hunter <[email protected]>Signed-off-by Peter Zijlstra <[email protected]>Signed-off-by Ingo Molnar <[email protected]>--- include/uapi/linux/perf_event.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)include/uapi/linux/perf_event.h +5
-4@@ -375,9 +375,11 @@ struct perf_event_mmap_page {__u64 time_running;/* time event on cpu */ union {__u64 capabilities; -__u64 cap_usr_time :1 , - cap_usr_rdpmc :1 , - cap_____res :62 ; +struct { +__u64 cap_usr_time :1 , + cap_usr_rdpmc :1 , + cap_____res :62 ; + }; };/* -- Quoted 5 lines
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/k
Re: [tip:perf/core] perf: Fix broken union in ' struct perf_event_mmap_page'
Quoted 12 lines · Adrian Hunter
Quoted 11 lines · Vince Weaver
This patch somehow breaks the perf-ABI.
If I take a program that reads "
mmap->cap_usr_rdpmc" and compile it against the new header with this change (say from 3.12-rc1) and then run it on an old kernel (say 3.11) then I get "0" forcap_usr_rdpmc.If I take the same program and recompile against the old (without this patch) header and run it on 3.11, I get the expected "1" value.
Quoted 7 lines
Quoted 2 lines
So something about this changed the bit pattern in an incompatible fashion.
cap_usr_timeandcap_usr_rdpmcwere occupying the same bit position i.e. bit 0That means that
cap_usr_timeandcap_usr_rdpmcwere both unreliable.
well then I have to say this patch wins today's award for "least useful commit message". Why wasn't this important info there?
Quoted 1 line
From what it originally sounded like this was just some shuffling of
low-level C minutia, not a hard-to-resolve break in the perf ABI.
Quoted 4 lines
Possible improvements are one or both of:
1. Addcap_usr_fixedto identify kernels that have the capabilities bits fixed
2. Swap the positions ofcap_usr_timeandcap_usr_rdpmcso thatcap_usr_rdpmcremains in bit 0
Or just create two new fields and mark the old ones as obsolete somehow.
The problem with just making this change silently is now tools like PAPI that care about cap_usr_rdpmc will behave in hard-to-debug ways.
For example, code compiled against new headers but run with old kernels won't detect rdpmc properly
Code compiled against old headers but run with new kernels won't detect rdpmc properly.
It's true existing code could have problems if you ran on a machine with conflicting rdpmc/usr_time, but my tests never noticed that, presumably because rdpmc and usr_time were added at the same time (in 3.4), x86 always enables rdpmc, and none of my code uses usr_time so I never see wrong time results.
Vince
Adrian Hunter
reviewerPATCH 2/5 x86: add ability to calculate TSC from perf sample timestamps
In reply to Adrian HunterFor modern CPUs, perf clock is directly related to TSC. TSC can be calculated from perf clock and vice versa using a simple calculation. Two of the three componenets of that calculation are already exported in struct perf_event_mmap_page. This patch exports the third.
--- arch/x86/include/asm/tsc.h | 1 + arch/x86/kernel/cpu/perf_event.c | 6 ++++++ arch/x86/kernel/tsc.c | 6 ++++++ include/uapi/linux/perf_event.h | 22 ++++++++++++++++++++-- 4 files changed, 33 insertions(+), 2 deletions(-)
arch/x86/include/asm/tsc.h +1 -0
@@ -49,6 +49,7 @@ extern void tsc_init(void);extern void mark_tsc_unstable (char *reason);extern int unsynchronized_tsc (void );extern int check_tsc_unstable (void ); +extern int check_tsc_disabled (void );extern unsigned long native_calibrate_tsc (void );extern int tsc_clocksource_reliable;
arch/x86/kernel/cpu/perf_event.c +6 -0
@@ -1860,6 +1860,7 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { userpg->cap_usr_time =0 ; + userpg->cap_usr_time_zero =0 ; userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;
@@ -1873,6 +1874,11 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now) userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now; + +if (sched_clock_stable && !check_tsc_disabled ()) { + userpg->cap_usr_time_zero =1 ; + userpg->time_zero =this_cpu_read (cyc2ns_offset); + } }/*
arch/x86/kernel/tsc.c +6 -0
@@ -89,6 +89,12 @@ int check_tsc_unstable(void) }EXPORT_SYMBOL_GPL (check_tsc_unstable); +int check_tsc_disabled (void ) +{ +return tsc_disabled; +} +EXPORT_SYMBOL_GPL (check_tsc_disabled); +#ifdef CONFIG_X86_TSC int __init notsc_setup (char *str) {
include/uapi/linux/perf_event.h +20 -2
@@ -378,7 +378,8 @@ struct perf_event_mmap_page {struct {__u64 cap_usr_time :1 , cap_usr_rdpmc :1 , - cap_____res :62 ; + cap_usr_time_zero :1 , + cap_____res :61 ; }; };
@@ -420,12 +421,29 @@ struct perf_event_mmap_page {__u16 time_shift;__u32 time_mult;__u64 time_offset; +/* +* If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated +* from sample timestamps. +* +* time = timestamp - time_zero; +* quot = time / time_mult; +* rem = time % time_mult; +* cyc = (quot << time_shift) + (rem << time_shift) / time_mult; +* +* And vice versa: +* +* quot = cyc >> time_shift; +* rem = cyc & ((1 << time_shift) - 1); +* timestamp = time_zero + quot * time_mult + +* ((rem * time_mult) >> time_shift); +*/ +__u64 time_zero;/* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[120 ];/* align to 1k */ +__u64 __reserved[119 ];/* align to 1k */ /* * Control data for the mmap() data buffer.
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf/x86: Add ability to calculate TSC from perf sample timestamps
perf/x86: Add ability to calculate TSC from perf sample timestamps
Commit-ID: c73deb6aecda2955716f31572516f09d930ef450 Gitweb: http://git.kernel.org/tip/c73deb6aecda2955716f31572516f09d930ef450 Author: Adrian Hunter <[email protected]> AuthorDate: Fri, 28 Jun 2013 16:22:18 +0300 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 23 Jul 2013 12:17:45 +0200
perf/x86: Add ability to calculate TSC from perf sample timestamps
For modern CPUs, perf clock is directly related to TSC. TSC can be calculated from perf clock and vice versa using a simple calculation. Two of the three componenets of that calculation are already exported in struct perf_event_mmap_page. This patch exports the third.
--- arch/x86/include/asm/tsc.h | 1 + arch/x86/kernel/cpu/perf_event.c | 6 ++++++ arch/x86/kernel/tsc.c | 6 ++++++ include/uapi/linux/perf_event.h | 22 ++++++++++++++++++++-- 4 files changed, 33 insertions(+), 2 deletions(-)
arch/x86/include/asm/tsc.h +1 -0
@@ -49,6 +49,7 @@ extern void tsc_init(void);extern void mark_tsc_unstable (char *reason);extern int unsynchronized_tsc (void );extern int check_tsc_unstable (void ); +extern int check_tsc_disabled (void );extern unsigned long native_calibrate_tsc (void );extern int tsc_clocksource_reliable;
arch/x86/kernel/cpu/perf_event.c +6 -0
@@ -1884,6 +1884,7 @@ static struct pmu pmu = {void arch_perf_update_userpage (struct perf_event_mmap_page *userpg,u64 now) { userpg->cap_usr_time =0 ; + userpg->cap_usr_time_zero =0 ; userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc; userpg->pmc_width = x86_pmu.cntval_bits;
@@ -1897,6 +1898,11 @@ void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now) userpg->time_mult =this_cpu_read (cyc2ns); userpg->time_shift =CYC2NS_SCALE_FACTOR ; userpg->time_offset =this_cpu_read (cyc2ns_offset) - now; + +if (sched_clock_stable && !check_tsc_disabled ()) { + userpg->cap_usr_time_zero =1 ; + userpg->time_zero =this_cpu_read (cyc2ns_offset); + } }/*
arch/x86/kernel/tsc.c +6 -0
@@ -89,6 +89,12 @@ int check_tsc_unstable(void) }EXPORT_SYMBOL_GPL (check_tsc_unstable); +int check_tsc_disabled (void ) +{ +return tsc_disabled; +} +EXPORT_SYMBOL_GPL (check_tsc_disabled); +#ifdef CONFIG_X86_TSC int __init notsc_setup (char *str) {
include/uapi/linux/perf_event.h +20 -2
@@ -378,7 +378,8 @@ struct perf_event_mmap_page {struct {__u64 cap_usr_time :1 , cap_usr_rdpmc :1 , - cap_____res :62 ; + cap_usr_time_zero :1 , + cap_____res :61 ; }; };
@@ -420,12 +421,29 @@ struct perf_event_mmap_page {__u16 time_shift;__u32 time_mult;__u64 time_offset; +/* +* If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated +* from sample timestamps. +* +* time = timestamp - time_zero; +* quot = time / time_mult; +* rem = time % time_mult; +* cyc = (quot << time_shift) + (rem << time_shift) / time_mult; +* +* And vice versa: +* +* quot = cyc >> time_shift; +* rem = cyc & ((1 << time_shift) - 1); +* timestamp = time_zero + quot * time_mult + +* ((rem * time_mult) >> time_shift); +*/ +__u64 time_zero;/* * Hole for extension of the self monitor capabilities */ -__u64 __reserved[120 ];/* align to 1k */ +__u64 __reserved[119 ];/* align to 1k */ /* * Control data for the mmap() data buffer.
Adrian Hunter
reviewerPATCH 3/5 perf tools: add test for converting perf time to/from TSC
In reply to Adrian HunterThe test uses the newly added cap_usr_time_zero and time_zero of perf_event_mmap_page. TSC from rdtsc is compared with the time from 2 perf events. The test passes if the calculated times are all in the correct order.
--- tools/perf/Makefile | 3 + tools/perf/arch/x86/Makefile | 2 + tools/perf/arch/x86/util/tsc.c | 59 ++++++++++++ tools/perf/arch/x86/util/tsc.h | 20 ++++ tools/perf/tests/builtin-test.c | 6 ++ tools/perf/tests/perf-time-to-tsc.c | 177 ++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 7 files changed, 268 insertions(+) create mode 100644 tools/perf/arch/x86/util/tsc.c create mode 100644 tools/perf/arch/x86/util/tsc.h create mode 100644 tools/perf/tests/perf-time-to-tsc.c
tools/perf/Makefile +3 -0
@@ -390,6 +390,9 @@ LIB_OBJS += $(OUTPUT)tests/bp_signal.o LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o LIB_OBJS += $(OUTPUT)tests/task-exit.o LIB_OBJS += $(OUTPUT)tests/sw-clock.o +ifeq ($(ARCH),x86) +LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o +endif BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
tools/perf/arch/x86/Makefile +2 -0
@@ -6,3 +6,5 @@ ifndef NO_LIBUNWIND LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o endif LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o +LIB_H += arch/$(ARCH)/util/tsc.h
tools/perf/arch/x86/util/tsc.c new file +59 -0
59 lines not on this page · raw message
tools/perf/arch/x86/util/tsc.h new file +20 -0
@@ -0,0 +1,20 @@ +#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ +#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ + +#include "../../util/types.h" + +struct perf_tsc_conversion { +u16 time_shift; +u32 time_mult; +u64 time_zero; +}; + +struct perf_event_mmap_page ; + +int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc, +struct perf_tsc_conversion *tc); + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); + +#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/builtin-test.c +6 -0
@@ -93,6 +93,12 @@ static struct test { .desc = "Test software clock events have valid period values", .func = test__sw_clock_freq, }, +#if defined(__x86_64__) || defined(__i386__) + { + .desc = "Test converting perf time to TSC", + .func = test__perf_time_to_tsc, + }, +#endif { .func = NULL, },
tools/perf/tests/perf-time-to-tsc.c new file +177 -0
177 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -27,5 +27,6 @@ int test__bp_signal(void);int test__bp_signal_overflow (void );int test__task_exit (void );int test__sw_clock_freq (void ); +int test__perf_time_to_tsc (void );#endif /* TESTS_H */
Signature · 1 line
1.7.11.7
tip-bot for Adrian Hunter
merge bot[tip:perf/core] perf tools: Add test for converting perf time to/ from TSC
perf tools: Add test for converting perf time to/from TSC
Commit-ID: 3bd5a5fc8c6b9fe769777abf74b0ab5fbd7930b4 Gitweb: http://git.kernel.org/tip/3bd5a5fc8c6b9fe769777abf74b0ab5fbd7930b4 Author: Adrian Hunter <[email protected]> AuthorDate: Fri, 28 Jun 2013 16:22:19 +0300 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 23 Jul 2013 12:17:59 +0200
perf tools: Add test for converting perf time to/from TSC
The test uses the newly added cap_usr_time_zero and time_zero of perf_event_mmap_page. TSC from rdtsc is compared with the time from 2 perf events. The test passes if the calculated times are all in the correct order.
--- tools/perf/Makefile | 3 + tools/perf/arch/x86/Makefile | 2 + tools/perf/arch/x86/util/tsc.c | 59 ++++++++++++ tools/perf/arch/x86/util/tsc.h | 20 ++++ tools/perf/tests/builtin-test.c | 6 ++ tools/perf/tests/perf-time-to-tsc.c | 177 ++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 7 files changed, 268 insertions(+)
tools/perf/Makefile +3 -0
@@ -389,6 +389,9 @@ LIB_OBJS += $(OUTPUT)tests/bp_signal.o LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o LIB_OBJS += $(OUTPUT)tests/task-exit.o LIB_OBJS += $(OUTPUT)tests/sw-clock.o +ifeq ($(ARCH),x86) +LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o +endif BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
tools/perf/arch/x86/Makefile +2 -0
@@ -6,3 +6,5 @@ ifndef NO_LIBUNWIND LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o endif LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o +LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o +LIB_H += arch/$(ARCH)/util/tsc.h
tools/perf/arch/x86/util/tsc.c new file +59 -0
59 lines not on this page · raw message
tools/perf/arch/x86/util/tsc.h new file +20 -0
@@ -0,0 +1,20 @@ +#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ +#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ + +#include "../../util/types.h" + +struct perf_tsc_conversion { +u16 time_shift; +u32 time_mult; +u64 time_zero; +}; + +struct perf_event_mmap_page ; + +int perf_read_tsc_conversion (const struct perf_event_mmap_page *pc, +struct perf_tsc_conversion *tc); + +u64 perf_time_to_tsc (u64 ns,struct perf_tsc_conversion *tc); +u64 tsc_to_perf_time (u64 cyc,struct perf_tsc_conversion *tc); + +#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/tests/builtin-test.c +6 -0
@@ -93,6 +93,12 @@ static struct test { .desc = "Test software clock events have valid period values", .func = test__sw_clock_freq, }, +#if defined(__x86_64__) || defined(__i386__) + { + .desc = "Test converting perf time to TSC", + .func = test__perf_time_to_tsc, + }, +#endif { .func = NULL, },
tools/perf/tests/perf-time-to-tsc.c new file +177 -0
177 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -35,5 +35,6 @@ int test__bp_signal(void);int test__bp_signal_overflow (void );int test__task_exit (void );int test__sw_clock_freq (void ); +int test__perf_time_to_tsc (void );#endif /* TESTS_H */
Adrian Hunter
reviewerPATCH 4/5 perf: add 'keep tracking' flag to PERF_EVENT_IOC_DISABLE
In reply to Adrian HunterMake it possible to disable an event but continue to receive "tracking" events i.e. continue to receive mmap, comm, task events. The flag is updated by both PERF_EVENT_IOC_DISABLE and PERF_EVENT_IOC_ENABLE. The flag is cleared by prctl PR_TASK_PERF_EVENTS_DISABLE.
--- include/linux/perf_event.h | 1 + include/uapi/linux/perf_event.h | 1 + kernel/events/core.c | 21 +++++++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-)
include/linux/perf_event.h +1 -0
@@ -436,6 +436,7 @@ struct perf_event {struct perf_cgroup *cgrp;/* cgroup event is attach to */ int cgrp_defer_enabled;#endif +int keep_tracking;#endif /* CONFIG_PERF_EVENTS */ };
include/uapi/linux/perf_event.h +1 -0
@@ -324,6 +324,7 @@ struct perf_event_attr {enum perf_event_ioc_flags {PERF_IOC_FLAG_GROUP =1U <<0 , +PERF_IOC_KEEP_TRACKING =1U <<1 , };/*
kernel/events/core.c +19 -2
@@ -3495,6 +3495,16 @@ static inline int perf_fget_light(int fd, struct fd *p)return 0 ; } +static void perf_event_keep_tracking (struct perf_event *event,u32 flags) +{ +int keep_tracking = !!(flags &PERF_IOC_KEEP_TRACKING ); + +if (flags &PERF_IOC_FLAG_GROUP ) + event->group_leader->keep_tracking = keep_tracking; +else + event->keep_tracking = keep_tracking; +} +static int perf_event_set_output (struct perf_event *event,struct perf_event *output_event);static int perf_event_set_filter (struct perf_event *event,void __user *arg);
@@ -3510,6 +3520,7 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) func = perf_event_enable;break ;case PERF_EVENT_IOC_DISABLE : +perf_event_keep_tracking (event, flags); func = perf_event_disable;break ;case PERF_EVENT_IOC_RESET :
@@ -3552,6 +3563,9 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)else perf_event_for_each_child (event, func); +if (cmd ==PERF_EVENT_IOC_ENABLE ) +perf_event_keep_tracking (event, flags); +return 0 ; }
@@ -3572,8 +3586,10 @@ int perf_event_task_disable(void)struct perf_event *event;mutex_lock (¤t->perf_event_mutex); -list_for_each_entry (event, ¤t->perf_event_list, owner_entry) +list_for_each_entry (event, ¤t->perf_event_list, owner_entry) {perf_event_for_each_child (event, perf_event_disable); + event->keep_tracking =0 ; + }mutex_unlock (¤t->perf_event_mutex);return 0 ;
@@ -4670,7 +4686,8 @@ perf_event_aux_ctx(struct perf_event_context *ctx,struct perf_event *event;list_for_each_entry_rcu (event, &ctx->event_list, event_entry) { -if (event->state <PERF_EVENT_STATE_INACTIVE ) +if (event->state <PERF_EVENT_STATE_INACTIVE && + !event->keep_tracking)continue ;if (!event_filter_match (event))continue ;
Signature · 1 line
1.7.11.7
Adrian Hunter
reviewerPATCH 5/5 perf tools: add 'keep tracking' test
In reply to Adrian HunterAdd a test for the newly added 'keep tracking' flag for the PERF_EVENT_IOC_DISABLE IOCTL. The test checks that comm events are present when the event is disabled with the 'keep tracking' flag set. The test also checks that comm events are not present when the event is disabled without the flag set.
--- tools/perf/Makefile | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/keep-tracking.c | 168 +++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + tools/perf/util/evlist.c | 32 ++++++++ tools/perf/util/evlist.h | 5 ++ 6 files changed, 211 insertions(+) create mode 100644 tools/perf/tests/keep-tracking.c
tools/perf/Makefile +1 -0
@@ -393,6 +393,7 @@ LIB_OBJS += $(OUTPUT)tests/sw-clock.o ifeq ($(ARCH),x86) LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o endif +LIB_OBJS += $(OUTPUT)tests/keep-tracking.o BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
tools/perf/tests/builtin-test.c +4 -0
@@ -100,6 +100,10 @@ static struct test { },#endif { + .desc = "Test event disable IOCTL 'keep tracking' flag", + .func = test__keep_tracking, + }, + { .func = NULL, }, };
tools/perf/tests/keep-tracking.c new file +168 -0
168 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -28,5 +28,6 @@ int test__bp_signal_overflow(void);int test__task_exit (void );int test__sw_clock_freq (void );int test__perf_time_to_tsc (void ); +int test__keep_tracking (void );#endif /* TESTS_H */
tools/perf/util/evlist.c +32 -0
@@ -303,6 +303,38 @@ void perf_evlist__enable(struct perf_evlist *evlist) } } +int perf_evlist__disable_event (struct perf_evlist *evlist, +struct perf_evsel *evsel,int flags) +{ +int cpu, thread, err; + +for (cpu =0 ; cpu < evlist->cpus->nr; cpu++) { +for (thread =0 ; thread < evlist->threads->nr; thread++) { + err =ioctl (FD (evsel, cpu, thread), +PERF_EVENT_IOC_DISABLE , flags); +if (err) +return err; + } + } +return 0 ; +} + +int perf_evlist__enable_event (struct perf_evlist *evlist, +struct perf_evsel *evsel,int flags) +{ +int cpu, thread, err; + +for (cpu =0 ; cpu < evlist->cpus->nr; cpu++) { +for (thread =0 ; thread < evlist->threads->nr; thread++) { + err =ioctl (FD (evsel, cpu, thread), +PERF_EVENT_IOC_ENABLE , flags); +if (err) +return err; + } + } +return 0 ; +} +static int perf_evlist__alloc_pollfd (struct perf_evlist *evlist) {int nr_cpus =cpu_map__nr (evlist->cpus);
tools/perf/util/evlist.h +5 -0
@@ -104,6 +104,11 @@ void perf_evlist__munmap(struct perf_evlist *evlist);void perf_evlist__disable (struct perf_evlist *evlist);void perf_evlist__enable (struct perf_evlist *evlist); +int perf_evlist__disable_event (struct perf_evlist *evlist, +struct perf_evsel *evsel,int flags); +int perf_evlist__enable_event (struct perf_evlist *evlist, +struct perf_evsel *evsel,int flags); +void perf_evlist__set_selected (struct perf_evlist *evlist,struct perf_evsel *evsel);
Signature · 1 line
1.7.11.7
Peter Zijlstra
maintainerQuoted 5 lines · Adrian Hunter
Hi
Please consider these two new perf features:
x86: add ability to calculate TSC from perf sample timestamps
perf: add 'keep tracking' flag toPERF_EVENT_IOC_DISABLE
Please explain to us why you'd like to do this..
Adrian Hunter
reviewerQuoted 8 lines · Peter Zijlstra
Quoted 5 lines · Adrian Hunter
Hi
Please consider these two new perf features:
x86: add ability to calculate TSC from perf sample timestamps
perf: add 'keep tracking' flag toPERF_EVENT_IOC_DISABLEPlease explain to us why you'd like to do this..
I will see what information I can dig up. The short answer is that I need to disable and re-enable a perf event but still be able to map IPs to their DSOs and symbols - which means not losing mmap events.
Adrian Hunter
reviewerQuoted 8 lines · Adrian Hunter
Quoted 7 lines · Peter Zijlstra
Quoted 5 lines · Adrian Hunter
Hi
Please consider these two new perf features:
x86: add ability to calculate TSC from perf sample timestamps
perf: add 'keep tracking' flag toPERF_EVENT_IOC_DISABLE
Quoted 5 lines
Quoted 1 line
Please explain to us why you'd like to do this..
I will see what information I can dig up. The short answer is that I need to disable and re-enable a perf event but still be able to map IPs to their DSOs and symbols - which means not losing mmap events.
Any other comments?
Peter Zijlstra
maintainerQuoted 9 lines · Adrian Hunter
Quoted 8 lines · Adrian Hunter
Quoted 7 lines · Peter Zijlstra
Quoted 5 lines · Adrian Hunter
Hi
Please consider these two new perf features:
x86: add ability to calculate TSC from perf sample timestamps
perf: add 'keep tracking' flag toPERF_EVENT_IOC_DISABLE
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Please explain to us why you'd like to do this..
I will see what information I can dig up. The short answer is that I need to disable and re-enable a perf event but still be able to map IPs to their DSOs and symbols - which means not losing mmap events.
Any other comments?
Ah, thanks for the reminder.. well, I've applied patches 1-3 as those seem useful on their own. I'm not entirely convinced about the 'keep tracking' thing though.
It seems to me you could get the same by opening a second event into the same buffer and keeping that enabled.
Adrian Hunter
reviewerQuoted 16 lines · Peter Zijlstra
Quoted 15 lines · Adrian Hunter
Quoted 13 lines · Adrian Hunter
Quoted 8 lines · Peter Zijlstra
Quoted 5 lines · Adrian Hunter
Hi
Please consider these two new perf features:
x86: add ability to calculate TSC from perf sample timestamps
perf: add 'keep tracking' flag toPERF_EVENT_IOC_DISABLEPlease explain to us why you'd like to do this..
I will see what information I can dig up. The short answer is that I need to disable and re-enable a perf event but still be able to map IPs to their DSOs and symbols - which means not losing mmap events.
Quoted 8 lines
Quoted 1 line
Any other comments?
Ah, thanks for the reminder.. well, I've applied patches 1-3 as those seem useful on their own. I'm not entirely convinced about the 'keep tracking' thing though.
It seems to me you could get the same by opening a second event into the same buffer and keeping that enabled.
In that case I would like a dummy event to use for that purpose. A software event could be set aside e.g.
include/uapi/linux/perf_event.h +1 -0
@@ -109,6 +109,7 @@ enum perf_sw_ids {PERF_COUNT_SW_PAGE_FAULTS_MAJ =6 ,PERF_COUNT_SW_ALIGNMENT_FAULTS =7 ,PERF_COUNT_SW_EMULATION_FAULTS =8 , +PERF_COUNT_SW_DUMMY =9 , PERF_COUNT_SW_MAX, /* non-ABI */ };