summaryrefslogtreecommitdiff
path: root/tools/perf/util/machine.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/machine.c')
-rw-r--r--tools/perf/util/machine.c183
1 files changed, 111 insertions, 72 deletions
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 27d5345d2b30..b5dd42588c91 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -20,6 +20,7 @@
#include "path.h"
#include "srcline.h"
#include "symbol.h"
+#include "synthetic-events.h"
#include "sort.h"
#include "strlist.h"
#include "target.h"
@@ -37,6 +38,7 @@
#include <internal/lib.h> // page_size
#include "cgroup.h"
#include "arm64-frame-pointer-unwind-support.h"
+#include <api/io_dir.h>
#include <linux/ctype.h>
#include <symbol/kallsyms.h>
@@ -94,6 +96,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->comm_exec = false;
machine->kernel_start = 0;
machine->vmlinux_map = NULL;
+ /* There is no initial context switch in, so we start at 1. */
+ machine->parallelism = 1;
machine->root_dir = strdup(root_dir);
if (machine->root_dir == NULL)
@@ -125,28 +129,62 @@ out:
return 0;
}
-struct machine *machine__new_host(void)
+static struct machine *__machine__new_host(struct perf_env *host_env, bool kernel_maps)
{
struct machine *machine = malloc(sizeof(*machine));
- if (machine != NULL) {
- machine__init(machine, "", HOST_KERNEL_ID);
+ if (!machine)
+ return NULL;
- if (machine__create_kernel_maps(machine) < 0)
- goto out_delete;
+ machine__init(machine, "", HOST_KERNEL_ID);
- machine->env = &perf_env;
+ if (kernel_maps && machine__create_kernel_maps(machine) < 0) {
+ free(machine);
+ return NULL;
}
+ machine->env = host_env;
+ return machine;
+}
+struct machine *machine__new_host(struct perf_env *host_env)
+{
+ return __machine__new_host(host_env, /*kernel_maps=*/true);
+}
+
+static int mmap_handler(const struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct machine *machine)
+{
+ return machine__process_mmap2_event(machine, event, sample);
+}
+
+static int machine__init_live(struct machine *machine, pid_t pid)
+{
+ union perf_event event;
+
+ memset(&event, 0, sizeof(event));
+ return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
+ mmap_handler, machine, true);
+}
+
+struct machine *machine__new_live(struct perf_env *host_env, bool kernel_maps, pid_t pid)
+{
+ struct machine *machine = __machine__new_host(host_env, kernel_maps);
+
+ if (!machine)
+ return NULL;
+
+ if (machine__init_live(machine, pid)) {
+ machine__delete(machine);
+ return NULL;
+ }
return machine;
-out_delete:
- free(machine);
- return NULL;
}
-struct machine *machine__new_kallsyms(void)
+struct machine *machine__new_kallsyms(struct perf_env *host_env)
{
- struct machine *machine = machine__new_host();
+ struct machine *machine = machine__new_host(host_env);
/*
* FIXME:
* 1) We should switch to machine__load_kallsyms(), i.e. not explicitly
@@ -677,8 +715,11 @@ int machine__process_aux_output_hw_id_event(struct machine *machine __maybe_unus
int machine__process_switch_event(struct machine *machine __maybe_unused,
union perf_event *event)
{
+ bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
+
if (dump_trace)
perf_event__fprintf_switch(event, stdout);
+ machine->parallelism += out ? -1 : 1;
return 0;
}
@@ -712,7 +753,7 @@ static int machine__process_ksymbol_register(struct machine *machine,
map__set_start(map, event->ksymbol.addr);
map__set_end(map, map__start(map) + event->ksymbol.len);
- err = maps__insert(machine__kernel_maps(machine), map);
+ err = maps__fixup_overlap_and_insert(machine__kernel_maps(machine), map);
if (err) {
err = -ENOMEM;
goto out;
@@ -773,6 +814,10 @@ int machine__process_ksymbol(struct machine *machine __maybe_unused,
if (dump_trace)
perf_event__fprintf_ksymbol(event, stdout);
+ /* no need to process non-JIT BPF as it cannot get samples */
+ if (event->ksymbol.len == 0)
+ return 0;
+
if (event->ksymbol.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER)
return machine__process_ksymbol_unregister(machine, event,
sample);
@@ -886,26 +931,6 @@ size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
return ret;
}
-size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
-{
- int i;
- size_t printed = 0;
- struct dso *kdso = machine__kernel_dso(machine);
-
- if (dso__has_build_id(kdso)) {
- char filename[PATH_MAX];
-
- if (dso__build_id_filename(kdso, filename, sizeof(filename), false))
- printed += fprintf(fp, "[0] %s\n", filename);
- }
-
- for (i = 0; i < vmlinux_path__nr_entries; ++i) {
- printed += fprintf(fp, "[%d] %s\n", i + dso__has_build_id(kdso),
- vmlinux_path[i]);
- }
- return printed;
-}
-
struct machine_fprintf_cb_args {
FILE *fp;
size_t printed;
@@ -1003,7 +1028,7 @@ static int machine__get_running_kernel_start(struct machine *machine,
err = kallsyms__get_symbol_start(filename, "_edata", &addr);
if (err)
- err = kallsyms__get_function_start(filename, "_etext", &addr);
+ err = kallsyms__get_symbol_start(filename, "_etext", &addr);
if (!err)
*end = addr;
@@ -1352,27 +1377,24 @@ static int maps__set_module_path(struct maps *maps, const char *path, struct kmo
return 0;
}
-static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, int depth)
+static int maps__set_modules_path_dir(struct maps *maps, char *path, size_t path_size, int depth)
{
- struct dirent *dent;
- DIR *dir = opendir(dir_name);
+ struct io_dirent64 *dent;
+ struct io_dir iod;
+ size_t root_len = strlen(path);
int ret = 0;
- if (!dir) {
- pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
+ io_dir__init(&iod, open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY));
+ if (iod.dirfd < 0) {
+ pr_debug("%s: cannot open %s dir\n", __func__, path);
return -1;
}
-
- while ((dent = readdir(dir)) != NULL) {
- char path[PATH_MAX];
- struct stat st;
-
- /*sshfs might return bad dent->d_type, so we have to stat*/
- path__join(path, sizeof(path), dir_name, dent->d_name);
- if (stat(path, &st))
- continue;
-
- if (S_ISDIR(st.st_mode)) {
+ /* Bounds check, should never happen. */
+ if (root_len >= path_size)
+ return -1;
+ path[root_len++] = '/';
+ while ((dent = io_dir__readdir(&iod)) != NULL) {
+ if (io_dir__is_dir(&iod, dent)) {
if (!strcmp(dent->d_name, ".") ||
!strcmp(dent->d_name, ".."))
continue;
@@ -1384,7 +1406,12 @@ static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, i
continue;
}
- ret = maps__set_modules_path_dir(maps, path, depth + 1);
+ /* Bounds check, should never happen. */
+ if (root_len + strlen(dent->d_name) >= path_size)
+ continue;
+
+ strcpy(path + root_len, dent->d_name);
+ ret = maps__set_modules_path_dir(maps, path, path_size, depth + 1);
if (ret < 0)
goto out;
} else {
@@ -1394,9 +1421,14 @@ static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, i
if (ret)
goto out;
- if (m.kmod)
- ret = maps__set_module_path(maps, path, &m);
+ if (m.kmod) {
+ /* Bounds check, should never happen. */
+ if (root_len + strlen(dent->d_name) < path_size) {
+ strcpy(path + root_len, dent->d_name);
+ ret = maps__set_module_path(maps, path, &m);
+ }
+ }
zfree(&m.name);
if (ret)
@@ -1405,7 +1437,7 @@ static int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, i
}
out:
- closedir(dir);
+ close(iod.dirfd);
return ret;
}
@@ -1422,7 +1454,8 @@ static int machine__set_modules_path(struct machine *machine)
machine->root_dir, version);
free(version);
- return maps__set_modules_path_dir(machine__kernel_maps(machine), modules_path, 0);
+ return maps__set_modules_path_dir(machine__kernel_maps(machine),
+ modules_path, sizeof(modules_path), 0);
}
int __weak arch__fix_module_text_start(u64 *start __maybe_unused,
u64 *size __maybe_unused,
@@ -1561,6 +1594,8 @@ int machine__create_kernel_maps(struct machine *machine)
}
}
+ maps__fixup_end(machine__kernel_maps(machine));
+
out_put:
dso__put(kernel);
return ret;
@@ -1696,21 +1731,21 @@ int machine__process_mmap2_event(struct machine *machine,
{
struct thread *thread;
struct map *map;
- struct dso_id dso_id = {
- .maj = event->mmap2.maj,
- .min = event->mmap2.min,
- .ino = event->mmap2.ino,
- .ino_generation = event->mmap2.ino_generation,
- };
- struct build_id __bid, *bid = NULL;
+ struct dso_id dso_id = dso_id_empty;
int ret = 0;
if (dump_trace)
perf_event__fprintf_mmap2(event, stdout);
if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
- bid = &__bid;
- build_id__init(bid, event->mmap2.build_id, event->mmap2.build_id_size);
+ build_id__init(&dso_id.build_id, event->mmap2.build_id, event->mmap2.build_id_size);
+ } else {
+ dso_id.maj = event->mmap2.maj;
+ dso_id.min = event->mmap2.min;
+ dso_id.ino = event->mmap2.ino;
+ dso_id.ino_generation = event->mmap2.ino_generation;
+ dso_id.mmap2_valid = true;
+ dso_id.mmap2_ino_generation_valid = true;
}
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
@@ -1722,7 +1757,7 @@ int machine__process_mmap2_event(struct machine *machine,
};
strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN);
- ret = machine__process_kernel_mmap_event(machine, &xm, bid);
+ ret = machine__process_kernel_mmap_event(machine, &xm, &dso_id.build_id);
if (ret < 0)
goto out_problem;
return 0;
@@ -1736,7 +1771,7 @@ int machine__process_mmap2_event(struct machine *machine,
map = map__new(machine, event->mmap2.start,
event->mmap2.len, event->mmap2.pgoff,
&dso_id, event->mmap2.prot,
- event->mmap2.flags, bid,
+ event->mmap2.flags,
event->mmap2.filename, thread);
if (map == NULL)
@@ -1794,8 +1829,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
prot = PROT_EXEC;
map = map__new(machine, event->mmap.start,
- event->mmap.len, event->mmap.pgoff,
- NULL, prot, 0, NULL, event->mmap.filename, thread);
+ event->mmap.len, event->mmap.pgoff,
+ &dso_id_empty, prot, /*flags=*/0, event->mmap.filename, thread);
if (map == NULL)
goto out_problem_map;
@@ -1898,6 +1933,8 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event
if (dump_trace)
perf_event__fprintf_task(event, stdout);
+ /* There is no context switch out before exit, so we decrement here. */
+ machine->parallelism--;
if (thread != NULL) {
if (symbol_conf.keep_exited_threads)
thread__set_exited(thread, /*exited=*/true);
@@ -1974,7 +2011,7 @@ static void ip__resolve_ams(struct thread *thread,
* Thus, we have to try consecutively until we find a match
* or else, the symbol is unknown
*/
- thread__find_cpumode_addr_location(thread, ip, &al);
+ thread__find_cpumode_addr_location(thread, ip, /*symbols=*/true, &al);
ams->addr = ip;
ams->al_addr = al.addr;
@@ -2076,7 +2113,7 @@ static int add_callchain_ip(struct thread *thread,
al.sym = NULL;
al.srcline = NULL;
if (!cpumode) {
- thread__find_cpumode_addr_location(thread, ip, &al);
+ thread__find_cpumode_addr_location(thread, ip, symbols, &al);
} else {
if (ip >= PERF_CONTEXT_MAX) {
switch (ip) {
@@ -2104,6 +2141,8 @@ static int add_callchain_ip(struct thread *thread,
}
if (symbols)
thread__find_symbol(thread, *cpumode, ip, &al);
+ else
+ thread__find_map(thread, *cpumode, ip, &al);
}
if (al.sym != NULL) {
@@ -2927,8 +2966,8 @@ static int thread__resolve_callchain_unwind(struct thread *thread,
return 0;
/* Bail out if nothing was captured. */
- if ((!sample->user_regs.regs) ||
- (!sample->user_stack.size))
+ if (!sample->user_regs || !sample->user_regs->regs ||
+ !sample->user_stack.size)
return 0;
if (!symbols)
@@ -3153,7 +3192,7 @@ struct dso *machine__findnew_dso_id(struct machine *machine, const char *filenam
struct dso *machine__findnew_dso(struct machine *machine, const char *filename)
{
- return machine__findnew_dso_id(machine, filename, NULL);
+ return machine__findnew_dso_id(machine, filename, &dso_id_empty);
}
char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)