[RFC PATCH v3 27/37] perf tools: Add new 'perf bpf' command

Wang Nan
2015-05-17T11:01:27Z

Adding new 'perf bpf' command to provide eBPF program management
operations. This patch only creates basic 'perf bpf'. Subcommands will
be introduced in following patches.

To utilize existing code of usage_with_options() while enable
subcommand list get output after 'Usage ...' indicator, this patch
add a usage_with_options_noexit() function, which does similar thing
except exiting, allows caller print more information before quit.

In this patch, 'perf bpf' command won't be built if doesn't find
libelf.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
tools/perf/Build | 1 +
tools/perf/Documentation/perf-bpf.txt | 18 ++++++++
tools/perf/builtin-bpf.c | 85 +++++++++++++++++++++++++++++++++++
tools/perf/builtin.h | 1 +
tools/perf/command-list.txt | 1 +
tools/perf/perf.c | 3 ++
tools/perf/util/parse-options.c | 8 +++-
tools/perf/util/parse-options.h | 2 +
8 files changed, 118 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/Documentation/perf-bpf.txt
create mode 100644 tools/perf/builtin-bpf.c

diff --git a/tools/perf/Build b/tools/perf/Build
index b77370e..c3c6cc3 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -19,6 +19,7 @@ perf-y += builtin-kvm.o
perf-y += builtin-inject.o
perf-y += builtin-mem.o
perf-y += builtin-data.o
+perf-$(CONFIG_LIBELF) += builtin-bpf.o

perf-$(CONFIG_AUDIT) += builtin-trace.o
perf-$(CONFIG_LIBELF) += builtin-probe.o
diff --git a/tools/perf/Documentation/perf-bpf.txt b/tools/perf/Documentation/perf-bpf.txt
new file mode 100644
index 0000000..0e8b590
--- /dev/null
+++ b/tools/perf/Documentation/perf-bpf.txt
@@ -0,0 +1,18 @@
+perf-bpf(1)
+==============
+
+NAME
+----
+perf-bpf - Management of eBPF programs.
+
+SYNOPSIS
+--------
+[verse]
+'perf bpf' [<common options>] <command> [<options>]",
+
+DESCRIPTION
+-----------
+Management of eBPF programs.
+
+OPTIONS
+-------
diff --git a/tools/perf/builtin-bpf.c b/tools/perf/builtin-bpf.c
new file mode 100644
index 0000000..a8858e2
--- /dev/null
+++ b/tools/perf/builtin-bpf.c
@@ -0,0 +1,85 @@
+/*
+ * builtin-bpf.c
+ *
+ * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015, Huawei Inc.
+ *
+ * Released under the GPL v2. (and only v2, not any later version)
+ *
+ * Builtin bpf command: management of bpf programs.
+ */
+#include "builtin.h"
+#include "perf.h"
+#include "debug.h"
+#include "parse-options.h"
+
+typedef int (*bpf_cmd_fn_t)(int argc, const char **argv, const char *prefix);
+
+struct bpf_cmd {
+ const char *name;
+ const char *summary;
+ bpf_cmd_fn_t fn;
+};
+
+static struct bpf_cmd bpf_cmds[];
+
+#define for_each_cmd(cmd) \
+ for (cmd = bpf_cmds; cmd && cmd->name; cmd++)
+
+struct option bpf_options[] = {
+ OPT_INCR('v', "verbose", &verbose, "be more verbose "
+ "(show debug information)"),
+ OPT_END()
+};
+
+static const char *bpf_usage[] = {
+ "perf bpf [<command options>] <command> [<options>]",
+ NULL
+};
+
+static void print_usage(void)
+{
+ struct bpf_cmd *cmd;
+
+ usage_with_options_noexit(bpf_usage, bpf_options);
+ printf("\tAvailable commands:\n");
+ for_each_cmd(cmd)
+ printf("\t %s\t- %s\n", cmd->name, cmd->summary);
+ exit(129);
+}
+
+static const char * const bpf_subcommands[] = { NULL };
+
+static struct bpf_cmd bpf_cmds[] = {
+ { .name = NULL, },
+};
+
+int cmd_bpf(int argc, const char **argv,
+ const char *prefix __maybe_unused)
+{
+ struct bpf_cmd *cmd;
+ const char *cmdstr;
+
+ /* No command specified. */
+ if (argc < 2)
+ goto usage;
+
+ argc = parse_options_subcommand(argc, argv, bpf_options, bpf_subcommands, bpf_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+ if (argc < 1)
+ goto usage;
+
+ cmdstr = argv[0];
+
+ for_each_cmd(cmd) {
+ if (strcmp(cmd->name, cmdstr))
+ continue;
+
+ return cmd->fn(argc, argv, prefix);
+ }
+
+ pr_err("Unknown command %s\n", cmdstr);
+usage:
+ print_usage();
+ return -1;
+}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 3688ad2..c2c4a0d 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -38,6 +38,7 @@ extern int cmd_trace(int argc, const char **argv, const char *prefix);
extern int cmd_inject(int argc, const char **argv, const char *prefix);
extern int cmd_mem(int argc, const char **argv, const char *prefix);
extern int cmd_data(int argc, const char **argv, const char *prefix);
+extern int cmd_bpf(int argc, const char **argv, const char *prefix);

extern int find_scripts(char **scripts_array, char **scripts_path_array);
#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00fcaf8..1000463 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -5,6 +5,7 @@
perf-annotate mainporcelain common
perf-archive mainporcelain common
perf-bench mainporcelain common
+perf-bpf mainporcelain full
perf-buildid-cache mainporcelain common
perf-buildid-list mainporcelain common
perf-data mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index b857fcb..eff1a55 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -64,6 +64,9 @@ static struct cmd_struct commands[] = {
{ "inject", cmd_inject, 0 },
{ "mem", cmd_mem, 0 },
{ "data", cmd_data, 0 },
+#ifdef HAVE_LIBELF_SUPPORT
+ { "bpf", cmd_bpf, 0 },
+#endif
};

struct pager_config {
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 01626be..09e48a2 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -672,9 +672,15 @@ int usage_with_options_internal(const char * const *usagestr,
void usage_with_options(const char * const *usagestr,
const struct option *opts)
{
+ usage_with_options_noexit(usagestr, opts);
+ exit(129);
+}
+
+void usage_with_options_noexit(const char * const *usagestr,
+ const struct option *opts)
+{
exit_browser(false);
usage_with_options_internal(usagestr, opts, 0);
- exit(129);
}

int parse_options_usage(const char * const *usagestr,
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 59561fd..41194db 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -156,6 +156,8 @@ extern int parse_options_subcommand(int argc, const char **argv,

extern NORETURN void usage_with_options(const char * const *usagestr,
const struct option *options);
+extern void usage_with_options_noexit(const char * const *usagestr,
+ const struct option *options);

/*----- incremantal advanced APIs -----*/

--
1.8.3.4