summaryrefslogtreecommitdiff
path: root/tools/perf/ui/browsers/scripts.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.com>2025-03-26 13:42:07 +0100
committerJiri Kosina <jkosina@suse.com>2025-03-26 13:42:07 +0100
commitb3cc7428a32202936904b5b07cf9f135025bafd6 (patch)
treed4a1a6180ac5939fccd92acd6f8d7d1388575c4a /tools/perf/ui/browsers/scripts.c
parentdb52926fb0be40e1d588a346df73f5ea3a34a4c6 (diff)
parent01601fdd40ecf4467c8ae4d215dbb7d2a0599a2c (diff)
Merge branch 'for-6.15/amd_sfh' into for-linus
From: Mario Limonciello <mario.limonciello@amd.com> Some platforms include a human presence detection (HPD) sensor. When enabled and a user is detected a wake event will be emitted from the sensor fusion hub that software can react to. Example use cases are "wake from suspend on approach" or to "lock when leaving". This is currently enabled by default on supported systems, but users can't control it. This essentially means that wake on approach is enabled which is a really surprising behavior to users that don't expect it. Instead of defaulting to enabled add a sysfs knob that users can use to enable the feature if desirable and set it to disabled by default.
Diffstat (limited to 'tools/perf/ui/browsers/scripts.c')
-rw-r--r--tools/perf/ui/browsers/scripts.c177
1 files changed, 175 insertions, 2 deletions
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index e437d7889de62..2d04ece833aaf 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.