You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Validate syscall list passed via -e argument to 'perf trace'. (Arnaldo Carvalho de Melo) - Introduce 'perf stat --per-thread'. (Jiri Olsa) - Check access permission for --kallsyms and --vmlinux. (Li Zhang) Infrastructure changes: - Move stuff out of 'perf stat' and into the lib for further use. (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:
@@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores. To enable this mod
|
||||
use --per-core in addition to -a. (system-wide). The output includes the
|
||||
core number and the number of online logical processors on that physical processor.
|
||||
|
||||
--per-thread::
|
||||
Aggregate counts per monitored threads, when monitoring threads (-t option)
|
||||
or processes (-p option).
|
||||
|
||||
-D msecs::
|
||||
--delay msecs::
|
||||
After starting the program, wait msecs before measuring. This is useful to
|
||||
|
||||
@@ -742,6 +742,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
|
||||
argc = parse_options(argc, argv, options, report_usage, 0);
|
||||
|
||||
if (symbol_conf.vmlinux_name &&
|
||||
access(symbol_conf.vmlinux_name, R_OK)) {
|
||||
pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (symbol_conf.kallsyms_name &&
|
||||
access(symbol_conf.kallsyms_name, R_OK)) {
|
||||
pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (report.use_stdio)
|
||||
use_browser = 0;
|
||||
else if (report.use_tui)
|
||||
|
||||
+208
-196
File diff suppressed because it is too large
Load Diff
@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id)
|
||||
return syscall__set_arg_fmts(sc);
|
||||
}
|
||||
|
||||
static int trace__validate_ev_qualifier(struct trace *trace)
|
||||
{
|
||||
int err = 0;
|
||||
struct str_node *pos;
|
||||
|
||||
strlist__for_each(pos, trace->ev_qualifier) {
|
||||
const char *sc = pos->s;
|
||||
|
||||
if (audit_name_to_syscall(sc, trace->audit.machine) < 0) {
|
||||
if (err == 0) {
|
||||
fputs("Error:\tInvalid syscall ", trace->output);
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
fputs(", ", trace->output);
|
||||
}
|
||||
|
||||
fputs(sc, trace->output);
|
||||
}
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
|
||||
"\nHint:\tand: 'man syscalls'\n", trace->output);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* args is to be interpreted as a series of longs but we need to handle
|
||||
* 8-byte unaligned accesses. args points to raw_data within the event
|
||||
@@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
err = -ENOMEM;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
err = trace__validate_ev_qualifier(&trace);
|
||||
if (err)
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
err = target__validate(&trace.opts.target);
|
||||
|
||||
@@ -31,6 +31,7 @@ perf-y += code-reading.o
|
||||
perf-y += sample-parsing.o
|
||||
perf-y += parse-no-sample-id-all.o
|
||||
perf-y += kmod-path.o
|
||||
perf-y += thread-map.o
|
||||
|
||||
perf-$(CONFIG_X86) += perf-time-to-tsc.o
|
||||
|
||||
|
||||
@@ -170,6 +170,10 @@ static struct test {
|
||||
.desc = "Test kmod_path__parse function",
|
||||
.func = test__kmod_path__parse,
|
||||
},
|
||||
{
|
||||
.desc = "Test thread map",
|
||||
.func = test__thread_map,
|
||||
},
|
||||
{
|
||||
.func = NULL,
|
||||
},
|
||||
|
||||
@@ -78,7 +78,7 @@ int test__openat_syscall_event_on_all_cpus(void)
|
||||
* we use the auto allocation it will allocate just for 1 cpu,
|
||||
* as we start by cpu 0.
|
||||
*/
|
||||
if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
|
||||
if (perf_evsel__alloc_counts(evsel, cpus->nr, 1) < 0) {
|
||||
pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
|
||||
goto out_close_fd;
|
||||
}
|
||||
@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void)
|
||||
}
|
||||
|
||||
expected = nr_openat_calls + cpu;
|
||||
if (evsel->counts->cpu[cpu].val != expected) {
|
||||
if (perf_counts(evsel->counts, cpu, 0)->val != expected) {
|
||||
pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
|
||||
expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
|
||||
expected, cpus->map[cpu], perf_counts(evsel->counts, cpu, 0)->val);
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ int test__openat_syscall_event(void)
|
||||
goto out_close_fd;
|
||||
}
|
||||
|
||||
if (evsel->counts->cpu[0].val != nr_openat_calls) {
|
||||
if (perf_counts(evsel->counts, 0, 0)->val != nr_openat_calls) {
|
||||
pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
|
||||
nr_openat_calls, evsel->counts->cpu[0].val);
|
||||
nr_openat_calls, perf_counts(evsel->counts, 0, 0)->val);
|
||||
goto out_close_fd;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ int test__switch_tracking(void);
|
||||
int test__fdarray__filter(void);
|
||||
int test__fdarray__add(void);
|
||||
int test__kmod_path__parse(void);
|
||||
int test__thread_map(void);
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
|
||||
#ifdef HAVE_DWARF_UNWIND_SUPPORT
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "tests.h"
|
||||
#include "thread_map.h"
|
||||
#include "debug.h"
|
||||
|
||||
int test__thread_map(void)
|
||||
{
|
||||
struct thread_map *map;
|
||||
|
||||
/* test map on current pid */
|
||||
map = thread_map__new_by_pid(getpid());
|
||||
TEST_ASSERT_VAL("failed to alloc map", map);
|
||||
|
||||
thread_map__read_comms(map);
|
||||
|
||||
TEST_ASSERT_VAL("wrong nr", map->nr == 1);
|
||||
TEST_ASSERT_VAL("wrong pid",
|
||||
thread_map__pid(map, 0) == getpid());
|
||||
TEST_ASSERT_VAL("wrong comm",
|
||||
thread_map__comm(map, 0) &&
|
||||
!strcmp(thread_map__comm(map, 0), "perf"));
|
||||
thread_map__put(map);
|
||||
|
||||
/* test dummy pid */
|
||||
map = thread_map__new_dummy();
|
||||
TEST_ASSERT_VAL("failed to alloc map", map);
|
||||
|
||||
thread_map__read_comms(map);
|
||||
|
||||
TEST_ASSERT_VAL("wrong nr", map->nr == 1);
|
||||
TEST_ASSERT_VAL("wrong pid", thread_map__pid(map, 0) == -1);
|
||||
TEST_ASSERT_VAL("wrong comm",
|
||||
thread_map__comm(map, 0) &&
|
||||
!strcmp(thread_map__comm(map, 0), "dummy"));
|
||||
thread_map__put(map);
|
||||
return 0;
|
||||
}
|
||||
@@ -289,5 +289,4 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
|
||||
|
||||
void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
|
||||
struct perf_evsel *tracking_evsel);
|
||||
|
||||
#endif /* __PERF_EVLIST_H */
|
||||
|
||||
+11
-13
@@ -898,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)
|
||||
free(evsel);
|
||||
}
|
||||
|
||||
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
|
||||
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread,
|
||||
struct perf_counts_values *count)
|
||||
{
|
||||
struct perf_counts_values tmp;
|
||||
@@ -910,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
|
||||
tmp = evsel->prev_raw_counts->aggr;
|
||||
evsel->prev_raw_counts->aggr = *count;
|
||||
} else {
|
||||
tmp = evsel->prev_raw_counts->cpu[cpu];
|
||||
evsel->prev_raw_counts->cpu[cpu] = *count;
|
||||
tmp = *perf_counts(evsel->prev_raw_counts, cpu, thread);
|
||||
*perf_counts(evsel->prev_raw_counts, cpu, thread) = *count;
|
||||
}
|
||||
|
||||
count->val = count->val - tmp.val;
|
||||
@@ -939,20 +939,18 @@ void perf_counts_values__scale(struct perf_counts_values *count,
|
||||
*pscaled = scaled;
|
||||
}
|
||||
|
||||
int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
|
||||
perf_evsel__read_cb_t cb)
|
||||
int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
|
||||
struct perf_counts_values *count)
|
||||
{
|
||||
struct perf_counts_values count;
|
||||
|
||||
memset(&count, 0, sizeof(count));
|
||||
memset(count, 0, sizeof(*count));
|
||||
|
||||
if (FD(evsel, cpu, thread) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (readn(FD(evsel, cpu, thread), &count, sizeof(count)) < 0)
|
||||
if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) < 0)
|
||||
return -errno;
|
||||
|
||||
return cb(evsel, cpu, thread, &count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
|
||||
@@ -964,15 +962,15 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
|
||||
if (FD(evsel, cpu, thread) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
|
||||
if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
|
||||
return -errno;
|
||||
|
||||
perf_evsel__compute_deltas(evsel, cpu, &count);
|
||||
perf_evsel__compute_deltas(evsel, cpu, thread, &count);
|
||||
perf_counts_values__scale(&count, scale, NULL);
|
||||
evsel->counts->cpu[cpu] = count;
|
||||
*perf_counts(evsel->counts, cpu, thread) = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+4
-24
@@ -9,23 +9,7 @@
|
||||
#include "xyarray.h"
|
||||
#include "symbol.h"
|
||||
#include "cpumap.h"
|
||||
|
||||
struct perf_counts_values {
|
||||
union {
|
||||
struct {
|
||||
u64 val;
|
||||
u64 ena;
|
||||
u64 run;
|
||||
};
|
||||
u64 values[3];
|
||||
};
|
||||
};
|
||||
|
||||
struct perf_counts {
|
||||
s8 scaled;
|
||||
struct perf_counts_values aggr;
|
||||
struct perf_counts_values cpu[];
|
||||
};
|
||||
#include "stat.h"
|
||||
|
||||
struct perf_evsel;
|
||||
|
||||
@@ -128,7 +112,7 @@ static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
|
||||
void perf_counts_values__scale(struct perf_counts_values *count,
|
||||
bool scale, s8 *pscaled);
|
||||
|
||||
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
|
||||
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread,
|
||||
struct perf_counts_values *count);
|
||||
|
||||
int perf_evsel__object_config(size_t object_size,
|
||||
@@ -245,12 +229,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
|
||||
(a)->attr.type == (b)->attr.type && \
|
||||
(a)->attr.config == (b)->attr.config)
|
||||
|
||||
typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel,
|
||||
int cpu, int thread,
|
||||
struct perf_counts_values *count);
|
||||
|
||||
int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
|
||||
perf_evsel__read_cb_t cb);
|
||||
int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
|
||||
struct perf_counts_values *count);
|
||||
|
||||
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
|
||||
int cpu, int thread, bool scale);
|
||||
|
||||
@@ -20,3 +20,4 @@ util/stat.c
|
||||
util/strlist.c
|
||||
util/trace-event.c
|
||||
../../lib/rbtree.c
|
||||
util/string.c
|
||||
|
||||
+120
-12
@@ -1,6 +1,8 @@
|
||||
#include <math.h>
|
||||
#include "stat.h"
|
||||
#include "evlist.h"
|
||||
#include "evsel.h"
|
||||
#include "thread_map.h"
|
||||
|
||||
void update_stats(struct stats *stats, u64 val)
|
||||
{
|
||||
@@ -95,33 +97,46 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
|
||||
}
|
||||
}
|
||||
|
||||
struct perf_counts *perf_counts__new(int ncpus)
|
||||
struct perf_counts *perf_counts__new(int ncpus, int nthreads)
|
||||
{
|
||||
int size = sizeof(struct perf_counts) +
|
||||
ncpus * sizeof(struct perf_counts_values);
|
||||
struct perf_counts *counts = zalloc(sizeof(*counts));
|
||||
|
||||
return zalloc(size);
|
||||
if (counts) {
|
||||
struct xyarray *values;
|
||||
|
||||
values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values));
|
||||
if (!values) {
|
||||
free(counts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
counts->values = values;
|
||||
}
|
||||
|
||||
return counts;
|
||||
}
|
||||
|
||||
void perf_counts__delete(struct perf_counts *counts)
|
||||
{
|
||||
free(counts);
|
||||
if (counts) {
|
||||
xyarray__delete(counts->values);
|
||||
free(counts);
|
||||
}
|
||||
}
|
||||
|
||||
static void perf_counts__reset(struct perf_counts *counts, int ncpus)
|
||||
static void perf_counts__reset(struct perf_counts *counts)
|
||||
{
|
||||
memset(counts, 0, (sizeof(*counts) +
|
||||
(ncpus * sizeof(struct perf_counts_values))));
|
||||
xyarray__reset(counts->values);
|
||||
}
|
||||
|
||||
void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
|
||||
void perf_evsel__reset_counts(struct perf_evsel *evsel)
|
||||
{
|
||||
perf_counts__reset(evsel->counts, ncpus);
|
||||
perf_counts__reset(evsel->counts);
|
||||
}
|
||||
|
||||
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
|
||||
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
{
|
||||
evsel->counts = perf_counts__new(ncpus);
|
||||
evsel->counts = perf_counts__new(ncpus, nthreads);
|
||||
return evsel->counts != NULL ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -130,3 +145,96 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)
|
||||
perf_counts__delete(evsel->counts);
|
||||
evsel->counts = NULL;
|
||||
}
|
||||
|
||||
void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
|
||||
{
|
||||
int i;
|
||||
struct perf_stat *ps = evsel->priv;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
init_stats(&ps->res_stats[i]);
|
||||
|
||||
perf_stat_evsel_id_init(evsel);
|
||||
}
|
||||
|
||||
int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
|
||||
{
|
||||
evsel->priv = zalloc(sizeof(struct perf_stat));
|
||||
if (evsel->priv == NULL)
|
||||
return -ENOMEM;
|
||||
perf_evsel__reset_stat_priv(evsel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
|
||||
{
|
||||
zfree(&evsel->priv);
|
||||
}
|
||||
|
||||
int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
|
||||
int ncpus, int nthreads)
|
||||
{
|
||||
struct perf_counts *counts;
|
||||
|
||||
counts = perf_counts__new(ncpus, nthreads);
|
||||
if (counts)
|
||||
evsel->prev_raw_counts = counts;
|
||||
|
||||
return counts ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
|
||||
{
|
||||
perf_counts__delete(evsel->prev_raw_counts);
|
||||
evsel->prev_raw_counts = NULL;
|
||||
}
|
||||
|
||||
int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
|
||||
{
|
||||
int ncpus = perf_evsel__nr_cpus(evsel);
|
||||
int nthreads = thread_map__nr(evsel->threads);
|
||||
|
||||
if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
|
||||
perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 ||
|
||||
(alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
if (perf_evsel__alloc_stats(evsel, alloc_raw))
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
perf_evlist__free_stats(evlist);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void perf_evlist__free_stats(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
perf_evsel__free_stat_priv(evsel);
|
||||
perf_evsel__free_counts(evsel);
|
||||
perf_evsel__free_prev_raw_counts(evsel);
|
||||
}
|
||||
}
|
||||
|
||||
void perf_evlist__reset_stats(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
evlist__for_each(evlist, evsel) {
|
||||
perf_evsel__reset_stat_priv(evsel);
|
||||
perf_evsel__reset_counts(evsel);
|
||||
}
|
||||
}
|
||||
|
||||
+44
-3
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <stdio.h>
|
||||
#include "xyarray.h"
|
||||
|
||||
struct stats
|
||||
{
|
||||
@@ -29,8 +30,32 @@ enum aggr_mode {
|
||||
AGGR_GLOBAL,
|
||||
AGGR_SOCKET,
|
||||
AGGR_CORE,
|
||||
AGGR_THREAD,
|
||||
};
|
||||
|
||||
struct perf_counts_values {
|
||||
union {
|
||||
struct {
|
||||
u64 val;
|
||||
u64 ena;
|
||||
u64 run;
|
||||
};
|
||||
u64 values[3];
|
||||
};
|
||||
};
|
||||
|
||||
struct perf_counts {
|
||||
s8 scaled;
|
||||
struct perf_counts_values aggr;
|
||||
struct xyarray *values;
|
||||
};
|
||||
|
||||
static inline struct perf_counts_values*
|
||||
perf_counts(struct perf_counts *counts, int cpu, int thread)
|
||||
{
|
||||
return xyarray__entry(counts->values, cpu, thread);
|
||||
}
|
||||
|
||||
void update_stats(struct stats *stats, u64 val);
|
||||
double avg_stats(struct stats *stats);
|
||||
double stddev_stats(struct stats *stats);
|
||||
@@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats)
|
||||
}
|
||||
|
||||
struct perf_evsel;
|
||||
struct perf_evlist;
|
||||
|
||||
bool __perf_evsel_stat__is(struct perf_evsel *evsel,
|
||||
enum perf_stat_evsel_id id);
|
||||
|
||||
@@ -62,10 +89,24 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
|
||||
void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
|
||||
double avg, int cpu, enum aggr_mode aggr);
|
||||
|
||||
struct perf_counts *perf_counts__new(int ncpus);
|
||||
struct perf_counts *perf_counts__new(int ncpus, int nthreads);
|
||||
void perf_counts__delete(struct perf_counts *counts);
|
||||
|
||||
void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
|
||||
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
|
||||
void perf_evsel__reset_counts(struct perf_evsel *evsel);
|
||||
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
|
||||
void perf_evsel__free_counts(struct perf_evsel *evsel);
|
||||
|
||||
void perf_evsel__reset_stat_priv(struct perf_evsel *evsel);
|
||||
int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel);
|
||||
void perf_evsel__free_stat_priv(struct perf_evsel *evsel);
|
||||
|
||||
int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
|
||||
int ncpus, int nthreads);
|
||||
void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel);
|
||||
|
||||
int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw);
|
||||
|
||||
int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
|
||||
void perf_evlist__free_stats(struct perf_evlist *evlist);
|
||||
void perf_evlist__reset_stats(struct perf_evlist *evlist);
|
||||
#endif
|
||||
|
||||
@@ -1132,8 +1132,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
INIT_LIST_HEAD(&md.maps);
|
||||
|
||||
fd = open(kcore_filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
pr_err("%s requires CAP_SYS_RAWIO capability to access.\n",
|
||||
kcore_filename);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read new maps into temporary lists */
|
||||
err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#include <unistd.h>
|
||||
#include "strlist.h"
|
||||
#include <string.h>
|
||||
#include <api/fs/fs.h>
|
||||
#include "asm/bug.h"
|
||||
#include "thread_map.h"
|
||||
#include "util.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* Skip "." and ".." directories */
|
||||
static int filter(const struct dirent *dir)
|
||||
@@ -21,11 +23,26 @@ static int filter(const struct dirent *dir)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void thread_map__reset(struct thread_map *map, int start, int nr)
|
||||
{
|
||||
size_t size = (nr - start) * sizeof(map->map[0]);
|
||||
|
||||
memset(&map->map[start], 0, size);
|
||||
}
|
||||
|
||||
static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
|
||||
{
|
||||
size_t size = sizeof(*map) + sizeof(map->map[0]) * nr;
|
||||
int start = map ? map->nr : 0;
|
||||
|
||||
return realloc(map, size);
|
||||
map = realloc(map, size);
|
||||
/*
|
||||
* We only realloc to add more items, let's reset new items.
|
||||
*/
|
||||
if (map)
|
||||
thread_map__reset(map, start, nr);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
#define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
|
||||
@@ -304,8 +321,12 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid,
|
||||
static void thread_map__delete(struct thread_map *threads)
|
||||
{
|
||||
if (threads) {
|
||||
int i;
|
||||
|
||||
WARN_ONCE(atomic_read(&threads->refcnt) != 0,
|
||||
"thread map refcnt unbalanced\n");
|
||||
for (i = 0; i < threads->nr; i++)
|
||||
free(thread_map__comm(threads, i));
|
||||
free(threads);
|
||||
}
|
||||
}
|
||||
@@ -333,3 +354,56 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
|
||||
|
||||
return printed + fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
static int get_comm(char **comm, pid_t pid)
|
||||
{
|
||||
char *path;
|
||||
size_t size;
|
||||
int err;
|
||||
|
||||
if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1)
|
||||
return -ENOMEM;
|
||||
|
||||
err = filename__read_str(path, comm, &size);
|
||||
if (!err) {
|
||||
/*
|
||||
* We're reading 16 bytes, while filename__read_str
|
||||
* allocates data per BUFSIZ bytes, so we can safely
|
||||
* mark the end of the string.
|
||||
*/
|
||||
(*comm)[size] = 0;
|
||||
rtrim(*comm);
|
||||
}
|
||||
|
||||
free(path);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void comm_init(struct thread_map *map, int i)
|
||||
{
|
||||
pid_t pid = thread_map__pid(map, i);
|
||||
char *comm = NULL;
|
||||
|
||||
/* dummy pid comm initialization */
|
||||
if (pid == -1) {
|
||||
map->map[i].comm = strdup("dummy");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The comm name is like extra bonus ;-),
|
||||
* so just warn if we fail for any reason.
|
||||
*/
|
||||
if (get_comm(&comm, pid))
|
||||
pr_warning("Couldn't resolve comm name for pid %d\n", pid);
|
||||
|
||||
map->map[i].comm = comm;
|
||||
}
|
||||
|
||||
void thread_map__read_comms(struct thread_map *threads)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < threads->nr; ++i)
|
||||
comm_init(threads, i);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
struct thread_map_data {
|
||||
pid_t pid;
|
||||
char *comm;
|
||||
};
|
||||
|
||||
struct thread_map {
|
||||
@@ -44,4 +45,11 @@ thread_map__set_pid(struct thread_map *map, int thread, pid_t pid)
|
||||
{
|
||||
map->map[thread].pid = pid;
|
||||
}
|
||||
|
||||
static inline char *thread_map__comm(struct thread_map *map, int thread)
|
||||
{
|
||||
return map->map[thread].comm;
|
||||
}
|
||||
|
||||
void thread_map__read_comms(struct thread_map *threads);
|
||||
#endif /* __PERF_THREAD_MAP_H */
|
||||
|
||||
Reference in New Issue
Block a user