This patch series is to refine the memory barriers for AUX ring buffer.
Patches 01 ~ 04 to address the barriers usage in the kernel. The first
patch is to make clear comment for how to use the barriers between the
data store and aux_head store, this asks the driver to make sure the
data is visible. Patches 02 ~ 04 is to refine the drivers for barriers
after the data store.
Patches 05 ~ 07 is to drop the legacy __sync functions, and polish for
duplicate code and cleanup the build after SYNC_COMPARE_AND_SWAP is not
used.
Patch 08 is to use WRITE_ONCE() for updating aux_tail.
Since the 64-bit value's atomicity is not promised on 32-bit perf, the
last two patches tries to fixup for perf tool when it runs in compat
mode. Patch 09 introduces a new global variable to indicate the kernel
runs in 64-bit mode which can be used to confirm if in compat mode;
patch 10 introduces variant functions for accessing AUX head/tail, it
can resolve the aotmicity issue for reading head pointer, and for the
tail write overflow issue it returns error to notify the tool to exit.
Have testes the patches on Arm64 Juno platform.
Changes from v2:
- Removed auxtrace_mmap__read_snapshot_head(), which has the duplicated
code with auxtrace_mmap__read_head();
- Cleanuped the build for HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT (Adrian);
- Added global variable "kernel_is_64_bit" (Adrian);
- Added compat variants compat_auxtrace_mmap__{read_head|write_tail}
(Adrian).
Leo Yan (10):
perf/ring_buffer: Add comment for barriers on AUX ring buffer
coresight: tmc-etr: Add barrier after updating AUX ring buffer
coresight: tmc-etf: Add comment for store ordering
perf/x86: Add barrier after updating bts
perf auxtrace: Drop legacy __sync functions
perf auxtrace: Remove auxtrace_mmap__read_snapshot_head()
perf: Cleanup for HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
perf auxtrace: Use WRITE_ONCE() for updating aux_tail
perf env: Set kernel bit mode
perf auxtrace: Add compat_auxtrace_mmap__{read_head|write_tail}
arch/x86/events/intel/bts.c | 3 +
.../hwtracing/coresight/coresight-tmc-etf.c | 6 +
.../hwtracing/coresight/coresight-tmc-etr.c | 8 ++
kernel/events/ring_buffer.c | 9 ++
tools/perf/Makefile.config | 4 -
tools/perf/util/auxtrace.c | 19 ++-
tools/perf/util/auxtrace.h | 109 ++++++++++++++----
tools/perf/util/env.c | 17 ++-
tools/perf/util/env.h | 1 +
9 files changed, 136 insertions(+), 40 deletions(-)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
AUX ring buffer applies almost the same barriers as perf ring buffer,
but there has an exception for ordering between writing the AUX trace
data and updating user_page::aux_head.
This patch adds comment for how to use the barriers on AUX ring buffer,
and gives comment to ask the drivers to flush the trace data into AUX
ring buffer prior to updating user_page::aux_head.
Signed-off-by: Leo Yan <redacted>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
kernel/events/ring_buffer.c | 9 +++++++++
1 file changed, 9 insertions(+)
Since a memory barrier is required between AUX trace data store and
aux_head store, and the AUX trace data is filled with memcpy(), it's
sufficient to use smp_wmb() so can ensure the trace data is visible
prior to updating aux_head.
Signed-off-by: Leo Yan <redacted>
---
drivers/hwtracing/coresight/coresight-tmc-etr.c | 8 ++++++++
1 file changed, 8 insertions(+)
AUX ring buffer is required to separate the data store and aux_head
store, since the function CS_LOCK() has contained memory barrier mb(),
mb() is a more conservative barrier than smp_wmb() on Arm32/Arm64, thus
it's needless to add any explicit barrier anymore.
Add comment to make clear for the barrier usage for ETF.
Signed-off-by: Leo Yan <redacted>
---
drivers/hwtracing/coresight/coresight-tmc-etf.c | 6 ++++++
1 file changed, 6 insertions(+)
Add barrier wmb() to separate the AUX data store and aux_head store.
Signed-off-by: Leo Yan <redacted>
---
arch/x86/events/intel/bts.c | 3 +++
1 file changed, 3 insertions(+)
@@ -209,6 +209,9 @@ static void bts_update(struct bts_ctx *bts)}else{local_set(&buf->data_size,head);}++/* The WMB separates data store and aux_head store matches. */+wmb();}staticint
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
The main purpose for using __sync built-in functions is to support
compat mode for 32-bit perf with 64-bit kernel. But using these
built-in functions might cause couple potential issues.
Firstly, __sync functions originally support Intel Itanium processoer [1]
but it cannot promise to support all 32-bit archs. Now these
functions have become the legacy functions.
As Peter also pointed out the logic issue in the function
auxtrace_mmap__write_tail(), it does a cmpxchg with 0 values to load
old_tail, and then executes a further cmpxchg with old_tail to write
the new tail. If consider the aux_tail might be assigned to '0' in the
middle of loops, this can introduce mess for AUX buffer if the kernel
fetches the temporary value '0'.
Considering __sync functions cannot really fix the 64-bit value
atomicity on 32-bit archs, thus this patch drops __sync functions.
Credits to Peter for detailed analysis.
[1] https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html#g_t_005f_005fsync-Builtins
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Leo Yan <redacted>
---
tools/perf/util/auxtrace.h | 19 -------------------
1 file changed, 19 deletions(-)
@@ -459,11 +453,7 @@ static inline u64 auxtrace_mmap__read_snapshot_head(struct auxtrace_mmap *mm)staticinlineu64auxtrace_mmap__read_head(structauxtrace_mmap*mm){structperf_event_mmap_page*pc=mm->userpg;-#if BITS_PER_LONG == 64 || !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)u64head=READ_ONCE(pc->aux_head);-#else-u64head=__sync_val_compare_and_swap(&pc->aux_head,0,0);-#endif/* Ensure all reads are done after we read the head */smp_rmb();
@@ -473,19 +463,10 @@ static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm)staticinlinevoidauxtrace_mmap__write_tail(structauxtrace_mmap*mm,u64tail){structperf_event_mmap_page*pc=mm->userpg;-#if BITS_PER_LONG != 64 && defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)-u64old_tail;-#endif/* Ensure all reads are done before we write the tail out */smp_mb();-#if BITS_PER_LONG == 64 || !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)pc->aux_tail=tail;-#else-do{-old_tail=__sync_val_compare_and_swap(&pc->aux_tail,0,0);-}while(!__sync_bool_compare_and_swap(&pc->aux_tail,old_tail,tail));-#endif}intauxtrace_mmap__mmap(structauxtrace_mmap*mm,
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Since the function auxtrace_mmap__read_snapshot_head() is exactly same
with auxtrace_mmap__read_head(), whether the session is in snapshot mode
or not, it's unified to use function auxtrace_mmap__read_head() for
reading AUX buffer head.
And the function auxtrace_mmap__read_snapshot_head() is unused so this
patch removes it.
Signed-off-by: Leo Yan <redacted>
---
tools/perf/util/auxtrace.c | 5 ++---
tools/perf/util/auxtrace.h | 10 ----------
2 files changed, 2 insertions(+), 13 deletions(-)
@@ -440,16 +440,6 @@ struct auxtrace_cache;#ifdef HAVE_AUXTRACE_SUPPORT-staticinlineu64auxtrace_mmap__read_snapshot_head(structauxtrace_mmap*mm)-{-structperf_event_mmap_page*pc=mm->userpg;-u64head=READ_ONCE(pc->aux_head);--/* Ensure all reads are done after we read the head */-smp_rmb();-returnhead;-}-staticinlineu64auxtrace_mmap__read_head(structauxtrace_mmap*mm){structperf_event_mmap_page*pc=mm->userpg;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Since the __sync functions have been dropped, This patch removes unused
build and checking for HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT in perf tool.
Note, there have a test for SYNC_COMPARE_AND_SWAP and the test file is
located in build/feature/test-sync-compare-and-swap.c. Since there
still has several components using the sync functions, it's deliberately
to not be removed.
$ cd linux/tools
$ git grep __sync_val_compare_and_swap | awk '{ printf $1"\n" }'
build/feature/test-sync-compare-and-swap.c:
include/asm-generic/atomic-gcc.h:
testing/selftests/bpf/progs/atomics.c:
testing/selftests/bpf/progs/atomics.c:
testing/selftests/bpf/progs/atomics.c:
testing/selftests/bpf/progs/atomics.c:
testing/selftests/futex/include/atomic.h:
testing/selftests/futex/include/futextest.h:
Signed-off-by: Leo Yan <redacted>
---
tools/perf/Makefile.config | 4 ----
tools/perf/util/auxtrace.c | 5 -----
2 files changed, 9 deletions(-)
@@ -130,11 +130,6 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,return0;}-#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)-pr_err("Cannot use AUX area tracing mmaps\n");-return-1;-#endif-pc->aux_offset=mp->offset;pc->aux_size=mp->len;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Use WRITE_ONCE() for updating aux_tail, so can avoid unexpected memory
behaviour.
Signed-off-by: Leo Yan <redacted>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
tools/perf/util/auxtrace.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -456,7 +456,7 @@ static inline void auxtrace_mmap__write_tail(struct auxtrace_mmap *mm, u64 tail)/* Ensure all reads are done before we write the tail out */smp_mb();-pc->aux_tail=tail;+WRITE_ONCE(pc->aux_tail,tail);}intauxtrace_mmap__mmap(structauxtrace_mmap*mm,
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
It's useful to know that the kernel is running in 32-bit or 64-bit
mode. E.g. We can decide perf tool is running in compat mode when
detects kernel is running in 64-bit mode and the tool is in 32-bit
mode with the compiler macro BITS_PER_LONG is 32.
This patch adds a global variable "kernel_is_64_bit", during the
environment initialization for the session, the kernel running mode
is decided by checking the architecture string.
Signed-off-by: Leo Yan <redacted>
---
tools/perf/util/env.c | 17 ++++++++++++++++-
tools/perf/util/env.h | 1 +
2 files changed, 17 insertions(+), 1 deletion(-)
When perf runs in compat mode (kernel in 64-bit mode and the perf is in
32-bit mode), the 64-bit value atomicity in the user space cannot be
assured, E.g. on some architectures, the 64-bit value accessing is split
into two instructions, one is the low 32-bit accessing and another is
for the high 32-bit.
This patch introduces two functions compat_auxtrace_mmap__read_head()
and compat_auxtrace_mmap__write_tail(), as their naming indicates, when
perf tool works in compat mode, it uses these two functions to access
the AUX head and tail. These two functions can allow the perf tool to
work properly in certain conditions, e.g. when perf tool works in
snapshot mode with only using AUX head pointer, or perf tool uses the
AUX buffer and the tail is not bigger than 4GB.
When the perf tool cannot handle the case when the AUX tail is overflow
for 4GB, the function compat_auxtrace_mmap__write_tail() returns -1 and
the caller is changed to bail out for the overflow error.
Suggested-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Leo Yan <redacted>
---
tools/perf/util/auxtrace.c | 9 ++--
tools/perf/util/auxtrace.h | 94 +++++++++++++++++++++++++++++++++++++-
2 files changed, 98 insertions(+), 5 deletions(-)
@@ -440,23 +442,111 @@ struct auxtrace_cache;#ifdef HAVE_AUXTRACE_SUPPORT+/*+*Inthecompatmodekernelrunsin64-bitandperftoolrunsin32-bitmode,+*32-bitperftoolcannotaccess64-bitvalueatomically,whichmightleadto+*theissuescausedbythebelowsequenceonmultipleCPUs:whenperftool+*accesseseithertheloadoperationorthestoreoperationfor64-bitvalue,+*onsomearchitecturestheoperationisdividedintotwoinstructions,one+*isforaccessingthelow32-bitvalueandanotherisforthehigh32-bit;+*thusthesetwouseroperationscangivethekernelchancestoaccessthe+*64-bitvalue,andthusleadstotheunexpectedloadvalues.+*+*kernel(64-bit)user(32-bit)+*+*if(LOAD->aux_tail){--,LOAD->aux_head_lo+*STORE$aux_data|,--->+*FLUSH$aux_data||LOAD->aux_head_hi+*STORE->aux_head--|-------`smp_rmb()+*}|LOAD$data+*|smp_mb()+*|STORE->aux_tail_lo+*`----------->+*STORE->aux_tail_hi+*+*Forthisreason,it'simpossiblefortheperftooltoworkcorrectlywhen+*theAUXheadortailisbiggerthan4GB(morethan32bitslength);andwe+*cannotsimplylimittheAUXringbuffertolessthan4GB,thereasonis+*thepointerscanbeincreasedmonotonically(e.ginsnapshotmode),whatever+*thebuffersizeitis,attheendtheheadandtailcanbebiggerthan4GB+*andcarryouttothehigh32-bit.+*+*Tomitigatetheissuesandimprovetheuserexperience,wecanallowthe+*perftoolworkingincertainconditionsandbailoutwitherrorifdetect+*anyoverflowcannotbehandled.+*+*ForreadingtheAUXhead,itreadsoutthevaluesforthreetimes,and+*comparesthehigh4bytesofthevaluesbetweenthefirsttimeandthelast+*time,iftherehasnochangeforhigh4bytesinjectedbythekernelduring+*theuserreadingsequence,it'ssafeforusethesecondvalue.+*+*WhenupdatetheAUXtailanddetectsanycarryinginthehigh32bits,it+*meanstherehavetwostoreoperationsinuserspaceanditcannotpromise+*theatomicityfor64-bitwrite,soreturn'-1'inthiscasetotellthe+*calleranoverflowerrorhashappened.+*/+staticinlineu64compat_auxtrace_mmap__read_head(structauxtrace_mmap*mm)+{+structperf_event_mmap_page*pc=mm->userpg;+u64first,second,last;+u64mask=(u64)(UINT32_MAX)<<32;++do{+first=READ_ONCE(pc->aux_head);+/* Ensure all reads are done after we read the head */+smp_rmb();+second=READ_ONCE(pc->aux_head);+/* Ensure all reads are done after we read the head */+smp_rmb();+last=READ_ONCE(pc->aux_head);+}while((first&mask)!=(last&mask));++returnsecond;+}++staticinlineintcompat_auxtrace_mmap__write_tail(structauxtrace_mmap*mm,+u64tail)+{+structperf_event_mmap_page*pc=mm->userpg;+u64mask=(u64)(UINT32_MAX)<<32;++if(tail&mask)+return-1;++/* Ensure all reads are done before we write the tail out */+smp_mb();+WRITE_ONCE(pc->aux_tail,tail);+return0;+}+staticinlineu64auxtrace_mmap__read_head(structauxtrace_mmap*mm){structperf_event_mmap_page*pc=mm->userpg;-u64head=READ_ONCE(pc->aux_head);+u64head;++#if BITS_PER_LONG == 32+if(kernel_is_64_bit)+returncompat_auxtrace_mmap__read_head(mm);+#endif+head=READ_ONCE(pc->aux_head);/* Ensure all reads are done after we read the head */smp_rmb();returnhead;}-staticinlinevoidauxtrace_mmap__write_tail(structauxtrace_mmap*mm,u64tail)+staticinlineintauxtrace_mmap__write_tail(structauxtrace_mmap*mm,u64tail){structperf_event_mmap_page*pc=mm->userpg;+#if BITS_PER_LONG == 32+if(kernel_is_64_bit)+returncompat_auxtrace_mmap__write_tail(mm,tail);+#endif/* Ensure all reads are done before we write the tail out */smp_mb();WRITE_ONCE(pc->aux_tail,tail);+return0;}intauxtrace_mmap__mmap(structauxtrace_mmap*mm,
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Adrian Hunter <adrian.hunter@intel.com> Date: 2021-07-10 12:34:26
On 4/07/21 10:16 am, Leo Yan wrote:
The main purpose for using __sync built-in functions is to support
compat mode for 32-bit perf with 64-bit kernel. But using these
built-in functions might cause couple potential issues.
Firstly, __sync functions originally support Intel Itanium processoer [1]
but it cannot promise to support all 32-bit archs. Now these
functions have become the legacy functions.
As Peter also pointed out the logic issue in the function
auxtrace_mmap__write_tail(), it does a cmpxchg with 0 values to load
old_tail, and then executes a further cmpxchg with old_tail to write
the new tail. If consider the aux_tail might be assigned to '0' in the
middle of loops, this can introduce mess for AUX buffer if the kernel
fetches the temporary value '0'.
That is not exactly true. The definition of __sync_*_compare_and_swap is
"if the current value of *ptr is oldval, then write newval into *pt"
so replacing zero with zero won't make any difference, but it will return
the old value in any case. Probably better to leave out that paragraph.
quoted hunk
Considering __sync functions cannot really fix the 64-bit value
atomicity on 32-bit archs, thus this patch drops __sync functions.
Credits to Peter for detailed analysis.
[1] https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html#g_t_005f_005fsync-Builtins
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Leo Yan <redacted>
---
tools/perf/util/auxtrace.h | 19 -------------------
1 file changed, 19 deletions(-)
@@ -459,11 +453,7 @@ static inline u64 auxtrace_mmap__read_snapshot_head(struct auxtrace_mmap *mm)staticinlineu64auxtrace_mmap__read_head(structauxtrace_mmap*mm){structperf_event_mmap_page*pc=mm->userpg;-#if BITS_PER_LONG == 64 || !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)u64head=READ_ONCE(pc->aux_head);-#else-u64head=__sync_val_compare_and_swap(&pc->aux_head,0,0);-#endif/* Ensure all reads are done after we read the head */smp_rmb();
@@ -473,19 +463,10 @@ static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm)staticinlinevoidauxtrace_mmap__write_tail(structauxtrace_mmap*mm,u64tail){structperf_event_mmap_page*pc=mm->userpg;-#if BITS_PER_LONG != 64 && defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)-u64old_tail;-#endif/* Ensure all reads are done before we write the tail out */smp_mb();-#if BITS_PER_LONG == 64 || !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)pc->aux_tail=tail;-#else-do{-old_tail=__sync_val_compare_and_swap(&pc->aux_tail,0,0);-}while(!__sync_bool_compare_and_swap(&pc->aux_tail,old_tail,tail));-#endif}intauxtrace_mmap__mmap(structauxtrace_mmap*mm,
From: Adrian Hunter <adrian.hunter@intel.com> Date: 2021-07-10 12:36:53
On 4/07/21 10:16 am, Leo Yan wrote:
Since the __sync functions have been dropped, This patch removes unused
build and checking for HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT in perf tool.
Note, there have a test for SYNC_COMPARE_AND_SWAP and the test file is
located in build/feature/test-sync-compare-and-swap.c. Since there
still has several components using the sync functions, it's deliberately
to not be removed.
I don't quite follow that. If they aren't using the feature test
macro, then why keep the feature test?
@@ -130,11 +130,6 @@ int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,return0;}-#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)-pr_err("Cannot use AUX area tracing mmaps\n");-return-1;-#endif-pc->aux_offset=mp->offset;pc->aux_size=mp->len;
On Sat, Jul 10, 2021 at 03:34:24PM +0300, Adrian Hunter wrote:
On 4/07/21 10:16 am, Leo Yan wrote:
quoted
The main purpose for using __sync built-in functions is to support
compat mode for 32-bit perf with 64-bit kernel. But using these
built-in functions might cause couple potential issues.
Firstly, __sync functions originally support Intel Itanium processoer [1]
but it cannot promise to support all 32-bit archs. Now these
functions have become the legacy functions.
As Peter also pointed out the logic issue in the function
auxtrace_mmap__write_tail(), it does a cmpxchg with 0 values to load
old_tail, and then executes a further cmpxchg with old_tail to write
the new tail. If consider the aux_tail might be assigned to '0' in the
middle of loops, this can introduce mess for AUX buffer if the kernel
fetches the temporary value '0'.
That is not exactly true. The definition of __sync_*_compare_and_swap is
"if the current value of *ptr is oldval, then write newval into *pt"
so replacing zero with zero won't make any difference, but it will return
the old value in any case. Probably better to leave out that paragraph.
Okay, I admit the paragraph is not right, will drop it to avoid
confusion. Thanks for review!
Leo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Hi Adrian,
On Sat, Jul 10, 2021 at 03:36:53PM +0300, Adrian Hunter wrote:
On 4/07/21 10:16 am, Leo Yan wrote:
quoted
Since the __sync functions have been dropped, This patch removes unused
build and checking for HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT in perf tool.
Note, there have a test for SYNC_COMPARE_AND_SWAP and the test file is
located in build/feature/test-sync-compare-and-swap.c. Since there
still has several components using the sync functions, it's deliberately
to not be removed.
I don't quite follow that. If they aren't using the feature test
macro, then why keep the feature test?
There are files are still using __sync_xxx_compare_and_swap() functions,
e.g. in the folder tools/testing/selftests/bpf. On the other hand,
after drop __sync functions from perf, there have no any Makefile check
the feature 'feature-sync-compare-and-swap'. So it's safe to remove the
feature test.
Sorry for confusion. Will drop the feature test in new patch set.
Thanks,
Leo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel