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,8 +459,18 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size)
|
|||
if (size || handle->aux_flags) {
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (handle->aux_flags & ~(u64)PERF_AUX_FLAG_OVERWRITE)
|
||||
perf_event_aux_event(handle->event, aux_head, size,
|
||||
handle->aux_flags);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -283,12 +283,11 @@ out_put:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int process_feature_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static int process_feature_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,12 +86,10 @@ static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int perf_event__repipe_op2_synth(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session
|
||||
__maybe_unused)
|
||||
static int perf_event__repipe_op2_synth(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
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,
|
||||
|
@ -133,10 +131,10 @@ static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static s64 perf_event__repipe_auxtrace(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_tool *tool = session->tool;
|
||||
struct perf_inject *inject = container_of(tool, struct perf_inject,
|
||||
tool);
|
||||
int ret;
|
||||
|
@ -174,9 +172,8 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
|
|||
#else
|
||||
|
||||
static s64
|
||||
perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_session *session __maybe_unused)
|
||||
perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event __maybe_unused)
|
||||
{
|
||||
pr_err("AUX area tracing not supported\n");
|
||||
return -EINVAL;
|
||||
|
@ -362,26 +359,24 @@ static int perf_event__repipe_exit(struct perf_tool *tool,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int perf_event__repipe_tracing_data(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static int perf_event__repipe_tracing_data(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
int err;
|
||||
|
||||
perf_event__repipe_synth(tool, event);
|
||||
err = perf_event__process_tracing_data(tool, event, session);
|
||||
perf_event__repipe_synth(session->tool, event);
|
||||
err = perf_event__process_tracing_data(session, event);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int perf_event__repipe_id_index(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static int perf_event__repipe_id_index(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
int err;
|
||||
|
||||
perf_event__repipe_synth(tool, event);
|
||||
err = perf_event__process_id_index(tool, event, session);
|
||||
perf_event__repipe_synth(session->tool, event);
|
||||
err = perf_event__process_id_index(session, event);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -106,9 +106,12 @@ static bool switch_output_time(struct record *rec)
|
|||
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");
|
||||
return -1;
|
||||
}
|
||||
|
@ -127,15 +130,15 @@ static int process_synthesized_event(struct perf_tool *tool,
|
|||
struct machine *machine __maybe_unused)
|
||||
{
|
||||
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;
|
||||
|
||||
rec->samples++;
|
||||
return record__write(rec, bf, size);
|
||||
return record__write(rec, map, bf, size);
|
||||
}
|
||||
|
||||
static volatile int done;
|
||||
|
@ -170,6 +173,7 @@ static void record__sig_exit(void)
|
|||
#ifdef HAVE_AUXTRACE_SUPPORT
|
||||
|
||||
static int record__process_auxtrace(struct perf_tool *tool,
|
||||
struct perf_mmap *map,
|
||||
union perf_event *event, void *data1,
|
||||
size_t len1, void *data2, size_t len2)
|
||||
{
|
||||
|
@ -197,21 +201,21 @@ static int record__process_auxtrace(struct perf_tool *tool,
|
|||
if (padding)
|
||||
padding = 8 - padding;
|
||||
|
||||
record__write(rec, event, event->header.size);
|
||||
record__write(rec, data1, len1);
|
||||
record__write(rec, map, event, event->header.size);
|
||||
record__write(rec, map, data1, len1);
|
||||
if (len2)
|
||||
record__write(rec, data2, len2);
|
||||
record__write(rec, &pad, padding);
|
||||
record__write(rec, map, data2, len2);
|
||||
record__write(rec, map, &pad, padding);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int record__auxtrace_mmap_read(struct record *rec,
|
||||
struct auxtrace_mmap *mm)
|
||||
struct perf_mmap *map)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = auxtrace_mmap__read(mm, rec->itr, &rec->tool,
|
||||
ret = auxtrace_mmap__read(map, rec->itr, &rec->tool,
|
||||
record__process_auxtrace);
|
||||
if (ret < 0)
|
||||
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,
|
||||
struct auxtrace_mmap *mm)
|
||||
struct perf_mmap *map)
|
||||
{
|
||||
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,
|
||||
rec->opts.auxtrace_snapshot_size);
|
||||
if (ret < 0)
|
||||
|
@ -245,13 +249,12 @@ static int record__auxtrace_read_snapshot_all(struct record *rec)
|
|||
int rc = 0;
|
||||
|
||||
for (i = 0; i < rec->evlist->nr_mmaps; i++) {
|
||||
struct auxtrace_mmap *mm =
|
||||
&rec->evlist->mmap[i].auxtrace_mmap;
|
||||
struct perf_mmap *map = &rec->evlist->mmap[i];
|
||||
|
||||
if (!mm->base)
|
||||
if (!map->auxtrace_mmap.base)
|
||||
continue;
|
||||
|
||||
if (record__auxtrace_mmap_read_snapshot(rec, mm) != 0) {
|
||||
if (record__auxtrace_mmap_read_snapshot(rec, map) != 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
@ -295,7 +298,7 @@ static int record__auxtrace_init(struct record *rec)
|
|||
|
||||
static inline
|
||||
int record__auxtrace_mmap_read(struct record *rec __maybe_unused,
|
||||
struct auxtrace_mmap *mm __maybe_unused)
|
||||
struct perf_mmap *map __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -529,17 +532,17 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
|
|||
return 0;
|
||||
|
||||
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 (perf_mmap__push(&maps[i], rec, record__pushfn) != 0) {
|
||||
if (map->base) {
|
||||
if (perf_mmap__push(map, rec, record__pushfn) != 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (mm->base && !rec->opts.auxtrace_snapshot_mode &&
|
||||
record__auxtrace_mmap_read(rec, mm) != 0) {
|
||||
if (map->auxtrace_mmap.base && !rec->opts.auxtrace_snapshot_mode &&
|
||||
record__auxtrace_mmap_read(rec, map) != 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
@ -550,7 +553,7 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
|
|||
* at least one event.
|
||||
*/
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
static int process_feature_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
static int process_feature_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
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)
|
||||
return perf_event__process_feature(tool, event, session);
|
||||
return perf_event__process_feature(session, event);
|
||||
|
||||
if (event->feat.feat_id != HEADER_LAST_FEATURE) {
|
||||
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,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static int process_stat_round_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct stat_round_event *round = &event->stat_round;
|
||||
struct perf_evsel *counter;
|
||||
|
@ -2981,9 +2980,8 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
static int process_stat_config_event(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event)
|
||||
{
|
||||
perf_event__read_stat_config(&stat_config, &event->stat_config);
|
||||
return 0;
|
||||
|
@ -3009,10 +3007,10 @@ static int set_maps(struct perf_script *script)
|
|||
}
|
||||
|
||||
static
|
||||
int process_thread_map_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_thread_map_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_tool *tool = session->tool;
|
||||
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
||||
|
||||
if (script->threads) {
|
||||
|
@ -3028,10 +3026,10 @@ int process_thread_map_event(struct perf_tool *tool,
|
|||
}
|
||||
|
||||
static
|
||||
int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_cpu_map_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_tool *tool = session->tool;
|
||||
struct perf_script *script = container_of(tool, struct perf_script, tool);
|
||||
|
||||
if (script->cpus) {
|
||||
|
@ -3046,21 +3044,21 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
|
|||
return set_maps(script);
|
||||
}
|
||||
|
||||
static int process_feature_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static int process_feature_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef HAVE_AUXTRACE_SUPPORT
|
||||
static int perf_script__process_auxtrace_info(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static int perf_script__process_auxtrace_info(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
static int process_stat_round_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct stat_round_event *stat_round = &event->stat_round;
|
||||
struct perf_evsel *counter;
|
||||
|
@ -1381,10 +1380,10 @@ static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
|
|||
}
|
||||
|
||||
static
|
||||
int process_stat_config_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_stat_config_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_tool *tool = session->tool;
|
||||
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
||||
|
||||
perf_event__read_stat_config(&stat_config, &event->stat_config);
|
||||
|
@ -1424,10 +1423,10 @@ static int set_maps(struct perf_stat *st)
|
|||
}
|
||||
|
||||
static
|
||||
int process_thread_map_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_thread_map_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_tool *tool = session->tool;
|
||||
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
||||
|
||||
if (st->threads) {
|
||||
|
@ -1443,10 +1442,10 @@ int process_thread_map_event(struct perf_tool *tool,
|
|||
}
|
||||
|
||||
static
|
||||
int process_cpu_map_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_cpu_map_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_tool *tool = session->tool;
|
||||
struct perf_stat *st = container_of(tool, struct perf_stat, tool);
|
||||
struct cpu_map *cpus;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ perf-y += python-use.o
|
|||
perf-y += bp_signal.o
|
||||
perf-y += bp_signal_overflow.o
|
||||
perf-y += bp_account.o
|
||||
perf-y += wp.o
|
||||
perf-y += task-exit.o
|
||||
perf-y += sw-clock.o
|
||||
perf-y += mmap-thread-lookup.o
|
||||
|
|
|
@ -120,6 +120,15 @@ static struct test generic_tests[] = {
|
|||
.func = test__bp_accounting,
|
||||
.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",
|
||||
.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_overflow(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__mem(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;
|
||||
}
|
||||
|
||||
int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
int perf_event__process_auxtrace_info(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
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,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
s64 perf_event__process_auxtrace(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
s64 err;
|
||||
|
||||
|
@ -950,7 +948,7 @@ s64 perf_event__process_auxtrace(struct perf_tool *tool,
|
|||
if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE)
|
||||
return -EINVAL;
|
||||
|
||||
err = session->auxtrace->process_auxtrace_event(session, event, tool);
|
||||
err = session->auxtrace->process_auxtrace_event(session, event, session->tool);
|
||||
if (err < 0)
|
||||
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,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
int perf_event__process_auxtrace_error(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
if (auxtrace__dont_decode(session))
|
||||
return 0;
|
||||
|
@ -1196,11 +1193,12 @@ int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
|
|||
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 perf_tool *tool, process_auxtrace_t fn,
|
||||
bool snapshot, size_t snapshot_size)
|
||||
{
|
||||
struct auxtrace_mmap *mm = &map->auxtrace_mmap;
|
||||
u64 head, old = mm->prev, offset, ref;
|
||||
unsigned char *data = mm->base;
|
||||
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.cpu = mm->cpu;
|
||||
|
||||
if (fn(tool, &ev, data1, len1, data2, len2))
|
||||
if (fn(tool, map, &ev, data1, len1, data2, len2))
|
||||
return -1;
|
||||
|
||||
mm->prev = head;
|
||||
|
@ -1306,18 +1304,18 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
|
|||
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)
|
||||
{
|
||||
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 perf_tool *tool, process_auxtrace_t fn,
|
||||
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_evlist;
|
||||
struct perf_tool;
|
||||
struct perf_mmap;
|
||||
struct option;
|
||||
struct record_opts;
|
||||
struct auxtrace_info_event;
|
||||
|
@ -434,13 +435,14 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
|
|||
bool per_cpu);
|
||||
|
||||
typedef int (*process_auxtrace_t)(struct perf_tool *tool,
|
||||
struct perf_mmap *map,
|
||||
union perf_event *event, void *data1,
|
||||
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);
|
||||
|
||||
int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
|
||||
int auxtrace_mmap__read_snapshot(struct perf_mmap *map,
|
||||
struct auxtrace_record *itr,
|
||||
struct perf_tool *tool, process_auxtrace_t fn,
|
||||
size_t snapshot_size);
|
||||
|
@ -517,15 +519,12 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
|
|||
struct perf_tool *tool,
|
||||
struct perf_session *session,
|
||||
perf_event__handler_t process);
|
||||
int perf_event__process_auxtrace_info(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
s64 perf_event__process_auxtrace(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
int perf_event__process_auxtrace_error(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
int perf_event__process_auxtrace_info(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
s64 perf_event__process_auxtrace(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
int perf_event__process_auxtrace_error(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
int itrace_parse_synth_opts(const struct option *opt, const char *str,
|
||||
int unset);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -1578,7 +1578,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
|
|||
{
|
||||
struct perf_session *session;
|
||||
struct perf_data data = {
|
||||
.file.path = input,
|
||||
.file = { .path = input, .fd = -1 },
|
||||
.mode = PERF_DATA_MODE_READ,
|
||||
.force = opts->force,
|
||||
};
|
||||
|
|
|
@ -3448,10 +3448,10 @@ int perf_event__synthesize_features(struct perf_tool *tool,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int perf_event__process_feature(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int perf_event__process_feature(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_tool *tool = session->tool;
|
||||
struct feat_fd ff = { .fd = 0 };
|
||||
struct feature_event *fe = (struct feature_event *)event;
|
||||
int type = fe->header.type;
|
||||
|
@ -3856,9 +3856,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
|
|||
return aligned_size;
|
||||
}
|
||||
|
||||
int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
int perf_event__process_tracing_data(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
ssize_t size_read, padding, size = event->tracing_data.size;
|
||||
int fd = perf_data__fd(session->data);
|
||||
|
@ -3924,9 +3923,8 @@ int perf_event__synthesize_build_id(struct perf_tool *tool,
|
|||
return err;
|
||||
}
|
||||
|
||||
int perf_event__process_build_id(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
int perf_event__process_build_id(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
__event_process_build_id(&event->build_id,
|
||||
event->build_id.filename,
|
||||
|
|
|
@ -116,9 +116,8 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool,
|
|||
perf_event__handler_t process,
|
||||
bool is_pipe);
|
||||
|
||||
int perf_event__process_feature(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
int perf_event__process_feature(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
|
||||
int perf_event__synthesize_attr(struct perf_tool *tool,
|
||||
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 fd, struct perf_evlist *evlist,
|
||||
perf_event__handler_t process);
|
||||
int perf_event__process_tracing_data(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
int perf_event__process_tracing_data(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
|
||||
int perf_event__synthesize_build_id(struct perf_tool *tool,
|
||||
struct dso *pos, u16 misc,
|
||||
perf_event__handler_t process,
|
||||
struct machine *machine);
|
||||
int perf_event__process_build_id(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
int perf_event__process_build_id(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
bool is_perf_magic(u64 magic);
|
||||
|
||||
#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 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);
|
||||
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);
|
||||
md->start += size;
|
||||
|
||||
if (push(to, buf, size) < 0) {
|
||||
if (push(md, to, buf, size) < 0) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ int perf_mmap__push(struct perf_mmap *md, void *to,
|
|||
size = md->end - md->start;
|
||||
md->start += size;
|
||||
|
||||
if (push(to, buf, size) < 0) {
|
||||
if (push(md, to, buf, size) < 0) {
|
||||
rc = -1;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -80,14 +80,20 @@ static union perf_event *dup_event(struct ordered_events *oe,
|
|||
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;
|
||||
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))
|
||||
static struct ordered_event *alloc_event(struct ordered_events *oe,
|
||||
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 ordered_event *new = NULL;
|
||||
union perf_event *new_event;
|
||||
size_t size;
|
||||
|
||||
new_event = dup_event(oe, event);
|
||||
if (!new_event)
|
||||
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)) {
|
||||
new = list_entry(cache->next, struct ordered_event, list);
|
||||
list_del(&new->list);
|
||||
} else if (oe->buffer) {
|
||||
new = oe->buffer + oe->buffer_idx;
|
||||
new = &oe->buffer->event[oe->buffer_idx];
|
||||
if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
|
||||
oe->buffer = NULL;
|
||||
} else if (oe->cur_alloc_size < oe->max_alloc_size) {
|
||||
size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
|
||||
|
||||
} else if ((oe->cur_alloc_size + size) < oe->max_alloc_size) {
|
||||
oe->buffer = malloc(size);
|
||||
if (!oe->buffer) {
|
||||
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;
|
||||
list_add(&oe->buffer->list, &oe->to_free);
|
||||
|
||||
/* First entry is abused to maintain the to_free list. */
|
||||
oe->buffer_idx = 2;
|
||||
new = oe->buffer + 1;
|
||||
oe->buffer_idx = 1;
|
||||
new = &oe->buffer->event[0];
|
||||
} else {
|
||||
pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new->event = new_event;
|
||||
|
@ -300,15 +334,38 @@ void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t d
|
|||
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)
|
||||
{
|
||||
while (!list_empty(&oe->to_free)) {
|
||||
struct ordered_event *event;
|
||||
struct ordered_events_buffer *buffer, *tmp;
|
||||
|
||||
event = list_entry(oe->to_free.next, struct ordered_event, list);
|
||||
list_del(&event->list);
|
||||
free_dup_event(oe, event->event);
|
||||
free(event);
|
||||
if (list_empty(&oe->to_free))
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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,6 +25,11 @@ struct ordered_events;
|
|||
typedef int (*ordered_events__deliver_t)(struct ordered_events *oe,
|
||||
struct ordered_event *event);
|
||||
|
||||
struct ordered_events_buffer {
|
||||
struct list_head list;
|
||||
struct ordered_event event[0];
|
||||
};
|
||||
|
||||
struct ordered_events {
|
||||
u64 last_flush;
|
||||
u64 next_flush;
|
||||
|
@ -34,7 +39,7 @@ struct ordered_events {
|
|||
struct list_head events;
|
||||
struct list_head cache;
|
||||
struct list_head to_free;
|
||||
struct ordered_event *buffer;
|
||||
struct ordered_events_buffer *buffer;
|
||||
struct ordered_event *last;
|
||||
ordered_events__deliver_t deliver;
|
||||
int buffer_idx;
|
||||
|
|
|
@ -199,11 +199,9 @@ void perf_session__delete(struct perf_session *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,
|
||||
union perf_event *event
|
||||
__maybe_unused,
|
||||
struct perf_session *session
|
||||
__maybe_unused)
|
||||
{
|
||||
dump_printf(": unhandled!\n");
|
||||
|
@ -277,10 +275,8 @@ static int skipn(int fd, off_t n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session
|
||||
__maybe_unused)
|
||||
static s64 process_event_auxtrace_stub(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event)
|
||||
{
|
||||
dump_printf(": unhandled!\n");
|
||||
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;
|
||||
}
|
||||
|
||||
static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_session *session __maybe_unused)
|
||||
static int process_event_op2_stub(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event __maybe_unused)
|
||||
{
|
||||
dump_printf(": unhandled!\n");
|
||||
return 0;
|
||||
|
@ -298,9 +293,8 @@ static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
|
|||
|
||||
|
||||
static
|
||||
int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_event_thread_map_stub(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event __maybe_unused)
|
||||
{
|
||||
if (dump_trace)
|
||||
perf_event__fprintf_thread_map(event, stdout);
|
||||
|
@ -310,9 +304,8 @@ int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
|
|||
}
|
||||
|
||||
static
|
||||
int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_event_cpu_map_stub(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event __maybe_unused)
|
||||
{
|
||||
if (dump_trace)
|
||||
perf_event__fprintf_cpu_map(event, stdout);
|
||||
|
@ -322,9 +315,8 @@ int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
|
|||
}
|
||||
|
||||
static
|
||||
int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_session *session __maybe_unused)
|
||||
int process_event_stat_config_stub(struct perf_session *session __maybe_unused,
|
||||
union perf_event *event __maybe_unused)
|
||||
{
|
||||
if (dump_trace)
|
||||
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;
|
||||
}
|
||||
|
||||
static int process_stat_stub(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_session *perf_session
|
||||
__maybe_unused)
|
||||
static int process_stat_stub(struct perf_session *perf_session __maybe_unused,
|
||||
union perf_event *event)
|
||||
{
|
||||
if (dump_trace)
|
||||
perf_event__fprintf_stat(event, stdout);
|
||||
|
@ -345,10 +335,8 @@ static int process_stat_stub(struct perf_tool *tool __maybe_unused,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event __maybe_unused,
|
||||
struct perf_session *perf_session
|
||||
__maybe_unused)
|
||||
static int process_stat_round_stub(struct perf_session *perf_session __maybe_unused,
|
||||
union perf_event *event)
|
||||
{
|
||||
if (dump_trace)
|
||||
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:
|
||||
/* setup for reading amidst mmap */
|
||||
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:
|
||||
return tool->build_id(tool, event, session);
|
||||
return tool->build_id(session, event);
|
||||
case PERF_RECORD_FINISHED_ROUND:
|
||||
return tool->finished_round(tool, event, oe);
|
||||
case PERF_RECORD_ID_INDEX:
|
||||
return tool->id_index(tool, event, session);
|
||||
return tool->id_index(session, event);
|
||||
case PERF_RECORD_AUXTRACE_INFO:
|
||||
return tool->auxtrace_info(tool, event, session);
|
||||
return tool->auxtrace_info(session, event);
|
||||
case PERF_RECORD_AUXTRACE:
|
||||
/* setup for reading amidst mmap */
|
||||
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:
|
||||
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:
|
||||
return tool->thread_map(tool, event, session);
|
||||
return tool->thread_map(session, event);
|
||||
case PERF_RECORD_CPU_MAP:
|
||||
return tool->cpu_map(tool, event, session);
|
||||
return tool->cpu_map(session, event);
|
||||
case PERF_RECORD_STAT_CONFIG:
|
||||
return tool->stat_config(tool, event, session);
|
||||
return tool->stat_config(session, event);
|
||||
case PERF_RECORD_STAT:
|
||||
return tool->stat(tool, event, session);
|
||||
return tool->stat(session, event);
|
||||
case PERF_RECORD_STAT_ROUND:
|
||||
return tool->stat_round(tool, event, session);
|
||||
return tool->stat_round(session, event);
|
||||
case PERF_RECORD_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:
|
||||
return tool->feature(tool, event, session);
|
||||
return tool->feature(session, event);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2133,9 +2121,8 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
int perf_event__process_id_index(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
int perf_event__process_id_index(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_evlist *evlist = session->evlist;
|
||||
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,
|
||||
struct perf_sample *sample);
|
||||
|
||||
int perf_event__process_id_index(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
int perf_event__process_id_index(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
|
||||
int perf_event__synthesize_id_index(struct perf_tool *tool,
|
||||
perf_event__handler_t process,
|
||||
|
|
|
@ -35,7 +35,7 @@ class install_lib(_install_lib):
|
|||
|
||||
cflags = getenv('CFLAGS', '').split()
|
||||
# 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":
|
||||
cflags += ['-Wno-cast-function-type' ]
|
||||
|
||||
|
|
|
@ -374,9 +374,8 @@ int perf_stat_process_counter(struct perf_stat_config *config,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_session *session)
|
||||
int perf_event__process_stat_event(struct perf_session *session,
|
||||
union perf_event *event)
|
||||
{
|
||||
struct perf_counts_values count;
|
||||
struct stat_event *st = &event->stat;
|
||||
|
|
|
@ -199,9 +199,8 @@ int perf_stat_process_counter(struct perf_stat_config *config,
|
|||
struct perf_tool;
|
||||
union perf_event;
|
||||
struct perf_session;
|
||||
int perf_event__process_stat_event(struct perf_tool *tool,
|
||||
union perf_event *event,
|
||||
struct perf_session *session);
|
||||
int perf_event__process_stat_event(struct perf_session *session,
|
||||
union perf_event *event);
|
||||
|
||||
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);
|
||||
|
|
|
@ -26,15 +26,12 @@ typedef int (*event_attr_op)(struct perf_tool *tool,
|
|||
union perf_event *event,
|
||||
struct perf_evlist **pevlist);
|
||||
|
||||
typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
|
||||
struct perf_session *session);
|
||||
typedef int (*event_op2)(struct perf_session *session, union perf_event *event);
|
||||
typedef s64 (*event_op3)(struct perf_session *session, union perf_event *event);
|
||||
|
||||
typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event,
|
||||
struct ordered_events *oe);
|
||||
|
||||
typedef s64 (*event_op3)(struct perf_tool *tool, union perf_event *event,
|
||||
struct perf_session *session);
|
||||
|
||||
enum show_feature_header {
|
||||
SHOW_FEAT_NO_HEADER = 0,
|
||||
SHOW_FEAT_HEADER,
|
||||
|
|
|
@ -221,7 +221,7 @@ out:
|
|||
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;
|
||||
loff_t pgoff;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
|
||||
#define _DEFAULT_SOURCE 1
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.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_mode(const char *from, const char *to, mode_t mode);
|
||||
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 writen(int fd, const void *buf, size_t n);
|
||||
|
|
Loading…
Reference in New Issue