mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-02 15:21:03 +00:00
perf/core improvements
User visible: - Add record.build-id config option to 'perf record', to allow configuring in the ~/.perfconfig file if and how build-ids should be processed, allowing a permanent setting for options such as -B and -N: (Namhyung Kim) $ perf record -h -B -N Usage: perf record [<options>] [<command>] or: perf record [<options>] -- <command> [<options>] -B, --no-buildid do not collect buildids in perf.data -N, --no-buildid-cache do not update the buildid cache $ Infrastructure: - Move code for options parsing and subcommand handling from tools/perf/ to tools/lib/subcmd/, so that it can be used by other tools/ living utilities (Josh Poimboeuf) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWcvFJAAoJENZQFvNTUqpAT5oP/A4JbkS+f80WdAztcIm2MC15 25TXdRLvcD3/oVXNLbieQitZ4pA8oEvCj/GYHr/p8DUYTaVj0Dmo5M5qFoJQP1GZ b9IW1dsbh5PqnuiKFnk2Fak6aCTv+D4dNTXz4jjKvwtjgSiyIC7IaJkvq0HMfeqZ bAoXzxKj79/QXEAoHZu6kkCyc9p7yhVp96zIqShF7ZVeZNu071nMIPA/5SNNxsoZ +IrHdGgwT1VfnFGf4Gcnjn3AwraBBt0xT0VTDMlVsGWExE5wjzX22FUz2UovU2Nc wmv8EHH0AXIs7oAj7AkUP6cMkHdW22BmbUg1ubDYLbXVmKfHvUCQ7cY4Ep2FXBP5 agI5H40RXs/NdyqLgI+nX33ilaTIe8DWX1Ce4ODkp25XlPPNyA/HVBUOFcZVQZ+c Z8t/KRRjPz87EQH2JzFm2S2cvb7dYfoOPJdCthH1vYyheIFNKRa5pl1xMLam0x2a +CfcPqHoCWjCHsURjbuKOcBsOLO3fT5M9/kLIviMYeG54WoKhA+edjxSGWc6JnNA ISPDdXNGTvjnf13Ec0s3GITpXbvp8xLt5l6DQpbijmh2xvLxqep/rLC2kjnhhHfP mosJnjTYcmtqBgpSxS2Nsib5AmVcLF4uwNYUt8kXzAWXLNJdYu1RlVaPunQ5jM0n l3ioc2QNPkB/3BRA3iIc =d45C -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-2.1' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements from Arnaldo Carvalho de Melo: User visible changes: - Add record.build-id config option to 'perf record', to allow configuring in the ~/.perfconfig file if and how build-ids should be processed, allowing a permanent setting for options such as -B and -N: (Namhyung Kim) $ perf record -h -B -N Usage: perf record [<options>] [<command>] or: perf record [<options>] -- <command> [<options>] -B, --no-buildid do not collect buildids in perf.data -N, --no-buildid-cache do not update the buildid cache $ Infrastructure changes: - Move code for options parsing and subcommand handling from tools/perf/ to tools/lib/subcmd/, so that it can be used by other tools/ living utilities (Josh Poimboeuf) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
b21daaede1
@ -7,7 +7,7 @@ endif
|
||||
|
||||
feature_check = $(eval $(feature_check_code))
|
||||
define feature_check_code
|
||||
feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
|
||||
endef
|
||||
|
||||
feature_set = $(eval $(feature_set_code))
|
||||
@ -101,7 +101,6 @@ ifeq ($(feature-all), 1)
|
||||
#
|
||||
$(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
|
||||
else
|
||||
$(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C $(feature_dir) $(addsuffix .bin,$(FEATURE_TESTS)) >/dev/null 2>&1)
|
||||
$(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
|
||||
endif
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
FILES= \
|
||||
test-all.bin \
|
||||
test-backtrace.bin \
|
||||
@ -38,38 +37,40 @@ FILES= \
|
||||
test-bpf.bin \
|
||||
test-get_cpuid.bin
|
||||
|
||||
FILES := $(addprefix $(OUTPUT),$(FILES))
|
||||
|
||||
CC := $(CROSS_COMPILE)gcc -MD
|
||||
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
|
||||
|
||||
all: $(FILES)
|
||||
|
||||
__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
|
||||
BUILD = $(__BUILD) > $(OUTPUT)$(@:.bin=.make.output) 2>&1
|
||||
__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
|
||||
BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
|
||||
|
||||
###############################
|
||||
|
||||
test-all.bin:
|
||||
$(OUTPUT)test-all.bin:
|
||||
$(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma
|
||||
|
||||
test-hello.bin:
|
||||
$(OUTPUT)test-hello.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-pthread-attr-setaffinity-np.bin:
|
||||
$(OUTPUT)test-pthread-attr-setaffinity-np.bin:
|
||||
$(BUILD) -D_GNU_SOURCE -lpthread
|
||||
|
||||
test-stackprotector-all.bin:
|
||||
$(OUTPUT)test-stackprotector-all.bin:
|
||||
$(BUILD) -fstack-protector-all
|
||||
|
||||
test-fortify-source.bin:
|
||||
$(OUTPUT)test-fortify-source.bin:
|
||||
$(BUILD) -O2 -D_FORTIFY_SOURCE=2
|
||||
|
||||
test-bionic.bin:
|
||||
$(OUTPUT)test-bionic.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-libelf.bin:
|
||||
$(OUTPUT)test-libelf.bin:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-glibc.bin:
|
||||
$(OUTPUT)test-glibc.bin:
|
||||
$(BUILD)
|
||||
|
||||
DWARFLIBS := -ldw
|
||||
@ -77,37 +78,37 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
|
||||
DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
|
||||
endif
|
||||
|
||||
test-dwarf.bin:
|
||||
$(OUTPUT)test-dwarf.bin:
|
||||
$(BUILD) $(DWARFLIBS)
|
||||
|
||||
test-libelf-mmap.bin:
|
||||
$(OUTPUT)test-libelf-mmap.bin:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libelf-getphdrnum.bin:
|
||||
$(OUTPUT)test-libelf-getphdrnum.bin:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libnuma.bin:
|
||||
$(OUTPUT)test-libnuma.bin:
|
||||
$(BUILD) -lnuma
|
||||
|
||||
test-numa_num_possible_cpus.bin:
|
||||
$(OUTPUT)test-numa_num_possible_cpus.bin:
|
||||
$(BUILD) -lnuma
|
||||
|
||||
test-libunwind.bin:
|
||||
$(OUTPUT)test-libunwind.bin:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libunwind-debug-frame.bin:
|
||||
$(OUTPUT)test-libunwind-debug-frame.bin:
|
||||
$(BUILD) -lelf
|
||||
|
||||
test-libaudit.bin:
|
||||
$(OUTPUT)test-libaudit.bin:
|
||||
$(BUILD) -laudit
|
||||
|
||||
test-libslang.bin:
|
||||
$(OUTPUT)test-libslang.bin:
|
||||
$(BUILD) -I/usr/include/slang -lslang
|
||||
|
||||
test-gtk2.bin:
|
||||
$(OUTPUT)test-gtk2.bin:
|
||||
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
|
||||
|
||||
test-gtk2-infobar.bin:
|
||||
$(OUTPUT)test-gtk2-infobar.bin:
|
||||
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
|
||||
|
||||
grep-libs = $(filter -l%,$(1))
|
||||
@ -119,63 +120,63 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
|
||||
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
|
||||
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
|
||||
|
||||
test-libperl.bin:
|
||||
$(OUTPUT)test-libperl.bin:
|
||||
$(BUILD) $(FLAGS_PERL_EMBED)
|
||||
|
||||
test-libpython.bin:
|
||||
$(OUTPUT)test-libpython.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-libpython-version.bin:
|
||||
$(OUTPUT)test-libpython-version.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-libbfd.bin:
|
||||
$(OUTPUT)test-libbfd.bin:
|
||||
$(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
|
||||
|
||||
test-liberty.bin:
|
||||
$(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
|
||||
$(OUTPUT)test-liberty.bin:
|
||||
$(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
|
||||
|
||||
test-liberty-z.bin:
|
||||
$(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
|
||||
$(OUTPUT)test-liberty-z.bin:
|
||||
$(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
|
||||
|
||||
test-cplus-demangle.bin:
|
||||
$(OUTPUT)test-cplus-demangle.bin:
|
||||
$(BUILD) -liberty
|
||||
|
||||
test-backtrace.bin:
|
||||
$(OUTPUT)test-backtrace.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-timerfd.bin:
|
||||
$(OUTPUT)test-timerfd.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-libdw-dwarf-unwind.bin:
|
||||
$(OUTPUT)test-libdw-dwarf-unwind.bin:
|
||||
$(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind)
|
||||
|
||||
test-libbabeltrace.bin:
|
||||
$(OUTPUT)test-libbabeltrace.bin:
|
||||
$(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)
|
||||
|
||||
test-sync-compare-and-swap.bin:
|
||||
$(OUTPUT)test-sync-compare-and-swap.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-compile-32.bin:
|
||||
$(CC) -m32 -o $(OUTPUT)$@ test-compile.c
|
||||
$(OUTPUT)test-compile-32.bin:
|
||||
$(CC) -m32 -o $@ test-compile.c
|
||||
|
||||
test-compile-x32.bin:
|
||||
$(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
|
||||
$(OUTPUT)test-compile-x32.bin:
|
||||
$(CC) -mx32 -o $@ test-compile.c
|
||||
|
||||
test-zlib.bin:
|
||||
$(OUTPUT)test-zlib.bin:
|
||||
$(BUILD) -lz
|
||||
|
||||
test-lzma.bin:
|
||||
$(OUTPUT)test-lzma.bin:
|
||||
$(BUILD) -llzma
|
||||
|
||||
test-get_cpuid.bin:
|
||||
$(OUTPUT)test-get_cpuid.bin:
|
||||
$(BUILD)
|
||||
|
||||
test-bpf.bin:
|
||||
$(OUTPUT)test-bpf.bin:
|
||||
$(BUILD)
|
||||
|
||||
-include *.d
|
||||
-include $(OUTPUT)*.d
|
||||
|
||||
###############################
|
||||
|
||||
clean:
|
||||
rm -f $(FILES) *.d $(FILES:.bin=.make.output)
|
||||
rm -f $(FILES) $(OUTPUT)*.d $(FILES:.bin=.make.output)
|
||||
|
@ -8,4 +8,8 @@ void *memdup(const void *src, size_t len);
|
||||
|
||||
int strtobool(const char *s, bool *res);
|
||||
|
||||
#ifndef __UCLIBC__
|
||||
extern size_t strlcpy(char *dest, const char *src, size_t size);
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_STRING_H_ */
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/**
|
||||
* memdup - duplicate region of memory
|
||||
@ -60,3 +61,29 @@ int strtobool(const char *s, bool *res)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* strlcpy - Copy a C-string into a sized buffer
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
* @size: size of destination buffer
|
||||
*
|
||||
* Compatible with *BSD: the result is always a valid
|
||||
* NUL-terminated string that fits in the buffer (unless,
|
||||
* of course, the buffer size is zero). It does not pad
|
||||
* out the result like strncpy() does.
|
||||
*
|
||||
* If libc has strlcpy() then that version will override this
|
||||
* implementation:
|
||||
*/
|
||||
size_t __weak strlcpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
size_t ret = strlen(src);
|
||||
|
||||
if (size) {
|
||||
size_t len = (ret >= size) ? size - 1 : ret;
|
||||
memcpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
7
tools/lib/subcmd/Build
Normal file
7
tools/lib/subcmd/Build
Normal file
@ -0,0 +1,7 @@
|
||||
libsubcmd-y += exec-cmd.o
|
||||
libsubcmd-y += help.o
|
||||
libsubcmd-y += pager.o
|
||||
libsubcmd-y += parse-options.o
|
||||
libsubcmd-y += run-command.o
|
||||
libsubcmd-y += sigchain.o
|
||||
libsubcmd-y += subcmd-config.o
|
48
tools/lib/subcmd/Makefile
Normal file
48
tools/lib/subcmd/Makefile
Normal file
@ -0,0 +1,48 @@
|
||||
include ../../scripts/Makefile.include
|
||||
include ../../perf/config/utilities.mak # QUIET_CLEAN
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
#$(info Determined 'srctree' to be $(srctree))
|
||||
endif
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
AR = $(CROSS_COMPILE)ar
|
||||
RM = rm -f
|
||||
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
LIBFILE = $(OUTPUT)libsubcmd.a
|
||||
|
||||
CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
||||
CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC
|
||||
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
|
||||
|
||||
CFLAGS += -I$(srctree)/tools/include/
|
||||
CFLAGS += -I$(srctree)/include/uapi
|
||||
CFLAGS += -I$(srctree)/include
|
||||
|
||||
SUBCMD_IN := $(OUTPUT)libsubcmd-in.o
|
||||
|
||||
all:
|
||||
|
||||
export srctree OUTPUT CC LD CFLAGS V
|
||||
include $(srctree)/tools/build/Makefile.include
|
||||
|
||||
all: fixdep $(LIBFILE)
|
||||
|
||||
$(SUBCMD_IN): FORCE
|
||||
@$(MAKE) $(build)=libsubcmd
|
||||
|
||||
$(LIBFILE): $(SUBCMD_IN)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(SUBCMD_IN)
|
||||
|
||||
clean:
|
||||
$(call QUIET_CLEAN, libsubcmd) $(RM) $(LIBFILE); \
|
||||
find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
|
||||
|
||||
FORCE:
|
||||
|
||||
.PHONY: clean FORCE
|
209
tools/lib/subcmd/exec-cmd.c
Normal file
209
tools/lib/subcmd/exec-cmd.c
Normal file
@ -0,0 +1,209 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "subcmd-util.h"
|
||||
#include "exec-cmd.h"
|
||||
#include "subcmd-config.h"
|
||||
|
||||
#define MAX_ARGS 32
|
||||
#define PATH_MAX 4096
|
||||
|
||||
static const char *argv_exec_path;
|
||||
static const char *argv0_path;
|
||||
|
||||
void exec_cmd_init(const char *exec_name, const char *prefix,
|
||||
const char *exec_path, const char *exec_path_env)
|
||||
{
|
||||
subcmd_config.exec_name = exec_name;
|
||||
subcmd_config.prefix = prefix;
|
||||
subcmd_config.exec_path = exec_path;
|
||||
subcmd_config.exec_path_env = exec_path_env;
|
||||
}
|
||||
|
||||
#define is_dir_sep(c) ((c) == '/')
|
||||
|
||||
static int is_absolute_path(const char *path)
|
||||
{
|
||||
return path[0] == '/';
|
||||
}
|
||||
|
||||
static const char *get_pwd_cwd(void)
|
||||
{
|
||||
static char cwd[PATH_MAX + 1];
|
||||
char *pwd;
|
||||
struct stat cwd_stat, pwd_stat;
|
||||
if (getcwd(cwd, PATH_MAX) == NULL)
|
||||
return NULL;
|
||||
pwd = getenv("PWD");
|
||||
if (pwd && strcmp(pwd, cwd)) {
|
||||
stat(cwd, &cwd_stat);
|
||||
if (!stat(pwd, &pwd_stat) &&
|
||||
pwd_stat.st_dev == cwd_stat.st_dev &&
|
||||
pwd_stat.st_ino == cwd_stat.st_ino) {
|
||||
strlcpy(cwd, pwd, PATH_MAX);
|
||||
}
|
||||
}
|
||||
return cwd;
|
||||
}
|
||||
|
||||
static const char *make_nonrelative_path(const char *path)
|
||||
{
|
||||
static char buf[PATH_MAX + 1];
|
||||
|
||||
if (is_absolute_path(path)) {
|
||||
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
|
||||
die("Too long path: %.*s", 60, path);
|
||||
} else {
|
||||
const char *cwd = get_pwd_cwd();
|
||||
if (!cwd)
|
||||
die("Cannot determine the current working directory");
|
||||
if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
|
||||
die("Too long path: %.*s", 60, path);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *system_path(const char *path)
|
||||
{
|
||||
char *buf = NULL;
|
||||
|
||||
if (is_absolute_path(path))
|
||||
return strdup(path);
|
||||
|
||||
astrcatf(&buf, "%s/%s", subcmd_config.prefix, path);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *extract_argv0_path(const char *argv0)
|
||||
{
|
||||
const char *slash;
|
||||
|
||||
if (!argv0 || !*argv0)
|
||||
return NULL;
|
||||
slash = argv0 + strlen(argv0);
|
||||
|
||||
while (argv0 <= slash && !is_dir_sep(*slash))
|
||||
slash--;
|
||||
|
||||
if (slash >= argv0) {
|
||||
argv0_path = strndup(argv0, slash - argv0);
|
||||
return argv0_path ? slash + 1 : NULL;
|
||||
}
|
||||
|
||||
return argv0;
|
||||
}
|
||||
|
||||
void set_argv_exec_path(const char *exec_path)
|
||||
{
|
||||
argv_exec_path = exec_path;
|
||||
/*
|
||||
* Propagate this setting to external programs.
|
||||
*/
|
||||
setenv(subcmd_config.exec_path_env, exec_path, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Returns the highest-priority location to look for subprograms. */
|
||||
char *get_argv_exec_path(void)
|
||||
{
|
||||
char *env;
|
||||
|
||||
if (argv_exec_path)
|
||||
return strdup(argv_exec_path);
|
||||
|
||||
env = getenv(subcmd_config.exec_path_env);
|
||||
if (env && *env)
|
||||
return strdup(env);
|
||||
|
||||
return system_path(subcmd_config.exec_path);
|
||||
}
|
||||
|
||||
static void add_path(char **out, const char *path)
|
||||
{
|
||||
if (path && *path) {
|
||||
if (is_absolute_path(path))
|
||||
astrcat(out, path);
|
||||
else
|
||||
astrcat(out, make_nonrelative_path(path));
|
||||
|
||||
astrcat(out, ":");
|
||||
}
|
||||
}
|
||||
|
||||
void setup_path(void)
|
||||
{
|
||||
const char *old_path = getenv("PATH");
|
||||
char *new_path = NULL;
|
||||
char *tmp = get_argv_exec_path();
|
||||
|
||||
add_path(&new_path, tmp);
|
||||
add_path(&new_path, argv0_path);
|
||||
free(tmp);
|
||||
|
||||
if (old_path)
|
||||
astrcat(&new_path, old_path);
|
||||
else
|
||||
astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin");
|
||||
|
||||
setenv("PATH", new_path, 1);
|
||||
|
||||
free(new_path);
|
||||
}
|
||||
|
||||
static const char **prepare_exec_cmd(const char **argv)
|
||||
{
|
||||
int argc;
|
||||
const char **nargv;
|
||||
|
||||
for (argc = 0; argv[argc]; argc++)
|
||||
; /* just counting */
|
||||
nargv = malloc(sizeof(*nargv) * (argc + 2));
|
||||
|
||||
nargv[0] = subcmd_config.exec_name;
|
||||
for (argc = 0; argv[argc]; argc++)
|
||||
nargv[argc + 1] = argv[argc];
|
||||
nargv[argc + 1] = NULL;
|
||||
return nargv;
|
||||
}
|
||||
|
||||
int execv_cmd(const char **argv) {
|
||||
const char **nargv = prepare_exec_cmd(argv);
|
||||
|
||||
/* execvp() can only ever return if it fails */
|
||||
execvp(subcmd_config.exec_name, (char **)nargv);
|
||||
|
||||
free(nargv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int execl_cmd(const char *cmd,...)
|
||||
{
|
||||
int argc;
|
||||
const char *argv[MAX_ARGS + 1];
|
||||
const char *arg;
|
||||
va_list param;
|
||||
|
||||
va_start(param, cmd);
|
||||
argv[0] = cmd;
|
||||
argc = 1;
|
||||
while (argc < MAX_ARGS) {
|
||||
arg = argv[argc++] = va_arg(param, char *);
|
||||
if (!arg)
|
||||
break;
|
||||
}
|
||||
va_end(param);
|
||||
if (MAX_ARGS <= argc) {
|
||||
fprintf(stderr, " Error: too many args to run %s\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
argv[argc] = NULL;
|
||||
return execv_cmd(argv);
|
||||
}
|
16
tools/lib/subcmd/exec-cmd.h
Normal file
16
tools/lib/subcmd/exec-cmd.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __SUBCMD_EXEC_CMD_H
|
||||
#define __SUBCMD_EXEC_CMD_H
|
||||
|
||||
extern void exec_cmd_init(const char *exec_name, const char *prefix,
|
||||
const char *exec_path, const char *exec_path_env);
|
||||
|
||||
extern void set_argv_exec_path(const char *exec_path);
|
||||
extern const char *extract_argv0_path(const char *path);
|
||||
extern void setup_path(void);
|
||||
extern int execv_cmd(const char **argv); /* NULL terminated */
|
||||
extern int execl_cmd(const char *cmd, ...);
|
||||
/* get_argv_exec_path and system_path return malloc'd string, caller must free it */
|
||||
extern char *get_argv_exec_path(void);
|
||||
extern char *system_path(const char *path);
|
||||
|
||||
#endif /* __SUBCMD_EXEC_CMD_H */
|
@ -1,9 +1,15 @@
|
||||
#include "cache.h"
|
||||
#include "../builtin.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "levenshtein.h"
|
||||
#include "help.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include "subcmd-util.h"
|
||||
#include "help.h"
|
||||
#include "exec-cmd.h"
|
||||
|
||||
void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
|
||||
{
|
||||
@ -17,7 +23,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
|
||||
cmds->names[cmds->cnt++] = ent;
|
||||
}
|
||||
|
||||
static void clean_cmdnames(struct cmdnames *cmds)
|
||||
void clean_cmdnames(struct cmdnames *cmds)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@ -28,14 +34,14 @@ static void clean_cmdnames(struct cmdnames *cmds)
|
||||
cmds->alloc = 0;
|
||||
}
|
||||
|
||||
static int cmdname_compare(const void *a_, const void *b_)
|
||||
int cmdname_compare(const void *a_, const void *b_)
|
||||
{
|
||||
struct cmdname *a = *(struct cmdname **)a_;
|
||||
struct cmdname *b = *(struct cmdname **)b_;
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static void uniq(struct cmdnames *cmds)
|
||||
void uniq(struct cmdnames *cmds)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
@ -71,6 +77,28 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
|
||||
cmds->cnt = cj;
|
||||
}
|
||||
|
||||
static void get_term_dimensions(struct winsize *ws)
|
||||
{
|
||||
char *s = getenv("LINES");
|
||||
|
||||
if (s != NULL) {
|
||||
ws->ws_row = atoi(s);
|
||||
s = getenv("COLUMNS");
|
||||
if (s != NULL) {
|
||||
ws->ws_col = atoi(s);
|
||||
if (ws->ws_row && ws->ws_col)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef TIOCGWINSZ
|
||||
if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
|
||||
ws->ws_row && ws->ws_col)
|
||||
return;
|
||||
#endif
|
||||
ws->ws_row = 25;
|
||||
ws->ws_col = 80;
|
||||
}
|
||||
|
||||
static void pretty_print_string_list(struct cmdnames *cmds, int longest)
|
||||
{
|
||||
int cols = 1, rows;
|
||||
@ -114,6 +142,14 @@ static int is_executable(const char *name)
|
||||
return st.st_mode & S_IXUSR;
|
||||
}
|
||||
|
||||
static int has_extension(const char *filename, const char *ext)
|
||||
{
|
||||
size_t len = strlen(filename);
|
||||
size_t extlen = strlen(ext);
|
||||
|
||||
return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
|
||||
}
|
||||
|
||||
static void list_commands_in_dir(struct cmdnames *cmds,
|
||||
const char *path,
|
||||
const char *prefix)
|
||||
@ -121,8 +157,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
|
||||
int prefix_len;
|
||||
DIR *dir = opendir(path);
|
||||
struct dirent *de;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int len;
|
||||
char *buf = NULL;
|
||||
|
||||
if (!dir)
|
||||
return;
|
||||
@ -130,8 +165,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
|
||||
prefix = "perf-";
|
||||
prefix_len = strlen(prefix);
|
||||
|
||||
strbuf_addf(&buf, "%s/", path);
|
||||
len = buf.len;
|
||||
astrcatf(&buf, "%s/", path);
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
int entlen;
|
||||
@ -139,9 +173,8 @@ static void list_commands_in_dir(struct cmdnames *cmds,
|
||||
if (prefixcmp(de->d_name, prefix))
|
||||
continue;
|
||||
|
||||
strbuf_setlen(&buf, len);
|
||||
strbuf_addstr(&buf, de->d_name);
|
||||
if (!is_executable(buf.buf))
|
||||
astrcat(&buf, de->d_name);
|
||||
if (!is_executable(buf))
|
||||
continue;
|
||||
|
||||
entlen = strlen(de->d_name) - prefix_len;
|
||||
@ -151,7 +184,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
|
||||
add_cmdname(cmds, de->d_name + prefix_len, entlen);
|
||||
}
|
||||
closedir(dir);
|
||||
strbuf_release(&buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void load_command_list(const char *prefix,
|
||||
@ -159,7 +192,7 @@ void load_command_list(const char *prefix,
|
||||
struct cmdnames *other_cmds)
|
||||
{
|
||||
const char *env_path = getenv("PATH");
|
||||
char *exec_path = perf_exec_path();
|
||||
char *exec_path = get_argv_exec_path();
|
||||
|
||||
if (exec_path) {
|
||||
list_commands_in_dir(main_cmds, exec_path, prefix);
|
||||
@ -172,7 +205,7 @@ void load_command_list(const char *prefix,
|
||||
char *paths, *path, *colon;
|
||||
path = paths = strdup(env_path);
|
||||
while (1) {
|
||||
if ((colon = strchr(path, PATH_SEP)))
|
||||
if ((colon = strchr(path, ':')))
|
||||
*colon = 0;
|
||||
if (!exec_path || strcmp(path, exec_path))
|
||||
list_commands_in_dir(other_cmds, path, prefix);
|
||||
@ -204,7 +237,7 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
|
||||
longest = other_cmds->names[i]->len;
|
||||
|
||||
if (main_cmds->cnt) {
|
||||
char *exec_path = perf_exec_path();
|
||||
char *exec_path = get_argv_exec_path();
|
||||
printf("available %s in '%s'\n", title, exec_path);
|
||||
printf("----------------");
|
||||
mput_char('-', strlen(title) + strlen(exec_path));
|
||||
@ -233,102 +266,3 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int autocorrect;
|
||||
static struct cmdnames aliases;
|
||||
|
||||
static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcmp(var, "help.autocorrect"))
|
||||
autocorrect = perf_config_int(var,value);
|
||||
/* Also use aliases for command lookup */
|
||||
if (!prefixcmp(var, "alias."))
|
||||
add_cmdname(&aliases, var + 6, strlen(var + 6));
|
||||
|
||||
return perf_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
static int levenshtein_compare(const void *p1, const void *p2)
|
||||
{
|
||||
const struct cmdname *const *c1 = p1, *const *c2 = p2;
|
||||
const char *s1 = (*c1)->name, *s2 = (*c2)->name;
|
||||
int l1 = (*c1)->len;
|
||||
int l2 = (*c2)->len;
|
||||
return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
|
||||
}
|
||||
|
||||
static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
|
||||
|
||||
for (i = 0; i < old->cnt; i++)
|
||||
cmds->names[cmds->cnt++] = old->names[i];
|
||||
zfree(&old->names);
|
||||
old->cnt = 0;
|
||||
}
|
||||
|
||||
const char *help_unknown_cmd(const char *cmd)
|
||||
{
|
||||
unsigned int i, n = 0, best_similarity = 0;
|
||||
struct cmdnames main_cmds, other_cmds;
|
||||
|
||||
memset(&main_cmds, 0, sizeof(main_cmds));
|
||||
memset(&other_cmds, 0, sizeof(main_cmds));
|
||||
memset(&aliases, 0, sizeof(aliases));
|
||||
|
||||
perf_config(perf_unknown_cmd_config, NULL);
|
||||
|
||||
load_command_list("perf-", &main_cmds, &other_cmds);
|
||||
|
||||
add_cmd_list(&main_cmds, &aliases);
|
||||
add_cmd_list(&main_cmds, &other_cmds);
|
||||
qsort(main_cmds.names, main_cmds.cnt,
|
||||
sizeof(main_cmds.names), cmdname_compare);
|
||||
uniq(&main_cmds);
|
||||
|
||||
if (main_cmds.cnt) {
|
||||
/* This reuses cmdname->len for similarity index */
|
||||
for (i = 0; i < main_cmds.cnt; ++i)
|
||||
main_cmds.names[i]->len =
|
||||
levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
|
||||
|
||||
qsort(main_cmds.names, main_cmds.cnt,
|
||||
sizeof(*main_cmds.names), levenshtein_compare);
|
||||
|
||||
best_similarity = main_cmds.names[0]->len;
|
||||
n = 1;
|
||||
while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
|
||||
++n;
|
||||
}
|
||||
|
||||
if (autocorrect && n == 1) {
|
||||
const char *assumed = main_cmds.names[0]->name;
|
||||
|
||||
main_cmds.names[0] = NULL;
|
||||
clean_cmdnames(&main_cmds);
|
||||
fprintf(stderr, "WARNING: You called a perf program named '%s', "
|
||||
"which does not exist.\n"
|
||||
"Continuing under the assumption that you meant '%s'\n",
|
||||
cmd, assumed);
|
||||
if (autocorrect > 0) {
|
||||
fprintf(stderr, "in %0.1f seconds automatically...\n",
|
||||
(float)autocorrect/10.0);
|
||||
poll(NULL, 0, autocorrect * 100);
|
||||
}
|
||||
return assumed;
|
||||
}
|
||||
|
||||
fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
|
||||
|
||||
if (main_cmds.cnt && best_similarity < 6) {
|
||||
fprintf(stderr, "\nDid you mean %s?\n",
|
||||
n < 2 ? "this": "one of these");
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
#ifndef __PERF_HELP_H
|
||||
#define __PERF_HELP_H
|
||||
#ifndef __SUBCMD_HELP_H
|
||||
#define __SUBCMD_HELP_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct cmdnames {
|
||||
size_t alloc;
|
||||
size_t cnt;
|
||||
struct cmdname {
|
||||
size_t len; /* also used for similarity index in help.c */
|
||||
char name[FLEX_ARRAY];
|
||||
char name[];
|
||||
} **names;
|
||||
};
|
||||
|
||||
@ -20,10 +22,13 @@ void load_command_list(const char *prefix,
|
||||
struct cmdnames *main_cmds,
|
||||
struct cmdnames *other_cmds);
|
||||
void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
|
||||
void clean_cmdnames(struct cmdnames *cmds);
|
||||
int cmdname_compare(const void *a, const void *b);
|
||||
void uniq(struct cmdnames *cmds);
|
||||
/* Here we require that excludes is a sorted list. */
|
||||
void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
|
||||
int is_in_cmdlist(struct cmdnames *c, const char *s);
|
||||
void list_commands(const char *title, struct cmdnames *main_cmds,
|
||||
struct cmdnames *other_cmds);
|
||||
|
||||
#endif /* __PERF_HELP_H */
|
||||
#endif /* __SUBCMD_HELP_H */
|
@ -1,6 +1,12 @@
|
||||
#include "cache.h"
|
||||
#include <sys/select.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include "pager.h"
|
||||
#include "run-command.h"
|
||||
#include "sigchain.h"
|
||||
#include "subcmd-config.h"
|
||||
|
||||
/*
|
||||
* This is split up from the rest of git so that we can do
|
||||
@ -9,6 +15,11 @@
|
||||
|
||||
static int spawned_pager;
|
||||
|
||||
void pager_init(const char *pager_env)
|
||||
{
|
||||
subcmd_config.pager_env = pager_env;
|
||||
}
|
||||
|
||||
static void pager_preexec(void)
|
||||
{
|
||||
/*
|
||||
@ -46,7 +57,7 @@ static void wait_for_pager_signal(int signo)
|
||||
|
||||
void setup_pager(void)
|
||||
{
|
||||
const char *pager = getenv("PERF_PAGER");
|
||||
const char *pager = getenv(subcmd_config.pager_env);
|
||||
|
||||
if (!isatty(1))
|
||||
return;
|
||||
@ -85,11 +96,5 @@ void setup_pager(void)
|
||||
|
||||
int pager_in_use(void)
|
||||
{
|
||||
const char *env;
|
||||
|
||||
if (spawned_pager)
|
||||
return 1;
|
||||
|
||||
env = getenv("PERF_PAGER_IN_USE");
|
||||
return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
|
||||
return spawned_pager;
|
||||
}
|
9
tools/lib/subcmd/pager.h
Normal file
9
tools/lib/subcmd/pager.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __SUBCMD_PAGER_H
|
||||
#define __SUBCMD_PAGER_H
|
||||
|
||||
extern void pager_init(const char *pager_env);
|
||||
|
||||
extern void setup_pager(void);
|
||||
extern int pager_in_use(void);
|
||||
|
||||
#endif /* __SUBCMD_PAGER_H */
|
@ -1,37 +1,66 @@
|
||||
#include "util.h"
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "subcmd-util.h"
|
||||
#include "parse-options.h"
|
||||
#include "cache.h"
|
||||
#include "header.h"
|
||||
#include <linux/string.h>
|
||||
#include "subcmd-config.h"
|
||||
#include "pager.h"
|
||||
|
||||
#define OPT_SHORT 1
|
||||
#define OPT_UNSET 2
|
||||
|
||||
static struct strbuf error_buf = STRBUF_INIT;
|
||||
char *error_buf;
|
||||
|
||||
static int opterror(const struct option *opt, const char *reason, int flags)
|
||||
{
|
||||
if (flags & OPT_SHORT)
|
||||
return error("switch `%c' %s", opt->short_name, reason);
|
||||
if (flags & OPT_UNSET)
|
||||
return error("option `no-%s' %s", opt->long_name, reason);
|
||||
return error("option `%s' %s", opt->long_name, reason);
|
||||
fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
|
||||
else if (flags & OPT_UNSET)
|
||||
fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
|
||||
else
|
||||
fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *skip_prefix(const char *str, const char *prefix)
|
||||
{
|
||||
size_t len = strlen(prefix);
|
||||
return strncmp(str, prefix, len) ? NULL : str + len;
|
||||
}
|
||||
|
||||
static void optwarning(const struct option *opt, const char *reason, int flags)
|
||||
{
|
||||
if (flags & OPT_SHORT)
|
||||
fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
|
||||
else if (flags & OPT_UNSET)
|
||||
fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
|
||||
else
|
||||
fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
|
||||
}
|
||||
|
||||
static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
|
||||
int flags, const char **arg)
|
||||
{
|
||||
const char *res;
|
||||
|
||||
if (p->opt) {
|
||||
*arg = p->opt;
|
||||
res = p->opt;
|
||||
p->opt = NULL;
|
||||
} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
|
||||
**(p->argv + 1) == '-')) {
|
||||
*arg = (const char *)opt->defval;
|
||||
res = (const char *)opt->defval;
|
||||
} else if (p->argc > 1) {
|
||||
p->argc--;
|
||||
*arg = *++p->argv;
|
||||
res = *++p->argv;
|
||||
} else
|
||||
return opterror(opt, "requires a value", flags);
|
||||
if (arg)
|
||||
*arg = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -55,11 +84,11 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||
|
||||
if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
|
||||
p->excl_opt->long_name == NULL) {
|
||||
scnprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
|
||||
p->excl_opt->short_name);
|
||||
snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
|
||||
p->excl_opt->short_name);
|
||||
} else {
|
||||
scnprintf(msg, sizeof(msg), "cannot be used with %s",
|
||||
p->excl_opt->long_name);
|
||||
snprintf(msg, sizeof(msg), "cannot be used with %s",
|
||||
p->excl_opt->long_name);
|
||||
}
|
||||
opterror(opt, msg, flags);
|
||||
return -3;
|
||||
@ -91,6 +120,64 @@ static int get_value(struct parse_opt_ctx_t *p,
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->flags & PARSE_OPT_NOBUILD) {
|
||||
char reason[128];
|
||||
bool noarg = false;
|
||||
|
||||
err = snprintf(reason, sizeof(reason),
|
||||
opt->flags & PARSE_OPT_CANSKIP ?
|
||||
"is being ignored because %s " :
|
||||
"is not available because %s",
|
||||
opt->build_opt);
|
||||
reason[sizeof(reason) - 1] = '\0';
|
||||
|
||||
if (err < 0)
|
||||
strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
|
||||
"is being ignored" :
|
||||
"is not available",
|
||||
sizeof(reason));
|
||||
|
||||
if (!(opt->flags & PARSE_OPT_CANSKIP))
|
||||
return opterror(opt, reason, flags);
|
||||
|
||||
err = 0;
|
||||
if (unset)
|
||||
noarg = true;
|
||||
if (opt->flags & PARSE_OPT_NOARG)
|
||||
noarg = true;
|
||||
if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
|
||||
noarg = true;
|
||||
|
||||
switch (opt->type) {
|
||||
case OPTION_BOOLEAN:
|
||||
case OPTION_INCR:
|
||||
case OPTION_BIT:
|
||||
case OPTION_SET_UINT:
|
||||
case OPTION_SET_PTR:
|
||||
case OPTION_END:
|
||||
case OPTION_ARGUMENT:
|
||||
case OPTION_GROUP:
|
||||
noarg = true;
|
||||
break;
|
||||
case OPTION_CALLBACK:
|
||||
case OPTION_STRING:
|
||||
case OPTION_INTEGER:
|
||||
case OPTION_UINTEGER:
|
||||
case OPTION_LONG:
|
||||
case OPTION_U64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!noarg)
|
||||
err = get_arg(p, opt, flags, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
optwarning(opt, reason, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (opt->type) {
|
||||
case OPTION_BIT:
|
||||
if (unset)
|
||||
@ -327,14 +414,16 @@ match:
|
||||
return get_value(p, options, flags);
|
||||
}
|
||||
|
||||
if (ambiguous_option)
|
||||
return error("Ambiguous option: %s "
|
||||
"(could be --%s%s or --%s%s)",
|
||||
arg,
|
||||
(ambiguous_flags & OPT_UNSET) ? "no-" : "",
|
||||
ambiguous_option->long_name,
|
||||
(abbrev_flags & OPT_UNSET) ? "no-" : "",
|
||||
abbrev_option->long_name);
|
||||
if (ambiguous_option) {
|
||||
fprintf(stderr,
|
||||
" Error: Ambiguous option: %s (could be --%s%s or --%s%s)",
|
||||
arg,
|
||||
(ambiguous_flags & OPT_UNSET) ? "no-" : "",
|
||||
ambiguous_option->long_name,
|
||||
(abbrev_flags & OPT_UNSET) ? "no-" : "",
|
||||
abbrev_option->long_name);
|
||||
return -1;
|
||||
}
|
||||
if (abbrev_option)
|
||||
return get_value(p, abbrev_option, abbrev_flags);
|
||||
return -2;
|
||||
@ -346,7 +435,7 @@ static void check_typos(const char *arg, const struct option *options)
|
||||
return;
|
||||
|
||||
if (!prefixcmp(arg, "no-")) {
|
||||
error ("did you mean `--%s` (with two dashes ?)", arg);
|
||||
fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
|
||||
exit(129);
|
||||
}
|
||||
|
||||
@ -354,14 +443,14 @@ static void check_typos(const char *arg, const struct option *options)
|
||||
if (!options->long_name)
|
||||
continue;
|
||||
if (!prefixcmp(options->long_name, arg)) {
|
||||
error ("did you mean `--%s` (with two dashes ?)", arg);
|
||||
fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
|
||||
exit(129);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void parse_options_start(struct parse_opt_ctx_t *ctx,
|
||||
int argc, const char **argv, int flags)
|
||||
static void parse_options_start(struct parse_opt_ctx_t *ctx,
|
||||
int argc, const char **argv, int flags)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->argc = argc - 1;
|
||||
@ -378,9 +467,9 @@ static int usage_with_options_internal(const char * const *,
|
||||
const struct option *, int,
|
||||
struct parse_opt_ctx_t *);
|
||||
|
||||
int parse_options_step(struct parse_opt_ctx_t *ctx,
|
||||
const struct option *options,
|
||||
const char * const usagestr[])
|
||||
static int parse_options_step(struct parse_opt_ctx_t *ctx,
|
||||
const struct option *options,
|
||||
const char * const usagestr[])
|
||||
{
|
||||
int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
|
||||
int excl_short_opt = 1;
|
||||
@ -489,7 +578,7 @@ exclusive:
|
||||
return PARSE_OPT_HELP;
|
||||
}
|
||||
|
||||
int parse_options_end(struct parse_opt_ctx_t *ctx)
|
||||
static int parse_options_end(struct parse_opt_ctx_t *ctx)
|
||||
{
|
||||
memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
|
||||
ctx->out[ctx->cpidx + ctx->argc] = NULL;
|
||||
@ -503,18 +592,18 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
|
||||
|
||||
/* build usage string if it's not provided */
|
||||
if (subcommands && !usagestr[0]) {
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
char *buf = NULL;
|
||||
|
||||
astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
|
||||
|
||||
strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
|
||||
for (int i = 0; subcommands[i]; i++) {
|
||||
if (i)
|
||||
strbuf_addstr(&buf, "|");
|
||||
strbuf_addstr(&buf, subcommands[i]);
|
||||
astrcat(&buf, "|");
|
||||
astrcat(&buf, subcommands[i]);
|
||||
}
|
||||
strbuf_addstr(&buf, "}");
|
||||
astrcat(&buf, "}");
|
||||
|
||||
usagestr[0] = strdup(buf.buf);
|
||||
strbuf_release(&buf);
|
||||
usagestr[0] = buf;
|
||||
}
|
||||
|
||||
parse_options_start(&ctx, argc, argv, flags);
|
||||
@ -539,13 +628,11 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
|
||||
putchar('\n');
|
||||
exit(130);
|
||||
default: /* PARSE_OPT_UNKNOWN */
|
||||
if (ctx.argv[0][1] == '-') {
|
||||
strbuf_addf(&error_buf, "unknown option `%s'",
|
||||
ctx.argv[0] + 2);
|
||||
} else {
|
||||
strbuf_addf(&error_buf, "unknown switch `%c'",
|
||||
*ctx.opt);
|
||||
}
|
||||
if (ctx.argv[0][1] == '-')
|
||||
astrcatf(&error_buf, "unknown option `%s'",
|
||||
ctx.argv[0] + 2);
|
||||
else
|
||||
astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
|
||||
usage_with_options(usagestr, options);
|
||||
}
|
||||
|
||||
@ -645,6 +732,10 @@ static void print_option_help(const struct option *opts, int full)
|
||||
pad = USAGE_OPTS_WIDTH;
|
||||
}
|
||||
fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
|
||||
if (opts->flags & PARSE_OPT_NOBUILD)
|
||||
fprintf(stderr, "%*s(not built-in because %s)\n",
|
||||
USAGE_OPTS_WIDTH + USAGE_GAP, "",
|
||||
opts->build_opt);
|
||||
}
|
||||
|
||||
static int option__cmp(const void *va, const void *vb)
|
||||
@ -670,16 +761,18 @@ static int option__cmp(const void *va, const void *vb)
|
||||
|
||||
static struct option *options__order(const struct option *opts)
|
||||
{
|
||||
int nr_opts = 0;
|
||||
int nr_opts = 0, len;
|
||||
const struct option *o = opts;
|
||||
struct option *ordered;
|
||||
|
||||
for (o = opts; o->type != OPTION_END; o++)
|
||||
++nr_opts;
|
||||
|
||||
ordered = memdup(opts, sizeof(*o) * (nr_opts + 1));
|
||||
if (ordered == NULL)
|
||||
len = sizeof(*o) * (nr_opts + 1);
|
||||
ordered = malloc(len);
|
||||
if (!ordered)
|
||||
goto out;
|
||||
memcpy(ordered, opts, len);
|
||||
|
||||
qsort(ordered, nr_opts, sizeof(*o), option__cmp);
|
||||
out:
|
||||
@ -717,9 +810,9 @@ static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx
|
||||
return false;
|
||||
}
|
||||
|
||||
int usage_with_options_internal(const char * const *usagestr,
|
||||
const struct option *opts, int full,
|
||||
struct parse_opt_ctx_t *ctx)
|
||||
static int usage_with_options_internal(const char * const *usagestr,
|
||||
const struct option *opts, int full,
|
||||
struct parse_opt_ctx_t *ctx)
|
||||
{
|
||||
struct option *ordered;
|
||||
|
||||
@ -728,9 +821,9 @@ int usage_with_options_internal(const char * const *usagestr,
|
||||
|
||||
setup_pager();
|
||||
|
||||
if (strbuf_avail(&error_buf)) {
|
||||
fprintf(stderr, " Error: %s\n", error_buf.buf);
|
||||
strbuf_release(&error_buf);
|
||||
if (error_buf) {
|
||||
fprintf(stderr, " Error: %s\n", error_buf);
|
||||
zfree(&error_buf);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n Usage: %s\n", *usagestr++);
|
||||
@ -774,11 +867,15 @@ void usage_with_options_msg(const char * const *usagestr,
|
||||
const struct option *opts, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *tmp = error_buf;
|
||||
|
||||
va_start(ap, fmt);
|
||||
strbuf_addv(&error_buf, fmt, ap);
|
||||
if (vasprintf(&error_buf, fmt, ap) == -1)
|
||||
die("vasprintf failed");
|
||||
va_end(ap);
|
||||
|
||||
free(tmp);
|
||||
|
||||
usage_with_options_internal(usagestr, opts, 0, NULL);
|
||||
exit(129);
|
||||
}
|
||||
@ -848,15 +945,39 @@ int parse_opt_verbosity_cb(const struct option *opt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_option_flag(struct option *opts, int shortopt, const char *longopt,
|
||||
int flag)
|
||||
static struct option *
|
||||
find_option(struct option *opts, int shortopt, const char *longopt)
|
||||
{
|
||||
for (; opts->type != OPTION_END; opts++) {
|
||||
if ((shortopt && opts->short_name == shortopt) ||
|
||||
(opts->long_name && longopt &&
|
||||
!strcmp(opts->long_name, longopt))) {
|
||||
opts->flags |= flag;
|
||||
break;
|
||||
}
|
||||
!strcmp(opts->long_name, longopt)))
|
||||
return opts;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_option_flag(struct option *opts, int shortopt, const char *longopt,
|
||||
int flag)
|
||||
{
|
||||
struct option *opt = find_option(opts, shortopt, longopt);
|
||||
|
||||
if (opt)
|
||||
opt->flags |= flag;
|
||||
return;
|
||||
}
|
||||
|
||||
void set_option_nobuild(struct option *opts, int shortopt,
|
||||
const char *longopt,
|
||||
const char *build_opt,
|
||||
bool can_skip)
|
||||
{
|
||||
struct option *opt = find_option(opts, shortopt, longopt);
|
||||
|
||||
if (!opt)
|
||||
return;
|
||||
|
||||
opt->flags |= PARSE_OPT_NOBUILD;
|
||||
opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
|
||||
opt->build_opt = build_opt;
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
#ifndef __PERF_PARSE_OPTIONS_H
|
||||
#define __PERF_PARSE_OPTIONS_H
|
||||
#ifndef __SUBCMD_PARSE_OPTIONS_H
|
||||
#define __SUBCMD_PARSE_OPTIONS_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum parse_opt_type {
|
||||
/* special types */
|
||||
@ -41,6 +41,8 @@ enum parse_opt_option_flags {
|
||||
PARSE_OPT_DISABLED = 32,
|
||||
PARSE_OPT_EXCLUSIVE = 64,
|
||||
PARSE_OPT_NOEMPTY = 128,
|
||||
PARSE_OPT_NOBUILD = 256,
|
||||
PARSE_OPT_CANSKIP = 512,
|
||||
};
|
||||
|
||||
struct option;
|
||||
@ -96,6 +98,7 @@ struct option {
|
||||
void *value;
|
||||
const char *argh;
|
||||
const char *help;
|
||||
const char *build_opt;
|
||||
|
||||
int flags;
|
||||
parse_opt_cb *callback;
|
||||
@ -149,6 +152,9 @@ struct option {
|
||||
/* parse_options() will filter out the processed options and leave the
|
||||
* non-option argments in argv[].
|
||||
* Returns the number of arguments left in argv[].
|
||||
*
|
||||
* NOTE: parse_options() and parse_options_subcommand() may call exit() in the
|
||||
* case of an error (or for 'special' options like --list-cmds or --list-opts).
|
||||
*/
|
||||
extern int parse_options(int argc, const char **argv,
|
||||
const struct option *options,
|
||||
@ -195,15 +201,6 @@ extern int parse_options_usage(const char * const *usagestr,
|
||||
const char *optstr,
|
||||
bool short_opt);
|
||||
|
||||
extern void parse_options_start(struct parse_opt_ctx_t *ctx,
|
||||
int argc, const char **argv, int flags);
|
||||
|
||||
extern int parse_options_step(struct parse_opt_ctx_t *ctx,
|
||||
const struct option *options,
|
||||
const char * const usagestr[]);
|
||||
|
||||
extern int parse_options_end(struct parse_opt_ctx_t *ctx);
|
||||
|
||||
|
||||
/*----- some often used options -----*/
|
||||
extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
|
||||
@ -226,4 +223,7 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
|
||||
extern const char *parse_options_fix_filename(const char *prefix, const char *file);
|
||||
|
||||
void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
|
||||
#endif /* __PERF_PARSE_OPTIONS_H */
|
||||
void set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
|
||||
const char *build_opt, bool can_skip);
|
||||
|
||||
#endif /* __SUBCMD_PARSE_OPTIONS_H */
|
@ -1,7 +1,15 @@
|
||||
#include "cache.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include "subcmd-util.h"
|
||||
#include "run-command.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "debug.h"
|
||||
#include "exec-cmd.h"
|
||||
|
||||
#define STRERR_BUFSIZE 128
|
||||
|
||||
static inline void close_pair(int fd[2])
|
||||
{
|
||||
@ -112,8 +120,8 @@ int start_command(struct child_process *cmd)
|
||||
}
|
||||
if (cmd->preexec_cb)
|
||||
cmd->preexec_cb();
|
||||
if (cmd->perf_cmd) {
|
||||
execv_perf_cmd(cmd->argv);
|
||||
if (cmd->exec_cmd) {
|
||||
execv_cmd(cmd->argv);
|
||||
} else {
|
||||
execvp(cmd->argv[0], (char *const*) cmd->argv);
|
||||
}
|
||||
@ -164,8 +172,8 @@ static int wait_or_whine(pid_t pid)
|
||||
if (waiting < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
error("waitpid failed (%s)",
|
||||
strerror_r(errno, sbuf, sizeof(sbuf)));
|
||||
fprintf(stderr, " Error: waitpid failed (%s)",
|
||||
strerror_r(errno, sbuf, sizeof(sbuf)));
|
||||
return -ERR_RUN_COMMAND_WAITPID;
|
||||
}
|
||||
if (waiting != pid)
|
||||
@ -207,7 +215,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->argv = argv;
|
||||
cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
|
||||
cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
|
||||
cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0;
|
||||
cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#ifndef __PERF_RUN_COMMAND_H
|
||||
#define __PERF_RUN_COMMAND_H
|
||||
#ifndef __SUBCMD_RUN_COMMAND_H
|
||||
#define __SUBCMD_RUN_COMMAND_H
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
enum {
|
||||
ERR_RUN_COMMAND_FORK = 10000,
|
||||
@ -41,7 +43,7 @@ struct child_process {
|
||||
unsigned no_stdin:1;
|
||||
unsigned no_stdout:1;
|
||||
unsigned no_stderr:1;
|
||||
unsigned perf_cmd:1; /* if this is to be perf sub-command */
|
||||
unsigned exec_cmd:1; /* if this is to be external sub-command */
|
||||
unsigned stdout_to_stderr:1;
|
||||
void (*preexec_cb)(void);
|
||||
};
|
||||
@ -51,8 +53,8 @@ int finish_command(struct child_process *);
|
||||
int run_command(struct child_process *);
|
||||
|
||||
#define RUN_COMMAND_NO_STDIN 1
|
||||
#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */
|
||||
#define RUN_EXEC_CMD 2 /*If this is to be external sub-command */
|
||||
#define RUN_COMMAND_STDOUT_TO_STDERR 4
|
||||
int run_command_v_opt(const char **argv, int opt);
|
||||
|
||||
#endif /* __PERF_RUN_COMMAND_H */
|
||||
#endif /* __SUBCMD_RUN_COMMAND_H */
|
@ -1,5 +1,6 @@
|
||||
#include <signal.h>
|
||||
#include "subcmd-util.h"
|
||||
#include "sigchain.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define SIGCHAIN_MAX_SIGNALS 32
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef __PERF_SIGCHAIN_H
|
||||
#define __PERF_SIGCHAIN_H
|
||||
#ifndef __SUBCMD_SIGCHAIN_H
|
||||
#define __SUBCMD_SIGCHAIN_H
|
||||
|
||||
typedef void (*sigchain_fun)(int);
|
||||
|
||||
@ -7,4 +7,4 @@ int sigchain_pop(int sig);
|
||||
|
||||
void sigchain_push_common(sigchain_fun f);
|
||||
|
||||
#endif /* __PERF_SIGCHAIN_H */
|
||||
#endif /* __SUBCMD_SIGCHAIN_H */
|
11
tools/lib/subcmd/subcmd-config.c
Normal file
11
tools/lib/subcmd/subcmd-config.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include "subcmd-config.h"
|
||||
|
||||
#define UNDEFINED "SUBCMD_HAS_NOT_BEEN_INITIALIZED"
|
||||
|
||||
struct subcmd_config subcmd_config = {
|
||||
.exec_name = UNDEFINED,
|
||||
.prefix = UNDEFINED,
|
||||
.exec_path = UNDEFINED,
|
||||
.exec_path_env = UNDEFINED,
|
||||
.pager_env = UNDEFINED,
|
||||
};
|
14
tools/lib/subcmd/subcmd-config.h
Normal file
14
tools/lib/subcmd/subcmd-config.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __PERF_SUBCMD_CONFIG_H
|
||||
#define __PERF_SUBCMD_CONFIG_H
|
||||
|
||||
struct subcmd_config {
|
||||
const char *exec_name;
|
||||
const char *prefix;
|
||||
const char *exec_path;
|
||||
const char *exec_path_env;
|
||||
const char *pager_env;
|
||||
};
|
||||
|
||||
extern struct subcmd_config subcmd_config;
|
||||
|
||||
#endif /* __PERF_SUBCMD_CONFIG_H */
|
91
tools/lib/subcmd/subcmd-util.h
Normal file
91
tools/lib/subcmd/subcmd-util.h
Normal file
@ -0,0 +1,91 @@
|
||||
#ifndef __SUBCMD_UTIL_H
|
||||
#define __SUBCMD_UTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
|
||||
static inline void report(const char *prefix, const char *err, va_list params)
|
||||
{
|
||||
char msg[1024];
|
||||
vsnprintf(msg, sizeof(msg), err, params);
|
||||
fprintf(stderr, " %s%s\n", prefix, msg);
|
||||
}
|
||||
|
||||
static NORETURN inline void die(const char *err, ...)
|
||||
{
|
||||
va_list params;
|
||||
|
||||
va_start(params, err);
|
||||
report(" Fatal: ", err, params);
|
||||
exit(128);
|
||||
va_end(params);
|
||||
}
|
||||
|
||||
#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
|
||||
|
||||
#define alloc_nr(x) (((x)+16)*3/2)
|
||||
|
||||
/*
|
||||
* Realloc the buffer pointed at by variable 'x' so that it can hold
|
||||
* at least 'nr' entries; the number of entries currently allocated
|
||||
* is 'alloc', using the standard growing factor alloc_nr() macro.
|
||||
*
|
||||
* DO NOT USE any expression with side-effect for 'x' or 'alloc'.
|
||||
*/
|
||||
#define ALLOC_GROW(x, nr, alloc) \
|
||||
do { \
|
||||
if ((nr) > alloc) { \
|
||||
if (alloc_nr(alloc) < (nr)) \
|
||||
alloc = (nr); \
|
||||
else \
|
||||
alloc = alloc_nr(alloc); \
|
||||
x = xrealloc((x), alloc * sizeof(*(x))); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static inline void *xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *ret = realloc(ptr, size);
|
||||
if (!ret && !size)
|
||||
ret = realloc(ptr, 1);
|
||||
if (!ret) {
|
||||
ret = realloc(ptr, size);
|
||||
if (!ret && !size)
|
||||
ret = realloc(ptr, 1);
|
||||
if (!ret)
|
||||
die("Out of memory, realloc failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define astrcatf(out, fmt, ...) \
|
||||
({ \
|
||||
char *tmp = *(out); \
|
||||
if (asprintf((out), "%s" fmt, tmp ?: "", ## __VA_ARGS__) == -1) \
|
||||
die("asprintf failed"); \
|
||||
free(tmp); \
|
||||
})
|
||||
|
||||
static inline void astrcat(char **out, const char *add)
|
||||
{
|
||||
char *tmp = *out;
|
||||
|
||||
if (asprintf(out, "%s%s", tmp ?: "", add) == -1)
|
||||
die("asprintf failed");
|
||||
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
static inline int prefixcmp(const char *str, const char *prefix)
|
||||
{
|
||||
for (; ; str++, prefix++)
|
||||
if (!*prefix)
|
||||
return 0;
|
||||
else if (*str != *prefix)
|
||||
return (unsigned char)*prefix - (unsigned char)*str;
|
||||
}
|
||||
|
||||
#endif /* __SUBCMD_UTIL_H */
|
@ -36,7 +36,10 @@ paths += -DPERF_MAN_PATH="BUILD_STR($(mandir_SQ))"
|
||||
|
||||
CFLAGS_builtin-help.o += $(paths)
|
||||
CFLAGS_builtin-timechart.o += $(paths)
|
||||
CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" -include $(OUTPUT)PERF-VERSION-FILE
|
||||
CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \
|
||||
-DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" \
|
||||
-DPREFIX="BUILD_STR($(prefix_SQ))" \
|
||||
-include $(OUTPUT)PERF-VERSION-FILE
|
||||
CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
|
||||
|
||||
libperf-y += util/
|
||||
|
@ -207,11 +207,23 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
|
||||
In per-thread mode with inheritance mode on (default), samples are captured only when
|
||||
the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||
|
||||
-B::
|
||||
--no-buildid::
|
||||
Do not save the build ids of binaries in the perf.data files. This skips
|
||||
post processing after recording, which sometimes makes the final step in
|
||||
the recording process to take a long time, as it needs to process all
|
||||
events looking for mmap records. The downside is that it can misresolve
|
||||
symbols if the workload binaries used when recording get locally rebuilt
|
||||
or upgraded, because the only key available in this case is the
|
||||
pathname. You can also set the "record.build-id" config variable to
|
||||
'skip to have this behaviour permanently.
|
||||
|
||||
-N::
|
||||
--no-buildid-cache::
|
||||
Do not update the buildid cache. This saves some overhead in situations
|
||||
where the information in the perf.data file (which includes buildids)
|
||||
is sufficient.
|
||||
is sufficient. You can also set the "record.build-id" config variable to
|
||||
'no-cache' to have the same effect.
|
||||
|
||||
-G name,...::
|
||||
--cgroup name,...::
|
||||
@ -314,11 +326,17 @@ This option sets the time out limit. The default value is 500 ms.
|
||||
Record context switch events i.e. events of type PERF_RECORD_SWITCH or
|
||||
PERF_RECORD_SWITCH_CPU_WIDE.
|
||||
|
||||
--clang-path::
|
||||
--clang-path=PATH::
|
||||
Path to clang binary to use for compiling BPF scriptlets.
|
||||
(enabled when BPF support is on)
|
||||
|
||||
--clang-opt::
|
||||
--clang-opt=OPTIONS::
|
||||
Options passed to clang when compiling BPF scriptlets.
|
||||
(enabled when BPF support is on)
|
||||
|
||||
--vmlinux=PATH::
|
||||
Specify vmlinux path which has debuginfo.
|
||||
(enabled when BPF prologue is on)
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
@ -20,6 +20,7 @@ tools/lib/traceevent
|
||||
tools/lib/bpf
|
||||
tools/lib/api
|
||||
tools/lib/bpf
|
||||
tools/lib/subcmd
|
||||
tools/lib/hweight.c
|
||||
tools/lib/rbtree.c
|
||||
tools/lib/string.c
|
||||
|
@ -145,9 +145,10 @@ BISON = bison
|
||||
STRIP = strip
|
||||
AWK = awk
|
||||
|
||||
LIB_DIR = $(srctree)/tools/lib/api/
|
||||
LIB_DIR = $(srctree)/tools/lib/api/
|
||||
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
|
||||
BPF_DIR = $(srctree)/tools/lib/bpf/
|
||||
BPF_DIR = $(srctree)/tools/lib/bpf/
|
||||
SUBCMD_DIR = $(srctree)/tools/lib/subcmd/
|
||||
|
||||
# include config/Makefile by default and rule out
|
||||
# non-config cases
|
||||
@ -184,15 +185,17 @@ strip-libs = $(filter-out -l%,$(1))
|
||||
ifneq ($(OUTPUT),)
|
||||
TE_PATH=$(OUTPUT)
|
||||
BPF_PATH=$(OUTPUT)
|
||||
SUBCMD_PATH=$(OUTPUT)
|
||||
ifneq ($(subdir),)
|
||||
LIB_PATH=$(OUTPUT)/../lib/api/
|
||||
API_PATH=$(OUTPUT)/../lib/api/
|
||||
else
|
||||
LIB_PATH=$(OUTPUT)
|
||||
API_PATH=$(OUTPUT)
|
||||
endif
|
||||
else
|
||||
TE_PATH=$(TRACE_EVENT_DIR)
|
||||
LIB_PATH=$(LIB_DIR)
|
||||
API_PATH=$(LIB_DIR)
|
||||
BPF_PATH=$(BPF_DIR)
|
||||
SUBCMD_PATH=$(SUBCMD_DIR)
|
||||
endif
|
||||
|
||||
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
|
||||
@ -201,11 +204,13 @@ export LIBTRACEEVENT
|
||||
LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
|
||||
LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST)
|
||||
|
||||
LIBAPI = $(LIB_PATH)libapi.a
|
||||
LIBAPI = $(API_PATH)libapi.a
|
||||
export LIBAPI
|
||||
|
||||
LIBBPF = $(BPF_PATH)libbpf.a
|
||||
|
||||
LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a
|
||||
|
||||
# python extension build directories
|
||||
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
|
||||
PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
|
||||
@ -257,7 +262,7 @@ export PERL_PATH
|
||||
|
||||
LIB_FILE=$(OUTPUT)libperf.a
|
||||
|
||||
PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT)
|
||||
PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
|
||||
ifndef NO_LIBBPF
|
||||
PERFLIBS += $(LIBBPF)
|
||||
endif
|
||||
@ -437,6 +442,13 @@ $(LIBBPF)-clean:
|
||||
$(call QUIET_CLEAN, libbpf)
|
||||
$(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
|
||||
$(LIBSUBCMD): fixdep FORCE
|
||||
$(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a
|
||||
|
||||
$(LIBSUBCMD)-clean:
|
||||
$(call QUIET_CLEAN, libsubcmd)
|
||||
$(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) clean
|
||||
|
||||
help:
|
||||
@echo 'Perf make targets:'
|
||||
@echo ' doc - make *all* documentation (see below)'
|
||||
@ -582,15 +594,16 @@ $(INSTALL_DOC_TARGETS):
|
||||
#
|
||||
config-clean:
|
||||
$(call QUIET_CLEAN, config)
|
||||
$(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null
|
||||
$(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
|
||||
|
||||
clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean config-clean
|
||||
clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean
|
||||
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
|
||||
$(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
|
||||
$(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
|
||||
$(Q)$(RM) $(OUTPUT).config-detected
|
||||
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
|
||||
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
|
||||
$(OUTPUT)util/intel-pt-decoder/inat-tables.c
|
||||
$(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
|
||||
$(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
|
||||
$(python-clean)
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "../../util/evlist.h"
|
||||
#include "../../util/evsel.h"
|
||||
#include "../../util/cpumap.h"
|
||||
#include "../../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../../util/parse-events.h"
|
||||
#include "../../util/pmu.h"
|
||||
#include "../../util/debug.h"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/stat.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../util/header.h"
|
||||
#include "bench.h"
|
||||
#include "futex.h"
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/stat.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../util/header.h"
|
||||
#include "bench.h"
|
||||
#include "futex.h"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/stat.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../util/header.h"
|
||||
#include "bench.h"
|
||||
#include "futex.h"
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/stat.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../util/header.h"
|
||||
#include "bench.h"
|
||||
#include "futex.h"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/stat.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../util/header.h"
|
||||
#include "bench.h"
|
||||
#include "futex.h"
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../util/header.h"
|
||||
#include "../util/cloexec.h"
|
||||
#include "bench.h"
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "../perf.h"
|
||||
#include "../builtin.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../util/cloexec.h"
|
||||
|
||||
#include "bench.h"
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../builtin.h"
|
||||
#include "bench.h"
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
#include "../perf.h"
|
||||
#include "../util/util.h"
|
||||
#include "../util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "../builtin.h"
|
||||
#include "bench.h"
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "util/evsel.h"
|
||||
#include "util/annotate.h"
|
||||
#include "util/event.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-events.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/sort.h"
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
#include "perf.h"
|
||||
#include "util/util.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "builtin.h"
|
||||
#include "bench/bench.h"
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "util/cache.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/header.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/strlist.h"
|
||||
#include "util/build-id.h"
|
||||
#include "util/session.h"
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "util/build-id.h"
|
||||
#include "util/cache.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/data.h"
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "perf.h"
|
||||
|
||||
#include "util/cache.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/util.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "builtin.h"
|
||||
#include "perf.h"
|
||||
#include "debug.h"
|
||||
#include "parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "data-convert-bt.h"
|
||||
|
||||
typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/parse-events.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/session.h"
|
||||
#include "util/data.h"
|
||||
#include "util/debug.h"
|
||||
|
@ -6,11 +6,11 @@
|
||||
#include "perf.h"
|
||||
#include "util/cache.h"
|
||||
#include "builtin.h"
|
||||
#include "util/exec_cmd.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "common-cmds.h"
|
||||
#include "util/parse-options.h"
|
||||
#include "util/run-command.h"
|
||||
#include "util/help.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include <subcmd/run-command.h>
|
||||
#include <subcmd/help.h>
|
||||
#include "util/debug.h"
|
||||
|
||||
static struct man_viewer_list {
|
||||
@ -407,7 +407,7 @@ static int get_html_page_path(struct strbuf *page_path, const char *page)
|
||||
#ifndef open_html
|
||||
static void open_html(const char *path)
|
||||
{
|
||||
execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL);
|
||||
execl_cmd("web--browse", "-c", "help.browser", path, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "util/data.h"
|
||||
#include "util/auxtrace.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "util/tool.h"
|
||||
#include "util/callchain.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/trace-event.h"
|
||||
#include "util/data.h"
|
||||
#include "util/cpumap.h"
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "util/header.h"
|
||||
#include "util/session.h"
|
||||
#include "util/intlist.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/trace-event.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/tool.h"
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "util/parse-events.h"
|
||||
#include "util/cache.h"
|
||||
#include "util/pmu.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
|
||||
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "util/thread.h"
|
||||
#include "util/header.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/trace-event.h"
|
||||
|
||||
#include "util/debug.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "builtin.h"
|
||||
#include "perf.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/trace-event.h"
|
||||
#include "util/tool.h"
|
||||
#include "util/session.h"
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "util/strfilter.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/probe-finder.h"
|
||||
#include "util/probe-event.h"
|
||||
#include "util/probe-file.h"
|
||||
@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
# define opt_show_lines NULL
|
||||
# define opt_show_vars NULL
|
||||
#endif
|
||||
static int opt_add_probe_event(const struct option *opt,
|
||||
const char *str, int unset __maybe_unused)
|
||||
@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
opt_add_probe_event),
|
||||
OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
|
||||
" with existing name"),
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
OPT_CALLBACK('L', "line", NULL,
|
||||
"FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
|
||||
"Show source code lines.", opt_show_lines),
|
||||
@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"directory", "path to kernel source"),
|
||||
OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
|
||||
"Don't search inlined functions"),
|
||||
#endif
|
||||
OPT__DRY_RUN(&probe_event_dry_run),
|
||||
OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
|
||||
"Set how many probe points can be found for a probe."),
|
||||
@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
#ifdef HAVE_DWARF_SUPPORT
|
||||
set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
|
||||
set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
|
||||
#else
|
||||
# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
|
||||
set_nobuild('L', "line", false);
|
||||
set_nobuild('V', "vars", false);
|
||||
set_nobuild('\0', "externs", false);
|
||||
set_nobuild('\0', "range", false);
|
||||
set_nobuild('k', "vmlinux", true);
|
||||
set_nobuild('s', "source", true);
|
||||
set_nobuild('\0', "no-inlines", true);
|
||||
# undef set_nobuild
|
||||
#endif
|
||||
set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "util/build-id.h"
|
||||
#include "util/util.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-events.h"
|
||||
|
||||
#include "util/callchain.h"
|
||||
@ -837,6 +837,19 @@ int record_callchain_opt(const struct option *opt,
|
||||
|
||||
static int perf_record_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
struct record *rec = cb;
|
||||
|
||||
if (!strcmp(var, "record.build-id")) {
|
||||
if (!strcmp(value, "cache"))
|
||||
rec->no_buildid_cache = false;
|
||||
else if (!strcmp(value, "no-cache"))
|
||||
rec->no_buildid_cache = true;
|
||||
else if (!strcmp(value, "skip"))
|
||||
rec->no_buildid = true;
|
||||
else
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "record.call-graph"))
|
||||
var = "call-graph.record-mode"; /* fall-through */
|
||||
|
||||
@ -1113,12 +1126,12 @@ struct option __record_options[] = {
|
||||
"per thread proc mmap processing timeout in ms"),
|
||||
OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
|
||||
"Record context switch events"),
|
||||
#ifdef HAVE_LIBBPF_SUPPORT
|
||||
OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
|
||||
"clang binary to use for compiling BPF scriptlets"),
|
||||
OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
|
||||
"options passed to clang when compiling BPF scriptlets"),
|
||||
#endif
|
||||
OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
|
||||
"file", "vmlinux pathname"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@ -1130,6 +1143,27 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
struct record *rec = &record;
|
||||
char errbuf[BUFSIZ];
|
||||
|
||||
#ifndef HAVE_LIBBPF_SUPPORT
|
||||
# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
|
||||
set_nobuild('\0', "clang-path", true);
|
||||
set_nobuild('\0', "clang-opt", true);
|
||||
# undef set_nobuild
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_BPF_PROLOGUE
|
||||
# if !defined (HAVE_DWARF_SUPPORT)
|
||||
# define REASON "NO_DWARF=1"
|
||||
# elif !defined (HAVE_LIBBPF_SUPPORT)
|
||||
# define REASON "NO_LIBBPF=1"
|
||||
# else
|
||||
# define REASON "this architecture doesn't support BPF prologue"
|
||||
# endif
|
||||
# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
|
||||
set_nobuild('\0', "vmlinux", true);
|
||||
# undef set_nobuild
|
||||
# undef REASON
|
||||
#endif
|
||||
|
||||
rec->evlist = perf_evlist__new();
|
||||
if (rec->evlist == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-events.h"
|
||||
|
||||
#include "util/thread.h"
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "util/tool.h"
|
||||
#include "util/cloexec.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/trace-event.h"
|
||||
|
||||
#include "util/debug.h"
|
||||
|
@ -3,9 +3,9 @@
|
||||
#include "perf.h"
|
||||
#include "util/cache.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/exec_cmd.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "util/header.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/perf_regs.h"
|
||||
#include "util/session.h"
|
||||
#include "util/tool.h"
|
||||
@ -1408,7 +1408,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
|
||||
char first_half[BUFSIZ];
|
||||
char *script_root;
|
||||
|
||||
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
|
||||
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
|
||||
|
||||
scripts_dir = opendir(scripts_path);
|
||||
if (!scripts_dir)
|
||||
@ -1529,7 +1529,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
|
||||
if (!session)
|
||||
return -1;
|
||||
|
||||
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
|
||||
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
|
||||
|
||||
scripts_dir = opendir(scripts_path);
|
||||
if (!scripts_dir) {
|
||||
@ -1587,7 +1587,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
|
||||
char lang_path[MAXPATHLEN];
|
||||
char *__script_root;
|
||||
|
||||
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
|
||||
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
|
||||
|
||||
scripts_dir = opendir(scripts_path);
|
||||
if (!scripts_dir)
|
||||
@ -1823,7 +1823,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
scripting_max_stack = itrace_synth_opts.callchain_sz;
|
||||
|
||||
/* make sure PERF_EXEC_PATH is set for scripts */
|
||||
perf_set_argv_exec_path(perf_exec_path());
|
||||
set_argv_exec_path(get_argv_exec_path());
|
||||
|
||||
if (argc && !script_name && !rec_script_path && !rep_script_path) {
|
||||
int live_pipe[2];
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include "builtin.h"
|
||||
#include "util/cgroup.h"
|
||||
#include "util/util.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-events.h"
|
||||
#include "util/pmu.h"
|
||||
#include "util/event.h"
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include "perf.h"
|
||||
#include "util/header.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-events.h"
|
||||
#include "util/event.h"
|
||||
#include "util/session.h"
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include "util/top.h"
|
||||
#include "util/util.h"
|
||||
#include <linux/rbtree.h>
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-events.h"
|
||||
#include "util/cpumap.h"
|
||||
#include "util/xyarray.h"
|
||||
|
@ -22,11 +22,11 @@
|
||||
#include "util/color.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/evlist.h"
|
||||
#include "util/exec_cmd.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "util/machine.h"
|
||||
#include "util/session.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/strlist.h"
|
||||
#include "util/intlist.h"
|
||||
#include "util/thread_map.h"
|
||||
|
@ -9,12 +9,12 @@
|
||||
#include "builtin.h"
|
||||
|
||||
#include "util/env.h"
|
||||
#include "util/exec_cmd.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "util/cache.h"
|
||||
#include "util/quote.h"
|
||||
#include "util/run-command.h"
|
||||
#include <subcmd/run-command.h>
|
||||
#include "util/parse-events.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/bpf-loader.h"
|
||||
#include "util/debug.h"
|
||||
#include <api/fs/tracing_path.h>
|
||||
@ -119,7 +119,7 @@ static void commit_pager_choice(void)
|
||||
{
|
||||
switch (use_pager) {
|
||||
case 0:
|
||||
setenv("PERF_PAGER", "cat", 1);
|
||||
setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
|
||||
break;
|
||||
case 1:
|
||||
/* setup_pager(); */
|
||||
@ -183,9 +183,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
|
||||
if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
|
||||
cmd += strlen(CMD_EXEC_PATH);
|
||||
if (*cmd == '=')
|
||||
perf_set_argv_exec_path(cmd + 1);
|
||||
set_argv_exec_path(cmd + 1);
|
||||
else {
|
||||
puts(perf_exec_path());
|
||||
puts(get_argv_exec_path());
|
||||
exit(0);
|
||||
}
|
||||
} else if (!strcmp(cmd, "--html-path")) {
|
||||
@ -530,11 +530,15 @@ int main(int argc, const char **argv)
|
||||
const char *cmd;
|
||||
char sbuf[STRERR_BUFSIZE];
|
||||
|
||||
/* libsubcmd init */
|
||||
exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
|
||||
pager_init(PERF_PAGER_ENVIRONMENT);
|
||||
|
||||
/* The page_size is placed in util object. */
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
|
||||
|
||||
cmd = perf_extract_argv0_path(argv[0]);
|
||||
cmd = extract_argv0_path(argv[0]);
|
||||
if (!cmd)
|
||||
cmd = "perf-help";
|
||||
|
||||
|
@ -35,21 +35,21 @@ perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o
|
||||
perf-y += bpf.o
|
||||
perf-y += topology.o
|
||||
|
||||
$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
|
||||
$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
|
||||
$(call rule_mkdir)
|
||||
$(Q)echo '#include <tests/llvm.h>' > $@
|
||||
$(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
|
||||
$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
|
||||
$(Q)echo ';' >> $@
|
||||
|
||||
$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c
|
||||
$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c tests/Build
|
||||
$(call rule_mkdir)
|
||||
$(Q)echo '#include <tests/llvm.h>' > $@
|
||||
$(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
|
||||
$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
|
||||
$(Q)echo ';' >> $@
|
||||
|
||||
$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c
|
||||
$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
|
||||
$(call rule_mkdir)
|
||||
$(Q)echo '#include <tests/llvm.h>' > $@
|
||||
$(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include "../perf.h"
|
||||
#include "util.h"
|
||||
#include "exec_cmd.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "tests.h"
|
||||
|
||||
#define ENV "PERF_TEST_ATTR"
|
||||
@ -164,7 +164,7 @@ int test__attr(int subtest __maybe_unused)
|
||||
return run_dir("./tests", "./perf");
|
||||
|
||||
/* Then installed path. */
|
||||
snprintf(path_dir, PATH_MAX, "%s/tests", perf_exec_path());
|
||||
snprintf(path_dir, PATH_MAX, "%s/tests", get_argv_exec_path());
|
||||
snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
|
||||
|
||||
if (!lstat(path_dir, &st) &&
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "tests.h"
|
||||
#include "debug.h"
|
||||
#include "color.h"
|
||||
#include "parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "symbol.h"
|
||||
|
||||
struct test __weak arch_tests[] = {
|
||||
@ -236,6 +236,9 @@ static int run_test(struct test *test, int subtest)
|
||||
dup2(STDOUT_FILENO, STDERR_FILENO);
|
||||
close(nullfd);
|
||||
}
|
||||
} else {
|
||||
signal(SIGSEGV, sighandler_dump_stack);
|
||||
signal(SIGFPE, sighandler_dump_stack);
|
||||
}
|
||||
|
||||
err = test->func(subtest);
|
||||
|
@ -88,8 +88,8 @@ struct machine *setup_fake_machine(struct machines *machines)
|
||||
}
|
||||
|
||||
if (machine__create_kernel_maps(machine)) {
|
||||
pr_debug("Not enough memory for machine setup\n");
|
||||
goto out;
|
||||
pr_debug("Cannot create kernel maps\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
|
||||
@ -155,7 +155,6 @@ struct machine *setup_fake_machine(struct machines *machines)
|
||||
out:
|
||||
pr_debug("Not enough memory for machine setup\n");
|
||||
machine__delete_threads(machine);
|
||||
machine__delete(machine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -259,7 +259,8 @@ $(run_O):
|
||||
tarpkg:
|
||||
@cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
|
||||
echo "- $@: $$cmd" && echo $$cmd > $@ && \
|
||||
( eval $$cmd ) >> $@ 2>&1
|
||||
( eval $$cmd ) >> $@ 2>&1 && \
|
||||
rm -f $@
|
||||
|
||||
make_kernelsrc:
|
||||
@echo "- make -C <kernelsrc> tools/perf"
|
||||
|
@ -9,13 +9,10 @@ libperf-y += env.o
|
||||
libperf-y += event.o
|
||||
libperf-y += evlist.o
|
||||
libperf-y += evsel.o
|
||||
libperf-y += exec_cmd.o
|
||||
libperf-y += find_next_bit.o
|
||||
libperf-y += help.o
|
||||
libperf-y += kallsyms.o
|
||||
libperf-y += levenshtein.o
|
||||
libperf-y += llvm-utils.o
|
||||
libperf-y += parse-options.o
|
||||
libperf-y += parse-events.o
|
||||
libperf-y += perf_regs.o
|
||||
libperf-y += path.o
|
||||
@ -23,7 +20,6 @@ libperf-y += rbtree.o
|
||||
libperf-y += libstring.o
|
||||
libperf-y += bitmap.o
|
||||
libperf-y += hweight.o
|
||||
libperf-y += run-command.o
|
||||
libperf-y += quote.o
|
||||
libperf-y += strbuf.o
|
||||
libperf-y += string.o
|
||||
@ -32,11 +28,9 @@ libperf-y += strfilter.o
|
||||
libperf-y += top.o
|
||||
libperf-y += usage.o
|
||||
libperf-y += wrapper.o
|
||||
libperf-y += sigchain.o
|
||||
libperf-y += dso.o
|
||||
libperf-y += symbol.o
|
||||
libperf-y += color.o
|
||||
libperf-y += pager.o
|
||||
libperf-y += header.o
|
||||
libperf-y += callchain.o
|
||||
libperf-y += values.o
|
||||
@ -87,6 +81,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-bts.o
|
||||
libperf-y += parse-branch-options.o
|
||||
libperf-y += parse-regs-options.o
|
||||
libperf-y += term.o
|
||||
libperf-y += help-unknown-cmd.o
|
||||
|
||||
libperf-$(CONFIG_LIBBPF) += bpf-loader.o
|
||||
libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
|
||||
@ -112,7 +107,6 @@ libperf-$(CONFIG_ZLIB) += zlib.o
|
||||
libperf-$(CONFIG_LZMA) += lzma.o
|
||||
|
||||
CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
|
||||
CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
|
||||
|
||||
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
|
||||
$(call rule_mkdir)
|
||||
|
@ -45,7 +45,7 @@
|
||||
#include "event.h"
|
||||
#include "session.h"
|
||||
#include "debug.h"
|
||||
#include "parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
|
||||
#include "intel-pt.h"
|
||||
#include "intel-bts.h"
|
||||
|
@ -4,9 +4,12 @@
|
||||
#include <stdbool.h>
|
||||
#include "util.h"
|
||||
#include "strbuf.h"
|
||||
#include <subcmd/pager.h>
|
||||
#include "../perf.h"
|
||||
#include "../ui/ui.h"
|
||||
|
||||
#include <linux/string.h>
|
||||
|
||||
#define CMD_EXEC_PATH "--exec-path"
|
||||
#define CMD_PERF_DIR "--perf-dir="
|
||||
#define CMD_WORK_TREE "--work-tree="
|
||||
@ -18,6 +21,7 @@
|
||||
#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
|
||||
#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
|
||||
#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
|
||||
#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
|
||||
|
||||
typedef int (*config_fn_t)(const char *, const char *, void *);
|
||||
extern int perf_default_config(const char *, const char *, void *);
|
||||
@ -28,10 +32,6 @@ extern int perf_config_bool(const char *, const char *);
|
||||
extern int config_error_nonbool(const char *);
|
||||
extern const char *perf_config_dirname(const char *, const char *);
|
||||
|
||||
/* pager.c */
|
||||
extern void setup_pager(void);
|
||||
extern int pager_in_use(void);
|
||||
|
||||
char *alias_lookup(const char *alias);
|
||||
int split_cmdline(char *cmdline, const char ***argv);
|
||||
|
||||
@ -70,9 +70,4 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
|
||||
extern char *perf_pathdup(const char *fmt, ...)
|
||||
__attribute__((format (printf, 1, 2)));
|
||||
|
||||
#ifndef __UCLIBC__
|
||||
/* Matches the libc/libbsd function attribute so we declare this unconditionally: */
|
||||
extern size_t strlcpy(char *dest, const char *src, size_t size);
|
||||
#endif
|
||||
|
||||
#endif /* __PERF_CACHE_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "util.h"
|
||||
#include "../perf.h"
|
||||
#include "parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "evsel.h"
|
||||
#include "cgroup.h"
|
||||
#include "evlist.h"
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
#include "util.h"
|
||||
#include "cache.h"
|
||||
#include "exec_cmd.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "util/hist.h" /* perf_hist_config */
|
||||
#include "util/llvm-utils.h" /* perf_llvm_config */
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "parse-events.h"
|
||||
#include "parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
|
@ -36,6 +36,7 @@ static struct {
|
||||
bool cloexec;
|
||||
bool clockid;
|
||||
bool clockid_wrong;
|
||||
bool lbr_flags;
|
||||
} perf_missing_features;
|
||||
|
||||
static clockid_t clockid;
|
||||
@ -574,7 +575,9 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
|
||||
} else {
|
||||
perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
|
||||
attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
|
||||
PERF_SAMPLE_BRANCH_CALL_STACK;
|
||||
PERF_SAMPLE_BRANCH_CALL_STACK |
|
||||
PERF_SAMPLE_BRANCH_NO_CYCLES |
|
||||
PERF_SAMPLE_BRANCH_NO_FLAGS;
|
||||
}
|
||||
} else
|
||||
pr_warning("Cannot use LBR callstack with branch stack. "
|
||||
@ -1337,6 +1340,9 @@ fallback_missing_features:
|
||||
evsel->attr.mmap2 = 0;
|
||||
if (perf_missing_features.exclude_guest)
|
||||
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
|
||||
if (perf_missing_features.lbr_flags)
|
||||
evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
|
||||
PERF_SAMPLE_BRANCH_NO_CYCLES);
|
||||
retry_sample_id:
|
||||
if (perf_missing_features.sample_id_all)
|
||||
evsel->attr.sample_id_all = 0;
|
||||
@ -1455,6 +1461,12 @@ try_fallback:
|
||||
} else if (!perf_missing_features.sample_id_all) {
|
||||
perf_missing_features.sample_id_all = true;
|
||||
goto retry_sample_id;
|
||||
} else if (!perf_missing_features.lbr_flags &&
|
||||
(evsel->attr.branch_sample_type &
|
||||
(PERF_SAMPLE_BRANCH_NO_CYCLES |
|
||||
PERF_SAMPLE_BRANCH_NO_FLAGS))) {
|
||||
perf_missing_features.lbr_flags = true;
|
||||
goto fallback_missing_features;
|
||||
}
|
||||
|
||||
out_close:
|
||||
|
@ -1,149 +0,0 @@
|
||||
#include "cache.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "quote.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_ARGS 32
|
||||
|
||||
static const char *argv_exec_path;
|
||||
static const char *argv0_path;
|
||||
|
||||
char *system_path(const char *path)
|
||||
{
|
||||
static const char *prefix = PREFIX;
|
||||
struct strbuf d = STRBUF_INIT;
|
||||
|
||||
if (is_absolute_path(path))
|
||||
return strdup(path);
|
||||
|
||||
strbuf_addf(&d, "%s/%s", prefix, path);
|
||||
path = strbuf_detach(&d, NULL);
|
||||
return (char *)path;
|
||||
}
|
||||
|
||||
const char *perf_extract_argv0_path(const char *argv0)
|
||||
{
|
||||
const char *slash;
|
||||
|
||||
if (!argv0 || !*argv0)
|
||||
return NULL;
|
||||
slash = argv0 + strlen(argv0);
|
||||
|
||||
while (argv0 <= slash && !is_dir_sep(*slash))
|
||||
slash--;
|
||||
|
||||
if (slash >= argv0) {
|
||||
argv0_path = strndup(argv0, slash - argv0);
|
||||
return argv0_path ? slash + 1 : NULL;
|
||||
}
|
||||
|
||||
return argv0;
|
||||
}
|
||||
|
||||
void perf_set_argv_exec_path(const char *exec_path)
|
||||
{
|
||||
argv_exec_path = exec_path;
|
||||
/*
|
||||
* Propagate this setting to external programs.
|
||||
*/
|
||||
setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Returns the highest-priority, location to look for perf programs. */
|
||||
char *perf_exec_path(void)
|
||||
{
|
||||
char *env;
|
||||
|
||||
if (argv_exec_path)
|
||||
return strdup(argv_exec_path);
|
||||
|
||||
env = getenv(EXEC_PATH_ENVIRONMENT);
|
||||
if (env && *env)
|
||||
return strdup(env);
|
||||
|
||||
return system_path(PERF_EXEC_PATH);
|
||||
}
|
||||
|
||||
static void add_path(struct strbuf *out, const char *path)
|
||||
{
|
||||
if (path && *path) {
|
||||
if (is_absolute_path(path))
|
||||
strbuf_addstr(out, path);
|
||||
else
|
||||
strbuf_addstr(out, make_nonrelative_path(path));
|
||||
|
||||
strbuf_addch(out, PATH_SEP);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_path(void)
|
||||
{
|
||||
const char *old_path = getenv("PATH");
|
||||
struct strbuf new_path = STRBUF_INIT;
|
||||
char *tmp = perf_exec_path();
|
||||
|
||||
add_path(&new_path, tmp);
|
||||
add_path(&new_path, argv0_path);
|
||||
free(tmp);
|
||||
|
||||
if (old_path)
|
||||
strbuf_addstr(&new_path, old_path);
|
||||
else
|
||||
strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
|
||||
|
||||
setenv("PATH", new_path.buf, 1);
|
||||
|
||||
strbuf_release(&new_path);
|
||||
}
|
||||
|
||||
static const char **prepare_perf_cmd(const char **argv)
|
||||
{
|
||||
int argc;
|
||||
const char **nargv;
|
||||
|
||||
for (argc = 0; argv[argc]; argc++)
|
||||
; /* just counting */
|
||||
nargv = malloc(sizeof(*nargv) * (argc + 2));
|
||||
|
||||
nargv[0] = "perf";
|
||||
for (argc = 0; argv[argc]; argc++)
|
||||
nargv[argc + 1] = argv[argc];
|
||||
nargv[argc + 1] = NULL;
|
||||
return nargv;
|
||||
}
|
||||
|
||||
int execv_perf_cmd(const char **argv) {
|
||||
const char **nargv = prepare_perf_cmd(argv);
|
||||
|
||||
/* execvp() can only ever return if it fails */
|
||||
execvp("perf", (char **)nargv);
|
||||
|
||||
free(nargv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int execl_perf_cmd(const char *cmd,...)
|
||||
{
|
||||
int argc;
|
||||
const char *argv[MAX_ARGS + 1];
|
||||
const char *arg;
|
||||
va_list param;
|
||||
|
||||
va_start(param, cmd);
|
||||
argv[0] = cmd;
|
||||
argc = 1;
|
||||
while (argc < MAX_ARGS) {
|
||||
arg = argv[argc++] = va_arg(param, char *);
|
||||
if (!arg)
|
||||
break;
|
||||
}
|
||||
va_end(param);
|
||||
if (MAX_ARGS <= argc)
|
||||
return error("too many args to run %s", cmd);
|
||||
|
||||
argv[argc] = NULL;
|
||||
return execv_perf_cmd(argv);
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#ifndef __PERF_EXEC_CMD_H
|
||||
#define __PERF_EXEC_CMD_H
|
||||
|
||||
extern void perf_set_argv_exec_path(const char *exec_path);
|
||||
extern const char *perf_extract_argv0_path(const char *path);
|
||||
extern void setup_path(void);
|
||||
extern int execv_perf_cmd(const char **argv); /* NULL terminated */
|
||||
extern int execl_perf_cmd(const char *cmd, ...);
|
||||
/* perf_exec_path and system_path return malloc'd string, caller must free it */
|
||||
extern char *perf_exec_path(void);
|
||||
extern char *system_path(const char *path);
|
||||
|
||||
#endif /* __PERF_EXEC_CMD_H */
|
103
tools/perf/util/help-unknown-cmd.c
Normal file
103
tools/perf/util/help-unknown-cmd.c
Normal file
@ -0,0 +1,103 @@
|
||||
#include "cache.h"
|
||||
#include <subcmd/help.h>
|
||||
#include "../builtin.h"
|
||||
#include "levenshtein.h"
|
||||
|
||||
static int autocorrect;
|
||||
static struct cmdnames aliases;
|
||||
|
||||
static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcmp(var, "help.autocorrect"))
|
||||
autocorrect = perf_config_int(var,value);
|
||||
/* Also use aliases for command lookup */
|
||||
if (!prefixcmp(var, "alias."))
|
||||
add_cmdname(&aliases, var + 6, strlen(var + 6));
|
||||
|
||||
return perf_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
static int levenshtein_compare(const void *p1, const void *p2)
|
||||
{
|
||||
const struct cmdname *const *c1 = p1, *const *c2 = p2;
|
||||
const char *s1 = (*c1)->name, *s2 = (*c2)->name;
|
||||
int l1 = (*c1)->len;
|
||||
int l2 = (*c2)->len;
|
||||
return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
|
||||
}
|
||||
|
||||
static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
|
||||
|
||||
for (i = 0; i < old->cnt; i++)
|
||||
cmds->names[cmds->cnt++] = old->names[i];
|
||||
zfree(&old->names);
|
||||
old->cnt = 0;
|
||||
}
|
||||
|
||||
const char *help_unknown_cmd(const char *cmd)
|
||||
{
|
||||
unsigned int i, n = 0, best_similarity = 0;
|
||||
struct cmdnames main_cmds, other_cmds;
|
||||
|
||||
memset(&main_cmds, 0, sizeof(main_cmds));
|
||||
memset(&other_cmds, 0, sizeof(main_cmds));
|
||||
memset(&aliases, 0, sizeof(aliases));
|
||||
|
||||
perf_config(perf_unknown_cmd_config, NULL);
|
||||
|
||||
load_command_list("perf-", &main_cmds, &other_cmds);
|
||||
|
||||
add_cmd_list(&main_cmds, &aliases);
|
||||
add_cmd_list(&main_cmds, &other_cmds);
|
||||
qsort(main_cmds.names, main_cmds.cnt,
|
||||
sizeof(main_cmds.names), cmdname_compare);
|
||||
uniq(&main_cmds);
|
||||
|
||||
if (main_cmds.cnt) {
|
||||
/* This reuses cmdname->len for similarity index */
|
||||
for (i = 0; i < main_cmds.cnt; ++i)
|
||||
main_cmds.names[i]->len =
|
||||
levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
|
||||
|
||||
qsort(main_cmds.names, main_cmds.cnt,
|
||||
sizeof(*main_cmds.names), levenshtein_compare);
|
||||
|
||||
best_similarity = main_cmds.names[0]->len;
|
||||
n = 1;
|
||||
while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
|
||||
++n;
|
||||
}
|
||||
|
||||
if (autocorrect && n == 1) {
|
||||
const char *assumed = main_cmds.names[0]->name;
|
||||
|
||||
main_cmds.names[0] = NULL;
|
||||
clean_cmdnames(&main_cmds);
|
||||
fprintf(stderr, "WARNING: You called a perf program named '%s', "
|
||||
"which does not exist.\n"
|
||||
"Continuing under the assumption that you meant '%s'\n",
|
||||
cmd, assumed);
|
||||
if (autocorrect > 0) {
|
||||
fprintf(stderr, "in %0.1f seconds automatically...\n",
|
||||
(float)autocorrect/10.0);
|
||||
poll(NULL, 0, autocorrect * 100);
|
||||
}
|
||||
return assumed;
|
||||
}
|
||||
|
||||
fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
|
||||
|
||||
if (main_cmds.cnt && best_similarity < 6) {
|
||||
fprintf(stderr, "\nDid you mean %s?\n",
|
||||
n < 2 ? "this": "one of these");
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
0
tools/perf/util/help-unknown-cmd.h
Normal file
0
tools/perf/util/help-unknown-cmd.h
Normal file
@ -1744,7 +1744,7 @@ static void intel_pt_free(struct perf_session *session)
|
||||
auxtrace_heap__free(&pt->heap);
|
||||
intel_pt_free_events(session);
|
||||
session->auxtrace = NULL;
|
||||
thread__delete(pt->unknown_thread);
|
||||
thread__put(pt->unknown_thread);
|
||||
free(pt);
|
||||
}
|
||||
|
||||
@ -2153,7 +2153,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
|
||||
return 0;
|
||||
|
||||
err_delete_thread:
|
||||
thread__delete(pt->unknown_thread);
|
||||
thread__zput(pt->unknown_thread);
|
||||
err_free_queues:
|
||||
intel_pt_log_disable();
|
||||
auxtrace_queues__free(&pt->queues);
|
||||
|
@ -352,13 +352,18 @@ static void machine__update_thread_pid(struct machine *machine,
|
||||
}
|
||||
|
||||
th->mg = map_groups__get(leader->mg);
|
||||
|
||||
out_put:
|
||||
thread__put(leader);
|
||||
return;
|
||||
|
||||
out_err:
|
||||
pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caller must eventually drop thread->refcnt returned with a successfull
|
||||
* lookup/new thread inserted.
|
||||
*/
|
||||
static struct thread *____machine__findnew_thread(struct machine *machine,
|
||||
pid_t pid, pid_t tid,
|
||||
bool create)
|
||||
@ -376,7 +381,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
||||
if (th != NULL) {
|
||||
if (th->tid == tid) {
|
||||
machine__update_thread_pid(machine, th, pid);
|
||||
return th;
|
||||
return thread__get(th);
|
||||
}
|
||||
|
||||
machine->last_match = NULL;
|
||||
@ -389,7 +394,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
||||
if (th->tid == tid) {
|
||||
machine->last_match = th;
|
||||
machine__update_thread_pid(machine, th, pid);
|
||||
return th;
|
||||
return thread__get(th);
|
||||
}
|
||||
|
||||
if (tid < th->tid)
|
||||
@ -417,7 +422,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
|
||||
if (thread__init_map_groups(th, machine)) {
|
||||
rb_erase_init(&th->rb_node, &machine->threads);
|
||||
RB_CLEAR_NODE(&th->rb_node);
|
||||
thread__delete(th);
|
||||
thread__put(th);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
@ -441,7 +446,7 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
|
||||
struct thread *th;
|
||||
|
||||
pthread_rwlock_wrlock(&machine->threads_lock);
|
||||
th = thread__get(__machine__findnew_thread(machine, pid, tid));
|
||||
th = __machine__findnew_thread(machine, pid, tid);
|
||||
pthread_rwlock_unlock(&machine->threads_lock);
|
||||
return th;
|
||||
}
|
||||
@ -451,7 +456,7 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
|
||||
{
|
||||
struct thread *th;
|
||||
pthread_rwlock_rdlock(&machine->threads_lock);
|
||||
th = thread__get(____machine__findnew_thread(machine, pid, tid, false));
|
||||
th = ____machine__findnew_thread(machine, pid, tid, false);
|
||||
pthread_rwlock_unlock(&machine->threads_lock);
|
||||
return th;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "perf.h"
|
||||
#include "util/util.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-branch-options.h"
|
||||
|
||||
#define BRANCH_OPT(n, m) \
|
||||
|
@ -4,9 +4,9 @@
|
||||
#include "../perf.h"
|
||||
#include "evlist.h"
|
||||
#include "evsel.h"
|
||||
#include "parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "parse-events.h"
|
||||
#include "exec_cmd.h"
|
||||
#include <subcmd/exec-cmd.h>
|
||||
#include "string.h"
|
||||
#include "symbol.h"
|
||||
#include "cache.h"
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "perf.h"
|
||||
#include "util/util.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "util/parse-regs-options.h"
|
||||
|
||||
int
|
||||
|
@ -22,24 +22,6 @@ static const char *get_perf_dir(void)
|
||||
return ".";
|
||||
}
|
||||
|
||||
/*
|
||||
* If libc has strlcpy() then that version will override this
|
||||
* implementation:
|
||||
*/
|
||||
size_t __weak strlcpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
size_t ret = strlen(src);
|
||||
|
||||
if (size) {
|
||||
size_t len = (ret >= size) ? size - 1 : ret;
|
||||
|
||||
memcpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *get_pathname(void)
|
||||
{
|
||||
static char pathname_array[4][PATH_MAX];
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "debug.h"
|
||||
#include "header.h"
|
||||
|
||||
#include "parse-options.h"
|
||||
#include <subcmd/parse-options.h>
|
||||
#include "parse-events.h"
|
||||
#include "hist.h"
|
||||
#include "thread.h"
|
||||
|
@ -19,8 +19,10 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
|
||||
thread->mg = map_groups__new(machine);
|
||||
} else {
|
||||
leader = __machine__findnew_thread(machine, pid, pid);
|
||||
if (leader)
|
||||
if (leader) {
|
||||
thread->mg = map_groups__get(leader->mg);
|
||||
thread__put(leader);
|
||||
}
|
||||
}
|
||||
|
||||
return thread->mg ? 0 : -1;
|
||||
@ -53,7 +55,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
|
||||
goto err_thread;
|
||||
|
||||
list_add(&comm->list, &thread->comm_list);
|
||||
atomic_set(&thread->refcnt, 0);
|
||||
atomic_set(&thread->refcnt, 1);
|
||||
RB_CLEAR_NODE(&thread->rb_node);
|
||||
}
|
||||
|
||||
@ -95,6 +97,10 @@ struct thread *thread__get(struct thread *thread)
|
||||
void thread__put(struct thread *thread)
|
||||
{
|
||||
if (thread && atomic_dec_and_test(&thread->refcnt)) {
|
||||
/*
|
||||
* Remove it from the dead_threads list, as last reference
|
||||
* is gone.
|
||||
*/
|
||||
list_del_init(&thread->node);
|
||||
thread__delete(thread);
|
||||
}
|
||||
|
@ -352,7 +352,8 @@ void sighandler_dump_stack(int sig)
|
||||
{
|
||||
psignal(sig, "perf");
|
||||
dump_stack();
|
||||
exit(sig);
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
int parse_nsec_time(const char *str, u64 *ptime)
|
||||
|
@ -151,12 +151,6 @@ extern void set_warning_routine(void (*routine)(const char *err, va_list params)
|
||||
extern int prefixcmp(const char *str, const char *prefix);
|
||||
extern void set_buildid_dir(const char *dir);
|
||||
|
||||
static inline const char *skip_prefix(const char *str, const char *prefix)
|
||||
{
|
||||
size_t len = strlen(prefix);
|
||||
return strncmp(str, prefix, len) ? NULL : str + len;
|
||||
}
|
||||
|
||||
#ifdef __GLIBC_PREREQ
|
||||
#if __GLIBC_PREREQ(2, 1)
|
||||
#define HAVE_STRCHRNUL
|
||||
@ -187,14 +181,6 @@ static inline void *zalloc(size_t size)
|
||||
|
||||
#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
|
||||
|
||||
static inline int has_extension(const char *filename, const char *ext)
|
||||
{
|
||||
size_t len = strlen(filename);
|
||||
size_t extlen = strlen(ext);
|
||||
|
||||
return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
|
||||
}
|
||||
|
||||
/* Sane ctype - no locale, and works with signed chars */
|
||||
#undef isascii
|
||||
#undef isspace
|
||||
|
Loading…
Reference in New Issue
Block a user