: perf: reduce data loss when profiling highly parallel CPU bound workloads
v11 cover : perf: reduce data loss when profiling highly parallel CPU bound workloads
Currently in record mode the tool implements trace writing serially. The algorithm loops over mapped per-cpu data buffers and stores ready data chunks into a trace file using write() system call.
At some circumstances the kernel may lack free space in a buffer because the other buffer's half is not yet written to disk due to some other buffer's data writing by the tool at the moment.
Thus serial trace writing implementation may cause the kernel to loose profiling data and that is what observed when profiling highly parallel CPU bound workloads on machines with big number of cores.
Experiment with profiling matrix multiplication code executing 128 threads on Intel Xeon Phi (KNM) with 272 cores, like below, demonstrates data loss metrics value of 98%:
/usr/bin/time perf record -o /tmp/perf-ser.data -a -N -B -T -R -g \
--call-graph dwarf,1024 --user-regs=IP,SP,BP --switch-events \
-e cycles,instructions,ref-cycles,software/period=1,name=cs,config=0x3/Duk -- \
matrix.gccData loss metrics is the ratio lost_time/elapsed_time where lost_time is the sum of time intervals containing PERF_RECORD_LOST records and elapsed_time is the elapsed application run time under profiling.
Applying asynchronous trace streaming thru Posix AIO API [1] lowers data loss metrics value providing 2x improvement (from 98% to ~1%)
Asynchronous trace streaming is currently limited to glibc linkage. musl libc [5] also provides Posix AIO API implementation, however the patchkit is not tested with it. There may be other libc libraries linked by Perf tool that currently lack Posix AIO API support [2], [3], [4] so NO_AIO define may be used to limit Perf tool binary to serial streaming only.
---
Alexey Budankov (3):
perf util: map data buffer for preserving collected data perf record: enable asynchronous trace writing perf record: extend trace writing to multi AIO
tools/perf/Documentation/perf-record.txt | 6 + tools/perf/Makefile.config | 5 + tools/perf/Makefile.perf | 7 +- tools/perf/builtin-record.c | 210 +++++++++++++++++++++++++++++-- tools/perf/perf.h | 3 + tools/perf/util/evlist.c | 8 +- tools/perf/util/evlist.h | 2 +- tools/perf/util/mmap.c | 154 ++++++++++++++++++++++- tools/perf/util/mmap.h | 17 +++ 9 files changed, 398 insertions(+), 14 deletions(-)
---
Changes in v11:
- replacing the both lseek() syscalls in every loop iteration by the only
two syscalls just before and after the loop at record__mmap_read_evlist() and advancing *in-flight* off file pos value at perf_mmap__aio_push()
Changes in v10:
- moved specific code to perf_mmap__aio_mmap(), perf_mmap__aio_munmap();
- adjusted error reporting by using %m
- avoided lseek() setting file pos back in case of record__aio_write() failure
- compacted code selecting between serial and AIO streaming
- optimized call places of record__mmap_read_sync()
- added description of aio-cblocks option into perf-record.txt
Changes in v9:
- enable AIO streaming only when --aio-cblocks option is specified explicitly
- enable AIO based implementation when linking with glibc only
- define NO_AIO to limit Perf binary to serial implementation
Changes in v8:
- run the whole thing thru checkpatch.pl and corrected found issues except lines longer than 80 symbols
- corrected comments alignment and formatting
- moved multi AIO implementation into 3rd patch in the series
- implemented explicit cblocks array allocation
- split AIO completion check into separate record__aio_complete()
- set nr_cblocks default to 1 and max allowed value to 4
Changes in v7:
- implemented handling record.aio setting from perfconfig file
Changes in v6:
- adjusted setting of priorities for cblocks;
- handled errno == EAGAIN case from aio_write() return;
Changes in v5:
- resolved livelock on perf record -e intel_pt// -- dd if=/dev/zero of=/dev/null count=100000
- data loss metrics decreased from 25% to 2x in trialed configuration;
- reshaped layout of data structures;
- implemented --aio option;
- avoided nanosleep() prior calling aio_suspend();
- switched to per-cpu aio multi buffer record__aio_sync();
- record_mmap_read_sync() now does global sync just before
switching trace file or collection stop;
Changes in v4:
- converted mmap()/munmap() to malloc()/free() for mmap->data buffer management
- converted void *bf to struct perf_mmap *md in signatures
- written comment in perf_mmap__push() just before perf_mmap__get();
- written comment in record__mmap_read_sync() on possible restarting
of aio_write() operation and releasing perf_mmap object after all;
- added perf_mmap__put() for the cases of failed aio_write();
Changes in v3:
- written comments about nanosleep(0.5ms) call prior aio_suspend()
to cope with intrusiveness of its implementation in glibc;
- written comments about rationale behind coping profiling data
into mmap->data buffer;
Changes in v2:
- converted zalloc() to calloc() for allocation of mmap_aio array,
- cleared typo and adjusted fallback branch code;
---
[1] http://man7.org/linux/man-pages/man7/aio.7.html
[2] https://android.googlesource.com/platform/bionic/+/master/docs/status.md
[3] https://www.uclibc.org/
[4] https://uclibc-ng.org/
[5] https://www.musl-libc.org/
PATCH v11 1/3 : perf util: map data buffer for preserving collected data
The map->data buffer is used to preserve map->base profiling data for writing to disk. AIO map->cblock is used to queue corresponding map->data buffer for asynchronous writing.
---
Changes in v10:
- moved specific code to perf_mmap__aio_mmap(), perf_mmap__aio_munmap()
- adjusted error reporting by using %m
Changes in v9:
- implemented NO_AIO and HAVE_AIO_SUPPORT defines to cover cases of libc implementations without Posix AIO API support
Changes in v7:
- implemented handling record.aio setting from perfconfig file
Changes in v6:
- adjusted setting of priorities for cblocks;
Changes in v5:
- reshaped layout of data structures;
- implemented --aio option;
Changes in v4:
- converted mmap()/munmap() to malloc()/free() for mmap->data buffer management
Changes in v2:
- converted zalloc() to calloc() for allocation of mmap_aio array,
- cleared typo and adjusted fallback branch code;
--- tools/perf/Makefile.config | 5 +++++ tools/perf/Makefile.perf | 7 ++++++- tools/perf/util/evlist.c | 4 +++- tools/perf/util/mmap.c | 48 +++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/mmap.h | 11 +++++++++++ 5 files changed, 72 insertions(+), 3 deletions(-)
tools/perf/Makefile.config +5 -0
@@ -355,6 +355,11 @@ endif # NO_LIBELF ifeq ($(feature-glibc), 1) CFLAGS += -DHAVE_GLIBC_SUPPORT + ifndef NO_AIO + ifndef BIONIC + CFLAGS += -DHAVE_AIO_SUPPORT + endif + endif endif ifdef NO_DWARF
tools/perf/Makefile.perf +6 -1
@@ -97,8 +97,13 @@ include ../scripts/utilities.mak # Define LIBCLANGLLVM if you DO want builtin clang and llvm support. # When selected, pass LLVM_CONFIG=/path/to/llvm-config to `make' if # llvm-config is not in $PATH. - +# # Define NO_CORESIGHT if you do not want support for CoreSight trace decoding. +# +# Define NO_AIO if you do not want support of Posix AIO based trace +# streaming for record mode. Currently Posix AIO trace streaming is +# supported only when linking with glibc. +# # As per kernel Makefile, avoid funny character set dependencies unexport LC_ALL
tools/perf/util/evlist.c +3 -1
@@ -1029,7 +1029,9 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,* So &mp should not be passed through const pointer. */ struct mmap_params mp; - +#ifdef HAVE_AIO_SUPPORT + mp.nr_cblocks =0 ; +#endif if (!evlist->mmap) evlist->mmap =perf_evlist__alloc_mmap (evlist, false);if (!evlist->mmap)
tools/perf/util/mmap.c +47 -1
70 lines not on this page · raw message
tools/perf/util/mmap.h +11 -0
@@ -6,6 +6,9 @@#include <linux/types.h> #include <asm/barrier.h> #include <stdbool.h> +#ifdef HAVE_AIO_SUPPORT +#include <aio.h> +#endif #include "auxtrace.h" #include "event.h"
@@ -26,6 +29,11 @@ struct perf_mmap {bool overwrite;struct auxtrace_mmap auxtrace_mmap;char event_copy[PERF_SAMPLE_MAX_SIZE ]__aligned(8) ; +#ifdef HAVE_AIO_SUPPORT +void *data; +struct aiocb cblock; +int nr_cblocks; +#endif };/*
@@ -59,6 +67,9 @@ enum bkw_mmap_state {struct mmap_params {int prot, mask;struct auxtrace_mmap_params auxtrace_mp; +#ifdef HAVE_AIO_SUPPORT +int nr_cblocks; +#endif };int perf_mmap__mmap (struct perf_mmap *map,struct mmap_params *mp,int fd,int cpu);
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Quoted 38 lines · Alexey Budankov
The
map->databuffer is used to preservemap->baseprofiling data for writing to disk. AIOmap->cblockis used to queue correspondingmap->databuffer for asynchronous writing.Signed-off-by Alexey Budankov <[email protected]>---
Changes in v10:
- moved specific code toperf_mmap__aio_mmap(),perf_mmap__aio_munmap()
- adjusted error reporting by using %m
Changes in v9:
- implementedNO_AIOandHAVE_AIO_SUPPORTdefines to cover cases of libc implementations without Posix AIO API support
Changes in v7:
- implemented handling record.aio setting from perfconfig file
Changes in v6:
- adjusted setting of priorities for cblocks;
Changes in v5:
- reshaped layout of data structures;
- implemented --aio option;
Changes in v4:
- converted mmap()/munmap() to malloc()/free() formmap->databuffer management
Changes in v2:
- convertedzalloc()tocalloc()for allocation ofmmap_aioarray,
- cleared typo and adjusted fallback branch code;--- tools/perf/Makefile.config | 5 +++++ tools/perf/Makefile.perf | 7 ++++++- tools/perf/util/evlist.c | 4 +++- tools/perf/util/mmap.c | 48 +++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/mmap.h | 11 +++++++++++ 5 files changed, 72 insertions(+), 3 deletions(-)tools/perf/Makefile.config +0
-0
tools/perf/Makefile.config endif # NO_LIBELF · line 358
Quoted 4 lines
tools/perf/Makefile.config +1
-0@@ -355,6 +355,11 @@ endif # NO_LIBELF ifeq ($(feature-glibc), 1) CFLAGS += -DHAVE_GLIBC_SUPPORT + ifndef NO_AIO
hum, do we need NO_AIO? we have the --aio option to enable that right? I guess BIONIC does not support aio, but but will it fail when it's compiled in there?
jirka
Quoted 5 lines
tools/perf/Makefile.config +4
-0+ ifndef BIONIC + CFLAGS += -DHAVE_AIO_SUPPORT + endif + endif endif
SNIP
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Hi,
Quoted 2 lines · Jiri Olsa
Quoted 1 line · Alexey Budankov
<SNIP>
Quoted 11 lines
tools/perf/Makefile.config endif # NO_LIBELF · line 358
Quoted 9 lines
tools/perf/Makefile.config +1
-0@@ -355,6 +355,11 @@ endif # NO_LIBELF ifeq ($(feature-glibc), 1) CFLAGS += -DHAVE_GLIBC_SUPPORT + ifndef NO_AIOhum, do we need
NO_AIO? we have the --aio option to enable that right?
Right. Enable that *in runtime*.
Quoted 2 lines
I guess BIONIC does not support aio, but but will it fail when it's compiled in there?
Please see updated section of the cover letter for more information regarding this. Possible compilation issues is that's why we better have this capability in advance:
objdump -T tools/perf/perf | grep aio
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_suspend64 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_return64 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_error64 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_write64
IMHO, it is worth implementing NO_AIO define.
Thanks,
Alexey
Quoted 11 lines
jirka
Quoted 5 lines
tools/perf/Makefile.config +4
-0+ ifndef BIONIC + CFLAGS += -DHAVE_AIO_SUPPORT + endif + endif endifSNIP
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Quoted 27 lines · Alexey Budankov
Hi,
Quoted 2 lines · Jiri Olsa
Quoted 1 line · Alexey Budankov
<SNIP>
Quoted 11 lines
tools/perf/Makefile.config endif # NO_LIBELF · line 358
Quoted 9 lines
tools/perf/Makefile.config +1
-0@@ -355,6 +355,11 @@ endif # NO_LIBELF ifeq ($(feature-glibc), 1) CFLAGS += -DHAVE_GLIBC_SUPPORT + ifndef NO_AIOhum, do we need
NO_AIO? we have the --aio option to enable that right?Right. Enable that *in runtime*.
Quoted 2 lines
I guess BIONIC does not support aio, but but will it fail when it's compiled in there?
Please see updated section of the cover letter for more information regarding this. Possible compilation issues is that's why we better have this capability in advance:
Quoted 8 lines
objdump -T
tools/perf/perf| grep aio0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_suspend64 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_return64 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_error64 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 aio_write64IMHO, it is worth implementing
NO_AIOdefine.
ok, if there are c libs that won't compile with that, then sure, we need it
thanks,
jirka
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
In reply to Alexey BudankovOn Mon, Oct 08, 2018 at 09:14:29AM +0300, Alexey Budankov wrote:
SNIP
Quoted 20 lines
tools/perf/util/evlist.c +3
-1@@ -1029,7 +1029,9 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,* So &mp should not be passed through const pointer. */ struct mmap_params mp; - +#ifdef HAVE_AIO_SUPPORT + mp.nr_cblocks =0 ; +#endif if (!evlist->mmap) evlist->mmap =perf_evlist__alloc_mmap (evlist, false);if (!evlist->mmap)tools/perf/util/mmap.c +0
-0
tools/perf/util/mmap.c void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __mayb · line 161
Quoted 9 lines
tools/perf/util/mmap.c +6
-0@@ -153,8 +153,19 @@ void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __mayb { } +#ifdef HAVE_AIO_SUPPORT +static void perf_mmap__aio_munmap (struct perf_mmap *map) +{ +if (map->data) +zfree (&map->data); +}
if we really need to keep this optional for compilation, please make it as single block with dummy functions for when it's not compiled in, like:
#ifdef
static void perf_mmap__aio_munmap(struct perf_mmap *map)
{
if (map->data)
zfree(&map->data);
}#else
static void perf_mmap__aio_munmap(struct perf_mmap *map) { } #endif
thanks,
jirka
Quoted 13 lines
tools/perf/util/mmap.c +5
-0+#endif +void perf_mmap__munmap (struct perf_mmap *map) { +#ifdef HAVE_AIO_SUPPORT +perf_mmap__aio_munmap (map); +#endif if (map->base !=NULL ) {munmap (map->base,perf_mmap__mmap_len (map)); map->base =NULL ;@@ -164,8 +175,40 @@ void perf_mmap__munmap(struct perf_mmap *map)auxtrace_mmap__munmap (&map->auxtrace_mmap); }
SNIP
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:14:29AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 14 lines
tools/perf/util/mmap.c void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __mayb · line 161
Quoted 7 lines
tools/perf/util/mmap.c +6
-0+#ifdef HAVE_AIO_SUPPORT +static void perf_mmap__aio_munmap (struct perf_mmap *map) +{ +if (map->data) +zfree (&map->data); +}if we really need to keep this optional for compilation, please make it as single block with dummy functions for when it's not compiled in, like:
#ifdef
static voidperf_mmap__aio_munmap(struct perf_mmap *map)
Quoted 7 lines
{ if (map->data) zfree(&map->data); }#else
static voidperf_mmap__aio_munmap(struct perf_mmap *map){ } #endif
Ok.
Quoted 5 lines
thanks,
jirka
Quoted 13 lines
tools/perf/util/mmap.c void perf_mmap__munmap(struct perf_mmap *map) · line 176
Quoted 13 lines
tools/perf/util/mmap.c +5
-0+#endif +void perf_mmap__munmap (struct perf_mmap *map) { +#ifdef HAVE_AIO_SUPPORT +perf_mmap__aio_munmap (map); +#endif if (map->base !=NULL ) {munmap (map->base,perf_mmap__mmap_len (map)); map->base =NULL ;@@ -164,8 +175,40 @@ void perf_mmap__munmap(struct perf_mmap *map)auxtrace_mmap__munmap (&map->auxtrace_mmap); }
Well, let's go with stub functions design as opposite to pure conditional compilation. However this may, probably, result in unintended Perf tool binary size growth, even if NO_AIO is defined during compilation.
Thanks,
Alexey
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Quoted 44 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:14:29AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 14 lines
tools/perf/util/mmap.c void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __mayb · line 161
Quoted 7 lines
tools/perf/util/mmap.c +6
-0+#ifdef HAVE_AIO_SUPPORT +static void perf_mmap__aio_munmap (struct perf_mmap *map) +{ +if (map->data) +zfree (&map->data); +}if we really need to keep this optional for compilation, please make it as single block with dummy functions for when it's not compiled in, like:
#ifdef
static voidperf_mmap__aio_munmap(struct perf_mmap *map)Quoted 7 lines
{ if (map->data) zfree(&map->data); }#else
static voidperf_mmap__aio_munmap(struct perf_mmap *map){ } #endifOk.
Quoted 15 lines
thanks,
jirkaQuoted 10 lines
tools/perf/util/mmap.c +5
-0+#endif +void perf_mmap__munmap (struct perf_mmap *map) { +#ifdef HAVE_AIO_SUPPORT +perf_mmap__aio_munmap (map); +#endif if (map->base !=NULL ) {munmap (map->base,perf_mmap__mmap_len (map)); map->base =NULL ;
Quoted 8 lines
Quoted 3 lines
tools/perf/util/mmap.c void perf_mmap__munmap(struct perf_mmap *map) · line 176
Quoted 3 lines
tools/perf/util/mmap.c +0
-0@@ -164,8 +175,40 @@ void perf_mmap__munmap(struct perf_mmap *map)auxtrace_mmap__munmap (&map->auxtrace_mmap); }Well, let's go with stub functions design as opposite to pure conditional compilation. However this may, probably, result in unintended Perf tool binary size growth, even if
NO_AIOis defined during compilation.
hum, empty functions are be optimized out
jirka
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 03:03:18PM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 7 lines
Quoted 5 lines
Well, let's go with stub functions design as opposite to pure conditional compilation. However this may, probably, result in unintended Perf tool binary size growth, even if
NO_AIOis defined during compilation.hum, empty functions are be optimized out
Yes, but there will be references to stubs in else branch of record__mmap_read_evlist() so I am not sure that *all* compilers are smart enough to recognize and still optimize it out.
Thanks,
Alexey
Quoted 3 lines
jirka
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Quoted 11 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 03:03:18PM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 6 lines
Quoted 5 lines
Well, let's go with stub functions design as opposite to pure conditional compilation. However this may, probably, result in unintended Perf tool binary size growth, even if
NO_AIOis defined during compilation.
Quoted 5 lines
Quoted 1 line
hum, empty functions are be optimized out
Yes, but there will be references to stubs in else branch of
record__mmap_read_evlist()so I am not sure that *all* compilers are smart enough to recognize and still optimize it out.
well, kernel is doing that and it seem to be fine, so I wouldn't worry about it
jirka
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Hi,
Quoted 12 lines · Jiri Olsa
Quoted 11 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 03:03:18PM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 6 lines
Quoted 5 lines
Well, let's go with stub functions design as opposite to pure conditional compilation. However this may, probably, result in unintended Perf tool binary size growth, even if
NO_AIOis defined during compilation.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
hum, empty functions are be optimized out
Yes, but there will be references to stubs in else branch of
record__mmap_read_evlist()so I am not sure that *all* compilers are smart enough to recognize and still optimize it out.well, kernel is doing that and it seem to be fine, so I wouldn't worry about it
Then, Ok. Good to know.
Thanks,
Alexey
Quoted 3 lines
jirka
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
In reply to Alexey BudankovOn Mon, Oct 08, 2018 at 09:14:29AM +0300, Alexey Budankov wrote:
SNIP
Quoted 16 lines
static int
overwrite_rb_find_range(void *buf, int mask, u64 *start, u64 *end)tools/perf/util/mmap.h +3
-0@@ -6,6 +6,9 @@#include <linux/types.h> #include <asm/barrier.h> #include <stdbool.h> +#ifdef HAVE_AIO_SUPPORT +#include <aio.h> +#endif #include "auxtrace.h" #include "event.h"
tools/perf/util/mmap.h struct perf_mmap { · line 36
Quoted 8 lines
tools/perf/util/mmap.h +5
-0@@ -26,6 +29,11 @@ struct perf_mmap {bool overwrite;struct auxtrace_mmap auxtrace_mmap;char event_copy[PERF_SAMPLE_MAX_SIZE ]__aligned(8) ; +#ifdef HAVE_AIO_SUPPORT +void *data; +struct aiocb cblock; +int nr_cblocks; +#endif
could you please separate those in struct, maybe anonymous like:
...
struct {
void *data;
struct aiocb cblock;
int nr_cblocks;
} aio;
...tools/perf/util/mmap.h enum bkw_mmap_state { · line 72
Quoted 10 lines
tools/perf/util/mmap.h +3
-0};/* @@ -59,6 +67,9 @@ enum bkw_mmap_state {struct mmap_params {int prot, mask;struct auxtrace_mmap_params auxtrace_mp; +#ifdef HAVE_AIO_SUPPORT +int nr_cblocks; +#endif
I dont think we need the ifdef here.. IMO one extra int is not worth of the ifdef endif confusion
jirka
Re: [PATCH v11 1/3]: perf util: map data buffer for preserving collected data
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:14:29AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 11 lines
could you please separate those in struct, maybe anonymous like:
... struct { void *data; struct aiocb cblock; int nr_cblocks; } aio; ...
Accepted.
Quoted 14 lines
tools/perf/util/mmap.h enum bkw_mmap_state { · line 72
Quoted 11 lines
};
/*
tools/perf/util/mmap.h +3
-0@@ -59,6 +67,9 @@ enum bkw_mmap_state {struct mmap_params {int prot, mask;struct auxtrace_mmap_params auxtrace_mp; +#ifdef HAVE_AIO_SUPPORT +int nr_cblocks; +#endif I dont think we need the ifdef here.. IMO one extra int is not worth of the ifdef endif confusion
Accepted.
Thanks,
Alexey
Quoted 3 lines
jirka
PATCH v11 2/3 : perf record: enable asynchronous trace writing
In reply to Alexey BudankovTrace file offset is read once before mmaps iterating loop and written back after all performance data enqueued for aio writing. Trace file offset is incremented linearly after every successful aio write operation.
record__aio_sync() blocks till completion of started AIO operation and then proceeds.
record__mmap_read_sync() implements a barrier for all incomplete aio write requests.
---
Changes in v11:
- replacing the both lseek() syscalls in every loop iteration by the only
two syscalls just before and after the loop at record__mmap_read_evlist() and advancing *in-flight* off file pos value at perf_mmap__aio_push()
Changes in v10:
- avoided lseek() setting file pos back in case of record__aio_write() failure
- compacted code selecting between serial and AIO streaming
- optimized call places of record__mmap_read_sync()
Changes in v9:
- enable AIO streaming only when --aio-cblocks option is specified explicitly Changes in v8:
- split AIO completion check into separate record__aio_complete()
Changes in v6:
- handled errno == EAGAIN case from aio_write();
Changes in v5:
- data loss metrics decreased from 25% to 2x in trialed configuration;
- avoided nanosleep() prior calling aio_suspend();
- switched to per cpu multi record__aio_sync() aio
- record_mmap_read_sync() now does global barrier just before
switching trace file or collection stop;
- resolved livelock on perf record -e intel_pt// -- dd if=/dev/zero of=/dev/null count=100000 Changes in v4:
- converted void *bf to struct perf_mmap *md in signatures
- written comment in perf_mmap__push() just before perf_mmap__get();
- written comment in record__mmap_read_sync() on possible restarting
of aio_write() operation and releasing perf_mmap object after all;
- added perf_mmap__put() for the cases of failed aio_write();
Changes in v3:
- written comments about nanosleep(0.5ms) call prior aio_suspend()
to cope with intrusiveness of its implementation in glibc;
- written comments about rationale behind coping profiling data
into mmap->data buffer;
--- tools/perf/builtin-record.c | 168 ++++++++++++++++++++++++++++++++++++++++++-- tools/perf/perf.h | 3 + tools/perf/util/mmap.c | 76 ++++++++++++++++++++ tools/perf/util/mmap.h | 5 ++ 4 files changed, 246 insertions(+), 6 deletions(-)
tools/perf/builtin-record.c +162 -6
@@ -124,6 +124,112 @@ static int record__write(struct record *rec, struct perf_mmap *map __maybe_unusereturn 0 ; } +#ifdef HAVE_AIO_SUPPORT +static int record__aio_write (struct aiocb *cblock,int trace_fd, +void *buf,size_t size,off_t off) +{ +int rc; + + cblock->aio_fildes = trace_fd; + cblock->aio_buf = buf; + cblock->aio_nbytes = size; + cblock->aio_offset = off; + cblock->aio_sigevent.sigev_notify =SIGEV_NONE ; + +do { + rc =aio_write (cblock); +if (rc ==0 ) { +break ; + }else if (errno !=EAGAIN ) { + cblock->aio_fildes =-1 ; +pr_err ("failed to queue perf data, error: %m\n" ); +break ; + } + }while (1 ); + +return rc; +} + +static int record__aio_complete (struct perf_mmap *md,struct aiocb *cblock) +{ +void *rem_buf; +off_t rem_off; +size_t rem_size; +int rc, aio_errno; +ssize_t aio_ret, written; + + aio_errno =aio_error (cblock); +if (aio_errno ==EINPROGRESS ) +return 0 ; + + written = aio_ret =aio_return (cblock); +if (aio_ret <0 ) { +if (aio_errno !=EINTR ) +pr_err ("failed to write perf data, error: %m\n" ); + written =0 ; + } + + rem_size = cblock->aio_nbytes - written; + +if (rem_size ==0 ) { + cblock->aio_fildes =-1 ; +/* +* md->refcount is incremented in perf_mmap__push() for +* every enqueued aio write request so decrement it because +* the request is now complete. +*/ +perf_mmap__put (md); + rc =1 ; + }else { +/* +* aio write request may require restart with the +* reminder if the kernel didn't write whole +* chunk at once. +*/ + rem_off = cblock->aio_offset + written; + rem_buf = (void *)(cblock->aio_buf + written); +record__aio_write (cblock, cblock->aio_fildes, + rem_buf, rem_size, rem_off); + rc =0 ; + } + +return rc; +} + +static void record__aio_sync (struct perf_mmap *md) +{ +struct aiocb *cblock = &md->cblock; +struct timespec timeout = {0 ,1000 *1000 *1 };/* 1ms */ + +do { +if (cblock->aio_fildes ==-1 ||record__aio_complete (md, cblock)) +return ; + +while (aio_suspend ((const struct aiocb **)&cblock,1 , &timeout)) { +if (!(errno ==EAGAIN || errno ==EINTR )) +pr_err ("failed to sync perf data, error: %m\n" ); + } + }while (1 ); +} + +static int record__aio_pushfn (void *to,struct aiocb *cblock,void *bf,size_t size,off_t off) +{ +struct record *rec = to; +int ret, trace_fd = rec->session->data->file.fd; + + rec->samples++; + + ret =record__aio_write (cblock, trace_fd, bf, size, off); +if (!ret) { + rec->bytes_written += size; +if (switch_output_size (rec)) +trigger_hit (&switch_output_trigger); + } + +return ret; +} +#endif + static int process_synthesized_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample __maybe_unused,
@@ -136,7 +242,6 @@ static int process_synthesized_event(struct perf_tool *tool,static int record__pushfn (struct perf_mmap *map,void *to,void *bf,size_t size) {struct record *rec = to; - rec->samples++;return record__write (rec, map, bf, size); }
@@ -513,6 +618,25 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; +#ifdef HAVE_AIO_SUPPORT +static void record__mmap_read_sync (struct record *rec) +{ +int i; +struct perf_evlist *evlist = rec->evlist; +struct perf_mmap *maps = evlist->mmap; + +if (!rec->opts.nr_cblocks) +return ; + +for (i =0 ; i < evlist->nr_mmaps; i++) { +struct perf_mmap *map = &maps[i]; + +if (map->base) +record__aio_sync (map); + } +} +#endif +static int record__mmap_read_evlist (struct record *rec,struct perf_evlist *evlist,bool overwrite) {
@@ -520,7 +644,10 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliint i;int rc =0 ;struct perf_mmap *maps; - +#ifdef HAVE_AIO_SUPPORT +int trace_fd = rec->data.file.fd; +off_t off; +#endif if (!evlist)return 0 ;
@@ -531,14 +658,34 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliif (overwrite && evlist->bkw_mmap_state !=BKW_MMAP_DATA_PENDING )return 0 ; +#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif for (i =0 ; i < evlist->nr_mmaps; i++) {struct perf_mmap *map = &maps[i];if (map->base) { -if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { - rc =-1 ; - goto out; +#ifdef HAVE_AIO_SUPPORT +if (!rec->opts.nr_cblocks) { +#endif +if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { + rc =-1 ; + goto out; + } +#ifdef HAVE_AIO_SUPPORT + }else { +/* +* Call record__aio_sync() to wait till map->data buffer +* becomes available after previous aio write request. +*/ +record__aio_sync (map); +if (perf_mmap__aio_push (map, rec, record__aio_pushfn, &off) !=0 ) { +lseek (trace_fd, off,SEEK_SET ); + rc =-1 ; + goto out; + } } +#endif } if (map->auxtrace_mmap.base && !rec->opts.auxtrace_snapshot_mode &&
@@ -547,7 +694,9 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli goto out; } } - +#ifdef HAVE_AIO_SUPPORT +lseek (trace_fd, off,SEEK_SET ); +#endif /* * Mark the round finished in case we wrote * at least one event.
@@ -650,6 +799,9 @@ record__switch_output(struct record *rec, bool at_exit)/* Same Size: "2015122520103046"*/ char timestamp[] ="InvalidTimestamp" ; +#ifdef HAVE_AIO_SUPPORT +record__mmap_read_sync (rec); +#endif record__synthesize (rec, true);if (target__none (&rec->opts.target))record__synthesize_workload (rec, true);
@@ -1157,6 +1309,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)record__synthesize_workload (rec, true); out_child: + +#ifdef HAVE_AIO_SUPPORT +record__mmap_read_sync (rec ); +#endif if (forks) {int exit_status;
tools/perf/perf.h +3 -0
@@ -82,6 +82,9 @@ struct record_opts {bool use_clockid;clockid_t clockid;unsigned int proc_map_timeout; +#ifdef HAVE_AIO_SUPPORT +int nr_cblocks; +#endif };struct option ;
tools/perf/util/mmap.c +76 -0
82 lines not on this page · raw message
tools/perf/util/mmap.h +5 -0
@@ -105,6 +105,11 @@ union perf_event *perf_mmap__read_event(struct perf_mmap *map);int perf_mmap__push (struct perf_mmap *md,void *to,int push (struct perf_mmap *map,void *to,void *buf,size_t size)); +#ifdef HAVE_AIO_SUPPORT +int perf_mmap__aio_push (struct perf_mmap *md,void *to, +int push (void *to,struct aiocb *cblock,void *buf,size_t size,off_t off), +off_t *off); +#endif size_t perf_mmap__mmap_len (struct perf_mmap *map);
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 8 lines
tools/perf/builtin-record.c +3
-1- +#ifdef HAVE_AIO_SUPPORT +lseek (trace_fd, off,SEEK_SET ); +#endif /* * Mark the round finished in case we wrote * at least one event.
tools/perf/builtin-record.c record__switch_output(struct record *rec, bool at_exit) · line 804
Quoted 6 lines
tools/perf/builtin-record.c +3
-0@@ -650,6 +799,9 @@ record__switch_output(struct record *rec, bool at_exit)/* Same Size: "2015122520103046"*/ char timestamp[] ="InvalidTimestamp" ; +#ifdef HAVE_AIO_SUPPORT +record__mmap_read_sync (rec); +#endif
same, please define the record__mmap_read_sync dummy so we can skip that #ifdef #endif
tools/perf/builtin-record.c static int __cmd_record(struct record *rec, int argc, const char **argv) · line 1315
Quoted 11 lines
tools/perf/builtin-record.c +4
-0record__synthesize (rec, true);if (target__none (&rec->opts.target))record__synthesize_workload (rec, true);@@ -1157,6 +1309,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)record__synthesize_workload (rec, true); out_child: + +#ifdef HAVE_AIO_SUPPORT +record__mmap_read_sync (rec ); +#endif
ditto
thanks,
jirka
SNIP
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Hi,
Quoted 15 lines · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 11 lines
tools/perf/builtin-record.c +3
-1- +#ifdef HAVE_AIO_SUPPORT +lseek (trace_fd, off,SEEK_SET ); +#endif /* * Mark the round finished in case we wrote * at least one event. @@ -650,6 +799,9 @@ record__switch_output(struct record *rec, bool at_exit)/* Same Size: "2015122520103046"*/ char timestamp[] ="InvalidTimestamp" ;
Quoted 6 lines
tools/perf/builtin-record.c record__switch_output(struct record *rec, bool at_exit) · line 804
Quoted 3 lines
tools/perf/builtin-record.c +3
-0+#ifdef HAVE_AIO_SUPPORT +record__mmap_read_sync (rec); +#endif same, please define the
record__mmap_read_syncdummy so we can skip that #ifdef #endif
Accepted.
Quoted 7 lines
Quoted 7 lines
tools/perf/builtin-record.c +0
-0record__synthesize (rec, true);if (target__none (&rec->opts.target))record__synthesize_workload (rec, true);@@ -1157,6 +1309,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)record__synthesize_workload (rec, true);
Quoted 7 lines
tools/perf/builtin-record.c static int __cmd_record(struct record *rec, int argc, const char **argv) · line 1315
Quoted 5 lines
tools/perf/builtin-record.c +4
-0out_child: + +#ifdef HAVE_AIO_SUPPORT +record__mmap_read_sync (rec ); +#endif ditto
Accepted.
Thanks,
Alexey
Quoted 6 lines
thanks,
jirkaSNIP
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
In reply to Alexey BudankovOn Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 6 lines
struct option;
tools/perf/util/mmap.c +0
-0
tools/perf/util/mmap.c int perf_mmap__push(struct perf_mmap *md, void *to, · line 374
Quoted 8 lines
tools/perf/util/mmap.c +5
-0@@ -367,6 +367,82 @@ int perf_mmap__push(struct perf_mmap *md, void *to,return rc; } +#ifdef HAVE_AIO_SUPPORT +int perf_mmap__aio_push (struct perf_mmap *md,void *to, +int push (void *to,struct aiocb *cblock,void *buf,size_t size,off_t off), +off_t *off) +{
seems like this could be defined static within builtin-record object, is there a reason why it's in here?
thanks,
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Hi,
Quoted 13 lines · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 9 lines
struct option;
tools/perf/util/mmap.c +0
-0@@ -367,6 +367,82 @@ int perf_mmap__push(struct perf_mmap *md, void *to,return rc; }
Quoted 8 lines
tools/perf/util/mmap.c int perf_mmap__push(struct perf_mmap *md, void *to, · line 374
Quoted 5 lines
tools/perf/util/mmap.c +5
-0+#ifdef HAVE_AIO_SUPPORT +int perf_mmap__aio_push (struct perf_mmap *md,void *to, +int push (void *to,struct aiocb *cblock,void *buf,size_t size,off_t off), +off_t *off) +{seems like this could be defined static within builtin-record object, is there a reason why it's in here?
The reason is analogy with perf_mmap__push() above.
Thanks,
Alexey
Quoted 4 lines
thanks,
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
In reply to Alexey BudankovOn Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 16 lines
static int record__mmap_read_evlist(struct record *rec, struct
perf_evlist*evlist,tools/perf/builtin-record.c +4
-1bool overwrite) {@@ -520,7 +644,10 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliint i;int rc =0 ;struct perf_mmap *maps; - +#ifdef HAVE_AIO_SUPPORT +int trace_fd = rec->data.file.fd; +off_t off; +#endif if (!evlist)return 0 ;
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 663
Quoted 6 lines
tools/perf/builtin-record.c +3
-0@@ -531,14 +658,34 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliif (overwrite && evlist->bkw_mmap_state !=BKW_MMAP_DATA_PENDING )return 0 ; +#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif
I'm still little puzzled why we need to do this,
when the aio write takes the offset value, but
please provide some aio_.. function for this
Quoted 32 lines
tools/perf/builtin-record.c +20
-3for (i =0 ; i < evlist->nr_mmaps; i++) {struct perf_mmap *map = &maps[i];if (map->base) { -if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { - rc =-1 ; - goto out; +#ifdef HAVE_AIO_SUPPORT +if (!rec->opts.nr_cblocks) { +#endif +if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { + rc =-1 ; + goto out; + } +#ifdef HAVE_AIO_SUPPORT + }else { +/* +* Call record__aio_sync() to wait till map->data buffer +* becomes available after previous aio write request. +*/ +record__aio_sync (map); +if (perf_mmap__aio_push (map, rec, record__aio_pushfn, &off) !=0 ) { +lseek (trace_fd, off,SEEK_SET ); + rc =-1 ; + goto out; + } } +#endif } if (map->auxtrace_mmap.base && !rec->opts.auxtrace_snapshot_mode &&
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 699
Quoted 7 lines
tools/perf/builtin-record.c +3
-1@@ -547,7 +694,9 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli goto out; } } - +#ifdef HAVE_AIO_SUPPORT +lseek (trace_fd, off,SEEK_SET ); +#endif
ditto
thanks,
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 6 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 663
Quoted 3 lines
tools/perf/builtin-record.c +3
-0+#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif I'm still little puzzled why we need to do this,
when the aio write takes the offset value, but
pwrite() syscall [1] which is the base for aio_write() doesn't advance file pos value so it requires to be calculated and updated by callers of aio_write() API.
Quoted 1 line
please provide some
aio_.. function for this
Accepted.
Quoted 32 lines
Quoted 32 lines
tools/perf/builtin-record.c +20
-3for (i =0 ; i < evlist->nr_mmaps; i++) {struct perf_mmap *map = &maps[i];if (map->base) { -if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { - rc =-1 ; - goto out; +#ifdef HAVE_AIO_SUPPORT +if (!rec->opts.nr_cblocks) { +#endif +if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { + rc =-1 ; + goto out; + } +#ifdef HAVE_AIO_SUPPORT + }else { +/* +* Call record__aio_sync() to wait till map->data buffer +* becomes available after previous aio write request. +*/ +record__aio_sync (map); +if (perf_mmap__aio_push (map, rec, record__aio_pushfn, &off) !=0 ) { +lseek (trace_fd, off,SEEK_SET ); + rc =-1 ; + goto out; + } } +#endif }
Quoted 11 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 699
Quoted 9 lines
tools/perf/builtin-record.c +3
-1if (map->auxtrace_mmap.base && !rec->opts.auxtrace_snapshot_mode &&@@ -547,7 +694,9 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli goto out; } } - +#ifdef HAVE_AIO_SUPPORT +lseek (trace_fd, off,SEEK_SET ); +#endif ditto
Accepted.
Thanks,
Alexey
Quoted 4 lines
thanks,
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Quoted 12 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 6 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 663
Quoted 3 lines
tools/perf/builtin-record.c +3
-0+#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif I'm still little puzzled why we need to do this,
when the aio write takes the offset value, but
Quoted 3 lines
pwrite()syscall [1] which is the base foraio_write()doesn't advance file pos value so it requires to be calculated and updated by callers ofaio_write()API.
ok, so aio_write does not need the offset to be updated, who needs it then?
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Hi,
Quoted 13 lines · Jiri Olsa
Quoted 12 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 6 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 663
Quoted 3 lines
tools/perf/builtin-record.c +3
-0+#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif I'm still little puzzled why we need to do this,
when the aio write takes the offset value, but
Quoted 6 lines
Quoted 3 lines
pwrite()syscall [1] which is the base foraio_write()doesn't advance file pos value so it requires to be calculated and updated by callers ofaio_write()API.ok, so
aio_writedoes not need the offset to be updated, who needs it then?
aio_write() needs this offset as an input parameter. aio_write() gets offset as a part of cblock object. Adjacent aio_write() records should not overlap in the trace file so off value is incremented by size in every loop iteration after successful aio_write() call.
Thanks,
Alexey
Quoted 3 lines
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Quoted 19 lines · Alexey Budankov
Hi,
Quoted 17 lines · Jiri Olsa
Quoted 15 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 6 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 663
Quoted 3 lines
tools/perf/builtin-record.c +3
-0+#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif I'm still little puzzled why we need to do this,
when the aio write takes the offset value, but
pwrite()syscall [1] which is the base foraio_write()doesn't advance file pos value so it requires to be calculated and updated by callers ofaio_write()API.
Quoted 5 lines
Quoted 2 lines
ok, so
aio_writedoes not need the offset to be updated, who needs it then?
aio_write()needs this offset as an input parameter.aio_write()gets offset as a part of cblock object.
yes, it's an 'arg' to aio_write syscall
Quoted 3 lines
Adjacent
aio_write()records should not overlap in the trace file so off value is incremented by size in every loop iteration after successfulaio_write()call.
but does the aio_write need the lseek 'set' call? if not, we could keep the 'offset' value within perf (like in the struct perf_data_file or struct record) without any need to call lseek
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Hi,
Quoted 26 lines · Jiri Olsa
Quoted 19 lines · Alexey Budankov
Hi,
Quoted 17 lines · Jiri Olsa
Quoted 15 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 6 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 663
Quoted 3 lines
tools/perf/builtin-record.c +3
-0+#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif I'm still little puzzled why we need to do this,
when the aio write takes the offset value, but
pwrite()syscall [1] which is the base foraio_write()doesn't advance file pos value so it requires to be calculated and updated by callers ofaio_write()API.Quoted 5 lines
Quoted 2 lines
ok, so
aio_writedoes not need the offset to be updated, who needs it then?
aio_write()needs this offset as an input parameter.aio_write()gets offset as a part of cblock object.
Quoted 7 lines
yes, it's an 'arg' to
aio_writesyscallQuoted 3 lines
Adjacent
aio_write()records should not overlap in the trace file so off value is incremented by size in every loop iteration after successfulaio_write()call.but does the
aio_writeneed the lseek 'set' call? if not, we could
Yes, lseek(,, SEEK_SET) is still required after the loop, so the next synchronous records would go after AIO written parts that might be still *in-flight* by that time.
Thanks,
Alexey
Quoted 5 lines
keep the 'offset' value within perf (like in the struct
perf_data_fileor struct record) without any need to call lseekjirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
In reply to Alexey BudankovOn Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 40 lines
static int record__mmap_read_evlist(struct record *rec, struct
perf_evlist*evlist,tools/perf/builtin-record.c +18
-4bool overwrite) {@@ -520,7 +644,10 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliint i;int rc =0 ;struct perf_mmap *maps; - +#ifdef HAVE_AIO_SUPPORT +int trace_fd = rec->data.file.fd; +off_t off; +#endif if (!evlist)return 0 ;@@ -531,14 +658,34 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliif (overwrite && evlist->bkw_mmap_state !=BKW_MMAP_DATA_PENDING )return 0 ; +#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif for (i =0 ; i < evlist->nr_mmaps; i++) {struct perf_mmap *map = &maps[i];if (map->base) { -if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { - rc =-1 ; - goto out; +#ifdef HAVE_AIO_SUPPORT +if (!rec->opts.nr_cblocks) { +#endif +if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { + rc =-1 ; + goto out; + } +#ifdef HAVE_AIO_SUPPORT + }else { +/* +* Call record__aio_sync() to wait till map->data buffer
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 688
Quoted 10 lines
tools/perf/builtin-record.c +9
-0+* becomes available after previous aio write request. +*/ +record__aio_sync (map); +if (perf_mmap__aio_push (map, rec, record__aio_pushfn, &off) !=0 ) { +lseek (trace_fd, off,SEEK_SET ); + rc =-1 ; + goto out; + } } +#endif
I really don't like this.. let's have some aio_... function with its dummy counterpart to be called in here.. and again.. if we realyl must have this compiled optionaly, which I'm not convinced of
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Hi,
Quoted 50 lines · Jiri Olsa
On Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 46 lines
static int record__mmap_read_evlist(struct record *rec, struct
perf_evlist*evlist,tools/perf/builtin-record.c +24
-4bool overwrite) {@@ -520,7 +644,10 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliint i;int rc =0 ;struct perf_mmap *maps; - +#ifdef HAVE_AIO_SUPPORT +int trace_fd = rec->data.file.fd; +off_t off; +#endif if (!evlist)return 0 ;@@ -531,14 +658,34 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliif (overwrite && evlist->bkw_mmap_state !=BKW_MMAP_DATA_PENDING )return 0 ; +#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif for (i =0 ; i < evlist->nr_mmaps; i++) {struct perf_mmap *map = &maps[i];if (map->base) { -if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { - rc =-1 ; - goto out; +#ifdef HAVE_AIO_SUPPORT +if (!rec->opts.nr_cblocks) { +#endif +if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { + rc =-1 ; + goto out; + } +#ifdef HAVE_AIO_SUPPORT + }else { +/* +* Call record__aio_sync() to wait till map->data buffer +* becomes available after previous aio write request. +*/ +record__aio_sync (map); +if (perf_mmap__aio_push (map, rec, record__aio_pushfn, &off) !=0 ) { +lseek (trace_fd, off,SEEK_SET ); + rc =-1 ;
Quoted 8 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 688
Quoted 4 lines
tools/perf/builtin-record.c +3
-0+ goto out; + } } +#endif I really don't like this.. let's have some
aio_... function with its dummy counterpart to be called in here.. and again.. if we realyl must have this compiled optionaly, which I'm not convinced of
Accepted.
Thanks,
Alexey
Quoted 3 lines
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
In reply to Alexey BudankovOn Mon, Oct 08, 2018 at 09:17:11AM +0300, Alexey Budankov wrote:
SNIP
Quoted 22 lines
static int record__mmap_read_evlist(struct record *rec, struct
perf_evlist*evlist,tools/perf/builtin-record.c +7
-1bool overwrite) {@@ -520,7 +644,10 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliint i;int rc =0 ;struct perf_mmap *maps; - +#ifdef HAVE_AIO_SUPPORT +int trace_fd = rec->data.file.fd; +off_t off; +#endif if (!evlist)return 0 ;@@ -531,14 +658,34 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evliif (overwrite && evlist->bkw_mmap_state !=BKW_MMAP_DATA_PENDING )return 0 ; +#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 670
Quoted 10 lines
tools/perf/builtin-record.c +3
-3for (i =0 ; i < evlist->nr_mmaps; i++) {struct perf_mmap *map = &maps[i];if (map->base) { -if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { - rc =-1 ; - goto out; +#ifdef HAVE_AIO_SUPPORT +if (!rec->opts.nr_cblocks) { +#endif
maybe it'd be less confusing having something like
rec->opts.aio.enabled
or aio__is_enabled() global with the dummy counterpart
jirka
Re: [PATCH v11 2/3]: perf record: enable asynchronous trace writing
Hi,
Quoted 2 lines · Jiri Olsa
Quoted 1 line · Alexey Budankov
<SNIP>
Quoted 17 lines
tools/perf/builtin-record.c static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli · line 670
Quoted 13 lines
tools/perf/builtin-record.c +6
-3+#ifdef HAVE_AIO_SUPPORT + off =lseek (trace_fd,0 ,SEEK_CUR ); +#endif for (i =0 ; i < evlist->nr_mmaps; i++) {struct perf_mmap *map = &maps[i];if (map->base) { -if (perf_mmap__push (map, rec, record__pushfn) !=0 ) { - rc =-1 ; - goto out; +#ifdef HAVE_AIO_SUPPORT +if (!rec->opts.nr_cblocks) { +#endif maybe it'd be less confusing having something like
rec->opts.aio.enabled
Quoted 1 line
or
aio__is_enabled()global with the dummy counterpart
Makes sense. Will implement __is_enabled() function.
Thanks,
Alexey
Quoted 3 lines
jirka
PATCH v11 3/3 : perf record: extend trace writing to multi AIO
In reply to Alexey BudankovMulti AIO trace writing allows caching more kernel data into userspace memory postponing trace writing for the sake of overall profiling data thruput increase. It could be seen as kernel data buffer extension into userspace memory.
With aio-cblocks option value different from 0, current default value, tool has capability to cache more and more data into user space along with delegating spill to AIO.
That allows avoiding suspend at record__aio_sync() between calls of record__mmap_read_evlist() and increase profiling data thruput for the cost of userspace memory.
---
Changes in v10:
- added description of aio-cblocks option into perf-record.txt
--- tools/perf/Documentation/perf-record.txt | 6 +++ tools/perf/builtin-record.c | 58 +++++++++++++++++++----- tools/perf/util/evlist.c | 6 +-- tools/perf/util/evlist.h | 2 +- tools/perf/util/mmap.c | 76 ++++++++++++++++++++++---------- tools/perf/util/mmap.h | 7 +-- 6 files changed, 115 insertions(+), 40 deletions(-)
tools/perf/Documentation/perf-record.txt +6 -0
@@ -435,6 +435,12 @@ Specify vmlinux path which has debuginfo. --buildid-all:: Record build-id of all DSOs regardless whether it's actually hit or not. +--aio-cblocks <n> +Use <n> control blocks for asynchronous (Posix AIO) trace writing (max: 4). +Default value is 0 that enables serial (none-AIO) trace writing mode. +AIO mode is supported only when linking Perf tool binary with libc library +providing implementation for Posix AIO API. + --all-kernel:: Configure all used events to run in kernel space.
tools/perf/builtin-record.c +48 -10
112 lines not on this page · raw message
tools/perf/util/evlist.c +3 -3
@@ -1018,7 +1018,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,*/ int perf_evlist__mmap_ex (struct perf_evlist *evlist,unsigned int pages,unsigned int auxtrace_pages, -bool auxtrace_overwrite) +bool auxtrace_overwrite,int nr_cblocks__maybe_unused ) {struct perf_evsel *evsel;const struct cpu_map *cpus = evlist->cpus;
@@ -1030,7 +1030,7 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,*/ struct mmap_params mp;#ifdef HAVE_AIO_SUPPORT - mp.nr_cblocks =0 ; + mp.nr_cblocks = nr_cblocks;#endif if (!evlist->mmap) evlist->mmap =perf_evlist__alloc_mmap (evlist, false);
@@ -1062,7 +1062,7 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,int perf_evlist__mmap (struct perf_evlist *evlist,unsigned int pages) { -return perf_evlist__mmap_ex (evlist, pages,0 , false); +return perf_evlist__mmap_ex (evlist, pages,0 , false,0 ); }int perf_evlist__create_maps (struct perf_evlist *evlist,struct target *target)
tools/perf/util/evlist.h +1 -1
@@ -162,7 +162,7 @@ unsigned long perf_event_mlock_kb_in_pages(void);int perf_evlist__mmap_ex (struct perf_evlist *evlist,unsigned int pages,unsigned int auxtrace_pages, -bool auxtrace_overwrite); +bool auxtrace_overwrite,int nr_cblocks);int perf_evlist__mmap (struct perf_evlist *evlist,unsigned int pages);void perf_evlist__munmap (struct perf_evlist *evlist);
tools/perf/util/mmap.c +53 -23
130 lines not on this page · raw message
tools/perf/util/mmap.h +4 -3
@@ -30,8 +30,9 @@ struct perf_mmap {struct auxtrace_mmap auxtrace_mmap;char event_copy[PERF_SAMPLE_MAX_SIZE ]__aligned(8) ;#ifdef HAVE_AIO_SUPPORT -void *data; -struct aiocb cblock; +void **data; +struct aiocb *cblocks; +struct aiocb **aiocb;int nr_cblocks;#endif };
@@ -106,7 +107,7 @@ union perf_event *perf_mmap__read_event(struct perf_mmap *map);int perf_mmap__push (struct perf_mmap *md,void *to,int push (struct perf_mmap *map,void *to,void *buf,size_t size));#ifdef HAVE_AIO_SUPPORT -int perf_mmap__aio_push (struct perf_mmap *md,void *to, +int perf_mmap__aio_push (struct perf_mmap *md,void *to,int idx,int push (void *to,struct aiocb *cblock,void *buf,size_t size,off_t off),off_t *off);#endif
Re: [PATCH v11 3/3]: perf record: extend trace writing to multi AIO
On Mon, Oct 08, 2018 at 09:19:17AM +0300, Alexey Budankov wrote:
SNIP
Quoted 26 lines
#ifdef
HAVE_AIO_SUPPORTtools/perf/builtin-record.c +7
-2}else { +int idx;/* * Call record__aio_sync() to wait till map->data buffer * becomes available after previous aio write request. */ -record__aio_sync (map); -if (perf_mmap__aio_push (map, rec, record__aio_pushfn, &off) !=0 ) { + idx =record__aio_sync (map, false); +if (perf_mmap__aio_push (map, rec, idx, record__aio_pushfn, &off) !=0 ) {lseek (trace_fd, off,SEEK_SET ); rc =-1 ; goto out;@@ -1446,6 +1469,10 @@ static int perf_record_config(const char *var, const char *value, void *cb) var ="call-graph.record-mode" ;return perf_default_config (var, value, cb); } +#ifdef HAVE_AIO_SUPPORT +if (!strcmp (var,"record.aio-cblocks" )) + rec->opts.nr_cblocks =strtol (value,NULL ,0 ); +#endif return 0 ; }
tools/perf/builtin-record.c static struct option __record_options[] = { · line 1870
Quoted 7 lines
tools/perf/builtin-record.c +4
-0@@ -1837,6 +1864,10 @@ static struct option __record_options[] = { "signal"), OPT_BOOLEAN(0, "dry-run", &dry_run, "Parse options then exit"), +#ifdef HAVE_AIO_SUPPORT + OPT_INTEGER(0, "aio-cblocks", &record.opts.nr_cblocks, + "Max number of simultaneous per-mmap trace writes (default: 0 - serial, max: 4)"), +#endif
could you please move the option to enable that to the previou patch? so we could test the simple variant as well
also I think it'd be better if we have simple '--aio' option that would enable this with some default values.. and add --aio-cblocks to configure that further
thanks,
jirka
Re: [PATCH v11 3/3]: perf record: extend trace writing to multi AIO
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:19:17AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 5 lines
Quoted 5 lines
tools/perf/builtin-record.c +4
-0+#ifdef HAVE_AIO_SUPPORT +if (!strcmp (var,"record.aio-cblocks" )) + rec->opts.nr_cblocks =strtol (value,NULL ,0 ); +#endif
Quoted 13 lines
tools/perf/builtin-record.c static struct option __record_options[] = { · line 1870
Quoted 10 lines
tools/perf/builtin-record.c +4
-0return 0 ; }@@ -1837,6 +1864,10 @@ static struct option __record_options[] = { "signal"), OPT_BOOLEAN(0, "dry-run", &dry_run, "Parse options then exit"), +#ifdef HAVE_AIO_SUPPORT + OPT_INTEGER(0, "aio-cblocks", &record.opts.nr_cblocks, + "Max number of simultaneous per-mmap trace writes (default: 0 - serial, max: 4)"), +#endif could you please move the option to enable that to the previou patch? so we could test the simple variant as well
Ok.
Quoted 4 lines
also I think it'd be better if we have simple '--aio' option that would enable this with some default values.. and add --aio-cblocks to configure that further
Well, absence of --aio option, on the command line or in .perfconfig, or --aio=0 means serial writing.
From this perspective perf record --aio --aio-cblocks=N looks like a complication.
Thanks,
Alexey
Re: [PATCH v11 3/3]: perf record: extend trace writing to multi AIO
Quoted 27 lines · Alexey Budankov
Hi,
Quoted 1 line · Jiri Olsa
On Mon, Oct 08, 2018 at 09:19:17AM +0300, Alexey Budankov wrote:
<SNIP>
Quoted 5 lines
Quoted 5 lines
tools/perf/builtin-record.c +4
-0+#ifdef HAVE_AIO_SUPPORT +if (!strcmp (var,"record.aio-cblocks" )) + rec->opts.nr_cblocks =strtol (value,NULL ,0 ); +#endif Quoted 13 lines
tools/perf/builtin-record.c static struct option __record_options[] = { · line 1870
Quoted 10 lines
tools/perf/builtin-record.c +4
-0return 0 ; }@@ -1837,6 +1864,10 @@ static struct option __record_options[] = { "signal"), OPT_BOOLEAN(0, "dry-run", &dry_run, "Parse options then exit"), +#ifdef HAVE_AIO_SUPPORT + OPT_INTEGER(0, "aio-cblocks", &record.opts.nr_cblocks, + "Max number of simultaneous per-mmap trace writes (default: 0 - serial, max: 4)"), +#endif could you please move the option to enable that to the previou patch? so we could test the simple variant as well
Ok.
Quoted 1 line
Quoted 8 lines
Quoted 3 lines
also I think it'd be better if we have simple '--aio' option that would enable this with some default values.. and add --aio-cblocks to configure that further
Well, absence of --aio option, on the command line or in .perfconfig, or --aio=0 means serial writing.
From this perspective perf record --aio --aio-cblocks=N looks like a complication.
'perf record --aio-cblocks=N' could imply '--aio',
I'd like to have simple/intuitive way to enable that, without studing the meaning of the cblocks argument
# perf record --aio ...
means that I'm storing data via async writes, and using some reasonable default for cblocks
and later on we'd add 'perf record --threads' allowing threads based writers ;-)
jirka
Re: [PATCH v11 3/3]: perf record: extend trace writing to multi AIO
Hi,
On 08.10.2018 15:45, Jiri Olsa wrote:
<SNIP>
Quoted 10 lines
'perf record --aio-cblocks=N' could imply '--aio',
I'd like to have simple/intuitive way to enable that, without studing the meaning of the cblocks argument
# perf record --aio ...means that I'm storing data via async writes, and using some reasonable default for cblocks
Semantically, --aio is equal to --aio-cblocks=default, as you said. So, options duplication could be avoided by having some parsing callback using OPT_CALLBACK().
Quoted 3 lines
and later on we'd add 'perf record --threads' allowing threads based writers ;-)
Oh, I see. Cool.
Thanks,
Alexey
Quoted 3 lines
jirka