Bladeren bron

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>
Ingo Molnar 9 jaren geleden
bovenliggende
commit
b21daaede1
85 gewijzigde bestanden met toevoegingen van 1103 en 582 verwijderingen
  1. 1 2
      tools/build/Makefile.feature
  2. 47 46
      tools/build/feature/Makefile
  3. 4 0
      tools/include/linux/string.h
  4. 27 0
      tools/lib/string.c
  5. 7 0
      tools/lib/subcmd/Build
  6. 48 0
      tools/lib/subcmd/Makefile
  7. 209 0
      tools/lib/subcmd/exec-cmd.c
  8. 16 0
      tools/lib/subcmd/exec-cmd.h
  9. 52 118
      tools/lib/subcmd/help.c
  10. 9 4
      tools/lib/subcmd/help.h
  11. 14 9
      tools/lib/subcmd/pager.c
  12. 9 0
      tools/lib/subcmd/pager.h
  13. 183 62
      tools/lib/subcmd/parse-options.c
  14. 13 13
      tools/lib/subcmd/parse-options.h
  15. 16 8
      tools/lib/subcmd/run-command.c
  16. 7 5
      tools/lib/subcmd/run-command.h
  17. 2 1
      tools/lib/subcmd/sigchain.c
  18. 3 3
      tools/lib/subcmd/sigchain.h
  19. 11 0
      tools/lib/subcmd/subcmd-config.c
  20. 14 0
      tools/lib/subcmd/subcmd-config.h
  21. 91 0
      tools/lib/subcmd/subcmd-util.h
  22. 4 1
      tools/perf/Build
  23. 21 3
      tools/perf/Documentation/perf-record.txt
  24. 1 0
      tools/perf/MANIFEST
  25. 24 11
      tools/perf/Makefile.perf
  26. 1 1
      tools/perf/arch/x86/util/intel-pt.c
  27. 1 1
      tools/perf/bench/futex-hash.c
  28. 1 1
      tools/perf/bench/futex-lock-pi.c
  29. 1 1
      tools/perf/bench/futex-requeue.c
  30. 1 1
      tools/perf/bench/futex-wake-parallel.c
  31. 1 1
      tools/perf/bench/futex-wake.c
  32. 1 1
      tools/perf/bench/mem-functions.c
  33. 1 1
      tools/perf/bench/numa.c
  34. 1 1
      tools/perf/bench/sched-messaging.c
  35. 1 1
      tools/perf/bench/sched-pipe.c
  36. 1 1
      tools/perf/builtin-annotate.c
  37. 1 1
      tools/perf/builtin-bench.c
  38. 1 1
      tools/perf/builtin-buildid-cache.c
  39. 1 1
      tools/perf/builtin-buildid-list.c
  40. 1 1
      tools/perf/builtin-config.c
  41. 1 1
      tools/perf/builtin-data.c
  42. 1 1
      tools/perf/builtin-evlist.c
  43. 5 5
      tools/perf/builtin-help.c
  44. 1 1
      tools/perf/builtin-inject.c
  45. 1 1
      tools/perf/builtin-kmem.c
  46. 1 1
      tools/perf/builtin-kvm.c
  47. 1 1
      tools/perf/builtin-list.c
  48. 1 1
      tools/perf/builtin-lock.c
  49. 1 1
      tools/perf/builtin-mem.c
  50. 14 3
      tools/perf/builtin-probe.c
  51. 37 3
      tools/perf/builtin-record.c
  52. 1 1
      tools/perf/builtin-report.c
  53. 1 1
      tools/perf/builtin-sched.c
  54. 6 6
      tools/perf/builtin-script.c
  55. 1 1
      tools/perf/builtin-stat.c
  56. 1 1
      tools/perf/builtin-timechart.c
  57. 1 1
      tools/perf/builtin-top.c
  58. 2 2
      tools/perf/builtin-trace.c
  59. 11 7
      tools/perf/perf.c
  60. 3 3
      tools/perf/tests/Build
  61. 2 2
      tools/perf/tests/attr.c
  62. 4 1
      tools/perf/tests/builtin-test.c
  63. 2 3
      tools/perf/tests/hists_common.c
  64. 2 1
      tools/perf/tests/make
  65. 1 7
      tools/perf/util/Build
  66. 1 1
      tools/perf/util/auxtrace.c
  67. 4 9
      tools/perf/util/cache.h
  68. 1 1
      tools/perf/util/cgroup.c
  69. 1 1
      tools/perf/util/config.c
  70. 1 1
      tools/perf/util/evlist.c
  71. 13 1
      tools/perf/util/evsel.c
  72. 0 149
      tools/perf/util/exec_cmd.c
  73. 0 13
      tools/perf/util/exec_cmd.h
  74. 103 0
      tools/perf/util/help-unknown-cmd.c
  75. 0 0
      tools/perf/util/help-unknown-cmd.h
  76. 2 2
      tools/perf/util/intel-pt.c
  77. 12 7
      tools/perf/util/machine.c
  78. 1 1
      tools/perf/util/parse-branch-options.c
  79. 2 2
      tools/perf/util/parse-events.c
  80. 1 1
      tools/perf/util/parse-regs-options.c
  81. 0 18
      tools/perf/util/path.c
  82. 1 1
      tools/perf/util/sort.h
  83. 8 2
      tools/perf/util/thread.c
  84. 2 1
      tools/perf/util/util.c
  85. 0 14
      tools/perf/util/util.h

+ 1 - 2
tools/build/Makefile.feature

@@ -7,7 +7,7 @@ endif
 
 
 feature_check = $(eval $(feature_check_code))
 feature_check = $(eval $(feature_check_code))
 define 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
 endef
 
 
 feature_set = $(eval $(feature_set_code))
 feature_set = $(eval $(feature_set_code))
@@ -101,7 +101,6 @@ ifeq ($(feature-all), 1)
   #
   #
   $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
   $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
 else
 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)))
   $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
 endif
 endif
 
 

+ 47 - 46
tools/build/feature/Makefile

@@ -1,4 +1,3 @@
-
 FILES=					\
 FILES=					\
 	test-all.bin			\
 	test-all.bin			\
 	test-backtrace.bin		\
 	test-backtrace.bin		\
@@ -38,38 +37,40 @@ FILES=					\
 	test-bpf.bin			\
 	test-bpf.bin			\
 	test-get_cpuid.bin
 	test-get_cpuid.bin
 
 
+FILES := $(addprefix $(OUTPUT),$(FILES))
+
 CC := $(CROSS_COMPILE)gcc -MD
 CC := $(CROSS_COMPILE)gcc -MD
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
 PKG_CONFIG := $(CROSS_COMPILE)pkg-config
 
 
 all: $(FILES)
 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
 	$(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)
 	$(BUILD)
 
 
-test-pthread-attr-setaffinity-np.bin:
+$(OUTPUT)test-pthread-attr-setaffinity-np.bin:
 	$(BUILD) -D_GNU_SOURCE -lpthread
 	$(BUILD) -D_GNU_SOURCE -lpthread
 
 
-test-stackprotector-all.bin:
+$(OUTPUT)test-stackprotector-all.bin:
 	$(BUILD) -fstack-protector-all
 	$(BUILD) -fstack-protector-all
 
 
-test-fortify-source.bin:
+$(OUTPUT)test-fortify-source.bin:
 	$(BUILD) -O2 -D_FORTIFY_SOURCE=2
 	$(BUILD) -O2 -D_FORTIFY_SOURCE=2
 
 
-test-bionic.bin:
+$(OUTPUT)test-bionic.bin:
 	$(BUILD)
 	$(BUILD)
 
 
-test-libelf.bin:
+$(OUTPUT)test-libelf.bin:
 	$(BUILD) -lelf
 	$(BUILD) -lelf
 
 
-test-glibc.bin:
+$(OUTPUT)test-glibc.bin:
 	$(BUILD)
 	$(BUILD)
 
 
 DWARFLIBS := -ldw
 DWARFLIBS := -ldw
@@ -77,37 +78,37 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
 DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
 DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
 endif
 endif
 
 
-test-dwarf.bin:
+$(OUTPUT)test-dwarf.bin:
 	$(BUILD) $(DWARFLIBS)
 	$(BUILD) $(DWARFLIBS)
 
 
-test-libelf-mmap.bin:
+$(OUTPUT)test-libelf-mmap.bin:
 	$(BUILD) -lelf
 	$(BUILD) -lelf
 
 
-test-libelf-getphdrnum.bin:
+$(OUTPUT)test-libelf-getphdrnum.bin:
 	$(BUILD) -lelf
 	$(BUILD) -lelf
 
 
-test-libnuma.bin:
+$(OUTPUT)test-libnuma.bin:
 	$(BUILD) -lnuma
 	$(BUILD) -lnuma
 
 
-test-numa_num_possible_cpus.bin:
+$(OUTPUT)test-numa_num_possible_cpus.bin:
 	$(BUILD) -lnuma
 	$(BUILD) -lnuma
 
 
-test-libunwind.bin:
+$(OUTPUT)test-libunwind.bin:
 	$(BUILD) -lelf
 	$(BUILD) -lelf
 
 
