perf/core improvements and fixes:
perf test: - Add watchpoint entry (Ravi Bangoria) Build fixes: - Initialize perf_data_file fd field to fix building the CTF (trace format) converter with with gcc 4.8.4 on Ubuntu 14.04 (Jérémie Galarneau) - Use -Wno-redundant-decls to build with PYTHON=python3 to build the python binding, fixing the build in systems such as Clear Linux (Arnaldo Carvalho de Melo) Hardware tracing: - Suppress AUX/OVERWRITE records (Alexander Shishkin) Infrastructure: - Adopt PTR_ERR_OR_ZERO from the kernel and use it in the bpf-loader instead of open coded equivalent (Ding Xiang) - Improve the event ordering code to make it clear and fix a bug related to freeing of events when using pipe mode from 'record' to 'inject' (Jiri Olsa) - Some prep work to facilitate per-cpu threads to write record data to per-cpu files (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCW6JP9wAKCRCyPKLppCJ+ J9vjAQDfizmUwoCqgZD4q9d9hIx1KWrFK5q6EJOPsY+l0288BQEAzgx3Q0c7zFS1 WB0DjtGgEntudoH57vqsswrT7VPKPAE= =Ee8x -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-4.20-20180919' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: perf test improvements: - Add watchpoint entry (Ravi Bangoria) Build fixes: - Initialize perf_data_file fd field to fix building the CTF (trace format) converter with with gcc 4.8.4 on Ubuntu 14.04 (Jérémie Galarneau) - Use -Wno-redundant-decls to build with PYTHON=python3 to build the python binding, fixing the build in systems such as Clear Linux (Arnaldo Carvalho de Melo) Hardware tracing improvements: - Suppress AUX/OVERWRITE records (Alexander Shishkin) Infrastructure changes: - Adopt PTR_ERR_OR_ZERO from the kernel and use it in the bpf-loader instead of open coded equivalent (Ding Xiang) - Improve the event ordering code to make it clear and fix a bug related to freeing of events when using pipe mode from 'record' to 'inject' (Jiri Olsa) - Some prep work to facilitate per-cpu threads to write record data to per-cpu files (Jiri Olsa) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
9835bf7ff8
|
@ -459,10 +459,20 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size)
|
||||||
if (size || handle->aux_flags) {
|
if (size || handle->aux_flags) {
|
||||||
/*
|
/*
|
||||||
* Only send RECORD_AUX if we have something useful to communicate
|
* Only send RECORD_AUX if we have something useful to communicate
|
||||||
|
*
|
||||||
|
* Note: the OVERWRITE records by themselves are not considered
|
||||||
|
* useful, as they don't communicate any *new* information,
|
||||||
|
* aside from the short-lived offset, that becomes history at
|
||||||
|
* the next event sched-in and therefore isn't useful.
|
||||||
|
* The userspace that needs to copy out AUX data in overwrite
|
||||||
|
* mode should know to use user_page::aux_head for the actual
|
||||||
|
* offset. So, from now on we don't output AUX records that
|
||||||
|
* have *only* OVERWRITE flag set.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
perf_event_aux_event(handle->event, aux_head, size,
|
if (handle->aux_flags & ~(u64)PERF_AUX_FLAG_OVERWRITE)
|
||||||
handle->aux_flags);
|
perf_event_aux_event(handle->event, aux_head, size,
|
||||||
|
handle->aux_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb->user_page->aux_head = rb->aux_head;
|
rb->user_page->aux_head = rb->aux_head;
|
||||||
|
|
|
@ -52,4 +52,11 @@ static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
|
||||||
return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
|
return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
|
||||||
|
{
|
||||||
|
if (IS_ERR(ptr))
|
||||||
|
return PTR_ERR(ptr);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* _LINUX_ERR_H */
|
#endif /* _LINUX_ERR_H */
|
||||||
|
|
|
@ -283,12 +283,11 @@ out_put:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_feature_event(struct perf_tool *tool,
|
static int process_feature_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
if (event->feat.feat_id < HEADER_LAST_FEATURE)
|
if (event->feat.feat_id < HEADER_LAST_FEATURE)
|
||||||
return perf_event__process_feature(tool, event, session);
|
return perf_event__process_feature(session, event);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,12 +86,10 @@ static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int perf_event__repipe_op2_synth(struct perf_tool *tool,
|
static int perf_event__repipe_op2_synth(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session
|
|
||||||
__maybe_unused)
|
|
||||||
{
|
{
|
||||||
return perf_event__repipe_synth(tool, event);
|
return perf_event__repipe_synth(session->tool, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_event__repipe_attr(struct perf_tool *tool,
|
static int perf_event__repipe_attr(struct perf_tool *tool,
|
||||||
|
@ -133,10 +131,10 @@ static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
|
static s64 perf_event__repipe_auxtrace(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
|
struct perf_tool *tool = session->tool;
|
||||||
struct perf_inject *inject = container_of(tool, struct perf_inject,
|
struct perf_inject *inject = container_of(tool, struct perf_inject,
|
||||||
tool);
|
tool);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -174,9 +172,8 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static s64
|
static s64
|
||||||
perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused,
|
perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event __maybe_unused)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
pr_err("AUX area tracing not supported\n");
|
pr_err("AUX area tracing not supported\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -362,26 +359,24 @@ static int perf_event__repipe_exit(struct perf_tool *tool,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_event__repipe_tracing_data(struct perf_tool *tool,
|
static int perf_event__repipe_tracing_data(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
perf_event__repipe_synth(tool, event);
|
perf_event__repipe_synth(session->tool, event);
|
||||||
err = perf_event__process_tracing_data(tool, event, session);
|
err = perf_event__process_tracing_data(session, event);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_event__repipe_id_index(struct perf_tool *tool,
|
static int perf_event__repipe_id_index(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
perf_event__repipe_synth(tool, event);
|
perf_event__repipe_synth(session->tool, event);
|
||||||
err = perf_event__process_id_index(tool, event, session);
|
err = perf_event__process_id_index(session, event);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,9 +106,12 @@ static bool switch_output_time(struct record *rec)
|
||||||
trigger_is_ready(&switch_output_trigger);
|
trigger_is_ready(&switch_output_trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int record__write(struct record *rec, void *bf, size_t size)
|
static int record__write(struct record *rec, struct perf_mmap *map __maybe_unused,
|
||||||
|
void *bf, size_t size)
|
||||||
{
|
{
|
||||||
if (perf_data__write(rec->session->data, bf, size) < 0) {
|
struct perf_data_file *file = &rec->session->data->file;
|
||||||
|
|
||||||
|
if (perf_data_file__write(file, bf, size) < 0) {
|
||||||
pr_err("failed to write perf data, error: %m\n");
|
pr_err("failed to write perf data, error: %m\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -127,15 +130,15 @@ static int process_synthesized_event(struct perf_tool *tool,
|
||||||
struct machine *machine __maybe_unused)
|
struct machine *machine __maybe_unused)
|
||||||
{
|
{
|
||||||
struct record *rec = container_of(tool, struct record, tool);
|
struct record *rec = container_of(tool, struct record, tool);
|
||||||
return record__write(rec, event, event->header.size);
|
return record__write(rec, NULL, event, event->header.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int record__pushfn(void *to, void *bf, size_t size)
|
static int record__pushfn(struct perf_mmap *map, void *to, void *bf, size_t size)
|
||||||
{
|
{
|
||||||
struct record *rec = to;
|
struct record *rec = to;
|
||||||
|
|
||||||
rec->samples++;
|
rec->samples++;
|
||||||
return record__write(rec, bf, size);
|
return record__write(rec, map, bf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static volatile int done;
|
static volatile int done;
|
||||||
|
@ -170,6 +173,7 @@ static void record__sig_exit(void)
|
||||||
#ifdef HAVE_AUXTRACE_SUPPORT
|
#ifdef HAVE_AUXTRACE_SUPPORT
|
||||||
|
|
||||||
static int record__process_auxtrace(struct perf_tool *tool,
|
static int record__process_auxtrace(struct perf_tool *tool,
|
||||||
|
struct perf_mmap *map,
|
||||||
union perf_event *event, void *data1,
|
union perf_event *event, void *data1,
|
||||||
size_t len1, void *data2, size_t len2)
|
size_t len1, void *data2, size_t len2)
|
||||||
{
|
{
|
||||||
|
@ -197,21 +201,21 @@ static int record__process_auxtrace(struct perf_tool *tool,
|
||||||
if (padding)
|
if (padding)
|
||||||
padding = 8 - padding;
|
padding = 8 - padding;
|
||||||
|
|
||||||
record__write(rec, event, event->header.size);
|
record__write(rec, map, event, event->header.size);
|
||||||
record__write(rec, data1, len1);
|
record__write(rec, map, data1, len1);
|
||||||
if (len2)
|
if (len2)
|
||||||
record__write(rec, data2, len2);
|
record__write(rec, map, data2, len2);
|
||||||
record__write(rec, &pad, padding);
|
record__write(rec, map, &pad, padding);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int record__auxtrace_mmap_read(struct record *rec,
|
static int record__auxtrace_mmap_read(struct record *rec,
|
||||||
struct auxtrace_mmap *mm)
|
struct perf_mmap *map)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
|
ret = auxtrace_mmap__read(map, rec->itr, &rec->tool,
|
||||||
record__process_auxtrace);
|
record__process_auxtrace);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -223,11 +227,11 @@ static int record__auxtrace_mmap_read(struct record *rec,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int record__auxtrace_mmap_read_snapshot(struct record *rec,
|
static int record__auxtrace_mmap_read_snapshot(struct record *rec,
|
||||||
struct auxtrace_mmap *mm)
|
struct perf_mmap *map)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = auxtrace_mmap__read_snapshot(mm, rec->itr, &rec->tool,
|
ret = auxtrace_mmap__read_snapshot(map, rec->itr, &rec->tool,
|
||||||
record__process_auxtrace,
|
record__process_auxtrace,
|
||||||
rec->opts.auxtrace_snapshot_size);
|
rec->opts.auxtrace_snapshot_size);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -245,13 +249,12 @@ static int record__auxtrace_read_snapshot_all(struct record *rec)
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
for (i = 0; i < rec->evlist->nr_mmaps; i++) {
|
for (i = 0; i < rec->evlist->nr_mmaps; i++) {
|
||||||
struct auxtrace_mmap *mm =
|
struct perf_mmap *map = &rec->evlist->mmap[i];
|
||||||
&rec->evlist->mmap[i].auxtrace_mmap;
|
|
||||||
|
|
||||||
if (!mm->base)
|
if (!map->auxtrace_mmap.base)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
|
if (record__auxtrace_mmap_read_snapshot(rec, map) != 0) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +298,7 @@ static int record__auxtrace_init(struct record *rec)
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
|
int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
|
||||||
struct auxtrace_mmap *mm __maybe_unused)
|
struct perf_mmap *map __maybe_unused)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -529,17 +532,17 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < evlist->nr_mmaps; i++) {
|
for (i = 0; i < evlist->nr_mmaps; i++) {
|
||||||
struct auxtrace_mmap *mm = &maps[i].auxtrace_mmap;
|
struct perf_mmap *map = &maps[i];
|
||||||
|
|
||||||
if (maps[i].base) {
|
if (map->base) {
|
||||||
if (perf_mmap__push(&maps[i], rec, record__pushfn) != 0) {
|
if (perf_mmap__push(map, rec, record__pushfn) != 0) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
|
if (map->auxtrace_mmap.base && !rec->opts.auxtrace_snapshot_mode &&
|
||||||
record__auxtrace_mmap_read(rec, mm) != 0) {
|
record__auxtrace_mmap_read(rec, map) != 0) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -550,7 +553,7 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
|
||||||
* at least one event.
|
* at least one event.
|
||||||
*/
|
*/
|
||||||
if (bytes_written != rec->bytes_written)
|
if (bytes_written != rec->bytes_written)
|
||||||
rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
|
rc = record__write(rec, NULL, &finished_round_event, sizeof(finished_round_event));
|
||||||
|
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY);
|
perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY);
|
||||||
|
|
|
@ -201,14 +201,13 @@ static void setup_forced_leader(struct report *report,
|
||||||
perf_evlist__force_leader(evlist);
|
perf_evlist__force_leader(evlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_feature_event(struct perf_tool *tool,
|
static int process_feature_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
struct report *rep = container_of(tool, struct report, tool);
|
struct report *rep = container_of(session->tool, struct report, tool);
|
||||||
|
|
||||||
if (event->feat.feat_id < HEADER_LAST_FEATURE)
|
if (event->feat.feat_id < HEADER_LAST_FEATURE)
|
||||||
return perf_event__process_feature(tool, event, session);
|
return perf_event__process_feature(session, event);
|
||||||
|
|
||||||
if (event->feat.feat_id != HEADER_LAST_FEATURE) {
|
if (event->feat.feat_id != HEADER_LAST_FEATURE) {
|
||||||
pr_err("failed: wrong feature ID: %" PRIu64 "\n",
|
pr_err("failed: wrong feature ID: %" PRIu64 "\n",
|
||||||
|
|
|
@ -2965,9 +2965,8 @@ static void script__setup_sample_type(struct perf_script *script)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
|
static int process_stat_round_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
struct stat_round_event *round = &event->stat_round;
|
struct stat_round_event *round = &event->stat_round;
|
||||||
struct perf_evsel *counter;
|
struct perf_evsel *counter;
|
||||||
|
@ -2981,9 +2980,8 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
|
static int process_stat_config_event(struct perf_session *session __maybe_unused,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
perf_event__read_stat_config(&stat_config, &event->stat_config);
|
perf_event__read_stat_config(&stat_config, &event->stat_config);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3009,10 +3007,10 @@ static int set_maps(struct perf_script *script)
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_thread_map_event(struct perf_tool *tool,
|
int process_thread_map_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
|
struct perf_tool *tool = session->tool;
|
||||||
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
||||||
|
|
||||||
if (script->threads) {
|
if (script->threads) {
|
||||||
|
@ -3028,10 +3026,10 @@ int process_thread_map_event(struct perf_tool *tool,
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
|
int process_cpu_map_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
|
struct perf_tool *tool = session->tool;
|
||||||
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
||||||
|
|
||||||
if (script->cpus) {
|
if (script->cpus) {
|
||||||
|
@ -3046,21 +3044,21 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
|
||||||
return set_maps(script);
|
return set_maps(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_feature_event(struct perf_tool *tool,
|
static int process_feature_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
if (event->feat.feat_id < HEADER_LAST_FEATURE)
|
if (event->feat.feat_id < HEADER_LAST_FEATURE)
|
||||||
return perf_event__process_feature(tool, event, session);
|
return perf_event__process_feature(session, event);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_AUXTRACE_SUPPORT
|
#ifdef HAVE_AUXTRACE_SUPPORT
|
||||||
static int perf_script__process_auxtrace_info(struct perf_tool *tool,
|
static int perf_script__process_auxtrace_info(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
int ret = perf_event__process_auxtrace_info(tool, event, session);
|
struct perf_tool *tool = session->tool;
|
||||||
|
|
||||||
|
int ret = perf_event__process_auxtrace_info(session, event);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
||||||
|
|
|
@ -1354,9 +1354,8 @@ static int __cmd_record(int argc, const char **argv)
|
||||||
return argc;
|
return argc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
|
static int process_stat_round_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
struct stat_round_event *stat_round = &event->stat_round;
|
struct stat_round_event *stat_round = &event->stat_round;
|
||||||
struct perf_evsel *counter;
|
struct perf_evsel *counter;
|
||||||
|
@ -1381,10 +1380,10 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_stat_config_event(struct perf_tool *tool,
|
int process_stat_config_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
|
struct perf_tool *tool = session->tool;
|
||||||
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
||||||
|
|
||||||
perf_event__read_stat_config(&stat_config, &event->stat_config);
|
perf_event__read_stat_config(&stat_config, &event->stat_config);
|
||||||
|
@ -1424,10 +1423,10 @@ static int set_maps(struct perf_stat *st)
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_thread_map_event(struct perf_tool *tool,
|
int process_thread_map_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
|
struct perf_tool *tool = session->tool;
|
||||||
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
||||||
|
|
||||||
if (st->threads) {
|
if (st->threads) {
|
||||||
|
@ -1443,10 +1442,10 @@ int process_thread_map_event(struct perf_tool *tool,
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_cpu_map_event(struct perf_tool *tool,
|
int process_cpu_map_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
|
struct perf_tool *tool = session->tool;
|
||||||
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
||||||
struct cpu_map *cpus;
|
struct cpu_map *cpus;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ perf-y += python-use.o
|
||||||
perf-y += bp_signal.o
|
perf-y += bp_signal.o
|
||||||
perf-y += bp_signal_overflow.o
|
perf-y += bp_signal_overflow.o
|
||||||
perf-y += bp_account.o
|
perf-y += bp_account.o
|
||||||
|
perf-y += wp.o
|
||||||
perf-y += task-exit.o
|
perf-y += task-exit.o
|
||||||
perf-y += sw-clock.o
|
perf-y += sw-clock.o
|
||||||
perf-y += mmap-thread-lookup.o
|
perf-y += mmap-thread-lookup.o
|
||||||
|
|
|
@ -120,6 +120,15 @@ static struct test generic_tests[] = {
|
||||||
.func = test__bp_accounting,
|
.func = test__bp_accounting,
|
||||||
.is_supported = test__bp_signal_is_supported,
|
.is_supported = test__bp_signal_is_supported,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.desc = "Watchpoint",
|
||||||
|
.func = test__wp,
|
||||||
|
.subtest = {
|
||||||
|
.skip_if_fail = false,
|
||||||
|
.get_nr = test__wp_subtest_get_nr,
|
||||||
|
.get_desc = test__wp_subtest_get_desc,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.desc = "Number of exit events of a simple workload",
|
.desc = "Number of exit events of a simple workload",
|
||||||
.func = test__task_exit,
|
.func = test__task_exit,
|
||||||
|
|
|
@ -59,6 +59,9 @@ int test__python_use(struct test *test, int subtest);
|
||||||
int test__bp_signal(struct test *test, int subtest);
|
int test__bp_signal(struct test *test, int subtest);
|
||||||
int test__bp_signal_overflow(struct test *test, int subtest);
|
int test__bp_signal_overflow(struct test *test, int subtest);
|
||||||
int test__bp_accounting(struct test *test, int subtest);
|
int test__bp_accounting(struct test *test, int subtest);
|
||||||
|
int test__wp(struct test *test, int subtest);
|
||||||
|
const char *test__wp_subtest_get_desc(int subtest);
|
||||||
|
int test__wp_subtest_get_nr(void);
|
||||||
int test__task_exit(struct test *test, int subtest);
|
int test__task_exit(struct test *test, int subtest);
|
||||||
int test__mem(struct test *test, int subtest);
|
int test__mem(struct test *test, int subtest);
|
||||||
int test__sw_clock_freq(struct test *test, int subtest);
|
int test__sw_clock_freq(struct test *test, int subtest);
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/hw_breakpoint.h>
|
||||||
|
#include "tests.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "cloexec.h"
|
||||||
|
|
||||||
|
#define WP_TEST_ASSERT_VAL(fd, text, val) \
|
||||||
|
do { \
|
||||||
|
long long count; \
|
||||||
|
wp_read(fd, &count, sizeof(long long)); \
|
||||||
|
TEST_ASSERT_VAL(text, count == val); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
volatile u64 data1;
|
||||||
|
volatile u8 data2[3];
|
||||||
|
|
||||||
|
static int wp_read(int fd, long long *count, int size)
|
||||||
|
{
|
||||||
|
int ret = read(fd, count, size);
|
||||||
|
|
||||||
|
if (ret != size) {
|
||||||
|
pr_debug("failed to read: %d\n", ret);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get__perf_event_attr(struct perf_event_attr *attr, int wp_type,
|
||||||
|
void *wp_addr, unsigned long wp_len)
|
||||||
|
{
|
||||||
|
memset(attr, 0, sizeof(struct perf_event_attr));
|
||||||
|
attr->type = PERF_TYPE_BREAKPOINT;
|
||||||
|
attr->size = sizeof(struct perf_event_attr);
|
||||||
|
attr->config = 0;
|
||||||
|
attr->bp_type = wp_type;
|
||||||
|
attr->bp_addr = (unsigned long)wp_addr;
|
||||||
|
attr->bp_len = wp_len;
|
||||||
|
attr->sample_period = 1;
|
||||||
|
attr->sample_type = PERF_SAMPLE_IP;
|
||||||
|
attr->exclude_kernel = 1;
|
||||||
|
attr->exclude_hv = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __event(int wp_type, void *wp_addr, unsigned long wp_len)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct perf_event_attr attr;
|
||||||
|
|
||||||
|
get__perf_event_attr(&attr, wp_type, wp_addr, wp_len);
|
||||||
|
fd = sys_perf_event_open(&attr, 0, -1, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
|
if (fd < 0)
|
||||||
|
pr_debug("failed opening event %x\n", attr.bp_type);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wp_ro_test(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned long tmp, tmp1 = rand();
|
||||||
|
|
||||||
|
fd = __event(HW_BREAKPOINT_R, (void *)&data1, sizeof(data1));
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tmp = data1;
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
|
||||||
|
|
||||||
|
data1 = tmp1 + tmp;
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "RO watchpoint", 1);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wp_wo_test(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned long tmp, tmp1 = rand();
|
||||||
|
|
||||||
|
fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tmp = data1;
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 0);
|
||||||
|
|
||||||
|
data1 = tmp1 + tmp;
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "WO watchpoint", 1);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wp_rw_test(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned long tmp, tmp1 = rand();
|
||||||
|
|
||||||
|
fd = __event(HW_BREAKPOINT_R | HW_BREAKPOINT_W, (void *)&data1,
|
||||||
|
sizeof(data1));
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tmp = data1;
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 1);
|
||||||
|
|
||||||
|
data1 = tmp1 + tmp;
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "RW watchpoint", 2);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wp_modify_test(void)
|
||||||
|
{
|
||||||
|
int fd, ret;
|
||||||
|
unsigned long tmp = rand();
|
||||||
|
struct perf_event_attr new_attr;
|
||||||
|
|
||||||
|
fd = __event(HW_BREAKPOINT_W, (void *)&data1, sizeof(data1));
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
data1 = tmp;
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
|
||||||
|
|
||||||
|
/* Modify watchpoint with disabled = 1 */
|
||||||
|
get__perf_event_attr(&new_attr, HW_BREAKPOINT_W, (void *)&data2[0],
|
||||||
|
sizeof(u8) * 2);
|
||||||
|
new_attr.disabled = 1;
|
||||||
|
ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_debug("ioctl(PERF_EVENT_IOC_MODIFY_ATTRIBUTES) failed\n");
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
data2[1] = tmp; /* Not Counted */
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 1);
|
||||||
|
|
||||||
|
/* Enable the event */
|
||||||
|
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_debug("Failed to enable event\n");
|
||||||
|
close(fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
data2[1] = tmp; /* Counted */
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
|
||||||
|
|
||||||
|
data2[2] = tmp; /* Not Counted */
|
||||||
|
WP_TEST_ASSERT_VAL(fd, "Modify watchpoint", 2);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool wp_ro_supported(void)
|
||||||
|
{
|
||||||
|
#if defined (__x86_64__) || defined (__i386__)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wp_ro_skip_msg(void)
|
||||||
|
{
|
||||||
|
#if defined (__x86_64__) || defined (__i386__)
|
||||||
|
pr_debug("Hardware does not support read only watchpoints.\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *desc;
|
||||||
|
int (*target_func)(void);
|
||||||
|
bool (*is_supported)(void);
|
||||||
|
void (*skip_msg)(void);
|
||||||
|
} wp_testcase_table[] = {
|
||||||
|
{
|
||||||
|
.desc = "Read Only Watchpoint",
|
||||||
|
.target_func = &wp_ro_test,
|
||||||
|
.is_supported = &wp_ro_supported,
|
||||||
|
.skip_msg = &wp_ro_skip_msg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.desc = "Write Only Watchpoint",
|
||||||
|
.target_func = &wp_wo_test,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.desc = "Read / Write Watchpoint",
|
||||||
|
.target_func = &wp_rw_test,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.desc = "Modify Watchpoint",
|
||||||
|
.target_func = &wp_modify_test,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int test__wp_subtest_get_nr(void)
|
||||||
|
{
|
||||||
|
return (int)ARRAY_SIZE(wp_testcase_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *test__wp_subtest_get_desc(int i)
|
||||||
|
{
|
||||||
|
if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
|
||||||
|
return NULL;
|
||||||
|
return wp_testcase_table[i].desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test__wp(struct test *test __maybe_unused, int i)
|
||||||
|
{
|
||||||
|
if (i < 0 || i >= (int)ARRAY_SIZE(wp_testcase_table))
|
||||||
|
return TEST_FAIL;
|
||||||
|
|
||||||
|
if (wp_testcase_table[i].is_supported &&
|
||||||
|
!wp_testcase_table[i].is_supported()) {
|
||||||
|
wp_testcase_table[i].skip_msg();
|
||||||
|
return TEST_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !wp_testcase_table[i].target_func() ? TEST_OK : TEST_FAIL;
|
||||||
|
}
|
|
@ -906,9 +906,8 @@ out_free:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
|
int perf_event__process_auxtrace_info(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
enum auxtrace_type type = event->auxtrace_info.type;
|
enum auxtrace_type type = event->auxtrace_info.type;
|
||||||
|
|
||||||
|
@ -932,9 +931,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 perf_event__process_auxtrace(struct perf_tool *tool,
|
s64 perf_event__process_auxtrace(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
s64 err;
|
s64 err;
|
||||||
|
|
||||||
|
@ -950,7 +948,7 @@ s64 perf_event__process_auxtrace(struct perf_tool *tool,
|
||||||
if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE)
|
if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
err = session->auxtrace->process_auxtrace_event(session, event, tool);
|
err = session->auxtrace->process_auxtrace_event(session, event, session->tool);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -1185,9 +1183,8 @@ void events_stats__auxtrace_error_warn(const struct events_stats *stats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
|
int perf_event__process_auxtrace_error(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
if (auxtrace__dont_decode(session))
|
if (auxtrace__dont_decode(session))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1196,11 +1193,12 @@ int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
|
static int __auxtrace_mmap__read(struct perf_mmap *map,
|
||||||
struct auxtrace_record *itr,
|
struct auxtrace_record *itr,
|
||||||
struct perf_tool *tool, process_auxtrace_t fn,
|
struct perf_tool *tool, process_auxtrace_t fn,
|
||||||
bool snapshot, size_t snapshot_size)
|
bool snapshot, size_t snapshot_size)
|
||||||
{
|
{
|
||||||
|
struct auxtrace_mmap *mm = &map->auxtrace_mmap;
|
||||||
u64 head, old = mm->prev, offset, ref;
|
u64 head, old = mm->prev, offset, ref;
|
||||||
unsigned char *data = mm->base;
|
unsigned char *data = mm->base;
|
||||||
size_t size, head_off, old_off, len1, len2, padding;
|
size_t size, head_off, old_off, len1, len2, padding;
|
||||||
|
@ -1287,7 +1285,7 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
|
||||||
ev.auxtrace.tid = mm->tid;
|
ev.auxtrace.tid = mm->tid;
|
||||||
ev.auxtrace.cpu = mm->cpu;
|
ev.auxtrace.cpu = mm->cpu;
|
||||||
|
|
||||||
if (fn(tool, &ev, data1, len1, data2, len2))
|
if (fn(tool, map, &ev, data1, len1, data2, len2))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
mm->prev = head;
|
mm->prev = head;
|
||||||
|
@ -1306,18 +1304,18 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
|
int auxtrace_mmap__read(struct perf_mmap *map, struct auxtrace_record *itr,
|
||||||
struct perf_tool *tool, process_auxtrace_t fn)
|
struct perf_tool *tool, process_auxtrace_t fn)
|
||||||
{
|
{
|
||||||
return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0);
|
return __auxtrace_mmap__read(map, itr, tool, fn, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
|
int auxtrace_mmap__read_snapshot(struct perf_mmap *map,
|
||||||
struct auxtrace_record *itr,
|
struct auxtrace_record *itr,
|
||||||
struct perf_tool *tool, process_auxtrace_t fn,
|
struct perf_tool *tool, process_auxtrace_t fn,
|
||||||
size_t snapshot_size)
|
size_t snapshot_size)
|
||||||
{
|
{
|
||||||
return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size);
|
return __auxtrace_mmap__read(map, itr, tool, fn, true, snapshot_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,6 +33,7 @@ union perf_event;
|
||||||
struct perf_session;
|
struct perf_session;
|
||||||
struct perf_evlist;
|
struct perf_evlist;
|
||||||
struct perf_tool;
|
struct perf_tool;
|
||||||
|
struct perf_mmap;
|
||||||
struct option;
|
struct option;
|
||||||
struct record_opts;
|
struct record_opts;
|
||||||
struct auxtrace_info_event;
|
struct auxtrace_info_event;
|
||||||
|
@ -434,13 +435,14 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
|
||||||
bool per_cpu);
|
bool per_cpu);
|
||||||
|
|
||||||
typedef int (*process_auxtrace_t)(struct perf_tool *tool,
|
typedef int (*process_auxtrace_t)(struct perf_tool *tool,
|
||||||
|
struct perf_mmap *map,
|
||||||
union perf_event *event, void *data1,
|
union perf_event *event, void *data1,
|
||||||
size_t len1, void *data2, size_t len2);
|
size_t len1, void *data2, size_t len2);
|
||||||
|
|
||||||
int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
|
int auxtrace_mmap__read(struct perf_mmap *map, struct auxtrace_record *itr,
|
||||||
struct perf_tool *tool, process_auxtrace_t fn);
|
struct perf_tool *tool, process_auxtrace_t fn);
|
||||||
|
|
||||||
int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
|
int auxtrace_mmap__read_snapshot(struct perf_mmap *map,
|
||||||
struct auxtrace_record *itr,
|
struct auxtrace_record *itr,
|
||||||
struct perf_tool *tool, process_auxtrace_t fn,
|
struct perf_tool *tool, process_auxtrace_t fn,
|
||||||
size_t snapshot_size);
|
size_t snapshot_size);
|
||||||
|
@ -517,15 +519,12 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
|
||||||
struct perf_tool *tool,
|
struct perf_tool *tool,
|
||||||
struct perf_session *session,
|
struct perf_session *session,
|
||||||
perf_event__handler_t process);
|
perf_event__handler_t process);
|
||||||
int perf_event__process_auxtrace_info(struct perf_tool *tool,
|
int perf_event__process_auxtrace_info(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event);
|
||||||
struct perf_session *session);
|
s64 perf_event__process_auxtrace(struct perf_session *session,
|
||||||
s64 perf_event__process_auxtrace(struct perf_tool *tool,
|
union perf_event *event);
|
||||||
union perf_event *event,
|
int perf_event__process_auxtrace_error(struct perf_session *session,
|
||||||
struct perf_session *session);
|
union perf_event *event);
|
||||||
int perf_event__process_auxtrace_error(struct perf_tool *tool,
|
|
||||||
union perf_event *event,
|
|
||||||
struct perf_session *session);
|
|
||||||
int itrace_parse_synth_opts(const struct option *opt, const char *str,
|
int itrace_parse_synth_opts(const struct option *opt, const char *str,
|
||||||
int unset);
|
int unset);
|
||||||
void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts);
|
void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts);
|
||||||
|
|
|
@ -1615,7 +1615,7 @@ struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const cha
|
||||||
int bpf__setup_stdout(struct perf_evlist *evlist)
|
int bpf__setup_stdout(struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__");
|
struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__");
|
||||||
return IS_ERR(evsel) ? PTR_ERR(evsel) : 0;
|
return PTR_ERR_OR_ZERO(evsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
|
#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
|
||||||
|
|
|
@ -1578,7 +1578,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
|
||||||
{
|
{
|
||||||
struct perf_session *session;
|
struct perf_session *session;
|
||||||
struct perf_data data = {
|
struct perf_data data = {
|
||||||
.file.path = input,
|
.file = { .path = input, .fd = -1 },
|
||||||
.mode = PERF_DATA_MODE_READ,
|
.mode = PERF_DATA_MODE_READ,
|
||||||
.force = opts->force,
|
.force = opts->force,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3448,10 +3448,10 @@ int perf_event__synthesize_features(struct perf_tool *tool,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__process_feature(struct perf_tool *tool,
|
int perf_event__process_feature(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
|
struct perf_tool *tool = session->tool;
|
||||||
struct feat_fd ff = { .fd = 0 };
|
struct feat_fd ff = { .fd = 0 };
|
||||||
struct feature_event *fe = (struct feature_event *)event;
|
struct feature_event *fe = (struct feature_event *)event;
|
||||||
int type = fe->header.type;
|
int type = fe->header.type;
|
||||||
|
@ -3856,9 +3856,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
|
||||||
return aligned_size;
|
return aligned_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
|
int perf_event__process_tracing_data(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
ssize_t size_read, padding, size = event->tracing_data.size;
|
ssize_t size_read, padding, size = event->tracing_data.size;
|
||||||
int fd = perf_data__fd(session->data);
|
int fd = perf_data__fd(session->data);
|
||||||
|
@ -3924,9 +3923,8 @@ int perf_event__synthesize_build_id(struct perf_tool *tool,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__process_build_id(struct perf_tool *tool __maybe_unused,
|
int perf_event__process_build_id(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
__event_process_build_id(&event->build_id,
|
__event_process_build_id(&event->build_id,
|
||||||
event->build_id.filename,
|
event->build_id.filename,
|
||||||
|
|
|
@ -116,9 +116,8 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
bool is_pipe);
|
bool is_pipe);
|
||||||
|
|
||||||
int perf_event__process_feature(struct perf_tool *tool,
|
int perf_event__process_feature(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event);
|
||||||
struct perf_session *session);
|
|
||||||
|
|
||||||
int perf_event__synthesize_attr(struct perf_tool *tool,
|
int perf_event__synthesize_attr(struct perf_tool *tool,
|
||||||
struct perf_event_attr *attr, u32 ids, u64 *id,
|
struct perf_event_attr *attr, u32 ids, u64 *id,
|
||||||
|
@ -148,17 +147,15 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp);
|
||||||
int perf_event__synthesize_tracing_data(struct perf_tool *tool,
|
int perf_event__synthesize_tracing_data(struct perf_tool *tool,
|
||||||
int fd, struct perf_evlist *evlist,
|
int fd, struct perf_evlist *evlist,
|
||||||
perf_event__handler_t process);
|
perf_event__handler_t process);
|
||||||
int perf_event__process_tracing_data(struct perf_tool *tool,
|
int perf_event__process_tracing_data(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event);
|
||||||
struct perf_session *session);
|
|
||||||
|
|
||||||
int perf_event__synthesize_build_id(struct perf_tool *tool,
|
int perf_event__synthesize_build_id(struct perf_tool *tool,
|
||||||
struct dso *pos, u16 misc,
|
struct dso *pos, u16 misc,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
struct machine *machine);
|
struct machine *machine);
|
||||||
int perf_event__process_build_id(struct perf_tool *tool,
|
int perf_event__process_build_id(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event);
|
||||||
struct perf_session *session);
|
|
||||||
bool is_perf_magic(u64 magic);
|
bool is_perf_magic(u64 magic);
|
||||||
|
|
||||||
#define NAME_ALIGN 64
|
#define NAME_ALIGN 64
|
||||||
|
|
|
@ -281,7 +281,7 @@ int perf_mmap__read_init(struct perf_mmap *map)
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_mmap__push(struct perf_mmap *md, void *to,
|
int perf_mmap__push(struct perf_mmap *md, void *to,
|
||||||
int push(void *to, void *buf, size_t size))
|
int push(struct perf_mmap *map, void *to, void *buf, size_t size))
|
||||||
{
|
{
|
||||||
u64 head = perf_mmap__read_head(md);
|
u64 head = perf_mmap__read_head(md);
|
||||||
unsigned char *data = md->base + page_size;
|
unsigned char *data = md->base + page_size;
|
||||||
|
@ -300,7 +300,7 @@ int perf_mmap__push(struct perf_mmap *md, void *to,
|
||||||
size = md->mask + 1 - (md->start & md->mask);
|
size = md->mask + 1 - (md->start & md->mask);
|
||||||
md->start += size;
|
md->start += size;
|
||||||
|
|
||||||
if (push(to, buf, size) < 0) {
|
if (push(md, to, buf, size) < 0) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ int perf_mmap__push(struct perf_mmap *md, void *to,
|
||||||
size = md->end - md->start;
|
size = md->end - md->start;
|
||||||
md->start += size;
|
md->start += size;
|
||||||
|
|
||||||
if (push(to, buf, size) < 0) {
|
if (push(md, to, buf, size) < 0) {
|
||||||
rc = -1;
|
rc = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *map);
|
||||||
union perf_event *perf_mmap__read_event(struct perf_mmap *map);
|
union perf_event *perf_mmap__read_event(struct perf_mmap *map);
|
||||||
|
|
||||||
int perf_mmap__push(struct perf_mmap *md, void *to,
|
int perf_mmap__push(struct perf_mmap *md, void *to,
|
||||||
int push(void *to, void *buf, size_t size));
|
int push(struct perf_mmap *map, void *to, void *buf, size_t size));
|
||||||
|
|
||||||
size_t perf_mmap__mmap_len(struct perf_mmap *map);
|
size_t perf_mmap__mmap_len(struct perf_mmap *map);
|
||||||
|
|
||||||
|
|
|
@ -80,14 +80,20 @@ static union perf_event *dup_event(struct ordered_events *oe,
|
||||||
return oe->copy_on_queue ? __dup_event(oe, event) : event;
|
return oe->copy_on_queue ? __dup_event(oe, event) : event;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_dup_event(struct ordered_events *oe, union perf_event *event)
|
static void __free_dup_event(struct ordered_events *oe, union perf_event *event)
|
||||||
{
|
{
|
||||||
if (event && oe->copy_on_queue) {
|
if (event) {
|
||||||
oe->cur_alloc_size -= event->header.size;
|
oe->cur_alloc_size -= event->header.size;
|
||||||
free(event);
|
free(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_dup_event(struct ordered_events *oe, union perf_event *event)
|
||||||
|
{
|
||||||
|
if (oe->copy_on_queue)
|
||||||
|
__free_dup_event(oe, event);
|
||||||
|
}
|
||||||
|
|
||||||
#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event))
|
#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event))
|
||||||
static struct ordered_event *alloc_event(struct ordered_events *oe,
|
static struct ordered_event *alloc_event(struct ordered_events *oe,
|
||||||
union perf_event *event)
|
union perf_event *event)
|
||||||
|
@ -95,21 +101,49 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
|
||||||
struct list_head *cache = &oe->cache;
|
struct list_head *cache = &oe->cache;
|
||||||
struct ordered_event *new = NULL;
|
struct ordered_event *new = NULL;
|
||||||
union perf_event *new_event;
|
union perf_event *new_event;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
new_event = dup_event(oe, event);
|
new_event = dup_event(oe, event);
|
||||||
if (!new_event)
|
if (!new_event)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We maintain the following scheme of buffers for ordered
|
||||||
|
* event allocation:
|
||||||
|
*
|
||||||
|
* to_free list -> buffer1 (64K)
|
||||||
|
* buffer2 (64K)
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* Each buffer keeps an array of ordered events objects:
|
||||||
|
* buffer -> event[0]
|
||||||
|
* event[1]
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* Each allocated ordered event is linked to one of
|
||||||
|
* following lists:
|
||||||
|
* - time ordered list 'events'
|
||||||
|
* - list of currently removed events 'cache'
|
||||||
|
*
|
||||||
|
* Allocation of the ordered event uses the following order
|
||||||
|
* to get the memory:
|
||||||
|
* - use recently removed object from 'cache' list
|
||||||
|
* - use available object in current allocation buffer
|
||||||
|
* - allocate new buffer if the current buffer is full
|
||||||
|
*
|
||||||
|
* Removal of ordered event object moves it from events to
|
||||||
|
* the cache list.
|
||||||
|
*/
|
||||||
|
size = sizeof(*oe->buffer) + MAX_SAMPLE_BUFFER * sizeof(*new);
|
||||||
|
|
||||||
if (!list_empty(cache)) {
|
if (!list_empty(cache)) {
|
||||||
new = list_entry(cache->next, struct ordered_event, list);
|
new = list_entry(cache->next, struct ordered_event, list);
|
||||||
list_del(&new->list);
|
list_del(&new->list);
|
||||||
} else if (oe->buffer) {
|
} else if (oe->buffer) {
|
||||||
new = oe->buffer + oe->buffer_idx;
|
new = &oe->buffer->event[oe->buffer_idx];
|
||||||
if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
|
if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
|
||||||
oe->buffer = NULL;
|
oe->buffer = NULL;
|
||||||
} else if (oe->cur_alloc_size < oe->max_alloc_size) {
|
} else if ((oe->cur_alloc_size + size) < oe->max_alloc_size) {
|
||||||
size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
|
|
||||||
|
|
||||||
oe->buffer = malloc(size);
|
oe->buffer = malloc(size);
|
||||||
if (!oe->buffer) {
|
if (!oe->buffer) {
|
||||||
free_dup_event(oe, new_event);
|
free_dup_event(oe, new_event);
|
||||||
|
@ -122,11 +156,11 @@ static struct ordered_event *alloc_event(struct ordered_events *oe,
|
||||||
oe->cur_alloc_size += size;
|
oe->cur_alloc_size += size;
|
||||||
list_add(&oe->buffer->list, &oe->to_free);
|
list_add(&oe->buffer->list, &oe->to_free);
|
||||||
|
|
||||||
/* First entry is abused to maintain the to_free list. */
|
oe->buffer_idx = 1;
|
||||||
oe->buffer_idx = 2;
|
new = &oe->buffer->event[0];
|
||||||
new = oe->buffer + 1;
|
|
||||||
} else {
|
} else {
|
||||||
pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
|
pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
new->event = new_event;
|
new->event = new_event;
|
||||||
|
@ -300,15 +334,38 @@ void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t d
|
||||||
oe->deliver = deliver;
|
oe->deliver = deliver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ordered_events_buffer__free(struct ordered_events_buffer *buffer,
|
||||||
|
unsigned int max, struct ordered_events *oe)
|
||||||
|
{
|
||||||
|
if (oe->copy_on_queue) {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < max; i++)
|
||||||
|
__free_dup_event(oe, buffer->event[i].event);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void ordered_events__free(struct ordered_events *oe)
|
void ordered_events__free(struct ordered_events *oe)
|
||||||
{
|
{
|
||||||
while (!list_empty(&oe->to_free)) {
|
struct ordered_events_buffer *buffer, *tmp;
|
||||||
struct ordered_event *event;
|
|
||||||
|
|
||||||
event = list_entry(oe->to_free.next, struct ordered_event, list);
|
if (list_empty(&oe->to_free))
|
||||||
list_del(&event->list);
|
return;
|
||||||
free_dup_event(oe, event->event);
|
|
||||||
free(event);
|
/*
|
||||||
|
* Current buffer might not have all the events allocated
|
||||||
|
* yet, we need to free only allocated ones ...
|
||||||
|
*/
|
||||||
|
list_del(&oe->buffer->list);
|
||||||
|
ordered_events_buffer__free(oe->buffer, oe->buffer_idx, oe);
|
||||||
|
|
||||||
|
/* ... and continue with the rest */
|
||||||
|
list_for_each_entry_safe(buffer, tmp, &oe->to_free, list) {
|
||||||
|
list_del(&buffer->list);
|
||||||
|
ordered_events_buffer__free(buffer, MAX_SAMPLE_BUFFER, oe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,23 +25,28 @@ struct ordered_events;
|
||||||
typedef int (*ordered_events__deliver_t)(struct ordered_events *oe,
|
typedef int (*ordered_events__deliver_t)(struct ordered_events *oe,
|
||||||
struct ordered_event *event);
|
struct ordered_event *event);
|
||||||
|
|
||||||
|
struct ordered_events_buffer {
|
||||||
|
struct list_head list;
|
||||||
|
struct ordered_event event[0];
|
||||||
|
};
|
||||||
|
|
||||||
struct ordered_events {
|
struct ordered_events {
|
||||||
u64 last_flush;
|
u64 last_flush;
|
||||||
u64 next_flush;
|
u64 next_flush;
|
||||||
u64 max_timestamp;
|
u64 max_timestamp;
|
||||||
u64 max_alloc_size;
|
u64 max_alloc_size;
|
||||||
u64 cur_alloc_size;
|
u64 cur_alloc_size;
|
||||||
struct list_head events;
|
struct list_head events;
|
||||||
struct list_head cache;
|
struct list_head cache;
|
||||||
struct list_head to_free;
|
struct list_head to_free;
|
||||||
struct ordered_event *buffer;
|
struct ordered_events_buffer *buffer;
|
||||||
struct ordered_event *last;
|
struct ordered_event *last;
|
||||||
ordered_events__deliver_t deliver;
|
ordered_events__deliver_t deliver;
|
||||||
int buffer_idx;
|
int buffer_idx;
|
||||||
unsigned int nr_events;
|
unsigned int nr_events;
|
||||||
enum oe_flush last_flush_type;
|
enum oe_flush last_flush_type;
|
||||||
u32 nr_unordered_events;
|
u32 nr_unordered_events;
|
||||||
bool copy_on_queue;
|
bool copy_on_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
|
int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
|
||||||
|
|
|
@ -199,12 +199,10 @@ void perf_session__delete(struct perf_session *session)
|
||||||
free(session);
|
free(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_event_synth_tracing_data_stub(struct perf_tool *tool
|
static int process_event_synth_tracing_data_stub(struct perf_session *session
|
||||||
__maybe_unused,
|
__maybe_unused,
|
||||||
union perf_event *event
|
union perf_event *event
|
||||||
__maybe_unused,
|
__maybe_unused)
|
||||||
struct perf_session *session
|
|
||||||
__maybe_unused)
|
|
||||||
{
|
{
|
||||||
dump_printf(": unhandled!\n");
|
dump_printf(": unhandled!\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -277,10 +275,8 @@ static int skipn(int fd, off_t n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
|
static s64 process_event_auxtrace_stub(struct perf_session *session __maybe_unused,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session
|
|
||||||
__maybe_unused)
|
|
||||||
{
|
{
|
||||||
dump_printf(": unhandled!\n");
|
dump_printf(": unhandled!\n");
|
||||||
if (perf_data__is_pipe(session->data))
|
if (perf_data__is_pipe(session->data))
|
||||||
|
@ -288,9 +284,8 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
|
||||||
return event->auxtrace.size;
|
return event->auxtrace.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
|
static int process_event_op2_stub(struct perf_session *session __maybe_unused,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event __maybe_unused)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
dump_printf(": unhandled!\n");
|
dump_printf(": unhandled!\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -298,9 +293,8 @@ static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
|
int process_event_thread_map_stub(struct perf_session *session __maybe_unused,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event __maybe_unused)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
if (dump_trace)
|
if (dump_trace)
|
||||||
perf_event__fprintf_thread_map(event, stdout);
|
perf_event__fprintf_thread_map(event, stdout);
|
||||||
|
@ -310,9 +304,8 @@ int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
|
int process_event_cpu_map_stub(struct perf_session *session __maybe_unused,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event __maybe_unused)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
if (dump_trace)
|
if (dump_trace)
|
||||||
perf_event__fprintf_cpu_map(event, stdout);
|
perf_event__fprintf_cpu_map(event, stdout);
|
||||||
|
@ -322,9 +315,8 @@ int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
|
int process_event_stat_config_stub(struct perf_session *session __maybe_unused,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event __maybe_unused)
|
||||||
struct perf_session *session __maybe_unused)
|
|
||||||
{
|
{
|
||||||
if (dump_trace)
|
if (dump_trace)
|
||||||
perf_event__fprintf_stat_config(event, stdout);
|
perf_event__fprintf_stat_config(event, stdout);
|
||||||
|
@ -333,10 +325,8 @@ int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_stat_stub(struct perf_tool *tool __maybe_unused,
|
static int process_stat_stub(struct perf_session *perf_session __maybe_unused,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event)
|
||||||
struct perf_session *perf_session
|
|
||||||
__maybe_unused)
|
|
||||||
{
|
{
|
||||||
if (dump_trace)
|
if (dump_trace)
|
||||||
perf_event__fprintf_stat(event, stdout);
|
perf_event__fprintf_stat(event, stdout);
|
||||||
|
@ -345,10 +335,8 @@ static int process_stat_stub(struct perf_tool *tool __maybe_unused,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,
|
static int process_stat_round_stub(struct perf_session *perf_session __maybe_unused,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event)
|
||||||
struct perf_session *perf_session
|
|
||||||
__maybe_unused)
|
|
||||||
{
|
{
|
||||||
if (dump_trace)
|
if (dump_trace)
|
||||||
perf_event__fprintf_stat_round(event, stdout);
|
perf_event__fprintf_stat_round(event, stdout);
|
||||||
|
@ -1374,37 +1362,37 @@ static s64 perf_session__process_user_event(struct perf_session *session,
|
||||||
case PERF_RECORD_HEADER_TRACING_DATA:
|
case PERF_RECORD_HEADER_TRACING_DATA:
|
||||||
/* setup for reading amidst mmap */
|
/* setup for reading amidst mmap */
|
||||||
lseek(fd, file_offset, SEEK_SET);
|
lseek(fd, file_offset, SEEK_SET);
|
||||||
return tool->tracing_data(tool, event, session);
|
return tool->tracing_data(session, event);
|
||||||
case PERF_RECORD_HEADER_BUILD_ID:
|
case PERF_RECORD_HEADER_BUILD_ID:
|
||||||
return tool->build_id(tool, event, session);
|
return tool->build_id(session, event);
|
||||||
case PERF_RECORD_FINISHED_ROUND:
|
case PERF_RECORD_FINISHED_ROUND:
|
||||||
return tool->finished_round(tool, event, oe);
|
return tool->finished_round(tool, event, oe);
|
||||||
case PERF_RECORD_ID_INDEX:
|
case PERF_RECORD_ID_INDEX:
|
||||||
return tool->id_index(tool, event, session);
|
return tool->id_index(session, event);
|
||||||
case PERF_RECORD_AUXTRACE_INFO:
|
case PERF_RECORD_AUXTRACE_INFO:
|
||||||
return tool->auxtrace_info(tool, event, session);
|
return tool->auxtrace_info(session, event);
|
||||||
case PERF_RECORD_AUXTRACE:
|
case PERF_RECORD_AUXTRACE:
|
||||||
/* setup for reading amidst mmap */
|
/* setup for reading amidst mmap */
|
||||||
lseek(fd, file_offset + event->header.size, SEEK_SET);
|
lseek(fd, file_offset + event->header.size, SEEK_SET);
|
||||||
return tool->auxtrace(tool, event, session);
|
return tool->auxtrace(session, event);
|
||||||
case PERF_RECORD_AUXTRACE_ERROR:
|
case PERF_RECORD_AUXTRACE_ERROR:
|
||||||
perf_session__auxtrace_error_inc(session, event);
|
perf_session__auxtrace_error_inc(session, event);
|
||||||
return tool->auxtrace_error(tool, event, session);
|
return tool->auxtrace_error(session, event);
|
||||||
case PERF_RECORD_THREAD_MAP:
|
case PERF_RECORD_THREAD_MAP:
|
||||||
return tool->thread_map(tool, event, session);
|
return tool->thread_map(session, event);
|
||||||
case PERF_RECORD_CPU_MAP:
|
case PERF_RECORD_CPU_MAP:
|
||||||
return tool->cpu_map(tool, event, session);
|
return tool->cpu_map(session, event);
|
||||||
case PERF_RECORD_STAT_CONFIG:
|
case PERF_RECORD_STAT_CONFIG:
|
||||||
return tool->stat_config(tool, event, session);
|
return tool->stat_config(session, event);
|
||||||
case PERF_RECORD_STAT:
|
case PERF_RECORD_STAT:
|
||||||
return tool->stat(tool, event, session);
|
return tool->stat(session, event);
|
||||||
case PERF_RECORD_STAT_ROUND:
|
case PERF_RECORD_STAT_ROUND:
|
||||||
return tool->stat_round(tool, event, session);
|
return tool->stat_round(session, event);
|
||||||
case PERF_RECORD_TIME_CONV:
|
case PERF_RECORD_TIME_CONV:
|
||||||
session->time_conv = event->time_conv;
|
session->time_conv = event->time_conv;
|
||||||
return tool->time_conv(tool, event, session);
|
return tool->time_conv(session, event);
|
||||||
case PERF_RECORD_HEADER_FEATURE:
|
case PERF_RECORD_HEADER_FEATURE:
|
||||||
return tool->feature(tool, event, session);
|
return tool->feature(session, event);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -2133,9 +2121,8 @@ out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__process_id_index(struct perf_tool *tool __maybe_unused,
|
int perf_event__process_id_index(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
struct perf_evlist *evlist = session->evlist;
|
struct perf_evlist *evlist = session->evlist;
|
||||||
struct id_index_event *ie = &event->id_index;
|
struct id_index_event *ie = &event->id_index;
|
||||||
|
|
|
@ -120,9 +120,8 @@ int perf_session__deliver_synth_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
struct perf_sample *sample);
|
struct perf_sample *sample);
|
||||||
|
|
||||||
int perf_event__process_id_index(struct perf_tool *tool,
|
int perf_event__process_id_index(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event);
|
||||||
struct perf_session *session);
|
|
||||||
|
|
||||||
int perf_event__synthesize_id_index(struct perf_tool *tool,
|
int perf_event__synthesize_id_index(struct perf_tool *tool,
|
||||||
perf_event__handler_t process,
|
perf_event__handler_t process,
|
||||||
|
|
|
@ -35,7 +35,7 @@ class install_lib(_install_lib):
|
||||||
|
|
||||||
cflags = getenv('CFLAGS', '').split()
|
cflags = getenv('CFLAGS', '').split()
|
||||||
# switch off several checks (need to be at the end of cflags list)
|
# switch off several checks (need to be at the end of cflags list)
|
||||||
cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
|
cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls' ]
|
||||||
if cc != "clang":
|
if cc != "clang":
|
||||||
cflags += ['-Wno-cast-function-type' ]
|
cflags += ['-Wno-cast-function-type' ]
|
||||||
|
|
||||||
|
|
|
@ -374,9 +374,8 @@ int perf_stat_process_counter(struct perf_stat_config *config,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
|
int perf_event__process_stat_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event)
|
||||||
struct perf_session *session)
|
|
||||||
{
|
{
|
||||||
struct perf_counts_values count;
|
struct perf_counts_values count;
|
||||||
struct stat_event *st = &event->stat;
|
struct stat_event *st = &event->stat;
|
||||||
|
|
|
@ -199,9 +199,8 @@ int perf_stat_process_counter(struct perf_stat_config *config,
|
||||||
struct perf_tool;
|
struct perf_tool;
|
||||||
union perf_event;
|
union perf_event;
|
||||||
struct perf_session;
|
struct perf_session;
|
||||||
int perf_event__process_stat_event(struct perf_tool *tool,
|
int perf_event__process_stat_event(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event);
|
||||||
struct perf_session *session);
|
|
||||||
|
|
||||||
size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp);
|
size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp);
|
||||||
size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp);
|
size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp);
|
||||||
|
|
|
@ -26,15 +26,12 @@ typedef int (*event_attr_op)(struct perf_tool *tool,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
struct perf_evlist **pevlist);
|
struct perf_evlist **pevlist);
|
||||||
|
|
||||||
typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
|
typedef int (*event_op2)(struct perf_session *session, union perf_event *event);
|
||||||
struct perf_session *session);
|
typedef s64 (*event_op3)(struct perf_session *session, union perf_event *event);
|
||||||
|
|
||||||
typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event,
|
typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event,
|
||||||
struct ordered_events *oe);
|
struct ordered_events *oe);
|
||||||
|
|
||||||
typedef s64 (*event_op3)(struct perf_tool *tool, union perf_event *event,
|
|
||||||
struct perf_session *session);
|
|
||||||
|
|
||||||
enum show_feature_header {
|
enum show_feature_header {
|
||||||
SHOW_FEAT_NO_HEADER = 0,
|
SHOW_FEAT_NO_HEADER = 0,
|
||||||
SHOW_FEAT_HEADER,
|
SHOW_FEAT_HEADER,
|
||||||
|
|
|
@ -221,7 +221,7 @@ out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
|
int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)
|
||||||
{
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
loff_t pgoff;
|
loff_t pgoff;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
|
/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
|
||||||
#define _DEFAULT_SOURCE 1
|
#define _DEFAULT_SOURCE 1
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -35,6 +36,7 @@ bool lsdir_no_dot_filter(const char *name, struct dirent *d);
|
||||||
int copyfile(const char *from, const char *to);
|
int copyfile(const char *from, const char *to);
|
||||||
int copyfile_mode(const char *from, const char *to, mode_t mode);
|
int copyfile_mode(const char *from, const char *to, mode_t mode);
|
||||||
int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi);
|
int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi);
|
||||||
|
int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size);
|
||||||
|
|
||||||
ssize_t readn(int fd, void *buf, size_t n);
|
ssize_t readn(int fd, void *buf, size_t n);
|
||||||
ssize_t writen(int fd, const void *buf, size_t n);
|
ssize_t writen(int fd, const void *buf, size_t n);
|
||||||
|
|
Loading…
Reference in New Issue