Commit 2d6dac2f authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 6eedf416 36c8bb56
...@@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores. To enable this mod ...@@ -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 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. 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:: -D msecs::
--delay msecs:: --delay msecs::
After starting the program, wait msecs before measuring. This is useful to 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) ...@@ -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); 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) if (report.use_stdio)
use_browser = 0; use_browser = 0;
else if (report.use_tui) else if (report.use_tui)
......
This diff is collapsed.
...@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id) ...@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id)
return syscall__set_arg_fmts(sc); 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 * 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 * 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) ...@@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
err = -ENOMEM; err = -ENOMEM;
goto out_close; goto out_close;
} }
err = trace__validate_ev_qualifier(&trace);
if (err)
goto out_close;
} }
err = target__validate(&trace.opts.target); err = target__validate(&trace.opts.target);
......
...@@ -31,6 +31,7 @@ perf-y += code-reading.o ...@@ -31,6 +31,7 @@ perf-y += code-reading.o
perf-y += sample-parsing.o perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o perf-y += kmod-path.o
perf-y += thread-map.o
perf-$(CONFIG_X86) += perf-time-to-tsc.o perf-$(CONFIG_X86) += perf-time-to-tsc.o
......
...@@ -170,6 +170,10 @@ static struct test { ...@@ -170,6 +170,10 @@ static struct test {
.desc = "Test kmod_path__parse function", .desc = "Test kmod_path__parse function",
.func = test__kmod_path__parse, .func = test__kmod_path__parse,
}, },
{
.desc = "Test thread map",
.func = test__thread_map,
},
{ {
.func = NULL, .func = NULL,
}, },
......
...@@ -78,7 +78,7 @@ int test__openat_syscall_event_on_all_cpus(void) ...@@ -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, * we use the auto allocation it will allocate just for 1 cpu,
* as we start by cpu 0. * 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); pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
goto out_close_fd; goto out_close_fd;
} }
...@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void) ...@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void)
} }
expected = nr_openat_calls + cpu; 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", 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; err = -1;
} }
} }
......
...@@ -44,9 +44,9 @@ int test__openat_syscall_event(void) ...@@ -44,9 +44,9 @@ int test__openat_syscall_event(void)
goto out_close_fd; 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", 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; goto out_close_fd;
} }
......
...@@ -61,6 +61,7 @@ int test__switch_tracking(void); ...@@ -61,6 +61,7 @@ int test__switch_tracking(void);
int test__fdarray__filter(void); int test__fdarray__filter(void);
int test__fdarray__add(void); int test__fdarray__add(void);
int test__kmod_path__parse(void); int test__kmod_path__parse(void);
int test__thread_map(void);
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT #ifdef HAVE_DWARF_UNWIND_SUPPORT
......
#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, ...@@ -289,5 +289,4 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
void perf_evlist__set_tracking_event(struct perf_evlist *evlist, void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
struct perf_evsel *tracking_evsel); struct perf_evsel *tracking_evsel);
#endif /* __PERF_EVLIST_H */ #endif /* __PERF_EVLIST_H */
...@@ -898,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel) ...@@ -898,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)
free(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 *count)
{ {
struct perf_counts_values tmp; struct perf_counts_values tmp;
...@@ -910,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, ...@@ -910,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
tmp = evsel->prev_raw_counts->aggr; tmp = evsel->prev_raw_counts->aggr;
evsel->prev_raw_counts->aggr = *count; evsel->prev_raw_counts->aggr = *count;
} else { } else {
tmp = evsel->prev_raw_counts->cpu[cpu]; tmp = *perf_counts(evsel->prev_raw_counts, cpu, thread);
evsel->prev_raw_counts->cpu[cpu] = *count; *perf_counts(evsel->prev_raw_counts, cpu, thread) = *count;
} }
count->val = count->val - tmp.val; count->val = count->val - tmp.val;
...@@ -939,20 +939,18 @@ void perf_counts_values__scale(struct perf_counts_values *count, ...@@ -939,20 +939,18 @@ void perf_counts_values__scale(struct perf_counts_values *count,
*pscaled = scaled; *pscaled = scaled;
} }
int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread, int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
perf_evsel__read_cb_t cb) 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) if (FD(evsel, cpu, thread) < 0)
return -EINVAL; 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 -errno;
return cb(evsel, cpu, thread, &count); return 0;
} }
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
...@@ -964,15 +962,15 @@ 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) if (FD(evsel, cpu, thread) < 0)
return -EINVAL; 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; return -ENOMEM;
if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
return -errno; return -errno;
perf_evsel__compute_deltas(evsel, cpu, &count); perf_evsel__compute_deltas(evsel, cpu, thread, &count);
perf_counts_values__scale(&count, scale, NULL); perf_counts_values__scale(&count, scale, NULL);
evsel->counts->cpu[cpu] = count; *perf_counts(evsel->counts, cpu, thread) = count;
return 0; return 0;
} }
......
...@@ -9,23 +9,7 @@ ...@@ -9,23 +9,7 @@
#include "xyarray.h" #include "xyarray.h"
#include "symbol.h" #include "symbol.h"
#include "cpumap.h" #include "cpumap.h"
#include "stat.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[];
};
struct perf_evsel; struct perf_evsel;
...@@ -128,7 +112,7 @@ static inline int perf_evsel__nr_cpus(struct perf_evsel *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, void perf_counts_values__scale(struct perf_counts_values *count,
bool scale, s8 *pscaled); 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); struct perf_counts_values *count);
int perf_evsel__object_config(size_t object_size, int perf_evsel__object_config(size_t object_size,
...@@ -245,12 +229,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1, ...@@ -245,12 +229,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
(a)->attr.type == (b)->attr.type && \ (a)->attr.type == (b)->attr.type && \
(a)->attr.config == (b)->attr.config) (a)->attr.config == (b)->attr.config)
typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel, int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
int cpu, int thread, struct perf_counts_values *count);
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_on_cpu(struct perf_evsel *evsel, int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
int cpu, int thread, bool scale); int cpu, int thread, bool scale);
......
...@@ -20,3 +20,4 @@ util/stat.c ...@@ -20,3 +20,4 @@ util/stat.c
util/strlist.c util/strlist.c
util/trace-event.c util/trace-event.c
../../lib/rbtree.c ../../lib/rbtree.c
util/string.c
#include <math.h> #include <math.h>
#include "stat.h" #include "stat.h"
#include "evlist.h"
#include "evsel.h" #include "evsel.h"
#include "thread_map.h"
void update_stats(struct stats *stats, u64 val) void update_stats(struct stats *stats, u64 val)
{ {
...@@ -95,33 +97,46 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) ...@@ -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) + struct perf_counts *counts = zalloc(sizeof(*counts));
ncpus * sizeof(struct perf_counts_values);
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) 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) + xyarray__reset(counts->values);
(ncpus * sizeof(struct perf_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; return evsel->counts != NULL ? 0 : -ENOMEM;
} }
...@@ -130,3 +145,96 @@ void perf_evsel__free_counts(struct perf_evsel *evsel) ...@@ -130,3 +145,96 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)
perf_counts__delete(evsel->counts); perf_counts__delete(evsel->counts);
evsel->counts = NULL; 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);
}
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <stdio.h> #include <stdio.h>
#include "xyarray.h"
struct stats struct stats
{ {
...@@ -29,8 +30,32 @@ enum aggr_mode { ...@@ -29,8 +30,32 @@ enum aggr_mode {
AGGR_GLOBAL, AGGR_GLOBAL,
AGGR_SOCKET, AGGR_SOCKET,
AGGR_CORE, 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); void update_stats(struct stats *stats, u64 val);
double avg_stats(struct stats *stats); double avg_stats(struct stats *stats);
double stddev_stats(struct stats *stats); double stddev_stats(struct stats *stats);
...@@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats) ...@@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats)
} }
struct perf_evsel; struct perf_evsel;
struct perf_evlist;
bool __perf_evsel_stat__is(struct perf_evsel *evsel, bool __perf_evsel_stat__is(struct perf_evsel *evsel,
enum perf_stat_evsel_id id); enum perf_stat_evsel_id id);
...@@ -62,10 +89,24 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, ...@@ -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, void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
double avg, int cpu, enum aggr_mode aggr); 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_counts__delete(struct perf_counts *counts);
void perf_evsel__reset_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 perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
void perf_evsel__free_counts(struct perf_evsel *evsel); 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 #endif
...@@ -1132,8 +1132,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map, ...@@ -1132,8 +1132,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
INIT_LIST_HEAD(&md.maps); INIT_LIST_HEAD(&md.maps);
fd = open(kcore_filename, O_RDONLY); 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; return -EINVAL;
}
/* Read new maps into temporary lists */ /* Read new maps into temporary lists */
err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
......
...@@ -8,9 +8,11 @@ ...@@ -8,9 +8,11 @@
#include <unistd.h> #include <unistd.h>
#include "strlist.h" #include "strlist.h"
#include <string.h> #include <string.h>
#include <api/fs/fs.h>
#include "asm/bug.h" #include "asm/bug.h"
#include "thread_map.h" #include "thread_map.h"
#include "util.h" #include "util.h"
#include "debug.h"
/* Skip "." and ".." directories */ /* Skip "." and ".." directories */
static int filter(const struct dirent *dir) static int filter(const struct dirent *dir)
...@@ -21,11 +23,26 @@ static int filter(const struct dirent *dir) ...@@ -21,11 +23,26 @@ static int filter(const struct dirent *dir)
return 1; 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) static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
{ {
size_t size = sizeof(*map) + sizeof(map->map[0]) * 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) #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, ...@@ -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) static void thread_map__delete(struct thread_map *threads)
{ {
if (threads) { if (threads) {
int i;
WARN_ONCE(atomic_read(&threads->refcnt) != 0, WARN_ONCE(atomic_read(&threads->refcnt) != 0,
"thread map refcnt unbalanced\n"); "thread map refcnt unbalanced\n");
for (i = 0; i < threads->nr; i++)
free(thread_map__comm(threads, i));
free(threads); free(threads);
} }
} }
...@@ -333,3 +354,56 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) ...@@ -333,3 +354,56 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
return printed + fprintf(fp, "\n"); 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 @@ ...@@ -7,6 +7,7 @@
struct thread_map_data { struct thread_map_data {
pid_t pid; pid_t pid;
char *comm;
}; };
struct thread_map { struct thread_map {
...@@ -44,4 +45,11 @@ thread_map__set_pid(struct thread_map *map, int thread, pid_t pid) ...@@ -44,4 +45,11 @@ thread_map__set_pid(struct thread_map *map, int thread, pid_t pid)
{ {
map->map[thread].pid = 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 */ #endif /* __PERF_THREAD_MAP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment