summaryrefslogtreecommitdiff
path: root/tools/perf/ui
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/ui')
-rw-r--r--tools/perf/ui/browsers/annotate.c2
-rw-r--r--tools/perf/ui/browsers/scripts.c177
-rw-r--r--tools/perf/ui/gtk/annotate.c16
-rw-r--r--tools/perf/ui/hist.c2
4 files changed, 186 insertions, 11 deletions
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index d7e727345dab..135d6ce88fb3 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -754,7 +754,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
hbt->timer(hbt->arg);
if (delay_secs != 0) {
- symbol__annotate_decay_histogram(sym, evsel->core.idx);
+ symbol__annotate_decay_histogram(sym, evsel);
hists__scnprintf_title(hists, title, sizeof(title));
annotate_browser__show(&browser->b, title, help);
}
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index e437d7889de6..2d04ece833aa 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -1,16 +1,18 @@
// SPDX-License-Identifier: GPL-2.0
-#include "../../builtin.h"
-#include "../../perf.h"
#include "../../util/util.h" // perf_exe()
#include "../util.h"
+#include "../../util/evlist.h"
#include "../../util/hist.h"
#include "../../util/debug.h"
+#include "../../util/session.h"
#include "../../util/symbol.h"
#include "../browser.h"
#include "../libslang.h"
#include "config.h"
+#include <linux/err.h>
#include <linux/string.h>
#include <linux/zalloc.h>
+#include <subcmd/exec-cmd.h>
#include <stdlib.h>
#define SCRIPT_NAMELEN 128
@@ -78,6 +80,177 @@ static int scripts_config(const char *var, const char *value, void *data)
}
/*
+ * Some scripts specify the required events in their "xxx-record" file,
+ * this function will check if the events in perf.data match those
+ * mentioned in the "xxx-record".
+ *
+ * Fixme: All existing "xxx-record" are all in good formats "-e event ",
+ * which is covered well now. And new parsing code should be added to
+ * cover the future complex formats like event groups etc.
+ */
+static int check_ev_match(int dir_fd, const char *scriptname, struct perf_session *session)
+{
+ char line[BUFSIZ];
+ FILE *fp;
+
+ {
+ char filename[FILENAME_MAX + 5];
+ int fd;
+
+ scnprintf(filename, sizeof(filename), "bin/%s-record", scriptname);
+ fd = openat(dir_fd, filename, O_RDONLY);
+ if (fd == -1)
+ return -1;
+ fp = fdopen(fd, "r");
+ if (!fp)
+ return -1;
+ }
+
+ while (fgets(line, sizeof(line), fp)) {
+ char *p = skip_spaces(line);
+
+ if (*p == '#')
+ continue;
+
+ while (strlen(p)) {
+ int match, len;
+ struct evsel *pos;
+ char evname[128];
+
+ p = strstr(p, "-e");
+ if (!p)
+ break;
+
+ p += 2;
+ p = skip_spaces(p);
+ len = strcspn(p, " \t");
+ if (!len)
+ break;
+
+ snprintf(evname, len + 1, "%s", p);
+
+ match = 0;
+ evlist__for_each_entry(session->evlist, pos) {
+ if (evsel__name_is(pos, evname)) {
+ match = 1;
+ break;
+ }
+ }
+
+ if (!match) {
+ fclose(fp);
+ return -1;
+ }
+ }
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+/*
+ * Return -1 if none is found, otherwise the actual scripts number.
+ *
+ * Currently the only user of this function is the script browser, which
+ * will list all statically runnable scripts, select one, execute it and
+ * show the output in a perf browser.
+ */
+static int find_scripts(char **scripts_array, char **scripts_path_array, int num,
+ int pathlen)
+{
+ struct dirent *script_dirent, *lang_dirent;
+ int scripts_dir_fd, lang_dir_fd;
+ DIR *scripts_dir, *lang_dir;
+ struct perf_session *session;
+ struct perf_data data = {
+ .path = input_name,
+ .mode = PERF_DATA_MODE_READ,
+ };
+ char *temp;
+ int i = 0;
+ const char *exec_path = get_argv_exec_path();
+
+ session = perf_session__new(&data, NULL);
+ if (IS_ERR(session))
+ return PTR_ERR(session);
+
+ {
+ char scripts_path[PATH_MAX];
+
+ snprintf(scripts_path, sizeof(scripts_path), "%s/scripts", exec_path);
+ scripts_dir_fd = open(scripts_path, O_DIRECTORY);
+ pr_err("Failed to open directory '%s'", scripts_path);
+ if (scripts_dir_fd == -1) {
+ perf_session__delete(session);
+ return -1;
+ }
+ }
+ scripts_dir = fdopendir(scripts_dir_fd);
+ if (!scripts_dir) {
+ close(scripts_dir_fd);
+ perf_session__delete(session);
+ return -1;
+ }
+
+ while ((lang_dirent = readdir(scripts_dir)) != NULL) {
+ if (lang_dirent->d_type != DT_DIR &&
+ (lang_dirent->d_type == DT_UNKNOWN &&
+ !is_directory_at(scripts_dir_fd, lang_dirent->d_name)))
+ continue;
+ if (!strcmp(lang_dirent->d_name, ".") || !strcmp(lang_dirent->d_name, ".."))
+ continue;
+
+#ifndef HAVE_LIBPERL_SUPPORT
+ if (strstr(lang_dirent->d_name, "perl"))
+ continue;
+#endif
+#ifndef HAVE_LIBPYTHON_SUPPORT
+ if (strstr(lang_dirent->d_name, "python"))
+ continue;
+#endif
+
+ lang_dir_fd = openat(scripts_dir_fd, lang_dirent->d_name, O_DIRECTORY);
+ if (lang_dir_fd == -1)
+ continue;
+ lang_dir = fdopendir(lang_dir_fd);
+ if (!lang_dir) {
+ close(lang_dir_fd);
+ continue;
+ }
+ while ((script_dirent = readdir(lang_dir)) != NULL) {
+ if (script_dirent->d_type == DT_DIR)
+ continue;
+ if (script_dirent->d_type == DT_UNKNOWN &&
+ is_directory_at(lang_dir_fd, script_dirent->d_name))
+ continue;
+ /* Skip those real time scripts: xxxtop.p[yl] */
+ if (strstr(script_dirent->d_name, "top."))
+ continue;
+ if (i >= num)
+ break;
+ scnprintf(scripts_path_array[i], pathlen, "%s/scripts/%s/%s",
+ exec_path,
+ lang_dirent->d_name,
+ script_dirent->d_name);
+ temp = strchr(script_dirent->d_name, '.');
+ snprintf(scripts_array[i],
+ (temp - script_dirent->d_name) + 1,
+ "%s", script_dirent->d_name);
+
+ if (check_ev_match(lang_dir_fd, scripts_array[i], session))
+ continue;
+
+ i++;
+ }
+ closedir(lang_dir);
+ }
+
+ closedir(scripts_dir);
+ perf_session__delete(session);
+ return i;
+}
+
+/*
* When success, will copy the full path of the selected script
* into the buffer pointed by script_name, and return 0.
* Return -1 on failure.
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
index 6da24aa039eb..8920e298420a 100644
--- a/tools/perf/ui/gtk/annotate.c
+++ b/tools/perf/ui/gtk/annotate.c
@@ -3,6 +3,7 @@
#include "util/sort.h"
#include "util/debug.h"
#include "util/annotate.h"
+#include "util/evlist.h"
#include "util/evsel.h"
#include "util/map.h"
#include "util/dso.h"
@@ -26,7 +27,7 @@ static const char *const col_names[] = {
};
static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
- struct disasm_line *dl, int evidx)
+ struct disasm_line *dl, const struct evsel *evsel)
{
struct annotation *notes;
struct sym_hist *symhist;
@@ -42,8 +43,8 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
return 0;
notes = symbol__annotation(sym);
- symhist = annotation__histogram(notes, evidx);
- entry = annotated_source__hist_entry(notes->src, evidx, dl->al.offset);
+ symhist = annotation__histogram(notes, evsel);
+ entry = annotated_source__hist_entry(notes->src, evsel, dl->al.offset);
if (entry)
nr_samples = entry->nr_samples;
@@ -139,16 +140,17 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct map_symbol *ms,
gtk_list_store_append(store, &iter);
if (evsel__is_group_event(evsel)) {
- for (i = 0; i < evsel->core.nr_members; i++) {
+ struct evsel *cur_evsel;
+
+ for_each_group_evsel(cur_evsel, evsel__leader(evsel)) {
ret += perf_gtk__get_percent(s + ret,
sizeof(s) - ret,
sym, pos,
- evsel->core.idx + i);
+ cur_evsel);
ret += scnprintf(s + ret, sizeof(s) - ret, " ");
}
} else {
- ret = perf_gtk__get_percent(s, sizeof(s), sym, pos,
- evsel->core.idx);
+ ret = perf_gtk__get_percent(s, sizeof(s), sym, pos, evsel);
}
if (ret)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index e5491995adf0..34fda1d5eccb 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -121,7 +121,7 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
const char *fmtstr, hpp_snprint_fn print_fn,
enum perf_hpp_fmt_type fmtype)
{
- int len = fmt->user_len ?: fmt->len;
+ int len = max(fmt->user_len ?: fmt->len, (int)strlen(fmt->name));
if (symbol_conf.field_sep) {
return __hpp__fmt(hpp, he, get_field, fmtstr, 1,