Hi Arnaldo,
This patch set is based on today's perf/core. It contains 3 parts:
1. Bugfix in my local tree. Most of them are resent (patch 1 - 17).
2. BPF related improvement. Also, you should have read them last
year. Nearly no change (18 - 26).
3. The most exciting feature I'd like to introduce to you and others:
perf record overwrite mode support:
This feature is based on a patch which is discussed but not merged
yet [1]. I also send it in this series as patch 27. In this patch,
kernel appends the size of an event at the end of the event data
in the ring buffer, which enables us reading as much data as
possible from a overwrite ring buffer, so it works like a flight
recorder. Patch 28 - 53 add support of it. This is an example:
# perf record -a -e cycles/overwrite/ \
-e raw_syscalls:sys_enter/overwrite/ \
-e raw_syscalls:sys_exit/overwrite/ \
-e sched:sched_switch/overwrite/ \
--switch-output --tail-tracking
Then send 3 SIGUSR2 to 'perf' in another console:
# kill -s SIGUSR2 `ps -e | grep 'pts.*perf' | awk '{print $1}'`
[ perf record: dump data: Woken up 1 times ]
[ perf record: Dump perf.data.2016011205392208 ]
[ perf record: dump data: Woken up 1 times ]
[ perf record: Dump perf.data.2016011205392597 ]
[ perf record: dump data: Woken up 1 times ]
[ perf record: Dump perf.data.2016011205392906 ]
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Dump perf.data.2016011205393040
Here's the result:
# ls -l ./perf.data.*
-rw------- 1 root root 4284861 Jan 12 05:39
./perf.data.2016011205392208
-rw------- 1 root root 4578477 Jan 12 05:39
./perf.data.2016011205392597
-rw------- 1 root root 4602757 Jan 12 05:39
./perf.data.2016011205392906
-rw------- 1 root root 5655429 Jan 12 05:39
./perf.data.2016011205393040
In each perf.data output, we get about 4M events before it receives
signal.
This should be useful if we have a extra monitor checks performance
metrics. When it found something unusual, it can send a SIGUSR2 to
perf to collect data near the bad things happen.
My next step is trying to trigger event dumping using eBPF. Then we can
triggeer a perf.data output immediately after a system call takes too
long or when we detect a losting of a display update.
Patch 28 - 40 add a switch-output mode, make perf dump a new perf.data
when it receive a SIGUSR2.
Patch 41 - 45 introduce a concept called 'channel', which allows perf to
collect data through more than one group of mmaped ring buffer with different
configurations.
Patch 46 - 53 are the core of flight record mode. Patch 51 does real
reading from flight recorder ring buffer.
[1] http://lkml.kernel.org/g/1452518653-1794-1-git-send-email-wangnan0@huawei.com
He Kuang (1):
perf tools: Support perf event alias name
Jiri Olsa (1):
perf tools: Add missing sources in perf's MANIFEST
Naveen N. Rao (1):
perf: bpf: Fix build breakage due to libbpf
Wang Nan (50):
perf tools: Add -lutil in python lib list for broken python-config
perf tools: Fix phony build target for build-test
perf tools: Set parallel making options build-test
perf tools: Pass O option to Makefile.perf in build-test
perf tools: Test correct path of perf in build-test
perf tools: Fix PowerPC native building
tools: Move Makefile.arch from perf/config to tools/scripts
tools build: Add BPF feature check to test-all
perf test: Fix false TEST_OK result for 'perf test hist'
perf test: Reset err after using it hold errcode in hist testcases
perf tools: Prevent calling machine__delete() on non-allocated machine
perf test: Check environment before start real BPF test
perf tools: Fix symbols searching for offline module in buildid-cache
perf tools: Fix mmap2 event allocation in synthesize code
perf test: Improve bp_signal
perf tools: Add API to config maps in bpf object
perf tools: Enable BPF object configure syntax
perf record: Apply config to BPF objects before recording
perf tools: Enable passing event to BPF object
perf tools: Support setting different slots in a BPF map separately
perf tools: Enable indices setting syntax for BPF maps
perf tools: Introduce bpf-output event
perf data: Support converting data from bpf_perf_event_output()
perf/core: Put size of a sample at the end of it by
PERF_SAMPLE_TAILSIZE
perf tools: Move timestamp creation to util
perf tools: Make ordered_events reusable
perf record: Extract synthesize code to record__synthesize()
perf tools: Add perf_data_file__switch() helper
perf record: Turns auxtrace_snapshot_enable into 3 states
perf record: Introduce record__finish_output() to finish a perf.data
perf record: Use OPT_BOOLEAN_SET for buildid cache related options
perf record: Add '--timestamp-filename' option to append timestamp to
output filename
perf record: Split output into multiple files via '--switch-output'
perf record: Force enable --timestamp-filename when --switch-output is
provided
perf record: Disable buildid cache options by default in switch output
mode
perf record: Re-synthesize tracking events after output switching
perf record: Generate tracking events for process forked by perf
perf record: Ensure return non-zero rc when mmap fail
perf record: Prevent reading invalid data in record__mmap_read
perf tools: Add evlist channel helpers
perf tools: Automatically add new channel according to evlist
perf tools: Operate multiple channels
perf tools: Squash overwrite setting into channel
perf record: Don't read from and poll overwrite channel
perf tools: Enable overwrite settings
perf tools: Consider TAILSIZE bit when caclulate is_pos
perf tools: Set tailsize attribut bit for overwrite events
perf record: Read from tailsize ring buffer
perf record: Toggle tailsize ring buffer for reading
perf record: Allow generate tracking events at the end of output
include/linux/perf_event.h | 17 +-
include/uapi/linux/perf_event.h | 3 +-
kernel/events/core.c | 82 +++-
kernel/events/ring_buffer.c | 7 +-
tools/build/feature/test-all.c | 5 +
tools/build/feature/test-bpf.c | 20 +-
tools/lib/bpf/Makefile | 16 +-
tools/lib/bpf/bpf.c | 4 +-
tools/perf/MANIFEST | 2 +
tools/perf/builtin-buildid-cache.c | 14 +-
tools/perf/builtin-record.c | 549 +++++++++++++++++----
tools/perf/config/Makefile | 4 +-
tools/perf/perf.h | 1 +
tools/perf/tests/bp_signal.c | 140 +++++-
tools/perf/tests/bpf.c | 37 ++
tools/perf/tests/hists_common.c | 5 -
tools/perf/tests/hists_cumulate.c | 1 +
tools/perf/tests/hists_filter.c | 1 +
tools/perf/tests/hists_link.c | 1 +
tools/perf/tests/hists_output.c | 1 +
tools/perf/tests/make | 72 ++-
tools/perf/tests/vmlinux-kallsyms.c | 4 +-
tools/perf/util/bpf-loader.c | 699 +++++++++++++++++++++++++++
tools/perf/util/bpf-loader.h | 59 +++
tools/perf/util/build-id.c | 44 ++
tools/perf/util/build-id.h | 1 +
tools/perf/util/data-convert-bt.c | 112 ++++-
tools/perf/util/data.c | 36 ++
tools/perf/util/data.h | 11 +-
tools/perf/util/event.c | 28 +-
tools/perf/util/evlist.c | 307 ++++++++++--
tools/perf/util/evlist.h | 67 ++-
tools/perf/util/evsel.c | 42 +-
tools/perf/util/evsel.h | 13 +
tools/perf/util/machine.c | 13 +-
tools/perf/util/machine.h | 3 +-
tools/perf/util/ordered-events.c | 9 +
tools/perf/util/ordered-events.h | 1 +
tools/perf/util/parse-events.c | 139 +++++-
tools/perf/util/parse-events.h | 24 +-
tools/perf/util/parse-events.l | 18 +-
tools/perf/util/parse-events.y | 123 ++++-
tools/perf/util/session.c | 4 +-
tools/perf/util/symbol.c | 4 +
tools/perf/util/util.c | 17 +
tools/perf/util/util.h | 1 +
tools/{perf/config => scripts}/Makefile.arch | 0
47 files changed, 2482 insertions(+), 279 deletions(-)
rename tools/{perf/config => scripts}/Makefile.arch (100%)
--
1.8.3.4
This patch introduces a PERF_SAMPLE_TAILSIZE flag which allows a size
field attached at the end of a sample. The idea comes from [1] that,
with tie size at tail of an event, it is possible for user program who
read from the ring buffer parse events backward.
For example:
head
|
V
+--+---+-------+----------+------+---+
|E6|...| B 8| C 11| D 7|E..|
+--+---+-------+----------+------+---+
In this case, from the 'head' pointer provided by kernel, user program
can first see '6' by (*(head - sizeof(u64))), then it can get the start
pointer of record 'E', then it can read size and find start position
of record D, C, B in similar way.
The implementation is easy: adding a PERF_SAMPLE_TAILSIZE flag, makes
perf_output_sample() output size at the end of a sample.
Following things are done for ensure the ring buffer is safe for
backward parsing:
- Don't allow two events with different PERF_SAMPLE_TAILSIZE setting
set their output to each other;
- For non-sample events, also output tailsize if required.
This patch has a limitation for perf:
Before reading such ring buffer, perf must ensure all events which may
output to it is already stopped, so the 'head' pointer it get is the
end of the last record.
[1] http://lkml.kernel.org/g/1449063499-236703-1-git-send-email-wangnan0@huawei.com
Signed-off-by: Wang Nan <redacted>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: David Ahern <redacted>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <redacted>
Cc: Yunlong Song <redacted>
---
include/linux/perf_event.h | 17 ++++++---
include/uapi/linux/perf_event.h | 3 +-
kernel/events/core.c | 82 +++++++++++++++++++++++++++++------------
kernel/events/ring_buffer.c | 7 ++--
4 files changed, 75 insertions(+), 34 deletions(-)
@@ -5407,6 +5411,13 @@ void perf_output_sample(struct perf_output_handle *handle,}}+/* Should be the last one */+if(sample_type&PERF_SAMPLE_TAILSIZE){+u64evt_size=header->size;++perf_output_put(handle,evt_size);+}+if(!event->attr.watermark){intwakeup_events=event->attr.wakeup_events;
@@ -352,6 +352,84 @@ static int add_tracepoint_values(struct ctf_writer *cw,returnret;}+staticint+add_bpf_output_values(structbt_ctf_event_class*event_class,+structbt_ctf_event*event,+structperf_sample*sample)+{+structbt_ctf_field_type*len_type,*seq_type;+structbt_ctf_field*len_field,*seq_field;+unsignedintraw_size=sample->raw_size;+unsignedintnr_elements=raw_size/sizeof(u32);+unsignedinti;+intret;++if(nr_elements*sizeof(u32)!=raw_size)+pr_warning("Incorrect raw_size (%u) in bpf output event, skip %lu bytes\n",+raw_size,nr_elements*sizeof(u32)-raw_size);++len_type=bt_ctf_event_class_get_field_by_name(event_class,"raw_len");+len_field=bt_ctf_field_create(len_type);+if(!len_field){+pr_err("failed to create 'raw_len' for bpf output event\n");+ret=-1;+gotoput_len_type;+}++ret=bt_ctf_field_unsigned_integer_set_value(len_field,nr_elements);+if(ret){+pr_err("failed to set field value for raw_len\n");+gotoput_len_field;+}+ret=bt_ctf_event_set_payload(event,"raw_len",len_field);+if(ret){+pr_err("failed to set payload to raw_len\n");+gotoput_len_field;+}++seq_type=bt_ctf_event_class_get_field_by_name(event_class,"raw_data");+seq_field=bt_ctf_field_create(seq_type);+if(!seq_field){+pr_err("failed to create 'raw_data' for bpf output event\n");+ret=-1;+gotoput_seq_type;+}++ret=bt_ctf_field_sequence_set_length(seq_field,len_field);+if(ret){+pr_err("failed to set length of 'raw_data'\n");+gotoput_seq_field;+}++for(i=0;i<nr_elements;i++){+structbt_ctf_field*elem_field=+bt_ctf_field_sequence_get_field(seq_field,i);++ret=bt_ctf_field_unsigned_integer_set_value(elem_field,+((u32*)(sample->raw_data))[i]);++bt_ctf_field_put(elem_field);+if(ret){+pr_err("failed to set raw_data[%d]\n",i);+gotoput_seq_field;+}+}++ret=bt_ctf_event_set_payload(event,"raw_data",seq_field);+if(ret)+pr_err("failed to set payload for raw_data\n");++put_seq_field:+bt_ctf_field_put(seq_field);+put_seq_type:+bt_ctf_field_type_put(seq_type);+put_len_field:+bt_ctf_field_put(len_field);+put_len_type:+bt_ctf_field_type_put(len_type);+returnret;+}+staticintadd_generic_values(structctf_writer*cw,structbt_ctf_event*event,structperf_evsel*evsel,
@@ -597,6 +675,12 @@ static int process_sample_event(struct perf_tool *tool,return-1;}+if(perf_evsel__is_bpf_output(evsel)){+ret=add_bpf_output_values(event_class,event,sample);+if(ret)+return-1;+}+cs=ctf_stream(cw,get_sample_cpu(cw,sample,evsel));if(cs){if(is_flush_needed(cs))
@@ -744,6 +828,25 @@ static int add_tracepoint_types(struct ctf_writer *cw,returnret;}+staticintadd_bpf_output_types(structctf_writer*cw,+structbt_ctf_event_class*class)+{+structbt_ctf_field_type*len_type=cw->data.u32;+structbt_ctf_field_type*seq_base_type=cw->data.u32_hex;+structbt_ctf_field_type*seq_type;+intret;++ret=bt_ctf_event_class_add_field(class,len_type,"raw_len");+if(ret)+returnret;++seq_type=bt_ctf_field_type_sequence_create(seq_base_type,"raw_len");+if(!seq_type)+return-1;++returnbt_ctf_event_class_add_field(class,seq_type,"raw_data");+}+staticintadd_generic_types(structctf_writer*cw,structperf_evsel*evsel,structbt_ctf_event_class*event_class){
@@ -824,6 +928,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)gotoerr;}+if(perf_evsel__is_bpf_output(evsel)){+ret=add_bpf_output_types(cw,event_class);+if(ret)+gotoerr;+}+ret=bt_ctf_stream_class_add_event_class(cw->stream_class,event_class);if(ret){pr("Failed to add event class into stream.\n");
bpf__apply_obj_config() is introduced as the core API to apply object
config options to all BPF objects. This patch also does the real work
for setting values for BPF_MAP_TYPE_PERF_ARRAY maps by inserting value
stored in map's private field into the BPF map.
This patch is required because we are not always able to set all
BPF config during parsing. Further patch will set events created
by perf to BPF_MAP_TYPE_PERF_EVENT_ARRAY maps, which is not exist
until perf_evsel__open().
bpf_map_foreach_key() is introduced to iterate over each key
needs to be configured. This function would be extended to support
more map types and different key settings.
In perf record, before start recording, call bpf__apply_config() to
turn on all BPF config options.
Test result:
# cat ./test_bpf_map_1.c
/************************ BEGIN **************************/
#include <uapi/linux/bpf.h>
#define SEC(NAME) __attribute__((section(NAME), used))
struct bpf_map_def {
unsigned int type;
unsigned int key_size;
unsigned int value_size;
unsigned int max_entries;
};
static void *(*map_lookup_elem)(struct bpf_map_def *, void *) =
(void *)BPF_FUNC_map_lookup_elem;
static int (*trace_printk)(const char *fmt, int fmt_size, ...) =
(void *)BPF_FUNC_trace_printk;
struct bpf_map_def SEC("maps") channel = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 1,
};
SEC("func=sys_nanosleep")
int func(void *ctx)
{
int key = 0;
char fmt[] = "%d\n";
int *pval = map_lookup_elem(&channel, &key);
if (!pval)
return 0;
trace_printk(fmt, sizeof(fmt), *pval);
return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
/************************* END ***************************/
# echo "" > /sys/kernel/debug/tracing/trace
# ./perf record -e './test_bpf_map_1.c/maps:channel.value=11/' usleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.012 MB perf.data ]
# cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 1/1 #P:8
[SNIP]
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
usleep-18593 [007] d... 2394714.395539: : 11
# ./perf record -e './test_bpf_map.c/maps:channel.value=101/' usleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.012 MB perf.data ]
# cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 1/1 #P:8
[SNIP]
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
usleep-18593 [007] d... 2394714.395539: : 11
usleep-19000 [006] d... 2394831.057840: : 101
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 11 +++
tools/perf/util/bpf-loader.c | 180 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/bpf-loader.h | 15 ++++
3 files changed, 206 insertions(+)
@@ -526,6 +527,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)gotoout_child;}+err=bpf__apply_obj_config();+if(err){+charerrbuf[BUFSIZ];++bpf__strerror_apply_obj_config(err,errbuf,sizeof(errbuf));+pr_err("ERROR: Apply config to BPF failed: %s\n",+errbuf);+gotoout_child;+}+/**Normallyperf_session__newwoulddothis,butitdoesn'thavethe*evlist.
@@ -984,6 +985,178 @@ out:}+typedefint(*map_config_func_t)(constchar*name,intmap_fd,+structbpf_map_def*pdef,+structbpf_map_op*op,+void*pkey,void*arg);++staticint+foreach_key_array_all(map_config_func_tfunc,+void*arg,constchar*name,+intmap_fd,structbpf_map_def*pdef,+structbpf_map_op*op)+{+unsignedinti;+interr;++for(i=0;i<pdef->max_entries;i++){+err=func(name,map_fd,pdef,op,&i,arg);+if(err){+pr_debug("ERROR: failed to insert value to %s[%u]\n",+name,i);+returnerr;+}+}+return0;+}++staticint+bpf_map_config_foreach_key(structbpf_map*map,+map_config_func_tfunc,+void*arg)+{+interr,map_fd;+constchar*name;+structbpf_map_op*op;+structbpf_map_defdef;+structbpf_map_priv*priv;++name=bpf_map__get_name(map);++err=bpf_map__get_private(map,(void**)&priv);+if(err){+pr_debug("ERROR: failed to get private from map %s\n",name);+return-BPF_LOADER_ERRNO__INTERNAL;+}+if(!priv||list_empty(&priv->ops_list)){+pr_debug("INFO: nothing to config for map %s\n",name);+return0;+}++err=bpf_map__get_def(map,&def);+if(err){+pr_debug("ERROR: failed to get definition from map %s\n",name);+return-BPF_LOADER_ERRNO__INTERNAL;+}+map_fd=bpf_map__get_fd(map);+if(map_fd<0){+pr_debug("ERROR: failed to get fd from map %s\n",name);+returnmap_fd;+}++list_for_each_entry(op,&priv->ops_list,list){+switch(def.type){+caseBPF_MAP_TYPE_ARRAY:+switch(op->key_type){+caseBPF_MAP_KEY_ALL:+returnforeach_key_array_all(func,arg,name,+map_fd,&def,op);+default:+pr_debug("ERROR: keytype for map '%s' invalid\n",+name);+return-BPF_LOADER_ERRNO__INTERNAL;+}+default:+pr_debug("ERROR: type of '%s' incorrect\n",name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;+}+}++return0;+}++staticint+apply_config_value_for_key(intmap_fd,void*pkey,+size_tval_size,u64val)+{+interr=0;++switch(val_size){+case1:{+u8_val=(u8)(val);+err=bpf_map_update_elem(map_fd,pkey,&_val,BPF_ANY);+break;+}+case2:{+u16_val=(u16)(val);+err=bpf_map_update_elem(map_fd,pkey,&_val,BPF_ANY);+break;+}+case4:{+u32_val=(u32)(val);+err=bpf_map_update_elem(map_fd,pkey,&_val,BPF_ANY);+break;+}+case8:{+err=bpf_map_update_elem(map_fd,pkey,&val,BPF_ANY);+break;+}+default:+pr_debug("ERROR: invalid value size\n");+return-BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE;+}+if(err&&errno)+err=-errno;+returnerr;+}++staticint+apply_obj_config_map_for_key(constchar*name,intmap_fd,+structbpf_map_def*pdef__maybe_unused,+structbpf_map_op*op,+void*pkey,void*arg__maybe_unused)+{+interr;++switch(op->op_type){+caseBPF_MAP_OP_SET_VALUE:+err=apply_config_value_for_key(map_fd,pkey,+pdef->value_size,+op->v.value);+break;+default:+pr_debug("ERROR: unknown value type for '%s'\n",name);+err=-BPF_LOADER_ERRNO__INTERNAL;+}+returnerr;+}++staticint+apply_obj_config_map(structbpf_map*map)+{+returnbpf_map_config_foreach_key(map,+apply_obj_config_map_for_key,+NULL);+}++staticint+apply_obj_config_object(structbpf_object*obj)+{+structbpf_map*map;+interr;++bpf_map__for_each(map,obj){+err=apply_obj_config_map(map);+if(err)+returnerr;+}+return0;+}++intbpf__apply_obj_config(void)+{+structbpf_object*obj,*tmp;+interr;++bpf_object__for_each_safe(obj,tmp){+err=apply_obj_config_object(obj);+if(err)+returnerr;+}++return0;+}+#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
@@ -1138,3 +1311,10 @@ int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,bpf__strerror_end(buf,size);return0;}++intbpf__strerror_apply_obj_config(interr,char*buf,size_tsize)+{+bpf__strerror_head(err,buf,size);+bpf__strerror_end(buf,size);+return0;+}
This patch introduces basic facilities to support config different
slots in a BPF map one by one.
array.nr_ranges and array.ranges are introduced into 'struct
parse_events_term', where ranges is an array of indices range (start,
length) which will be configured by this config term. nr_ranges
is the size of the array. The array is passed to 'struct bpf_map_priv'.
To indicate the new type of configuration, BPF_MAP_KEY_RANGES is
added as a new key type. bpf_map_config_foreach_key() is extended to
iterate over those indices instead of all possible keys.
Code in this commit will be enabled by following commit which enables
the indices syntax for array configuration.
Signed-off-by: Wang Nan <redacted>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/bpf-loader.c | 132 ++++++++++++++++++++++++++++++++++++++---
tools/perf/util/bpf-loader.h | 1 +
tools/perf/util/parse-events.c | 33 ++++++++++-
tools/perf/util/parse-events.h | 12 ++++
4 files changed, 170 insertions(+), 8 deletions(-)
@@ -794,8 +801,30 @@ bpf_map_priv__clear(struct bpf_map *map __maybe_unused,free(priv);}+staticint+bpf_map_op_setkey(structbpf_map_op*op,structparse_events_term*term,+constchar*map_name)+{+op->key_type=BPF_MAP_KEY_ALL;++if(term->array.nr_ranges){+size_tmemsz=term->array.nr_ranges*+sizeof(op->k.array.ranges[0]);++op->k.array.ranges=memdup(term->array.ranges,memsz);+if(!op->k.array.ranges){+pr_debug("No enough memory to alloc indices for %s\n",+map_name);+return-ENOMEM;+}+op->key_type=BPF_MAP_KEY_RANGES;+op->k.array.nr_ranges=term->array.nr_ranges;+}+return0;+}+staticstructbpf_map_op*-bpf_map_op__alloc(structbpf_map*map)+bpf_map_op__alloc(structbpf_map*map,structparse_events_term*term){structbpf_map_op*op;structbpf_map_priv*priv;
@@ -972,6 +1006,44 @@ struct bpf_obj_config_map_func bpf_obj_config_map_funcs[] = {};staticint+config_map_indices_range_check(structparse_events_term*term,+structbpf_map*map,+constchar*map_name)+{+structparse_events_array*array=&term->array;+structbpf_map_defdef;+unsignedinti;+interr;++if(!array->nr_ranges)+return0;+if(!array->ranges){+pr_debug("ERROR: map %s: array->nr_ranges is %d but range array is NULL\n",+map_name,(int)array->nr_ranges);+return-BPF_LOADER_ERRNO__INTERNAL;+}++err=bpf_map__get_def(map,&def);+if(err){+pr_debug("ERROR: Unable to get map definition from '%s'\n",+map_name);+return-BPF_LOADER_ERRNO__INTERNAL;+}++for(i=0;i<array->nr_ranges;i++){+unsignedintstart=array->ranges[i].start;+size_tlength=array->ranges[i].length;+unsignedintidx=start+length-1;++if(idx>=def.max_entries){+pr_debug("ERROR: index %d too large\n",idx);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG;+}+}+return0;+}++staticintbpf__obj_config_map(structbpf_object*obj,structparse_events_term*term,structperf_evlist*evlist,
@@ -1077,6 +1156,33 @@ foreach_key_array_all(map_config_func_t func,}staticint+foreach_key_array_ranges(map_config_func_tfunc,void*arg,+constchar*name,intmap_fd,+structbpf_map_def*pdef,+structbpf_map_op*op)+{+unsignedinti,j;+interr;++for(i=0;i<op->k.array.nr_ranges;i++){+unsignedintstart=op->k.array.ranges[i].start;+size_tlength=op->k.array.ranges[i].length;++for(j=0;j<length;j++){+unsignedintidx=start+j;++err=func(name,map_fd,pdef,op,&idx,arg);+if(err){+pr_debug("ERROR: failed to insert value to %s[%u]\n",+name,idx);+returnerr;+}+}+}+return0;+}++staticintbpf_map_config_foreach_key(structbpf_map*map,map_config_func_tfunc,void*arg)
@@ -1116,13 +1222,24 @@ bpf_map_config_foreach_key(struct bpf_map *map,caseBPF_MAP_TYPE_PERF_EVENT_ARRAY:switch(op->key_type){caseBPF_MAP_KEY_ALL:-returnforeach_key_array_all(func,arg,name,-map_fd,&def,op);+err=foreach_key_array_all(func,arg,name,+map_fd,&def,op);+if(err)+returnerr;+break;+caseBPF_MAP_KEY_RANGES:+err=foreach_key_array_ranges(func,arg,name,+map_fd,&def,+op);+if(err)+returnerr;+break;default:pr_debug("ERROR: keytype for map '%s' invalid\n",name);return-BPF_LOADER_ERRNO__INTERNAL;-}+}+break;default:pr_debug("ERROR: type of '%s' incorrect\n",name);return-BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
@@ -1309,6 +1426,7 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {[ERRCODE_OFFSET(OBJCONF_MAP_EVTDIM)]="Event dimension too large",[ERRCODE_OFFSET(OBJCONF_MAP_EVTINH)]="Doesn't support inherit event",[ERRCODE_OFFSET(OBJCONF_MAP_EVTTYPE)]="Wrong event type for map",+[ERRCODE_OFFSET(OBJCONF_MAP_IDX2BIG)]="Index too large",};staticint
@@ -38,6 +38,7 @@ enum bpf_loader_errno {BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,/* Event dimension too large */BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,/* Doesn't support inherit event */BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,/* Wrong event type for map */+BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG,/* Index too large */__BPF_LOADER_ERRNO__END,};
On some system the perf-config is broken, causes link failure like this:
/usr/lib64/python2.7/config/libpython2.7.a(posixmodule.o): In function `posix_forkpty':
/opt/wangnan/yocto-build/tmp-eglibc/work/x86_64-oe-linux/python/2.7.3-r0.3.1/Python-2.7.3/./Modules/posixmodule.c:3816: undefined reference to `forkpty'
/usr/lib64/python2.7/config/libpython2.7.a(posixmodule.o): In function `posix_openpty':
/opt/wangnan/yocto-build/tmp-eglibc/work/x86_64-oe-linux/python/2.7.3-r0.3.1/Python-2.7.3/./Modules/posixmodule.c:3756: undefined reference to `openpty'
collect2: error: ld returned 1 exit status
make[1]: *** [/home/wangnan/kernel-hydrogen/tools/perf/out/perf] Error 1
make: *** [all] Error 2
$ python-config --libs
-lpthread -ldl -lpthread -lutil -lm -lpython2.7
In this case a '-lutil' should be appended to -lpython2.7.
(I know we have --start-group and --end-group. I can see them in
command line of collect2 by strace. However it doesn't work. Seems
I have a broken environment?)
Signed-off-by: Wang Nan <redacted>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/config/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
evsel->is_pos indicates event id location in a event (count backward).
It is used to find id for tracking events (mmap, exit...). If TAILSIZE
is selected, this location should be changed accordingly.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/evsel.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Toggel tailsize_evt_stopped director after receiving done or switch
output. After this patch it is possible to trigger a dump use SIGUSR2
when something happen.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
@@ -591,6 +591,26 @@ static void record__init_features(struct record *rec)}staticvoid+record__toggle_tailsize_evsels(structrecord*rec,boolstop)+{+structperf_evsel*pos;+structperf_evlist*evlist=rec->evlist;++evlist__for_each(evlist,pos){+if(!pos->tailsize)+continue;+if(!pos->overwrite)+continue;+if(stop)+perf_evsel__disable(pos);+else+perf_evsel__enable(pos);+}++rec->tailsize_evt_stopped=stop;+}++staticvoidrecord__finish_output(structrecord*rec){structperf_data_file*file=&rec->file;
@@ -925,6 +945,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)for(;;){unsignedlonglonghits=rec->samples;+if(switch_output_started||done)+record__toggle_tailsize_evsels(rec,true);+if(record__mmap_read_all(rec)<0){auxtrace_snapshot_disable();err=-1;
@@ -943,7 +966,20 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)}if(switch_output_started){+/*+*SIGUSR2raiseafterorduringrecord__mmap_read_all().+*continuetoreadagain.+*/+if(!rec->tailsize_evt_stopped)+continue;+switch_output_started=0;+/* +*Reenableeventsintailsizeringbufferafter+*record__mmap_read_all():wehavecollected+*datafromit.+*/+record__toggle_tailsize_evsels(rec,false);if(!quiet)fprintf(stderr,"[ perf record: dump data: Woken up %ld times ]\n",
In this commit sereval helpers are introduced to support the principle
of channel. Channels hold different groups of evsels which configured
differently. It will be used for overwritable evsels, which allows perf
record some events continuously while capture snapshot for other events
when something happen. Tracking events (mmap, mmap2, fork, exit ...)
are another possible events worth to be put into a separated channel.
Channels are represented by an array with channel flags. Each channel
contains evlist->nr_mmaps mmaps. Channels are configured before
perf_evlist__mmap_ex(). During that function nr_mmaps mmaps for each
channel are allocated together as a big array.
perf_evlist__channel_idx() converts index in the big array and the
channel number. For API functions which accept idx, _ex() versions are
introduced to accept selecting an mmap from a channel.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 6 ++
tools/perf/util/evlist.c | 132 ++++++++++++++++++++++++++++++++++++++++++--
tools/perf/util/evlist.h | 58 +++++++++++++++++++
3 files changed, 190 insertions(+), 6 deletions(-)
tailsize_rb_find_start() introduced to find the first available event
from a tailsize ring buffer through tailsize. event with '/overwrite/'
setting is able to be read. record__mmap_should_read() is changed
accordingly.
Reading a active tailsize ring buffer is unsafe. A global tailsize ring
buffer director is introduced into 'struct record'
record__mmap_should_read() returns true if tailsize_evt_stopped is true.
Following patch whould turn off events attached to tailsize ring buffer
and toggle this director.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 68 insertions(+), 1 deletion(-)
@@ -56,6 +56,7 @@ struct record {boolno_buildid_cache_set;booltimestamp_filename;boolswitch_output;+booltailsize_evt_stopped;unsignedlonglongsamples;};
@@ -79,6 +80,63 @@ static int process_synthesized_event(struct perf_tool *tool,returnrecord__write(rec,event,event->header.size);}+staticint+tailsize_rb_find_start(void*buf,u64head,intmask,u64*p_evt_head)+{+intbuf_size=mask+1;+u64evt_head=head;+u64*pevt_size;++pr_debug("start reading tailsize, head=%"PRId64"\n",head);+while(true){+structperf_event_header*pheader;++pevt_size=buf+((evt_head-sizeof(*pevt_size))&mask);+pr_debug4("read tailsize: size: %"PRId64"\n",*pevt_size);++if(*pevt_size%sizeof(u64)!=0){+pr_warning("Tailsize ring buffer corrupted: unaligned\n");+return-1;+}++if(!*pevt_size){+if(evt_head){+pr_warning("Tailsize ring buffer corrupted: size is 0 but evt_head (0x%"PRIx64") is not 0\n",+(unsignedlong)evt_head);+return-1;+}+*p_evt_head=evt_head;+return0;+}++if(evt_head<*pevt_size){+pr_warning("Tailsize ring buffer corrupted: head (%"PRId64") < size (%"PRId64")\n",+evt_head,*pevt_size);+return-1;+}++evt_head-=*pevt_size;++if(evt_head+buf_size<head){+evt_head+=*pevt_size;+pr_debug("Finish reading tailsize buffer, evt_head=%"PRIx64", head=%"PRIx64"\n",+evt_head,head);+*p_evt_head=evt_head;+return0;+}++pheader=(structperf_event_header*)(buf+(evt_head&mask));+if(pheader->size!=*pevt_size){+pr_warning("Tailsize ring buffer corrupted: found size mismatch: %d vs %"PRId64"\n",+pheader->size,*pevt_size);+return-1;+}+}++pr_warning("ERROR: shouldn't get there\n");+return-1;+}+staticintrecord__mmap_read(structrecord*rec,intidx){structperf_mmap*md=&rec->evlist->mmap[idx];
@@ -88,10 +146,17 @@ static int record__mmap_read(struct record *rec, int idx)unsignedlongsize;void*buf;intrc=0;+intchannel;if(old==head)return0;+channel=perf_evlist__idx_channel(rec->evlist,idx);+if(perf_evlist__channel_check(rec->evlist,channel,TAILSIZE)){+if(tailsize_rb_find_start(data,head,md->mask,&old))+return-1;+}+rec->samples++;size=head-old;
@@ -462,7 +527,8 @@ static bool record__mmap_should_read(struct record *rec, int idx)if(perf_evlist__channel_idx(rec->evlist,&channel,&idx))returnfalse;if(perf_evlist__channel_check(rec->evlist,channel,RDONLY))-returnfalse;+if(perf_evlist__channel_check(rec->evlist,channel,TAILSIZE))+returnrec->tailsize_evt_stopped;returntrue;}
@@ -1226,6 +1292,7 @@ static struct record record = {.mmap2=perf_event__process_mmap2,.ordered_events=true,},+.tailsize_evt_stopped=false,};constcharrecord_callchain_help[]=CALLCHAIN_RECORD_HELP
perf_evlist__mmap_ex() can fail without setting errno (for example,
fail in condition checking. In this case all syscall is success).
If this happen, record__open() incorrectly returns 0. Force setting
rc is a quick way to avoid this problem, or we have to follow all
possible code path in perf_evlist__mmap_ex() to make sure there's
at least one system call before returning an error.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
@@ -361,7 +361,10 @@ try_again:}else{pr_err("failed to mmap with %d (%s)\n",errno,strerror_r(errno,msg,sizeof(msg)));-rc=-errno;+if(errno)+rc=-errno;+else+rc=-EINVAL;}gotoout;}
With 'perf record --switch-output' without -a, record__synthesize() in
record__switch_output() won't generate tracking events because there's
no thread_map in evlist. Which causes newly created perf.data doesn't
contain map and comm information.
This patch creates a fake thread_map and directly call
perf_event__synthesize_thread_map() for those events.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
When record__mmap_read() require data more than the size of ring
buffer, drop those data to avoid access invalid memory.
This can happen when reading from overwritable ring buffer, which
should be avoided. However, check this for robustness.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -94,6 +95,13 @@ static int record__mmap_read(struct record *rec, int idx)rec->samples++;size=head-old;+if(size>(unsignedlong)(md->mask)+1){+WARN_ONCE(1,"WARNING: failed to keep up with mmap data. (warn only once)\n");++md->prev=head;+perf_evlist__mmap_consume(rec->evlist,idx);+return0;+}if((old&md->mask)+size!=(head&md->mask)){buf=&data[old&md->mask];
perf_evlist__channel_find() can be used to find a proper channel based
on propreties of a evsel. If the channel doesn't exist, it can create
new one for it. After this patch there's no need to create default
channel explicitly.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 5 -----
tools/perf/util/evlist.c | 47 ++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 42 insertions(+), 10 deletions(-)
Make 'overwrite' a channel configuration other than a evlist global
option. With this setting an evlist can have two channels, one is
normal channel, another is overwritable channel.
perf_evlist__channel_for_evsel() ensures events with 'overwrite'
configuration inserted to overwritable channel.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 2 +-
tools/perf/util/evlist.c | 42 +++++++++++++++++++++++++++---------------
tools/perf/util/evlist.h | 5 ++---
tools/perf/util/evsel.h | 1 +
4 files changed, 31 insertions(+), 19 deletions(-)
@@ -942,7 +950,7 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,atomic_set(&evlist->mmap[idx].refcnt,2);evlist->mmap[idx].prev=0;evlist->mmap[idx].mask=mp->mask;-evlist->mmap[idx].base=mmap(NULL,evlist->mmap_len,mp->prot,+evlist->mmap[idx].base=mmap(NULL,evlist->mmap_len,prot,MAP_SHARED,fd,0);if(evlist->mmap[idx].base==MAP_FAILED){pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -959,9 +967,13 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,}staticunsignedlong-perf_evlist__channel_for_evsel(structperf_evsel*evsel__maybe_unused)+perf_evlist__channel_for_evsel(structperf_evsel*evsel){-return0;+unsignedlongflag=0;++if(evsel->overwrite)+flag|=PERF_EVLIST__CHANNEL_RDONLY;+returnflag;}staticint
'perf record' knows whether buildid cache is enabled (via
--no-no-buildid-cache) deliberately. Buildid cache can be turned off
in some situations.
Output switching support needs this feature to turn off buildid cache
by default.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
@@ -50,7 +50,9 @@ struct record {constchar*progname;intrealtime_prio;boolno_buildid;+boolno_buildid_set;boolno_buildid_cache;+boolno_buildid_cache_set;unsignedlonglongsamples;};
@@ -1176,10 +1178,12 @@ struct option __record_options[] = {OPT_BOOLEAN('P',"period",&record.opts.period,"Record the sample period"),OPT_BOOLEAN('n',"no-samples",&record.opts.no_samples,"don't sample"),-OPT_BOOLEAN('N',"no-buildid-cache",&record.no_buildid_cache,-"do not update the buildid cache"),-OPT_BOOLEAN('B',"no-buildid",&record.no_buildid,-"do not collect buildids in perf.data"),+OPT_BOOLEAN_SET('N',"no-buildid-cache",&record.no_buildid_cache,+&record.no_buildid_cache_set,+"do not update the buildid cache"),+OPT_BOOLEAN_SET('B',"no-buildid",&record.no_buildid,+&record.no_buildid_set,+"do not collect buildids in perf.data"),OPT_CALLBACK('G',"cgroup",&record.evlist,"name","monitor event in cgroup name only",parse_cgroups),
Before this patch tracking events are generated based on information in
/proc before all samples. However, with the introducing of overwrite
evsel in perf record, it becomes inconvenience: 'perf record' now can
executed as a daemon for sereval hours and only capture the last
snapshot when it receives SIGUSR2. The tracking events generated at
the head of output 'perf.data' becomes too old, but most of tracking
events during 'perf record' running are dropped.
This patch generates tracking events at the end of output. The output
events series would better reflecting status of system when SIGUSR2
received.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 62 +++++++++++++++++++++++++++++++--------------
1 file changed, 43 insertions(+), 19 deletions(-)
@@ -56,6 +56,7 @@ struct record {boolno_buildid_cache_set;booltimestamp_filename;boolswitch_output;+booltail_tracking;booltailsize_evt_stopped;unsignedlonglongsamples;};
@@ -639,6 +640,26 @@ record__finish_output(struct record *rec)staticintrecord__synthesize(structrecord*rec);+staticvoidrecord__synthesize_target(structrecord*rec)+{+if(target__none(&rec->opts.target)){+struct{+structthread_mapmap;+structthread_map_datamap_data;+}thread_map;++thread_map.map.nr=1;+thread_map.map.map[0].pid=rec->evlist->workload.pid;+thread_map.map.map[0].comm=NULL;+perf_event__synthesize_thread_map(&rec->tool,+&thread_map.map,+process_synthesized_event,+&rec->session->machines.host,+rec->opts.sample_address,+rec->opts.proc_map_timeout);+}+}+staticintrecord__switch_output(structrecord*rec,boolat_exit){
@@ -648,6 +669,11 @@ record__switch_output(struct record *rec, bool at_exit)/* Same Size: "2015122520103046"*/chartimestamp[]="InvalidTimestamp";+if(rec->tail_tracking){+record__synthesize(rec);+record__synthesize_target(rec);+}+rec->samples=0;record__finish_output(rec);err=fetch_current_timestamp(timestamp,sizeof(timestamp));
@@ -674,23 +700,10 @@ record__switch_output(struct record *rec, bool at_exit)machines__init(&rec->session->machines);perf_session__create_kernel_maps(rec->session);perf_session__set_id_hdr_size(rec->session);-record__synthesize(rec);-if(target__none(&rec->opts.target)){-struct{-structthread_mapmap;-structthread_map_datamap_data;-}thread_map;--thread_map.map.nr=1;-thread_map.map.map[0].pid=rec->evlist->workload.pid;-thread_map.map.map[0].comm=NULL;-perf_event__synthesize_thread_map(&rec->tool,-&thread_map.map,-process_synthesized_event,-&rec->session->machines.host,-rec->opts.sample_address,-rec->opts.proc_map_timeout);+if(!rec->tail_tracking){+record__synthesize(rec);+record__synthesize_target(rec);}}returnfd;
@@ -886,9 +899,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)machine=&session->machines.host;-err=record__synthesize(rec);-if(err<0)-gotoout_child;+if(!rec->tail_tracking){+err=record__synthesize(rec);+if(err<0)+gotoout_child;+}if(rec->realtime_prio){structsched_paramparam;
@@ -1021,6 +1036,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)disabled=true;}}++if(rec->tail_tracking){+err=record__synthesize(rec);+if(err<0)+gotoout_child;+}+auxtrace_snapshot_disable();if(forks&&workload_exec_errno){
@@ -1446,6 +1468,8 @@ struct option __record_options[] = {"append timestamp to output filename"),OPT_BOOLEAN(0,"switch-output",&record.switch_output,"Switch output when receive SIGUSR2"),+OPT_BOOLEAN(0,"tail-tracking",&record.tail_tracking,+"Generate tracking events at the end of output"),OPT_END()};
Before this patch perf operates on only the first channel. Make perf
mmap and read from multiple channels.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 3 ++-
tools/perf/util/evlist.c | 55 ++++++++++++++++++++++++++++++++++-----------
tools/perf/util/evlist.h | 2 +-
3 files changed, 45 insertions(+), 15 deletions(-)
@@ -458,8 +458,9 @@ static int record__mmap_read_all(struct record *rec)u64bytes_written=rec->bytes_written;inti;intrc=0;+inttotal_mmaps=perf_evlist__mmap_nr(rec->evlist);-for(i=0;i<rec->evlist->nr_mmaps;i++){+for(i=0;i<total_mmaps;i++){structauxtrace_mmap*mm=&rec->evlist->mmap[i].auxtrace_mmap;if(rec->evlist->mmap[i].base){
@@ -980,26 +995,38 @@ perf_evlist__channel_complete(struct perf_evlist *evlist)return0;}-staticintperf_evlist__mmap_per_evsel(structperf_evlist*evlist,intidx,+staticintperf_evlist__mmap_per_evsel(structperf_evlist*evlist,int_idx,structmmap_params*mp,intcpu,-intthread,int*output)+intthread,int*outputs){structperf_evsel*evsel;evlist__for_each(evlist,evsel){-intfd;+intfd,channel,idx,err;++channel=perf_evlist__channel_find(evlist,evsel,false);+if(channel<0){+pr_err("ERROR: unable to find suitable channel for %s\n",+evsel->name);+return-1;+}++idx=_idx;+err=perf_evlist__channel_idx(evlist,&channel,&idx);+if(err<0)+returnerr;if(evsel->system_wide&&thread)continue;fd=FD(evsel,cpu,thread);-if(*output==-1){-*output=fd;-if(__perf_evlist__mmap(evlist,idx,mp,*output)<0)+if(outputs[channel]==-1){+outputs[channel]=fd;+if(__perf_evlist__mmap(evlist,idx,mp,outputs[channel])<0)return-1;}else{-if(ioctl(fd,PERF_EVENT_IOC_SET_OUTPUT,*output)!=0)+if(ioctl(fd,PERF_EVENT_IOC_SET_OUTPUT,outputs[channel])!=0)return-1;perf_evlist__mmap_get(evlist,idx);
@@ -1039,14 +1066,15 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,pr_debug2("perf event ring buffer mmapped per cpu\n");for(cpu=0;cpu<nr_cpus;cpu++){-intoutput=-1;+intoutputs[PERF_EVLIST__NR_CHANNELS];+memset(outputs,-1,sizeof(outputs));auxtrace_mmap_params__set_idx(&mp->auxtrace_mp,evlist,cpu,true);for(thread=0;thread<nr_threads;thread++){if(perf_evlist__mmap_per_evsel(evlist,cpu,mp,cpu,-thread,&output))+thread,outputs))gotoout_unmap;}}
@@ -1055,7 +1083,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,out_unmap:for(cpu=0;cpu<nr_cpus;cpu++)-__perf_evlist__munmap(evlist,cpu);+__perf_evlist__munmap_channels(evlist,cpu);return-1;}
@@ -1067,13 +1095,14 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,pr_debug2("perf event ring buffer mmapped per thread\n");for(thread=0;thread<nr_threads;thread++){-intoutput=-1;+intoutputs[PERF_EVLIST__NR_CHANNELS];+memset(outputs,-1,sizeof(outputs));auxtrace_mmap_params__set_idx(&mp->auxtrace_mp,evlist,thread,false);if(perf_evlist__mmap_per_evsel(evlist,thread,mp,0,thread,-&output))+outputs))gotoout_unmap;}
@@ -1081,7 +1110,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,out_unmap:for(thread=0;thread<nr_threads;thread++)-__perf_evlist__munmap(evlist,thread);+__perf_evlist__munmap_channels(evlist,thread);return-1;}
@@ -1267,6 +1267,7 @@ struct option __record_options[] = {OPT_BOOLEAN_SET('i',"no-inherit",&record.opts.no_inherit,&record.opts.no_inherit_set,"child tasks do not inherit counters"),+OPT_BOOLEAN(0,"overwrite",&record.opts.overwrite,"use overwrite mode"),OPT_UINTEGER('F',"freq",&record.opts.user_freq,"profile at this frequency"),OPT_CALLBACK('m',"mmap-pages",&record.opts,"pages[,pages]","number of mmap data pages and AUX area tracing mmap pages",
PERF_SAMPLE_TAILSIZE pad the size of an event at the end of it in the
ring buffer, makes reading from overwrite ring buffer possible. This
patch set that bit if evsel->overwrite is selected explicitly by user.
Overwrite and tailsize are still controled separatly for legacy
readonly mmap users (most of them are in perf/tests).
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/evlist.c | 2 ++
tools/perf/util/evlist.h | 1 +
tools/perf/util/evsel.c | 28 ++++++++++++++++++++++++++++
tools/perf/util/evsel.h | 1 +
4 files changed, 32 insertions(+)
@@ -671,13 +671,33 @@ static void apply_config_terms(struct perf_evsel *evsel,attr->inherit=term->val.inherit?1:0;break;casePERF_EVSEL__CONFIG_TERM_OVERWRITE:+/*+*Lettailsizeandoverwritecontroledby/overwrite/+*semultaneouslybecause/overwrite/canonlybe+*passedbyuserexplicitly,inthiscaseusershould+*beabletoreadfromthateventsotailsizemust+*set.+*+*(overwrite&&!tailsize)canhappenonlywhen+*perf_evlist__mmap()iscalledwithoverwrite==true.+*Inthatcasethere'snochancetopass/overwrite/.+*/evsel->overwrite=term->val.overwrite?1:0;+evsel->tailsize=term->val.overwrite?1:0;break;default:break;}}+/*+*Settailsizesamplebitafterconfigtermprocessingbecause+*itispossibletosetoverwriteglobally,withoutconfig+*terms.+*/+if(evsel->tailsize)+perf_evsel__set_sample_bit(evsel,TAILSIZE);+/* User explicitly set per-event callgraph, clear the old setting and reset. */if((callgraph_buf!=NULL)||(dump_size>0)){
Read from overwritable ring buffer is unreliable. Also, there's
no need to poll on a overwritable channel because we don't need
consuming data from it. Only select PULLHUP and PULLERR events.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 15 ++++++++++++++-
tools/perf/util/evlist.c | 27 +++++++++++++++++++++++----
2 files changed, 37 insertions(+), 5 deletions(-)
@@ -463,7 +476,7 @@ static int record__mmap_read_all(struct record *rec)for(i=0;i<total_mmaps;i++){structauxtrace_mmap*mm=&rec->evlist->mmap[i].auxtrace_mmap;-if(rec->evlist->mmap[i].base){+if(record__mmap_should_read(rec,i)){if(record__mmap_read(rec,i)!=0){rc=-1;gotoout;
@@ -461,9 +461,9 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)return0;}-staticint__perf_evlist__add_pollfd(structperf_evlist*evlist,intfd,intidx)+staticint__perf_evlist__add_pollfd(structperf_evlist*evlist,intfd,intidx,shortrevent){-intpos=fdarray__add(&evlist->pollfd,fd,POLLIN|POLLERR|POLLHUP);+intpos=fdarray__add(&evlist->pollfd,fd,revent|POLLERR|POLLHUP);/**SavetheidxsothatwhenwefilteroutfdsPOLLHUP'edwecan*closetheassociatedevlist->mmap[]entry.
@@ -479,7 +479,7 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idxintperf_evlist__add_pollfd(structperf_evlist*evlist,intfd){-return__perf_evlist__add_pollfd(evlist,fd,-1);+return__perf_evlist__add_pollfd(evlist,fd,-1,POLLIN);}staticvoidperf_evlist__munmap_filtered(structfdarray*fda,intfd)
From: "Naveen N. Rao" <redacted>
perf build is currently (v4.4-rc5) broken on powerpc:
bpf.c:28:4: error: #error __NR_bpf not defined. libbpf does not support
your arch.
# error __NR_bpf not defined. libbpf does not support your arch.
^
Fix this by including tools/scripts/Makefile.arch for the proper
$ARCH macro. While at it, remove redundant LP64 macro definition.
Also, since libbpf require $(srctree) now, detect the path of
srctree like perf.
Signed-off-by: Naveen N. Rao <redacted>
Signed-off-by: Wang Nan <redacted>
[Use tools/scripts/Makefile.arch]
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Sukadev Bhattiprolu <redacted>
---
tools/lib/bpf/Makefile | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
@@ -6,6 +6,12 @@ BPF_EXTRAVERSION = 1MAKEFLAGS+=--no-print-directory+ifeq ($(srctree),)+srctree:=$(patsubst%/,%,$(dir$(shellpwd)))+srctree:=$(patsubst%/,%,$(dir$(srctree)))+srctree:=$(patsubst%/,%,$(dir$(srctree)))+#$(info Determined 'srctree' to be $(srctree))+endif# Makefiles suck: This macro sets a default value of $(2) for the# variable named by $(1), unless the variable has been set by
Create record__synthesize(). It can be used to creating tracking events
for each perf.data after perf supporting splitting into multiple
outputs.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 132 +++++++++++++++++++++++++-------------------
1 file changed, 76 insertions(+), 56 deletions(-)
@@ -475,6 +475,81 @@ static void workload_exec_failed_signal(int signo __maybe_unused,staticvoidsnapshot_sig_handler(intsig);+staticintrecord__synthesize(structrecord*rec)+{+structperf_session*session=rec->session;+structmachine*machine=&session->machines.host;+structperf_data_file*file=&rec->file;+structrecord_opts*opts=&rec->opts;+structperf_tool*tool=&rec->tool;+intfd=perf_data_file__fd(file);+interr=0;+staticboolwarned_kmaps=false,warned_modules=false;++if(file->is_pipe){+err=perf_event__synthesize_attrs(tool,session,+process_synthesized_event);+if(err<0){+pr_err("Couldn't synthesize attrs.\n");+gotoout;+}++if(have_tracepoints(&rec->evlist->entries)){+/*+*FIXMEerr<=0hereactuallymeansthat+*therewerenotracepointssoitsnotreally+*anerror,justthatwedon'tneedto+*synthesizeanything.Wereallyhaveto+*returnthismoreproperlyandalso+*propagateerrorsthatnowarecallingdie()+*/+err=perf_event__synthesize_tracing_data(tool,fd,rec->evlist,+process_synthesized_event);+if(err<=0){+pr_err("Couldn't record tracing data.\n");+gotoout;+}+rec->bytes_written+=err;+}+}++if(rec->opts.full_auxtrace){+err=perf_event__synthesize_auxtrace_info(rec->itr,tool,+session,process_synthesized_event);+if(err)+gotoout;+}++err=perf_event__synthesize_kernel_mmap(tool,process_synthesized_event,+machine);+if(err<0&&!warned_kmaps){+warned_kmaps=true;+pr_err("Couldn't record kernel reference relocation symbol\n"+"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"+"Check /proc/kallsyms permission or run as root.\n");+}++err=perf_event__synthesize_modules(tool,process_synthesized_event,+machine);+if(err<0&&!warned_modules){+warned_modules=true;+pr_err("Couldn't record kernel module information.\n"+"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"+"Check /proc/modules permission or run as root.\n");+}++if(perf_guest){+machines__process_guests(&session->machines,+perf_event__synthesize_guest_os,tool);+}++err=__machine__synthesize_threads(machine,tool,&opts->target,rec->evlist->threads,+process_synthesized_event,opts->sample_address,+opts->proc_map_timeout);+out:+returnerr;+}+staticint__cmd_record(structrecord*rec,intargc,constchar**argv){interr;
@@ -569,63 +644,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)machine=&session->machines.host;-if(file->is_pipe){-err=perf_event__synthesize_attrs(tool,session,-process_synthesized_event);-if(err<0){-pr_err("Couldn't synthesize attrs.\n");-gotoout_child;-}--if(have_tracepoints(&rec->evlist->entries)){-/*-*FIXMEerr<=0hereactuallymeansthat-*therewerenotracepointssoitsnotreally-*anerror,justthatwedon'tneedto-*synthesizeanything.Wereallyhaveto-*returnthismoreproperlyandalso-*propagateerrorsthatnowarecallingdie()-*/-err=perf_event__synthesize_tracing_data(tool,fd,rec->evlist,-process_synthesized_event);-if(err<=0){-pr_err("Couldn't record tracing data.\n");-gotoout_child;-}-rec->bytes_written+=err;-}-}--if(rec->opts.full_auxtrace){-err=perf_event__synthesize_auxtrace_info(rec->itr,tool,-session,process_synthesized_event);-if(err)-gotoout_delete_session;-}--err=perf_event__synthesize_kernel_mmap(tool,process_synthesized_event,-machine);-if(err<0)-pr_err("Couldn't record kernel reference relocation symbol\n"-"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"-"Check /proc/kallsyms permission or run as root.\n");--err=perf_event__synthesize_modules(tool,process_synthesized_event,-machine);+err=record__synthesize(rec);if(err<0)-pr_err("Couldn't record kernel module information.\n"-"Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"-"Check /proc/modules permission or run as root.\n");--if(perf_guest){-machines__process_guests(&session->machines,-perf_event__synthesize_guest_os,tool);-}--err=__machine__synthesize_threads(machine,tool,&opts->target,rec->evlist->threads,-process_synthesized_event,opts->sample_address,-opts->proc_map_timeout);-if(err!=0)gotoout_child;if(rec->realtime_prio){
Timestamp generation becomes a public available helper. Which will
be used by 'perf record', help it output to split output file based
on time.
For example:
perf.data.2015122620363710
perf.data.2015122620364092
perf.data.2015122620365423
...
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-buildid-cache.c | 14 +-------------
tools/perf/util/util.c | 17 +++++++++++++++++
tools/perf/util/util.h | 1 +
3 files changed, 19 insertions(+), 13 deletions(-)
perf_data_file__switch() closes current output file, renames it, then
open a new one to continue record. It will be used by perf record
to split output into multiple perf.data files.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/data.c | 36 ++++++++++++++++++++++++++++++++++++
tools/perf/util/data.h | 11 ++++++++++-
2 files changed, 46 insertions(+), 1 deletion(-)
Tracking events describe kernel and threads. They are generated by
reading /proc/kallsyms, /proc/*/maps and /proc/*/task/* during
initialization of 'perf record', serialized into event sequences and put
at the head of 'perf.data'. In case of output switching, each output
file should contain those events.
This patch calls record__synthesize() during output switching, so the
event sequences described above can be collected again.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 11 +++++++++++
1 file changed, 11 insertions(+)
Move code for finalizing 'perf.data' to record__finish_output(). It
will be used by following commits to split output to multiple files.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 45 +++++++++++++++++++++++++++++----------------
1 file changed, 29 insertions(+), 16 deletions(-)
@@ -493,6 +493,33 @@ static void record__init_features(struct record *rec)perf_header__clear_feat(&session->header,HEADER_STAT);}+staticvoid+record__finish_output(structrecord*rec)+{+structperf_data_file*file=&rec->file;+intfd=perf_data_file__fd(file);++if(file->is_pipe)+return;++rec->session->header.data_size+=rec->bytes_written;+file->size=lseek(perf_data_file__fd(file),0,SEEK_CUR);++if(!rec->no_buildid){+process_buildids(rec);+/*+*Wetakeallbuildidswhenthefilecontains+*AUXareatracingdatabecausewedonotdecodethe+*tracebecauseitwouldtaketoolong.+*/+if(rec->opts.full_auxtrace)+dsos__hit_all(rec->session);+}+perf_session__write_header(rec->session,rec->evlist,fd,true);++return;+}+staticvolatileintworkload_exec_errno;/*
@@ -820,22 +847,8 @@ out_child:/* this will be recalculated during process_buildids() */rec->samples=0;-if(!err&&!file->is_pipe){-rec->session->header.data_size+=rec->bytes_written;-file->size=lseek(perf_data_file__fd(file),0,SEEK_CUR);--if(!rec->no_buildid){-process_buildids(rec);-/*-*Wetakeallbuildidswhenthefilecontains-*AUXareatracingdatabecausewedonotdecodethe-*tracebecauseitwouldtaketoolong.-*/-if(rec->opts.full_auxtrace)-dsos__hit_all(rec->session);-}-perf_session__write_header(rec->session,rec->evlist,fd,true);-}+if(!err)+record__finish_output(rec);if(!err&&!quiet){charsamples[128];
After this patch other directories can use this architecture detector
without directly including it from perf's directory. Libbpf would
utilize it to get proper $(ARCH) so it can receive correct uapi include
directory.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: Arnaldo Carvalho de Melo <acme@kernel.org>
[Add missing srctree definition in tests/make]
Acked-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Naveen N. Rao <redacted>
Cc: Naveen N. Rao <redacted>
Cc: Sukadev Bhattiprolu <redacted>
---
tools/perf/config/Makefile | 2 +-
tools/perf/tests/make | 16 +++++++++++++++-
tools/{perf/config => scripts}/Makefile.arch | 0
3 files changed, 16 insertions(+), 2 deletions(-)
rename tools/{perf/config => scripts}/Makefile.arch (100%)
@@ -1,3 +1,5 @@+include ../scripts/Makefile.include+ ifndef MK ifeq ($(MAKECMDGOALS),) # no target specified, trigger the whole suite
@@ -31,7 +33,19 @@ ifeq ($(SET_PARALLEL),1) PARALLEL_OPT="-j$(cores)" endif-include config/Makefile.arch+# As per kernel Makefile, avoid funny character set dependencies+unexport LC_ALL+LC_COLLATE=C+LC_NUMERIC=C+export LC_COLLATE LC_NUMERIC++ifeq ($(srctree),)+srctree := $(patsubst %/,%,$(dir $(shell pwd)))+srctree := $(patsubst %/,%,$(dir $(srctree)))+#$(info Determined 'srctree' to be $(srctree))+endif++include $(srctree)/tools/scripts/Makefile.arch # FIXME looks like x86 is the only arch running tests ;-) # we need some IS_(32/64) flag to make this generic
diff --git a/tools/perf/config/Makefile.arch b/tools/scripts/Makefile.archsimilarity index 100%rename from tools/perf/config/Makefile.archrename to tools/scripts/Makefile.arch
--
1.8.3.4
Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:
1. A watchpoint and a breakpoint that fire on the same instruction
2. Nested signals
Test result:
On x86_64 and ARM64 (result are similar with patch [2] on ARM64):
# ./perf test -v signal
17: Test breakpoint overflow signal handler :
--- start ---
test child forked, pid 10213
count1 1, count2 3, count3 2, overflow 3, overflows_2 3
test child finished with 0
---- end ----
Test breakpoint overflow signal handler: Ok
So at least 2 cases Will doubted are handled correctly.
[1] http://lkml.kernel.org/g/20160104165535.GI1616@arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0@huawei.com
Signed-off-by: Wang Nan <redacted>
Cc: Will Deacon <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
---
tools/perf/tests/bp_signal.c | 140 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 118 insertions(+), 22 deletions(-)
@@ -29,14 +29,59 @@staticintfd1;staticintfd2;+staticintfd3;staticintoverflows;+staticintoverflows_2;++volatilelongthe_var;+++/*+*UseASMtoensurewatchpointandbreakpointcanbetriggered+*atoneinstruction.+*/+#if defined (__x86_64__)+externvoid__test_function(volatilelong*ptr);+asm(+".globl __test_function\n"+"__test_function:\n"+"incq (%rdi)\n"+"ret\n");+#elif defined (__aarch64__)+externvoid__test_function(volatilelong*ptr);+asm(+".globl __test_function\n"+"__test_function:\n"+"str x30, [x0]\n"+"ret\n");++#else+staticvoid__test_function(volatilelong*ptr)+{+*ptr=0x1234;+}+#endif__attribute__((noinline))staticinttest_function(void){+__test_function(&the_var);+the_var++;returntime(NULL);}+staticvoidsig_handler_2(intsignum__maybe_unused,+siginfo_t*oh__maybe_unused,+void*uc__maybe_unused)+{+overflows_2++;+if(overflows_2>10){+ioctl(fd1,PERF_EVENT_IOC_DISABLE,0);+ioctl(fd2,PERF_EVENT_IOC_DISABLE,0);+ioctl(fd3,PERF_EVENT_IOC_DISABLE,0);+}+}+staticvoidsig_handler(intsignum__maybe_unused,siginfo_t*oh__maybe_unused,void*uc__maybe_unused)
@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,*/ioctl(fd1,PERF_EVENT_IOC_DISABLE,0);ioctl(fd2,PERF_EVENT_IOC_DISABLE,0);+ioctl(fd3,PERF_EVENT_IOC_DISABLE,0);}}-staticintbp_event(void*fn,intsetup_signal)+staticint__event(boolis_x,void*addr,intsignal){structperf_event_attrpe;intfd;
@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)pe.size=sizeof(structperf_event_attr);pe.config=0;-pe.bp_type=HW_BREAKPOINT_X;-pe.bp_addr=(unsignedlong)fn;+pe.bp_type=is_x?HW_BREAKPOINT_X:HW_BREAKPOINT_W;+pe.bp_addr=(unsignedlong)addr;pe.bp_len=sizeof(long);pe.sample_period=1;
@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)returnTEST_FAIL;}-if(setup_signal){-fcntl(fd,F_SETFL,O_RDWR|O_NONBLOCK|O_ASYNC);-fcntl(fd,F_SETSIG,SIGIO);-fcntl(fd,F_SETOWN,getpid());-}+fcntl(fd,F_SETFL,O_RDWR|O_NONBLOCK|O_ASYNC);+fcntl(fd,F_SETSIG,signal);+fcntl(fd,F_SETOWN,getpid());ioctl(fd,PERF_EVENT_IOC_RESET,0);returnfd;}+staticintbp_event(void*addr,intsignal)+{+return__event(true,addr,signal);+}++staticintwp_event(void*addr,intsignal)+{+return__event(false,addr,signal);+}+staticlonglongbp_count(intfd){longlongcount;
@@ -114,7 +168,7 @@ static long long bp_count(int fd)inttest__bp_signal(intsubtest__maybe_unused){structsigactionsa;-longlongcount1,count2;+longlongcount1,count2,count3;/* setup SIGIO signal handler */memset(&sa,0,sizeof(structsigaction));
@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)returnTEST_FAIL;}+sa.sa_sigaction=(void*)sig_handler_2;+if(sigaction(SIGUSR1,&sa,NULL)<0){+pr_debug("failed setting up signal handler 2\n");+returnTEST_FAIL;+}+/**Wecreatefollowingevents:*-*fd1-breakpointeventontest_functionwithSIGIO+*fd1-breakpointeventon__test_functionwithSIGIO*signalconfigured.Weshouldgetsignal*notificationeachtimethebreakpointishit*-*fd2-breakpointeventonsig_handlerwithoutSIGIO+*fd2-breakpointeventonsig_handlerwithSIGUSR1+*configured.WeshouldgetSIGUSR1eachtimewhen+*breakpointishit+*+*fd3-watchpointeventon__test_functionwithSIGIO*configured.**Followingprocessingshouldhappen:-*-executetest_function-*-fd1eventbreakpointhit->count1==1-*-SIGIOisdelivered->overflows==1-*-fd2eventbreakpointhit->count2==1+*Exec:Action:Result:+*incq(%rdi)-fd1eventbreakpointhit->count1==1+*-SIGIOisdelivered+*sig_handler-fd2eventbreakpointhit->count2==1+*-SIGUSR1isdelivered+*sig_handler_2->overflows_2==1(nestedsignal)+*sys_rt_sigreturn-returnfromsig_handler_2+*overflows++->overflows=1+*sys_rt_sigreturn-returnfromsig_handler+*incq(%rdi)-fd3eventwatchpointhit->count3==1(wpandbpinoneinsn)+*-SIGIOisdelivered+*sig_handler-fd2eventbreakpointhit->count2==2+*-SIGUSR1isdelivered+*sig_handler_2->overflows_2==2(nestedsignal)+*sys_rt_sigreturn-returnfromsig_handler_2+*overflows++->overflows=2+*sys_rt_sigreturn-returnfromsig_handler+*the_var++-fd3eventwatchpointhit->count3==2(standalonewatchpoint)+*-SIGIOisdelivered+*sig_handler-fd2eventbreakpointhit->count2==3+*-SIGUSR1isdelivered+*sig_handler_2->overflows_2==3(nestedsignal)+*sys_rt_sigreturn-returnfromsig_handler_2+*overflows++->overflows==3+*sys_rt_sigreturn-returnfromsig_handler**Thetestcasecheckfollowingerrorconditions:*-wegetstuckinsignalhandlerbecauseofdebug
@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)**/-fd1=bp_event(test_function,1);-fd2=bp_event(sig_handler,0);+fd1=bp_event(__test_function,SIGIO);+fd2=bp_event(sig_handler,SIGUSR1);+fd3=wp_event((void*)&the_var,SIGIO);ioctl(fd1,PERF_EVENT_IOC_ENABLE,0);ioctl(fd2,PERF_EVENT_IOC_ENABLE,0);+ioctl(fd3,PERF_EVENT_IOC_ENABLE,0);/**Kickoffthetestbytrigering'fd1'
Doesn't like tools/perf/Makefile, tools/perf/Makefile.perf obey 'O'
option when it is passed through cmdline only, because of code in
tools/scripts/Makefile.include:
ifneq ($(O),)
ifeq ($(origin O), command line)
...
ABSOLUTE_O := $(shell cd $(O) ; pwd)
OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/)
endif
endif
This patch passes 'O' to Makefile.perf through cmdline explicitly
to make it follow O variable during build-test.
Signed-off-by: Wang Nan <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/tests/make | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
auxtrace_snapshot_enable has only two states (0/1). Turns it into a
triple states enum so SIGUSR2 handler can safely do other works without
triggering auxtrace snapshot.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 59 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 49 insertions(+), 10 deletions(-)
@@ -244,7 +280,7 @@ static void record__read_auxtrace_snapshot(struct record *rec)}else{auxtrace_snapshot_err=auxtrace_record__snapshot_finish(rec->itr);if(!auxtrace_snapshot_err)-auxtrace_snapshot_enabled=1;+auxtrace_snapshot_enable();}}
@@ -570,10 +606,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)signal(SIGCHLD,sig_handler);signal(SIGINT,sig_handler);signal(SIGTERM,sig_handler);-if(rec->opts.auxtrace_snapshot_mode)++if(rec->opts.auxtrace_snapshot_mode){signal(SIGUSR2,snapshot_sig_handler);-else+auxtrace_snapshot_on();+}else{signal(SIGUSR2,SIG_IGN);+}session=perf_session__new(file,false,tool);if(session==NULL){
@@ -699,12 +738,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)perf_evlist__enable(rec->evlist);}-auxtrace_snapshot_enabled=1;+auxtrace_snapshot_enable();for(;;){unsignedlonglonghits=rec->samples;if(record__mmap_read_all(rec)<0){-auxtrace_snapshot_enabled=0;+auxtrace_snapshot_disable();err=-1;gotoout_child;}
@@ -742,12 +781,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)*disableeventsinthiscase.*/if(done&&!disabled&&!target__none(&opts->target)){-auxtrace_snapshot_enabled=0;+auxtrace_snapshot_disable();perf_evlist__disable(rec->evlist);disabled=true;}}-auxtrace_snapshot_enabled=0;+auxtrace_snapshot_disable();if(forks&&workload_exec_errno){charmsg[STRERR_BUFSIZE];
@@ -668,7 +670,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)signal(SIGINT,sig_handler);signal(SIGTERM,sig_handler);-if(rec->opts.auxtrace_snapshot_mode){+if(rec->opts.auxtrace_snapshot_mode||rec->switch_output){signal(SIGUSR2,snapshot_sig_handler);auxtrace_snapshot_on();}else{
@@ -820,9 +822,25 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)}}+if(switch_output_started){+switch_output_started=0;++if(!quiet)+fprintf(stderr,"[ perf record: dump data: Woken up %ld times ]\n",+waking);+waking=0;+fd=record__switch_output(rec,false);+if(fd<0){+pr_err("Failed to switch to new file\n");+err=fd;+gotoout_child;+}+}+if(hits==rec->samples){if(done||draining)break;+err=perf_evlist__poll(rec->evlist,-1);/**Propagateerror,onlyifthere'sany.Ignorepositive
@@ -1268,6 +1286,8 @@ struct option __record_options[] = {"file","vmlinux pathname"),OPT_BOOLEAN(0,"timestamp-filename",&record.timestamp_filename,"append timestamp to output filename"),+OPT_BOOLEAN(0,"switch-output",&record.switch_output,+"Switch output when receive SIGUSR2"),OPT_END()};
Before this patch, if a sample is triggered inside an offline module
(module not in /lib/modules/`uname -r`/), even if the module is in
buildid-cache, 'perf report' is still unable to get correct symbol.
For example:
# rm -rf ~/.debug/
# perf buildid-cache -a ./mymodule.ko
# perf probe -m ./mymodule.ko -a get_mymodule_val
Added new event:
probe:get_mymodule_val (on get_mymodule_val in mymodule)
You can now use it in all perf tools, such as:
perf record -e probe:get_mymodule_val -aR sleep 1
# perf record -e probe:get_mymodule_val cat /proc/mymodule
mymodule:3
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.011 MB perf.data (1 samples) ]
# perf report --stdio
[SNIP]
#
# Overhead Command Shared Object Symbol
# ........ ....... ................ ......................
#
100.00% cat [mymodule] [k] 0x0000000000000001
# perf report -vvvv --stdio
dso__load_sym: adjusting symbol: st_value: 0 sh_addr: 0 sh_offset: 0x70
symbol__new: get_mymodule_val 0x70-0x8a
[SNIP]
This is caused by dso__load() -> dso__load_sym(). In dso__load(), kmod
is true only when dso is regular kernel module. All files loaded from
buildid-cache is treated as user programs. Following dso__load_sym()
set map->pgoff incorrectly.
This patch gives kernel modules in buildid-cache a chance to adjust
value of kmod. After dso__load() get the type of symbols, if it is
buildid, check the last 3 chars of original filename against '.ko',
and adjust the value of kmod if the file is a kernel module.
Signed-off-by: Wang Nan <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Li Zefan <redacted>
---
tools/perf/util/build-id.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/build-id.h | 1 +
tools/perf/util/symbol.c | 4 ++++
3 files changed, 49 insertions(+)
Copying perf to old kernel system results:
# perf test bpf
37: Test BPF filter :
37.1: Test basic BPF filtering : FAILED!
37.2: Test BPF prologue generation : Skip
However, in case when kernel doesn't support a test case it should
return 'Skip', 'FAILED!' should be reserved for kernel tests for when
the kernel supports a feature that then fails to work as advertised.
This patch checks environment before real testcase.
Signed-off-by: Wang Nan <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
---
tools/perf/tests/bpf.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
@@ -891,10 +893,73 @@ bpf__obj_config_map_value(struct bpf_map *map,if(term->type_val==PARSE_EVENTS__TERM_TYPE_NUM)returnbpf__obj_config_map_array_value(map,term);-pr_debug("ERROR: wrong value type\n");+pr_debug("ERROR: wrong value type for 'value'\n");return-BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE;}+staticint+bpf__obj_config_map_array_event(structbpf_map*map,+structparse_events_term*term,+structperf_evlist*evlist)+{+structperf_evsel*evsel;+structbpf_map_defdef;+structbpf_map_op*op;+constchar*map_name;+interr;++map_name=bpf_map__get_name(map);+evsel=perf_evlist__find_evsel_by_str(evlist,term->val.str);+if(!evsel){+pr_debug("Event (for '%s') '%s' doesn't exist\n",+map_name,term->val.str);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT;+}++err=bpf_map__get_def(map,&def);+if(err){+pr_debug("Unable to get map definition from '%s'\n",+map_name);+returnerr;+}++/*+*Noneedtocheckkey_sizeandvalue_size:+*kernelhasalreadycheckedthem.+*/+if(def.type!=BPF_MAP_TYPE_PERF_EVENT_ARRAY){+pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n",+map_name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;+}++op=bpf_map_op__alloc(map);+if(IS_ERR(op))+returnPTR_ERR(op);++op->v.evsel=evsel;+op->op_type=BPF_MAP_OP_SET_EVSEL;+return0;+}++staticint+bpf__obj_config_map_event(structbpf_map*map,+structparse_events_term*term,+structperf_evlist*evlist)+{+if(!term->err_val){+pr_debug("Config value not set\n");+return-BPF_LOADER_ERRNO__OBJCONF_CONF;+}++if(term->type_val==PARSE_EVENTS__TERM_TYPE_STR)+returnbpf__obj_config_map_array_event(map,term,evlist);++pr_debug("ERROR: wrong value type for 'event'\n");+return-BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE;+}++structbpf_obj_config_map_func{constchar*config_opt;int(*config_func)(structbpf_map*,structparse_events_term*,
@@ -1101,6 +1168,60 @@ apply_config_value_for_key(int map_fd, void *pkey,}staticint+apply_config_evsel_for_key(constchar*name,intmap_fd,void*pkey,+structperf_evsel*evsel)+{+structxyarray*xy=evsel->fd;+structperf_event_attr*attr;+unsignedintkey,events;+boolcheck_pass=false;+int*evt_fd;+interr;++if(!xy){+pr_debug("ERROR: evsel not ready for map %s\n",name);+return-BPF_LOADER_ERRNO__INTERNAL;+}++if(xy->row_size/xy->entry_size!=1){+pr_debug("ERROR: Dimension of target event is incorrect for map %s\n",+name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM;+}++attr=&evsel->attr;+if(attr->inherit){+pr_debug("ERROR: Can't put inherit event into map %s\n",name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH;+}++if(attr->type==PERF_TYPE_RAW)+check_pass=true;+if(attr->type==PERF_TYPE_HARDWARE)+check_pass=true;+if(attr->type==PERF_TYPE_SOFTWARE&&+attr->config==PERF_COUNT_SW_BPF_OUTPUT)+check_pass=true;+if(!check_pass){+pr_debug("ERROR: Event type is wrong for map %s\n",name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE;+}++events=xy->entries/(xy->row_size/xy->entry_size);+key=*((unsignedint*)pkey);+if(key>=events){+pr_debug("ERROR: there is no event %d for map %s\n",+key,name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE;+}+evt_fd=xyarray__entry(xy,key,0);+err=bpf_map_update_elem(map_fd,pkey,evt_fd,BPF_ANY);+if(err&&errno)+err=-errno;+returnerr;+}++staticintapply_obj_config_map_for_key(constchar*name,intmap_fd,structbpf_map_def*pdef__maybe_unused,structbpf_map_op*op,
@@ -1114,6 +1235,10 @@ apply_obj_config_map_for_key(const char *name, int map_fd,pdef->value_size,op->v.value);break;+caseBPF_MAP_OP_SET_EVSEL:+err=apply_config_evsel_for_key(name,map_fd,pkey,+op->v.evsel);+break;default:pr_debug("ERROR: unknown value type for '%s'\n",name);err=-BPF_LOADER_ERRNO__INTERNAL;
@@ -1179,6 +1304,11 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {[ERRCODE_OFFSET(OBJCONF_MAP_TYPE)]="Incorrect map type",[ERRCODE_OFFSET(OBJCONF_MAP_KEYSIZE)]="Incorrect map key size",[ERRCODE_OFFSET(OBJCONF_MAP_VALUESIZE)]="Incorrect map value size",+[ERRCODE_OFFSET(OBJCONF_MAP_NOEVT)]="Event not found for map setting",+[ERRCODE_OFFSET(OBJCONF_MAP_MAPSIZE)]="Invalid map size for event setting",+[ERRCODE_OFFSET(OBJCONF_MAP_EVTDIM)]="Event dimension too large",+[ERRCODE_OFFSET(OBJCONF_MAP_EVTINH)]="Doesn't support inherit event",+[ERRCODE_OFFSET(OBJCONF_MAP_EVTTYPE)]="Wrong event type for map",};staticint
@@ -1315,6 +1445,12 @@ int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,intbpf__strerror_apply_obj_config(interr,char*buf,size_tsize){bpf__strerror_head(err,buf,size);+bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,+"Cannot set event to BPF maps in multi-thread tracing");+bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,+"%s (Hint: use -i to turn off inherit)",emsg);+bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,+"Can only put raw, hardware and BPF output event into a BPF map");bpf__strerror_end(buf,size);return0;}
@@ -33,6 +33,11 @@ enum bpf_loader_errno {BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE,/* Incorrect map type */BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE,/* Incorrect map key size */BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE,/* Incorrect map value size */+BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT,/* Event not found for map setting */+BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE,/* Invalid map size for event setting */+BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,/* Event dimension too large */+BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,/* Doesn't support inherit event */+BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,/* Wrong event type for map */__BPF_LOADER_ERRNO__END,};
make_kernelsrc and make_kernelsrc_tools are skiped if a previous
build-test is done, because 'make build-test' creates two files with
same names. To avoid this, they should be included in .PHONY list.
Signed-off-by: Wang Nan <redacted>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/tests/make | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
If an 'O' is passed to 'make build-test', many 'test -x' and 'test -f'
will fail because perf resides in a different directory. Fix this by
computing PERF_OUT according to 'O' and test correct output files.
For make_kernelsrc and make_kernelsrc_tools, set KBUILD_OUTPUT_DIR
instead because the path is different from others ($(O)/perf vs
$(O)/tools/perf).
Signed-off-by: Wang Nan <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/tests/make | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
@@ -159,11 +161,11 @@ test_make_doc := $(test_ok) test_make_help_O := $(test_ok) test_make_doc_O := $(test_ok)-test_make_python_perf_so := test -f $(PERF)/python/perf.so+test_make_python_perf_so := test -f $(PERF_OUT)/python/perf.so-test_make_perf_o := test -f $(PERF)/perf.o-test_make_util_map_o := test -f $(PERF)/util/map.o-test_make_util_pmu_bison_o := test -f $(PERF)/util/pmu-bison.o+test_make_perf_o := test -f $(PERF_OUT)/perf.o+test_make_util_map_o := test -f $(PERF_OUT)/util/map.o+test_make_util_pmu_bison_o := test -f $(PERF_OUT)/util/pmu-bison.o define test_dest_files for file in $(1); do \
@@ -230,7 +232,7 @@ test_make_perf_o_O := test -f $$TMP_O/perf.o test_make_util_map_o_O := test -f $$TMP_O/util/map.o test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o-test_default = test -x $(PERF)/perf+test_default = test -x $(PERF_OUT)/perf test = $(if $(test_$1),$(test_$1),$(test_default)) test_default_O = test -x $$TMP_O/perf
perf_event__synthesize_mmap_events() issues mmap2 events, but the
memory of that event is allocated using:
mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
If path of mmap source file is long (near PATH_MAX), random crash
would happen. Should use sizeof(mmap_event->mmap2).
Fix two memory allocations and rename all mmap_event to mmap2_event
to make it clear.
Signed-off-by: Wang Nan <redacted>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: He Kuang <redacted>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/event.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
@@ -413,7 +413,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool,}staticint__event__synthesize_thread(unionperf_event*comm_event,-unionperf_event*mmap_event,+unionperf_event*mmap2_event,unionperf_event*fork_event,pid_tpid,intfull,perf_event__handler_tprocess,
@@ -436,7 +436,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,if(tgid==-1)return-1;-returnperf_event__synthesize_mmap_events(tool,mmap_event,pid,tgid,+returnperf_event__synthesize_mmap_events(tool,mmap2_event,pid,tgid,process,machine,mmap_data,proc_map_timeout);}
@@ -478,7 +478,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,rc=0;if(_pid==pid){/* process the parent's maps too */-rc=perf_event__synthesize_mmap_events(tool,mmap_event,pid,tgid,+rc=perf_event__synthesize_mmap_events(tool,mmap2_event,pid,tgid,process,machine,mmap_data,proc_map_timeout);if(rc)break;
@@ -496,15 +496,15 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,boolmmap_data,unsignedintproc_map_timeout){-unionperf_event*comm_event,*mmap_event,*fork_event;+unionperf_event*comm_event,*mmap2_event,*fork_event;interr=-1,thread,j;comm_event=malloc(sizeof(comm_event->comm)+machine->id_hdr_size);if(comm_event==NULL)gotoout;-mmap_event=malloc(sizeof(mmap_event->mmap)+machine->id_hdr_size);-if(mmap_event==NULL)+mmap2_event=malloc(sizeof(mmap2_event->mmap2)+machine->id_hdr_size);+if(mmap2_event==NULL)gotoout_free_comm;fork_event=malloc(sizeof(fork_event->fork)+machine->id_hdr_size);
@@ -513,7 +513,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,err=0;for(thread=0;thread<threads->nr;++thread){-if(__event__synthesize_thread(comm_event,mmap_event,+if(__event__synthesize_thread(comm_event,mmap2_event,fork_event,thread_map__pid(threads,thread),0,process,tool,machine,
@@ -539,7 +539,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,/* if not, generate events for it */if(need_leader&&-__event__synthesize_thread(comm_event,mmap_event,+__event__synthesize_thread(comm_event,mmap2_event,fork_event,comm_event->comm.pid,0,process,tool,machine,
@@ -551,7 +551,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,}free(fork_event);out_free_mmap:-free(mmap_event);+free(mmap2_event);out_free_comm:free(comm_event);out:
@@ -567,7 +567,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,DIR*proc;charproc_path[PATH_MAX];structdirentdirent,*next;-unionperf_event*comm_event,*mmap_event,*fork_event;+unionperf_event*comm_event,*mmap2_event,*fork_event;interr=-1;if(machine__is_default_guest(machine))
@@ -577,8 +577,8 @@ int perf_event__synthesize_threads(struct perf_tool *tool,if(comm_event==NULL)gotoout;-mmap_event=malloc(sizeof(mmap_event->mmap)+machine->id_hdr_size);-if(mmap_event==NULL)+mmap2_event=malloc(sizeof(mmap2_event->mmap2)+machine->id_hdr_size);+if(mmap2_event==NULL)gotoout_free_comm;fork_event=malloc(sizeof(fork_event->fork)+machine->id_hdr_size);
@@ -601,7 +601,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,*Wemayracewithexitingthread,sodon'tstopjustbecause*onethreadcouldn'tbesynthesized.*/-__event__synthesize_thread(comm_event,mmap_event,fork_event,pid,+__event__synthesize_thread(comm_event,mmap2_event,fork_event,pid,1,process,tool,machine,mmap_data,proc_map_timeout);}
@@ -611,7 +611,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,out_free_fork:free(fork_event);out_free_mmap:-free(mmap_event);+free(mmap2_event);out_free_comm:free(comm_event);out:
Commit 71d6de64feddd4b455555326fba2111b3006d9e0 ('perf test: Fix hist
testcases when kptr_restrict is on') solves a double free problem when
'perf test hist' calling setup_fake_machine(). However, the result is
still incorrect. For example:
$ ./perf test -v 'filtering hist entries'
25: Test filtering hist entries :
--- start ---
test child forked, pid 4186
Cannot create kernel maps
test child finished with 0
---- end ----
Test filtering hist entries: Ok
In this case the body of this test is not get executed at all, but the
result is 'Ok'.
Actually, in setup_fake_machine() there's no need to create real kernel
maps. What we want is the fake maps. This patch removes the
machine__create_kernel_maps() in setup_fake_machine(), so it won't be
affected by kptr_restrict setting.
Test result:
$ cat /proc/sys/kernel/kptr_restrict
1
$ ~/perf test -v hist
15: Test matching and linking multiple hists :
--- start ---
test child forked, pid 24031
test child finished with 0
---- end ----
Test matching and linking multiple hists: Ok
[SNIP]
Signed-off-by: Wang Nan <redacted>
Suggested-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
---
tools/perf/tests/hists_common.c | 5 -----
1 file changed, 5 deletions(-)
This patch adds the final step for BPF map configuration. A new syntax
is appended into parser so user can config BPF objects through '/' '/'
enclosed config terms.
After this patch, following syntax is available:
# perf record -e ./test_bpf_map_1.c/maps:channel.value=10/ ...
It would takes effect after appling following commits.
Test result:
# cat ./test_bpf_map_1.c
/************************ BEGIN **************************/
#include <uapi/linux/bpf.h>
#define SEC(NAME) __attribute__((section(NAME), used))
struct bpf_map_def {
unsigned int type;
unsigned int key_size;
unsigned int value_size;
unsigned int max_entries;
};
static void *(*map_lookup_elem)(struct bpf_map_def *, void *) =
(void *)BPF_FUNC_map_lookup_elem;
static int (*trace_printk)(const char *fmt, int fmt_size, ...) =
(void *)BPF_FUNC_trace_printk;
struct bpf_map_def SEC("maps") channel = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 1,
};
SEC("func=sys_nanosleep")
int func(void *ctx)
{
int key = 0;
char fmt[] = "%d\n";
int *pval = map_lookup_elem(&channel, &key);
if (!pval)
return 0;
trace_printk(fmt, sizeof(fmt), *pval);
return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
/************************* END ***************************/
- Normal case:
# ./perf record -e './test_bpf_map_1.c/maps:channel.value=10/' usleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.012 MB perf.data ]
- Error case:
# ./perf record -e './test_bpf_map_1.c/maps:channel.value/' usleep 10
event syntax error: '..ps:channel:value/'
\___ Config value not set (lost '=')
Hint: Valid config term:
maps:[<arraymap>]:value=[value]
(add -v to see detail)
Run 'perf list' for a list of valid events
Usage: perf record [<options>] [<command>]
or: perf record [<options>] -- <command> [<options>]
-e, --event <event> event selector. use 'perf list' to list available events
# ./perf record -e './test_bpf_map_1.c/xmaps:channel.value=10/' usleep 10
event syntax error: '..pf_map_1.c/xmaps:channel.value=10/'
\___ Invalid object config option
[SNIP]
# ./perf record -e './test_bpf_map_1.c/maps:xchannel.value=10/' usleep 10
event syntax error: '..p_1.c/maps:xchannel.value=10/'
\___ Target map not exist
[SNIP]
# ./perf record -e './test_bpf_map_1.c/maps:channel.xvalue=10/' usleep 10
event syntax error: '..ps:channel.xvalue=10/'
\___ Invalid object maps config option
[SNIP]
# ./perf record -e './test_bpf_map_1.c/maps:channel.value=x10/' usleep 10
event syntax error: '..nnel.value=x10/'
\___ Incorrect value type for map
[SNIP]
Change BPF_MAP_TYPE_ARRAY to '1':
# ./perf record -e './test_bpf_map_1.c/maps:channel.value=10/' usleep 10
event syntax error: '..ps:channel.value=10/'
\___ Can't use this config term to this type of map
Hint: Valid config term:
maps:[<arraymap>].value=[value]
(add -v to see detail)
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/parse-events.c | 56 +++++++++++++++++++++++++++++++++++++++---
tools/perf/util/parse-events.h | 3 ++-
tools/perf/util/parse-events.l | 2 +-
tools/perf/util/parse-events.y | 23 ++++++++++++++---
4 files changed, 75 insertions(+), 9 deletions(-)
@@ -628,17 +628,64 @@ errout:returnerr;}+staticint+parse_events_config_bpf(structparse_events_evlist*data,+structbpf_object*obj,+structlist_head*head_config)+{+structparse_events_term*term;+interror_pos;++if(!head_config||list_empty(head_config))+return0;++list_for_each_entry(term,head_config,list){+charerrbuf[BUFSIZ];+interr;++if(term->type_term!=PARSE_EVENTS__TERM_TYPE_USER){+snprintf(errbuf,sizeof(errbuf),+"Invalid config term for BPF object");+errbuf[BUFSIZ-1]='\0';++data->error->idx=term->err_term;+data->error->str=strdup(errbuf);+return-EINVAL;+}++err=bpf__config_obj(obj,term,NULL,&error_pos);+if(err){+bpf__strerror_config_obj(obj,term,NULL,+&error_pos,err,errbuf,+sizeof(errbuf));+data->error->help=strdup(+"Hint:\tValid config term:\n"+" \tmaps:[<arraymap>].value=[value]\n"+" \t(add -v to see detail)");+data->error->str=strdup(errbuf);+if(err==-BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE)+data->error->idx=term->err_val;+else+data->error->idx=term->err_term+error_pos;+returnerr;+}+}+return0;++}+intparse_events_load_bpf(structparse_events_evlist*data,structlist_head*list,char*bpf_file_name,-boolsource)+boolsource,+structlist_head*head_config){structbpf_object*obj;+interr;obj=bpf__prepare_load(bpf_file_name,source);if(IS_ERR(obj)){charerrbuf[BUFSIZ];-interr;err=PTR_ERR(obj);
@@ -656,7 +703,10 @@ int parse_events_load_bpf(struct parse_events_evlist *data,returnerr;}-returnparse_events_load_bpf_obj(data,list,obj);+err=parse_events_load_bpf_obj(data,list,obj);+if(err)+returnerr;+returnparse_events_config_bpf(data,obj,head_config);}staticint
@@ -126,7 +126,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,intparse_events_load_bpf(structparse_events_evlist*data,structlist_head*list,char*bpf_file_name,-boolsource);+boolsource,+structlist_head*head_config);/* Provide this function for perf test */structbpf_object;intparse_events_load_bpf_obj(structparse_events_evlist*data,
@@ -122,7 +122,7 @@ num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+ name [a-zA-Z_*?][a-zA-Z0-9_*?.]*-name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.]*+name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* /* If you add a modifier you need to update check_modifier() */ modifier_event [ukhpPGHSDI]+ modifier_bp [rwx]{1,3}
All hists test cases forget to reset err after using it to hold an
error code. If error occure in setup_fake_machine() it incorrectly
return TEST_OK.
This patch fixes it.
Signed-off-by: Wang Nan <redacted>
Suggested-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
---
tools/perf/tests/hists_cumulate.c | 1 +
tools/perf/tests/hists_filter.c | 1 +
tools/perf/tests/hists_link.c | 1 +
tools/perf/tests/hists_output.c | 1 +
4 files changed, 4 insertions(+)
@@ -120,6 +120,7 @@ int test__hists_filter(int subtest __maybe_unused)err=parse_events(evlist,"task-clock",NULL);if(err)gotoout;+err=TEST_FAIL;/* default sort order (comm,dso,sym) will be used */if(setup_sorting(NULL)<0)
@@ -293,6 +293,7 @@ int test__hists_link(int subtest __maybe_unused)if(err)gotoout;+err=TEST_FAIL;/* default sort order (comm,dso,sym) will be used */if(setup_sorting(NULL)<0)gotoout;
After this patch other directories can use this architecture detector
without directly including it from perf's directory. Libbpf would
utilize it to get proper $(ARCH) so it can receive correct uapi include
directory.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: Arnaldo Carvalho de Melo <acme@kernel.org>
[Add missing srctree definition in tests/make]
Hi Arnaldo, I guess you will be okay provide your SOB so I add it here.
You didn't provide it on your original code.
Thank you.
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 14:11:10
Em Mon, Jan 11, 2016 at 09:52:38PM +0800, Wangnan (F) escreveu:
On 2016/1/11 21:47, Wang Nan wrote:
quoted
After this patch other directories can use this architecture detector
without directly including it from perf's directory. Libbpf would
utilize it to get proper $(ARCH) so it can receive correct uapi include
directory.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: Arnaldo Carvalho de Melo <acme@kernel.org>
[Add missing srctree definition in tests/make]
Hi Arnaldo, I guess you will be okay provide your SOB so I add it here.
You didn't provide it on your original code.
Sure, and I'll cherry pick this into perf/urgent, to get the PowerPC
build fixed.
- Arnaldo
Existing test-all.c doesn't check BPF related features. For environment
with all other features enabled, BPF would be considered enabled
without doing real feature check.
This patch adds test-bpf.c into test-all.c.
Signed-off-by: Wang Nan <redacted>
Acked-by: Jiri Olsa <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/build/feature/test-all.c | 5 +++++
1 file changed, 5 insertions(+)
bpf__config_obj() is introduced as a core API to config BPF object
after loading. One configuration option of maps is introduced. After
this patch BPF object can accept configuration like:
maps:my_map.value=1234
(maps.my_map.value looks pretty. However, there's a small but hard
to fixed problem related to flex's greedy matching. Please see [1].
Choose ':' to avoid it in a simpler way.)
This patch is more complex than the work it really does because the
consideration of extension. In designing of BPF map configuration,
following things should be considered:
1. Array indices selection: perf should allow user setting different
value to different slots in an array, with syntax like:
maps:my_map.value[0,3...6]=1234;
2. A map can be config by different config terms, each for a part
of it. For example, set each slot to pid of a thread;
3. Type of value: integer is not the only valid value type. Perf
event can also be put into a map after commit 35578d7984003097af2b1e3
(bpf: Implement function bpf_perf_event_read() that get the selected
hardware PMU conuter);
4. For hash table, it is possible to use string or other as key;
5. It is possible that map configuration is unable to be setup
during parsing. Perf event is an example.
Therefore, this patch does following:
1. Instead of updating map element during parsing, this patch stores
map config options in 'struct bpf_map_priv'. Following patches
would apply those configs at proper time;
2. Link map operations to a list so a map can have multiple config
terms attached, so different parts can be configured separately;
3. Make 'struct bpf_map_priv' extensible so following patches can
add new types of keys and operations;
4. Use bpf_config_map_funcs array to support more maps config options.
Since the patch changing event parser to parse BPF object config is
relative large, I put in another commit. Code in this patch
could be tested after applying next patch.
[1] http://lkml.kernel.org/g/564ED621.4050500@huawei.com
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/bpf-loader.c | 266 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/bpf-loader.h | 38 +++++++
2 files changed, 304 insertions(+)
@@ -739,6 +739,251 @@ int bpf__foreach_tev(struct bpf_object *obj,return0;}+enumbpf_map_op_type{+BPF_MAP_OP_SET_VALUE,+};++enumbpf_map_key_type{+BPF_MAP_KEY_ALL,+};++structbpf_map_op{+structlist_headlist;+enumbpf_map_op_typeop_type;+enumbpf_map_key_typekey_type;+union{+u64value;+}v;+};++structbpf_map_priv{+structlist_headops_list;+};++staticvoid+bpf_map_op__free(structbpf_map_op*op)+{+structlist_head*list=&op->list;+/*+*bpf_map_op__free()needstoconsiderfollowingcases:+*1.Whentheopiscreatedbutnotlinkedtoanylist:+*impossible.Thisonlyhappeninbpf_map_op__alloc()+*anditwouldbefreeddirectly;+*2.Normalcase,whentheopislinkedtoalist;+*3.Aftertheophasalreadyberemoved.+*Thankstolist.h,ifithasremovedbylist_del()then+*list->{next,prev}shouldhavebeensettoLIST_POISON{1,2}.+*/+if((list->next!=LIST_POISON1)&&(list->prev!=LIST_POISON2))+list_del(list);+free(op);+}++staticvoid+bpf_map_priv__clear(structbpf_map*map__maybe_unused,+void*_priv)+{+structbpf_map_priv*priv=_priv;+structbpf_map_op*pos,*n;++list_for_each_entry_safe(pos,n,&priv->ops_list,list)+bpf_map_op__free(pos);+free(priv);+}++staticstructbpf_map_op*+bpf_map_op__alloc(structbpf_map*map)+{+structbpf_map_op*op;+structbpf_map_priv*priv;+constchar*map_name;+interr;++map_name=bpf_map__get_name(map);+err=bpf_map__get_private(map,(void**)&priv);+if(err){+pr_debug("Failed to get private from map %s\n",map_name);+returnERR_PTR(err);+}++if(!priv){+priv=zalloc(sizeof(*priv));+if(!priv){+pr_debug("No enough memory to alloc map private\n");+returnERR_PTR(-ENOMEM);+}+INIT_LIST_HEAD(&priv->ops_list);++if(bpf_map__set_private(map,priv,bpf_map_priv__clear)){+free(priv);+returnERR_PTR(-BPF_LOADER_ERRNO__INTERNAL);+}+}++op=zalloc(sizeof(*op));+if(!op){+pr_debug("Failed to alloc bpf_map_op\n");+returnERR_PTR(-ENOMEM);+}++op->key_type=BPF_MAP_KEY_ALL;+list_add_tail(&op->list,&priv->ops_list);+returnop;+}++staticint+bpf__obj_config_map_array_value(structbpf_map*map,+structparse_events_term*term)+{+structbpf_map_defdef;+structbpf_map_op*op;+constchar*map_name;+interr;++map_name=bpf_map__get_name(map);++err=bpf_map__get_def(map,&def);+if(err){+pr_debug("Unable to get map definition from '%s'\n",+map_name);+return-BPF_LOADER_ERRNO__INTERNAL;+}++if(def.type!=BPF_MAP_TYPE_ARRAY){+pr_debug("Map %s type is not BPF_MAP_TYPE_ARRAY\n",+map_name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;+}+if(def.key_size<sizeof(unsignedint)){+pr_debug("Map %s has incorrect key size\n",map_name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE;+}+switch(def.value_size){+case1:+case2:+case4:+case8:+break;+default:+pr_debug("Map %s has incorrect value size\n",map_name);+return-BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE;+}++op=bpf_map_op__alloc(map);+if(IS_ERR(op))+returnPTR_ERR(op);+op->op_type=BPF_MAP_OP_SET_VALUE;+op->v.value=term->val.num;+return0;+}++staticint+bpf__obj_config_map_value(structbpf_map*map,+structparse_events_term*term,+structperf_evlist*evlist__maybe_unused)+{+if(!term->err_val){+pr_debug("Config value not set\n");+return-BPF_LOADER_ERRNO__OBJCONF_CONF;+}++if(term->type_val==PARSE_EVENTS__TERM_TYPE_NUM)+returnbpf__obj_config_map_array_value(map,term);++pr_debug("ERROR: wrong value type\n");+return-BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE;+}++structbpf_obj_config_map_func{+constchar*config_opt;+int(*config_func)(structbpf_map*,structparse_events_term*,+structperf_evlist*);+};++structbpf_obj_config_map_funcbpf_obj_config_map_funcs[]={+{"value",bpf__obj_config_map_value},+};++staticint+bpf__obj_config_map(structbpf_object*obj,+structparse_events_term*term,+structperf_evlist*evlist,+int*key_scan_pos)+{+/* key is "maps:<mapname>.<config opt>" */+char*map_name=strdup(term->config+sizeof("maps:")-1);+structbpf_map*map;+interr=-BPF_LOADER_ERRNO__OBJCONF_OPT;+char*map_opt;+size_ti;++if(!map_name)+return-ENOMEM;++map_opt=strchr(map_name,'.');+if(!map_opt){+pr_debug("ERROR: Invalid map config: %s\n",map_name);+gotoout;+}++*map_opt++='\0';+if(*map_opt=='\0'){+pr_debug("ERROR: Invalid map option: %s\n",term->config);+gotoout;+}++map=bpf_object__get_map_by_name(obj,map_name);+if(!map){+pr_debug("ERROR: Map %s is not exist\n",map_name);+err=-BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST;+gotoout;+}++*key_scan_pos+=map_opt-map_name;+for(i=0;i<ARRAY_SIZE(bpf_obj_config_map_funcs);i++){+structbpf_obj_config_map_func*func=+&bpf_obj_config_map_funcs[i];++if(strcmp(map_opt,func->config_opt)==0){+err=func->config_func(map,term,evlist);+gotoout;+}+}++pr_debug("ERROR: invalid config option '%s' for maps\n",+map_opt);+err=-BPF_LOADER_ERRNO__OBJCONF_MAP_OPT;+out:+free(map_name);+if(!err)+key_scan_pos+=strlen(map_opt);+returnerr;+}++intbpf__config_obj(structbpf_object*obj,+structparse_events_term*term,+structperf_evlist*evlist,+int*error_pos)+{+intkey_scan_pos=0;+interr;++if(!obj||!term||!term->config)+return-EINVAL;++if(!prefixcmp(term->config,"maps:")){+key_scan_pos=sizeof("maps:")-1;+err=bpf__obj_config_map(obj,term,evlist,&key_scan_pos);+gotoout;+}+err=-BPF_LOADER_ERRNO__OBJCONF_OPT;+out:+if(error_pos)+*error_pos=key_scan_pos;+returnerr;++}+#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
@@ -753,6 +998,14 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {[ERRCODE_OFFSET(PROLOGUE)]="Failed to generate prologue",[ERRCODE_OFFSET(PROLOGUE2BIG)]="Prologue too big for program",[ERRCODE_OFFSET(PROLOGUEOOB)]="Offset out of bound for prologue",+[ERRCODE_OFFSET(OBJCONF_OPT)]="Invalid object config option",+[ERRCODE_OFFSET(OBJCONF_CONF)]="Config value not set (lost '=')",+[ERRCODE_OFFSET(OBJCONF_MAP_OPT)]="Invalid object maps config option",+[ERRCODE_OFFSET(OBJCONF_MAP_NOTEXIST)]="Target map not exist",+[ERRCODE_OFFSET(OBJCONF_MAP_VALUE)]="Incorrect value type for map",+[ERRCODE_OFFSET(OBJCONF_MAP_TYPE)]="Incorrect map type",+[ERRCODE_OFFSET(OBJCONF_MAP_KEYSIZE)]="Incorrect map key size",+[ERRCODE_OFFSET(OBJCONF_MAP_VALUESIZE)]="Incorrect map value size",};staticint
@@ -872,3 +1125,16 @@ int bpf__strerror_load(struct bpf_object *obj,bpf__strerror_end(buf,size);return0;}++intbpf__strerror_config_obj(structbpf_object*obj__maybe_unused,+structparse_events_term*term__maybe_unused,+structperf_evlist*evlist__maybe_unused,+int*error_pos__maybe_unused,interr,+char*buf,size_tsize)+{+bpf__strerror_head(err,buf,size);+bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE,+"Can't use this config term to this type of map");+bpf__strerror_end(buf,size);+return0;+}
@@ -24,10 +25,19 @@ enum bpf_loader_errno {BPF_LOADER_ERRNO__PROLOGUE,/* Failed to generate prologue */BPF_LOADER_ERRNO__PROLOGUE2BIG,/* Prologue too big for program */BPF_LOADER_ERRNO__PROLOGUEOOB,/* Offset out of bound for prologue */+BPF_LOADER_ERRNO__OBJCONF_OPT,/* Invalid object config option */+BPF_LOADER_ERRNO__OBJCONF_CONF,/* Config value not set (lost '=')) */+BPF_LOADER_ERRNO__OBJCONF_MAP_OPT,/* Invalid object maps config option */+BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST,/* Target map not exist */+BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE,/* Incorrect value type for map */+BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE,/* Incorrect map type */+BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE,/* Incorrect map key size */+BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE,/* Incorrect map value size */__BPF_LOADER_ERRNO__END,};structbpf_object;+structparse_events_term;#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"typedefint(*bpf_prog_iter_callback_t)(structprobe_trace_event*tev,
@@ -53,6 +63,14 @@ int bpf__strerror_load(struct bpf_object *obj, int err,char*buf,size_tsize);intbpf__foreach_tev(structbpf_object*obj,bpf_prog_iter_callback_tfunc,void*arg);++intbpf__config_obj(structbpf_object*obj,structparse_events_term*term,+structperf_evlist*evlist,int*error_pos);+intbpf__strerror_config_obj(structbpf_object*obj,+structparse_events_term*term,+structperf_evlist*evlist,+int*error_pos,interr,char*buf,+size_tsize);#elsestaticinlinestructbpf_object*bpf__prepare_load(constchar*filename__maybe_unused,
Without this patch, the last output doesn't have timestamp appended if
--timestamp-filename is not explicitly provided. For example:
# perf record -a --switch-output &
[1] 11224
# kill -s SIGUSR2 11224
[ perf record: dump data: Woken up 1 times ]
# [ perf record: Dump perf.data.2015122622372823 ]
# fg
perf record -a --switch-output
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.027 MB perf.data (540 samples) ]
# ls -l
total 836
-rw------- 1 root root 33256 Dec 26 22:37 perf.data <---- *Odd*
-rw------- 1 root root 817156 Dec 26 22:37 perf.data.2015122622372823
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 3 +++
1 file changed, 3 insertions(+)
@@ -1312,13 +1312,12 @@ apply_config_evsel_for_key(const char *name, int map_fd, void *pkey,return-BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH;}+if(perf_evsel__is_bpf_output(evsel))+check_pass=true;if(attr->type==PERF_TYPE_RAW)check_pass=true;if(attr->type==PERF_TYPE_HARDWARE)check_pass=true;-if(attr->type==PERF_TYPE_SOFTWARE&&-attr->config==PERF_COUNT_SW_BPF_OUTPUT)-check_pass=true;if(!check_pass){pr_debug("ERROR: Event type is wrong for map %s\n",name);return-BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE;
To prevent futher commits calling machine__delete() on non-allocated
'struct machine' (which would cause memory corruption), this patch
enforces machine__init(), record whether a machine structure is
dynamically allocated or not, and warn if machine__delete() is called
on incorrect object.
Signed-off-by: Wang Nan <redacted>
Reviewed-by: Masami Hiramatsu <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/tests/vmlinux-kallsyms.c | 4 ++--
tools/perf/util/machine.c | 13 ++++++++-----
tools/perf/util/machine.h | 3 ++-
3 files changed, 12 insertions(+), 8 deletions(-)
'make build-test' is painful because of time consuming. In a full test,
all test cases are built twice with tools/perf/Makefile and
tools/perf/Makefile.perf. 'Makefile' automatically computes parallel
options for make, but 'Makefile.perf' not, so all test cases is built
with one job. It is very slow.
This patch adds '-j' options to Makefile.perf testing. It computes
parallel building options like what tools/perf/Makefile does, and pass
'-j' option to Makefile.perf test.
Signed-off-by: Wang Nan <redacted>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/tests/make | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
From: He Kuang <redacted>
This patch is useful when trying to pass a perf event to BPF map.
Before this patch we are unable to pass an event with config term to
BPF maps. For example:
# perf record -a -e cycles/no-inherit,period=0x7fffffffffffffff/ \
-e './test_bpf_map_2.c/maps:pmu_map.event=cycles/no-inherit,period=0x7fffffffffffffff//' ls /
event syntax error: '..ps:pmu_map.event=cycles/'
\___ Event not found for map setting
Because those '/' and ',' embarrass parser.
This patch adds new bison rules for specifying an alias name to a perf
event, which allows cmdline refer to previous defined perf event through
its name. With this patch user can give alias name to a perf event using
following cmdline. The above goal can be achieved using:
# perf record -a -e cyc=cycles/no-inherit,period=0x7fffffffffffffff/ \
-e './test_bpf_map_2.c/maps:pmu_map.event=cyc/' ls /
If alias is not provided (normal case):
# perf record -e cycles ...
It will be set to event's name automatically ('cycles' in the above
example).
To allow parser refer to existing event selector, pass event list to
'struct parse_events_evlist'. perf_evlist__find_evsel_by_alias() is
introduced to get evsel through its alias.
Test result:
# cat ./test_bpf_map_2.c
/************************ BEGIN **************************/
#include <uapi/linux/bpf.h>
#define SEC(NAME) __attribute__((section(NAME), used))
struct bpf_map_def {
unsigned int type;
unsigned int key_size;
unsigned int value_size;
unsigned int max_entries;
};
static int (*trace_printk)(const char *fmt, int fmt_size, ...) =
(void *)BPF_FUNC_trace_printk;
static int (*get_smp_processor_id)(void) =
(void *)BPF_FUNC_get_smp_processor_id;
static int (*perf_event_read)(struct bpf_map_def *, int) =
(void *)BPF_FUNC_perf_event_read;
struct bpf_map_def SEC("maps") pmu_map = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = __NR_CPUS__,
};
SEC("func_write=sys_write")
int func_write(void *ctx)
{
unsigned long long val;
char fmt[] = "sys_write: pmu=%llu\n";
val = perf_event_read(&pmu_map, get_smp_processor_id());
trace_printk(fmt, sizeof(fmt), val);
return 0;
}
SEC("func_write_return=sys_write%return")
int func_write_return(void *ctx)
{
unsigned long long val = 0;
char fmt[] = "sys_write_return: pmu=%llu\n";
val = perf_event_read(&pmu_map, get_smp_processor_id());
trace_printk(fmt, sizeof(fmt), val);
return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
/************************* END ***************************/
# echo "" > /sys/kernel/debug/tracing/trace
# ./perf record -a -e cyc=cycles/no-inherit,period=0x7fffffffffffffff/ \
-e './test_bpf_map_2.c/maps:pmu_map.event=cyc/' ls /
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.755 MB perf.data ]
# cat /sys/kernel/debug/tracing/trace | grep ls
ls-25328 [002] d... 940138.313178: : sys_write: pmu=4503165
ls-25328 [002] dN.. 940138.313207: : sys_write_return: pmu=4582975
ls-25328 [002] d... 940138.313211: : sys_write: pmu=4599840
ls-25328 [002] dN.. 940138.313220: : sys_write_return: pmu=4633352
# ./perf report --stdio
Error:
The perf.data file has no samples!
...
(This is expected because we set period of cycles to a very large
value to period of cycles event because we want to use this event
as a counter only, don't need sampling)
# ./perf record -e cycles -e './test_bpf_map_2.c/maps:pmu_map.event=cycles/' ls /
ERROR: Apply config to BPF failed: Doesn't support inherit event (Hint: use -i or use /no-inherit/ to turn off inherit)
Signed-off-by: He Kuang <redacted>
Signed-off-by: Wang Nan <redacted>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/bpf-loader.c | 2 +-
tools/perf/util/evlist.c | 4 ++--
tools/perf/util/evsel.c | 1 +
tools/perf/util/evsel.h | 1 +
tools/perf/util/parse-events.c | 26 ++++++++++++++++++++++++++
tools/perf/util/parse-events.h | 4 ++++
tools/perf/util/parse-events.y | 15 ++++++++++++++-
7 files changed, 49 insertions(+), 4 deletions(-)
@@ -1448,7 +1448,7 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size)bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,"Cannot set event to BPF maps in multi-thread tracing");bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,-"%s (Hint: use -i to turn off inherit)",emsg);+"%s (Hint: use -i or use /no-inherit/ to turn off inherit)",emsg);bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,"Can only put raw, hardware and BPF output event into a BPF map");bpf__strerror_end(buf,size);
@@ -1091,6 +1091,30 @@ int parse_events__modifier_group(struct list_head *list,returnparse_events__modifier_event(list,event_mod,true);}+intparse_events__set_event_alias(structparse_events_evlist*data,+structlist_head*list,+constchar*str,+void*loc_alias_)+{+structperf_evsel*evsel;+YYLTYPE*loc_alias=loc_alias_;++if(!str)+return0;++if(!list_is_singular(list)){+structparse_events_error*err=data->error;++err->idx=loc_alias->first_column;+err->str=strdup("One alias can be applied to one event only");+return-EINVAL;+}++evsel=list_first_entry(list,structperf_evsel,node);+evsel->alias=strdup(str);+returnevsel->alias?0:-ENOMEM;+}+voidparse_events__set_leader(char*name,structlist_head*list){structperf_evsel*leader;
@@ -1283,6 +1307,8 @@ int parse_events_name(struct list_head *list, char *name)__evlist__for_each(list,evsel){if(!evsel->name)evsel->name=strdup(name);+if(!evsel->alias)+evsel->alias=strdup(name);}return0;
From: Sergei Shtylyov <hidden> Date: 2016-01-11 14:21:50
Hello.
On 01/11/2016 04:48 PM, Wang Nan wrote:
quoted hunk
When record__mmap_read() require data more than the size of ring
buffer, drop those data to avoid access invalid memory.
This can happen when reading from overwritable ring buffer, which
should be avoided. However, check this for robustness.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 8 ++++++++
1 file changed, 8 insertions(+)
@@ -94,6 +95,13 @@ static int record__mmap_read(struct record *rec, int idx)rec->samples++;size=head-old;+if(size>(unsignedlong)(md->mask)+1){+WARN_ONCE(1,"WARNING: failed to keep up with mmap data. (warn only once)\n");
WARNING is already printed by WARN*(), no?
[...]
MBR, Sergei
From: Sergei Shtylyov <hidden> Date: 2016-01-11 14:25:54
On 01/11/2016 04:48 PM, Wang Nan wrote:
Commit 71d6de64feddd4b455555326fba2111b3006d9e0 ('perf test: Fix hist
testcases when kptr_restrict is on') solves a double free problem when
You didn't run this patch thru scripts/checkpatch.pl, I guess? A certain
commit citing style is enforced now, and yours doesn't quite match it...
'perf test hist' calling setup_fake_machine(). However, the result is
still incorrect. For example:
$ ./perf test -v 'filtering hist entries'
25: Test filtering hist entries :
--- start ---
test child forked, pid 4186
Cannot create kernel maps
test child finished with 0
---- end ----
Test filtering hist entries: Ok
In this case the body of this test is not get executed at all, but the
result is 'Ok'.
Actually, in setup_fake_machine() there's no need to create real kernel
maps. What we want is the fake maps. This patch removes the
machine__create_kernel_maps() in setup_fake_machine(), so it won't be
affected by kptr_restrict setting.
Test result:
$ cat /proc/sys/kernel/kptr_restrict
1
$ ~/perf test -v hist
15: Test matching and linking multiple hists :
--- start ---
test child forked, pid 24031
test child finished with 0
---- end ----
Test matching and linking multiple hists: Ok
[SNIP]
Signed-off-by: Wang Nan <redacted>
Suggested-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
This options append current timestamp to output. For example:
# perf record -a --timestamp-filename
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Dump perf.data.2015122622265847 ]
[ perf record: Captured and wrote 0.742 MB perf.data (90 samples) ]
# ls
perf.data.201512262226584
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 47 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
@@ -53,6 +53,7 @@ struct record {boolno_buildid_set;boolno_buildid_cache;boolno_buildid_cache_set;+booltimestamp_filename;unsignedlonglongsamples;};
@@ -522,6 +523,37 @@ record__finish_output(struct record *rec)return;}+staticint+record__switch_output(structrecord*rec,boolat_exit)+{+structperf_data_file*file=&rec->file;+intfd,err;++/* Same Size: "2015122520103046"*/+chartimestamp[]="InvalidTimestamp";++rec->samples=0;+record__finish_output(rec);+err=fetch_current_timestamp(timestamp,sizeof(timestamp));+if(err){+pr_err("Failed to get current timestamp\n");+return-EINVAL;+}++fd=perf_data_file__switch(file,timestamp,+rec->session->header.data_offset,+at_exit);+if(fd>=0&&!at_exit){+rec->bytes_written=0;+rec->session->header.data_size=0;+}++if(!quiet)+fprintf(stderr,"[ perf record: Dump %s.%s ]\n",+file->path,timestamp);+returnfd;+}+staticvolatileintworkload_exec_errno;/*
@@ -849,8 +881,17 @@ out_child:/* this will be recalculated during process_buildids() */rec->samples=0;-if(!err)-record__finish_output(rec);+if(!err){+if(!rec->timestamp_filename){+record__finish_output(rec);+}else{+fd=record__switch_output(rec,true);+if(fd<0){+status=fd;+gotoout_delete_session;+}+}+}if(!err&&!quiet){charsamples[128];
@@ -1225,6 +1266,8 @@ struct option __record_options[] = {"options passed to clang when compiling BPF scriptlets"),OPT_STRING(0,"vmlinux",&symbol_conf.vmlinux_name,"file","vmlinux pathname"),+OPT_BOOLEAN(0,"timestamp-filename",&record.timestamp_filename,+"append timestamp to output filename"),OPT_END()};
Cost of buildid cache processing is high: read all events in output
perf.data, open elf files to read buildid then copy them into
~/.debug directory. In switch output mode, causes perf stop receiving
from perf events for too long.
Enable no-buildid and no-buildid-cache by default if --switch-output
is provided. Still allow user use --no-no-buildid to explicitly enable
buildid in this case.
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/builtin-record.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
@@ -1371,8 +1371,36 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)"If some relocation was applied (e.g. kexec) symbols may be misresolved\n""even with a suitable vmlinux or kallsyms file.\n\n");-if(rec->no_buildid_cache||rec->no_buildid)+if(rec->no_buildid_cache||rec->no_buildid){disable_buildid_cache();+}elseif(rec->switch_output){+/*+*In'perfrecord--switch-output',disablebuildid+*generationbydefaulttoreducedatafileswitching+*overhead.Stillgeneratebuildidiftheyarerequired+*explicitlyusing+*+*perfrecord--signal-trigger--no-no-buildid\+*--no-no-buildid-cache+*+*Equalsto:+*+*if((rec->no_buildid||!rec->no_buildid_set)&&+*(rec->no_buildid_cache||!rec->no_buildid_cache_set))+*disable_buildid_cache();+*/+booldisable=true;++if(rec->no_buildid_set&&!rec->no_buildid)+disable=false;+if(rec->no_buildid_cache_set&&!rec->no_buildid_cache)+disable=false;+if(disable){+rec->no_buildid=true;+rec->no_buildid_cache=true;+disable_buildid_cache();+}+}if(rec->evlist->nr_entries==0&&perf_evlist__add_default(rec->evlist)<0){
From: Arnaldo Carvalho de Melo <hidden> Date: 2016-01-11 14:58:39
Em Mon, Jan 11, 2016 at 05:25:48PM +0300, Sergei Shtylyov escreveu:
On 01/11/2016 04:48 PM, Wang Nan wrote:
quoted
Commit 71d6de64feddd4b455555326fba2111b3006d9e0 ('perf test: Fix hist
testcases when kptr_restrict is on') solves a double free problem when
You didn't run this patch thru scripts/checkpatch.pl, I guess? A
certain commit citing style is enforced now, and yours doesn't quite
match it...
Which is? /me goes to read checpatch.pl...
- Arnaldo
quoted
'perf test hist' calling setup_fake_machine(). However, the result is
still incorrect. For example:
$ ./perf test -v 'filtering hist entries'
25: Test filtering hist entries :
--- start ---
test child forked, pid 4186
Cannot create kernel maps
test child finished with 0
---- end ----
Test filtering hist entries: Ok
In this case the body of this test is not get executed at all, but the
result is 'Ok'.
Actually, in setup_fake_machine() there's no need to create real kernel
maps. What we want is the fake maps. This patch removes the
machine__create_kernel_maps() in setup_fake_machine(), so it won't be
affected by kptr_restrict setting.
Test result:
$ cat /proc/sys/kernel/kptr_restrict
1
$ ~/perf test -v hist
15: Test matching and linking multiple hists :
--- start ---
test child forked, pid 24031
test child finished with 0
---- end ----
Test matching and linking multiple hists: Ok
[SNIP]
Signed-off-by: Wang Nan <redacted>
Suggested-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 15:25:10
Em Mon, Jan 11, 2016 at 01:47:56PM +0000, Wang Nan escreveu:
If an 'O' is passed to 'make build-test', many 'test -x' and 'test -f'
will fail because perf resides in a different directory. Fix this by
computing PERF_OUT according to 'O' and test correct output files.
For make_kernelsrc and make_kernelsrc_tools, set KBUILD_OUTPUT_DIR
instead because the path is different from others ($(O)/perf vs
$(O)/tools/perf).
Ok, applying up to this patch I now manage to almost cleanly build it using O=,
see below, but seems that we have some race, as not all tests end up producing
such warnings.
[acme@felicio linux]$ rm -rf /tmp/build/perf ; mkdir -p /tmp/build/perf ; make O=/tmp/build/perf -C tools/perf build-test
make: Entering directory `/home/acme/git/linux/tools/perf'
Testing Makefile
- make_no_libperl: cd . && make -f Makefile DESTDIR=/tmp/tmp.m1nXBMqhSA NO_LIBPERL=1
find: ‘/tmp/build/perf/util/trace-event-scripting.o’: No such file or directory
find: ‘/tmp/build/perf/util/build-id.o’: No such file or directory
- make_no_libdw_dwarf_unwind: cd . && make -f Makefile DESTDIR=/tmp/tmp.RB7Ile9C0b NO_LIBDW_DWARF_UNWIND=1
- make_no_backtrace: cd . && make -f Makefile DESTDIR=/tmp/tmp.HeNpC0PW1O NO_BACKTRACE=1
find: ‘/tmp/build/perf/util/trace-event-scripting.o’: No such file or directory
find: ‘/tmp/build/perf/util/alias.o’: No such file or directory
- make_install_prefix: cd . && make -f Makefile DESTDIR=/tmp/tmp.JPK5a72h53 install prefix=/tmp/krava
find: ‘/tmp/build/perf/libapi.a’: No such file or directory
- make_help: cd . && make -f Makefile DESTDIR=/tmp/tmp.F3Z0qPtslS help
- make_doc: cd . && make -f Makefile DESTDIR=/tmp/tmp.6a2HbvC2ej doc
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 15:32:43
Em Mon, Jan 11, 2016 at 12:58:37PM -0200, Arnaldo Carvalho de Melo escreveu:
Em Mon, Jan 11, 2016 at 05:25:48PM +0300, Sergei Shtylyov escreveu:
quoted
On 01/11/2016 04:48 PM, Wang Nan wrote:
quoted
Commit 71d6de64feddd4b455555326fba2111b3006d9e0 ('perf test: Fix hist
testcases when kptr_restrict is on') solves a double free problem when
You didn't run this patch thru scripts/checkpatch.pl, I guess? A
certain commit citing style is enforced now, and yours doesn't quite
match it...
Which is? /me goes to read checpatch.pl...
So, this is it:
[acme@felicio linux]$ scripts/checkpatch.pl /wb/1.patch
ERROR: Please use git commit description style 'commit <12+ chars of
sha1> ("<title line>")' - ie: 'Commit 71d6de64fedd ("perf test: Fix hist
testcases when kptr_restrict is on")'
#62:
Commit 71d6de64feddd4b455555326fba2111b3006d9e0 ('perf test: Fix hist
total: 1 errors, 0 warnings, 11 lines checked
/wb/1.patch has style problems, please review.
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
[acme@felicio linux]$
Ok, matches what I use with this macro that I run in vim with ':!fixes'
after selecting the long commit hash:
#!/bin/bash
if [ $# -eq 1 ] ; then
cset=$1
else
read cset
fi
git log --oneline $cset | head -1 | sed -r 's/([^ ]+) (.*)/Fixes: \1 \("\2\")/g'
------------------------
And I have:
[acme@felicio linux]$ grep abbrev .git/config
abbrev = 12
- Arnaldo
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 15:42:09
Em Mon, Jan 11, 2016 at 01:48:04PM +0000, Wang Nan escreveu:
To prevent futher commits calling machine__delete() on non-allocated
'struct machine' (which would cause memory corruption), this patch
enforces machine__init(), record whether a machine structure is
dynamically allocated or not, and warn if machine__delete() is called
on incorrect object.
Not sure on this one, I think I voiced this before, this seems like
something to be tested using some static analysis tool or even checking
if the address for the struct hitting machine__delete() is from malloc
or not.
I.e. if we do it here, we may have to do it to any other struct where we
allocate it in the stack or via malloc, and furthermore there are cases
where we embed a struct in another, when we would free just the main
struct but not the second, embedded one, that would need just calling
foo__exit() and not foo__delete().
- Arnaldo
quoted hunk
Signed-off-by: Wang Nan <redacted>
Reviewed-by: Masami Hiramatsu <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/tests/vmlinux-kallsyms.c | 4 ++--
tools/perf/util/machine.c | 13 ++++++++-----
tools/perf/util/machine.h | 3 ++-
3 files changed, 12 insertions(+), 8 deletions(-)
On Mon, Jan 11, 2016 at 01:48:18PM +0000, Wang Nan wrote:
This patch introduces a PERF_SAMPLE_TAILSIZE flag which allows a size
field attached at the end of a sample. The idea comes from [1] that,
with tie size at tail of an event, it is possible for user program who
read from the ring buffer parse events backward.
For example:
head
|
V
+--+---+-------+----------+------+---+
|E6|...| B 8| C 11| D 7|E..|
+--+---+-------+----------+------+---+
In this case, from the 'head' pointer provided by kernel, user program
can first see '6' by (*(head - sizeof(u64))), then it can get the start
pointer of record 'E', then it can read size and find start position
of record D, C, B in similar way.
adding extra 8 bytes for every sample is quite unfortunate.
How about another idea:
. update data_tail pointer when head is about to overwrite it
Ex:
head data_tail
| |
V V
+--+-------+-------+---+----+---+
|E | ... | B | C | D | E |
+--+-------+-------+---+----+---+
if new sample F is about to overwrite B, the kernel would need
to read the size of B from B's header and update data_tail to point C.
Or even further.
Comparing to TAILSIZE approach, now kernel will be doing both reads
and writes into ring-buffer and there is a concern that reads may
be hitting cold data, but if the records are small they may be
actually on the same cache line brought by the previous
read A's header, write E record cycle. So I think we shouldn't see
cache misses.
Another concern is validity of records stored. If user space messes
with ring-buffer, kernel won't be able to move data_tail properly
and would need to indicate that to userspace somehow.
But memory saving of 8 bytes per record could be sizable and
user space wouldn't need to walk the whole buffer backwards and
can just start from valid data_tail, so the dumps of overwrite
ring-buffer will be faster too.
Thoughts?
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 21:33:27
Em Mon, Jan 11, 2016 at 01:48:20PM +0000, Wang Nan escreveu:
ordered_events__free() leaves linked lists and timestamps not cleared.
Introduce ordered_events__reset() to reinit ordered_events so it can
be reused again.
Reused where? Can you mention the usecase?
Do we have to introduce a new function? Why not just make
ordered_events__free() to get the state to what was after
ordered_events__init()?
- Arnaldo
quoted hunk
Signed-off-by: Wang Nan <redacted>
Signed-off-by: He Kuang <redacted>
Cc: Arnaldo Carvalho de Melo <redacted>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <redacted>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <redacted>
Cc: pi3orama@163.com
---
tools/perf/util/ordered-events.c | 9 +++++++++
tools/perf/util/ordered-events.h | 1 +
tools/perf/util/session.c | 4 ++--
3 files changed, 12 insertions(+), 2 deletions(-)
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 21:37:37
Em Mon, Jan 11, 2016 at 01:48:08PM +0000, Wang Nan escreveu:
Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:
1. A watchpoint and a breakpoint that fire on the same instruction
2. Nested signals
Test result:
On x86_64 and ARM64 (result are similar with patch [2] on ARM64):
# ./perf test -v signal
17: Test breakpoint overflow signal handler :
--- start ---
test child forked, pid 10213
count1 1, count2 3, count3 2, overflow 3, overflows_2 3
test child finished with 0
---- end ----
Test breakpoint overflow signal handler: Ok
So at least 2 cases Will doubted are handled correctly.
[1] http://lkml.kernel.org/g/20160104165535.GI1616@arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0@huawei.com
Signed-off-by: Wang Nan <redacted>
Cc: Will Deacon <redacted>
Will, are you ok with this one? Can I have an Acked-by or better,
Tested-by for the AARCH64 base?
IIRC Jiri made some comment about this one?
- Arnaldo
@@ -29,14 +29,59 @@staticintfd1;staticintfd2;+staticintfd3;staticintoverflows;+staticintoverflows_2;++volatilelongthe_var;+++/*+*UseASMtoensurewatchpointandbreakpointcanbetriggered+*atoneinstruction.+*/+#if defined (__x86_64__)+externvoid__test_function(volatilelong*ptr);+asm(+".globl __test_function\n"+"__test_function:\n"+"incq (%rdi)\n"+"ret\n");+#elif defined (__aarch64__)+externvoid__test_function(volatilelong*ptr);+asm(+".globl __test_function\n"+"__test_function:\n"+"str x30, [x0]\n"+"ret\n");++#else+staticvoid__test_function(volatilelong*ptr)+{+*ptr=0x1234;+}+#endif__attribute__((noinline))staticinttest_function(void){+__test_function(&the_var);+the_var++;returntime(NULL);}+staticvoidsig_handler_2(intsignum__maybe_unused,+siginfo_t*oh__maybe_unused,+void*uc__maybe_unused)+{+overflows_2++;+if(overflows_2>10){+ioctl(fd1,PERF_EVENT_IOC_DISABLE,0);+ioctl(fd2,PERF_EVENT_IOC_DISABLE,0);+ioctl(fd3,PERF_EVENT_IOC_DISABLE,0);+}+}+staticvoidsig_handler(intsignum__maybe_unused,siginfo_t*oh__maybe_unused,void*uc__maybe_unused)
@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,*/ioctl(fd1,PERF_EVENT_IOC_DISABLE,0);ioctl(fd2,PERF_EVENT_IOC_DISABLE,0);+ioctl(fd3,PERF_EVENT_IOC_DISABLE,0);}}-staticintbp_event(void*fn,intsetup_signal)+staticint__event(boolis_x,void*addr,intsignal){structperf_event_attrpe;intfd;
@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)pe.size=sizeof(structperf_event_attr);pe.config=0;-pe.bp_type=HW_BREAKPOINT_X;-pe.bp_addr=(unsignedlong)fn;+pe.bp_type=is_x?HW_BREAKPOINT_X:HW_BREAKPOINT_W;+pe.bp_addr=(unsignedlong)addr;pe.bp_len=sizeof(long);pe.sample_period=1;
@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)returnTEST_FAIL;}-if(setup_signal){-fcntl(fd,F_SETFL,O_RDWR|O_NONBLOCK|O_ASYNC);-fcntl(fd,F_SETSIG,SIGIO);-fcntl(fd,F_SETOWN,getpid());-}+fcntl(fd,F_SETFL,O_RDWR|O_NONBLOCK|O_ASYNC);+fcntl(fd,F_SETSIG,signal);+fcntl(fd,F_SETOWN,getpid());ioctl(fd,PERF_EVENT_IOC_RESET,0);returnfd;}+staticintbp_event(void*addr,intsignal)+{+return__event(true,addr,signal);+}++staticintwp_event(void*addr,intsignal)+{+return__event(false,addr,signal);+}+staticlonglongbp_count(intfd){longlongcount;
@@ -114,7 +168,7 @@ static long long bp_count(int fd)inttest__bp_signal(intsubtest__maybe_unused){structsigactionsa;-longlongcount1,count2;+longlongcount1,count2,count3;/* setup SIGIO signal handler */memset(&sa,0,sizeof(structsigaction));
@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)returnTEST_FAIL;}+sa.sa_sigaction=(void*)sig_handler_2;+if(sigaction(SIGUSR1,&sa,NULL)<0){+pr_debug("failed setting up signal handler 2\n");+returnTEST_FAIL;+}+/**Wecreatefollowingevents:*-*fd1-breakpointeventontest_functionwithSIGIO+*fd1-breakpointeventon__test_functionwithSIGIO*signalconfigured.Weshouldgetsignal*notificationeachtimethebreakpointishit*-*fd2-breakpointeventonsig_handlerwithoutSIGIO+*fd2-breakpointeventonsig_handlerwithSIGUSR1+*configured.WeshouldgetSIGUSR1eachtimewhen+*breakpointishit+*+*fd3-watchpointeventon__test_functionwithSIGIO*configured.**Followingprocessingshouldhappen:-*-executetest_function-*-fd1eventbreakpointhit->count1==1-*-SIGIOisdelivered->overflows==1-*-fd2eventbreakpointhit->count2==1+*Exec:Action:Result:+*incq(%rdi)-fd1eventbreakpointhit->count1==1+*-SIGIOisdelivered+*sig_handler-fd2eventbreakpointhit->count2==1+*-SIGUSR1isdelivered+*sig_handler_2->overflows_2==1(nestedsignal)+*sys_rt_sigreturn-returnfromsig_handler_2+*overflows++->overflows=1+*sys_rt_sigreturn-returnfromsig_handler+*incq(%rdi)-fd3eventwatchpointhit->count3==1(wpandbpinoneinsn)+*-SIGIOisdelivered+*sig_handler-fd2eventbreakpointhit->count2==2+*-SIGUSR1isdelivered+*sig_handler_2->overflows_2==2(nestedsignal)+*sys_rt_sigreturn-returnfromsig_handler_2+*overflows++->overflows=2+*sys_rt_sigreturn-returnfromsig_handler+*the_var++-fd3eventwatchpointhit->count3==2(standalonewatchpoint)+*-SIGIOisdelivered+*sig_handler-fd2eventbreakpointhit->count2==3+*-SIGUSR1isdelivered+*sig_handler_2->overflows_2==3(nestedsignal)+*sys_rt_sigreturn-returnfromsig_handler_2+*overflows++->overflows==3+*sys_rt_sigreturn-returnfromsig_handler**Thetestcasecheckfollowingerrorconditions:*-wegetstuckinsignalhandlerbecauseofdebug
@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)**/-fd1=bp_event(test_function,1);-fd2=bp_event(sig_handler,0);+fd1=bp_event(__test_function,SIGIO);+fd2=bp_event(sig_handler,SIGUSR1);+fd3=wp_event((void*)&the_var,SIGIO);ioctl(fd1,PERF_EVENT_IOC_ENABLE,0);ioctl(fd2,PERF_EVENT_IOC_ENABLE,0);+ioctl(fd3,PERF_EVENT_IOC_ENABLE,0);/**Kickoffthetestbytrigering'fd1'
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 21:55:09
Em Mon, Jan 11, 2016 at 01:48:05PM +0000, Wang Nan escreveu:
Copying perf to old kernel system results:
# perf test bpf
37: Test BPF filter :
37.1: Test basic BPF filtering : FAILED!
37.2: Test BPF prologue generation : Skip
However, in case when kernel doesn't support a test case it should
return 'Skip', 'FAILED!' should be reserved for kernel tests for when
the kernel supports a feature that then fails to work as advertised.
This patch checks environment before real testcase.
This is really strange, this other test is failing if the above patch is
present, found by bisecting:
[acme@felicio linux]$ perf test decoder
47: Test x86 instruction decoder - new instructions : FAILED!
[acme@felicio linux]$ git log --oneline -1
91fedd318e3d perf test: Check environment before start real BPF test
[acme@felicio linux]$ git reset --hard HEAD^
HEAD is now at f1f23526d3b6 perf test: Reset err after using it hold
errcode in hist testcases
[acme@felicio linux]$ m
make: Entering directory `/home/acme/git/linux/tools/perf'
BUILD: Doing 'make -j4' parallel build
CC /tmp/build/perf/arch/common.o
CC /tmp/build/perf/util/abspath.o
CC /tmp/build/perf/builtin-bench.o
CC /tmp/build/perf/util/alias.o
<SNIP>
[acme@felicio linux]$ git log --oneline -1
f1f23526d3b6 perf test: Reset err after using it hold errcode in hist
testcases
[acme@felicio linux]$ perf test decoder
47: Test x86 instruction decoder - new instructions : Ok
[acme@felicio linux]$
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 22:06:28
Em Mon, Jan 11, 2016 at 12:24:56PM -0300, Arnaldo Carvalho de Melo escreveu:
Em Mon, Jan 11, 2016 at 01:47:56PM +0000, Wang Nan escreveu:
quoted
If an 'O' is passed to 'make build-test', many 'test -x' and 'test -f'
will fail because perf resides in a different directory. Fix this by
computing PERF_OUT according to 'O' and test correct output files.
For make_kernelsrc and make_kernelsrc_tools, set KBUILD_OUTPUT_DIR
instead because the path is different from others ($(O)/perf vs
$(O)/tools/perf).
Ok, applying up to this patch I now manage to almost cleanly build it using O=,
see below, but seems that we have some race, as not all tests end up producing
such warnings.
[acme@felicio linux]$ rm -rf /tmp/build/perf ; mkdir -p /tmp/build/perf ; make O=/tmp/build/perf -C tools/perf build-test
make: Entering directory `/home/acme/git/linux/tools/perf'
Testing Makefile
- make_no_libperl: cd . && make -f Makefile DESTDIR=/tmp/tmp.m1nXBMqhSA NO_LIBPERL=1
find: ‘/tmp/build/perf/util/trace-event-scripting.o’: No such file or directory
Well, it is happening even without O=:
[acme@felicio linux]$ perf stat make -C tools/perf build-test
make: Entering directory `/home/acme/git/linux/tools/perf'
Testing Makefile
- make_doc: cd . && make -f Makefile DESTDIR=/tmp/tmp.H8z3S3cEJ0 doc
- make_install_bin: cd . && make -f Makefile DESTDIR=/tmp/tmp.njIAPXMF7f install-bin
- make_install_prefix: cd . && make -f Makefile DESTDIR=/tmp/tmp.9FEKGBoeyN install prefix=/tmp/krava
- make_no_gtk2: cd . && make -f Makefile DESTDIR=/tmp/tmp.nHl593wfMP NO_GTK2=1
- make_util_map_o: cd . && make -f Makefile DESTDIR=/tmp/tmp.ZSmZP490hX util/map.o
- make_no_slang: cd . && make -f Makefile DESTDIR=/tmp/tmp.7q24C1xmcu NO_SLANG=1
- make_pure: cd . && make -f Makefile DESTDIR=/tmp/tmp.R51cy8kdWl
- make_no_libpython: cd . && make -f Makefile DESTDIR=/tmp/tmp.3t9tEc0e4b NO_LIBPYTHON=1
- make_no_libbionic: cd . && make -f Makefile DESTDIR=/tmp/tmp.4yYelFUaq0 NO_LIBBIONIC=1
- make_no_newt: cd . && make -f Makefile DESTDIR=/tmp/tmp.3Fg7hv3Hn1 NO_NEWT=1
- make_tags: cd . && make -f Makefile DESTDIR=/tmp/tmp.8WMgskFkOH tags
- make_install: cd . && make -f Makefile DESTDIR=/tmp/tmp.YQq3wOEkyB install
- make_no_libdw_dwarf_unwind: cd . && make -f Makefile DESTDIR=/tmp/tmp.WKRVFDA2ty NO_LIBDW_DWARF_UNWIND=1
find: ‘/home/acme/git/linux/tools/perf/.gtk-in.o.cmd’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/builtin-script.o’: No such file or directory
- make_no_libunwind: cd . && make -f Makefile DESTDIR=/tmp/tmp.SQftzGTUYf NO_LIBUNWIND=1
- make_no_auxtrace: cd . && make -f Makefile DESTDIR=/tmp/tmp.Xy2xrSCVuO NO_AUXTRACE=1
- make_no_ui: cd . && make -f Makefile DESTDIR=/tmp/tmp.ZFNEHWqQFN NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
- make_no_libnuma: cd . && make -f Makefile DESTDIR=/tmp/tmp.68zRtMaEqf NO_LIBNUMA=1
- make_no_backtrace: cd . && make -f Makefile DESTDIR=/tmp/tmp.5xcea8XfdC NO_BACKTRACE=1
find: ‘/home/acme/git/linux/tools/perf/arch/x86/tests/dwarf-unwind.o’: No such file or directory
- make_install_prefix_slash: cd . && make -f Makefile DESTDIR=/tmp/tmp.2c5BqUKGef install prefix=/tmp/krava/
find: ‘/home/acme/git/linux/tools/perf/builtin-record.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/builtin-inject.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/builtin-bench.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/.builtin-lock.o.cmd’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/perf.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/scripts/.libperf-in.o.cmd’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/tests/evsel-tp-sched.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/tests/hists_cumulate.o’: No such file or directory
- make_util_pmu_bison_o: cd . && make -f Makefile DESTDIR=/tmp/tmp.aJUWyFbXsp util/pmu-bis
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 22:39:13
Em Mon, Jan 11, 2016 at 07:06:18PM -0300, Arnaldo Carvalho de Melo escreveu:
Em Mon, Jan 11, 2016 at 12:24:56PM -0300, Arnaldo Carvalho de Melo escreveu:
quoted
Em Mon, Jan 11, 2016 at 01:47:56PM +0000, Wang Nan escreveu:
quoted
If an 'O' is passed to 'make build-test', many 'test -x' and 'test -f'
will fail because perf resides in a different directory. Fix this by
computing PERF_OUT according to 'O' and test correct output files.
For make_kernelsrc and make_kernelsrc_tools, set KBUILD_OUTPUT_DIR
instead because the path is different from others ($(O)/perf vs
$(O)/tools/perf).
Ok, applying up to this patch I now manage to almost cleanly build it using O=,
see below, but seems that we have some race, as not all tests end up producing
such warnings.
[acme@felicio linux]$ rm -rf /tmp/build/perf ; mkdir -p /tmp/build/perf ; make O=/tmp/build/perf -C tools/perf build-test
make: Entering directory `/home/acme/git/linux/tools/perf'
Testing Makefile
- make_no_libperl: cd . && make -f Makefile DESTDIR=/tmp/tmp.m1nXBMqhSA NO_LIBPERL=1
find: ‘/tmp/build/perf/util/trace-event-scripting.o’: No such file or directory
Well, it is happening even without O=:
So I removed a few patches and those aren't appearing anymore, please
take a look at my perf/core branch, running build-test on a few machines
now, will push soon.
My hunch is that build-test has issues with parallel builds, but I'm not
sure...
- Arnaldo
[acme@felicio linux]$ perf stat make -C tools/perf build-test
make: Entering directory `/home/acme/git/linux/tools/perf'
Testing Makefile
- make_doc: cd . && make -f Makefile DESTDIR=/tmp/tmp.H8z3S3cEJ0 doc
- make_install_bin: cd . && make -f Makefile DESTDIR=/tmp/tmp.njIAPXMF7f install-bin
- make_install_prefix: cd . && make -f Makefile DESTDIR=/tmp/tmp.9FEKGBoeyN install prefix=/tmp/krava
- make_no_gtk2: cd . && make -f Makefile DESTDIR=/tmp/tmp.nHl593wfMP NO_GTK2=1
- make_util_map_o: cd . && make -f Makefile DESTDIR=/tmp/tmp.ZSmZP490hX util/map.o
- make_no_slang: cd . && make -f Makefile DESTDIR=/tmp/tmp.7q24C1xmcu NO_SLANG=1
- make_pure: cd . && make -f Makefile DESTDIR=/tmp/tmp.R51cy8kdWl
- make_no_libpython: cd . && make -f Makefile DESTDIR=/tmp/tmp.3t9tEc0e4b NO_LIBPYTHON=1
- make_no_libbionic: cd . && make -f Makefile DESTDIR=/tmp/tmp.4yYelFUaq0 NO_LIBBIONIC=1
- make_no_newt: cd . && make -f Makefile DESTDIR=/tmp/tmp.3Fg7hv3Hn1 NO_NEWT=1
- make_tags: cd . && make -f Makefile DESTDIR=/tmp/tmp.8WMgskFkOH tags
- make_install: cd . && make -f Makefile DESTDIR=/tmp/tmp.YQq3wOEkyB install
- make_no_libdw_dwarf_unwind: cd . && make -f Makefile DESTDIR=/tmp/tmp.WKRVFDA2ty NO_LIBDW_DWARF_UNWIND=1
find: ‘/home/acme/git/linux/tools/perf/.gtk-in.o.cmd’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/builtin-script.o’: No such file or directory
- make_no_libunwind: cd . && make -f Makefile DESTDIR=/tmp/tmp.SQftzGTUYf NO_LIBUNWIND=1
- make_no_auxtrace: cd . && make -f Makefile DESTDIR=/tmp/tmp.Xy2xrSCVuO NO_AUXTRACE=1
- make_no_ui: cd . && make -f Makefile DESTDIR=/tmp/tmp.ZFNEHWqQFN NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
- make_no_libnuma: cd . && make -f Makefile DESTDIR=/tmp/tmp.68zRtMaEqf NO_LIBNUMA=1
- make_no_backtrace: cd . && make -f Makefile DESTDIR=/tmp/tmp.5xcea8XfdC NO_BACKTRACE=1
find: ‘/home/acme/git/linux/tools/perf/arch/x86/tests/dwarf-unwind.o’: No such file or directory
- make_install_prefix_slash: cd . && make -f Makefile DESTDIR=/tmp/tmp.2c5BqUKGef install prefix=/tmp/krava/
find: ‘/home/acme/git/linux/tools/perf/builtin-record.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/builtin-inject.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/builtin-bench.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/.builtin-lock.o.cmd’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/perf.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/scripts/.libperf-in.o.cmd’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/tests/evsel-tp-sched.o’: No such file or directory
find: ‘/home/acme/git/linux/tools/perf/tests/hists_cumulate.o’: No such file or directory
- make_util_pmu_bison_o: cd . && make -f Makefile DESTDIR=/tmp/tmp.aJUWyFbXsp util/pmu-bis
From: Arnaldo Carvalho de Melo <acme@kernel.org> Date: 2016-01-11 22:40:00
Em Mon, Jan 11, 2016 at 07:39:04PM -0300, Arnaldo Carvalho de Melo escreveu:
Em Mon, Jan 11, 2016 at 07:06:18PM -0300, Arnaldo Carvalho de Melo escreveu:
quoted
Em Mon, Jan 11, 2016 at 12:24:56PM -0300, Arnaldo Carvalho de Melo escreveu:
quoted
Em Mon, Jan 11, 2016 at 01:47:56PM +0000, Wang Nan escreveu:
quoted
If an 'O' is passed to 'make build-test', many 'test -x' and 'test -f'
will fail because perf resides in a different directory. Fix this by
computing PERF_OUT according to 'O' and test correct output files.
For make_kernelsrc and make_kernelsrc_tools, set KBUILD_OUTPUT_DIR
instead because the path is different from others ($(O)/perf vs
$(O)/tools/perf).
Ok, applying up to this patch I now manage to almost cleanly build it using O=,
see below, but seems that we have some race, as not all tests end up producing
such warnings.
[acme@felicio linux]$ rm -rf /tmp/build/perf ; mkdir -p /tmp/build/perf ; make O=/tmp/build/perf -C tools/perf build-test
make: Entering directory `/home/acme/git/linux/tools/perf'
Testing Makefile
- make_no_libperl: cd . && make -f Makefile DESTDIR=/tmp/tmp.m1nXBMqhSA NO_LIBPERL=1
find: ‘/tmp/build/perf/util/trace-event-scripting.o’: No such file or directory
Well, it is happening even without O=:
So I removed a few patches and those aren't appearing anymore, please
take a look at my perf/core branch, running build-test on a few machines
now, will push soon.
My hunch is that build-test has issues with parallel builds, but I'm not
sure...
Good:
- make_perf_o_O: cd . && make -f Makefile O=/tmp/tmp.oLeg8aUaOo DESTDIR=/tmp/tmp.16WP4HTQJs perf.o
- make_util_pmu_bison_o_O: cd . && make -f Makefile O=/tmp/tmp.xNRV0pCXfD DESTDIR=/tmp/tmp.8dyU9uEbHe util/pmu-bison.o
- make_no_libdw_dwarf_unwind_O: cd . && make -f Makefile O=/tmp/tmp.pHH4HExHcH DESTDIR=/tmp/tmp.Wo0m8fF5cp NO_LIBDW_DWARF_UNWIND=1
- make_no_demangle_O: cd . && make -f Makefile O=/tmp/tmp.yWNsd4jOsI DESTDIR=/tmp/tmp.Q7eA4kCvwL NO_DEMANGLE=1
- tarpkg: ./tests/perf-targz-src-pkg .
- make -C <kernelsrc> tools/perf
- make -C <kernelsrc>/tools perf
OK
On 2016/1/12 5:37, Arnaldo Carvalho de Melo wrote:
Em Mon, Jan 11, 2016 at 01:48:08PM +0000, Wang Nan escreveu:
quoted
Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:
1. A watchpoint and a breakpoint that fire on the same instruction
2. Nested signals
Test result:
On x86_64 and ARM64 (result are similar with patch [2] on ARM64):
# ./perf test -v signal
17: Test breakpoint overflow signal handler :
--- start ---
test child forked, pid 10213
count1 1, count2 3, count3 2, overflow 3, overflows_2 3
test child finished with 0
---- end ----
Test breakpoint overflow signal handler: Ok
So at least 2 cases Will doubted are handled correctly.
[1] http://lkml.kernel.org/g/20160104165535.GI1616@arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0@huawei.com
Signed-off-by: Wang Nan <redacted>
Cc: Will Deacon <redacted>
Will, are you ok with this one? Can I have an Acked-by or better,
Tested-by for the AARCH64 base?
Patch [2] is still in question. On AArch64 this test will fail even
without this patch.
Thank you.
On Mon, Jan 11, 2016 at 01:48:18PM +0000, Wang Nan wrote:
quoted
This patch introduces a PERF_SAMPLE_TAILSIZE flag which allows a size
field attached at the end of a sample. The idea comes from [1] that,
with tie size at tail of an event, it is possible for user program who
read from the ring buffer parse events backward.
For example:
head
|
V
+--+---+-------+----------+------+---+
|E6|...| B 8| C 11| D 7|E..|
+--+---+-------+----------+------+---+
In this case, from the 'head' pointer provided by kernel, user program
can first see '6' by (*(head - sizeof(u64))), then it can get the start
pointer of record 'E', then it can read size and find start position
of record D, C, B in similar way.
adding extra 8 bytes for every sample is quite unfortunate.
How about another idea:
. update data_tail pointer when head is about to overwrite it
Ex:
head data_tail
| |
V V
+--+-------+-------+---+----+---+
|E | ... | B | C | D | E |
+--+-------+-------+---+----+---+
if new sample F is about to overwrite B, the kernel would need
to read the size of B from B's header and update data_tail to point C.
Or even further.
Comparing to TAILSIZE approach, now kernel will be doing both reads
and writes into ring-buffer and there is a concern that reads may
be hitting cold data, but if the records are small they may be
actually on the same cache line brought by the previous
read A's header, write E record cycle. So I think we shouldn't see
cache misses.
After ring buffer rewind, we need a read before nearly
every write operations. The performance penalty depends on
configuration of write allocate. In addition, another data
dependency is required: we must wait for the size of
event B is retrived before overwrite it.
Even in the very first try at 2013 in [1], reading from the ring
buffer is avoided. I don't think Peter changes his mind now.
Another concern is validity of records stored. If user space messes
with ring-buffer, kernel won't be able to move data_tail properly
and would need to indicate that to userspace somehow.
But memory saving of 8 bytes per record could be sizable
Yes. But I have already discussed with Peter on this in [2].
Last month I suggested:
<quote>
1. If PERF_SAMPLE_SIZE is selected, we can avoid outputting the event
size in header. Which eliminate extra space cost;
</quote>
However:
<quote>
That would mandate you always parse the stream backwards. Which seems
rather unfortunate. Also, no you cannot recoup the extra space, see the
alignment and size requirement.
</quote>
and
user space wouldn't need to walk the whole buffer backwards and
can just start from valid data_tail, so the dumps of overwrite
ring-buffer will be faster too.
Thoughts?
On Tue, Jan 12, 2016 at 01:33:28PM +0800, Wangnan (F) wrote:
On 2016/1/12 2:09, Alexei Starovoitov wrote:
quoted
On Mon, Jan 11, 2016 at 01:48:18PM +0000, Wang Nan wrote:
quoted
This patch introduces a PERF_SAMPLE_TAILSIZE flag which allows a size
field attached at the end of a sample. The idea comes from [1] that,
with tie size at tail of an event, it is possible for user program who
read from the ring buffer parse events backward.
For example:
head
|
V
+--+---+-------+----------+------+---+
|E6|...| B 8| C 11| D 7|E..|
+--+---+-------+----------+------+---+
In this case, from the 'head' pointer provided by kernel, user program
can first see '6' by (*(head - sizeof(u64))), then it can get the start
pointer of record 'E', then it can read size and find start position
of record D, C, B in similar way.
adding extra 8 bytes for every sample is quite unfortunate.
How about another idea:
. update data_tail pointer when head is about to overwrite it
Ex:
head data_tail
| |
V V
+--+-------+-------+---+----+---+
|E | ... | B | C | D | E |
+--+-------+-------+---+----+---+
if new sample F is about to overwrite B, the kernel would need
to read the size of B from B's header and update data_tail to point C.
Or even further.
Comparing to TAILSIZE approach, now kernel will be doing both reads
and writes into ring-buffer and there is a concern that reads may
be hitting cold data, but if the records are small they may be
actually on the same cache line brought by the previous
read A's header, write E record cycle. So I think we shouldn't see
cache misses.
After ring buffer rewind, we need a read before nearly
every write operations. The performance penalty depends on
configuration of write allocate. In addition, another data
dependency is required: we must wait for the size of
event B is retrived before overwrite it.
Even in the very first try at 2013 in [1], reading from the ring
buffer is avoided. I don't think Peter changes his mind now.
quoted
Another concern is validity of records stored. If user space messes
with ring-buffer, kernel won't be able to move data_tail properly
and would need to indicate that to userspace somehow.
But memory saving of 8 bytes per record could be sizable
Yes. But I have already discussed with Peter on this in [2].
Last month I suggested:
<quote>
1. If PERF_SAMPLE_SIZE is selected, we can avoid outputting the event
size in header. Which eliminate extra space cost;
</quote>
However:
<quote>
That would mandate you always parse the stream backwards. Which seems
rather unfortunate. Also, no you cannot recoup the extra space, see the
alignment and size requirement.
hmm, in this kernel patch I see that you're adding 8 bytes for
every record via this extra TAILSISZE flag and in perf you're
walking the ring buffer backwards by reading this 8 byte
sizes, comparing header sizes and so on until reaching beginning,
where you start dumping it as normal.
So for this 'signal to perf' approach to work the ring buffer
will contain tailsizes everywhere just so that user space can
find the beginning. That's not very pretty. imo if kernel
can do header read to adjust data_tail it would make user
space side clean. May be there are other solutions.
Adding tailsize seems like brute force hack.
There must be some nicer way.
On 2016/1/11 23:42, Arnaldo Carvalho de Melo wrote:
Em Mon, Jan 11, 2016 at 01:48:04PM +0000, Wang Nan escreveu:
quoted
To prevent futher commits calling machine__delete() on non-allocated
'struct machine' (which would cause memory corruption), this patch
enforces machine__init(), record whether a machine structure is
dynamically allocated or not, and warn if machine__delete() is called
on incorrect object.
Not sure on this one, I think I voiced this before, this seems like
something to be tested using some static analysis tool or even checking
if the address for the struct hitting machine__delete() is from malloc
or not.
I.e. if we do it here, we may have to do it to any other struct where we
allocate it in the stack or via malloc, and furthermore there are cases
where we embed a struct in another, when we would free just the main
struct but not the second, embedded one, that would need just calling
foo__exit() and not foo__delete().
- Arnaldo