-test-libunwind-debug-frame.bin:
+$(OUTPUT)test-libunwind-debug-frame.bin:
 	$(BUILD) -lelf
 	$(BUILD) -lelf
 
 
-test-libaudit.bin:
+$(OUTPUT)test-libaudit.bin:
 	$(BUILD) -laudit
 	$(BUILD) -laudit
 
 
-test-libslang.bin:
+$(OUTPUT)test-libslang.bin:
 	$(BUILD) -I/usr/include/slang -lslang
 	$(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)
 	$(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)
 	$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
 
 
 grep-libs  = $(filter -l%,$(1))
 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`
 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 
 
-test-libperl.bin:
+$(OUTPUT)test-libperl.bin:
 	$(BUILD) $(FLAGS_PERL_EMBED)
 	$(BUILD) $(FLAGS_PERL_EMBED)
 
 
-test-libpython.bin:
+$(OUTPUT)test-libpython.bin:
 	$(BUILD)
 	$(BUILD)
 
 
-test-libpython-version.bin:
+$(OUTPUT)test-libpython-version.bin:
 	$(BUILD)
 	$(BUILD)
 
 
-test-libbfd.bin:
+$(OUTPUT)test-libbfd.bin:
 	$(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
 	$(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
 	$(BUILD) -liberty
 
 
-test-backtrace.bin:
+$(OUTPUT)test-backtrace.bin:
 	$(BUILD)
 	$(BUILD)
 
 
-test-timerfd.bin:
+$(OUTPUT)test-timerfd.bin:
 	$(BUILD)
 	$(BUILD)
 
 
-test-libdw-dwarf-unwind.bin:
+$(OUTPUT)test-libdw-dwarf-unwind.bin:
 	$(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind)
 	$(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)
 	$(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)
 
 
-test-sync-compare-and-swap.bin:
+$(OUTPUT)test-sync-compare-and-swap.bin:
 	$(BUILD)
 	$(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
 	$(BUILD) -lz
 
 
-test-lzma.bin:
+$(OUTPUT)test-lzma.bin:
 	$(BUILD) -llzma
 	$(BUILD) -llzma
 
 
-test-get_cpuid.bin:
+$(OUTPUT)test-get_cpuid.bin:
 	$(BUILD)
 	$(BUILD)
 
 
-test-bpf.bin:
+$(OUTPUT)test-bpf.bin:
 	$(BUILD)
 	$(BUILD)
 
 
--include *.d
+-include $(OUTPUT)*.d
 
 
 ###############################
 ###############################
 
 
 clean:
 clean:
-	rm -f $(FILES) *.d $(FILES:.bin=.make.output)
+	rm -f $(FILES) $(OUTPUT)*.d $(FILES:.bin=.make.output)

+ 4 - 0
tools/include/linux/string.h

@@ -8,4 +8,8 @@ void *memdup(const void *src, size_t len);
 
 
 int strtobool(const char *s, bool *res);
 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_ */
 #endif /* _LINUX_STRING_H_ */

+ 27 - 0
tools/lib/string.c

@@ -16,6 +16,7 @@
 #include <string.h>
 #include <string.h>
 #include <errno.h>
 #include <errno.h>
 #include <linux/string.h>
 #include <linux/string.h>
+#include <linux/compiler.h>
 
 
 /**
 /**
  * memdup - duplicate region of memory
  * memdup - duplicate region of memory
@@ -60,3 +61,29 @@ int strtobool(const char *s, bool *res)
 	}
 	}
 	return 0;
 	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 - 0
tools/lib/subcmd/Build

@@ -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 - 0
tools/lib/subcmd/Makefile

@@ -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 - 0
tools/lib/subcmd/exec-cmd.c

@@ -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 - 0
tools/lib/subcmd/exec-cmd.h

@@ -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 */

+ 52 - 118
tools/perf/util/help.c → tools/lib/subcmd/help.c

@@ -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 <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)
 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;
 	cmds->names[cmds->cnt++] = ent;
 }
 }
 
 
-static void clean_cmdnames(struct cmdnames *cmds)
+void clean_cmdnames(struct cmdnames *cmds)
 {
 {
 	unsigned int i;
 	unsigned int i;
 
 
@@ -28,14 +34,14 @@ static void clean_cmdnames(struct cmdnames *cmds)
 	cmds->alloc = 0;
 	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 *a = *(struct cmdname **)a_;
 	struct cmdname *b = *(struct cmdname **)b_;
 	struct cmdname *b = *(struct cmdname **)b_;
 	return strcmp(a->name, b->name);
 	return strcmp(a->name, b->name);
 }
 }
 
 
-static void uniq(struct cmdnames *cmds)
+void uniq(struct cmdnames *cmds)
 {
 {
 	unsigned int i, j;
 	unsigned int i, j;
 
 
@@ -71,6 +77,28 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
 	cmds->cnt = cj;
 	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)
 static void pretty_print_string_list(struct cmdnames *cmds, int longest)
 {
 {
 	int cols = 1, rows;
 	int cols = 1, rows;
@@ -114,6 +142,14 @@ static int is_executable(const char *name)
 	return st.st_mode & S_IXUSR;
 	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,
 static void list_commands_in_dir(struct cmdnames *cmds,
 					 const char *path,
 					 const char *path,
 					 const char *prefix)
 					 const char *prefix)
@@ -121,8 +157,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
 	int prefix_len;
 	int prefix_len;
 	DIR *dir = opendir(path);
 	DIR *dir = opendir(path);
 	struct dirent *de;
 	struct dirent *de;
-	struct strbuf buf = STRBUF_INIT;
-	int len;
+	char *buf = NULL;
 
 
 	if (!dir)
 	if (!dir)
 		return;
 		return;
@@ -130,8 +165,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
 		prefix = "perf-";
 		prefix = "perf-";
 	prefix_len = strlen(prefix);
 	prefix_len = strlen(prefix);
 
 
-	strbuf_addf(&buf, "%s/", path);
-	len = buf.len;
+	astrcatf(&buf, "%s/", path);
 
 
 	while ((de = readdir(dir)) != NULL) {
 	while ((de = readdir(dir)) != NULL) {
 		int entlen;
 		int entlen;
@@ -139,9 +173,8 @@ static void list_commands_in_dir(struct cmdnames *cmds,
 		if (prefixcmp(de->d_name, prefix))
 		if (prefixcmp(de->d_name, prefix))
 			continue;
 			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;
 			continue;
 
 
 		entlen = strlen(de->d_name) - prefix_len;
 		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);
 		add_cmdname(cmds, de->d_name + prefix_len, entlen);
 	}
 	}
 	closedir(dir);
 	closedir(dir);
-	strbuf_release(&buf);
+	free(buf);
 }
 }
 
 
 void load_command_list(const char *prefix,
 void load_command_list(const char *prefix,
@@ -159,7 +192,7 @@ void load_command_list(const char *prefix,
 		struct cmdnames *other_cmds)
 		struct cmdnames *other_cmds)
 {
 {
 	const char *env_path = getenv("PATH");
 	const char *env_path = getenv("PATH");
-	char *exec_path = perf_exec_path();
+	char *exec_path = get_argv_exec_path();
 
 
 	if (exec_path) {
 	if (exec_path) {
 		list_commands_in_dir(main_cmds, exec_path, prefix);
 		list_commands_in_dir(main_cmds, exec_path, prefix);
@@ -172,7 +205,7 @@ void load_command_list(const char *prefix,
 		char *paths, *path, *colon;
 		char *paths, *path, *colon;
 		path = paths = strdup(env_path);
 		path = paths = strdup(env_path);
 		while (1) {
 		while (1) {
-			if ((colon = strchr(path, PATH_SEP)))
+			if ((colon = strchr(path, ':')))
 				*colon = 0;
 				*colon = 0;
 			if (!exec_path || strcmp(path, exec_path))
 			if (!exec_path || strcmp(path, exec_path))
 				list_commands_in_dir(other_cmds, path, prefix);
 				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;
 			longest = other_cmds->names[i]->len;
 
 
 	if (main_cmds->cnt) {
 	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("available %s in '%s'\n", title, exec_path);
 		printf("----------------");
 		printf("----------------");
 		mput_char('-', strlen(title) + strlen(exec_path));
 		mput_char('-', strlen(title) + strlen(exec_path));
@@ -233,102 +266,3 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
 			return 1;
 			return 1;
 	return 0;
 	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);
-}

+ 9 - 4
tools/perf/util/help.h → tools/lib/subcmd/help.h

@@ -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 {
 struct cmdnames {
 	size_t alloc;
 	size_t alloc;
 	size_t cnt;
 	size_t cnt;
 	struct cmdname {
 	struct cmdname {
 		size_t len; /* also used for similarity index in help.c */
 		size_t len; /* also used for similarity index in help.c */
-		char name[FLEX_ARRAY];
+		char name[];
 	} **names;
 	} **names;
 };
 };
 
 
@@ -20,10 +22,13 @@ void load_command_list(const char *prefix,
 		struct cmdnames *main_cmds,
 		struct cmdnames *main_cmds,
 		struct cmdnames *other_cmds);
 		struct cmdnames *other_cmds);
 void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
 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. */
 /* Here we require that excludes is a sorted list. */
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
 int is_in_cmdlist(struct cmdnames *c, const char *s);
 int is_in_cmdlist(struct cmdnames *c, const char *s);
 void list_commands(const char *title, struct cmdnames *main_cmds,
 void list_commands(const char *title, struct cmdnames *main_cmds,
 		   struct cmdnames *other_cmds);
 		   struct cmdnames *other_cmds);
 
 
-#endif /* __PERF_HELP_H */
+#endif /* __SUBCMD_HELP_H */

+ 14 - 9
tools/perf/util/pager.c → tools/lib/subcmd/pager.c

@@ -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 "run-command.h"
 #include "sigchain.h"
 #include "sigchain.h"
+#include "subcmd-config.h"
 
 
 /*
 /*
  * This is split up from the rest of git so that we can do
  * This is split up from the rest of git so that we can do
@@ -9,6 +15,11 @@
 
 
 static int spawned_pager;
 static int spawned_pager;
 
 
+void pager_init(const char *pager_env)
+{
+	subcmd_config.pager_env = pager_env;
+}
+
 static void pager_preexec(void)
 static void pager_preexec(void)
 {
 {
 	/*
 	/*
@@ -46,7 +57,7 @@ static void wait_for_pager_signal(int signo)
 
 
 void setup_pager(void)
 void setup_pager(void)
 {
 {
-	const char *pager = getenv("PERF_PAGER");
+	const char *pager = getenv(subcmd_config.pager_env);
 
 
 	if (!isatty(1))
 	if (!isatty(1))
 		return;
 		return;
@@ -85,11 +96,5 @@ void setup_pager(void)
 
 
 int pager_in_use(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 - 0
tools/lib/subcmd/pager.h

@@ -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 */

+ 183 - 62
tools/perf/util/parse-options.c → tools/lib/subcmd/parse-options.c

@@ -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 "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_SHORT 1
 #define OPT_UNSET 2
 #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)
 static int opterror(const struct option *opt, const char *reason, int flags)
 {
 {
 	if (flags & OPT_SHORT)
 	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,
 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
 		   int flags, const char **arg)
 		   int flags, const char **arg)
 {
 {
+	const char *res;
+
 	if (p->opt) {
 	if (p->opt) {
-		*arg = p->opt;
+		res = p->opt;
 		p->opt = NULL;
 		p->opt = NULL;
 	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
 	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
 		    **(p->argv + 1) == '-')) {
 		    **(p->argv + 1) == '-')) {
-		*arg = (const char *)opt->defval;
+		res = (const char *)opt->defval;
 	} else if (p->argc > 1) {
 	} else if (p->argc > 1) {
 		p->argc--;
 		p->argc--;
-		*arg = *++p->argv;
+		res = *++p->argv;
 	} else
 	} else
 		return opterror(opt, "requires a value", flags);
 		return opterror(opt, "requires a value", flags);
+	if (arg)
+		*arg = res;
 	return 0;
 	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) ||
 			if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
 			    p->excl_opt->long_name == NULL) {
 			    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 {
 			} 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);
 			opterror(opt, msg, flags);
 			return -3;
 			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) {
 	switch (opt->type) {
 	case OPTION_BIT:
 	case OPTION_BIT:
 		if (unset)
 		if (unset)
@@ -327,14 +414,16 @@ match:
 		return get_value(p, options, flags);
 		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)
 	if (abbrev_option)
 		return get_value(p, abbrev_option, abbrev_flags);
 		return get_value(p, abbrev_option, abbrev_flags);
 	return -2;
 	return -2;
@@ -346,7 +435,7 @@ static void check_typos(const char *arg, const struct option *options)
 		return;
 		return;
 
 
 	if (!prefixcmp(arg, "no-")) {
 	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);
 		exit(129);
 	}
 	}
 
 
@@ -354,14 +443,14 @@ static void check_typos(const char *arg, const struct option *options)
 		if (!options->long_name)
 		if (!options->long_name)
 			continue;
 			continue;
 		if (!prefixcmp(options->long_name, arg)) {
 		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);
 			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));
 	memset(ctx, 0, sizeof(*ctx));
 	ctx->argc = argc - 1;
 	ctx->argc = argc - 1;
@@ -378,9 +467,9 @@ static int usage_with_options_internal(const char * const *,
 				       const struct option *, int,
 				       const struct option *, int,
 				       struct parse_opt_ctx_t *);
 				       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 internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
 	int excl_short_opt = 1;
 	int excl_short_opt = 1;
@@ -489,7 +578,7 @@ exclusive:
 	return PARSE_OPT_HELP;
 	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));
 	memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
 	ctx->out[ctx->cpidx + ctx->argc] = NULL;
 	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 */
 	/* build usage string if it's not provided */
 	if (subcommands && !usagestr[0]) {
 	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++) {
 		for (int i = 0; subcommands[i]; i++) {
 			if (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);
 	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');
 		putchar('\n');
 		exit(130);
 		exit(130);
 	default: /* PARSE_OPT_UNKNOWN */
 	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);
 		usage_with_options(usagestr, options);
 	}
 	}
 
 
@@ -645,6 +732,10 @@ static void print_option_help(const struct option *opts, int full)
 		pad = USAGE_OPTS_WIDTH;
 		pad = USAGE_OPTS_WIDTH;
 	}
 	}
 	fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
 	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)
 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)
 static struct option *options__order(const struct option *opts)
 {
 {
-	int nr_opts = 0;
+	int nr_opts = 0, len;
 	const struct option *o = opts;
 	const struct option *o = opts;
 	struct option *ordered;
 	struct option *ordered;
 
 
 	for (o = opts; o->type != OPTION_END; o++)
 	for (o = opts; o->type != OPTION_END; o++)
 		++nr_opts;
 		++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;
 		goto out;
+	memcpy(ordered, opts, len);
 
 
 	qsort(ordered, nr_opts, sizeof(*o), option__cmp);
 	qsort(ordered, nr_opts, sizeof(*o), option__cmp);
 out:
 out:
@@ -717,9 +810,9 @@ static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx
 	return false;
 	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;
 	struct option *ordered;
 
 
@@ -728,9 +821,9 @@ int usage_with_options_internal(const char * const *usagestr,
 
 
 	setup_pager();
 	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++);
 	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, ...)
 			    const struct option *opts, const char *fmt, ...)
 {
 {
 	va_list ap;
 	va_list ap;
+	char *tmp = error_buf;
 
 
 	va_start(ap, fmt);
 	va_start(ap, fmt);
-	strbuf_addv(&error_buf, fmt, ap);
+	if (vasprintf(&error_buf, fmt, ap) == -1)
+		die("vasprintf failed");
 	va_end(ap);
 	va_end(ap);
 
 
+	free(tmp);
+
 	usage_with_options_internal(usagestr, opts, 0, NULL);
 	usage_with_options_internal(usagestr, opts, 0, NULL);
 	exit(129);
 	exit(129);
 }
 }
@@ -848,15 +945,39 @@ int parse_opt_verbosity_cb(const struct option *opt,
 	return 0;
 	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++) {
 	for (; opts->type != OPTION_END; opts++) {
 		if ((shortopt && opts->short_name == shortopt) ||
 		if ((shortopt && opts->short_name == shortopt) ||
 		    (opts->long_name && longopt &&
 		    (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;
 }
 }

+ 13 - 13
tools/perf/util/parse-options.h → tools/lib/subcmd/parse-options.h

@@ -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 <stdbool.h>
+#include <stdint.h>
 
 
 enum parse_opt_type {
 enum parse_opt_type {
 	/* special types */
 	/* special types */
@@ -41,6 +41,8 @@ enum parse_opt_option_flags {
 	PARSE_OPT_DISABLED = 32,
 	PARSE_OPT_DISABLED = 32,
 	PARSE_OPT_EXCLUSIVE = 64,
 	PARSE_OPT_EXCLUSIVE = 64,
 	PARSE_OPT_NOEMPTY  = 128,
 	PARSE_OPT_NOEMPTY  = 128,
+	PARSE_OPT_NOBUILD  = 256,
+	PARSE_OPT_CANSKIP  = 512,
 };
 };
 
 
 struct option;
 struct option;
@@ -96,6 +98,7 @@ struct option {
 	void *value;
 	void *value;
 	const char *argh;
 	const char *argh;
 	const char *help;
 	const char *help;
+	const char *build_opt;
 
 
 	int flags;
 	int flags;
 	parse_opt_cb *callback;
 	parse_opt_cb *callback;
@@ -149,6 +152,9 @@ struct option {
 /* parse_options() will filter out the processed options and leave the
 /* parse_options() will filter out the processed options and leave the
  * non-option argments in argv[].
  * non-option argments in argv[].
  * Returns the number of arguments left 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,
 extern int parse_options(int argc, const char **argv,
                          const struct option *options,
                          const struct option *options,
@@ -195,15 +201,6 @@ extern int parse_options_usage(const char * const *usagestr,
 			       const char *optstr,
 			       const char *optstr,
 			       bool short_opt);
 			       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 -----*/
 /*----- some often used options -----*/
 extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
 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);
 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);
 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 */

+ 16 - 8
tools/perf/util/run-command.c → tools/lib/subcmd/run-command.c

@@ -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 "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])
 static inline void close_pair(int fd[2])
 {
 {
@@ -112,8 +120,8 @@ int start_command(struct child_process *cmd)
 		}
 		}
 		if (cmd->preexec_cb)
 		if (cmd->preexec_cb)
 			cmd->preexec_cb();
 			cmd->preexec_cb();
-		if (cmd->perf_cmd) {
-			execv_perf_cmd(cmd->argv);
+		if (cmd->exec_cmd) {
+			execv_cmd(cmd->argv);
 		} else {
 		} else {
 			execvp(cmd->argv[0], (char *const*) cmd->argv);
 			execvp(cmd->argv[0], (char *const*) cmd->argv);
 		}
 		}
@@ -164,8 +172,8 @@ static int wait_or_whine(pid_t pid)
 		if (waiting < 0) {
 		if (waiting < 0) {
 			if (errno == EINTR)
 			if (errno == EINTR)
 				continue;
 				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;
 			return -ERR_RUN_COMMAND_WAITPID;
 		}
 		}
 		if (waiting != pid)
 		if (waiting != pid)
@@ -207,7 +215,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
 	memset(cmd, 0, sizeof(*cmd));
 	memset(cmd, 0, sizeof(*cmd));
 	cmd->argv = argv;
 	cmd->argv = argv;
 	cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
 	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;
 	cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
 }
 }
 
 

+ 7 - 5
tools/perf/util/run-command.h → tools/lib/subcmd/run-command.h

@@ -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 {
 enum {
 	ERR_RUN_COMMAND_FORK = 10000,
 	ERR_RUN_COMMAND_FORK = 10000,
@@ -41,7 +43,7 @@ struct child_process {
 	unsigned no_stdin:1;
 	unsigned no_stdin:1;
 	unsigned no_stdout:1;
 	unsigned no_stdout:1;
 	unsigned no_stderr: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;
 	unsigned stdout_to_stderr:1;
 	void (*preexec_cb)(void);
 	void (*preexec_cb)(void);
 };
 };
@@ -51,8 +53,8 @@ int finish_command(struct child_process *);
 int run_command(struct child_process *);
 int run_command(struct child_process *);
 
 
 #define RUN_COMMAND_NO_STDIN 1
 #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
 #define RUN_COMMAND_STDOUT_TO_STDERR 4
 int run_command_v_opt(const char **argv, int opt);
 int run_command_v_opt(const char **argv, int opt);
 
 
-#endif /* __PERF_RUN_COMMAND_H */
+#endif /* __SUBCMD_RUN_COMMAND_H */

+ 2 - 1
tools/perf/util/sigchain.c → tools/lib/subcmd/sigchain.c

@@ -1,5 +1,6 @@
+#include <signal.h>
+#include "subcmd-util.h"
 #include "sigchain.h"
 #include "sigchain.h"
-#include "cache.h"
 
 
 #define SIGCHAIN_MAX_SIGNALS 32
 #define SIGCHAIN_MAX_SIGNALS 32
 
 

+ 3 - 3
tools/perf/util/sigchain.h → tools/lib/subcmd/sigchain.h

@@ -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);
 typedef void (*sigchain_fun)(int);
 
 
@@ -7,4 +7,4 @@ int sigchain_pop(int sig);
 
 
 void sigchain_push_common(sigchain_fun f);
 void sigchain_push_common(sigchain_fun f);
 
 
-#endif /* __PERF_SIGCHAIN_H */
+#endif /* __SUBCMD_SIGCHAIN_H */

+ 11 - 0
tools/lib/subcmd/subcmd-config.c

@@ -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 - 0
tools/lib/subcmd/subcmd-config.h

@@ -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 - 0
tools/lib/subcmd/subcmd-util.h

@@ -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 */

+ 4 - 1
tools/perf/Build

@@ -36,7 +36,10 @@ paths += -DPERF_MAN_PATH="BUILD_STR($(mandir_SQ))"
 
 
 CFLAGS_builtin-help.o      += $(paths)
 CFLAGS_builtin-help.o      += $(paths)
 CFLAGS_builtin-timechart.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))"
 CFLAGS_builtin-trace.o	   += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
 
 
 libperf-y += util/
 libperf-y += util/

+ 21 - 3
tools/perf/Documentation/perf-record.txt

@@ -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
 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.
 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::
 -N::
 --no-buildid-cache::
 --no-buildid-cache::
 Do not update the buildid cache. This saves some overhead in situations
 Do not update the buildid cache. This saves some overhead in situations
 where the information in the perf.data file (which includes buildids)
 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,...::
 -G name,...::
 --cgroup 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
 Record context switch events i.e. events of type PERF_RECORD_SWITCH or
 PERF_RECORD_SWITCH_CPU_WIDE.
 PERF_RECORD_SWITCH_CPU_WIDE.
 
 
---clang-path::
+--clang-path=PATH::
 Path to clang binary to use for compiling BPF scriptlets.
 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.
 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
 SEE ALSO
 --------
 --------

+ 1 - 0
tools/perf/MANIFEST

@@ -20,6 +20,7 @@ tools/lib/traceevent
 tools/lib/bpf
 tools/lib/bpf
 tools/lib/api
 tools/lib/api
 tools/lib/bpf
 tools/lib/bpf
+tools/lib/subcmd
 tools/lib/hweight.c
 tools/lib/hweight.c
 tools/lib/rbtree.c
 tools/lib/rbtree.c
 tools/lib/string.c
 tools/lib/string.c

+ 24 - 11
tools/perf/Makefile.perf

@@ -145,9 +145,10 @@ BISON   = bison
 STRIP   = strip
 STRIP   = strip
 AWK     = awk
 AWK     = awk
 
 
-LIB_DIR          = $(srctree)/tools/lib/api/
+LIB_DIR		= $(srctree)/tools/lib/api/
 TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
 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
 # include config/Makefile by default and rule out
 # non-config cases
 # non-config cases
@@ -184,15 +185,17 @@ strip-libs = $(filter-out -l%,$(1))
 ifneq ($(OUTPUT),)
 ifneq ($(OUTPUT),)
   TE_PATH=$(OUTPUT)
   TE_PATH=$(OUTPUT)
   BPF_PATH=$(OUTPUT)
   BPF_PATH=$(OUTPUT)
+  SUBCMD_PATH=$(OUTPUT)
 ifneq ($(subdir),)
 ifneq ($(subdir),)
-  LIB_PATH=$(OUTPUT)/../lib/api/
+  API_PATH=$(OUTPUT)/../lib/api/
 else
 else
-  LIB_PATH=$(OUTPUT)
+  API_PATH=$(OUTPUT)
 endif
 endif
 else
 else
   TE_PATH=$(TRACE_EVENT_DIR)
   TE_PATH=$(TRACE_EVENT_DIR)
-  LIB_PATH=$(LIB_DIR)
+  API_PATH=$(LIB_DIR)
   BPF_PATH=$(BPF_DIR)
   BPF_PATH=$(BPF_DIR)
+  SUBCMD_PATH=$(SUBCMD_DIR)
 endif
 endif
 
 
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -201,11 +204,13 @@ export LIBTRACEEVENT
 LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
 LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
 LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(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
 export LIBAPI
 
 
 LIBBPF = $(BPF_PATH)libbpf.a
 LIBBPF = $(BPF_PATH)libbpf.a
 
 
+LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a
+
 # python extension build directories
 # python extension build directories
 PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
 PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -257,7 +262,7 @@ export PERL_PATH
 
 
 LIB_FILE=$(OUTPUT)libperf.a
 LIB_FILE=$(OUTPUT)libperf.a
 
 
-PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT)
+PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
 ifndef NO_LIBBPF
 ifndef NO_LIBBPF
   PERFLIBS += $(LIBBPF)
   PERFLIBS += $(LIBBPF)
 endif
 endif
@@ -437,6 +442,13 @@ $(LIBBPF)-clean:
 	$(call QUIET_CLEAN, libbpf)
 	$(call QUIET_CLEAN, libbpf)
 	$(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null
 	$(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:
 help:
 	@echo 'Perf make targets:'
 	@echo 'Perf make targets:'
 	@echo '  doc		- make *all* documentation (see below)'
 	@echo '  doc		- make *all* documentation (see below)'
@@ -582,15 +594,16 @@ $(INSTALL_DOC_TARGETS):
 #
 #
 config-clean:
 config-clean:
 	$(call QUIET_CLEAN, config)
 	$(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)
 	$(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
 	$(Q)$(RM) $(OUTPUT).config-detected
 	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
 	$(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* \
 	$(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
 	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
 	$(python-clean)
 	$(python-clean)
 
 

+ 1 - 1
tools/perf/arch/x86/util/intel-pt.c

@@ -26,7 +26,7 @@
 #include "../../util/evlist.h"
 #include "../../util/evlist.h"
 #include "../../util/evsel.h"
 #include "../../util/evsel.h"
 #include "../../util/cpumap.h"
 #include "../../util/cpumap.h"
-#include "../../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../../util/parse-events.h"
 #include "../../util/parse-events.h"
 #include "../../util/pmu.h"
 #include "../../util/pmu.h"
 #include "../../util/debug.h"
 #include "../../util/debug.h"

+ 1 - 1
tools/perf/bench/futex-hash.c

@@ -11,7 +11,7 @@
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
 #include "../util/stat.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "../util/header.h"
 #include "bench.h"
 #include "bench.h"
 #include "futex.h"
 #include "futex.h"

+ 1 - 1
tools/perf/bench/futex-lock-pi.c

@@ -5,7 +5,7 @@
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
 #include "../util/stat.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "../util/header.h"
 #include "bench.h"
 #include "bench.h"
 #include "futex.h"
 #include "futex.h"

+ 1 - 1
tools/perf/bench/futex-requeue.c

@@ -11,7 +11,7 @@
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
 #include "../util/stat.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "../util/header.h"
 #include "bench.h"
 #include "bench.h"
 #include "futex.h"
 #include "futex.h"

+ 1 - 1
tools/perf/bench/futex-wake-parallel.c

@@ -10,7 +10,7 @@
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
 #include "../util/stat.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "../util/header.h"
 #include "bench.h"
 #include "bench.h"
 #include "futex.h"
 #include "futex.h"

+ 1 - 1
tools/perf/bench/futex-wake.c

@@ -11,7 +11,7 @@
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
 #include "../util/stat.h"
 #include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "../util/header.h"
 #include "bench.h"
 #include "bench.h"
 #include "futex.h"
 #include "futex.h"

+ 1 - 1
tools/perf/bench/mem-functions.c

@@ -8,7 +8,7 @@
 
 
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/header.h"
 #include "../util/header.h"
 #include "../util/cloexec.h"
 #include "../util/cloexec.h"
 #include "bench.h"
 #include "bench.h"

+ 1 - 1
tools/perf/bench/numa.c

@@ -7,7 +7,7 @@
 #include "../perf.h"
 #include "../perf.h"
 #include "../builtin.h"
 #include "../builtin.h"
 #include "../util/util.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../util/cloexec.h"
 #include "../util/cloexec.h"
 
 
 #include "bench.h"
 #include "bench.h"

+ 1 - 1
tools/perf/bench/sched-messaging.c

@@ -11,7 +11,7 @@
 
 
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../builtin.h"
 #include "../builtin.h"
 #include "bench.h"
 #include "bench.h"
 
 

+ 1 - 1
tools/perf/bench/sched-pipe.c

@@ -10,7 +10,7 @@
  */
  */
 #include "../perf.h"
 #include "../perf.h"
 #include "../util/util.h"
 #include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "../builtin.h"
 #include "../builtin.h"
 #include "bench.h"
 #include "bench.h"
 
 

+ 1 - 1
tools/perf/builtin-annotate.c

@@ -21,7 +21,7 @@
 #include "util/evsel.h"
 #include "util/evsel.h"
 #include "util/annotate.h"
 #include "util/annotate.h"
 #include "util/event.h"
 #include "util/event.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/parse-events.h"
 #include "util/thread.h"
 #include "util/thread.h"
 #include "util/sort.h"
 #include "util/sort.h"

+ 1 - 1
tools/perf/builtin-bench.c

@@ -16,7 +16,7 @@
  */
  */
 #include "perf.h"
 #include "perf.h"
 #include "util/util.h"
 #include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "builtin.h"
 #include "builtin.h"
 #include "bench/bench.h"
 #include "bench/bench.h"
 
 

+ 1 - 1
tools/perf/builtin-buildid-cache.c

@@ -16,7 +16,7 @@
 #include "util/cache.h"
 #include "util/cache.h"
 #include "util/debug.h"
 #include "util/debug.h"
 #include "util/header.h"
 #include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/strlist.h"
 #include "util/strlist.h"
 #include "util/build-id.h"
 #include "util/build-id.h"
 #include "util/session.h"
 #include "util/session.h"

+ 1 - 1
tools/perf/builtin-buildid-list.c

@@ -12,7 +12,7 @@
 #include "util/build-id.h"
 #include "util/build-id.h"
 #include "util/cache.h"
 #include "util/cache.h"
 #include "util/debug.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/session.h"
 #include "util/session.h"
 #include "util/symbol.h"
 #include "util/symbol.h"
 #include "util/data.h"
 #include "util/data.h"

+ 1 - 1
tools/perf/builtin-config.c

@@ -9,7 +9,7 @@
 #include "perf.h"
 #include "perf.h"
 
 
 #include "util/cache.h"
 #include "util/cache.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/util.h"
 #include "util/util.h"
 #include "util/debug.h"
 #include "util/debug.h"
 
 

+ 1 - 1
tools/perf/builtin-data.c

@@ -2,7 +2,7 @@
 #include "builtin.h"
 #include "builtin.h"
 #include "perf.h"
 #include "perf.h"
 #include "debug.h"
 #include "debug.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "data-convert-bt.h"
 #include "data-convert-bt.h"
 
 
 typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
 typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);

+ 1 - 1
tools/perf/builtin-evlist.c

@@ -12,7 +12,7 @@
 #include "util/evlist.h"
 #include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/evsel.h"
 #include "util/parse-events.h"
 #include "util/parse-events.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/session.h"
 #include "util/session.h"
 #include "util/data.h"
 #include "util/data.h"
 #include "util/debug.h"
 #include "util/debug.h"

+ 5 - 5
tools/perf/builtin-help.c

@@ -6,11 +6,11 @@
 #include "perf.h"
 #include "perf.h"
 #include "util/cache.h"
 #include "util/cache.h"
 #include "builtin.h"
 #include "builtin.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "common-cmds.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"
 #include "util/debug.h"
 
 
 static struct man_viewer_list {
 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
 #ifndef open_html
 static void open_html(const char *path)
 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
 #endif
 
 

+ 1 - 1
tools/perf/builtin-inject.c

@@ -18,7 +18,7 @@
 #include "util/data.h"
 #include "util/data.h"
 #include "util/auxtrace.h"
 #include "util/auxtrace.h"
 
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 
 
 #include <linux/list.h>
 #include <linux/list.h>
 
 

+ 1 - 1
tools/perf/builtin-kmem.c

@@ -12,7 +12,7 @@
 #include "util/tool.h"
 #include "util/tool.h"
 #include "util/callchain.h"
 #include "util/callchain.h"
 
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/trace-event.h"
 #include "util/data.h"
 #include "util/data.h"
 #include "util/cpumap.h"
 #include "util/cpumap.h"

+ 1 - 1
tools/perf/builtin-kvm.c

@@ -10,7 +10,7 @@
 #include "util/header.h"
 #include "util/header.h"
 #include "util/session.h"
 #include "util/session.h"
 #include "util/intlist.h"
 #include "util/intlist.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/trace-event.h"
 #include "util/debug.h"
 #include "util/debug.h"
 #include "util/tool.h"
 #include "util/tool.h"

+ 1 - 1
tools/perf/builtin-list.c

@@ -14,7 +14,7 @@
 #include "util/parse-events.h"
 #include "util/parse-events.h"
 #include "util/cache.h"
 #include "util/cache.h"
 #include "util/pmu.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)
 int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 {

+ 1 - 1
tools/perf/builtin-lock.c

@@ -9,7 +9,7 @@
 #include "util/thread.h"
 #include "util/thread.h"
 #include "util/header.h"
 #include "util/header.h"
 
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/trace-event.h"
 
 
 #include "util/debug.h"
 #include "util/debug.h"

+ 1 - 1
tools/perf/builtin-mem.c

@@ -1,7 +1,7 @@
 #include "builtin.h"
 #include "builtin.h"
 #include "perf.h"
 #include "perf.h"
 
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/trace-event.h"
 #include "util/tool.h"
 #include "util/tool.h"
 #include "util/session.h"
 #include "util/session.h"

+ 14 - 3
tools/perf/builtin-probe.c

@@ -37,7 +37,7 @@
 #include "util/strfilter.h"
 #include "util/strfilter.h"
 #include "util/symbol.h"
 #include "util/symbol.h"
 #include "util/debug.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/probe-finder.h"
 #include "util/probe-finder.h"
 #include "util/probe-event.h"
 #include "util/probe-event.h"
 #include "util/probe-file.h"
 #include "util/probe-file.h"
@@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
 
 
 	return ret;
 	return ret;
 }
 }
+#else
+# define opt_show_lines NULL
+# define opt_show_vars NULL
 #endif
 #endif
 static int opt_add_probe_event(const struct option *opt,
 static int opt_add_probe_event(const struct option *opt,
 			      const char *str, int unset __maybe_unused)
 			      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_add_probe_event),
 	OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
 	OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
 		    " with existing name"),
 		    " with existing name"),
-#ifdef HAVE_DWARF_SUPPORT
 	OPT_CALLBACK('L', "line", NULL,
 	OPT_CALLBACK('L', "line", NULL,
 		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 		     "Show source code lines.", opt_show_lines),
 		     "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"),
 		   "directory", "path to kernel source"),
 	OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
 	OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
 		"Don't search inlined functions"),
 		"Don't search inlined functions"),
-#endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
 	OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
 		 "Set how many probe points can be found for a probe."),
 		 "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
 #ifdef HAVE_DWARF_SUPPORT
 	set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
 	set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
 	set_option_flag(options, 'V', "vars", 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
 #endif
 	set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
 	set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
 
 

+ 37 - 3
tools/perf/builtin-record.c

@@ -11,7 +11,7 @@
 
 
 #include "util/build-id.h"
 #include "util/build-id.h"
 #include "util/util.h"
 #include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/parse-events.h"
 
 
 #include "util/callchain.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)
 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"))
 	if (!strcmp(var, "record.call-graph"))
 		var = "call-graph.record-mode"; /* fall-through */
 		var = "call-graph.record-mode"; /* fall-through */
 
 
@@ -1113,12 +1126,12 @@ struct option __record_options[] = {
 			"per thread proc mmap processing timeout in ms"),
 			"per thread proc mmap processing timeout in ms"),
 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
 		    "Record context switch events"),
 		    "Record context switch events"),
-#ifdef HAVE_LIBBPF_SUPPORT
 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
 		   "clang binary to use for compiling BPF scriptlets"),
 		   "clang binary to use for compiling BPF scriptlets"),
 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
 		   "options passed to clang when compiling BPF scriptlets"),
 		   "options passed to clang when compiling BPF scriptlets"),
-#endif
+	OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
+		   "file", "vmlinux pathname"),
 	OPT_END()
 	OPT_END()
 };
 };
 
 
@@ -1130,6 +1143,27 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 	struct record *rec = &record;
 	struct record *rec = &record;
 	char errbuf[BUFSIZ];
 	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();
 	rec->evlist = perf_evlist__new();
 	if (rec->evlist == NULL)
 	if (rec->evlist == NULL)
 		return -ENOMEM;
 		return -ENOMEM;

+ 1 - 1
tools/perf/builtin-report.c

@@ -27,7 +27,7 @@
 #include "util/session.h"
 #include "util/session.h"
 #include "util/tool.h"
 #include "util/tool.h"
 
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/parse-events.h"
 
 
 #include "util/thread.h"
 #include "util/thread.h"

+ 1 - 1
tools/perf/builtin-sched.c

@@ -12,7 +12,7 @@
 #include "util/tool.h"
 #include "util/tool.h"
 #include "util/cloexec.h"
 #include "util/cloexec.h"
 
 
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/trace-event.h"
 #include "util/trace-event.h"
 
 
 #include "util/debug.h"
 #include "util/debug.h"

+ 6 - 6
tools/perf/builtin-script.c

@@ -3,9 +3,9 @@
 #include "perf.h"
 #include "perf.h"
 #include "util/cache.h"
 #include "util/cache.h"
 #include "util/debug.h"
 #include "util/debug.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/header.h"
 #include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/perf_regs.h"
 #include "util/perf_regs.h"
 #include "util/session.h"
 #include "util/session.h"
 #include "util/tool.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 first_half[BUFSIZ];
 	char *script_root;
 	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);
 	scripts_dir = opendir(scripts_path);
 	if (!scripts_dir)
 	if (!scripts_dir)
@@ -1529,7 +1529,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
 	if (!session)
 	if (!session)
 		return -1;
 		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);
 	scripts_dir = opendir(scripts_path);
 	if (!scripts_dir) {
 	if (!scripts_dir) {
@@ -1587,7 +1587,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
 	char lang_path[MAXPATHLEN];
 	char lang_path[MAXPATHLEN];
 	char *__script_root;
 	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);
 	scripts_dir = opendir(scripts_path);
 	if (!scripts_dir)
 	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;
 		scripting_max_stack = itrace_synth_opts.callchain_sz;
 
 
 	/* make sure PERF_EXEC_PATH is set for scripts */
 	/* 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) {
 	if (argc && !script_name && !rec_script_path && !rep_script_path) {
 		int live_pipe[2];
 		int live_pipe[2];

+ 1 - 1
tools/perf/builtin-stat.c

@@ -45,7 +45,7 @@
 #include "builtin.h"
 #include "builtin.h"
 #include "util/cgroup.h"
 #include "util/cgroup.h"
 #include "util/util.h"
 #include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/parse-events.h"
 #include "util/pmu.h"
 #include "util/pmu.h"
 #include "util/event.h"
 #include "util/event.h"

+ 1 - 1
tools/perf/builtin-timechart.c

@@ -30,7 +30,7 @@
 
 
 #include "perf.h"
 #include "perf.h"
 #include "util/header.h"
 #include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/parse-events.h"
 #include "util/event.h"
 #include "util/event.h"
 #include "util/session.h"
 #include "util/session.h"

+ 1 - 1
tools/perf/builtin-top.c

@@ -34,7 +34,7 @@
 #include "util/top.h"
 #include "util/top.h"
 #include "util/util.h"
 #include "util/util.h"
 #include <linux/rbtree.h>
 #include <linux/rbtree.h>
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-events.h"
 #include "util/parse-events.h"
 #include "util/cpumap.h"
 #include "util/cpumap.h"
 #include "util/xyarray.h"
 #include "util/xyarray.h"

+ 2 - 2
tools/perf/builtin-trace.c

@@ -22,11 +22,11 @@
 #include "util/color.h"
 #include "util/color.h"
 #include "util/debug.h"
 #include "util/debug.h"
 #include "util/evlist.h"
 #include "util/evlist.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/machine.h"
 #include "util/machine.h"
 #include "util/session.h"
 #include "util/session.h"
 #include "util/thread.h"
 #include "util/thread.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/strlist.h"
 #include "util/strlist.h"
 #include "util/intlist.h"
 #include "util/intlist.h"
 #include "util/thread_map.h"
 #include "util/thread_map.h"

+ 11 - 7
tools/perf/perf.c

@@ -9,12 +9,12 @@
 #include "builtin.h"
 #include "builtin.h"
 
 
 #include "util/env.h"
 #include "util/env.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/cache.h"
 #include "util/cache.h"
 #include "util/quote.h"
 #include "util/quote.h"
-#include "util/run-command.h"
+#include <subcmd/run-command.h>
 #include "util/parse-events.h"
 #include "util/parse-events.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/bpf-loader.h"
 #include "util/bpf-loader.h"
 #include "util/debug.h"
 #include "util/debug.h"
 #include <api/fs/tracing_path.h>
 #include <api/fs/tracing_path.h>
@@ -119,7 +119,7 @@ static void commit_pager_choice(void)
 {
 {
 	switch (use_pager) {
 	switch (use_pager) {
 	case 0:
 	case 0:
-		setenv("PERF_PAGER", "cat", 1);
+		setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
 		break;
 		break;
 	case 1:
 	case 1:
 		/* setup_pager(); */
 		/* setup_pager(); */
@@ -183,9 +183,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
 		if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
 		if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
 			cmd += strlen(CMD_EXEC_PATH);
 			cmd += strlen(CMD_EXEC_PATH);
 			if (*cmd == '=')
 			if (*cmd == '=')
-				perf_set_argv_exec_path(cmd + 1);
+				set_argv_exec_path(cmd + 1);
 			else {
 			else {
-				puts(perf_exec_path());
+				puts(get_argv_exec_path());
 				exit(0);
 				exit(0);
 			}
 			}
 		} else if (!strcmp(cmd, "--html-path")) {
 		} else if (!strcmp(cmd, "--html-path")) {
@@ -530,11 +530,15 @@ int main(int argc, const char **argv)
 	const char *cmd;
 	const char *cmd;
 	char sbuf[STRERR_BUFSIZE];
 	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. */
 	/* The page_size is placed in util object. */
 	page_size = sysconf(_SC_PAGE_SIZE);
 	page_size = sysconf(_SC_PAGE_SIZE);
 	cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
 	cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
 
 
-	cmd = perf_extract_argv0_path(argv[0]);
+	cmd = extract_argv0_path(argv[0]);
 	if (!cmd)
 	if (!cmd)
 		cmd = "perf-help";
 		cmd = "perf-help";
 
 

+ 3 - 3
tools/perf/tests/Build

@@ -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 += bpf.o
 perf-y += topology.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)
 	$(call rule_mkdir)
 	$(Q)echo '#include <tests/llvm.h>' > $@
 	$(Q)echo '#include <tests/llvm.h>' > $@
 	$(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
 	$(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)echo ';' >> $@
 	$(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)
 	$(call rule_mkdir)
 	$(Q)echo '#include <tests/llvm.h>' > $@
 	$(Q)echo '#include <tests/llvm.h>' > $@
 	$(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
 	$(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
 	$(Q)echo ';' >> $@
 	$(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)
 	$(call rule_mkdir)
 	$(Q)echo '#include <tests/llvm.h>' > $@
 	$(Q)echo '#include <tests/llvm.h>' > $@
 	$(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@
 	$(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@

+ 2 - 2
tools/perf/tests/attr.c

@@ -24,7 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include "../perf.h"
 #include "../perf.h"
 #include "util.h"
 #include "util.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "tests.h"
 #include "tests.h"
 
 
 #define ENV "PERF_TEST_ATTR"
 #define ENV "PERF_TEST_ATTR"
@@ -164,7 +164,7 @@ int test__attr(int subtest __maybe_unused)
 		return run_dir("./tests", "./perf");
 		return run_dir("./tests", "./perf");
 
 
 	/* Then installed path. */
 	/* 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);
 	snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
 
 
 	if (!lstat(path_dir, &st) &&
 	if (!lstat(path_dir, &st) &&

+ 4 - 1
tools/perf/tests/builtin-test.c

@@ -11,7 +11,7 @@
 #include "tests.h"
 #include "tests.h"
 #include "debug.h"
 #include "debug.h"
 #include "color.h"
 #include "color.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "symbol.h"
 #include "symbol.h"
 
 
 struct test __weak arch_tests[] = {
 struct test __weak arch_tests[] = {
@@ -236,6 +236,9 @@ static int run_test(struct test *test, int subtest)
 				dup2(STDOUT_FILENO, STDERR_FILENO);
 				dup2(STDOUT_FILENO, STDERR_FILENO);
 				close(nullfd);
 				close(nullfd);
 			}
 			}
+		} else {
+			signal(SIGSEGV, sighandler_dump_stack);
+			signal(SIGFPE, sighandler_dump_stack);
 		}
 		}
 
 
 		err = test->func(subtest);
 		err = test->func(subtest);

+ 2 - 3
tools/perf/tests/hists_common.c

@@ -88,8 +88,8 @@ struct machine *setup_fake_machine(struct machines *machines)
 	}
 	}
 
 
 	if (machine__create_kernel_maps(machine)) {
 	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++) {
 	for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
@@ -155,7 +155,6 @@ struct machine *setup_fake_machine(struct machines *machines)
 out:
 out:
 	pr_debug("Not enough memory for machine setup\n");
 	pr_debug("Not enough memory for machine setup\n");
 	machine__delete_threads(machine);
 	machine__delete_threads(machine);
-	machine__delete(machine);
 	return NULL;
 	return NULL;
 }
 }
 
 

+ 2 - 1
tools/perf/tests/make

@@ -259,7 +259,8 @@ $(run_O):
 tarpkg:
 tarpkg:
 	@cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
 	@cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
 	echo "- $@: $$cmd" && echo $$cmd > $@ && \
 	echo "- $@: $$cmd" && echo $$cmd > $@ && \
-	( eval $$cmd ) >> $@ 2>&1
+	( eval $$cmd ) >> $@ 2>&1 && \
+	rm -f $@
 
 
 make_kernelsrc:
 make_kernelsrc:
 	@echo "- make -C <kernelsrc> tools/perf"
 	@echo "- make -C <kernelsrc> tools/perf"

+ 1 - 7
tools/perf/util/Build

@@ -9,13 +9,10 @@ libperf-y += env.o
 libperf-y += event.o
 libperf-y += event.o
 libperf-y += evlist.o
 libperf-y += evlist.o
 libperf-y += evsel.o
 libperf-y += evsel.o
-libperf-y += exec_cmd.o
 libperf-y += find_next_bit.o
 libperf-y += find_next_bit.o
-libperf-y += help.o
 libperf-y += kallsyms.o
 libperf-y += kallsyms.o
 libperf-y += levenshtein.o
 libperf-y += levenshtein.o
 libperf-y += llvm-utils.o
 libperf-y += llvm-utils.o
-libperf-y += parse-options.o
 libperf-y += parse-events.o
 libperf-y += parse-events.o
 libperf-y += perf_regs.o
 libperf-y += perf_regs.o
 libperf-y += path.o
 libperf-y += path.o
@@ -23,7 +20,6 @@ libperf-y += rbtree.o
 libperf-y += libstring.o
 libperf-y += libstring.o
 libperf-y += bitmap.o
 libperf-y += bitmap.o
 libperf-y += hweight.o
 libperf-y += hweight.o
-libperf-y += run-command.o
 libperf-y += quote.o
 libperf-y += quote.o
 libperf-y += strbuf.o
 libperf-y += strbuf.o
 libperf-y += string.o
 libperf-y += string.o
@@ -32,11 +28,9 @@ libperf-y += strfilter.o
 libperf-y += top.o
 libperf-y += top.o
 libperf-y += usage.o
 libperf-y += usage.o
 libperf-y += wrapper.o
 libperf-y += wrapper.o
-libperf-y += sigchain.o
 libperf-y += dso.o
 libperf-y += dso.o
 libperf-y += symbol.o
 libperf-y += symbol.o
 libperf-y += color.o
 libperf-y += color.o
-libperf-y += pager.o
 libperf-y += header.o
 libperf-y += header.o
 libperf-y += callchain.o
 libperf-y += callchain.o
 libperf-y += values.o
 libperf-y += values.o
@@ -87,6 +81,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-bts.o
 libperf-y += parse-branch-options.o
 libperf-y += parse-branch-options.o
 libperf-y += parse-regs-options.o
 libperf-y += parse-regs-options.o
 libperf-y += term.o
 libperf-y += term.o
+libperf-y += help-unknown-cmd.o
 
 
 libperf-$(CONFIG_LIBBPF) += bpf-loader.o
 libperf-$(CONFIG_LIBBPF) += bpf-loader.o
 libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
 libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
@@ -112,7 +107,6 @@ libperf-$(CONFIG_ZLIB) += zlib.o
 libperf-$(CONFIG_LZMA) += lzma.o
 libperf-$(CONFIG_LZMA) += lzma.o
 
 
 CFLAGS_config.o   += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 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
 $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
 	$(call rule_mkdir)
 	$(call rule_mkdir)

+ 1 - 1
tools/perf/util/auxtrace.c

@@ -45,7 +45,7 @@
 #include "event.h"
 #include "event.h"
 #include "session.h"
 #include "session.h"
 #include "debug.h"
 #include "debug.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 
 
 #include "intel-pt.h"
 #include "intel-pt.h"
 #include "intel-bts.h"
 #include "intel-bts.h"

+ 4 - 9
tools/perf/util/cache.h

@@ -4,9 +4,12 @@
 #include <stdbool.h>
 #include <stdbool.h>
 #include "util.h"
 #include "util.h"
 #include "strbuf.h"
 #include "strbuf.h"
+#include <subcmd/pager.h>
 #include "../perf.h"
 #include "../perf.h"
 #include "../ui/ui.h"
 #include "../ui/ui.h"
 
 
+#include <linux/string.h>
+
 #define CMD_EXEC_PATH "--exec-path"
 #define CMD_EXEC_PATH "--exec-path"
 #define CMD_PERF_DIR "--perf-dir="
 #define CMD_PERF_DIR "--perf-dir="
 #define CMD_WORK_TREE "--work-tree="
 #define CMD_WORK_TREE "--work-tree="
@@ -18,6 +21,7 @@
 #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
 #define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
 #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
 #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
 #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
 #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
+#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
 
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(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 int config_error_nonbool(const char *);
 extern const char *perf_config_dirname(const char *, 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);
 char *alias_lookup(const char *alias);
 int split_cmdline(char *cmdline, const char ***argv);
 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, ...)
 extern char *perf_pathdup(const char *fmt, ...)
 	__attribute__((format (printf, 1, 2)));
 	__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 */
 #endif /* __PERF_CACHE_H */

+ 1 - 1
tools/perf/util/cgroup.c

@@ -1,6 +1,6 @@
 #include "util.h"
 #include "util.h"
 #include "../perf.h"
 #include "../perf.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "evsel.h"
 #include "evsel.h"
 #include "cgroup.h"
 #include "cgroup.h"
 #include "evlist.h"
 #include "evlist.h"

+ 1 - 1
tools/perf/util/config.c

@@ -10,7 +10,7 @@
  */
  */
 #include "util.h"
 #include "util.h"
 #include "cache.h"
 #include "cache.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "util/hist.h"  /* perf_hist_config */
 #include "util/hist.h"  /* perf_hist_config */
 #include "util/llvm-utils.h"   /* perf_llvm_config */
 #include "util/llvm-utils.h"   /* perf_llvm_config */
 
 

+ 1 - 1
tools/perf/util/evlist.c

@@ -18,7 +18,7 @@
 #include <unistd.h>
 #include <unistd.h>
 
 
 #include "parse-events.h"
 #include "parse-events.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 
 
 #include <sys/mman.h>
 #include <sys/mman.h>
 
 

+ 13 - 1
tools/perf/util/evsel.c

@@ -36,6 +36,7 @@ static struct {
 	bool cloexec;
 	bool cloexec;
 	bool clockid;
 	bool clockid;
 	bool clockid_wrong;
 	bool clockid_wrong;
+	bool lbr_flags;
 } perf_missing_features;
 } perf_missing_features;
 
 
 static clockid_t clockid;
 static clockid_t clockid;
@@ -574,7 +575,9 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
 			} else {
 			} else {
 				perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
 				perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
 				attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
 				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
 		} else
 			 pr_warning("Cannot use LBR callstack with branch stack. "
 			 pr_warning("Cannot use LBR callstack with branch stack. "
@@ -1337,6 +1340,9 @@ fallback_missing_features:
 		evsel->attr.mmap2 = 0;
 		evsel->attr.mmap2 = 0;
 	if (perf_missing_features.exclude_guest)
 	if (perf_missing_features.exclude_guest)
 		evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
 		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:
 retry_sample_id:
 	if (perf_missing_features.sample_id_all)
 	if (perf_missing_features.sample_id_all)
 		evsel->attr.sample_id_all = 0;
 		evsel->attr.sample_id_all = 0;
@@ -1455,6 +1461,12 @@ try_fallback:
 	} else if (!perf_missing_features.sample_id_all) {
 	} else if (!perf_missing_features.sample_id_all) {
 		perf_missing_features.sample_id_all = true;
 		perf_missing_features.sample_id_all = true;
 		goto retry_sample_id;
 		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:
 out_close:

+ 0 - 149
tools/perf/util/exec_cmd.c

@@ -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);
-}

+ 0 - 13
tools/perf/util/exec_cmd.h

@@ -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 - 0
tools/perf/util/help-unknown-cmd.c

@@ -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 - 0
tools/perf/util/help-unknown-cmd.h


+ 2 - 2
tools/perf/util/intel-pt.c

@@ -1744,7 +1744,7 @@ static void intel_pt_free(struct perf_session *session)
 	auxtrace_heap__free(&pt->heap);
 	auxtrace_heap__free(&pt->heap);
 	intel_pt_free_events(session);
 	intel_pt_free_events(session);
 	session->auxtrace = NULL;
 	session->auxtrace = NULL;
-	thread__delete(pt->unknown_thread);
+	thread__put(pt->unknown_thread);
 	free(pt);
 	free(pt);
 }
 }
 
 
@@ -2153,7 +2153,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
 	return 0;
 	return 0;
 
 
 err_delete_thread:
 err_delete_thread:
-	thread__delete(pt->unknown_thread);
+	thread__zput(pt->unknown_thread);
 err_free_queues:
 err_free_queues:
 	intel_pt_log_disable();
 	intel_pt_log_disable();
 	auxtrace_queues__free(&pt->queues);
 	auxtrace_queues__free(&pt->queues);

+ 12 - 7
tools/perf/util/machine.c

@@ -352,13 +352,18 @@ static void machine__update_thread_pid(struct machine *machine,
 	}
 	}
 
 
 	th->mg = map_groups__get(leader->mg);
 	th->mg = map_groups__get(leader->mg);
-
+out_put:
+	thread__put(leader);
 	return;
 	return;
-
 out_err:
 out_err:
 	pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
 	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,
 static struct thread *____machine__findnew_thread(struct machine *machine,
 						  pid_t pid, pid_t tid,
 						  pid_t pid, pid_t tid,
 						  bool create)
 						  bool create)
@@ -376,7 +381,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
 	if (th != NULL) {
 	if (th != NULL) {
 		if (th->tid == tid) {
 		if (th->tid == tid) {
 			machine__update_thread_pid(machine, th, pid);
 			machine__update_thread_pid(machine, th, pid);
-			return th;
+			return thread__get(th);
 		}
 		}
 
 
 		machine->last_match = NULL;
 		machine->last_match = NULL;
@@ -389,7 +394,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
 		if (th->tid == tid) {
 		if (th->tid == tid) {
 			machine->last_match = th;
 			machine->last_match = th;
 			machine__update_thread_pid(machine, th, pid);
 			machine__update_thread_pid(machine, th, pid);
-			return th;
+			return thread__get(th);
 		}
 		}
 
 
 		if (tid < th->tid)
 		if (tid < th->tid)
@@ -417,7 +422,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
 		if (thread__init_map_groups(th, machine)) {
 		if (thread__init_map_groups(th, machine)) {
 			rb_erase_init(&th->rb_node, &machine->threads);
 			rb_erase_init(&th->rb_node, &machine->threads);
 			RB_CLEAR_NODE(&th->rb_node);
 			RB_CLEAR_NODE(&th->rb_node);
-			thread__delete(th);
+			thread__put(th);
 			return NULL;
 			return NULL;
 		}
 		}
 		/*
 		/*
@@ -441,7 +446,7 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
 	struct thread *th;
 	struct thread *th;
 
 
 	pthread_rwlock_wrlock(&machine->threads_lock);
 	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);
 	pthread_rwlock_unlock(&machine->threads_lock);
 	return th;
 	return th;
 }
 }
@@ -451,7 +456,7 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
 {
 {
 	struct thread *th;
 	struct thread *th;
 	pthread_rwlock_rdlock(&machine->threads_lock);
 	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);
 	pthread_rwlock_unlock(&machine->threads_lock);
 	return th;
 	return th;
 }
 }

+ 1 - 1
tools/perf/util/parse-branch-options.c

@@ -1,7 +1,7 @@
 #include "perf.h"
 #include "perf.h"
 #include "util/util.h"
 #include "util/util.h"
 #include "util/debug.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-branch-options.h"
 #include "util/parse-branch-options.h"
 
 
 #define BRANCH_OPT(n, m) \
 #define BRANCH_OPT(n, m) \

+ 2 - 2
tools/perf/util/parse-events.c

@@ -4,9 +4,9 @@
 #include "../perf.h"
 #include "../perf.h"
 #include "evlist.h"
 #include "evlist.h"
 #include "evsel.h"
 #include "evsel.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "parse-events.h"
 #include "parse-events.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
 #include "string.h"
 #include "string.h"
 #include "symbol.h"
 #include "symbol.h"
 #include "cache.h"
 #include "cache.h"

+ 1 - 1
tools/perf/util/parse-regs-options.c

@@ -1,7 +1,7 @@
 #include "perf.h"
 #include "perf.h"
 #include "util/util.h"
 #include "util/util.h"
 #include "util/debug.h"
 #include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
 #include "util/parse-regs-options.h"
 #include "util/parse-regs-options.h"
 
 
 int
 int

+ 0 - 18
tools/perf/util/path.c

@@ -22,24 +22,6 @@ static const char *get_perf_dir(void)
 	return ".";
 	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 *get_pathname(void)
 {
 {
 	static char pathname_array[4][PATH_MAX];
 	static char pathname_array[4][PATH_MAX];

+ 1 - 1
tools/perf/util/sort.h

@@ -18,7 +18,7 @@
 #include "debug.h"
 #include "debug.h"
 #include "header.h"
 #include "header.h"
 
 
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
 #include "parse-events.h"
 #include "parse-events.h"
 #include "hist.h"
 #include "hist.h"
 #include "thread.h"
 #include "thread.h"

+ 8 - 2
tools/perf/util/thread.c

@@ -19,8 +19,10 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
 		thread->mg = map_groups__new(machine);
 		thread->mg = map_groups__new(machine);
 	} else {
 	} else {
 		leader = __machine__findnew_thread(machine, pid, pid);
 		leader = __machine__findnew_thread(machine, pid, pid);
-		if (leader)
+		if (leader) {
 			thread->mg = map_groups__get(leader->mg);
 			thread->mg = map_groups__get(leader->mg);
+			thread__put(leader);
+		}
 	}
 	}
 
 
 	return thread->mg ? 0 : -1;
 	return thread->mg ? 0 : -1;
@@ -53,7 +55,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
 			goto err_thread;
 			goto err_thread;
 
 
 		list_add(&comm->list, &thread->comm_list);
 		list_add(&comm->list, &thread->comm_list);
-		atomic_set(&thread->refcnt, 0);
+		atomic_set(&thread->refcnt, 1);
 		RB_CLEAR_NODE(&thread->rb_node);
 		RB_CLEAR_NODE(&thread->rb_node);
 	}
 	}
 
 
@@ -95,6 +97,10 @@ struct thread *thread__get(struct thread *thread)
 void thread__put(struct thread *thread)
 void thread__put(struct thread *thread)
 {
 {
 	if (thread && atomic_dec_and_test(&thread->refcnt)) {
 	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);
 		list_del_init(&thread->node);
 		thread__delete(thread);
 		thread__delete(thread);
 	}
 	}

+ 2 - 1
tools/perf/util/util.c

@@ -352,7 +352,8 @@ void sighandler_dump_stack(int sig)
 {
 {
 	psignal(sig, "perf");
 	psignal(sig, "perf");
 	dump_stack();
 	dump_stack();
-	exit(sig);
+	signal(sig, SIG_DFL);
+	raise(sig);
 }
 }
 
 
 int parse_nsec_time(const char *str, u64 *ptime)
 int parse_nsec_time(const char *str, u64 *ptime)

+ 0 - 14
tools/perf/util/util.h

@@ -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 int prefixcmp(const char *str, const char *prefix);
 extern void set_buildid_dir(const char *dir);
 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
 #ifdef __GLIBC_PREREQ
 #if __GLIBC_PREREQ(2, 1)
 #if __GLIBC_PREREQ(2, 1)
 #define HAVE_STRCHRNUL
 #define HAVE_STRCHRNUL
@@ -187,14 +181,6 @@ static inline void *zalloc(size_t size)
 
 
 #define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
 #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 */
 /* Sane ctype - no locale, and works with signed chars */
 #undef isascii
 #undef isascii
 #undef isspace
 #undef isspace