aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/include/tools/endian.h56
-rw-r--r--tools/lib/api/Makefile7
-rw-r--r--tools/lib/api/fd/array.c127
-rw-r--r--tools/lib/api/fd/array.h46
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/perf-probe.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt5
-rw-r--r--tools/perf/Documentation/perf-top.txt9
-rw-r--r--tools/perf/Makefile.perf11
-rw-r--r--tools/perf/arch/arm/tests/dwarf-unwind.c1
-rw-r--r--tools/perf/arch/arm/util/unwind-libunwind.c1
-rw-r--r--tools/perf/arch/arm64/include/perf_regs.h2
-rw-r--r--tools/perf/arch/arm64/util/unwind-libunwind.c1
-rw-r--r--tools/perf/arch/common.c9
-rw-r--r--tools/perf/arch/powerpc/Makefile2
-rw-r--r--tools/perf/arch/powerpc/util/skip-callchain-idx.c1
-rw-r--r--tools/perf/bench/futex-hash.c7
-rw-r--r--tools/perf/bench/futex-requeue.c28
-rw-r--r--tools/perf/bench/futex-wake.c15
-rw-r--r--tools/perf/bench/sched-messaging.c2
-rw-r--r--tools/perf/builtin-annotate.c77
-rw-r--r--tools/perf/builtin-buildid-cache.c44
-rw-r--r--tools/perf/builtin-diff.c6
-rw-r--r--tools/perf/builtin-evlist.c2
-rw-r--r--tools/perf/builtin-help.c20
-rw-r--r--tools/perf/builtin-inject.c33
-rw-r--r--tools/perf/builtin-kmem.c56
-rw-r--r--tools/perf/builtin-kvm.c98
-rw-r--r--tools/perf/builtin-lock.c7
-rw-r--r--tools/perf/builtin-mem.c6
-rw-r--r--tools/perf/builtin-probe.c10
-rw-r--r--tools/perf/builtin-record.c146
-rw-r--r--tools/perf/builtin-report.c23
-rw-r--r--tools/perf/builtin-sched.c9
-rw-r--r--tools/perf/builtin-script.c74
-rw-r--r--tools/perf/builtin-stat.c11
-rw-r--r--tools/perf/builtin-timechart.c8
-rw-r--r--tools/perf/builtin-top.c87
-rw-r--r--tools/perf/builtin-trace.c57
-rw-r--r--tools/perf/config/Makefile52
-rw-r--r--tools/perf/config/feature-checks/Makefile18
-rw-r--r--tools/perf/config/utilities.mak2
-rw-r--r--tools/perf/perf-with-kcore.sh259
-rw-r--r--tools/perf/perf.c10
-rw-r--r--tools/perf/perf.h3
-rw-r--r--tools/perf/tests/builtin-test.c18
-rw-r--r--tools/perf/tests/fdarray.c174
-rw-r--r--tools/perf/tests/mmap-basic.c7
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c5
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c9
-rw-r--r--tools/perf/tests/open-syscall.c3
-rw-r--r--tools/perf/tests/perf-record.c15
-rw-r--r--tools/perf/tests/pmu.c2
-rw-r--r--tools/perf/tests/rdpmc.c6
-rw-r--r--tools/perf/tests/sw-clock.c6
-rw-r--r--tools/perf/tests/switch-tracking.c572
-rw-r--r--tools/perf/tests/task-exit.c8
-rw-r--r--tools/perf/tests/tests.h3
-rw-r--r--tools/perf/ui/browsers/hists.c384
-rw-r--r--tools/perf/ui/gtk/hists.c18
-rw-r--r--tools/perf/ui/hist.c284
-rw-r--r--tools/perf/ui/stdio/hist.c4
-rw-r--r--tools/perf/util/annotate.c21
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c240
-rw-r--r--tools/perf/util/callchain.h6
-rw-r--r--tools/perf/util/cloexec.c35
-rw-r--r--tools/perf/util/color.c16
-rw-r--r--tools/perf/util/color.h1
-rw-r--r--tools/perf/util/comm.c7
-rw-r--r--tools/perf/util/comm.h6
-rw-r--r--tools/perf/util/config.c40
-rw-r--r--tools/perf/util/data.c8
-rw-r--r--tools/perf/util/debug.c36
-rw-r--r--tools/perf/util/debug.h11
-rw-r--r--tools/perf/util/dso.c121
-rw-r--r--tools/perf/util/dso.h16
-rw-r--r--tools/perf/util/event.c14
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c236
-rw-r--r--tools/perf/util/evlist.h21
-rw-r--r--tools/perf/util/evsel.c67
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/header.c32
-rw-r--r--tools/perf/util/hist.c22
-rw-r--r--tools/perf/util/hist.h18
-rw-r--r--tools/perf/util/kvm-stat.h1
-rw-r--r--tools/perf/util/machine.c96
-rw-r--r--tools/perf/util/machine.h26
-rw-r--r--tools/perf/util/map.c1
-rw-r--r--tools/perf/util/ordered-events.c245
-rw-r--r--tools/perf/util/ordered-events.h51
-rw-r--r--tools/perf/util/parse-events.c29
-rw-r--r--tools/perf/util/parse-events.y10
-rw-r--r--tools/perf/util/pmu.c121
-rw-r--r--tools/perf/util/pmu.h25
-rw-r--r--tools/perf/util/probe-event.c181
-rw-r--r--tools/perf/util/probe-event.h3
-rw-r--r--tools/perf/util/probe-finder.c23
-rw-r--r--tools/perf/util/python.c6
-rw-r--r--tools/perf/util/record.c40
-rw-r--r--tools/perf/util/run-command.c9
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c6
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c120
-rw-r--r--tools/perf/util/session.c300
-rw-r--r--tools/perf/util/session.h32
-rw-r--r--tools/perf/util/sort.c119
-rw-r--r--tools/perf/util/sort.h1
-rw-r--r--tools/perf/util/string.c90
-rw-r--r--tools/perf/util/symbol-elf.c31
-rw-r--r--tools/perf/util/symbol.c43
-rw-r--r--tools/perf/util/symbol.h14
-rw-r--r--tools/perf/util/thread.c24
-rw-r--r--tools/perf/util/thread.h10
-rw-r--r--tools/perf/util/tool.h2
-rw-r--r--tools/perf/util/trace-event-scripting.c7
-rw-r--r--tools/perf/util/trace-event.h1
-rw-r--r--tools/perf/util/util.c54
-rw-r--r--tools/perf/util/util.h23
-rwxr-xr-xtools/testing/ktest/ktest.pl61
-rw-r--r--tools/testing/ktest/sample.conf10
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/ftrace/Makefile7
-rw-r--r--tools/testing/selftests/ftrace/README82
-rwxr-xr-xtools/testing/selftests/ftrace/ftracetest253
-rw-r--r--tools/testing/selftests/ftrace/samples/fail.tc4
-rw-r--r--tools/testing/selftests/ftrace/samples/pass.tc3
-rw-r--r--tools/testing/selftests/ftrace/samples/unresolved.tc4
-rw-r--r--tools/testing/selftests/ftrace/samples/unsupported.tc3
-rw-r--r--tools/testing/selftests/ftrace/samples/untested.tc3
-rw-r--r--tools/testing/selftests/ftrace/samples/xfail.tc3
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic1.tc3
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic2.tc7
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic3.tc8
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc11
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc13
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc16
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc15
-rw-r--r--tools/testing/selftests/ftrace/test.d/template9
-rw-r--r--tools/testing/selftests/ipc/Makefile6
-rw-r--r--tools/testing/selftests/kcmp/Makefile6
-rw-r--r--tools/testing/selftests/memfd/Makefile21
-rw-r--r--tools/testing/selftests/memfd/memfd_test.c36
-rw-r--r--tools/testing/selftests/powerpc/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/primitives/Makefile17
l---------tools/testing/selftests/powerpc/primitives/asm/asm-compat.h1
-rw-r--r--tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h0
-rw-r--r--tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c147
l---------tools/testing/selftests/powerpc/primitives/word-at-a-time.h1
-rwxr-xr-x[-rw-r--r--]tools/testing/selftests/rcutorture/bin/config2frag.sh4
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configcheck.sh4
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/configinit.sh4
-rw-r--r--tools/testing/selftests/rcutorture/bin/functions.sh20
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-build.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh2
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh5
-rwxr-xr-x[-rw-r--r--]tools/testing/selftests/rcutorture/bin/kvm.sh6
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-build.sh5
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-console.sh9
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-torture.sh5
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/CFLIST3
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK026
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK036
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK046
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/CFLIST3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS019
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS025
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS0313
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE014
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE073
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh2
-rw-r--r--tools/testing/selftests/rcutorture/doc/initrd.txt1
-rw-r--r--tools/testing/selftests/vm/Makefile1
-rw-r--r--tools/testing/selftests/vm/transhuge-stress.c144
-rw-r--r--tools/usb/ffs-test.c126
-rw-r--r--tools/usb/usbip/.gitignore28
-rw-r--r--tools/usb/usbip/AUTHORS3
-rw-r--r--tools/usb/usbip/COPYING340
-rw-r--r--tools/usb/usbip/INSTALL237
-rw-r--r--tools/usb/usbip/Makefile.am6
-rw-r--r--tools/usb/usbip/README202
-rwxr-xr-xtools/usb/usbip/autogen.sh9
-rwxr-xr-xtools/usb/usbip/cleanup.sh12
-rw-r--r--tools/usb/usbip/configure.ac111
-rw-r--r--tools/usb/usbip/doc/usbip.895
-rw-r--r--tools/usb/usbip/doc/usbipd.891
-rw-r--r--tools/usb/usbip/libsrc/Makefile.am8
-rw-r--r--tools/usb/usbip/libsrc/list.h136
-rw-r--r--tools/usb/usbip/libsrc/names.c504
-rw-r--r--tools/usb/usbip/libsrc/names.h41
-rw-r--r--tools/usb/usbip/libsrc/sysfs_utils.c31
-rw-r--r--tools/usb/usbip/libsrc/sysfs_utils.h8
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.c285
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.h137
-rw-r--r--tools/usb/usbip/libsrc/usbip_host_driver.c280
-rw-r--r--tools/usb/usbip/libsrc/usbip_host_driver.h49
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.c411
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.h59
-rw-r--r--tools/usb/usbip/src/Makefile.am11
-rw-r--r--tools/usb/usbip/src/usbip.c201
-rw-r--r--tools/usb/usbip/src/usbip.h40
-rw-r--r--tools/usb/usbip/src/usbip_attach.c241
-rw-r--r--tools/usb/usbip/src/usbip_bind.c214
-rw-r--r--tools/usb/usbip/src/usbip_detach.c110
-rw-r--r--tools/usb/usbip/src/usbip_list.c283
-rw-r--r--tools/usb/usbip/src/usbip_network.c303
-rw-r--r--tools/usb/usbip/src/usbip_network.h185
-rw-r--r--tools/usb/usbip/src/usbip_port.c57
-rw-r--r--tools/usb/usbip/src/usbip_unbind.c141
-rw-r--r--tools/usb/usbip/src/usbipd.c679
-rw-r--r--tools/usb/usbip/src/utils.c52
-rw-r--r--tools/usb/usbip/src/utils.h25
-rw-r--r--tools/vm/page-types.c1
224 files changed, 10862 insertions, 1623 deletions
diff --git a/tools/include/tools/endian.h b/tools/include/tools/endian.h
new file mode 100644
index 000000000000..8001194008da
--- /dev/null
+++ b/tools/include/tools/endian.h
@@ -0,0 +1,56 @@
1#ifndef _TOOLS_ENDIAN_H
2#define _TOOLS_ENDIAN_H
3
4#include <byteswap.h>
5
6#if __BYTE_ORDER == __LITTLE_ENDIAN
7
8#ifndef htole16
9#define htole16(x) (x)
10#endif
11#ifndef htole32
12#define htole32(x) (x)
13#endif
14#ifndef htole64
15#define htole64(x) (x)
16#endif
17
18#ifndef le16toh
19#define le16toh(x) (x)
20#endif
21
22#ifndef le32toh
23#define le32toh(x) (x)
24#endif
25
26#ifndef le64toh
27#define le64toh(x) (x)
28#endif
29
30#else /* __BYTE_ORDER */
31
32#ifndef htole16
33#define htole16(x) __bswap_16(x)
34#endif
35#ifndef htole32
36#define htole32(x) __bswap_32(x)
37#endif
38#ifndef htole64
39#define htole64(x) __bswap_64(x)
40#endif
41
42#ifndef le16toh
43#define le16toh(x) __bswap_16(x)
44#endif
45
46#ifndef le32toh
47#define le32toh(x) __bswap_32(x)
48#endif
49
50#ifndef le64toh
51#define le64toh(x) __bswap_64(x)
52#endif
53
54#endif
55
56#endif /* _TOOLS_ENDIAN_H */
diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile
index ce00f7ee6455..36c08b1f4afb 100644
--- a/tools/lib/api/Makefile
+++ b/tools/lib/api/Makefile
@@ -10,9 +10,14 @@ LIB_OBJS=
10 10
11LIB_H += fs/debugfs.h 11LIB_H += fs/debugfs.h
12LIB_H += fs/fs.h 12LIB_H += fs/fs.h
13# See comment below about piggybacking...
14LIB_H += fd/array.h
13 15
14LIB_OBJS += $(OUTPUT)fs/debugfs.o 16LIB_OBJS += $(OUTPUT)fs/debugfs.o
15LIB_OBJS += $(OUTPUT)fs/fs.o 17LIB_OBJS += $(OUTPUT)fs/fs.o
18# XXX piggybacking here, need to introduce libapikfd, or rename this
19# to plain libapik.a and make it have it all api goodies
20LIB_OBJS += $(OUTPUT)fd/array.o
16 21
17LIBFILE = libapikfs.a 22LIBFILE = libapikfs.a
18 23
@@ -29,7 +34,7 @@ $(LIBFILE): $(LIB_OBJS)
29$(LIB_OBJS): $(LIB_H) 34$(LIB_OBJS): $(LIB_H)
30 35
31libapi_dirs: 36libapi_dirs:
32 $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/ 37 $(QUIET_MKDIR)mkdir -p $(OUTPUT)fd $(OUTPUT)fs
33 38
34$(OUTPUT)%.o: %.c libapi_dirs 39$(OUTPUT)%.o: %.c libapi_dirs
35 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 40 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
diff --git a/tools/lib/api/fd/array.c b/tools/lib/api/fd/array.c
new file mode 100644
index 000000000000..0e636c4339b8
--- /dev/null
+++ b/tools/lib/api/fd/array.c
@@ -0,0 +1,127 @@
1/*
2 * Copyright (C) 2014, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Released under the GPL v2. (and only v2, not any later version)
5 */
6#include "array.h"
7#include <errno.h>
8#include <fcntl.h>
9#include <poll.h>
10#include <stdlib.h>
11#include <unistd.h>
12
13void fdarray__init(struct fdarray *fda, int nr_autogrow)
14{
15 fda->entries = NULL;
16 fda->priv = NULL;
17 fda->nr = fda->nr_alloc = 0;
18 fda->nr_autogrow = nr_autogrow;
19}
20
21int fdarray__grow(struct fdarray *fda, int nr)
22{
23 void *priv;
24 int nr_alloc = fda->nr_alloc + nr;
25 size_t psize = sizeof(fda->priv[0]) * nr_alloc;
26 size_t size = sizeof(struct pollfd) * nr_alloc;
27 struct pollfd *entries = realloc(fda->entries, size);
28
29 if (entries == NULL)
30 return -ENOMEM;
31
32 priv = realloc(fda->priv, psize);
33 if (priv == NULL) {
34 free(entries);
35 return -ENOMEM;
36 }
37
38 fda->nr_alloc = nr_alloc;
39 fda->entries = entries;
40 fda->priv = priv;
41 return 0;
42}
43
44struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow)
45{
46 struct fdarray *fda = calloc(1, sizeof(*fda));
47
48 if (fda != NULL) {
49 if (fdarray__grow(fda, nr_alloc)) {
50 free(fda);
51 fda = NULL;
52 } else {
53 fda->nr_autogrow = nr_autogrow;
54 }
55 }
56
57 return fda;
58}
59
60void fdarray__exit(struct fdarray *fda)
61{
62 free(fda->entries);
63 free(fda->priv);
64 fdarray__init(fda, 0);
65}
66
67void fdarray__delete(struct fdarray *fda)
68{
69 fdarray__exit(fda);
70 free(fda);
71}
72
73int fdarray__add(struct fdarray *fda, int fd, short revents)
74{
75 int pos = fda->nr;
76
77 if (fda->nr == fda->nr_alloc &&
78 fdarray__grow(fda, fda->nr_autogrow) < 0)
79 return -ENOMEM;
80
81 fda->entries[fda->nr].fd = fd;
82 fda->entries[fda->nr].events = revents;
83 fda->nr++;
84 return pos;
85}
86
87int fdarray__filter(struct fdarray *fda, short revents,
88 void (*entry_destructor)(struct fdarray *fda, int fd))
89{
90 int fd, nr = 0;
91
92 if (fda->nr == 0)
93 return 0;
94
95 for (fd = 0; fd < fda->nr; ++fd) {
96 if (fda->entries[fd].revents & revents) {
97 if (entry_destructor)
98 entry_destructor(fda, fd);
99
100 continue;
101 }
102
103 if (fd != nr) {
104 fda->entries[nr] = fda->entries[fd];
105 fda->priv[nr] = fda->priv[fd];
106 }
107
108 ++nr;
109 }
110
111 return fda->nr = nr;
112}
113
114int fdarray__poll(struct fdarray *fda, int timeout)
115{
116 return poll(fda->entries, fda->nr, timeout);
117}
118
119int fdarray__fprintf(struct fdarray *fda, FILE *fp)
120{
121 int fd, printed = fprintf(fp, "%d [ ", fda->nr);
122
123 for (fd = 0; fd < fda->nr; ++fd)
124 printed += fprintf(fp, "%s%d", fd ? ", " : "", fda->entries[fd].fd);
125
126 return printed + fprintf(fp, " ]");
127}
diff --git a/tools/lib/api/fd/array.h b/tools/lib/api/fd/array.h
new file mode 100644
index 000000000000..45db01818f45
--- /dev/null
+++ b/tools/lib/api/fd/array.h
@@ -0,0 +1,46 @@
1#ifndef __API_FD_ARRAY__
2#define __API_FD_ARRAY__
3
4#include <stdio.h>
5
6struct pollfd;
7
8/**
9 * struct fdarray: Array of file descriptors
10 *
11 * @priv: Per array entry priv area, users should access just its contents,
12 * not set it to anything, as it is kept in synch with @entries, being
13 * realloc'ed, * for instance, in fdarray__{grow,filter}.
14 *
15 * I.e. using 'fda->priv[N].idx = * value' where N < fda->nr is ok,
16 * but doing 'fda->priv = malloc(M)' is not allowed.
17 */
18struct fdarray {
19 int nr;
20 int nr_alloc;
21 int nr_autogrow;
22 struct pollfd *entries;
23 union {
24 int idx;
25 } *priv;
26};
27
28void fdarray__init(struct fdarray *fda, int nr_autogrow);
29void fdarray__exit(struct fdarray *fda);
30
31struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow);
32void fdarray__delete(struct fdarray *fda);
33
34int fdarray__add(struct fdarray *fda, int fd, short revents);
35int fdarray__poll(struct fdarray *fda, int timeout);
36int fdarray__filter(struct fdarray *fda, short revents,
37 void (*entry_destructor)(struct fdarray *fda, int fd));
38int fdarray__grow(struct fdarray *fda, int extra);
39int fdarray__fprintf(struct fdarray *fda, FILE *fp);
40
41static inline int fdarray__available_entries(struct fdarray *fda)
42{
43 return fda->nr_alloc - fda->nr;
44}
45
46#endif /* __API_FD_ARRAY__ */
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 782d86e961b9..717221e98450 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -15,6 +15,7 @@ perf.data
15perf.data.old 15perf.data.old
16output.svg 16output.svg
17perf-archive 17perf-archive
18perf-with-kcore
18tags 19tags
19TAGS 20TAGS
20cscope* 21cscope*
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 1513935c399b..aaa869be3dc1 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -104,6 +104,9 @@ OPTIONS
104 Specify path to the executable or shared library file for user 104 Specify path to the executable or shared library file for user
105 space tracing. Can also be used with --funcs option. 105 space tracing. Can also be used with --funcs option.
106 106
107--demangle-kernel::
108 Demangle kernel symbols.
109
107In absence of -m/-x options, perf probe checks if the first argument after 110In absence of -m/-x options, perf probe checks if the first argument after
108the options is an absolute path name. If its an absolute path, perf probe 111the options is an absolute path name. If its an absolute path, perf probe
109uses it as a target module/target user space binary to probe. 112uses it as a target module/target user space binary to probe.
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index d2b59af62bc0..0927bf4e6c2a 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -147,7 +147,7 @@ OPTIONS
147-w:: 147-w::
148--column-widths=<width[,width...]>:: 148--column-widths=<width[,width...]>::
149 Force each column width to the provided list, for large terminal 149 Force each column width to the provided list, for large terminal
150 readability. 150 readability. 0 means no limit (default behavior).
151 151
152-t:: 152-t::
153--field-separator=:: 153--field-separator=::
@@ -276,6 +276,9 @@ OPTIONS
276 Demangle symbol names to human readable form. It's enabled by default, 276 Demangle symbol names to human readable form. It's enabled by default,
277 disable with --no-demangle. 277 disable with --no-demangle.
278 278
279--demangle-kernel::
280 Demangle kernel symbol names to human readable form (for C++ kernels).
281
279--mem-mode:: 282--mem-mode::
280 Use the data addresses of samples in addition to instruction addresses 283 Use the data addresses of samples in addition to instruction addresses
281 to build the histograms. To generate meaningful output, the perf.data 284 to build the histograms. To generate meaningful output, the perf.data
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 180ae02137a5..3265b1070518 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -98,6 +98,9 @@ Default is to monitor all CPUS.
98--hide_user_symbols:: 98--hide_user_symbols::
99 Hide user symbols. 99 Hide user symbols.
100 100
101--demangle-kernel::
102 Demangle kernel symbols.
103
101-D:: 104-D::
102--dump-symtab:: 105--dump-symtab::
103 Dump the symbol table used for profiling. 106 Dump the symbol table used for profiling.
@@ -193,6 +196,12 @@ Default is to monitor all CPUS.
193 sum of shown entries will be always 100%. "absolute" means it retains 196 sum of shown entries will be always 100%. "absolute" means it retains
194 the original value before and after the filter is applied. 197 the original value before and after the filter is applied.
195 198
199-w::
200--column-widths=<width[,width...]>::
201 Force each column width to the provided list, for large terminal
202 readability. 0 means no limit (default behavior).
203
204
196INTERACTIVE PROMPTING KEYS 205INTERACTIVE PROMPTING KEYS
197-------------------------- 206--------------------------
198 207
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 2240974b7745..262916f4a377 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -126,6 +126,7 @@ PYRF_OBJS =
126SCRIPT_SH = 126SCRIPT_SH =
127 127
128SCRIPT_SH += perf-archive.sh 128SCRIPT_SH += perf-archive.sh
129SCRIPT_SH += perf-with-kcore.sh
129 130
130grep-libs = $(filter -l%,$(1)) 131grep-libs = $(filter -l%,$(1))
131strip-libs = $(filter-out -l%,$(1)) 132strip-libs = $(filter-out -l%,$(1))
@@ -263,6 +264,7 @@ LIB_H += util/xyarray.h
263LIB_H += util/header.h 264LIB_H += util/header.h
264LIB_H += util/help.h 265LIB_H += util/help.h
265LIB_H += util/session.h 266LIB_H += util/session.h
267LIB_H += util/ordered-events.h
266LIB_H += util/strbuf.h 268LIB_H += util/strbuf.h
267LIB_H += util/strlist.h 269LIB_H += util/strlist.h
268LIB_H += util/strfilter.h 270LIB_H += util/strfilter.h
@@ -347,6 +349,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
347LIB_OBJS += $(OUTPUT)util/map.o 349LIB_OBJS += $(OUTPUT)util/map.o
348LIB_OBJS += $(OUTPUT)util/pstack.o 350LIB_OBJS += $(OUTPUT)util/pstack.o
349LIB_OBJS += $(OUTPUT)util/session.o 351LIB_OBJS += $(OUTPUT)util/session.o
352LIB_OBJS += $(OUTPUT)util/ordered-events.o
350LIB_OBJS += $(OUTPUT)util/comm.o 353LIB_OBJS += $(OUTPUT)util/comm.o
351LIB_OBJS += $(OUTPUT)util/thread.o 354LIB_OBJS += $(OUTPUT)util/thread.o
352LIB_OBJS += $(OUTPUT)util/thread_map.o 355LIB_OBJS += $(OUTPUT)util/thread_map.o
@@ -399,6 +402,7 @@ LIB_OBJS += $(OUTPUT)tests/perf-record.o
399LIB_OBJS += $(OUTPUT)tests/rdpmc.o 402LIB_OBJS += $(OUTPUT)tests/rdpmc.o
400LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o 403LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
401LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o 404LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
405LIB_OBJS += $(OUTPUT)tests/fdarray.o
402LIB_OBJS += $(OUTPUT)tests/pmu.o 406LIB_OBJS += $(OUTPUT)tests/pmu.o
403LIB_OBJS += $(OUTPUT)tests/hists_common.o 407LIB_OBJS += $(OUTPUT)tests/hists_common.o
404LIB_OBJS += $(OUTPUT)tests/hists_link.o 408LIB_OBJS += $(OUTPUT)tests/hists_link.o
@@ -423,6 +427,7 @@ endif
423endif 427endif
424LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o 428LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o
425LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o 429LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o
430LIB_OBJS += $(OUTPUT)tests/switch-tracking.o
426 431
427BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 432BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
428BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 433BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -765,7 +770,7 @@ $(LIBTRACEEVENT)-clean:
765install-traceevent-plugins: $(LIBTRACEEVENT) 770install-traceevent-plugins: $(LIBTRACEEVENT)
766 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins 771 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
767 772
768LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch]) 773LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch])
769 774
770# if subdir is set, we've been called from above so target has been built 775# if subdir is set, we've been called from above so target has been built
771# already 776# already
@@ -875,6 +880,8 @@ install-bin: all install-gtk
875 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 880 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
876 $(call QUIET_INSTALL, perf-archive) \ 881 $(call QUIET_INSTALL, perf-archive) \
877 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 882 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
883 $(call QUIET_INSTALL, perf-with-kcore) \
884 $(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
878ifndef NO_LIBPERL 885ifndef NO_LIBPERL
879 $(call QUIET_INSTALL, perl-scripts) \ 886 $(call QUIET_INSTALL, perl-scripts) \
880 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ 887 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
@@ -920,7 +927,7 @@ config-clean:
920 @$(MAKE) -C config/feature-checks clean >/dev/null 927 @$(MAKE) -C config/feature-checks clean >/dev/null
921 928
922clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean 929clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
923 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) 930 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
924 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf 931 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
925 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* 932 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
926 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 933 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
diff --git a/tools/perf/arch/arm/tests/dwarf-unwind.c b/tools/perf/arch/arm/tests/dwarf-unwind.c
index 9f870d27cb39..62eff847f91c 100644
--- a/tools/perf/arch/arm/tests/dwarf-unwind.c
+++ b/tools/perf/arch/arm/tests/dwarf-unwind.c
@@ -3,6 +3,7 @@
3#include "thread.h" 3#include "thread.h"
4#include "map.h" 4#include "map.h"
5#include "event.h" 5#include "event.h"
6#include "debug.h"
6#include "tests/tests.h" 7#include "tests/tests.h"
7 8
8#define STACK_SIZE 8192 9#define STACK_SIZE 8192
diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c
index 729ed69a6664..62c397ed3d97 100644
--- a/tools/perf/arch/arm/util/unwind-libunwind.c
+++ b/tools/perf/arch/arm/util/unwind-libunwind.c
@@ -3,6 +3,7 @@
3#include <libunwind.h> 3#include <libunwind.h>
4#include "perf_regs.h" 4#include "perf_regs.h"
5#include "../../util/unwind.h" 5#include "../../util/unwind.h"
6#include "../../util/debug.h"
6 7
7int libunwind__arch_reg_id(int regnum) 8int libunwind__arch_reg_id(int regnum)
8{ 9{
diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h
index e9441b9e2a30..1d3f39c3aa56 100644
--- a/tools/perf/arch/arm64/include/perf_regs.h
+++ b/tools/perf/arch/arm64/include/perf_regs.h
@@ -6,6 +6,8 @@
6#include <asm/perf_regs.h> 6#include <asm/perf_regs.h>
7 7
8#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1) 8#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1)
9#define PERF_REGS_MAX PERF_REG_ARM64_MAX
10
9#define PERF_REG_IP PERF_REG_ARM64_PC 11#define PERF_REG_IP PERF_REG_ARM64_PC
10#define PERF_REG_SP PERF_REG_ARM64_SP 12#define PERF_REG_SP PERF_REG_ARM64_SP
11 13
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c
index 436ee43859dc..a87afa91a99e 100644
--- a/tools/perf/arch/arm64/util/unwind-libunwind.c
+++ b/tools/perf/arch/arm64/util/unwind-libunwind.c
@@ -3,6 +3,7 @@
3#include <libunwind.h> 3#include <libunwind.h>
4#include "perf_regs.h" 4#include "perf_regs.h"
5#include "../../util/unwind.h" 5#include "../../util/unwind.h"
6#include "../../util/debug.h"
6 7
7int libunwind__arch_reg_id(int regnum) 8int libunwind__arch_reg_id(int regnum)
8{ 9{
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
index 42faf369211c..49776f190abf 100644
--- a/tools/perf/arch/common.c
+++ b/tools/perf/arch/common.c
@@ -12,6 +12,11 @@ const char *const arm_triplets[] = {
12 NULL 12 NULL
13}; 13};
14 14
15const char *const arm64_triplets[] = {
16 "aarch64-linux-android-",
17 NULL
18};
19
15const char *const powerpc_triplets[] = { 20const char *const powerpc_triplets[] = {
16 "powerpc-unknown-linux-gnu-", 21 "powerpc-unknown-linux-gnu-",
17 "powerpc64-unknown-linux-gnu-", 22 "powerpc64-unknown-linux-gnu-",
@@ -105,6 +110,8 @@ static const char *normalize_arch(char *arch)
105 return "x86"; 110 return "x86";
106 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) 111 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
107 return "sparc"; 112 return "sparc";
113 if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64"))
114 return "arm64";
108 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) 115 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
109 return "arm"; 116 return "arm";
110 if (!strncmp(arch, "s390", 4)) 117 if (!strncmp(arch, "s390", 4))
@@ -159,6 +166,8 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
159 166
160 if (!strcmp(arch, "arm")) 167 if (!strcmp(arch, "arm"))
161 path_list = arm_triplets; 168 path_list = arm_triplets;
169 else if (!strcmp(arch, "arm64"))
170 path_list = arm64_triplets;
162 else if (!strcmp(arch, "powerpc")) 171 else if (!strcmp(arch, "powerpc"))
163 path_list = powerpc_triplets; 172 path_list = powerpc_triplets;
164 else if (!strcmp(arch, "sh")) 173 else if (!strcmp(arch, "sh"))
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index b92219b1900d..6f7782bea5dd 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -1,6 +1,6 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
4endif 5endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
index a7c23a4b3778..d73ef8bb08c7 100644
--- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c
+++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
@@ -15,6 +15,7 @@
15 15
16#include "util/thread.h" 16#include "util/thread.h"
17#include "util/callchain.h" 17#include "util/callchain.h"
18#include "util/debug.h"
18 19
19/* 20/*
20 * When saving the callchain on Power, the kernel conservatively saves 21 * When saving the callchain on Power, the kernel conservatively saves
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
index a84206e9c4aa..fc9bebd2cca0 100644
--- a/tools/perf/bench/futex-hash.c
+++ b/tools/perf/bench/futex-hash.c
@@ -26,6 +26,7 @@ static unsigned int nsecs = 10;
26/* amount of futexes per thread */ 26/* amount of futexes per thread */
27static unsigned int nfutexes = 1024; 27static unsigned int nfutexes = 1024;
28static bool fshared = false, done = false, silent = false; 28static bool fshared = false, done = false, silent = false;
29static int futex_flag = 0;
29 30
30struct timeval start, end, runtime; 31struct timeval start, end, runtime;
31static pthread_mutex_t thread_lock; 32static pthread_mutex_t thread_lock;
@@ -75,8 +76,7 @@ static void *workerfn(void *arg)
75 * such as internal waitqueue handling, thus enlarging 76 * such as internal waitqueue handling, thus enlarging
76 * the critical region protected by hb->lock. 77 * the critical region protected by hb->lock.
77 */ 78 */
78 ret = futex_wait(&w->futex[i], 1234, NULL, 79 ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag);
79 fshared ? 0 : FUTEX_PRIVATE_FLAG);
80 if (!silent && 80 if (!silent &&
81 (!ret || errno != EAGAIN || errno != EWOULDBLOCK)) 81 (!ret || errno != EAGAIN || errno != EWOULDBLOCK))
82 warn("Non-expected futex return call"); 82 warn("Non-expected futex return call");
@@ -135,6 +135,9 @@ int bench_futex_hash(int argc, const char **argv,
135 if (!worker) 135 if (!worker)
136 goto errmem; 136 goto errmem;
137 137
138 if (!fshared)
139 futex_flag = FUTEX_PRIVATE_FLAG;
140
138 printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n", 141 printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
139 getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs); 142 getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs);
140 143
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
index 732403bfd31a..bedff6b5b3cf 100644
--- a/tools/perf/bench/futex-requeue.c
+++ b/tools/perf/bench/futex-requeue.c
@@ -30,16 +30,18 @@ static u_int32_t futex1 = 0, futex2 = 0;
30static unsigned int nrequeue = 1; 30static unsigned int nrequeue = 1;
31 31
32static pthread_t *worker; 32static pthread_t *worker;
33static bool done = 0, silent = 0; 33static bool done = false, silent = false, fshared = false;
34static pthread_mutex_t thread_lock; 34static pthread_mutex_t thread_lock;
35static pthread_cond_t thread_parent, thread_worker; 35static pthread_cond_t thread_parent, thread_worker;
36static struct stats requeuetime_stats, requeued_stats; 36static struct stats requeuetime_stats, requeued_stats;
37static unsigned int ncpus, threads_starting, nthreads = 0; 37static unsigned int ncpus, threads_starting, nthreads = 0;
38static int futex_flag = 0;
38 39
39static const struct option options[] = { 40static const struct option options[] = {
40 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 41 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
41 OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"), 42 OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"),
42 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 43 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
44 OPT_BOOLEAN( 'S', "shared", &fshared, "Use shared futexes instead of private ones"),
43 OPT_END() 45 OPT_END()
44}; 46};
45 47
@@ -70,7 +72,7 @@ static void *workerfn(void *arg __maybe_unused)
70 pthread_cond_wait(&thread_worker, &thread_lock); 72 pthread_cond_wait(&thread_worker, &thread_lock);
71 pthread_mutex_unlock(&thread_lock); 73 pthread_mutex_unlock(&thread_lock);
72 74
73 futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG); 75 futex_wait(&futex1, 0, NULL, futex_flag);
74 return NULL; 76 return NULL;
75} 77}
76 78
@@ -127,9 +129,12 @@ int bench_futex_requeue(int argc, const char **argv,
127 if (!worker) 129 if (!worker)
128 err(EXIT_FAILURE, "calloc"); 130 err(EXIT_FAILURE, "calloc");
129 131
130 printf("Run summary [PID %d]: Requeuing %d threads (from %p to %p), " 132 if (!fshared)
131 "%d at a time.\n\n", 133 futex_flag = FUTEX_PRIVATE_FLAG;
132 getpid(), nthreads, &futex1, &futex2, nrequeue); 134
135 printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %p), "
136 "%d at a time.\n\n", getpid(), nthreads,
137 fshared ? "shared":"private", &futex1, &futex2, nrequeue);
133 138
134 init_stats(&requeued_stats); 139 init_stats(&requeued_stats);
135 init_stats(&requeuetime_stats); 140 init_stats(&requeuetime_stats);
@@ -156,16 +161,20 @@ int bench_futex_requeue(int argc, const char **argv,
156 161
157 /* Ok, all threads are patiently blocked, start requeueing */ 162 /* Ok, all threads are patiently blocked, start requeueing */
158 gettimeofday(&start, NULL); 163 gettimeofday(&start, NULL);
159 for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) 164 for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) {
160 /* 165 /*
161 * Do not wakeup any tasks blocked on futex1, allowing 166 * Do not wakeup any tasks blocked on futex1, allowing
162 * us to really measure futex_wait functionality. 167 * us to really measure futex_wait functionality.
163 */ 168 */
164 futex_cmp_requeue(&futex1, 0, &futex2, 0, nrequeue, 169 futex_cmp_requeue(&futex1, 0, &futex2, 0,
165 FUTEX_PRIVATE_FLAG); 170 nrequeue, futex_flag);
171 }
166 gettimeofday(&end, NULL); 172 gettimeofday(&end, NULL);
167 timersub(&end, &start, &runtime); 173 timersub(&end, &start, &runtime);
168 174
175 if (nrequeued > nthreads)
176 nrequeued = nthreads;
177
169 update_stats(&requeued_stats, nrequeued); 178 update_stats(&requeued_stats, nrequeued);
170 update_stats(&requeuetime_stats, runtime.tv_usec); 179 update_stats(&requeuetime_stats, runtime.tv_usec);
171 180
@@ -175,7 +184,7 @@ int bench_futex_requeue(int argc, const char **argv,
175 } 184 }
176 185
177 /* everybody should be blocked on futex2, wake'em up */ 186 /* everybody should be blocked on futex2, wake'em up */
178 nrequeued = futex_wake(&futex2, nthreads, FUTEX_PRIVATE_FLAG); 187 nrequeued = futex_wake(&futex2, nthreads, futex_flag);
179 if (nthreads != nrequeued) 188 if (nthreads != nrequeued)
180 warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads); 189 warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads);
181 190
@@ -184,7 +193,6 @@ int bench_futex_requeue(int argc, const char **argv,
184 if (ret) 193 if (ret)
185 err(EXIT_FAILURE, "pthread_join"); 194 err(EXIT_FAILURE, "pthread_join");
186 } 195 }
187
188 } 196 }
189 197
190 /* cleanup & report results */ 198 /* cleanup & report results */
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
index 50022cbce87e..929f762be47e 100644
--- a/tools/perf/bench/futex-wake.c
+++ b/tools/perf/bench/futex-wake.c
@@ -31,16 +31,18 @@ static u_int32_t futex1 = 0;
31static unsigned int nwakes = 1; 31static unsigned int nwakes = 1;
32 32
33pthread_t *worker; 33pthread_t *worker;
34static bool done = false, silent = false; 34static bool done = false, silent = false, fshared = false;
35static pthread_mutex_t thread_lock; 35static pthread_mutex_t thread_lock;
36static pthread_cond_t thread_parent, thread_worker; 36static pthread_cond_t thread_parent, thread_worker;
37static struct stats waketime_stats, wakeup_stats; 37static struct stats waketime_stats, wakeup_stats;
38static unsigned int ncpus, threads_starting, nthreads = 0; 38static unsigned int ncpus, threads_starting, nthreads = 0;
39static int futex_flag = 0;
39 40
40static const struct option options[] = { 41static const struct option options[] = {
41 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 42 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
42 OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"), 43 OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"),
43 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 44 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
45 OPT_BOOLEAN( 'S', "shared", &fshared, "Use shared futexes instead of private ones"),
44 OPT_END() 46 OPT_END()
45}; 47};
46 48
@@ -58,7 +60,7 @@ static void *workerfn(void *arg __maybe_unused)
58 pthread_cond_wait(&thread_worker, &thread_lock); 60 pthread_cond_wait(&thread_worker, &thread_lock);
59 pthread_mutex_unlock(&thread_lock); 61 pthread_mutex_unlock(&thread_lock);
60 62
61 futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG); 63 futex_wait(&futex1, 0, NULL, futex_flag);
62 return NULL; 64 return NULL;
63} 65}
64 66
@@ -130,9 +132,12 @@ int bench_futex_wake(int argc, const char **argv,
130 if (!worker) 132 if (!worker)
131 err(EXIT_FAILURE, "calloc"); 133 err(EXIT_FAILURE, "calloc");
132 134
133 printf("Run summary [PID %d]: blocking on %d threads (at futex %p), " 135 if (!fshared)
136 futex_flag = FUTEX_PRIVATE_FLAG;
137
138 printf("Run summary [PID %d]: blocking on %d threads (at [%s] futex %p), "
134 "waking up %d at a time.\n\n", 139 "waking up %d at a time.\n\n",
135 getpid(), nthreads, &futex1, nwakes); 140 getpid(), nthreads, fshared ? "shared":"private", &futex1, nwakes);
136 141
137 init_stats(&wakeup_stats); 142 init_stats(&wakeup_stats);
138 init_stats(&waketime_stats); 143 init_stats(&waketime_stats);
@@ -160,7 +165,7 @@ int bench_futex_wake(int argc, const char **argv,
160 /* Ok, all threads are patiently blocked, start waking folks up */ 165 /* Ok, all threads are patiently blocked, start waking folks up */
161 gettimeofday(&start, NULL); 166 gettimeofday(&start, NULL);
162 while (nwoken != nthreads) 167 while (nwoken != nthreads)
163 nwoken += futex_wake(&futex1, nwakes, FUTEX_PRIVATE_FLAG); 168 nwoken += futex_wake(&futex1, nwakes, futex_flag);
164 gettimeofday(&end, NULL); 169 gettimeofday(&end, NULL);
165 timersub(&end, &start, &runtime); 170 timersub(&end, &start, &runtime);
166 171
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index 52a56599a543..d7f281c2828d 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -26,7 +26,7 @@
26#include <sys/socket.h> 26#include <sys/socket.h>
27#include <sys/wait.h> 27#include <sys/wait.h>
28#include <sys/time.h> 28#include <sys/time.h>
29#include <sys/poll.h> 29#include <poll.h>
30#include <limits.h> 30#include <limits.h>
31#include <err.h> 31#include <err.h>
32 32
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 1ec429fef2be..be5939418425 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -36,7 +36,8 @@
36 36
37struct perf_annotate { 37struct perf_annotate {
38 struct perf_tool tool; 38 struct perf_tool tool;
39 bool force, use_tui, use_stdio, use_gtk; 39 struct perf_session *session;
40 bool use_tui, use_stdio, use_gtk;
40 bool full_paths; 41 bool full_paths;
41 bool print_line; 42 bool print_line;
42 bool skip_missing; 43 bool skip_missing;
@@ -188,18 +189,9 @@ find_next:
188static int __cmd_annotate(struct perf_annotate *ann) 189static int __cmd_annotate(struct perf_annotate *ann)
189{ 190{
190 int ret; 191 int ret;
191 struct perf_session *session; 192 struct perf_session *session = ann->session;
192 struct perf_evsel *pos; 193 struct perf_evsel *pos;
193 u64 total_nr_samples; 194 u64 total_nr_samples;
194 struct perf_data_file file = {
195 .path = input_name,
196 .mode = PERF_DATA_MODE_READ,
197 .force = ann->force,
198 };
199
200 session = perf_session__new(&file, false, &ann->tool);
201 if (session == NULL)
202 return -ENOMEM;
203 195
204 machines__set_symbol_filter(&session->machines, symbol__annotate_init); 196 machines__set_symbol_filter(&session->machines, symbol__annotate_init);
205 197
@@ -207,22 +199,22 @@ static int __cmd_annotate(struct perf_annotate *ann)
207 ret = perf_session__cpu_bitmap(session, ann->cpu_list, 199 ret = perf_session__cpu_bitmap(session, ann->cpu_list,
208 ann->cpu_bitmap); 200 ann->cpu_bitmap);
209 if (ret) 201 if (ret)
210 goto out_delete; 202 goto out;
211 } 203 }
212 204
213 if (!objdump_path) { 205 if (!objdump_path) {
214 ret = perf_session_env__lookup_objdump(&session->header.env); 206 ret = perf_session_env__lookup_objdump(&session->header.env);
215 if (ret) 207 if (ret)
216 goto out_delete; 208 goto out;
217 } 209 }
218 210
219 ret = perf_session__process_events(session, &ann->tool); 211 ret = perf_session__process_events(session, &ann->tool);
220 if (ret) 212 if (ret)
221 goto out_delete; 213 goto out;
222 214
223 if (dump_trace) { 215 if (dump_trace) {
224 perf_session__fprintf_nr_events(session, stdout); 216 perf_session__fprintf_nr_events(session, stdout);
225 goto out_delete; 217 goto out;
226 } 218 }
227 219
228 if (verbose > 3) 220 if (verbose > 3)
@@ -250,8 +242,8 @@ static int __cmd_annotate(struct perf_annotate *ann)
250 } 242 }
251 243
252 if (total_nr_samples == 0) { 244 if (total_nr_samples == 0) {
253 ui__error("The %s file has no samples!\n", file.path); 245 ui__error("The %s file has no samples!\n", session->file->path);
254 goto out_delete; 246 goto out;
255 } 247 }
256 248
257 if (use_browser == 2) { 249 if (use_browser == 2) {
@@ -261,24 +253,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
261 "perf_gtk__show_annotations"); 253 "perf_gtk__show_annotations");
262 if (show_annotations == NULL) { 254 if (show_annotations == NULL) {
263 ui__error("GTK browser not found!\n"); 255 ui__error("GTK browser not found!\n");
264 goto out_delete; 256 goto out;
265 } 257 }
266 show_annotations(); 258 show_annotations();
267 } 259 }
268 260
269out_delete: 261out:
270 /*
271 * Speed up the exit process, for large files this can
272 * take quite a while.
273 *
274 * XXX Enable this when using valgrind or if we ever
275 * librarize this command.
276 *
277 * Also experiment with obstacks to see how much speed
278 * up we'll get here.
279 *
280 * perf_session__delete(session);
281 */
282 return ret; 262 return ret;
283} 263}
284 264
@@ -297,10 +277,14 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
297 .comm = perf_event__process_comm, 277 .comm = perf_event__process_comm,
298 .exit = perf_event__process_exit, 278 .exit = perf_event__process_exit,
299 .fork = perf_event__process_fork, 279 .fork = perf_event__process_fork,
300 .ordered_samples = true, 280 .ordered_events = true,
301 .ordering_requires_timestamps = true, 281 .ordering_requires_timestamps = true,
302 }, 282 },
303 }; 283 };
284 struct perf_data_file file = {
285 .path = input_name,
286 .mode = PERF_DATA_MODE_READ,
287 };
304 const struct option options[] = { 288 const struct option options[] = {
305 OPT_STRING('i', "input", &input_name, "file", 289 OPT_STRING('i', "input", &input_name, "file",
306 "input file name"), 290 "input file name"),
@@ -308,7 +292,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
308 "only consider symbols in these dsos"), 292 "only consider symbols in these dsos"),
309 OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", 293 OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
310 "symbol to annotate"), 294 "symbol to annotate"),
311 OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"), 295 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
312 OPT_INCR('v', "verbose", &verbose, 296 OPT_INCR('v', "verbose", &verbose,
313 "be more verbose (show symbol address, etc)"), 297 "be more verbose (show symbol address, etc)"),
314 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 298 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
@@ -341,6 +325,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
341 "Show event group information together"), 325 "Show event group information together"),
342 OPT_END() 326 OPT_END()
343 }; 327 };
328 int ret;
344 329
345 argc = parse_options(argc, argv, options, annotate_usage, 0); 330 argc = parse_options(argc, argv, options, annotate_usage, 0);
346 331
@@ -353,11 +338,16 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
353 338
354 setup_browser(true); 339 setup_browser(true);
355 340
341 annotate.session = perf_session__new(&file, false, &annotate.tool);
342 if (annotate.session == NULL)
343 return -1;
344
356 symbol_conf.priv_size = sizeof(struct annotation); 345 symbol_conf.priv_size = sizeof(struct annotation);
357 symbol_conf.try_vmlinux_path = true; 346 symbol_conf.try_vmlinux_path = true;
358 347
359 if (symbol__init() < 0) 348 ret = symbol__init(&annotate.session->header.env);
360 return -1; 349 if (ret < 0)
350 goto out_delete;
361 351
362 if (setup_sorting() < 0) 352 if (setup_sorting() < 0)
363 usage_with_options(annotate_usage, options); 353 usage_with_options(annotate_usage, options);
@@ -373,5 +363,20 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
373 annotate.sym_hist_filter = argv[0]; 363 annotate.sym_hist_filter = argv[0];
374 } 364 }
375 365
376 return __cmd_annotate(&annotate); 366 ret = __cmd_annotate(&annotate);
367
368out_delete:
369 /*
370 * Speed up the exit process, for large files this can
371 * take quite a while.
372 *
373 * XXX Enable this when using valgrind or if we ever
374 * librarize this command.
375 *
376 * Also experiment with obstacks to see how much speed
377 * up we'll get here.
378 *
379 * perf_session__delete(session);
380 */
381 return ret;
377} 382}
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 2a2c78f80876..70385756da63 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -246,20 +246,9 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
246 return true; 246 return true;
247} 247}
248 248
249static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) 249static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp)
250{ 250{
251 struct perf_data_file file = {
252 .path = filename,
253 .mode = PERF_DATA_MODE_READ,
254 .force = force,
255 };
256 struct perf_session *session = perf_session__new(&file, false, NULL);
257 if (session == NULL)
258 return -1;
259
260 perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0); 251 perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
261 perf_session__delete(session);
262
263 return 0; 252 return 0;
264} 253}
265 254
@@ -302,6 +291,12 @@ int cmd_buildid_cache(int argc, const char **argv,
302 *missing_filename = NULL, 291 *missing_filename = NULL,
303 *update_name_list_str = NULL, 292 *update_name_list_str = NULL,
304 *kcore_filename; 293 *kcore_filename;
294 char sbuf[STRERR_BUFSIZE];
295
296 struct perf_data_file file = {
297 .mode = PERF_DATA_MODE_READ,
298 };
299 struct perf_session *session = NULL;
305 300
306 const struct option buildid_cache_options[] = { 301 const struct option buildid_cache_options[] = {
307 OPT_STRING('a', "add", &add_name_list_str, 302 OPT_STRING('a', "add", &add_name_list_str,
@@ -326,8 +321,17 @@ int cmd_buildid_cache(int argc, const char **argv,
326 argc = parse_options(argc, argv, buildid_cache_options, 321 argc = parse_options(argc, argv, buildid_cache_options,
327 buildid_cache_usage, 0); 322 buildid_cache_usage, 0);
328 323
329 if (symbol__init() < 0) 324 if (missing_filename) {
330 return -1; 325 file.path = missing_filename;
326 file.force = force;
327
328 session = perf_session__new(&file, false, NULL);
329 if (session == NULL)
330 return -1;
331 }
332
333 if (symbol__init(session ? &session->header.env : NULL) < 0)
334 goto out;
331 335
332 setup_pager(); 336 setup_pager();
333 337
@@ -344,7 +348,7 @@ int cmd_buildid_cache(int argc, const char **argv,
344 continue; 348 continue;
345 } 349 }
346 pr_warning("Couldn't add %s: %s\n", 350 pr_warning("Couldn't add %s: %s\n",
347 pos->s, strerror(errno)); 351 pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
348 } 352 }
349 353
350 strlist__delete(list); 354 strlist__delete(list);
@@ -362,7 +366,7 @@ int cmd_buildid_cache(int argc, const char **argv,
362 continue; 366 continue;
363 } 367 }
364 pr_warning("Couldn't remove %s: %s\n", 368 pr_warning("Couldn't remove %s: %s\n",
365 pos->s, strerror(errno)); 369 pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
366 } 370 }
367 371
368 strlist__delete(list); 372 strlist__delete(list);
@@ -370,7 +374,7 @@ int cmd_buildid_cache(int argc, const char **argv,
370 } 374 }
371 375
372 if (missing_filename) 376 if (missing_filename)
373 ret = build_id_cache__fprintf_missing(missing_filename, force, stdout); 377 ret = build_id_cache__fprintf_missing(session, stdout);
374 378
375 if (update_name_list_str) { 379 if (update_name_list_str) {
376 list = strlist__new(true, update_name_list_str); 380 list = strlist__new(true, update_name_list_str);
@@ -383,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv,
383 continue; 387 continue;
384 } 388 }
385 pr_warning("Couldn't update %s: %s\n", 389 pr_warning("Couldn't update %s: %s\n",
386 pos->s, strerror(errno)); 390 pos->s, strerror_r(errno, sbuf, sizeof(sbuf)));
387 } 391 }
388 392
389 strlist__delete(list); 393 strlist__delete(list);
@@ -394,5 +398,9 @@ int cmd_buildid_cache(int argc, const char **argv,
394 build_id_cache__add_kcore(kcore_filename, debugdir, force)) 398 build_id_cache__add_kcore(kcore_filename, debugdir, force))
395 pr_warning("Couldn't add %s\n", kcore_filename); 399 pr_warning("Couldn't add %s\n", kcore_filename);
396 400
401out:
402 if (session)
403 perf_session__delete(session);
404
397 return ret; 405 return ret;
398} 406}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 9a5a035cb426..a3ce19f7aebd 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -360,7 +360,7 @@ static struct perf_tool tool = {
360 .exit = perf_event__process_exit, 360 .exit = perf_event__process_exit,
361 .fork = perf_event__process_fork, 361 .fork = perf_event__process_fork,
362 .lost = perf_event__process_lost, 362 .lost = perf_event__process_lost,
363 .ordered_samples = true, 363 .ordered_events = true,
364 .ordering_requires_timestamps = true, 364 .ordering_requires_timestamps = true,
365}; 365};
366 366
@@ -683,7 +683,7 @@ static int __cmd_diff(void)
683 d->session = perf_session__new(&d->file, false, &tool); 683 d->session = perf_session__new(&d->file, false, &tool);
684 if (!d->session) { 684 if (!d->session) {
685 pr_err("Failed to open %s\n", d->file.path); 685 pr_err("Failed to open %s\n", d->file.path);
686 ret = -ENOMEM; 686 ret = -1;
687 goto out_delete; 687 goto out_delete;
688 } 688 }
689 689
@@ -1143,7 +1143,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1143 1143
1144 argc = parse_options(argc, argv, options, diff_usage, 0); 1144 argc = parse_options(argc, argv, options, diff_usage, 0);
1145 1145
1146 if (symbol__init() < 0) 1146 if (symbol__init(NULL) < 0)
1147 return -1; 1147 return -1;
1148 1148
1149 if (data_init(argc, argv) < 0) 1149 if (data_init(argc, argv) < 0)
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 66e12f55c052..0f93f859b782 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -28,7 +28,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
28 28
29 session = perf_session__new(&file, 0, NULL); 29 session = perf_session__new(&file, 0, NULL);
30 if (session == NULL) 30 if (session == NULL)
31 return -ENOMEM; 31 return -1;
32 32
33 evlist__for_each(session->evlist, pos) 33 evlist__for_each(session->evlist, pos)
34 perf_evsel__fprintf(pos, details, stdout); 34 perf_evsel__fprintf(pos, details, stdout);
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 0384d930480b..25d20628212e 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -103,6 +103,8 @@ static int check_emacsclient_version(void)
103 103
104static void exec_woman_emacs(const char *path, const char *page) 104static void exec_woman_emacs(const char *path, const char *page)
105{ 105{
106 char sbuf[STRERR_BUFSIZE];
107
106 if (!check_emacsclient_version()) { 108 if (!check_emacsclient_version()) {
107 /* This works only with emacsclient version >= 22. */ 109 /* This works only with emacsclient version >= 22. */
108 struct strbuf man_page = STRBUF_INIT; 110 struct strbuf man_page = STRBUF_INIT;
@@ -111,16 +113,19 @@ static void exec_woman_emacs(const char *path, const char *page)
111 path = "emacsclient"; 113 path = "emacsclient";
112 strbuf_addf(&man_page, "(woman \"%s\")", page); 114 strbuf_addf(&man_page, "(woman \"%s\")", page);
113 execlp(path, "emacsclient", "-e", man_page.buf, NULL); 115 execlp(path, "emacsclient", "-e", man_page.buf, NULL);
114 warning("failed to exec '%s': %s", path, strerror(errno)); 116 warning("failed to exec '%s': %s", path,
117 strerror_r(errno, sbuf, sizeof(sbuf)));
115 } 118 }
116} 119}
117 120
118static void exec_man_konqueror(const char *path, const char *page) 121static void exec_man_konqueror(const char *path, const char *page)
119{ 122{
120 const char *display = getenv("DISPLAY"); 123 const char *display = getenv("DISPLAY");
124
121 if (display && *display) { 125 if (display && *display) {
122 struct strbuf man_page = STRBUF_INIT; 126 struct strbuf man_page = STRBUF_INIT;
123 const char *filename = "kfmclient"; 127 const char *filename = "kfmclient";
128 char sbuf[STRERR_BUFSIZE];
124 129
125 /* It's simpler to launch konqueror using kfmclient. */ 130 /* It's simpler to launch konqueror using kfmclient. */
126 if (path) { 131 if (path) {
@@ -139,24 +144,31 @@ static void exec_man_konqueror(const char *path, const char *page)
139 path = "kfmclient"; 144 path = "kfmclient";
140 strbuf_addf(&man_page, "man:%s(1)", page); 145 strbuf_addf(&man_page, "man:%s(1)", page);
141 execlp(path, filename, "newTab", man_page.buf, NULL); 146 execlp(path, filename, "newTab", man_page.buf, NULL);
142 warning("failed to exec '%s': %s", path, strerror(errno)); 147 warning("failed to exec '%s': %s", path,
148 strerror_r(errno, sbuf, sizeof(sbuf)));
143 } 149 }
144} 150}
145 151
146static void exec_man_man(const char *path, const char *page) 152static void exec_man_man(const char *path, const char *page)
147{ 153{
154 char sbuf[STRERR_BUFSIZE];
155
148 if (!path) 156 if (!path)
149 path = "man"; 157 path = "man";
150 execlp(path, "man", page, NULL); 158 execlp(path, "man", page, NULL);
151 warning("failed to exec '%s': %s", path, strerror(errno)); 159 warning("failed to exec '%s': %s", path,
160 strerror_r(errno, sbuf, sizeof(sbuf)));
152} 161}
153 162
154static void exec_man_cmd(const char *cmd, const char *page) 163static void exec_man_cmd(const char *cmd, const char *page)
155{ 164{
156 struct strbuf shell_cmd = STRBUF_INIT; 165 struct strbuf shell_cmd = STRBUF_INIT;
166 char sbuf[STRERR_BUFSIZE];
167
157 strbuf_addf(&shell_cmd, "%s %s", cmd, page); 168 strbuf_addf(&shell_cmd, "%s %s", cmd, page);
158 execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); 169 execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
159 warning("failed to exec '%s': %s", cmd, strerror(errno)); 170 warning("failed to exec '%s': %s", cmd,
171 strerror_r(errno, sbuf, sizeof(sbuf)));
160} 172}
161 173
162static void add_man_viewer(const char *name) 174static void add_man_viewer(const char *name)
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 9a02807387d6..de99ca1bb942 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -23,6 +23,7 @@
23 23
24struct perf_inject { 24struct perf_inject {
25 struct perf_tool tool; 25 struct perf_tool tool;
26 struct perf_session *session;
26 bool build_ids; 27 bool build_ids;
27 bool sched_stat; 28 bool sched_stat;
28 const char *input_name; 29 const char *input_name;
@@ -340,12 +341,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
340 341
341static int __cmd_inject(struct perf_inject *inject) 342static int __cmd_inject(struct perf_inject *inject)
342{ 343{
343 struct perf_session *session;
344 int ret = -EINVAL; 344 int ret = -EINVAL;
345 struct perf_data_file file = { 345 struct perf_session *session = inject->session;
346 .path = inject->input_name,
347 .mode = PERF_DATA_MODE_READ,
348 };
349 struct perf_data_file *file_out = &inject->output; 346 struct perf_data_file *file_out = &inject->output;
350 347
351 signal(SIGINT, sig_handler); 348 signal(SIGINT, sig_handler);
@@ -357,16 +354,12 @@ static int __cmd_inject(struct perf_inject *inject)
357 inject->tool.tracing_data = perf_event__repipe_tracing_data; 354 inject->tool.tracing_data = perf_event__repipe_tracing_data;
358 } 355 }
359 356
360 session = perf_session__new(&file, true, &inject->tool);
361 if (session == NULL)
362 return -ENOMEM;
363
364 if (inject->build_ids) { 357 if (inject->build_ids) {
365 inject->tool.sample = perf_event__inject_buildid; 358 inject->tool.sample = perf_event__inject_buildid;
366 } else if (inject->sched_stat) { 359 } else if (inject->sched_stat) {
367 struct perf_evsel *evsel; 360 struct perf_evsel *evsel;
368 361
369 inject->tool.ordered_samples = true; 362 inject->tool.ordered_events = true;
370 363
371 evlist__for_each(session->evlist, evsel) { 364 evlist__for_each(session->evlist, evsel) {
372 const char *name = perf_evsel__name(evsel); 365 const char *name = perf_evsel__name(evsel);
@@ -396,8 +389,6 @@ static int __cmd_inject(struct perf_inject *inject)
396 perf_session__write_header(session, session->evlist, file_out->fd, true); 389 perf_session__write_header(session, session->evlist, file_out->fd, true);
397 } 390 }
398 391
399 perf_session__delete(session);
400
401 return ret; 392 return ret;
402} 393}
403 394
@@ -427,6 +418,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
427 .mode = PERF_DATA_MODE_WRITE, 418 .mode = PERF_DATA_MODE_WRITE,
428 }, 419 },
429 }; 420 };
421 struct perf_data_file file = {
422 .mode = PERF_DATA_MODE_READ,
423 };
424 int ret;
425
430 const struct option options[] = { 426 const struct option options[] = {
431 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 427 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
432 "Inject build-ids into the output stream"), 428 "Inject build-ids into the output stream"),
@@ -461,8 +457,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
461 return -1; 457 return -1;
462 } 458 }
463 459
464 if (symbol__init() < 0) 460 file.path = inject.input_name;
461 inject.session = perf_session__new(&file, true, &inject.tool);
462 if (inject.session == NULL)
463 return -1;
464
465 if (symbol__init(&inject.session->header.env) < 0)
465 return -1; 466 return -1;
466 467
467 return __cmd_inject(&inject); 468 ret = __cmd_inject(&inject);
469
470 perf_session__delete(inject.session);
471
472 return ret;
468} 473}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index bef3376bfaf3..f295141025bc 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -256,7 +256,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
256static struct perf_tool perf_kmem = { 256static struct perf_tool perf_kmem = {
257 .sample = process_sample_event, 257 .sample = process_sample_event,
258 .comm = perf_event__process_comm, 258 .comm = perf_event__process_comm,
259 .ordered_samples = true, 259 .mmap = perf_event__process_mmap,
260 .mmap2 = perf_event__process_mmap2,
261 .ordered_events = true,
260}; 262};
261 263
262static double fragmentation(unsigned long n_req, unsigned long n_alloc) 264static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -403,10 +405,9 @@ static void sort_result(void)
403 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); 405 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
404} 406}
405 407
406static int __cmd_kmem(void) 408static int __cmd_kmem(struct perf_session *session)
407{ 409{
408 int err = -EINVAL; 410 int err = -EINVAL;
409 struct perf_session *session;
410 const struct perf_evsel_str_handler kmem_tracepoints[] = { 411 const struct perf_evsel_str_handler kmem_tracepoints[] = {
411 { "kmem:kmalloc", perf_evsel__process_alloc_event, }, 412 { "kmem:kmalloc", perf_evsel__process_alloc_event, },
412 { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, }, 413 { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, },
@@ -415,34 +416,22 @@ static int __cmd_kmem(void)
415 { "kmem:kfree", perf_evsel__process_free_event, }, 416 { "kmem:kfree", perf_evsel__process_free_event, },
416 { "kmem:kmem_cache_free", perf_evsel__process_free_event, }, 417 { "kmem:kmem_cache_free", perf_evsel__process_free_event, },
417 }; 418 };
418 struct perf_data_file file = {
419 .path = input_name,
420 .mode = PERF_DATA_MODE_READ,
421 };
422
423 session = perf_session__new(&file, false, &perf_kmem);
424 if (session == NULL)
425 return -ENOMEM;
426
427 if (perf_session__create_kernel_maps(session) < 0)
428 goto out_delete;
429 419
430 if (!perf_session__has_traces(session, "kmem record")) 420 if (!perf_session__has_traces(session, "kmem record"))
431 goto out_delete; 421 goto out;
432 422
433 if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) { 423 if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
434 pr_err("Initializing perf session tracepoint handlers failed\n"); 424 pr_err("Initializing perf session tracepoint handlers failed\n");
435 return -1; 425 goto out;
436 } 426 }
437 427
438 setup_pager(); 428 setup_pager();
439 err = perf_session__process_events(session, &perf_kmem); 429 err = perf_session__process_events(session, &perf_kmem);
440 if (err != 0) 430 if (err != 0)
441 goto out_delete; 431 goto out;
442 sort_result(); 432 sort_result();
443 print_result(session); 433 print_result(session);
444out_delete: 434out:
445 perf_session__delete(session);
446 return err; 435 return err;
447} 436}
448 437
@@ -689,29 +678,46 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
689 NULL, 678 NULL,
690 NULL 679 NULL
691 }; 680 };
681 struct perf_session *session;
682 struct perf_data_file file = {
683 .path = input_name,
684 .mode = PERF_DATA_MODE_READ,
685 };
686 int ret = -1;
687
692 argc = parse_options_subcommand(argc, argv, kmem_options, 688 argc = parse_options_subcommand(argc, argv, kmem_options,
693 kmem_subcommands, kmem_usage, 0); 689 kmem_subcommands, kmem_usage, 0);
694 690
695 if (!argc) 691 if (!argc)
696 usage_with_options(kmem_usage, kmem_options); 692 usage_with_options(kmem_usage, kmem_options);
697 693
698 symbol__init();
699
700 if (!strncmp(argv[0], "rec", 3)) { 694 if (!strncmp(argv[0], "rec", 3)) {
695 symbol__init(NULL);
701 return __cmd_record(argc, argv); 696 return __cmd_record(argc, argv);
702 } else if (!strcmp(argv[0], "stat")) { 697 }
698
699 session = perf_session__new(&file, false, &perf_kmem);
700 if (session == NULL)
701 return -1;
702
703 symbol__init(&session->header.env);
704
705 if (!strcmp(argv[0], "stat")) {
703 if (cpu__setup_cpunode_map()) 706 if (cpu__setup_cpunode_map())
704 return -1; 707 goto out_delete;
705 708
706 if (list_empty(&caller_sort)) 709 if (list_empty(&caller_sort))
707 setup_sorting(&caller_sort, default_sort_order); 710 setup_sorting(&caller_sort, default_sort_order);
708 if (list_empty(&alloc_sort)) 711 if (list_empty(&alloc_sort))
709 setup_sorting(&alloc_sort, default_sort_order); 712 setup_sorting(&alloc_sort, default_sort_order);
710 713
711 return __cmd_kmem(); 714 ret = __cmd_kmem(session);
712 } else 715 } else
713 usage_with_options(kmem_usage, kmem_options); 716 usage_with_options(kmem_usage, kmem_options);
714 717
715 return 0; 718out_delete:
719 perf_session__delete(session);
720
721 return ret;
716} 722}
717 723
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 43367eb00510..d8bf2271f4ea 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -543,14 +543,12 @@ static void print_vcpu_info(struct perf_kvm_stat *kvm)
543 543
544 pr_info("Analyze events for "); 544 pr_info("Analyze events for ");
545 545
546 if (kvm->live) { 546 if (kvm->opts.target.system_wide)
547 if (kvm->opts.target.system_wide) 547 pr_info("all VMs, ");
548 pr_info("all VMs, "); 548 else if (kvm->opts.target.pid)
549 else if (kvm->opts.target.pid) 549 pr_info("pid(s) %s, ", kvm->opts.target.pid);
550 pr_info("pid(s) %s, ", kvm->opts.target.pid); 550 else
551 else 551 pr_info("dazed and confused on what is monitored, ");
552 pr_info("dazed and confused on what is monitored, ");
553 }
554 552
555 if (vcpu == -1) 553 if (vcpu == -1)
556 pr_info("all VCPUs:\n\n"); 554 pr_info("all VCPUs:\n\n");
@@ -592,8 +590,8 @@ static void print_result(struct perf_kvm_stat *kvm)
592 pr_info("%9s ", "Samples%"); 590 pr_info("%9s ", "Samples%");
593 591
594 pr_info("%9s ", "Time%"); 592 pr_info("%9s ", "Time%");
595 pr_info("%10s ", "Min Time"); 593 pr_info("%11s ", "Min Time");
596 pr_info("%10s ", "Max Time"); 594 pr_info("%11s ", "Max Time");
597 pr_info("%16s ", "Avg time"); 595 pr_info("%16s ", "Avg time");
598 pr_info("\n\n"); 596 pr_info("\n\n");
599 597
@@ -610,8 +608,8 @@ static void print_result(struct perf_kvm_stat *kvm)
610 pr_info("%10llu ", (unsigned long long)ecount); 608 pr_info("%10llu ", (unsigned long long)ecount);
611 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 609 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
612 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); 610 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
613 pr_info("%8" PRIu64 "us ", min / 1000); 611 pr_info("%9.2fus ", (double)min / 1e3);
614 pr_info("%8" PRIu64 "us ", max / 1000); 612 pr_info("%9.2fus ", (double)max / 1e3);
615 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, 613 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
616 kvm_event_rel_stddev(vcpu, event)); 614 kvm_event_rel_stddev(vcpu, event));
617 pr_info("\n"); 615 pr_info("\n");
@@ -732,7 +730,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
732 return -1; 730 return -1;
733 } 731 }
734 732
735 err = perf_session_queue_event(kvm->session, event, &sample, 0); 733 err = perf_session_queue_event(kvm->session, event, &kvm->tool, &sample, 0);
736 /* 734 /*
737 * FIXME: Here we can't consume the event, as perf_session_queue_event will 735 * FIXME: Here we can't consume the event, as perf_session_queue_event will
738 * point to it, and it'll get possibly overwritten by the kernel. 736 * point to it, and it'll get possibly overwritten by the kernel.
@@ -785,7 +783,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
785 783
786 /* flush queue after each round in which we processed events */ 784 /* flush queue after each round in which we processed events */
787 if (ntotal) { 785 if (ntotal) {
788 kvm->session->ordered_samples.next_flush = flush_time; 786 kvm->session->ordered_events.next_flush = flush_time;
789 err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session); 787 err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
790 if (err) { 788 if (err) {
791 if (kvm->lost_events) 789 if (kvm->lost_events)
@@ -885,15 +883,11 @@ static int fd_set_nonblock(int fd)
885 return 0; 883 return 0;
886} 884}
887 885
888static 886static int perf_kvm__handle_stdin(void)
889int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
890{ 887{
891 int c; 888 int c;
892 889
893 tcsetattr(0, TCSANOW, tc_now);
894 c = getc(stdin); 890 c = getc(stdin);
895 tcsetattr(0, TCSAFLUSH, tc_save);
896
897 if (c == 'q') 891 if (c == 'q')
898 return 1; 892 return 1;
899 893
@@ -904,7 +898,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
904{ 898{
905 struct pollfd *pollfds = NULL; 899 struct pollfd *pollfds = NULL;
906 int nr_fds, nr_stdin, ret, err = -EINVAL; 900 int nr_fds, nr_stdin, ret, err = -EINVAL;
907 struct termios tc, save; 901 struct termios save;
908 902
909 /* live flag must be set first */ 903 /* live flag must be set first */
910 kvm->live = true; 904 kvm->live = true;
@@ -919,26 +913,14 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
919 goto out; 913 goto out;
920 } 914 }
921 915
916 set_term_quiet_input(&save);
922 init_kvm_event_record(kvm); 917 init_kvm_event_record(kvm);
923 918
924 tcgetattr(0, &save);
925 tc = save;
926 tc.c_lflag &= ~(ICANON | ECHO);
927 tc.c_cc[VMIN] = 0;
928 tc.c_cc[VTIME] = 0;
929
930 signal(SIGINT, sig_handler); 919 signal(SIGINT, sig_handler);
931 signal(SIGTERM, sig_handler); 920 signal(SIGTERM, sig_handler);
932 921
933 /* copy pollfds -- need to add timerfd and stdin */ 922 /* use pollfds -- need to add timerfd and stdin */
934 nr_fds = kvm->evlist->nr_fds; 923 nr_fds = kvm->evlist->pollfd.nr;
935 pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
936 if (!pollfds) {
937 err = -ENOMEM;
938 goto out;
939 }
940 memcpy(pollfds, kvm->evlist->pollfd,
941 sizeof(struct pollfd) * kvm->evlist->nr_fds);
942 924
943 /* add timer fd */ 925 /* add timer fd */
944 if (perf_kvm__timerfd_create(kvm) < 0) { 926 if (perf_kvm__timerfd_create(kvm) < 0) {
@@ -946,17 +928,21 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
946 goto out; 928 goto out;
947 } 929 }
948 930
949 pollfds[nr_fds].fd = kvm->timerfd; 931 if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd))
950 pollfds[nr_fds].events = POLLIN; 932 goto out;
933
951 nr_fds++; 934 nr_fds++;
952 935
953 pollfds[nr_fds].fd = fileno(stdin); 936 if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)))
954 pollfds[nr_fds].events = POLLIN; 937 goto out;
938
955 nr_stdin = nr_fds; 939 nr_stdin = nr_fds;
956 nr_fds++; 940 nr_fds++;
957 if (fd_set_nonblock(fileno(stdin)) != 0) 941 if (fd_set_nonblock(fileno(stdin)) != 0)
958 goto out; 942 goto out;
959 943
944 pollfds = kvm->evlist->pollfd.entries;
945
960 /* everything is good - enable the events and process */ 946 /* everything is good - enable the events and process */
961 perf_evlist__enable(kvm->evlist); 947 perf_evlist__enable(kvm->evlist);
962 948
@@ -972,7 +958,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
972 goto out; 958 goto out;
973 959
974 if (pollfds[nr_stdin].revents & POLLIN) 960 if (pollfds[nr_stdin].revents & POLLIN)
975 done = perf_kvm__handle_stdin(&tc, &save); 961 done = perf_kvm__handle_stdin();
976 962
977 if (!rc && !done) 963 if (!rc && !done)
978 err = poll(pollfds, nr_fds, 100); 964 err = poll(pollfds, nr_fds, 100);
@@ -989,7 +975,7 @@ out:
989 if (kvm->timerfd >= 0) 975 if (kvm->timerfd >= 0)
990 close(kvm->timerfd); 976 close(kvm->timerfd);
991 977
992 free(pollfds); 978 tcsetattr(0, TCSAFLUSH, &save);
993 return err; 979 return err;
994} 980}
995 981
@@ -998,6 +984,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
998 int err, rc = -1; 984 int err, rc = -1;
999 struct perf_evsel *pos; 985 struct perf_evsel *pos;
1000 struct perf_evlist *evlist = kvm->evlist; 986 struct perf_evlist *evlist = kvm->evlist;
987 char sbuf[STRERR_BUFSIZE];
1001 988
1002 perf_evlist__config(evlist, &kvm->opts); 989 perf_evlist__config(evlist, &kvm->opts);
1003 990
@@ -1034,12 +1021,14 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
1034 1021
1035 err = perf_evlist__open(evlist); 1022 err = perf_evlist__open(evlist);
1036 if (err < 0) { 1023 if (err < 0) {
1037 printf("Couldn't create the events: %s\n", strerror(errno)); 1024 printf("Couldn't create the events: %s\n",
1025 strerror_r(errno, sbuf, sizeof(sbuf)));
1038 goto out; 1026 goto out;
1039 } 1027 }
1040 1028
1041 if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) { 1029 if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
1042 ui__error("Failed to mmap the events: %s\n", strerror(errno)); 1030 ui__error("Failed to mmap the events: %s\n",
1031 strerror_r(errno, sbuf, sizeof(sbuf)));
1043 perf_evlist__close(evlist); 1032 perf_evlist__close(evlist);
1044 goto out; 1033 goto out;
1045 } 1034 }
@@ -1058,7 +1047,7 @@ static int read_events(struct perf_kvm_stat *kvm)
1058 struct perf_tool eops = { 1047 struct perf_tool eops = {
1059 .sample = process_sample_event, 1048 .sample = process_sample_event,
1060 .comm = perf_event__process_comm, 1049 .comm = perf_event__process_comm,
1061 .ordered_samples = true, 1050 .ordered_events = true,
1062 }; 1051 };
1063 struct perf_data_file file = { 1052 struct perf_data_file file = {
1064 .path = kvm->file_name, 1053 .path = kvm->file_name,
@@ -1069,9 +1058,11 @@ static int read_events(struct perf_kvm_stat *kvm)
1069 kvm->session = perf_session__new(&file, false, &kvm->tool); 1058 kvm->session = perf_session__new(&file, false, &kvm->tool);
1070 if (!kvm->session) { 1059 if (!kvm->session) {
1071 pr_err("Initializing perf session failed\n"); 1060 pr_err("Initializing perf session failed\n");
1072 return -EINVAL; 1061 return -1;
1073 } 1062 }
1074 1063
1064 symbol__init(&kvm->session->header.env);
1065
1075 if (!perf_session__has_traces(kvm->session, "kvm record")) 1066 if (!perf_session__has_traces(kvm->session, "kvm record"))
1076 return -EINVAL; 1067 return -EINVAL;
1077 1068
@@ -1088,8 +1079,8 @@ static int read_events(struct perf_kvm_stat *kvm)
1088 1079
1089static int parse_target_str(struct perf_kvm_stat *kvm) 1080static int parse_target_str(struct perf_kvm_stat *kvm)
1090{ 1081{
1091 if (kvm->pid_str) { 1082 if (kvm->opts.target.pid) {
1092 kvm->pid_list = intlist__new(kvm->pid_str); 1083 kvm->pid_list = intlist__new(kvm->opts.target.pid);
1093 if (kvm->pid_list == NULL) { 1084 if (kvm->pid_list == NULL) {
1094 pr_err("Error parsing process id string\n"); 1085 pr_err("Error parsing process id string\n");
1095 return -EINVAL; 1086 return -EINVAL;
@@ -1191,7 +1182,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
1191 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", 1182 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
1192 "key for sorting: sample(sort by samples number)" 1183 "key for sorting: sample(sort by samples number)"
1193 " time (sort by avg time)"), 1184 " time (sort by avg time)"),
1194 OPT_STRING('p', "pid", &kvm->pid_str, "pid", 1185 OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
1195 "analyze events only for given process id(s)"), 1186 "analyze events only for given process id(s)"),
1196 OPT_END() 1187 OPT_END()
1197 }; 1188 };
@@ -1201,8 +1192,6 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
1201 NULL 1192 NULL
1202 }; 1193 };
1203 1194
1204 symbol__init();
1205
1206 if (argc) { 1195 if (argc) {
1207 argc = parse_options(argc, argv, 1196 argc = parse_options(argc, argv,
1208 kvm_events_report_options, 1197 kvm_events_report_options,
@@ -1212,6 +1201,9 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
1212 kvm_events_report_options); 1201 kvm_events_report_options);
1213 } 1202 }
1214 1203
1204 if (!kvm->opts.target.pid)
1205 kvm->opts.target.system_wide = true;
1206
1215 return kvm_events_report_vcpu(kvm); 1207 return kvm_events_report_vcpu(kvm);
1216} 1208}
1217 1209
@@ -1311,7 +1303,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1311 kvm->tool.exit = perf_event__process_exit; 1303 kvm->tool.exit = perf_event__process_exit;
1312 kvm->tool.fork = perf_event__process_fork; 1304 kvm->tool.fork = perf_event__process_fork;
1313 kvm->tool.lost = process_lost_event; 1305 kvm->tool.lost = process_lost_event;
1314 kvm->tool.ordered_samples = true; 1306 kvm->tool.ordered_events = true;
1315 perf_tool__fill_defaults(&kvm->tool); 1307 perf_tool__fill_defaults(&kvm->tool);
1316 1308
1317 /* set defaults */ 1309 /* set defaults */
@@ -1322,7 +1314,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1322 kvm->opts.target.uid_str = NULL; 1314 kvm->opts.target.uid_str = NULL;
1323 kvm->opts.target.uid = UINT_MAX; 1315 kvm->opts.target.uid = UINT_MAX;
1324 1316
1325 symbol__init(); 1317 symbol__init(NULL);
1326 disable_buildid_cache(); 1318 disable_buildid_cache();
1327 1319
1328 use_browser = 0; 1320 use_browser = 0;
@@ -1369,7 +1361,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1369 */ 1361 */
1370 kvm->session = perf_session__new(&file, false, &kvm->tool); 1362 kvm->session = perf_session__new(&file, false, &kvm->tool);
1371 if (kvm->session == NULL) { 1363 if (kvm->session == NULL) {
1372 err = -ENOMEM; 1364 err = -1;
1373 goto out; 1365 goto out;
1374 } 1366 }
1375 kvm->session->evlist = kvm->evlist; 1367 kvm->session->evlist = kvm->evlist;
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 6148afc995c6..e7ec71589da6 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -852,7 +852,7 @@ static int __cmd_report(bool display_info)
852 struct perf_tool eops = { 852 struct perf_tool eops = {
853 .sample = process_sample_event, 853 .sample = process_sample_event,
854 .comm = perf_event__process_comm, 854 .comm = perf_event__process_comm,
855 .ordered_samples = true, 855 .ordered_events = true,
856 }; 856 };
857 struct perf_data_file file = { 857 struct perf_data_file file = {
858 .path = input_name, 858 .path = input_name,
@@ -862,9 +862,11 @@ static int __cmd_report(bool display_info)
862 session = perf_session__new(&file, false, &eops); 862 session = perf_session__new(&file, false, &eops);
863 if (!session) { 863 if (!session) {
864 pr_err("Initializing perf session failed\n"); 864 pr_err("Initializing perf session failed\n");
865 return -ENOMEM; 865 return -1;
866 } 866 }
867 867
868 symbol__init(&session->header.env);
869
868 if (!perf_session__has_traces(session, "lock record")) 870 if (!perf_session__has_traces(session, "lock record"))
869 goto out_delete; 871 goto out_delete;
870 872
@@ -974,7 +976,6 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
974 unsigned int i; 976 unsigned int i;
975 int rc = 0; 977 int rc = 0;
976 978
977 symbol__init();
978 for (i = 0; i < LOCKHASH_SIZE; i++) 979 for (i = 0; i < LOCKHASH_SIZE; i++)
979 INIT_LIST_HEAD(lockhash_table + i); 980 INIT_LIST_HEAD(lockhash_table + i);
980 981
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 4a1a6c94a5eb..24db6ffe2957 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -124,7 +124,7 @@ static int report_raw_events(struct perf_mem *mem)
124 &mem->tool); 124 &mem->tool);
125 125
126 if (session == NULL) 126 if (session == NULL)
127 return -ENOMEM; 127 return -1;
128 128
129 if (mem->cpu_list) { 129 if (mem->cpu_list) {
130 ret = perf_session__cpu_bitmap(session, mem->cpu_list, 130 ret = perf_session__cpu_bitmap(session, mem->cpu_list,
@@ -133,7 +133,7 @@ static int report_raw_events(struct perf_mem *mem)
133 goto out_delete; 133 goto out_delete;
134 } 134 }
135 135
136 if (symbol__init() < 0) 136 if (symbol__init(&session->header.env) < 0)
137 return -1; 137 return -1;
138 138
139 printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); 139 printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
@@ -194,7 +194,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
194 .lost = perf_event__process_lost, 194 .lost = perf_event__process_lost,
195 .fork = perf_event__process_fork, 195 .fork = perf_event__process_fork,
196 .build_id = perf_event__process_build_id, 196 .build_id = perf_event__process_build_id,
197 .ordered_samples = true, 197 .ordered_events = true,
198 }, 198 },
199 .input_name = "perf.data", 199 .input_name = "perf.data",
200 }; 200 };
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c63fa2925075..04412b4770a2 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -290,8 +290,11 @@ static void cleanup_params(void)
290 290
291static void pr_err_with_code(const char *msg, int err) 291static void pr_err_with_code(const char *msg, int err)
292{ 292{
293 char sbuf[STRERR_BUFSIZE];
294
293 pr_err("%s", msg); 295 pr_err("%s", msg);
294 pr_debug(" Reason: %s (Code: %d)", strerror(-err), err); 296 pr_debug(" Reason: %s (Code: %d)",
297 strerror_r(-err, sbuf, sizeof(sbuf)), err);
295 pr_err("\n"); 298 pr_err("\n");
296} 299}
297 300
@@ -373,6 +376,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
373 "target executable name or path", opt_set_target), 376 "target executable name or path", opt_set_target),
374 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, 377 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
375 "Disable symbol demangling"), 378 "Disable symbol demangling"),
379 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
380 "Enable kernel symbol demangling"),
376 OPT_END() 381 OPT_END()
377 }; 382 };
378 int ret; 383 int ret;
@@ -467,7 +472,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
467 usage_with_options(probe_usage, options); 472 usage_with_options(probe_usage, options);
468 } 473 }
469 474
470 ret = show_line_range(&params.line_range, params.target); 475 ret = show_line_range(&params.line_range, params.target,
476 params.uprobes);
471 if (ret < 0) 477 if (ret < 0)
472 pr_err_with_code(" Error: Failed to show lines.", ret); 478 pr_err_with_code(" Error: Failed to show lines.", ret);
473 return ret; 479 return ret;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4869050e7194..44c6f3d55ce7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -65,8 +65,9 @@ static int process_synthesized_event(struct perf_tool *tool,
65 return record__write(rec, event, event->header.size); 65 return record__write(rec, event, event->header.size);
66} 66}
67 67
68static int record__mmap_read(struct record *rec, struct perf_mmap *md) 68static int record__mmap_read(struct record *rec, int idx)
69{ 69{
70 struct perf_mmap *md = &rec->evlist->mmap[idx];
70 unsigned int head = perf_mmap__read_head(md); 71 unsigned int head = perf_mmap__read_head(md);
71 unsigned int old = md->prev; 72 unsigned int old = md->prev;
72 unsigned char *data = md->base + page_size; 73 unsigned char *data = md->base + page_size;
@@ -102,8 +103,7 @@ static int record__mmap_read(struct record *rec, struct perf_mmap *md)
102 } 103 }
103 104
104 md->prev = old; 105 md->prev = old;
105 perf_mmap__write_tail(md, old); 106 perf_evlist__mmap_consume(rec->evlist, idx);
106
107out: 107out:
108 return rc; 108 return rc;
109} 109}
@@ -161,7 +161,7 @@ try_again:
161 161
162 if (perf_evlist__apply_filters(evlist)) { 162 if (perf_evlist__apply_filters(evlist)) {
163 error("failed to set filter with %d (%s)\n", errno, 163 error("failed to set filter with %d (%s)\n", errno,
164 strerror(errno)); 164 strerror_r(errno, msg, sizeof(msg)));
165 rc = -1; 165 rc = -1;
166 goto out; 166 goto out;
167 } 167 }
@@ -175,7 +175,8 @@ try_again:
175 "(current value: %u)\n", opts->mmap_pages); 175 "(current value: %u)\n", opts->mmap_pages);
176 rc = -errno; 176 rc = -errno;
177 } else { 177 } else {
178 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 178 pr_err("failed to mmap with %d (%s)\n", errno,
179 strerror_r(errno, msg, sizeof(msg)));
179 rc = -errno; 180 rc = -errno;
180 } 181 }
181 goto out; 182 goto out;
@@ -244,7 +245,7 @@ static int record__mmap_read_all(struct record *rec)
244 245
245 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 246 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
246 if (rec->evlist->mmap[i].base) { 247 if (rec->evlist->mmap[i].base) {
247 if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 248 if (record__mmap_read(rec, i) != 0) {
248 rc = -1; 249 rc = -1;
249 goto out; 250 goto out;
250 } 251 }
@@ -307,7 +308,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
307 struct record_opts *opts = &rec->opts; 308 struct record_opts *opts = &rec->opts;
308 struct perf_data_file *file = &rec->file; 309 struct perf_data_file *file = &rec->file;
309 struct perf_session *session; 310 struct perf_session *session;
310 bool disabled = false; 311 bool disabled = false, draining = false;
311 312
312 rec->progname = argv[0]; 313 rec->progname = argv[0];
313 314
@@ -456,9 +457,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
456 } 457 }
457 458
458 if (hits == rec->samples) { 459 if (hits == rec->samples) {
459 if (done) 460 if (done || draining)
460 break; 461 break;
461 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 462 err = perf_evlist__poll(rec->evlist, -1);
462 /* 463 /*
463 * Propagate error, only if there's any. Ignore positive 464 * Propagate error, only if there's any. Ignore positive
464 * number of returned events and interrupt error. 465 * number of returned events and interrupt error.
@@ -466,6 +467,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
466 if (err > 0 || (err < 0 && errno == EINTR)) 467 if (err > 0 || (err < 0 && errno == EINTR))
467 err = 0; 468 err = 0;
468 waking++; 469 waking++;
470
471 if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0)
472 draining = true;
469 } 473 }
470 474
471 /* 475 /*
@@ -480,7 +484,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
480 } 484 }
481 485
482 if (forks && workload_exec_errno) { 486 if (forks && workload_exec_errno) {
483 char msg[512]; 487 char msg[STRERR_BUFSIZE];
484 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 488 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
485 pr_err("Workload failed: %s\n", emsg); 489 pr_err("Workload failed: %s\n", emsg);
486 err = -1; 490 err = -1;
@@ -620,145 +624,56 @@ error:
620 return ret; 624 return ret;
621} 625}
622 626
623#ifdef HAVE_DWARF_UNWIND_SUPPORT 627static void callchain_debug(void)
624static int get_stack_size(char *str, unsigned long *_size)
625{
626 char *endptr;
627 unsigned long size;
628 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
629
630 size = strtoul(str, &endptr, 0);
631
632 do {
633 if (*endptr)
634 break;
635
636 size = round_up(size, sizeof(u64));
637 if (!size || size > max_size)
638 break;
639
640 *_size = size;
641 return 0;
642
643 } while (0);
644
645 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
646 max_size, str);
647 return -1;
648}
649#endif /* HAVE_DWARF_UNWIND_SUPPORT */
650
651int record_parse_callchain(const char *arg, struct record_opts *opts)
652{
653 char *tok, *name, *saveptr = NULL;
654 char *buf;
655 int ret = -1;
656
657 /* We need buffer that we know we can write to. */
658 buf = malloc(strlen(arg) + 1);
659 if (!buf)
660 return -ENOMEM;
661
662 strcpy(buf, arg);
663
664 tok = strtok_r((char *)buf, ",", &saveptr);
665 name = tok ? : (char *)buf;
666
667 do {
668 /* Framepointer style */
669 if (!strncmp(name, "fp", sizeof("fp"))) {
670 if (!strtok_r(NULL, ",", &saveptr)) {
671 opts->call_graph = CALLCHAIN_FP;
672 ret = 0;
673 } else
674 pr_err("callchain: No more arguments "
675 "needed for -g fp\n");
676 break;
677
678#ifdef HAVE_DWARF_UNWIND_SUPPORT
679 /* Dwarf style */
680 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
681 const unsigned long default_stack_dump_size = 8192;
682
683 ret = 0;
684 opts->call_graph = CALLCHAIN_DWARF;
685 opts->stack_dump_size = default_stack_dump_size;
686
687 tok = strtok_r(NULL, ",", &saveptr);
688 if (tok) {
689 unsigned long size = 0;
690
691 ret = get_stack_size(tok, &size);
692 opts->stack_dump_size = size;
693 }
694#endif /* HAVE_DWARF_UNWIND_SUPPORT */
695 } else {
696 pr_err("callchain: Unknown --call-graph option "
697 "value: %s\n", arg);
698 break;
699 }
700
701 } while (0);
702
703 free(buf);
704 return ret;
705}
706
707static void callchain_debug(struct record_opts *opts)
708{ 628{
709 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; 629 static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
710 630
711 pr_debug("callchain: type %s\n", str[opts->call_graph]); 631 pr_debug("callchain: type %s\n", str[callchain_param.record_mode]);
712 632
713 if (opts->call_graph == CALLCHAIN_DWARF) 633 if (callchain_param.record_mode == CALLCHAIN_DWARF)
714 pr_debug("callchain: stack dump size %d\n", 634 pr_debug("callchain: stack dump size %d\n",
715 opts->stack_dump_size); 635 callchain_param.dump_size);
716} 636}
717 637
718int record_parse_callchain_opt(const struct option *opt, 638int record_parse_callchain_opt(const struct option *opt __maybe_unused,
719 const char *arg, 639 const char *arg,
720 int unset) 640 int unset)
721{ 641{
722 struct record_opts *opts = opt->value;
723 int ret; 642 int ret;
724 643
725 opts->call_graph_enabled = !unset; 644 callchain_param.enabled = !unset;
726 645
727 /* --no-call-graph */ 646 /* --no-call-graph */
728 if (unset) { 647 if (unset) {
729 opts->call_graph = CALLCHAIN_NONE; 648 callchain_param.record_mode = CALLCHAIN_NONE;
730 pr_debug("callchain: disabled\n"); 649 pr_debug("callchain: disabled\n");
731 return 0; 650 return 0;
732 } 651 }
733 652
734 ret = record_parse_callchain(arg, opts); 653 ret = parse_callchain_record_opt(arg);
735 if (!ret) 654 if (!ret)
736 callchain_debug(opts); 655 callchain_debug();
737 656
738 return ret; 657 return ret;
739} 658}
740 659
741int record_callchain_opt(const struct option *opt, 660int record_callchain_opt(const struct option *opt __maybe_unused,
742 const char *arg __maybe_unused, 661 const char *arg __maybe_unused,
743 int unset __maybe_unused) 662 int unset __maybe_unused)
744{ 663{
745 struct record_opts *opts = opt->value; 664 callchain_param.enabled = true;
746 665
747 opts->call_graph_enabled = !unset; 666 if (callchain_param.record_mode == CALLCHAIN_NONE)
667 callchain_param.record_mode = CALLCHAIN_FP;
748 668
749 if (opts->call_graph == CALLCHAIN_NONE) 669 callchain_debug();
750 opts->call_graph = CALLCHAIN_FP;
751
752 callchain_debug(opts);
753 return 0; 670 return 0;
754} 671}
755 672
756static int perf_record_config(const char *var, const char *value, void *cb) 673static int perf_record_config(const char *var, const char *value, void *cb)
757{ 674{
758 struct record *rec = cb;
759
760 if (!strcmp(var, "record.call-graph")) 675 if (!strcmp(var, "record.call-graph"))
761 return record_parse_callchain(value, &rec->opts); 676 var = "call-graph.record-mode"; /* fall-through */
762 677
763 return perf_default_config(var, value, cb); 678 return perf_default_config(var, value, cb);
764} 679}
@@ -781,6 +696,7 @@ static const char * const record_usage[] = {
781 */ 696 */
782static struct record record = { 697static struct record record = {
783 .opts = { 698 .opts = {
699 .sample_time = true,
784 .mmap_pages = UINT_MAX, 700 .mmap_pages = UINT_MAX,
785 .user_freq = UINT_MAX, 701 .user_freq = UINT_MAX,
786 .user_interval = ULLONG_MAX, 702 .user_interval = ULLONG_MAX,
@@ -907,7 +823,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
907 usage_with_options(record_usage, record_options); 823 usage_with_options(record_usage, record_options);
908 } 824 }
909 825
910 symbol__init(); 826 symbol__init(NULL);
911 827
912 if (symbol_conf.kptr_restrict) 828 if (symbol_conf.kptr_restrict)
913 pr_warning( 829 pr_warning(
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 21d830bafff3..ac145fae0521 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -58,17 +58,19 @@ struct report {
58 const char *symbol_filter_str; 58 const char *symbol_filter_str;
59 float min_percent; 59 float min_percent;
60 u64 nr_entries; 60 u64 nr_entries;
61 u64 queue_size;
61 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 62 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
62}; 63};
63 64
64static int report__config(const char *var, const char *value, void *cb) 65static int report__config(const char *var, const char *value, void *cb)
65{ 66{
67 struct report *rep = cb;
68
66 if (!strcmp(var, "report.group")) { 69 if (!strcmp(var, "report.group")) {
67 symbol_conf.event_group = perf_config_bool(var, value); 70 symbol_conf.event_group = perf_config_bool(var, value);
68 return 0; 71 return 0;
69 } 72 }
70 if (!strcmp(var, "report.percent-limit")) { 73 if (!strcmp(var, "report.percent-limit")) {
71 struct report *rep = cb;
72 rep->min_percent = strtof(value, NULL); 74 rep->min_percent = strtof(value, NULL);
73 return 0; 75 return 0;
74 } 76 }
@@ -76,6 +78,10 @@ static int report__config(const char *var, const char *value, void *cb)
76 symbol_conf.cumulate_callchain = perf_config_bool(var, value); 78 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
77 return 0; 79 return 0;
78 } 80 }
81 if (!strcmp(var, "report.queue-size")) {
82 rep->queue_size = perf_config_u64(var, value);
83 return 0;
84 }
79 85
80 return perf_default_config(var, value, cb); 86 return perf_default_config(var, value, cb);
81} 87}
@@ -578,7 +584,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
578 .attr = perf_event__process_attr, 584 .attr = perf_event__process_attr,
579 .tracing_data = perf_event__process_tracing_data, 585 .tracing_data = perf_event__process_tracing_data,
580 .build_id = perf_event__process_build_id, 586 .build_id = perf_event__process_build_id,
581 .ordered_samples = true, 587 .ordered_events = true,
582 .ordering_requires_timestamps = true, 588 .ordering_requires_timestamps = true,
583 }, 589 },
584 .max_stack = PERF_MAX_STACK_DEPTH, 590 .max_stack = PERF_MAX_STACK_DEPTH,
@@ -674,6 +680,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
674 "objdump binary to use for disassembly and annotations"), 680 "objdump binary to use for disassembly and annotations"),
675 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, 681 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
676 "Disable symbol demangling"), 682 "Disable symbol demangling"),
683 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
684 "Enable kernel symbol demangling"),
677 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), 685 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
678 OPT_CALLBACK(0, "percent-limit", &report, "percent", 686 OPT_CALLBACK(0, "percent-limit", &report, "percent",
679 "Don't show entries under that percent", parse_percent_limit), 687 "Don't show entries under that percent", parse_percent_limit),
@@ -712,14 +720,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
712repeat: 720repeat:
713 session = perf_session__new(&file, false, &report.tool); 721 session = perf_session__new(&file, false, &report.tool);
714 if (session == NULL) 722 if (session == NULL)
715 return -ENOMEM; 723 return -1;
724
725 if (report.queue_size) {
726 ordered_events__set_alloc_size(&session->ordered_events,
727 report.queue_size);
728 }
716 729
717 report.session = session; 730 report.session = session;
718 731
719 has_br_stack = perf_header__has_feat(&session->header, 732 has_br_stack = perf_header__has_feat(&session->header,
720 HEADER_BRANCH_STACK); 733 HEADER_BRANCH_STACK);
721 734
722 if (branch_mode == -1 && has_br_stack) { 735 if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) {
723 sort__mode = SORT_MODE__BRANCH; 736 sort__mode = SORT_MODE__BRANCH;
724 symbol_conf.cumulate_callchain = false; 737 symbol_conf.cumulate_callchain = false;
725 } 738 }
@@ -787,7 +800,7 @@ repeat:
787 } 800 }
788 } 801 }
789 802
790 if (symbol__init() < 0) 803 if (symbol__init(&session->header.env) < 0)
791 goto error; 804 goto error;
792 805
793 if (argc) { 806 if (argc) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index f83c08c0dd87..9c9287fbf8e9 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -428,6 +428,7 @@ static u64 get_cpu_usage_nsec_parent(void)
428static int self_open_counters(void) 428static int self_open_counters(void)
429{ 429{
430 struct perf_event_attr attr; 430 struct perf_event_attr attr;
431 char sbuf[STRERR_BUFSIZE];
431 int fd; 432 int fd;
432 433
433 memset(&attr, 0, sizeof(attr)); 434 memset(&attr, 0, sizeof(attr));
@@ -440,7 +441,8 @@ static int self_open_counters(void)
440 441
441 if (fd < 0) 442 if (fd < 0)
442 pr_err("Error: sys_perf_event_open() syscall returned " 443 pr_err("Error: sys_perf_event_open() syscall returned "
443 "with %d (%s)\n", fd, strerror(errno)); 444 "with %d (%s)\n", fd,
445 strerror_r(errno, sbuf, sizeof(sbuf)));
444 return fd; 446 return fd;
445} 447}
446 448
@@ -1462,6 +1464,8 @@ static int perf_sched__read_events(struct perf_sched *sched,
1462 return -1; 1464 return -1;
1463 } 1465 }
1464 1466
1467 symbol__init(&session->header.env);
1468
1465 if (perf_session__set_tracepoints_handlers(session, handlers)) 1469 if (perf_session__set_tracepoints_handlers(session, handlers))
1466 goto out_delete; 1470 goto out_delete;
1467 1471
@@ -1662,7 +1666,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1662 .comm = perf_event__process_comm, 1666 .comm = perf_event__process_comm,
1663 .lost = perf_event__process_lost, 1667 .lost = perf_event__process_lost,
1664 .fork = perf_sched__process_fork_event, 1668 .fork = perf_sched__process_fork_event,
1665 .ordered_samples = true, 1669 .ordered_events = true,
1666 }, 1670 },
1667 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), 1671 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
1668 .sort_list = LIST_HEAD_INIT(sched.sort_list), 1672 .sort_list = LIST_HEAD_INIT(sched.sort_list),
@@ -1747,7 +1751,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1747 if (!strcmp(argv[0], "script")) 1751 if (!strcmp(argv[0], "script"))
1748 return cmd_script(argc, argv, prefix); 1752 return cmd_script(argc, argv, prefix);
1749 1753
1750 symbol__init();
1751 if (!strncmp(argv[0], "rec", 3)) { 1754 if (!strncmp(argv[0], "rec", 3)) {
1752 return __cmd_record(argc, argv); 1755 return __cmd_record(argc, argv);
1753 } else if (!strncmp(argv[0], "lat", 3)) { 1756 } else if (!strncmp(argv[0], "lat", 3)) {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index f57035b89c15..b9b9e58a6c39 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
184 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", 184 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
185 PERF_OUTPUT_IP)) 185 PERF_OUTPUT_IP))
186 return -EINVAL; 186 return -EINVAL;
187
188 if (!no_callchain &&
189 !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
190 symbol_conf.use_callchain = false;
191 } 187 }
192 188
193 if (PRINT_FIELD(ADDR) && 189 if (PRINT_FIELD(ADDR) &&
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
290 set_print_ip_opts(&evsel->attr); 286 set_print_ip_opts(&evsel->attr);
291 } 287 }
292 288
289 if (!no_callchain) {
290 bool use_callchain = false;
291
292 evlist__for_each(session->evlist, evsel) {
293 if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
294 use_callchain = true;
295 break;
296 }
297 }
298 if (!use_callchain)
299 symbol_conf.use_callchain = false;
300 }
301
293 /* 302 /*
294 * set default for tracepoints to print symbols only 303 * set default for tracepoints to print symbols only
295 * if callchains are present 304 * if callchains are present
@@ -476,6 +485,11 @@ static int default_start_script(const char *script __maybe_unused,
476 return 0; 485 return 0;
477} 486}
478 487
488static int default_flush_script(void)
489{
490 return 0;
491}
492
479static int default_stop_script(void) 493static int default_stop_script(void)
480{ 494{
481 return 0; 495 return 0;
@@ -489,6 +503,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused,
489 503
490static struct scripting_ops default_scripting_ops = { 504static struct scripting_ops default_scripting_ops = {
491 .start_script = default_start_script, 505 .start_script = default_start_script,
506 .flush_script = default_flush_script,
492 .stop_script = default_stop_script, 507 .stop_script = default_stop_script,
493 .process_event = process_event, 508 .process_event = process_event,
494 .generate_script = default_generate_script, 509 .generate_script = default_generate_script,
@@ -504,6 +519,11 @@ static void setup_scripting(void)
504 scripting_ops = &default_scripting_ops; 519 scripting_ops = &default_scripting_ops;
505} 520}
506 521
522static int flush_scripting(void)
523{
524 return scripting_ops->flush_script();
525}
526
507static int cleanup_scripting(void) 527static int cleanup_scripting(void)
508{ 528{
509 pr_debug("\nperf script stopped\n"); 529 pr_debug("\nperf script stopped\n");
@@ -1471,12 +1491,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1471 bool show_full_info = false; 1491 bool show_full_info = false;
1472 bool header = false; 1492 bool header = false;
1473 bool header_only = false; 1493 bool header_only = false;
1494 bool script_started = false;
1474 char *rec_script_path = NULL; 1495 char *rec_script_path = NULL;
1475 char *rep_script_path = NULL; 1496 char *rep_script_path = NULL;
1476 struct perf_session *session; 1497 struct perf_session *session;
1477 char *script_path = NULL; 1498 char *script_path = NULL;
1478 const char **__argv; 1499 const char **__argv;
1479 int i, j, err; 1500 int i, j, err = 0;
1480 struct perf_script script = { 1501 struct perf_script script = {
1481 .tool = { 1502 .tool = {
1482 .sample = process_sample_event, 1503 .sample = process_sample_event,
@@ -1488,7 +1509,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1488 .attr = process_attr, 1509 .attr = process_attr,
1489 .tracing_data = perf_event__process_tracing_data, 1510 .tracing_data = perf_event__process_tracing_data,
1490 .build_id = perf_event__process_build_id, 1511 .build_id = perf_event__process_build_id,
1491 .ordered_samples = true, 1512 .ordered_events = true,
1492 .ordering_requires_timestamps = true, 1513 .ordering_requires_timestamps = true,
1493 }, 1514 },
1494 }; 1515 };
@@ -1718,26 +1739,28 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1718 exit(-1); 1739 exit(-1);
1719 } 1740 }
1720 1741
1721 if (symbol__init() < 0)
1722 return -1;
1723 if (!script_name) 1742 if (!script_name)
1724 setup_pager(); 1743 setup_pager();
1725 1744
1726 session = perf_session__new(&file, false, &script.tool); 1745 session = perf_session__new(&file, false, &script.tool);
1727 if (session == NULL) 1746 if (session == NULL)
1728 return -ENOMEM; 1747 return -1;
1729 1748
1730 if (header || header_only) { 1749 if (header || header_only) {
1731 perf_session__fprintf_info(session, stdout, show_full_info); 1750 perf_session__fprintf_info(session, stdout, show_full_info);
1732 if (header_only) 1751 if (header_only)
1733 return 0; 1752 goto out_delete;
1734 } 1753 }
1735 1754
1755 if (symbol__init(&session->header.env) < 0)
1756 goto out_delete;
1757
1736 script.session = session; 1758 script.session = session;
1737 1759
1738 if (cpu_list) { 1760 if (cpu_list) {
1739 if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) 1761 err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
1740 return -1; 1762 if (err < 0)
1763 goto out_delete;
1741 } 1764 }
1742 1765
1743 if (!no_callchain) 1766 if (!no_callchain)
@@ -1752,53 +1775,62 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1752 if (output_set_by_user()) { 1775 if (output_set_by_user()) {
1753 fprintf(stderr, 1776 fprintf(stderr,
1754 "custom fields not supported for generated scripts"); 1777 "custom fields not supported for generated scripts");
1755 return -1; 1778 err = -EINVAL;
1779 goto out_delete;
1756 } 1780 }
1757 1781
1758 input = open(file.path, O_RDONLY); /* input_name */ 1782 input = open(file.path, O_RDONLY); /* input_name */
1759 if (input < 0) { 1783 if (input < 0) {
1784 err = -errno;
1760 perror("failed to open file"); 1785 perror("failed to open file");
1761 return -1; 1786 goto out_delete;
1762 } 1787 }
1763 1788
1764 err = fstat(input, &perf_stat); 1789 err = fstat(input, &perf_stat);
1765 if (err < 0) { 1790 if (err < 0) {
1766 perror("failed to stat file"); 1791 perror("failed to stat file");
1767 return -1; 1792 goto out_delete;
1768 } 1793 }
1769 1794
1770 if (!perf_stat.st_size) { 1795 if (!perf_stat.st_size) {
1771 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1796 fprintf(stderr, "zero-sized file, nothing to do!\n");
1772 return 0; 1797 goto out_delete;
1773 } 1798 }
1774 1799
1775 scripting_ops = script_spec__lookup(generate_script_lang); 1800 scripting_ops = script_spec__lookup(generate_script_lang);
1776 if (!scripting_ops) { 1801 if (!scripting_ops) {
1777 fprintf(stderr, "invalid language specifier"); 1802 fprintf(stderr, "invalid language specifier");
1778 return -1; 1803 err = -ENOENT;
1804 goto out_delete;
1779 } 1805 }
1780 1806
1781 err = scripting_ops->generate_script(session->tevent.pevent, 1807 err = scripting_ops->generate_script(session->tevent.pevent,
1782 "perf-script"); 1808 "perf-script");
1783 goto out; 1809 goto out_delete;
1784 } 1810 }
1785 1811
1786 if (script_name) { 1812 if (script_name) {
1787 err = scripting_ops->start_script(script_name, argc, argv); 1813 err = scripting_ops->start_script(script_name, argc, argv);
1788 if (err) 1814 if (err)
1789 goto out; 1815 goto out_delete;
1790 pr_debug("perf script started with script %s\n\n", script_name); 1816 pr_debug("perf script started with script %s\n\n", script_name);
1817 script_started = true;
1791 } 1818 }
1792 1819
1793 1820
1794 err = perf_session__check_output_opt(session); 1821 err = perf_session__check_output_opt(session);
1795 if (err < 0) 1822 if (err < 0)
1796 goto out; 1823 goto out_delete;
1797 1824
1798 err = __cmd_script(&script); 1825 err = __cmd_script(&script);
1799 1826
1827 flush_scripting();
1828
1829out_delete:
1800 perf_session__delete(session); 1830 perf_session__delete(session);
1801 cleanup_scripting(); 1831
1832 if (script_started)
1833 cleanup_scripting();
1802out: 1834out:
1803 return err; 1835 return err;
1804} 1836}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 3e80aa10cfd8..b22c62f80078 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -593,7 +593,7 @@ static int __run_perf_stat(int argc, const char **argv)
593 593
594 if (perf_evlist__apply_filters(evsel_list)) { 594 if (perf_evlist__apply_filters(evsel_list)) {
595 error("failed to set filter with %d (%s)\n", errno, 595 error("failed to set filter with %d (%s)\n", errno,
596 strerror(errno)); 596 strerror_r(errno, msg, sizeof(msg)));
597 return -1; 597 return -1;
598 } 598 }
599 599
@@ -732,7 +732,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
732 } 732 }
733} 733}
734 734
735static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 735static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
736{ 736{
737 double msecs = avg / 1e6; 737 double msecs = avg / 1e6;
738 const char *fmt_v, *fmt_n; 738 const char *fmt_v, *fmt_n;
@@ -741,7 +741,7 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
741 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; 741 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
742 fmt_n = csv_output ? "%s" : "%-25s"; 742 fmt_n = csv_output ? "%s" : "%-25s";
743 743
744 aggr_printout(evsel, cpu, nr); 744 aggr_printout(evsel, id, nr);
745 745
746 scnprintf(name, sizeof(name), "%s%s", 746 scnprintf(name, sizeof(name), "%s%s",
747 perf_evsel__name(evsel), csv_output ? "" : " (msec)"); 747 perf_evsel__name(evsel), csv_output ? "" : " (msec)");
@@ -947,11 +947,12 @@ static void print_ll_cache_misses(int cpu,
947 fprintf(output, " of all LL-cache hits "); 947 fprintf(output, " of all LL-cache hits ");
948} 948}
949 949
950static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 950static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
951{ 951{
952 double total, ratio = 0.0, total2; 952 double total, ratio = 0.0, total2;
953 double sc = evsel->scale; 953 double sc = evsel->scale;
954 const char *fmt; 954 const char *fmt;
955 int cpu = cpu_map__id_to_cpu(id);
955 956
956 if (csv_output) { 957 if (csv_output) {
957 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; 958 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
@@ -962,7 +963,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
962 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; 963 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
963 } 964 }
964 965
965 aggr_printout(evsel, cpu, nr); 966 aggr_printout(evsel, id, nr);
966 967
967 if (aggr_mode == AGGR_GLOBAL) 968 if (aggr_mode == AGGR_GLOBAL)
968 cpu = 0; 969 cpu = 0;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 2f1a5220c090..35b425b6293f 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -1605,7 +1605,9 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
1605 int ret = -EINVAL; 1605 int ret = -EINVAL;
1606 1606
1607 if (session == NULL) 1607 if (session == NULL)
1608 return -ENOMEM; 1608 return -1;
1609
1610 symbol__init(&session->header.env);
1609 1611
1610 (void)perf_header__process_sections(&session->header, 1612 (void)perf_header__process_sections(&session->header,
1611 perf_data_file__fd(session->file), 1613 perf_data_file__fd(session->file),
@@ -1920,7 +1922,7 @@ int cmd_timechart(int argc, const char **argv,
1920 .fork = process_fork_event, 1922 .fork = process_fork_event,
1921 .exit = process_exit_event, 1923 .exit = process_exit_event,
1922 .sample = process_sample_event, 1924 .sample = process_sample_event,
1923 .ordered_samples = true, 1925 .ordered_events = true,
1924 }, 1926 },
1925 .proc_num = 15, 1927 .proc_num = 15,
1926 .min_time = 1000000, 1928 .min_time = 1000000,
@@ -1982,8 +1984,6 @@ int cmd_timechart(int argc, const char **argv,
1982 return -1; 1984 return -1;
1983 } 1985 }
1984 1986
1985 symbol__init();
1986
1987 if (argc && !strncmp(argv[0], "rec", 3)) { 1987 if (argc && !strncmp(argv[0], "rec", 3)) {
1988 argc = parse_options(argc, argv, record_options, record_usage, 1988 argc = parse_options(argc, argv, record_options, record_usage,
1989 PARSE_OPT_STOP_AT_NON_OPTION); 1989 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 377971dc89a3..fc3d55f832ac 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -59,7 +59,7 @@
59 59
60#include <sys/syscall.h> 60#include <sys/syscall.h>
61#include <sys/ioctl.h> 61#include <sys/ioctl.h>
62#include <sys/poll.h> 62#include <poll.h>
63#include <sys/prctl.h> 63#include <sys/prctl.h>
64#include <sys/wait.h> 64#include <sys/wait.h>
65#include <sys/uio.h> 65#include <sys/uio.h>
@@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top)
276 return; 276 return;
277 } 277 }
278 278
279 if (top->zero) {
280 hists__delete_entries(&top->sym_evsel->hists);
281 } else {
282 hists__decay_entries(&top->sym_evsel->hists,
283 top->hide_user_symbols,
284 top->hide_kernel_symbols);
285 }
286
279 hists__collapse_resort(&top->sym_evsel->hists, NULL); 287 hists__collapse_resort(&top->sym_evsel->hists, NULL);
280 hists__output_resort(&top->sym_evsel->hists); 288 hists__output_resort(&top->sym_evsel->hists);
281 hists__decay_entries(&top->sym_evsel->hists, 289
282 top->hide_user_symbols,
283 top->hide_kernel_symbols);
284 hists__output_recalc_col_len(&top->sym_evsel->hists, 290 hists__output_recalc_col_len(&top->sym_evsel->hists,
285 top->print_entries - printed); 291 top->print_entries - printed);
286 putchar('\n'); 292 putchar('\n');
@@ -427,18 +433,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
427 433
428 if (!perf_top__key_mapped(top, c)) { 434 if (!perf_top__key_mapped(top, c)) {
429 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 435 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
430 struct termios tc, save; 436 struct termios save;
431 437
432 perf_top__print_mapped_keys(top); 438 perf_top__print_mapped_keys(top);
433 fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); 439 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
434 fflush(stdout); 440 fflush(stdout);
435 441
436 tcgetattr(0, &save); 442 set_term_quiet_input(&save);
437 tc = save;
438 tc.c_lflag &= ~(ICANON | ECHO);
439 tc.c_cc[VMIN] = 0;
440 tc.c_cc[VTIME] = 0;
441 tcsetattr(0, TCSANOW, &tc);
442 443
443 poll(&stdin_poll, 1, -1); 444 poll(&stdin_poll, 1, -1);
444 c = getc(stdin); 445 c = getc(stdin);
@@ -542,11 +543,16 @@ static void perf_top__sort_new_samples(void *arg)
542 if (t->evlist->selected != NULL) 543 if (t->evlist->selected != NULL)
543 t->sym_evsel = t->evlist->selected; 544 t->sym_evsel = t->evlist->selected;
544 545
546 if (t->zero) {
547 hists__delete_entries(&t->sym_evsel->hists);
548 } else {
549 hists__decay_entries(&t->sym_evsel->hists,
550 t->hide_user_symbols,
551 t->hide_kernel_symbols);
552 }
553
545 hists__collapse_resort(&t->sym_evsel->hists, NULL); 554 hists__collapse_resort(&t->sym_evsel->hists, NULL);
546 hists__output_resort(&t->sym_evsel->hists); 555 hists__output_resort(&t->sym_evsel->hists);
547 hists__decay_entries(&t->sym_evsel->hists,
548 t->hide_user_symbols,
549 t->hide_kernel_symbols);
550} 556}
551 557
552static void *display_thread_tui(void *arg) 558static void *display_thread_tui(void *arg)
@@ -577,23 +583,32 @@ static void *display_thread_tui(void *arg)
577 return NULL; 583 return NULL;
578} 584}
579 585
586static void display_sig(int sig __maybe_unused)
587{
588 done = 1;
589}
590
591static void display_setup_sig(void)
592{
593 signal(SIGSEGV, display_sig);
594 signal(SIGFPE, display_sig);
595 signal(SIGINT, display_sig);
596 signal(SIGQUIT, display_sig);
597 signal(SIGTERM, display_sig);
598}
599
580static void *display_thread(void *arg) 600static void *display_thread(void *arg)
581{ 601{
582 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 602 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
583 struct termios tc, save; 603 struct termios save;
584 struct perf_top *top = arg; 604 struct perf_top *top = arg;
585 int delay_msecs, c; 605 int delay_msecs, c;
586 606
587 tcgetattr(0, &save); 607 display_setup_sig();
588 tc = save;
589 tc.c_lflag &= ~(ICANON | ECHO);
590 tc.c_cc[VMIN] = 0;
591 tc.c_cc[VTIME] = 0;
592
593 pthread__unblock_sigwinch(); 608 pthread__unblock_sigwinch();
594repeat: 609repeat:
595 delay_msecs = top->delay_secs * 1000; 610 delay_msecs = top->delay_secs * 1000;
596 tcsetattr(0, TCSANOW, &tc); 611 set_term_quiet_input(&save);
597 /* trash return*/ 612 /* trash return*/
598 getc(stdin); 613 getc(stdin);
599 614
@@ -620,13 +635,16 @@ repeat:
620 } 635 }
621 } 636 }
622 637
638 tcsetattr(0, TCSAFLUSH, &save);
623 return NULL; 639 return NULL;
624} 640}
625 641
626static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) 642static int symbol_filter(struct map *map, struct symbol *sym)
627{ 643{
628 const char *name = sym->name; 644 const char *name = sym->name;
629 645
646 if (!map->dso->kernel)
647 return 0;
630 /* 648 /*
631 * ppc64 uses function descriptors and appends a '.' to the 649 * ppc64 uses function descriptors and appends a '.' to the
632 * start of every instruction address. Remove it. 650 * start of every instruction address. Remove it.
@@ -876,7 +894,7 @@ try_again:
876 894
877 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 895 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
878 ui__error("Failed to mmap with %d (%s)\n", 896 ui__error("Failed to mmap with %d (%s)\n",
879 errno, strerror(errno)); 897 errno, strerror_r(errno, msg, sizeof(msg)));
880 goto out_err; 898 goto out_err;
881 } 899 }
882 900
@@ -911,7 +929,7 @@ static int __cmd_top(struct perf_top *top)
911 929
912 top->session = perf_session__new(NULL, false, NULL); 930 top->session = perf_session__new(NULL, false, NULL);
913 if (top->session == NULL) 931 if (top->session == NULL)
914 return -ENOMEM; 932 return -1;
915 933
916 machines__set_symbol_filter(&top->session->machines, symbol_filter); 934 machines__set_symbol_filter(&top->session->machines, symbol_filter);
917 935
@@ -946,7 +964,7 @@ static int __cmd_top(struct perf_top *top)
946 perf_evlist__enable(top->evlist); 964 perf_evlist__enable(top->evlist);
947 965
948 /* Wait for a minimal set of events before starting the snapshot */ 966 /* Wait for a minimal set of events before starting the snapshot */
949 poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 967 perf_evlist__poll(top->evlist, 100);
950 968
951 perf_top__mmap_read(top); 969 perf_top__mmap_read(top);
952 970
@@ -963,7 +981,7 @@ static int __cmd_top(struct perf_top *top)
963 param.sched_priority = top->realtime_prio; 981 param.sched_priority = top->realtime_prio;
964 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 982 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
965 ui__error("Could not set realtime priority.\n"); 983 ui__error("Could not set realtime priority.\n");
966 goto out_delete; 984 goto out_join;
967 } 985 }
968 } 986 }
969 987
@@ -973,10 +991,12 @@ static int __cmd_top(struct perf_top *top)
973 perf_top__mmap_read(top); 991 perf_top__mmap_read(top);
974 992
975 if (hits == top->samples) 993 if (hits == top->samples)
976 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 994 ret = perf_evlist__poll(top->evlist, 100);
977 } 995 }
978 996
979 ret = 0; 997 ret = 0;
998out_join:
999 pthread_join(thread, NULL);
980out_delete: 1000out_delete:
981 perf_session__delete(top->session); 1001 perf_session__delete(top->session);
982 top->session = NULL; 1002 top->session = NULL;
@@ -1000,10 +1020,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1000 1020
1001static int perf_top_config(const char *var, const char *value, void *cb) 1021static int perf_top_config(const char *var, const char *value, void *cb)
1002{ 1022{
1003 struct perf_top *top = cb;
1004
1005 if (!strcmp(var, "top.call-graph")) 1023 if (!strcmp(var, "top.call-graph"))
1006 return record_parse_callchain(value, &top->record_opts); 1024 var = "call-graph.record-mode"; /* fall-through */
1007 if (!strcmp(var, "top.children")) { 1025 if (!strcmp(var, "top.children")) {
1008 symbol_conf.cumulate_callchain = perf_config_bool(var, value); 1026 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
1009 return 0; 1027 return 0;
@@ -1122,6 +1140,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1122 "Interleave source code with assembly code (default)"), 1140 "Interleave source code with assembly code (default)"),
1123 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, 1141 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1124 "Display raw encoding of assembly instructions (default)"), 1142 "Display raw encoding of assembly instructions (default)"),
1143 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
1144 "Enable kernel symbol demangling"),
1125 OPT_STRING(0, "objdump", &objdump_path, "path", 1145 OPT_STRING(0, "objdump", &objdump_path, "path",
1126 "objdump binary to use for disassembly and annotations"), 1146 "objdump binary to use for disassembly and annotations"),
1127 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1147 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
@@ -1131,6 +1151,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1131 "Don't show entries under that percent", parse_percent_limit), 1151 "Don't show entries under that percent", parse_percent_limit),
1132 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", 1152 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
1133 "How to display percentage of filtered entries", parse_filter_percentage), 1153 "How to display percentage of filtered entries", parse_filter_percentage),
1154 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
1155 "width[,width...]",
1156 "don't try to adjust column width, use these fixed values"),
1134 OPT_END() 1157 OPT_END()
1135 }; 1158 };
1136 const char * const top_usage[] = { 1159 const char * const top_usage[] = {
@@ -1217,7 +1240,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1217 symbol_conf.priv_size = sizeof(struct annotation); 1240 symbol_conf.priv_size = sizeof(struct annotation);
1218 1241
1219 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1242 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1220 if (symbol__init() < 0) 1243 if (symbol__init(NULL) < 0)
1221 return -1; 1244 return -1;
1222 1245
1223 sort__setup_elide(stdout); 1246 sort__setup_elide(stdout);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index a6c375224f46..09bcf2393910 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -402,6 +402,31 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
402 402
403#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags 403#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
404 404
405static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
406 struct syscall_arg *arg)
407{
408 int printed = 0, flags = arg->val;
409
410#define P_MREMAP_FLAG(n) \
411 if (flags & MREMAP_##n) { \
412 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
413 flags &= ~MREMAP_##n; \
414 }
415
416 P_MREMAP_FLAG(MAYMOVE);
417#ifdef MREMAP_FIXED
418 P_MREMAP_FLAG(FIXED);
419#endif
420#undef P_MREMAP_FLAG
421
422 if (flags)
423 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
424
425 return printed;
426}
427
428#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
429
405static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, 430static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
406 struct syscall_arg *arg) 431 struct syscall_arg *arg)
407{ 432{
@@ -1004,6 +1029,7 @@ static struct syscall_fmt {
1004 [2] = SCA_MMAP_PROT, /* prot */ }, }, 1029 [2] = SCA_MMAP_PROT, /* prot */ }, },
1005 { .name = "mremap", .hexret = true, 1030 { .name = "mremap", .hexret = true,
1006 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 1031 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
1032 [3] = SCA_MREMAP_FLAGS, /* flags */
1007 [4] = SCA_HEX, /* new_addr */ }, }, 1033 [4] = SCA_HEX, /* new_addr */ }, },
1008 { .name = "munlock", .errmsg = true, 1034 { .name = "munlock", .errmsg = true,
1009 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 1035 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
@@ -1385,7 +1411,7 @@ static int trace__tool_process(struct perf_tool *tool,
1385 1411
1386static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) 1412static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1387{ 1413{
1388 int err = symbol__init(); 1414 int err = symbol__init(NULL);
1389 1415
1390 if (err) 1416 if (err)
1391 return err; 1417 return err;
@@ -1669,7 +1695,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1669 union perf_event *event __maybe_unused, 1695 union perf_event *event __maybe_unused,
1670 struct perf_sample *sample) 1696 struct perf_sample *sample)
1671{ 1697{
1672 int ret; 1698 long ret;
1673 u64 duration = 0; 1699 u64 duration = 0;
1674 struct thread *thread; 1700 struct thread *thread;
1675 int id = perf_evsel__sc_tp_uint(evsel, id, sample); 1701 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
@@ -1722,9 +1748,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1722 1748
1723 if (sc->fmt == NULL) { 1749 if (sc->fmt == NULL) {
1724signed_print: 1750signed_print:
1725 fprintf(trace->output, ") = %d", ret); 1751 fprintf(trace->output, ") = %ld", ret);
1726 } else if (ret < 0 && sc->fmt->errmsg) { 1752 } else if (ret < 0 && sc->fmt->errmsg) {
1727 char bf[256]; 1753 char bf[STRERR_BUFSIZE];
1728 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 1754 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1729 *e = audit_errno_to_name(-ret); 1755 *e = audit_errno_to_name(-ret);
1730 1756
@@ -1732,7 +1758,7 @@ signed_print:
1732 } else if (ret == 0 && sc->fmt->timeout) 1758 } else if (ret == 0 && sc->fmt->timeout)
1733 fprintf(trace->output, ") = 0 Timeout"); 1759 fprintf(trace->output, ") = 0 Timeout");
1734 else if (sc->fmt->hexret) 1760 else if (sc->fmt->hexret)
1735 fprintf(trace->output, ") = %#x", ret); 1761 fprintf(trace->output, ") = %#lx", ret);
1736 else 1762 else
1737 goto signed_print; 1763 goto signed_print;
1738 1764
@@ -2018,6 +2044,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2018 int err = -1, i; 2044 int err = -1, i;
2019 unsigned long before; 2045 unsigned long before;
2020 const bool forks = argc > 0; 2046 const bool forks = argc > 0;
2047 bool draining = false;
2048 char sbuf[STRERR_BUFSIZE];
2021 2049
2022 trace->live = true; 2050 trace->live = true;
2023 2051
@@ -2079,7 +2107,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2079 2107
2080 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); 2108 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
2081 if (err < 0) { 2109 if (err < 0) {
2082 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); 2110 fprintf(trace->output, "Couldn't mmap the events: %s\n",
2111 strerror_r(errno, sbuf, sizeof(sbuf)));
2083 goto out_delete_evlist; 2112 goto out_delete_evlist;
2084 } 2113 }
2085 2114
@@ -2143,8 +2172,12 @@ next_event:
2143 if (trace->nr_events == before) { 2172 if (trace->nr_events == before) {
2144 int timeout = done ? 100 : -1; 2173 int timeout = done ? 100 : -1;
2145 2174
2146 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0) 2175 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2176 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2177 draining = true;
2178
2147 goto again; 2179 goto again;
2180 }
2148 } else { 2181 } else {
2149 goto again; 2182 goto again;
2150 } 2183 }
@@ -2209,18 +2242,18 @@ static int trace__replay(struct trace *trace)
2209 trace->tool.tracing_data = perf_event__process_tracing_data; 2242 trace->tool.tracing_data = perf_event__process_tracing_data;
2210 trace->tool.build_id = perf_event__process_build_id; 2243 trace->tool.build_id = perf_event__process_build_id;
2211 2244
2212 trace->tool.ordered_samples = true; 2245 trace->tool.ordered_events = true;
2213 trace->tool.ordering_requires_timestamps = true; 2246 trace->tool.ordering_requires_timestamps = true;
2214 2247
2215 /* add tid to output */ 2248 /* add tid to output */
2216 trace->multiple_threads = true; 2249 trace->multiple_threads = true;
2217 2250
2218 if (symbol__init() < 0)
2219 return -1;
2220
2221 session = perf_session__new(&file, false, &trace->tool); 2251 session = perf_session__new(&file, false, &trace->tool);
2222 if (session == NULL) 2252 if (session == NULL)
2223 return -ENOMEM; 2253 return -1;
2254
2255 if (symbol__init(&session->header.env) < 0)
2256 goto out;
2224 2257
2225 trace->host = &session->machines.host; 2258 trace->host = &session->machines.host;
2226 2259
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 1f67aa02d240..58f609198c6d 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -48,10 +48,6 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
48 NO_LIBDW_DWARF_UNWIND := 1 48 NO_LIBDW_DWARF_UNWIND := 1
49endif 49endif
50 50
51ifeq ($(ARCH),powerpc)
52 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
53endif
54
55ifeq ($(LIBUNWIND_LIBS),) 51ifeq ($(LIBUNWIND_LIBS),)
56 NO_LIBUNWIND := 1 52 NO_LIBUNWIND := 1
57else 53else
@@ -120,6 +116,29 @@ ifdef PARSER_DEBUG
120 CFLAGS += -DPARSER_DEBUG 116 CFLAGS += -DPARSER_DEBUG
121endif 117endif
122 118
119ifndef NO_LIBPYTHON
120 # Try different combinations to accommodate systems that only have
121 # python[2][-config] in weird combinations but always preferring
122 # python2 and python2-config as per pep-0394. If we catch a
123 # python[-config] in version 3, the version check will kill it.
124 PYTHON2 := $(if $(call get-executable,python2),python2,python)
125 override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
126 PYTHON2_CONFIG := \
127 $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
128 override PYTHON_CONFIG := \
129 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
130
131 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
132
133 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
134 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
135
136 FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
137 FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
138 FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
139 FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
140endif
141
123CFLAGS += -fno-omit-frame-pointer 142CFLAGS += -fno-omit-frame-pointer
124CFLAGS += -ggdb3 143CFLAGS += -ggdb3
125CFLAGS += -funwind-tables 144CFLAGS += -funwind-tables
@@ -355,6 +374,12 @@ ifndef NO_LIBELF
355 endif # NO_DWARF 374 endif # NO_DWARF
356endif # NO_LIBELF 375endif # NO_LIBELF
357 376
377ifeq ($(ARCH),powerpc)
378 ifndef NO_DWARF
379 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
380 endif
381endif
382
358ifndef NO_LIBUNWIND 383ifndef NO_LIBUNWIND
359 ifneq ($(feature-libunwind), 1) 384 ifneq ($(feature-libunwind), 1)
360 msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); 385 msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR);
@@ -482,21 +507,14 @@ define disable-python_code
482 NO_LIBPYTHON := 1 507 NO_LIBPYTHON := 1
483endef 508endef
484 509
485override PYTHON := \ 510ifdef NO_LIBPYTHON
486 $(call get-executable-or-default,PYTHON,python) 511 $(call disable-python)
487
488ifndef PYTHON
489 $(call disable-python,python interpreter)
490else 512else
491 513
492 PYTHON_WORD := $(call shell-wordify,$(PYTHON)) 514 ifndef PYTHON
493 515 $(call disable-python,python interpreter)
494 ifdef NO_LIBPYTHON
495 $(call disable-python)
496 else 516 else
497 517 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
498 override PYTHON_CONFIG := \
499 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
500 518
501 ifndef PYTHON_CONFIG 519 ifndef PYTHON_CONFIG
502 $(call disable-python,python-config tool) 520 $(call disable-python,python-config tool)
@@ -635,11 +653,13 @@ else
635sysconfdir = $(prefix)/etc 653sysconfdir = $(prefix)/etc
636ETC_PERFCONFIG = etc/perfconfig 654ETC_PERFCONFIG = etc/perfconfig
637endif 655endif
656ifndef lib
638ifeq ($(IS_X86_64),1) 657ifeq ($(IS_X86_64),1)
639lib = lib64 658lib = lib64
640else 659else
641lib = lib 660lib = lib
642endif 661endif
662endif # lib
643libdir = $(prefix)/$(lib) 663libdir = $(prefix)/$(lib)
644 664
645# Shell quote (do not use $(call) to accommodate ancient setups); 665# Shell quote (do not use $(call) to accommodate ancient setups);
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 6088f8d8a434..72ab2984718e 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -101,25 +101,11 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
101test-libperl.bin: 101test-libperl.bin:
102 $(BUILD) $(FLAGS_PERL_EMBED) 102 $(BUILD) $(FLAGS_PERL_EMBED)
103 103
104override PYTHON := python
105override PYTHON_CONFIG := python-config
106
107escape-for-shell-sq = $(subst ','\'',$(1))
108shell-sq = '$(escape-for-shell-sq)'
109
110PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG))
111
112PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
113PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
114PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
115PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
116FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
117
118test-libpython.bin: 104test-libpython.bin:
119 $(BUILD) $(FLAGS_PYTHON_EMBED) 105 $(BUILD)
120 106
121test-libpython-version.bin: 107test-libpython-version.bin:
122 $(BUILD) $(FLAGS_PYTHON_EMBED) 108 $(BUILD)
123 109
124test-libbfd.bin: 110test-libbfd.bin:
125 $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl 111 $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index 4d985e0f03f5..7076a62d0ff7 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -132,7 +132,7 @@ endef
132# 132#
133# Usage: bool-value = $(call is-absolute,path) 133# Usage: bool-value = $(call is-absolute,path)
134# 134#
135is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y) 135is-absolute = $(shell echo $(shell-sq) | grep -q ^/ && echo y)
136 136
137# lookup 137# lookup
138# 138#
diff --git a/tools/perf/perf-with-kcore.sh b/tools/perf/perf-with-kcore.sh
new file mode 100644
index 000000000000..c7ff90a90e4e
--- /dev/null
+++ b/tools/perf/perf-with-kcore.sh
@@ -0,0 +1,259 @@
1#!/bin/bash
2# perf-with-kcore: use perf with a copy of kcore
3# Copyright (c) 2014, Intel Corporation.
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms and conditions of the GNU General Public License,
7# version 2, as published by the Free Software Foundation.
8#
9# This program is distributed in the hope it will be useful, but WITHOUT
10# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12# more details.
13
14set -e
15
16usage()
17{
18 echo "Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]" >&2
19 echo " <perf sub-command> can be record, script, report or inject" >&2
20 echo " or: perf-with-kcore fix_buildid_cache_permissions" >&2
21 exit 1
22}
23
24find_perf()
25{
26 if [ -n "$PERF" ] ; then
27 return
28 fi
29 PERF=`which perf || true`
30 if [ -z "$PERF" ] ; then
31 echo "Failed to find perf" >&2
32 exit 1
33 fi
34 if [ ! -x "$PERF" ] ; then
35 echo "Failed to find perf" >&2
36 exit 1
37 fi
38 echo "Using $PERF"
39 "$PERF" version
40}
41
42copy_kcore()
43{
44 echo "Copying kcore"
45
46 if [ $EUID -eq 0 ] ; then
47 SUDO=""
48 else
49 SUDO="sudo"
50 fi
51
52 rm -f perf.data.junk
53 ("$PERF" record -o perf.data.junk $PERF_OPTIONS -- sleep 60) >/dev/null 2>/dev/null &
54 PERF_PID=$!
55
56 # Need to make sure that perf has started
57 sleep 1
58
59 KCORE=$(($SUDO "$PERF" buildid-cache -v -f -k /proc/kcore >/dev/null) 2>&1)
60 case "$KCORE" in
61 "kcore added to build-id cache directory "*)
62 KCORE_DIR=${KCORE#"kcore added to build-id cache directory "}
63 ;;
64 *)
65 kill $PERF_PID
66 wait >/dev/null 2>/dev/null || true
67 rm perf.data.junk
68 echo "$KCORE"
69 echo "Failed to find kcore" >&2
70 exit 1
71 ;;
72 esac
73
74 kill $PERF_PID
75 wait >/dev/null 2>/dev/null || true
76 rm perf.data.junk
77
78 $SUDO cp -a "$KCORE_DIR" "$(pwd)/$PERF_DATA_DIR"
79 $SUDO rm -f "$KCORE_DIR/kcore"
80 $SUDO rm -f "$KCORE_DIR/kallsyms"
81 $SUDO rm -f "$KCORE_DIR/modules"
82 $SUDO rmdir "$KCORE_DIR"
83
84 KCORE_DIR_BASENAME=$(basename "$KCORE_DIR")
85 KCORE_DIR="$(pwd)/$PERF_DATA_DIR/$KCORE_DIR_BASENAME"
86
87 $SUDO chown $UID "$KCORE_DIR"
88 $SUDO chown $UID "$KCORE_DIR/kcore"
89 $SUDO chown $UID "$KCORE_DIR/kallsyms"
90 $SUDO chown $UID "$KCORE_DIR/modules"
91
92 $SUDO chgrp $GROUPS "$KCORE_DIR"
93 $SUDO chgrp $GROUPS "$KCORE_DIR/kcore"
94 $SUDO chgrp $GROUPS "$KCORE_DIR/kallsyms"
95 $SUDO chgrp $GROUPS "$KCORE_DIR/modules"
96
97 ln -s "$KCORE_DIR_BASENAME" "$PERF_DATA_DIR/kcore_dir"
98}
99
100fix_buildid_cache_permissions()
101{
102 if [ $EUID -ne 0 ] ; then
103 echo "This script must be run as root via sudo " >&2
104 exit 1
105 fi
106
107 if [ -z "$SUDO_USER" ] ; then
108 echo "This script must be run via sudo" >&2
109 exit 1
110 fi
111
112 USER_HOME=$(bash <<< "echo ~$SUDO_USER")
113
114 if [ "$HOME" != "$USER_HOME" ] ; then
115 echo "Fix unnecessary because root has a home: $HOME" >&2
116 exit 1
117 fi
118
119 echo "Fixing buildid cache permissions"
120
121 find "$USER_HOME/.debug" -xdev -type d ! -user "$SUDO_USER" -ls -exec chown "$SUDO_USER" \{\} \;
122 find "$USER_HOME/.debug" -xdev -type f -links 1 ! -user "$SUDO_USER" -ls -exec chown "$SUDO_USER" \{\} \;
123 find "$USER_HOME/.debug" -xdev -type l ! -user "$SUDO_USER" -ls -exec chown -h "$SUDO_USER" \{\} \;
124
125 if [ -n "$SUDO_GID" ] ; then
126 find "$USER_HOME/.debug" -xdev -type d ! -group "$SUDO_GID" -ls -exec chgrp "$SUDO_GID" \{\} \;
127 find "$USER_HOME/.debug" -xdev -type f -links 1 ! -group "$SUDO_GID" -ls -exec chgrp "$SUDO_GID" \{\} \;
128 find "$USER_HOME/.debug" -xdev -type l ! -group "$SUDO_GID" -ls -exec chgrp -h "$SUDO_GID" \{\} \;
129 fi
130
131 echo "Done"
132}
133
134check_buildid_cache_permissions()
135{
136 if [ $EUID -eq 0 ] ; then
137 return
138 fi
139
140 PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d ! -user "$USER" -print -quit)
141 PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -user "$USER" -print -quit)
142 PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l ! -user "$USER" -print -quit)
143
144 PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d ! -group "$GROUPS" -print -quit)
145 PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -group "$GROUPS" -print -quit)
146 PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l ! -group "$GROUPS" -print -quit)
147
148 if [ -n "$PERMISSIONS_OK" ] ; then
149 echo "*** WARNING *** buildid cache permissions may need fixing" >&2
150 fi
151}
152
153record()
154{
155 echo "Recording"
156
157 if [ $EUID -ne 0 ] ; then
158
159 if [ "$(cat /proc/sys/kernel/kptr_restrict)" -ne 0 ] ; then
160 echo "*** WARNING *** /proc/sys/kernel/kptr_restrict prevents access to kernel addresses" >&2
161 fi
162
163 if echo "$PERF_OPTIONS" | grep -q ' -a \|^-a \| -a$\|^-a$\| --all-cpus \|^--all-cpus \| --all-cpus$\|^--all-cpus$' ; then
164 echo "*** WARNING *** system-wide tracing without root access will not be able to read all necessary information from /proc" >&2
165 fi
166
167 if echo "$PERF_OPTIONS" | grep -q 'intel_pt\|intel_bts\| -I\|^-I' ; then
168 if [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt -1 ] ; then
169 echo "*** WARNING *** /proc/sys/kernel/perf_event_paranoid restricts buffer size and tracepoint (sched_switch) use" >&2
170 fi
171
172 if echo "$PERF_OPTIONS" | grep -q ' --per-thread \|^--per-thread \| --per-thread$\|^--per-thread$' ; then
173 true
174 elif echo "$PERF_OPTIONS" | grep -q ' -t \|^-t \| -t$\|^-t$' ; then
175 true
176 elif [ ! -r /sys/kernel/debug -o ! -x /sys/kernel/debug ] ; then
177 echo "*** WARNING *** /sys/kernel/debug permissions prevent tracepoint (sched_switch) use" >&2
178 fi
179 fi
180 fi
181
182 if [ -z "$1" ] ; then
183 echo "Workload is required for recording" >&2
184 usage
185 fi
186
187 if [ -e "$PERF_DATA_DIR" ] ; then
188 echo "'$PERF_DATA_DIR' exists" >&2
189 exit 1
190 fi
191
192 find_perf
193
194 mkdir "$PERF_DATA_DIR"
195
196 echo "$PERF record -o $PERF_DATA_DIR/perf.data $PERF_OPTIONS -- $*"
197 "$PERF" record -o "$PERF_DATA_DIR/perf.data" $PERF_OPTIONS -- $* || true
198
199 if rmdir "$PERF_DATA_DIR" > /dev/null 2>/dev/null ; then
200 exit 1
201 fi
202
203 copy_kcore
204
205 echo "Done"
206}
207
208subcommand()
209{
210 find_perf
211 check_buildid_cache_permissions
212 echo "$PERF $PERF_SUB_COMMAND -i $PERF_DATA_DIR/perf.data --kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms $*"
213 "$PERF" $PERF_SUB_COMMAND -i "$PERF_DATA_DIR/perf.data" "--kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms" $*
214}
215
216if [ "$1" = "fix_buildid_cache_permissions" ] ; then
217 fix_buildid_cache_permissions
218 exit 0
219fi
220
221PERF_SUB_COMMAND=$1
222PERF_DATA_DIR=$2
223shift || true
224shift || true
225
226if [ -z "$PERF_SUB_COMMAND" ] ; then
227 usage
228fi
229
230if [ -z "$PERF_DATA_DIR" ] ; then
231 usage
232fi
233
234case "$PERF_SUB_COMMAND" in
235"record")
236 while [ "$1" != "--" ] ; do
237 PERF_OPTIONS+="$1 "
238 shift || break
239 done
240 if [ "$1" != "--" ] ; then
241 echo "Options and workload are required for recording" >&2
242 usage
243 fi
244 shift
245 record $*
246;;
247"script")
248 subcommand $*
249;;
250"report")
251 subcommand $*
252;;
253"inject")
254 subcommand $*
255;;
256*)
257 usage
258;;
259esac
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 2282d41879a2..452a8474d29d 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -313,6 +313,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
313 int status; 313 int status;
314 struct stat st; 314 struct stat st;
315 const char *prefix; 315 const char *prefix;
316 char sbuf[STRERR_BUFSIZE];
316 317
317 prefix = NULL; 318 prefix = NULL;
318 if (p->option & RUN_SETUP) 319 if (p->option & RUN_SETUP)
@@ -343,7 +344,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
343 status = 1; 344 status = 1;
344 /* Check for ENOSPC and EIO errors.. */ 345 /* Check for ENOSPC and EIO errors.. */
345 if (fflush(stdout)) { 346 if (fflush(stdout)) {
346 fprintf(stderr, "write failure on standard output: %s", strerror(errno)); 347 fprintf(stderr, "write failure on standard output: %s",
348 strerror_r(errno, sbuf, sizeof(sbuf)));
347 goto out; 349 goto out;
348 } 350 }
349 if (ferror(stdout)) { 351 if (ferror(stdout)) {
@@ -351,7 +353,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
351 goto out; 353 goto out;
352 } 354 }
353 if (fclose(stdout)) { 355 if (fclose(stdout)) {
354 fprintf(stderr, "close failed on standard output: %s", strerror(errno)); 356 fprintf(stderr, "close failed on standard output: %s",
357 strerror_r(errno, sbuf, sizeof(sbuf)));
355 goto out; 358 goto out;
356 } 359 }
357 status = 0; 360 status = 0;
@@ -466,6 +469,7 @@ void pthread__unblock_sigwinch(void)
466int main(int argc, const char **argv) 469int main(int argc, const char **argv)
467{ 470{
468 const char *cmd; 471 const char *cmd;
472 char sbuf[STRERR_BUFSIZE];
469 473
470 /* The page_size is placed in util object. */ 474 /* The page_size is placed in util object. */
471 page_size = sysconf(_SC_PAGE_SIZE); 475 page_size = sysconf(_SC_PAGE_SIZE);
@@ -561,7 +565,7 @@ int main(int argc, const char **argv)
561 } 565 }
562 566
563 fprintf(stderr, "Failed to run command '%s': %s\n", 567 fprintf(stderr, "Failed to run command '%s': %s\n",
564 cmd, strerror(errno)); 568 cmd, strerror_r(errno, sbuf, sizeof(sbuf)));
565out: 569out:
566 return 1; 570 return 1;
567} 571}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 510c65f72858..220d44e44c1b 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -41,8 +41,6 @@ void pthread__unblock_sigwinch(void);
41 41
42struct record_opts { 42struct record_opts {
43 struct target target; 43 struct target target;
44 int call_graph;
45 bool call_graph_enabled;
46 bool group; 44 bool group;
47 bool inherit_stat; 45 bool inherit_stat;
48 bool no_buffering; 46 bool no_buffering;
@@ -60,7 +58,6 @@ struct record_opts {
60 u64 branch_stack; 58 u64 branch_stack;
61 u64 default_interval; 59 u64 default_interval;
62 u64 user_interval; 60 u64 user_interval;
63 u16 stack_dump_size;
64 bool sample_transaction; 61 bool sample_transaction;
65 unsigned initial_delay; 62 unsigned initial_delay;
66}; 63};
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 6f8b01bc6033..ac655b0700e7 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -154,6 +154,18 @@ static struct test {
154 .func = test__hists_cumulate, 154 .func = test__hists_cumulate,
155 }, 155 },
156 { 156 {
157 .desc = "Test tracking with sched_switch",
158 .func = test__switch_tracking,
159 },
160 {
161 .desc = "Filter fds with revents mask in a fdarray",
162 .func = test__fdarray__filter,
163 },
164 {
165 .desc = "Add fd to a fdarray, making it autogrow",
166 .func = test__fdarray__add,
167 },
168 {
157 .func = NULL, 169 .func = NULL,
158 }, 170 },
159}; 171};
@@ -185,9 +197,11 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
185static int run_test(struct test *test) 197static int run_test(struct test *test)
186{ 198{
187 int status, err = -1, child = fork(); 199 int status, err = -1, child = fork();
200 char sbuf[STRERR_BUFSIZE];
188 201
189 if (child < 0) { 202 if (child < 0) {
190 pr_err("failed to fork test: %s\n", strerror(errno)); 203 pr_err("failed to fork test: %s\n",
204 strerror_r(errno, sbuf, sizeof(sbuf)));
191 return -1; 205 return -1;
192 } 206 }
193 207
@@ -297,7 +311,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
297 symbol_conf.sort_by_name = true; 311 symbol_conf.sort_by_name = true;
298 symbol_conf.try_vmlinux_path = true; 312 symbol_conf.try_vmlinux_path = true;
299 313
300 if (symbol__init() < 0) 314 if (symbol__init(NULL) < 0)
301 return -1; 315 return -1;
302 316
303 if (skip != NULL) 317 if (skip != NULL)
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c
new file mode 100644
index 000000000000..d24b837951d4
--- /dev/null
+++ b/tools/perf/tests/fdarray.c
@@ -0,0 +1,174 @@
1#include <api/fd/array.h>
2#include "util/debug.h"
3#include "tests/tests.h"
4
5static void fdarray__init_revents(struct fdarray *fda, short revents)
6{
7 int fd;
8
9 fda->nr = fda->nr_alloc;
10
11 for (fd = 0; fd < fda->nr; ++fd) {
12 fda->entries[fd].fd = fda->nr - fd;
13 fda->entries[fd].revents = revents;
14 }
15}
16
17static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE *fp)
18{
19 int printed = 0;
20
21 if (!verbose)
22 return 0;
23
24 printed += fprintf(fp, "\n%s: ", prefix);
25 return printed + fdarray__fprintf(fda, fp);
26}
27
28int test__fdarray__filter(void)
29{
30 int nr_fds, expected_fd[2], fd, err = TEST_FAIL;
31 struct fdarray *fda = fdarray__new(5, 5);
32
33 if (fda == NULL) {
34 pr_debug("\nfdarray__new() failed!");
35 goto out;
36 }
37
38 fdarray__init_revents(fda, POLLIN);
39 nr_fds = fdarray__filter(fda, POLLHUP, NULL);
40 if (nr_fds != fda->nr_alloc) {
41 pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything",
42 nr_fds, fda->nr_alloc);
43 goto out_delete;
44 }
45
46 fdarray__init_revents(fda, POLLHUP);
47 nr_fds = fdarray__filter(fda, POLLHUP, NULL);
48 if (nr_fds != 0) {
49 pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds",
50 nr_fds, fda->nr_alloc);
51 goto out_delete;
52 }
53
54 fdarray__init_revents(fda, POLLHUP);
55 fda->entries[2].revents = POLLIN;
56 expected_fd[0] = fda->entries[2].fd;
57
58 pr_debug("\nfiltering all but fda->entries[2]:");
59 fdarray__fprintf_prefix(fda, "before", stderr);
60 nr_fds = fdarray__filter(fda, POLLHUP, NULL);
61 fdarray__fprintf_prefix(fda, " after", stderr);
62 if (nr_fds != 1) {
63 pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds);
64 goto out_delete;
65 }
66
67 if (fda->entries[0].fd != expected_fd[0]) {
68 pr_debug("\nfda->entries[0].fd=%d != %d\n",
69 fda->entries[0].fd, expected_fd[0]);
70 goto out_delete;
71 }
72
73 fdarray__init_revents(fda, POLLHUP);
74 fda->entries[0].revents = POLLIN;
75 expected_fd[0] = fda->entries[0].fd;
76 fda->entries[3].revents = POLLIN;
77 expected_fd[1] = fda->entries[3].fd;
78
79 pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):");
80 fdarray__fprintf_prefix(fda, "before", stderr);
81 nr_fds = fdarray__filter(fda, POLLHUP, NULL);
82 fdarray__fprintf_prefix(fda, " after", stderr);
83 if (nr_fds != 2) {
84 pr_debug("\nfdarray__filter()=%d != 2, should have left just two events",
85 nr_fds);
86 goto out_delete;
87 }
88
89 for (fd = 0; fd < 2; ++fd) {
90 if (fda->entries[fd].fd != expected_fd[fd]) {
91 pr_debug("\nfda->entries[%d].fd=%d != %d\n", fd,
92 fda->entries[fd].fd, expected_fd[fd]);
93 goto out_delete;
94 }
95 }
96
97 pr_debug("\n");
98
99 err = 0;
100out_delete:
101 fdarray__delete(fda);
102out:
103 return err;
104}
105
106int test__fdarray__add(void)
107{
108 int err = TEST_FAIL;
109 struct fdarray *fda = fdarray__new(2, 2);
110
111 if (fda == NULL) {
112 pr_debug("\nfdarray__new() failed!");
113 goto out;
114 }
115
116#define FDA_CHECK(_idx, _fd, _revents) \
117 if (fda->entries[_idx].fd != _fd) { \
118 pr_debug("\n%d: fda->entries[%d](%d) != %d!", \
119 __LINE__, _idx, fda->entries[1].fd, _fd); \
120 goto out_delete; \
121 } \
122 if (fda->entries[_idx].events != (_revents)) { \
123 pr_debug("\n%d: fda->entries[%d].revents(%d) != %d!", \
124 __LINE__, _idx, fda->entries[_idx].fd, _revents); \
125 goto out_delete; \
126 }
127
128#define FDA_ADD(_idx, _fd, _revents, _nr) \
129 if (fdarray__add(fda, _fd, _revents) < 0) { \
130 pr_debug("\n%d: fdarray__add(fda, %d, %d) failed!", \
131 __LINE__,_fd, _revents); \
132 goto out_delete; \
133 } \
134 if (fda->nr != _nr) { \
135 pr_debug("\n%d: fdarray__add(fda, %d, %d)=%d != %d", \
136 __LINE__,_fd, _revents, fda->nr, _nr); \
137 goto out_delete; \
138 } \
139 FDA_CHECK(_idx, _fd, _revents)
140
141 FDA_ADD(0, 1, POLLIN, 1);
142 FDA_ADD(1, 2, POLLERR, 2);
143
144 fdarray__fprintf_prefix(fda, "before growing array", stderr);
145
146 FDA_ADD(2, 35, POLLHUP, 3);
147
148 if (fda->entries == NULL) {
149 pr_debug("\nfdarray__add(fda, 35, POLLHUP) should have allocated fda->pollfd!");
150 goto out_delete;
151 }
152
153 fdarray__fprintf_prefix(fda, "after 3rd add", stderr);
154
155 FDA_ADD(3, 88, POLLIN | POLLOUT, 4);
156
157 fdarray__fprintf_prefix(fda, "after 4th add", stderr);
158
159 FDA_CHECK(0, 1, POLLIN);
160 FDA_CHECK(1, 2, POLLERR);
161 FDA_CHECK(2, 35, POLLHUP);
162 FDA_CHECK(3, 88, POLLIN | POLLOUT);
163
164#undef FDA_ADD
165#undef FDA_CHECK
166
167 pr_debug("\n");
168
169 err = 0;
170out_delete:
171 fdarray__delete(fda);
172out:
173 return err;
174}
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 142263492f6f..9b9622a33932 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -31,6 +31,7 @@ int test__basic_mmap(void)
31 unsigned int nr_events[nsyscalls], 31 unsigned int nr_events[nsyscalls],
32 expected_nr_events[nsyscalls], i, j; 32 expected_nr_events[nsyscalls], i, j;
33 struct perf_evsel *evsels[nsyscalls], *evsel; 33 struct perf_evsel *evsels[nsyscalls], *evsel;
34 char sbuf[STRERR_BUFSIZE];
34 35
35 threads = thread_map__new(-1, getpid(), UINT_MAX); 36 threads = thread_map__new(-1, getpid(), UINT_MAX);
36 if (threads == NULL) { 37 if (threads == NULL) {
@@ -49,7 +50,7 @@ int test__basic_mmap(void)
49 sched_setaffinity(0, sizeof(cpu_set), &cpu_set); 50 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
50 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { 51 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
51 pr_debug("sched_setaffinity() failed on CPU %d: %s ", 52 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
52 cpus->map[0], strerror(errno)); 53 cpus->map[0], strerror_r(errno, sbuf, sizeof(sbuf)));
53 goto out_free_cpus; 54 goto out_free_cpus;
54 } 55 }
55 56
@@ -79,7 +80,7 @@ int test__basic_mmap(void)
79 if (perf_evsel__open(evsels[i], cpus, threads) < 0) { 80 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
80 pr_debug("failed to open counter: %s, " 81 pr_debug("failed to open counter: %s, "
81 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 82 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
82 strerror(errno)); 83 strerror_r(errno, sbuf, sizeof(sbuf)));
83 goto out_delete_evlist; 84 goto out_delete_evlist;
84 } 85 }
85 86
@@ -89,7 +90,7 @@ int test__basic_mmap(void)
89 90
90 if (perf_evlist__mmap(evlist, 128, true) < 0) { 91 if (perf_evlist__mmap(evlist, 128, true) < 0) {
91 pr_debug("failed to mmap events: %d (%s)\n", errno, 92 pr_debug("failed to mmap events: %d (%s)\n", errno,
92 strerror(errno)); 93 strerror_r(errno, sbuf, sizeof(sbuf)));
93 goto out_delete_evlist; 94 goto out_delete_evlist;
94 } 95 }
95 96
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c
index 5fecdbd2f5f7..8fa82d1700c7 100644
--- a/tools/perf/tests/open-syscall-all-cpus.c
+++ b/tools/perf/tests/open-syscall-all-cpus.c
@@ -12,6 +12,7 @@ int test__open_syscall_event_on_all_cpus(void)
12 unsigned int nr_open_calls = 111, i; 12 unsigned int nr_open_calls = 111, i;
13 cpu_set_t cpu_set; 13 cpu_set_t cpu_set;
14 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); 14 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
15 char sbuf[STRERR_BUFSIZE];
15 16
16 if (threads == NULL) { 17 if (threads == NULL) {
17 pr_debug("thread_map__new\n"); 18 pr_debug("thread_map__new\n");
@@ -35,7 +36,7 @@ int test__open_syscall_event_on_all_cpus(void)
35 if (perf_evsel__open(evsel, cpus, threads) < 0) { 36 if (perf_evsel__open(evsel, cpus, threads) < 0) {
36 pr_debug("failed to open counter: %s, " 37 pr_debug("failed to open counter: %s, "
37 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 38 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
38 strerror(errno)); 39 strerror_r(errno, sbuf, sizeof(sbuf)));
39 goto out_evsel_delete; 40 goto out_evsel_delete;
40 } 41 }
41 42
@@ -56,7 +57,7 @@ int test__open_syscall_event_on_all_cpus(void)
56 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { 57 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
57 pr_debug("sched_setaffinity() failed on CPU %d: %s ", 58 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
58 cpus->map[cpu], 59 cpus->map[cpu],
59 strerror(errno)); 60 strerror_r(errno, sbuf, sizeof(sbuf)));
60 goto out_close_fd; 61 goto out_close_fd;
61 } 62 }
62 for (i = 0; i < ncalls; ++i) { 63 for (i = 0; i < ncalls; ++i) {
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index 0785b64ffd6c..127dcae0b760 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -22,6 +22,7 @@ int test__syscall_open_tp_fields(void)
22 struct perf_evlist *evlist = perf_evlist__new(); 22 struct perf_evlist *evlist = perf_evlist__new();
23 struct perf_evsel *evsel; 23 struct perf_evsel *evsel;
24 int err = -1, i, nr_events = 0, nr_polls = 0; 24 int err = -1, i, nr_events = 0, nr_polls = 0;
25 char sbuf[STRERR_BUFSIZE];
25 26
26 if (evlist == NULL) { 27 if (evlist == NULL) {
27 pr_debug("%s: perf_evlist__new\n", __func__); 28 pr_debug("%s: perf_evlist__new\n", __func__);
@@ -48,13 +49,15 @@ int test__syscall_open_tp_fields(void)
48 49
49 err = perf_evlist__open(evlist); 50 err = perf_evlist__open(evlist);
50 if (err < 0) { 51 if (err < 0) {
51 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 52 pr_debug("perf_evlist__open: %s\n",
53 strerror_r(errno, sbuf, sizeof(sbuf)));
52 goto out_delete_evlist; 54 goto out_delete_evlist;
53 } 55 }
54 56
55 err = perf_evlist__mmap(evlist, UINT_MAX, false); 57 err = perf_evlist__mmap(evlist, UINT_MAX, false);
56 if (err < 0) { 58 if (err < 0) {
57 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 59 pr_debug("perf_evlist__mmap: %s\n",
60 strerror_r(errno, sbuf, sizeof(sbuf)));
58 goto out_delete_evlist; 61 goto out_delete_evlist;
59 } 62 }
60 63
@@ -102,7 +105,7 @@ int test__syscall_open_tp_fields(void)
102 } 105 }
103 106
104 if (nr_events == before) 107 if (nr_events == before)
105 poll(evlist->pollfd, evlist->nr_fds, 10); 108 perf_evlist__poll(evlist, 10);
106 109
107 if (++nr_polls > 5) { 110 if (++nr_polls > 5) {
108 pr_debug("%s: no events!\n", __func__); 111 pr_debug("%s: no events!\n", __func__);
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c
index c1dc7d25f38c..a33b2daae40f 100644
--- a/tools/perf/tests/open-syscall.c
+++ b/tools/perf/tests/open-syscall.c
@@ -9,6 +9,7 @@ int test__open_syscall_event(void)
9 struct perf_evsel *evsel; 9 struct perf_evsel *evsel;
10 unsigned int nr_open_calls = 111, i; 10 unsigned int nr_open_calls = 111, i;
11 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); 11 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
12 char sbuf[STRERR_BUFSIZE];
12 13
13 if (threads == NULL) { 14 if (threads == NULL) {
14 pr_debug("thread_map__new\n"); 15 pr_debug("thread_map__new\n");
@@ -24,7 +25,7 @@ int test__open_syscall_event(void)
24 if (perf_evsel__open_per_thread(evsel, threads) < 0) { 25 if (perf_evsel__open_per_thread(evsel, threads) < 0) {
25 pr_debug("failed to open counter: %s, " 26 pr_debug("failed to open counter: %s, "
26 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 27 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
27 strerror(errno)); 28 strerror_r(errno, sbuf, sizeof(sbuf)));
28 goto out_evsel_delete; 29 goto out_evsel_delete;
29 } 30 }
30 31
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index aca1a83dd13a..7a228a2a070b 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -59,6 +59,7 @@ int test__PERF_RECORD(void)
59 int err = -1, errs = 0, i, wakeups = 0; 59 int err = -1, errs = 0, i, wakeups = 0;
60 u32 cpu; 60 u32 cpu;
61 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; 61 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
62 char sbuf[STRERR_BUFSIZE];
62 63
63 if (evlist == NULL || argv == NULL) { 64 if (evlist == NULL || argv == NULL) {
64 pr_debug("Not enough memory to create evlist\n"); 65 pr_debug("Not enough memory to create evlist\n");
@@ -100,7 +101,8 @@ int test__PERF_RECORD(void)
100 101
101 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); 102 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
102 if (err < 0) { 103 if (err < 0) {
103 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); 104 pr_debug("sched__get_first_possible_cpu: %s\n",
105 strerror_r(errno, sbuf, sizeof(sbuf)));
104 goto out_delete_evlist; 106 goto out_delete_evlist;
105 } 107 }
106 108
@@ -110,7 +112,8 @@ int test__PERF_RECORD(void)
110 * So that we can check perf_sample.cpu on all the samples. 112 * So that we can check perf_sample.cpu on all the samples.
111 */ 113 */
112 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { 114 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
113 pr_debug("sched_setaffinity: %s\n", strerror(errno)); 115 pr_debug("sched_setaffinity: %s\n",
116 strerror_r(errno, sbuf, sizeof(sbuf)));
114 goto out_delete_evlist; 117 goto out_delete_evlist;
115 } 118 }
116 119
@@ -120,7 +123,8 @@ int test__PERF_RECORD(void)
120 */ 123 */
121 err = perf_evlist__open(evlist); 124 err = perf_evlist__open(evlist);
122 if (err < 0) { 125 if (err < 0) {
123 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 126 pr_debug("perf_evlist__open: %s\n",
127 strerror_r(errno, sbuf, sizeof(sbuf)));
124 goto out_delete_evlist; 128 goto out_delete_evlist;
125 } 129 }
126 130
@@ -131,7 +135,8 @@ int test__PERF_RECORD(void)
131 */ 135 */
132 err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 136 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
133 if (err < 0) { 137 if (err < 0) {
134 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 138 pr_debug("perf_evlist__mmap: %s\n",
139 strerror_r(errno, sbuf, sizeof(sbuf)));
135 goto out_delete_evlist; 140 goto out_delete_evlist;
136 } 141 }
137 142
@@ -263,7 +268,7 @@ int test__PERF_RECORD(void)
263 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does. 268 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
264 */ 269 */
265 if (total_events == before && false) 270 if (total_events == before && false)
266 poll(evlist->pollfd, evlist->nr_fds, -1); 271 perf_evlist__poll(evlist, -1);
267 272
268 sleep(1); 273 sleep(1);
269 if (++wakeups > 5) { 274 if (++wakeups > 5) {
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index 12b322fa3475..eeb68bb1972d 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -152,7 +152,7 @@ int test__pmu(void)
152 if (ret) 152 if (ret)
153 break; 153 break;
154 154
155 ret = perf_pmu__config_terms(&formats, &attr, terms); 155 ret = perf_pmu__config_terms(&formats, &attr, terms, false);
156 if (ret) 156 if (ret)
157 break; 157 break;
158 158
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
index c04d1f268576..d31f2c4d9f64 100644
--- a/tools/perf/tests/rdpmc.c
+++ b/tools/perf/tests/rdpmc.c
@@ -100,6 +100,7 @@ static int __test__rdpmc(void)
100 }; 100 };
101 u64 delta_sum = 0; 101 u64 delta_sum = 0;
102 struct sigaction sa; 102 struct sigaction sa;
103 char sbuf[STRERR_BUFSIZE];
103 104
104 sigfillset(&sa.sa_mask); 105 sigfillset(&sa.sa_mask);
105 sa.sa_sigaction = segfault_handler; 106 sa.sa_sigaction = segfault_handler;
@@ -109,14 +110,15 @@ static int __test__rdpmc(void)
109 perf_event_open_cloexec_flag()); 110 perf_event_open_cloexec_flag());
110 if (fd < 0) { 111 if (fd < 0) {
111 pr_err("Error: sys_perf_event_open() syscall returned " 112 pr_err("Error: sys_perf_event_open() syscall returned "
112 "with %d (%s)\n", fd, strerror(errno)); 113 "with %d (%s)\n", fd,
114 strerror_r(errno, sbuf, sizeof(sbuf)));
113 return -1; 115 return -1;
114 } 116 }
115 117
116 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); 118 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
117 if (addr == (void *)(-1)) { 119 if (addr == (void *)(-1)) {
118 pr_err("Error: mmap() syscall returned with (%s)\n", 120 pr_err("Error: mmap() syscall returned with (%s)\n",
119 strerror(errno)); 121 strerror_r(errno, sbuf, sizeof(sbuf)));
120 goto out_close; 122 goto out_close;
121 } 123 }
122 124
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 983d6b8562a8..1aa21c90731b 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -22,6 +22,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
22 volatile int tmp = 0; 22 volatile int tmp = 0;
23 u64 total_periods = 0; 23 u64 total_periods = 0;
24 int nr_samples = 0; 24 int nr_samples = 0;
25 char sbuf[STRERR_BUFSIZE];
25 union perf_event *event; 26 union perf_event *event;
26 struct perf_evsel *evsel; 27 struct perf_evsel *evsel;
27 struct perf_evlist *evlist; 28 struct perf_evlist *evlist;
@@ -62,14 +63,15 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
62 63
63 err = -errno; 64 err = -errno;
64 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", 65 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
65 strerror(errno), knob, (u64)attr.sample_freq); 66 strerror_r(errno, sbuf, sizeof(sbuf)),
67 knob, (u64)attr.sample_freq);
66 goto out_delete_evlist; 68 goto out_delete_evlist;
67 } 69 }
68 70
69 err = perf_evlist__mmap(evlist, 128, true); 71 err = perf_evlist__mmap(evlist, 128, true);
70 if (err < 0) { 72 if (err < 0) {
71 pr_debug("failed to mmap event: %d (%s)\n", errno, 73 pr_debug("failed to mmap event: %d (%s)\n", errno,
72 strerror(errno)); 74 strerror_r(errno, sbuf, sizeof(sbuf)));
73 goto out_delete_evlist; 75 goto out_delete_evlist;
74 } 76 }
75 77
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
new file mode 100644
index 000000000000..cc68648c7c55
--- /dev/null
+++ b/tools/perf/tests/switch-tracking.c
@@ -0,0 +1,572 @@
1#include <sys/time.h>
2#include <sys/prctl.h>
3#include <time.h>
4#include <stdlib.h>
5
6#include "parse-events.h"
7#include "evlist.h"
8#include "evsel.h"
9#include "thread_map.h"
10#include "cpumap.h"
11#include "tests.h"
12
13static int spin_sleep(void)
14{
15 struct timeval start, now, diff, maxtime;
16 struct timespec ts;
17 int err, i;
18
19 maxtime.tv_sec = 0;
20 maxtime.tv_usec = 50000;
21
22 err = gettimeofday(&start, NULL);
23 if (err)
24 return err;
25
26 /* Spin for 50ms */
27 while (1) {
28 for (i = 0; i < 1000; i++)
29 barrier();
30
31 err = gettimeofday(&now, NULL);
32 if (err)
33 return err;
34
35 timersub(&now, &start, &diff);
36 if (timercmp(&diff, &maxtime, > /* For checkpatch */))
37 break;
38 }
39
40 ts.tv_nsec = 50 * 1000 * 1000;
41 ts.tv_sec = 0;
42
43 /* Sleep for 50ms */
44 err = nanosleep(&ts, NULL);
45 if (err == EINTR)
46 err = 0;
47
48 return err;
49}
50
51struct switch_tracking {
52 struct perf_evsel *switch_evsel;
53 struct perf_evsel *cycles_evsel;
54 pid_t *tids;
55 int nr_tids;
56 int comm_seen[4];
57 int cycles_before_comm_1;
58 int cycles_between_comm_2_and_comm_3;
59 int cycles_after_comm_4;
60};
61
62static int check_comm(struct switch_tracking *switch_tracking,
63 union perf_event *event, const char *comm, int nr)
64{
65 if (event->header.type == PERF_RECORD_COMM &&
66 (pid_t)event->comm.pid == getpid() &&
67 (pid_t)event->comm.tid == getpid() &&
68 strcmp(event->comm.comm, comm) == 0) {
69 if (switch_tracking->comm_seen[nr]) {
70 pr_debug("Duplicate comm event\n");
71 return -1;
72 }
73 switch_tracking->comm_seen[nr] = 1;
74 pr_debug3("comm event: %s nr: %d\n", event->comm.comm, nr);
75 return 1;
76 }
77 return 0;
78}
79
80static int check_cpu(struct switch_tracking *switch_tracking, int cpu)
81{
82 int i, nr = cpu + 1;
83
84 if (cpu < 0)
85 return -1;
86
87 if (!switch_tracking->tids) {
88 switch_tracking->tids = calloc(nr, sizeof(pid_t));
89 if (!switch_tracking->tids)
90 return -1;
91 for (i = 0; i < nr; i++)
92 switch_tracking->tids[i] = -1;
93 switch_tracking->nr_tids = nr;
94 return 0;
95 }
96
97 if (cpu >= switch_tracking->nr_tids) {
98 void *addr;
99
100 addr = realloc(switch_tracking->tids, nr * sizeof(pid_t));
101 if (!addr)
102 return -1;
103 switch_tracking->tids = addr;
104 for (i = switch_tracking->nr_tids; i < nr; i++)
105 switch_tracking->tids[i] = -1;
106 switch_tracking->nr_tids = nr;
107 return 0;
108 }
109
110 return 0;
111}
112
113static int process_sample_event(struct perf_evlist *evlist,
114 union perf_event *event,
115 struct switch_tracking *switch_tracking)
116{
117 struct perf_sample sample;
118 struct perf_evsel *evsel;
119 pid_t next_tid, prev_tid;
120 int cpu, err;
121
122 if (perf_evlist__parse_sample(evlist, event, &sample)) {
123 pr_debug("perf_evlist__parse_sample failed\n");
124 return -1;
125 }
126
127 evsel = perf_evlist__id2evsel(evlist, sample.id);
128 if (evsel == switch_tracking->switch_evsel) {
129 next_tid = perf_evsel__intval(evsel, &sample, "next_pid");
130 prev_tid = perf_evsel__intval(evsel, &sample, "prev_pid");
131 cpu = sample.cpu;
132 pr_debug3("sched_switch: cpu: %d prev_tid %d next_tid %d\n",
133 cpu, prev_tid, next_tid);
134 err = check_cpu(switch_tracking, cpu);
135 if (err)
136 return err;
137 /*
138 * Check for no missing sched_switch events i.e. that the
139 * evsel->system_wide flag has worked.
140 */
141 if (switch_tracking->tids[cpu] != -1 &&
142 switch_tracking->tids[cpu] != prev_tid) {
143 pr_debug("Missing sched_switch events\n");
144 return -1;
145 }
146 switch_tracking->tids[cpu] = next_tid;
147 }
148
149 if (evsel == switch_tracking->cycles_evsel) {
150 pr_debug3("cycles event\n");
151 if (!switch_tracking->comm_seen[0])
152 switch_tracking->cycles_before_comm_1 = 1;
153 if (switch_tracking->comm_seen[1] &&
154 !switch_tracking->comm_seen[2])
155 switch_tracking->cycles_between_comm_2_and_comm_3 = 1;
156 if (switch_tracking->comm_seen[3])
157 switch_tracking->cycles_after_comm_4 = 1;
158 }
159
160 return 0;
161}
162
163static int process_event(struct perf_evlist *evlist, union perf_event *event,
164 struct switch_tracking *switch_tracking)
165{
166 if (event->header.type == PERF_RECORD_SAMPLE)
167 return process_sample_event(evlist, event, switch_tracking);
168
169 if (event->header.type == PERF_RECORD_COMM) {
170 int err, done = 0;
171
172 err = check_comm(switch_tracking, event, "Test COMM 1", 0);
173 if (err < 0)
174 return -1;
175 done += err;
176 err = check_comm(switch_tracking, event, "Test COMM 2", 1);
177 if (err < 0)
178 return -1;
179 done += err;
180 err = check_comm(switch_tracking, event, "Test COMM 3", 2);
181 if (err < 0)
182 return -1;
183 done += err;
184 err = check_comm(switch_tracking, event, "Test COMM 4", 3);
185 if (err < 0)
186 return -1;
187 done += err;
188 if (done != 1) {
189 pr_debug("Unexpected comm event\n");
190 return -1;
191 }
192 }
193
194 return 0;
195}
196
197struct event_node {
198 struct list_head list;
199 union perf_event *event;
200 u64 event_time;
201};
202
203static int add_event(struct perf_evlist *evlist, struct list_head *events,
204 union perf_event *event)
205{
206 struct perf_sample sample;
207 struct event_node *node;
208
209 node = malloc(sizeof(struct event_node));
210 if (!node) {
211 pr_debug("malloc failed\n");
212 return -1;
213 }
214 node->event = event;
215 list_add(&node->list, events);
216
217 if (perf_evlist__parse_sample(evlist, event, &sample)) {
218 pr_debug("perf_evlist__parse_sample failed\n");
219 return -1;
220 }
221
222 if (!sample.time) {
223 pr_debug("event with no time\n");
224 return -1;
225 }
226
227 node->event_time = sample.time;
228
229 return 0;
230}
231
232static void free_event_nodes(struct list_head *events)
233{
234 struct event_node *node;
235
236 while (!list_empty(events)) {
237 node = list_entry(events->next, struct event_node, list);
238 list_del(&node->list);
239 free(node);
240 }
241}
242
243static int compar(const void *a, const void *b)
244{
245 const struct event_node *nodea = a;
246 const struct event_node *nodeb = b;
247 s64 cmp = nodea->event_time - nodeb->event_time;
248
249 return cmp;
250}
251
252static int process_events(struct perf_evlist *evlist,
253 struct switch_tracking *switch_tracking)
254{
255 union perf_event *event;
256 unsigned pos, cnt = 0;
257 LIST_HEAD(events);
258 struct event_node *events_array, *node;
259 int i, ret;
260
261 for (i = 0; i < evlist->nr_mmaps; i++) {
262 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
263 cnt += 1;
264 ret = add_event(evlist, &events, event);
265 perf_evlist__mmap_consume(evlist, i);
266 if (ret < 0)
267 goto out_free_nodes;
268 }
269 }
270
271 events_array = calloc(cnt, sizeof(struct event_node));
272 if (!events_array) {
273 pr_debug("calloc failed\n");
274 ret = -1;
275 goto out_free_nodes;
276 }
277
278 pos = 0;
279 list_for_each_entry(node, &events, list)
280 events_array[pos++] = *node;
281
282 qsort(events_array, cnt, sizeof(struct event_node), compar);
283
284 for (pos = 0; pos < cnt; pos++) {
285 ret = process_event(evlist, events_array[pos].event,
286 switch_tracking);
287 if (ret < 0)
288 goto out_free;
289 }
290
291 ret = 0;
292out_free:
293 pr_debug("%u events recorded\n", cnt);
294 free(events_array);
295out_free_nodes:
296 free_event_nodes(&events);
297 return ret;
298}
299
300/**
301 * test__switch_tracking - test using sched_switch and tracking events.
302 *
303 * This function implements a test that checks that sched_switch events and
304 * tracking events can be recorded for a workload (current process) using the
305 * evsel->system_wide and evsel->tracking flags (respectively) with other events
306 * sometimes enabled or disabled.
307 */
308int test__switch_tracking(void)
309{
310 const char *sched_switch = "sched:sched_switch";
311 struct switch_tracking switch_tracking = { .tids = NULL, };
312 struct record_opts opts = {
313 .mmap_pages = UINT_MAX,
314 .user_freq = UINT_MAX,
315 .user_interval = ULLONG_MAX,
316 .freq = 4000,
317 .target = {
318 .uses_mmap = true,
319 },
320 };
321 struct thread_map *threads = NULL;
322 struct cpu_map *cpus = NULL;
323 struct perf_evlist *evlist = NULL;
324 struct perf_evsel *evsel, *cpu_clocks_evsel, *cycles_evsel;
325 struct perf_evsel *switch_evsel, *tracking_evsel;
326 const char *comm;
327 int err = -1;
328
329 threads = thread_map__new(-1, getpid(), UINT_MAX);
330 if (!threads) {
331 pr_debug("thread_map__new failed!\n");
332 goto out_err;
333 }
334
335 cpus = cpu_map__new(NULL);
336 if (!cpus) {
337 pr_debug("cpu_map__new failed!\n");
338 goto out_err;
339 }
340
341 evlist = perf_evlist__new();
342 if (!evlist) {
343 pr_debug("perf_evlist__new failed!\n");
344 goto out_err;
345 }
346
347 perf_evlist__set_maps(evlist, cpus, threads);
348
349 /* First event */
350 err = parse_events(evlist, "cpu-clock:u");
351 if (err) {
352 pr_debug("Failed to parse event dummy:u\n");
353 goto out_err;
354 }
355
356 cpu_clocks_evsel = perf_evlist__last(evlist);
357
358 /* Second event */
359 err = parse_events(evlist, "cycles:u");
360 if (err) {
361 pr_debug("Failed to parse event cycles:u\n");
362 goto out_err;
363 }
364
365 cycles_evsel = perf_evlist__last(evlist);
366
367 /* Third event */
368 if (!perf_evlist__can_select_event(evlist, sched_switch)) {
369 fprintf(stderr, " (no sched_switch)");
370 err = 0;
371 goto out;
372 }
373
374 err = parse_events(evlist, sched_switch);
375 if (err) {
376 pr_debug("Failed to parse event %s\n", sched_switch);
377 goto out_err;
378 }
379
380 switch_evsel = perf_evlist__last(evlist);
381
382 perf_evsel__set_sample_bit(switch_evsel, CPU);
383 perf_evsel__set_sample_bit(switch_evsel, TIME);
384
385 switch_evsel->system_wide = true;
386 switch_evsel->no_aux_samples = true;
387 switch_evsel->immediate = true;
388
389 /* Test moving an event to the front */
390 if (cycles_evsel == perf_evlist__first(evlist)) {
391 pr_debug("cycles event already at front");
392 goto out_err;
393 }
394 perf_evlist__to_front(evlist, cycles_evsel);
395 if (cycles_evsel != perf_evlist__first(evlist)) {
396 pr_debug("Failed to move cycles event to front");
397 goto out_err;
398 }
399
400 perf_evsel__set_sample_bit(cycles_evsel, CPU);
401 perf_evsel__set_sample_bit(cycles_evsel, TIME);
402
403 /* Fourth event */
404 err = parse_events(evlist, "dummy:u");
405 if (err) {
406 pr_debug("Failed to parse event dummy:u\n");
407 goto out_err;
408 }
409
410 tracking_evsel = perf_evlist__last(evlist);
411
412 perf_evlist__set_tracking_event(evlist, tracking_evsel);
413
414 tracking_evsel->attr.freq = 0;
415 tracking_evsel->attr.sample_period = 1;
416
417 perf_evsel__set_sample_bit(tracking_evsel, TIME);
418
419 /* Config events */
420 perf_evlist__config(evlist, &opts);
421
422 /* Check moved event is still at the front */
423 if (cycles_evsel != perf_evlist__first(evlist)) {
424 pr_debug("Front event no longer at front");
425 goto out_err;
426 }
427
428 /* Check tracking event is tracking */
429 if (!tracking_evsel->attr.mmap || !tracking_evsel->attr.comm) {
430 pr_debug("Tracking event not tracking\n");
431 goto out_err;
432 }
433
434 /* Check non-tracking events are not tracking */
435 evlist__for_each(evlist, evsel) {
436 if (evsel != tracking_evsel) {
437 if (evsel->attr.mmap || evsel->attr.comm) {
438 pr_debug("Non-tracking event is tracking\n");
439 goto out_err;
440 }
441 }
442 }
443
444 if (perf_evlist__open(evlist) < 0) {
445 fprintf(stderr, " (not supported)");
446 err = 0;
447 goto out;
448 }
449
450 err = perf_evlist__mmap(evlist, UINT_MAX, false);
451 if (err) {
452 pr_debug("perf_evlist__mmap failed!\n");
453 goto out_err;
454 }
455
456 perf_evlist__enable(evlist);
457
458 err = perf_evlist__disable_event(evlist, cpu_clocks_evsel);
459 if (err) {
460 pr_debug("perf_evlist__disable_event failed!\n");
461 goto out_err;
462 }
463
464 err = spin_sleep();
465 if (err) {
466 pr_debug("spin_sleep failed!\n");
467 goto out_err;
468 }
469
470 comm = "Test COMM 1";
471 err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
472 if (err) {
473 pr_debug("PR_SET_NAME failed!\n");
474 goto out_err;
475 }
476
477 err = perf_evlist__disable_event(evlist, cycles_evsel);
478 if (err) {
479 pr_debug("perf_evlist__disable_event failed!\n");
480 goto out_err;
481 }
482
483 comm = "Test COMM 2";
484 err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
485 if (err) {
486 pr_debug("PR_SET_NAME failed!\n");
487 goto out_err;
488 }
489
490 err = spin_sleep();
491 if (err) {
492 pr_debug("spin_sleep failed!\n");
493 goto out_err;
494 }
495
496 comm = "Test COMM 3";
497 err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
498 if (err) {
499 pr_debug("PR_SET_NAME failed!\n");
500 goto out_err;
501 }
502
503 err = perf_evlist__enable_event(evlist, cycles_evsel);
504 if (err) {
505 pr_debug("perf_evlist__disable_event failed!\n");
506 goto out_err;
507 }
508
509 comm = "Test COMM 4";
510 err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0);
511 if (err) {
512 pr_debug("PR_SET_NAME failed!\n");
513 goto out_err;
514 }
515
516 err = spin_sleep();
517 if (err) {
518 pr_debug("spin_sleep failed!\n");
519 goto out_err;
520 }
521
522 perf_evlist__disable(evlist);
523
524 switch_tracking.switch_evsel = switch_evsel;
525 switch_tracking.cycles_evsel = cycles_evsel;
526
527 err = process_events(evlist, &switch_tracking);
528
529 zfree(&switch_tracking.tids);
530
531 if (err)
532 goto out_err;
533
534 /* Check all 4 comm events were seen i.e. that evsel->tracking works */
535 if (!switch_tracking.comm_seen[0] || !switch_tracking.comm_seen[1] ||
536 !switch_tracking.comm_seen[2] || !switch_tracking.comm_seen[3]) {
537 pr_debug("Missing comm events\n");
538 goto out_err;
539 }
540
541 /* Check cycles event got enabled */
542 if (!switch_tracking.cycles_before_comm_1) {
543 pr_debug("Missing cycles events\n");
544 goto out_err;
545 }
546
547 /* Check cycles event got disabled */
548 if (switch_tracking.cycles_between_comm_2_and_comm_3) {
549 pr_debug("cycles events even though event was disabled\n");
550 goto out_err;
551 }
552
553 /* Check cycles event got enabled again */
554 if (!switch_tracking.cycles_after_comm_4) {
555 pr_debug("Missing cycles events\n");
556 goto out_err;
557 }
558out:
559 if (evlist) {
560 perf_evlist__disable(evlist);
561 perf_evlist__delete(evlist);
562 } else {
563 cpu_map__delete(cpus);
564 thread_map__delete(threads);
565 }
566
567 return err;
568
569out_err:
570 err = -1;
571 goto out;
572}
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index 5ff3db318f12..3a8fedef83bc 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -42,6 +42,7 @@ int test__task_exit(void)
42 .uses_mmap = true, 42 .uses_mmap = true,
43 }; 43 };
44 const char *argv[] = { "true", NULL }; 44 const char *argv[] = { "true", NULL };
45 char sbuf[STRERR_BUFSIZE];
45 46
46 signal(SIGCHLD, sig_handler); 47 signal(SIGCHLD, sig_handler);
47 48
@@ -82,13 +83,14 @@ int test__task_exit(void)
82 83
83 err = perf_evlist__open(evlist); 84 err = perf_evlist__open(evlist);
84 if (err < 0) { 85 if (err < 0) {
85 pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); 86 pr_debug("Couldn't open the evlist: %s\n",
87 strerror_r(-err, sbuf, sizeof(sbuf)));
86 goto out_delete_evlist; 88 goto out_delete_evlist;
87 } 89 }
88 90
89 if (perf_evlist__mmap(evlist, 128, true) < 0) { 91 if (perf_evlist__mmap(evlist, 128, true) < 0) {
90 pr_debug("failed to mmap events: %d (%s)\n", errno, 92 pr_debug("failed to mmap events: %d (%s)\n", errno,
91 strerror(errno)); 93 strerror_r(errno, sbuf, sizeof(sbuf)));
92 goto out_delete_evlist; 94 goto out_delete_evlist;
93 } 95 }
94 96
@@ -103,7 +105,7 @@ retry:
103 } 105 }
104 106
105 if (!exited || !nr_exit) { 107 if (!exited || !nr_exit) {
106 poll(evlist->pollfd, evlist->nr_fds, -1); 108 perf_evlist__poll(evlist, -1);
107 goto retry; 109 goto retry;
108 } 110 }
109 111
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index ed64790a395f..00e776a87a9c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -48,6 +48,9 @@ int test__mmap_thread_lookup(void);
48int test__thread_mg_share(void); 48int test__thread_mg_share(void);
49int test__hists_output(void); 49int test__hists_output(void);
50int test__hists_cumulate(void); 50int test__hists_cumulate(void);
51int test__switch_tracking(void);
52int test__fdarray__filter(void);
53int test__fdarray__add(void);
51 54
52#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) 55#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
53#ifdef HAVE_DWARF_UNWIND_SUPPORT 56#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a94b11fc5e00..8f60a970404f 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -10,6 +10,7 @@
10#include "../../util/pstack.h" 10#include "../../util/pstack.h"
11#include "../../util/sort.h" 11#include "../../util/sort.h"
12#include "../../util/util.h" 12#include "../../util/util.h"
13#include "../../util/top.h"
13#include "../../arch/common.h" 14#include "../../arch/common.h"
14 15
15#include "../browser.h" 16#include "../browser.h"
@@ -228,8 +229,10 @@ static void callchain_node__init_have_children(struct callchain_node *node)
228{ 229{
229 struct callchain_list *chain; 230 struct callchain_list *chain;
230 231
231 list_for_each_entry(chain, &node->val, list) 232 if (!list_empty(&node->val)) {
233 chain = list_entry(node->val.prev, struct callchain_list, list);
232 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); 234 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
235 }
233 236
234 callchain_node__init_have_children_rb_tree(node); 237 callchain_node__init_have_children_rb_tree(node);
235} 238}
@@ -474,26 +477,87 @@ static char *callchain_list__sym_name(struct callchain_list *cl,
474 return bf; 477 return bf;
475} 478}
476 479
480struct callchain_print_arg {
481 /* for hists browser */
482 off_t row_offset;
483 bool is_current_entry;
484
485 /* for file dump */
486 FILE *fp;
487 int printed;
488};
489
490typedef void (*print_callchain_entry_fn)(struct hist_browser *browser,
491 struct callchain_list *chain,
492 const char *str, int offset,
493 unsigned short row,
494 struct callchain_print_arg *arg);
495
496static void hist_browser__show_callchain_entry(struct hist_browser *browser,
497 struct callchain_list *chain,
498 const char *str, int offset,
499 unsigned short row,
500 struct callchain_print_arg *arg)
501{
502 int color, width;
503 char folded_sign = callchain_list__folded(chain);
504
505 color = HE_COLORSET_NORMAL;
506 width = browser->b.width - (offset + 2);
507 if (ui_browser__is_current_entry(&browser->b, row)) {
508 browser->selection = &chain->ms;
509 color = HE_COLORSET_SELECTED;
510 arg->is_current_entry = true;
511 }
512
513 ui_browser__set_color(&browser->b, color);
514 hist_browser__gotorc(browser, row, 0);
515 slsmg_write_nstring(" ", offset);
516 slsmg_printf("%c ", folded_sign);
517 slsmg_write_nstring(str, width);
518}
519
520static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused,
521 struct callchain_list *chain,
522 const char *str, int offset,
523 unsigned short row __maybe_unused,
524 struct callchain_print_arg *arg)
525{
526 char folded_sign = callchain_list__folded(chain);
527
528 arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ",
529 folded_sign, str);
530}
531
532typedef bool (*check_output_full_fn)(struct hist_browser *browser,
533 unsigned short row);
534
535static bool hist_browser__check_output_full(struct hist_browser *browser,
536 unsigned short row)
537{
538 return browser->b.rows == row;
539}
540
541static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused,
542 unsigned short row __maybe_unused)
543{
544 return false;
545}
546
477#define LEVEL_OFFSET_STEP 3 547#define LEVEL_OFFSET_STEP 3
478 548
479static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser, 549static int hist_browser__show_callchain(struct hist_browser *browser,
480 struct callchain_node *chain_node, 550 struct rb_root *root, int level,
481 u64 total, int level, 551 unsigned short row, u64 total,
482 unsigned short row, 552 print_callchain_entry_fn print,
483 off_t *row_offset, 553 struct callchain_print_arg *arg,
484 bool *is_current_entry) 554 check_output_full_fn is_output_full)
485{ 555{
486 struct rb_node *node; 556 struct rb_node *node;
487 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; 557 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
488 u64 new_total, remaining; 558 u64 new_total;
489 559
490 if (callchain_param.mode == CHAIN_GRAPH_REL) 560 node = rb_first(root);
491 new_total = chain_node->children_hit;
492 else
493 new_total = total;
494
495 remaining = new_total;
496 node = rb_first(&chain_node->rb_root);
497 while (node) { 561 while (node) {
498 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 562 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
499 struct rb_node *next = rb_next(node); 563 struct rb_node *next = rb_next(node);
@@ -503,30 +567,28 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
503 int first = true; 567 int first = true;
504 int extra_offset = 0; 568 int extra_offset = 0;
505 569
506 remaining -= cumul;
507
508 list_for_each_entry(chain, &child->val, list) { 570 list_for_each_entry(chain, &child->val, list) {
509 char bf[1024], *alloc_str; 571 char bf[1024], *alloc_str;
510 const char *str; 572 const char *str;
511 int color;
512 bool was_first = first; 573 bool was_first = first;
513 574
514 if (first) 575 if (first)
515 first = false; 576 first = false;
516 else 577 else if (level > 1)
517 extra_offset = LEVEL_OFFSET_STEP; 578 extra_offset = LEVEL_OFFSET_STEP;
518 579
519 folded_sign = callchain_list__folded(chain); 580 folded_sign = callchain_list__folded(chain);
520 if (*row_offset != 0) { 581 if (arg->row_offset != 0) {
521 --*row_offset; 582 arg->row_offset--;
522 goto do_next; 583 goto do_next;
523 } 584 }
524 585
525 alloc_str = NULL; 586 alloc_str = NULL;
526 str = callchain_list__sym_name(chain, bf, sizeof(bf), 587 str = callchain_list__sym_name(chain, bf, sizeof(bf),
527 browser->show_dso); 588 browser->show_dso);
528 if (was_first) { 589
529 double percent = cumul * 100.0 / new_total; 590 if (was_first && level > 1) {
591 double percent = cumul * 100.0 / total;
530 592
531 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 593 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
532 str = "Not enough memory!"; 594 str = "Not enough memory!";
@@ -534,22 +596,11 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse
534 str = alloc_str; 596 str = alloc_str;
535 } 597 }
536 598
537 color = HE_COLORSET_NORMAL; 599 print(browser, chain, str, offset + extra_offset, row, arg);
538 width = browser->b.width - (offset + extra_offset + 2);
539 if (ui_browser__is_current_entry(&browser->b, row)) {
540 browser->selection = &chain->ms;
541 color = HE_COLORSET_SELECTED;
542 *is_current_entry = true;
543 }
544 600
545 ui_browser__set_color(&browser->b, color);
546 hist_browser__gotorc(browser, row, 0);
547 slsmg_write_nstring(" ", offset + extra_offset);
548 slsmg_printf("%c ", folded_sign);
549 slsmg_write_nstring(str, width);
550 free(alloc_str); 601 free(alloc_str);
551 602
552 if (++row == browser->b.rows) 603 if (is_output_full(browser, ++row))
553 goto out; 604 goto out;
554do_next: 605do_next:
555 if (folded_sign == '+') 606 if (folded_sign == '+')
@@ -558,89 +609,21 @@ do_next:
558 609
559 if (folded_sign == '-') { 610 if (folded_sign == '-') {
560 const int new_level = level + (extra_offset ? 2 : 1); 611 const int new_level = level + (extra_offset ? 2 : 1);
561 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
562 new_level, row, row_offset,
563 is_current_entry);
564 }
565 if (row == browser->b.rows)
566 goto out;
567 node = next;
568 }
569out:
570 return row - first_row;
571}
572
573static int hist_browser__show_callchain_node(struct hist_browser *browser,
574 struct callchain_node *node,
575 int level, unsigned short row,
576 off_t *row_offset,
577 bool *is_current_entry)
578{
579 struct callchain_list *chain;
580 int first_row = row,
581 offset = level * LEVEL_OFFSET_STEP,
582 width = browser->b.width - offset;
583 char folded_sign = ' ';
584 612
585 list_for_each_entry(chain, &node->val, list) { 613 if (callchain_param.mode == CHAIN_GRAPH_REL)
586 char bf[1024], *s; 614 new_total = child->children_hit;
587 int color; 615 else
588 616 new_total = total;
589 folded_sign = callchain_list__folded(chain);
590
591 if (*row_offset != 0) {
592 --*row_offset;
593 continue;
594 }
595 617
596 color = HE_COLORSET_NORMAL; 618 row += hist_browser__show_callchain(browser, &child->rb_root,
597 if (ui_browser__is_current_entry(&browser->b, row)) { 619 new_level, row, new_total,
598 browser->selection = &chain->ms; 620 print, arg, is_output_full);
599 color = HE_COLORSET_SELECTED;
600 *is_current_entry = true;
601 } 621 }
602 622 if (is_output_full(browser, row))
603 s = callchain_list__sym_name(chain, bf, sizeof(bf),
604 browser->show_dso);
605 hist_browser__gotorc(browser, row, 0);
606 ui_browser__set_color(&browser->b, color);
607 slsmg_write_nstring(" ", offset);
608 slsmg_printf("%c ", folded_sign);
609 slsmg_write_nstring(s, width - 2);
610
611 if (++row == browser->b.rows)
612 goto out;
613 }
614
615 if (folded_sign == '-')
616 row += hist_browser__show_callchain_node_rb_tree(browser, node,
617 browser->hists->stats.total_period,
618 level + 1, row,
619 row_offset,
620 is_current_entry);
621out:
622 return row - first_row;
623}
624
625static int hist_browser__show_callchain(struct hist_browser *browser,
626 struct rb_root *chain,
627 int level, unsigned short row,
628 off_t *row_offset,
629 bool *is_current_entry)
630{
631 struct rb_node *nd;
632 int first_row = row;
633
634 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
635 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
636
637 row += hist_browser__show_callchain_node(browser, node, level,
638 row, row_offset,
639 is_current_entry);
640 if (row == browser->b.rows)
641 break; 623 break;
624 node = next;
642 } 625 }
643 626out:
644 return row - first_row; 627 return row - first_row;
645} 628}
646 629
@@ -653,17 +636,18 @@ struct hpp_arg {
653static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 636static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
654{ 637{
655 struct hpp_arg *arg = hpp->ptr; 638 struct hpp_arg *arg = hpp->ptr;
656 int ret; 639 int ret, len;
657 va_list args; 640 va_list args;
658 double percent; 641 double percent;
659 642
660 va_start(args, fmt); 643 va_start(args, fmt);
644 len = va_arg(args, int);
661 percent = va_arg(args, double); 645 percent = va_arg(args, double);
662 va_end(args); 646 va_end(args);
663 647
664 ui_browser__set_percent_color(arg->b, percent, arg->current_entry); 648 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
665 649
666 ret = scnprintf(hpp->buf, hpp->size, fmt, percent); 650 ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
667 slsmg_printf("%s", hpp->buf); 651 slsmg_printf("%s", hpp->buf);
668 652
669 advance_hpp(hpp, ret); 653 advance_hpp(hpp, ret);
@@ -677,12 +661,12 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \
677} \ 661} \
678 \ 662 \
679static int \ 663static int \
680hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ 664hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
681 struct perf_hpp *hpp, \ 665 struct perf_hpp *hpp, \
682 struct hist_entry *he) \ 666 struct hist_entry *he) \
683{ \ 667{ \
684 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \ 668 return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \
685 __hpp__slsmg_color_printf, true); \ 669 __hpp__slsmg_color_printf, true); \
686} 670}
687 671
688#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 672#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
@@ -692,18 +676,20 @@ static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
692} \ 676} \
693 \ 677 \
694static int \ 678static int \
695hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ 679hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
696 struct perf_hpp *hpp, \ 680 struct perf_hpp *hpp, \
697 struct hist_entry *he) \ 681 struct hist_entry *he) \
698{ \ 682{ \
699 if (!symbol_conf.cumulate_callchain) { \ 683 if (!symbol_conf.cumulate_callchain) { \
700 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \ 684 int len = fmt->user_len ?: fmt->len; \
685 int ret = scnprintf(hpp->buf, hpp->size, \
686 "%*s", len, "N/A"); \
701 slsmg_printf("%s", hpp->buf); \ 687 slsmg_printf("%s", hpp->buf); \
702 \ 688 \
703 return ret; \ 689 return ret; \
704 } \ 690 } \
705 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \ 691 return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \
706 __hpp__slsmg_color_printf, true); \ 692 " %*.2f%%", __hpp__slsmg_color_printf, true); \
707} 693}
708 694
709__HPP_COLOR_PERCENT_FN(overhead, period) 695__HPP_COLOR_PERCENT_FN(overhead, period)
@@ -812,10 +798,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
812 --row_offset; 798 --row_offset;
813 799
814 if (folded_sign == '-' && row != browser->b.rows) { 800 if (folded_sign == '-' && row != browser->b.rows) {
815 printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 801 u64 total = hists__total_period(entry->hists);
816 1, row, &row_offset, 802 struct callchain_print_arg arg = {
817 &current_entry); 803 .row_offset = row_offset,
818 if (current_entry) 804 .is_current_entry = current_entry,
805 };
806
807 printed += hist_browser__show_callchain(browser,
808 &entry->sorted_chain, 1, row, total,
809 hist_browser__show_callchain_entry, &arg,
810 hist_browser__check_output_full);
811
812 if (arg.is_current_entry)
819 browser->he_selection = entry; 813 browser->he_selection = entry;
820 } 814 }
821 815
@@ -847,9 +841,6 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
847 if (perf_hpp__should_skip(fmt)) 841 if (perf_hpp__should_skip(fmt))
848 continue; 842 continue;
849 843
850 /* We need to add the length of the columns header. */
851 perf_hpp__reset_width(fmt, hists);
852
853 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 844 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
854 if (advance_hpp_check(&dummy_hpp, ret)) 845 if (advance_hpp_check(&dummy_hpp, ret))
855 break; 846 break;
@@ -1074,113 +1065,21 @@ do_offset:
1074 } 1065 }
1075} 1066}
1076 1067
1077static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
1078 struct callchain_node *chain_node,
1079 u64 total, int level,
1080 FILE *fp)
1081{
1082 struct rb_node *node;
1083 int offset = level * LEVEL_OFFSET_STEP;
1084 u64 new_total, remaining;
1085 int printed = 0;
1086
1087 if (callchain_param.mode == CHAIN_GRAPH_REL)
1088 new_total = chain_node->children_hit;
1089 else
1090 new_total = total;
1091
1092 remaining = new_total;
1093 node = rb_first(&chain_node->rb_root);
1094 while (node) {
1095 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1096 struct rb_node *next = rb_next(node);
1097 u64 cumul = callchain_cumul_hits(child);
1098 struct callchain_list *chain;
1099 char folded_sign = ' ';
1100 int first = true;
1101 int extra_offset = 0;
1102
1103 remaining -= cumul;
1104
1105 list_for_each_entry(chain, &child->val, list) {
1106 char bf[1024], *alloc_str;
1107 const char *str;
1108 bool was_first = first;
1109
1110 if (first)
1111 first = false;
1112 else
1113 extra_offset = LEVEL_OFFSET_STEP;
1114
1115 folded_sign = callchain_list__folded(chain);
1116
1117 alloc_str = NULL;
1118 str = callchain_list__sym_name(chain, bf, sizeof(bf),
1119 browser->show_dso);
1120 if (was_first) {
1121 double percent = cumul * 100.0 / new_total;
1122
1123 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
1124 str = "Not enough memory!";
1125 else
1126 str = alloc_str;
1127 }
1128
1129 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
1130 free(alloc_str);
1131 if (folded_sign == '+')
1132 break;
1133 }
1134
1135 if (folded_sign == '-') {
1136 const int new_level = level + (extra_offset ? 2 : 1);
1137 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
1138 new_level, fp);
1139 }
1140
1141 node = next;
1142 }
1143
1144 return printed;
1145}
1146
1147static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
1148 struct callchain_node *node,
1149 int level, FILE *fp)
1150{
1151 struct callchain_list *chain;
1152 int offset = level * LEVEL_OFFSET_STEP;
1153 char folded_sign = ' ';
1154 int printed = 0;
1155
1156 list_for_each_entry(chain, &node->val, list) {
1157 char bf[1024], *s;
1158
1159 folded_sign = callchain_list__folded(chain);
1160 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
1161 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
1162 }
1163
1164 if (folded_sign == '-')
1165 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
1166 browser->hists->stats.total_period,
1167 level + 1, fp);
1168 return printed;
1169}
1170
1171static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1068static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1172 struct rb_root *chain, int level, FILE *fp) 1069 struct hist_entry *he, FILE *fp)
1173{ 1070{
1174 struct rb_node *nd; 1071 u64 total = hists__total_period(he->hists);
1175 int printed = 0; 1072 struct callchain_print_arg arg = {
1073 .fp = fp,
1074 };
1176 1075
1177 for (nd = rb_first(chain); nd; nd = rb_next(nd)) { 1076 if (symbol_conf.cumulate_callchain)
1178 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 1077 total = he->stat_acc->period;
1179 1078
1180 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); 1079 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1181 } 1080 hist_browser__fprintf_callchain_entry, &arg,
1182 1081 hist_browser__check_dump_full);
1183 return printed; 1082 return arg.printed;
1184} 1083}
1185 1084
1186static int hist_browser__fprintf_entry(struct hist_browser *browser, 1085static int hist_browser__fprintf_entry(struct hist_browser *browser,
@@ -1219,7 +1118,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1219 printed += fprintf(fp, "%s\n", rtrim(s)); 1118 printed += fprintf(fp, "%s\n", rtrim(s));
1220 1119
1221 if (folded_sign == '-') 1120 if (folded_sign == '-')
1222 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); 1121 printed += hist_browser__fprintf_callchain(browser, he, fp);
1223 1122
1224 return printed; 1123 return printed;
1225} 1124}
@@ -1498,6 +1397,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1498 char buf[64]; 1397 char buf[64];
1499 char script_opt[64]; 1398 char script_opt[64];
1500 int delay_secs = hbt ? hbt->refresh : 0; 1399 int delay_secs = hbt ? hbt->refresh : 0;
1400 struct perf_hpp_fmt *fmt;
1501 1401
1502#define HIST_BROWSER_HELP_COMMON \ 1402#define HIST_BROWSER_HELP_COMMON \
1503 "h/?/F1 Show this window\n" \ 1403 "h/?/F1 Show this window\n" \
@@ -1529,6 +1429,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1529 "P Print histograms to perf.hist.N\n" 1429 "P Print histograms to perf.hist.N\n"
1530 "t Zoom into current Thread\n" 1430 "t Zoom into current Thread\n"
1531 "V Verbose (DSO names in callchains, etc)\n" 1431 "V Verbose (DSO names in callchains, etc)\n"
1432 "z Toggle zeroing of samples\n"
1532 "/ Filter symbol by name"; 1433 "/ Filter symbol by name";
1533 1434
1534 if (browser == NULL) 1435 if (browser == NULL)
@@ -1547,6 +1448,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1547 1448
1548 memset(options, 0, sizeof(options)); 1449 memset(options, 0, sizeof(options));
1549 1450
1451 perf_hpp__for_each_format(fmt)
1452 perf_hpp__reset_width(fmt, hists);
1453
1454 if (symbol_conf.col_width_list_str)
1455 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
1456
1550 while (1) { 1457 while (1) {
1551 const struct thread *thread = NULL; 1458 const struct thread *thread = NULL;
1552 const struct dso *dso = NULL; 1459 const struct dso *dso = NULL;
@@ -1623,6 +1530,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1623 case 'F': 1530 case 'F':
1624 symbol_conf.filter_relative ^= 1; 1531 symbol_conf.filter_relative ^= 1;
1625 continue; 1532 continue;
1533 case 'z':
1534 if (!is_report_browser(hbt)) {
1535 struct perf_top *top = hbt->arg;
1536
1537 top->zero = !top->zero;
1538 }
1539 continue;
1626 case K_F1: 1540 case K_F1:
1627 case 'h': 1541 case 'h':
1628 case '?': 1542 case '?':
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 6ca60e482cdc..f3fa4258b256 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -11,6 +11,7 @@
11static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) 11static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
12{ 12{
13 int ret = 0; 13 int ret = 0;
14 int len;
14 va_list args; 15 va_list args;
15 double percent; 16 double percent;
16 const char *markup; 17 const char *markup;
@@ -18,6 +19,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
18 size_t size = hpp->size; 19 size_t size = hpp->size;
19 20
20 va_start(args, fmt); 21 va_start(args, fmt);
22 len = va_arg(args, int);
21 percent = va_arg(args, double); 23 percent = va_arg(args, double);
22 va_end(args); 24 va_end(args);
23 25
@@ -25,7 +27,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
25 if (markup) 27 if (markup)
26 ret += scnprintf(buf, size, markup); 28 ret += scnprintf(buf, size, markup);
27 29
28 ret += scnprintf(buf + ret, size - ret, fmt, percent); 30 ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
29 31
30 if (markup) 32 if (markup)
31 ret += scnprintf(buf + ret, size - ret, "</span>"); 33 ret += scnprintf(buf + ret, size - ret, "</span>");
@@ -39,12 +41,12 @@ static u64 he_get_##_field(struct hist_entry *he) \
39 return he->stat._field; \ 41 return he->stat._field; \
40} \ 42} \
41 \ 43 \
42static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 44static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
43 struct perf_hpp *hpp, \ 45 struct perf_hpp *hpp, \
44 struct hist_entry *he) \ 46 struct hist_entry *he) \
45{ \ 47{ \
46 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ 48 return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \
47 __percent_color_snprintf, true); \ 49 __percent_color_snprintf, true); \
48} 50}
49 51
50#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 52#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
@@ -57,8 +59,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
57 struct perf_hpp *hpp, \ 59 struct perf_hpp *hpp, \
58 struct hist_entry *he) \ 60 struct hist_entry *he) \
59{ \ 61{ \
60 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ 62 return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \
61 __percent_color_snprintf, true); \ 63 __percent_color_snprintf, true); \
62} 64}
63 65
64__HPP_COLOR_PERCENT_FN(overhead, period) 66__HPP_COLOR_PERCENT_FN(overhead, period)
@@ -205,10 +207,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
205 if (perf_hpp__is_sort_entry(fmt)) 207 if (perf_hpp__is_sort_entry(fmt))
206 sym_col = col_idx; 208 sym_col = col_idx;
207 209
208 fmt->header(fmt, &hpp, hists_to_evsel(hists));
209
210 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 210 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
211 -1, ltrim(s), 211 -1, fmt->name,
212 renderer, "markup", 212 renderer, "markup",
213 col_idx++, NULL); 213 col_idx++, NULL);
214 } 214 }
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 498adb23c02e..2af18376b077 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -15,9 +15,9 @@
15 __ret; \ 15 __ret; \
16}) 16})
17 17
18int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 18static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
19 hpp_field_fn get_field, const char *fmt, 19 hpp_field_fn get_field, const char *fmt, int len,
20 hpp_snprint_fn print_fn, bool fmt_percent) 20 hpp_snprint_fn print_fn, bool fmt_percent)
21{ 21{
22 int ret; 22 int ret;
23 struct hists *hists = he->hists; 23 struct hists *hists = he->hists;
@@ -32,9 +32,9 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
32 if (total) 32 if (total)
33 percent = 100.0 * get_field(he) / total; 33 percent = 100.0 * get_field(he) / total;
34 34
35 ret = hpp__call_print_fn(hpp, print_fn, fmt, percent); 35 ret = hpp__call_print_fn(hpp, print_fn, fmt, len, percent);
36 } else 36 } else
37 ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he)); 37 ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he));
38 38
39 if (perf_evsel__is_group_event(evsel)) { 39 if (perf_evsel__is_group_event(evsel)) {
40 int prev_idx, idx_delta; 40 int prev_idx, idx_delta;
@@ -60,19 +60,19 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
60 */ 60 */
61 if (fmt_percent) { 61 if (fmt_percent) {
62 ret += hpp__call_print_fn(hpp, print_fn, 62 ret += hpp__call_print_fn(hpp, print_fn,
63 fmt, 0.0); 63 fmt, len, 0.0);
64 } else { 64 } else {
65 ret += hpp__call_print_fn(hpp, print_fn, 65 ret += hpp__call_print_fn(hpp, print_fn,
66 fmt, 0ULL); 66 fmt, len, 0ULL);
67 } 67 }
68 } 68 }
69 69
70 if (fmt_percent) { 70 if (fmt_percent) {
71 ret += hpp__call_print_fn(hpp, print_fn, fmt, 71 ret += hpp__call_print_fn(hpp, print_fn, fmt, len,
72 100.0 * period / total); 72 100.0 * period / total);
73 } else { 73 } else {
74 ret += hpp__call_print_fn(hpp, print_fn, fmt, 74 ret += hpp__call_print_fn(hpp, print_fn, fmt,
75 period); 75 len, period);
76 } 76 }
77 77
78 prev_idx = perf_evsel__group_idx(evsel); 78 prev_idx = perf_evsel__group_idx(evsel);
@@ -86,10 +86,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
86 */ 86 */
87 if (fmt_percent) { 87 if (fmt_percent) {
88 ret += hpp__call_print_fn(hpp, print_fn, 88 ret += hpp__call_print_fn(hpp, print_fn,
89 fmt, 0.0); 89 fmt, len, 0.0);
90 } else { 90 } else {
91 ret += hpp__call_print_fn(hpp, print_fn, 91 ret += hpp__call_print_fn(hpp, print_fn,
92 fmt, 0ULL); 92 fmt, len, 0ULL);
93 } 93 }
94 } 94 }
95 } 95 }
@@ -104,16 +104,35 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
104 return ret; 104 return ret;
105} 105}
106 106
107int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, 107int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
108 hpp_field_fn get_field, const char *fmt, 108 struct hist_entry *he, hpp_field_fn get_field,
109 hpp_snprint_fn print_fn, bool fmt_percent) 109 const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
110{
111 int len = fmt->user_len ?: fmt->len;
112
113 if (symbol_conf.field_sep) {
114 return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
115 print_fn, fmt_percent);
116 }
117
118 if (fmt_percent)
119 len -= 2; /* 2 for a space and a % sign */
120 else
121 len -= 1;
122
123 return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent);
124}
125
126int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
127 struct hist_entry *he, hpp_field_fn get_field,
128 const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
110{ 129{
111 if (!symbol_conf.cumulate_callchain) { 130 if (!symbol_conf.cumulate_callchain) {
112 return snprintf(hpp->buf, hpp->size, "%*s", 131 int len = fmt->user_len ?: fmt->len;
113 fmt_percent ? 8 : 12, "N/A"); 132 return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A");
114 } 133 }
115 134
116 return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent); 135 return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmt_percent);
117} 136}
118 137
119static int field_cmp(u64 field_a, u64 field_b) 138static int field_cmp(u64 field_a, u64 field_b)
@@ -190,30 +209,26 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
190 return ret; 209 return ret;
191} 210}
192 211
193#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 212static int hpp__width_fn(struct perf_hpp_fmt *fmt,
194static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 213 struct perf_hpp *hpp __maybe_unused,
195 struct perf_hpp *hpp, \ 214 struct perf_evsel *evsel)
196 struct perf_evsel *evsel) \ 215{
197{ \ 216 int len = fmt->user_len ?: fmt->len;
198 int len = _min_width; \ 217
199 \ 218 if (symbol_conf.event_group)
200 if (symbol_conf.event_group) \ 219 len = max(len, evsel->nr_members * fmt->len);
201 len = max(len, evsel->nr_members * _unit_width); \ 220
202 \ 221 if (len < (int)strlen(fmt->name))
203 return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ 222 len = strlen(fmt->name);
204} 223
205 224 return len;
206#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 225}
207static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 226
208 struct perf_hpp *hpp __maybe_unused, \ 227static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
209 struct perf_evsel *evsel) \ 228 struct perf_evsel *evsel)
210{ \ 229{
211 int len = _min_width; \ 230 int len = hpp__width_fn(fmt, hpp, evsel);
212 \ 231 return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
213 if (symbol_conf.event_group) \
214 len = max(len, evsel->nr_members * _unit_width); \
215 \
216 return len; \
217} 232}
218 233
219static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) 234static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
@@ -221,11 +236,12 @@ static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
221 va_list args; 236 va_list args;
222 ssize_t ssize = hpp->size; 237 ssize_t ssize = hpp->size;
223 double percent; 238 double percent;
224 int ret; 239 int ret, len;
225 240
226 va_start(args, fmt); 241 va_start(args, fmt);
242 len = va_arg(args, int);
227 percent = va_arg(args, double); 243 percent = va_arg(args, double);
228 ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent); 244 ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent);
229 va_end(args); 245 va_end(args);
230 246
231 return (ret >= ssize) ? (ssize - 1) : ret; 247 return (ret >= ssize) ? (ssize - 1) : ret;
@@ -250,20 +266,19 @@ static u64 he_get_##_field(struct hist_entry *he) \
250 return he->stat._field; \ 266 return he->stat._field; \
251} \ 267} \
252 \ 268 \
253static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 269static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \
254 struct perf_hpp *hpp, struct hist_entry *he) \ 270 struct perf_hpp *hpp, struct hist_entry *he) \
255{ \ 271{ \
256 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ 272 return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \
257 hpp_color_scnprintf, true); \ 273 hpp_color_scnprintf, true); \
258} 274}
259 275
260#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ 276#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
261static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ 277static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
262 struct perf_hpp *hpp, struct hist_entry *he) \ 278 struct perf_hpp *hpp, struct hist_entry *he) \
263{ \ 279{ \
264 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ 280 return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \
265 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ 281 hpp_entry_scnprintf, true); \
266 hpp_entry_scnprintf, true); \
267} 282}
268 283
269#define __HPP_SORT_FN(_type, _field) \ 284#define __HPP_SORT_FN(_type, _field) \
@@ -278,20 +293,19 @@ static u64 he_get_acc_##_field(struct hist_entry *he) \
278 return he->stat_acc->_field; \ 293 return he->stat_acc->_field; \
279} \ 294} \
280 \ 295 \
281static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 296static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \
282 struct perf_hpp *hpp, struct hist_entry *he) \ 297 struct perf_hpp *hpp, struct hist_entry *he) \
283{ \ 298{ \
284 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ 299 return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \
285 hpp_color_scnprintf, true); \ 300 hpp_color_scnprintf, true); \
286} 301}
287 302
288#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ 303#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
289static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ 304static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
290 struct perf_hpp *hpp, struct hist_entry *he) \ 305 struct perf_hpp *hpp, struct hist_entry *he) \
291{ \ 306{ \
292 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ 307 return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \
293 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \ 308 hpp_entry_scnprintf, true); \
294 hpp_entry_scnprintf, true); \
295} 309}
296 310
297#define __HPP_SORT_ACC_FN(_type, _field) \ 311#define __HPP_SORT_ACC_FN(_type, _field) \
@@ -306,12 +320,11 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \
306 return he->stat._field; \ 320 return he->stat._field; \
307} \ 321} \
308 \ 322 \
309static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ 323static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
310 struct perf_hpp *hpp, struct hist_entry *he) \ 324 struct perf_hpp *hpp, struct hist_entry *he) \
311{ \ 325{ \
312 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ 326 return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64, \
313 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, \ 327 hpp_entry_scnprintf, false); \
314 hpp_entry_scnprintf, false); \
315} 328}
316 329
317#define __HPP_SORT_RAW_FN(_type, _field) \ 330#define __HPP_SORT_RAW_FN(_type, _field) \
@@ -321,37 +334,29 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
321} 334}
322 335
323 336
324#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ 337#define HPP_PERCENT_FNS(_type, _field) \
325__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
326__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
327__HPP_COLOR_PERCENT_FN(_type, _field) \ 338__HPP_COLOR_PERCENT_FN(_type, _field) \
328__HPP_ENTRY_PERCENT_FN(_type, _field) \ 339__HPP_ENTRY_PERCENT_FN(_type, _field) \
329__HPP_SORT_FN(_type, _field) 340__HPP_SORT_FN(_type, _field)
330 341
331#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\ 342#define HPP_PERCENT_ACC_FNS(_type, _field) \
332__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
333__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
334__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ 343__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
335__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ 344__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
336__HPP_SORT_ACC_FN(_type, _field) 345__HPP_SORT_ACC_FN(_type, _field)
337 346
338#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ 347#define HPP_RAW_FNS(_type, _field) \
339__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
340__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
341__HPP_ENTRY_RAW_FN(_type, _field) \ 348__HPP_ENTRY_RAW_FN(_type, _field) \
342__HPP_SORT_RAW_FN(_type, _field) 349__HPP_SORT_RAW_FN(_type, _field)
343 350
344__HPP_HEADER_FN(overhead_self, "Self", 8, 8) 351HPP_PERCENT_FNS(overhead, period)
345 352HPP_PERCENT_FNS(overhead_sys, period_sys)
346HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) 353HPP_PERCENT_FNS(overhead_us, period_us)
347HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) 354HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys)
348HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) 355HPP_PERCENT_FNS(overhead_guest_us, period_guest_us)
349HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) 356HPP_PERCENT_ACC_FNS(overhead_acc, period)
350HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
351HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)
352 357
353HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 358HPP_RAW_FNS(samples, nr_events)
354HPP_RAW_FNS(period, "Period", period, 12, 12) 359HPP_RAW_FNS(period, period)
355 360
356static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, 361static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
357 struct hist_entry *b __maybe_unused) 362 struct hist_entry *b __maybe_unused)
@@ -359,47 +364,50 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
359 return 0; 364 return 0;
360} 365}
361 366
362#define HPP__COLOR_PRINT_FNS(_name) \ 367#define HPP__COLOR_PRINT_FNS(_name, _fn) \
363 { \ 368 { \
364 .header = hpp__header_ ## _name, \ 369 .name = _name, \
365 .width = hpp__width_ ## _name, \ 370 .header = hpp__header_fn, \
366 .color = hpp__color_ ## _name, \ 371 .width = hpp__width_fn, \
367 .entry = hpp__entry_ ## _name, \ 372 .color = hpp__color_ ## _fn, \
373 .entry = hpp__entry_ ## _fn, \
368 .cmp = hpp__nop_cmp, \ 374 .cmp = hpp__nop_cmp, \
369 .collapse = hpp__nop_cmp, \ 375 .collapse = hpp__nop_cmp, \
370 .sort = hpp__sort_ ## _name, \ 376 .sort = hpp__sort_ ## _fn, \
371 } 377 }
372 378
373#define HPP__COLOR_ACC_PRINT_FNS(_name) \ 379#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn) \
374 { \ 380 { \
375 .header = hpp__header_ ## _name, \ 381 .name = _name, \
376 .width = hpp__width_ ## _name, \ 382 .header = hpp__header_fn, \
377 .color = hpp__color_ ## _name, \ 383 .width = hpp__width_fn, \
378 .entry = hpp__entry_ ## _name, \ 384 .color = hpp__color_ ## _fn, \
385 .entry = hpp__entry_ ## _fn, \
379 .cmp = hpp__nop_cmp, \ 386 .cmp = hpp__nop_cmp, \
380 .collapse = hpp__nop_cmp, \ 387 .collapse = hpp__nop_cmp, \
381 .sort = hpp__sort_ ## _name, \ 388 .sort = hpp__sort_ ## _fn, \
382 } 389 }
383 390
384#define HPP__PRINT_FNS(_name) \ 391#define HPP__PRINT_FNS(_name, _fn) \
385 { \ 392 { \
386 .header = hpp__header_ ## _name, \ 393 .name = _name, \
387 .width = hpp__width_ ## _name, \ 394 .header = hpp__header_fn, \
388 .entry = hpp__entry_ ## _name, \ 395 .width = hpp__width_fn, \
396 .entry = hpp__entry_ ## _fn, \
389 .cmp = hpp__nop_cmp, \ 397 .cmp = hpp__nop_cmp, \
390 .collapse = hpp__nop_cmp, \ 398 .collapse = hpp__nop_cmp, \
391 .sort = hpp__sort_ ## _name, \ 399 .sort = hpp__sort_ ## _fn, \
392 } 400 }
393 401
394struct perf_hpp_fmt perf_hpp__format[] = { 402struct perf_hpp_fmt perf_hpp__format[] = {
395 HPP__COLOR_PRINT_FNS(overhead), 403 HPP__COLOR_PRINT_FNS("Overhead", overhead),
396 HPP__COLOR_PRINT_FNS(overhead_sys), 404 HPP__COLOR_PRINT_FNS("sys", overhead_sys),
397 HPP__COLOR_PRINT_FNS(overhead_us), 405 HPP__COLOR_PRINT_FNS("usr", overhead_us),
398 HPP__COLOR_PRINT_FNS(overhead_guest_sys), 406 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys),
399 HPP__COLOR_PRINT_FNS(overhead_guest_us), 407 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
400 HPP__COLOR_ACC_PRINT_FNS(overhead_acc), 408 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
401 HPP__PRINT_FNS(samples), 409 HPP__PRINT_FNS("Samples", samples),
402 HPP__PRINT_FNS(period) 410 HPP__PRINT_FNS("Period", period)
403}; 411};
404 412
405LIST_HEAD(perf_hpp__list); 413LIST_HEAD(perf_hpp__list);
@@ -444,14 +452,12 @@ void perf_hpp__init(void)
444 /* 452 /*
445 * If user specified field order, no need to setup default fields. 453 * If user specified field order, no need to setup default fields.
446 */ 454 */
447 if (field_order) 455 if (is_strict_order(field_order))
448 return; 456 return;
449 457
450 if (symbol_conf.cumulate_callchain) { 458 if (symbol_conf.cumulate_callchain) {
451 perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC); 459 perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC);
452 460 perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self";
453 perf_hpp__format[PERF_HPP__OVERHEAD].header =
454 hpp__header_overhead_self;
455 } 461 }
456 462
457 perf_hpp__column_enable(PERF_HPP__OVERHEAD); 463 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
@@ -513,11 +519,11 @@ void perf_hpp__column_disable(unsigned col)
513 519
514void perf_hpp__cancel_cumulate(void) 520void perf_hpp__cancel_cumulate(void)
515{ 521{
516 if (field_order) 522 if (is_strict_order(field_order))
517 return; 523 return;
518 524
519 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); 525 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
520 perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead; 526 perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead";
521} 527}
522 528
523void perf_hpp__setup_output_field(void) 529void perf_hpp__setup_output_field(void)
@@ -622,3 +628,59 @@ unsigned int hists__sort_list_width(struct hists *hists)
622 628
623 return ret; 629 return ret;
624} 630}
631
632void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
633{
634 int idx;
635
636 if (perf_hpp__is_sort_entry(fmt))
637 return perf_hpp__reset_sort_width(fmt, hists);
638
639 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
640 if (fmt == &perf_hpp__format[idx])
641 break;
642 }
643
644 if (idx == PERF_HPP__MAX_INDEX)
645 return;
646
647 switch (idx) {
648 case PERF_HPP__OVERHEAD:
649 case PERF_HPP__OVERHEAD_SYS:
650 case PERF_HPP__OVERHEAD_US:
651 case PERF_HPP__OVERHEAD_ACC:
652 fmt->len = 8;
653 break;
654
655 case PERF_HPP__OVERHEAD_GUEST_SYS:
656 case PERF_HPP__OVERHEAD_GUEST_US:
657 fmt->len = 9;
658 break;
659
660 case PERF_HPP__SAMPLES:
661 case PERF_HPP__PERIOD:
662 fmt->len = 12;
663 break;
664
665 default:
666 break;
667 }
668}
669
670void perf_hpp__set_user_width(const char *width_list_str)
671{
672 struct perf_hpp_fmt *fmt;
673 const char *ptr = width_list_str;
674
675 perf_hpp__for_each_format(fmt) {
676 char *p;
677
678 int len = strtol(ptr, &p, 10);
679 fmt->user_len = len;
680
681 if (*p == ',')
682 ptr = p + 1;
683 else
684 break;
685 }
686}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 40af0acb4fe9..15b451acbde6 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -395,10 +395,12 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
395 395
396 init_rem_hits(); 396 init_rem_hits();
397 397
398
399 perf_hpp__for_each_format(fmt) 398 perf_hpp__for_each_format(fmt)
400 perf_hpp__reset_width(fmt, hists); 399 perf_hpp__reset_width(fmt, hists);
401 400
401 if (symbol_conf.col_width_list_str)
402 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
403
402 if (!show_header) 404 if (!show_header)
403 goto print_entries; 405 goto print_entries;
404 406
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 809b4c50beae..36437527dbb3 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -232,9 +232,16 @@ static int mov__parse(struct ins_operands *ops)
232 return -1; 232 return -1;
233 233
234 target = ++s; 234 target = ++s;
235 comment = strchr(s, '#');
235 236
236 while (s[0] != '\0' && !isspace(s[0])) 237 if (comment != NULL)
237 ++s; 238 s = comment - 1;
239 else
240 s = strchr(s, '\0') - 1;
241
242 while (s > target && isspace(s[0]))
243 --s;
244 s++;
238 prev = *s; 245 prev = *s;
239 *s = '\0'; 246 *s = '\0';
240 247
@@ -244,7 +251,6 @@ static int mov__parse(struct ins_operands *ops)
244 if (ops->target.raw == NULL) 251 if (ops->target.raw == NULL)
245 goto out_free_source; 252 goto out_free_source;
246 253
247 comment = strchr(s, '#');
248 if (comment == NULL) 254 if (comment == NULL)
249 return 0; 255 return 0;
250 256
@@ -899,10 +905,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
899 struct kcore_extract kce; 905 struct kcore_extract kce;
900 bool delete_extract = false; 906 bool delete_extract = false;
901 907
902 if (filename) { 908 if (filename)
903 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 909 symbol__join_symfs(symfs_filename, filename);
904 symbol_conf.symfs, filename);
905 }
906 910
907 if (filename == NULL) { 911 if (filename == NULL) {
908 if (dso->has_build_id) { 912 if (dso->has_build_id) {
@@ -922,8 +926,7 @@ fallback:
922 * DSO is the same as when 'perf record' ran. 926 * DSO is the same as when 'perf record' ran.
923 */ 927 */
924 filename = (char *)dso->long_name; 928 filename = (char *)dso->long_name;
925 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 929 symbol__join_symfs(symfs_filename, filename);
926 symbol_conf.symfs, filename);
927 free_filename = false; 930 free_filename = false;
928 } 931 }
929 932
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 7b176dd02e1a..5cf9e1b5989d 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -22,6 +22,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
22extern int perf_default_config(const char *, const char *, void *); 22extern int perf_default_config(const char *, const char *, void *);
23extern int perf_config(config_fn_t fn, void *); 23extern int perf_config(config_fn_t fn, void *);
24extern int perf_config_int(const char *, const char *); 24extern int perf_config_int(const char *, const char *);
25extern u64 perf_config_u64(const char *, const char *);
25extern int perf_config_bool(const char *, const char *); 26extern int perf_config_bool(const char *, const char *);
26extern int config_error_nonbool(const char *); 27extern int config_error_nonbool(const char *);
27extern const char *perf_config_dirname(const char *, const char *); 28extern const char *perf_config_dirname(const char *, const char *);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 437ee09727e6..c84d3f8dcb75 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -25,77 +25,172 @@
25 25
26__thread struct callchain_cursor callchain_cursor; 26__thread struct callchain_cursor callchain_cursor;
27 27
28int 28#ifdef HAVE_DWARF_UNWIND_SUPPORT
29parse_callchain_report_opt(const char *arg) 29static int get_stack_size(const char *str, unsigned long *_size)
30{ 30{
31 char *tok, *tok2;
32 char *endptr; 31 char *endptr;
32 unsigned long size;
33 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
33 34
34 symbol_conf.use_callchain = true; 35 size = strtoul(str, &endptr, 0);
35 36
36 if (!arg) 37 do {
38 if (*endptr)
39 break;
40
41 size = round_up(size, sizeof(u64));
42 if (!size || size > max_size)
43 break;
44
45 *_size = size;
37 return 0; 46 return 0;
38 47
39 tok = strtok((char *)arg, ","); 48 } while (0);
40 if (!tok)
41 return -1;
42 49
43 /* get the output mode */ 50 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
44 if (!strncmp(tok, "graph", strlen(arg))) { 51 max_size, str);
45 callchain_param.mode = CHAIN_GRAPH_ABS; 52 return -1;
53}
54#endif /* HAVE_DWARF_UNWIND_SUPPORT */
46 55
47 } else if (!strncmp(tok, "flat", strlen(arg))) { 56int parse_callchain_record_opt(const char *arg)
48 callchain_param.mode = CHAIN_FLAT; 57{
49 } else if (!strncmp(tok, "fractal", strlen(arg))) { 58 char *tok, *name, *saveptr = NULL;
50 callchain_param.mode = CHAIN_GRAPH_REL; 59 char *buf;
51 } else if (!strncmp(tok, "none", strlen(arg))) { 60 int ret = -1;
52 callchain_param.mode = CHAIN_NONE; 61
53 symbol_conf.use_callchain = false; 62 /* We need buffer that we know we can write to. */
54 return 0; 63 buf = malloc(strlen(arg) + 1);
55 } else { 64 if (!buf)
56 return -1; 65 return -ENOMEM;
57 } 66
67 strcpy(buf, arg);
68
69 tok = strtok_r((char *)buf, ",", &saveptr);
70 name = tok ? : (char *)buf;
71
72 do {
73 /* Framepointer style */
74 if (!strncmp(name, "fp", sizeof("fp"))) {
75 if (!strtok_r(NULL, ",", &saveptr)) {
76 callchain_param.record_mode = CALLCHAIN_FP;
77 ret = 0;
78 } else
79 pr_err("callchain: No more arguments "
80 "needed for -g fp\n");
81 break;
58 82
59 /* get the min percentage */ 83#ifdef HAVE_DWARF_UNWIND_SUPPORT
60 tok = strtok(NULL, ","); 84 /* Dwarf style */
61 if (!tok) 85 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
62 goto setup; 86 const unsigned long default_stack_dump_size = 8192;
63 87
64 callchain_param.min_percent = strtod(tok, &endptr); 88 ret = 0;
65 if (tok == endptr) 89 callchain_param.record_mode = CALLCHAIN_DWARF;
66 return -1; 90 callchain_param.dump_size = default_stack_dump_size;
67 91
68 /* get the print limit */ 92 tok = strtok_r(NULL, ",", &saveptr);
69 tok2 = strtok(NULL, ","); 93 if (tok) {
70 if (!tok2) 94 unsigned long size = 0;
71 goto setup;
72 95
73 if (tok2[0] != 'c') { 96 ret = get_stack_size(tok, &size);
74 callchain_param.print_limit = strtoul(tok2, &endptr, 0); 97 callchain_param.dump_size = size;
75 tok2 = strtok(NULL, ","); 98 }
76 if (!tok2) 99#endif /* HAVE_DWARF_UNWIND_SUPPORT */
77 goto setup; 100 } else {
101 pr_err("callchain: Unknown --call-graph option "
102 "value: %s\n", arg);
103 break;
104 }
105
106 } while (0);
107
108 free(buf);
109 return ret;
110}
111
112static int parse_callchain_mode(const char *value)
113{
114 if (!strncmp(value, "graph", strlen(value))) {
115 callchain_param.mode = CHAIN_GRAPH_ABS;
116 return 0;
117 }
118 if (!strncmp(value, "flat", strlen(value))) {
119 callchain_param.mode = CHAIN_FLAT;
120 return 0;
78 } 121 }
122 if (!strncmp(value, "fractal", strlen(value))) {
123 callchain_param.mode = CHAIN_GRAPH_REL;
124 return 0;
125 }
126 return -1;
127}
79 128
80 /* get the call chain order */ 129static int parse_callchain_order(const char *value)
81 if (!strncmp(tok2, "caller", strlen("caller"))) 130{
131 if (!strncmp(value, "caller", strlen(value))) {
82 callchain_param.order = ORDER_CALLER; 132 callchain_param.order = ORDER_CALLER;
83 else if (!strncmp(tok2, "callee", strlen("callee"))) 133 return 0;
134 }
135 if (!strncmp(value, "callee", strlen(value))) {
84 callchain_param.order = ORDER_CALLEE; 136 callchain_param.order = ORDER_CALLEE;
85 else 137 return 0;
86 return -1; 138 }
139 return -1;
140}
87 141
88 /* Get the sort key */ 142static int parse_callchain_sort_key(const char *value)
89 tok2 = strtok(NULL, ","); 143{
90 if (!tok2) 144 if (!strncmp(value, "function", strlen(value))) {
91 goto setup;
92 if (!strncmp(tok2, "function", strlen("function")))
93 callchain_param.key = CCKEY_FUNCTION; 145 callchain_param.key = CCKEY_FUNCTION;
94 else if (!strncmp(tok2, "address", strlen("address"))) 146 return 0;
147 }
148 if (!strncmp(value, "address", strlen(value))) {
95 callchain_param.key = CCKEY_ADDRESS; 149 callchain_param.key = CCKEY_ADDRESS;
96 else 150 return 0;
97 return -1; 151 }
98setup: 152 return -1;
153}
154
155int
156parse_callchain_report_opt(const char *arg)
157{
158 char *tok;
159 char *endptr;
160 bool minpcnt_set = false;
161
162 symbol_conf.use_callchain = true;
163
164 if (!arg)
165 return 0;
166
167 while ((tok = strtok((char *)arg, ",")) != NULL) {
168 if (!strncmp(tok, "none", strlen(tok))) {
169 callchain_param.mode = CHAIN_NONE;
170 symbol_conf.use_callchain = false;
171 return 0;
172 }
173
174 if (!parse_callchain_mode(tok) ||
175 !parse_callchain_order(tok) ||
176 !parse_callchain_sort_key(tok)) {
177 /* parsing ok - move on to the next */
178 } else if (!minpcnt_set) {
179 /* try to get the min percent */
180 callchain_param.min_percent = strtod(tok, &endptr);
181 if (tok == endptr)
182 return -1;
183 minpcnt_set = true;
184 } else {
185 /* try print limit at last */
186 callchain_param.print_limit = strtoul(tok, &endptr, 0);
187 if (tok == endptr)
188 return -1;
189 }
190
191 arg = NULL;
192 }
193
99 if (callchain_register_param(&callchain_param) < 0) { 194 if (callchain_register_param(&callchain_param) < 0) {
100 pr_err("Can't register callchain params\n"); 195 pr_err("Can't register callchain params\n");
101 return -1; 196 return -1;
@@ -103,6 +198,47 @@ setup:
103 return 0; 198 return 0;
104} 199}
105 200
201int perf_callchain_config(const char *var, const char *value)
202{
203 char *endptr;
204
205 if (prefixcmp(var, "call-graph."))
206 return 0;
207 var += sizeof("call-graph.") - 1;
208
209 if (!strcmp(var, "record-mode"))
210 return parse_callchain_record_opt(value);
211#ifdef HAVE_DWARF_UNWIND_SUPPORT
212 if (!strcmp(var, "dump-size")) {
213 unsigned long size = 0;
214 int ret;
215
216 ret = get_stack_size(value, &size);
217 callchain_param.dump_size = size;
218
219 return ret;
220 }
221#endif
222 if (!strcmp(var, "print-type"))
223 return parse_callchain_mode(value);
224 if (!strcmp(var, "order"))
225 return parse_callchain_order(value);
226 if (!strcmp(var, "sort-key"))
227 return parse_callchain_sort_key(value);
228 if (!strcmp(var, "threshold")) {
229 callchain_param.min_percent = strtod(value, &endptr);
230 if (value == endptr)
231 return -1;
232 }
233 if (!strcmp(var, "print-limit")) {
234 callchain_param.print_limit = strtod(value, &endptr);
235 if (value == endptr)
236 return -1;
237 }
238
239 return 0;
240}
241
106static void 242static void
107rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 243rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
108 enum chain_mode mode) 244 enum chain_mode mode)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index da43619d6173..2a1f5a46543a 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -54,6 +54,9 @@ enum chain_key {
54}; 54};
55 55
56struct callchain_param { 56struct callchain_param {
57 bool enabled;
58 enum perf_call_graph_mode record_mode;
59 u32 dump_size;
57 enum chain_mode mode; 60 enum chain_mode mode;
58 u32 print_limit; 61 u32 print_limit;
59 double min_percent; 62 double min_percent;
@@ -154,7 +157,6 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
154struct option; 157struct option;
155struct hist_entry; 158struct hist_entry;
156 159
157int record_parse_callchain(const char *arg, struct record_opts *opts);
158int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); 160int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
159int record_callchain_opt(const struct option *opt, const char *arg, int unset); 161int record_callchain_opt(const struct option *opt, const char *arg, int unset);
160 162
@@ -166,7 +168,9 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
166 bool hide_unresolved); 168 bool hide_unresolved);
167 169
168extern const char record_callchain_help[]; 170extern const char record_callchain_help[];
171int parse_callchain_record_opt(const char *arg);
169int parse_callchain_report_opt(const char *arg); 172int parse_callchain_report_opt(const char *arg);
173int perf_callchain_config(const char *var, const char *value);
170 174
171static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, 175static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
172 struct callchain_cursor *src) 176 struct callchain_cursor *src)
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
index c5d05ec17220..47b78b3f0325 100644
--- a/tools/perf/util/cloexec.c
+++ b/tools/perf/util/cloexec.c
@@ -1,7 +1,9 @@
1#include <sched.h>
1#include "util.h" 2#include "util.h"
2#include "../perf.h" 3#include "../perf.h"
3#include "cloexec.h" 4#include "cloexec.h"
4#include "asm/bug.h" 5#include "asm/bug.h"
6#include "debug.h"
5 7
6static unsigned long flag = PERF_FLAG_FD_CLOEXEC; 8static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
7 9
@@ -9,15 +11,30 @@ static int perf_flag_probe(void)
9{ 11{
10 /* use 'safest' configuration as used in perf_evsel__fallback() */ 12 /* use 'safest' configuration as used in perf_evsel__fallback() */
11 struct perf_event_attr attr = { 13 struct perf_event_attr attr = {
12 .type = PERF_COUNT_SW_CPU_CLOCK, 14 .type = PERF_TYPE_SOFTWARE,
13 .config = PERF_COUNT_SW_CPU_CLOCK, 15 .config = PERF_COUNT_SW_CPU_CLOCK,
16 .exclude_kernel = 1,
14 }; 17 };
15 int fd; 18 int fd;
16 int err; 19 int err;
20 int cpu;
21 pid_t pid = -1;
22 char sbuf[STRERR_BUFSIZE];
17 23
18 /* check cloexec flag */ 24 cpu = sched_getcpu();
19 fd = sys_perf_event_open(&attr, 0, -1, -1, 25 if (cpu < 0)
20 PERF_FLAG_FD_CLOEXEC); 26 cpu = 0;
27
28 while (1) {
29 /* check cloexec flag */
30 fd = sys_perf_event_open(&attr, pid, cpu, -1,
31 PERF_FLAG_FD_CLOEXEC);
32 if (fd < 0 && pid == -1 && errno == EACCES) {
33 pid = 0;
34 continue;
35 }
36 break;
37 }
21 err = errno; 38 err = errno;
22 39
23 if (fd >= 0) { 40 if (fd >= 0) {
@@ -25,17 +42,17 @@ static int perf_flag_probe(void)
25 return 1; 42 return 1;
26 } 43 }
27 44
28 WARN_ONCE(err != EINVAL, 45 WARN_ONCE(err != EINVAL && err != EBUSY,
29 "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", 46 "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
30 err, strerror(err)); 47 err, strerror_r(err, sbuf, sizeof(sbuf)));
31 48
32 /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ 49 /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
33 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 50 fd = sys_perf_event_open(&attr, pid, cpu, -1, 0);
34 err = errno; 51 err = errno;
35 52
36 if (WARN_ONCE(fd < 0, 53 if (WARN_ONCE(fd < 0 && err != EBUSY,
37 "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", 54 "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
38 err, strerror(err))) 55 err, strerror_r(err, sbuf, sizeof(sbuf))))
39 return -1; 56 return -1;
40 57
41 close(fd); 58 close(fd);
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 87b8672eb413..f4654183d391 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -335,3 +335,19 @@ int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
335 va_end(args); 335 va_end(args);
336 return value_color_snprintf(bf, size, fmt, percent); 336 return value_color_snprintf(bf, size, fmt, percent);
337} 337}
338
339int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...)
340{
341 va_list args;
342 int len;
343 double percent;
344 const char *color;
345
346 va_start(args, fmt);
347 len = va_arg(args, int);
348 percent = va_arg(args, double);
349 va_end(args);
350
351 color = get_percent_color(percent);
352 return color_snprintf(bf, size, color, fmt, len, percent);
353}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 7ff30a62a132..0a594b8a0c26 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -41,6 +41,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); 42int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
43int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); 43int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
44int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...);
44int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 45int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
45const char *get_percent_color(double percent); 46const char *get_percent_color(double percent);
46 47
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index f9e777629e21..b2bb59df65e1 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
74 return new; 74 return new;
75} 75}
76 76
77struct comm *comm__new(const char *str, u64 timestamp) 77struct comm *comm__new(const char *str, u64 timestamp, bool exec)
78{ 78{
79 struct comm *comm = zalloc(sizeof(*comm)); 79 struct comm *comm = zalloc(sizeof(*comm));
80 80
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
82 return NULL; 82 return NULL;
83 83
84 comm->start = timestamp; 84 comm->start = timestamp;
85 comm->exec = exec;
85 86
86 comm->comm_str = comm_str__findnew(str, &comm_str_root); 87 comm->comm_str = comm_str__findnew(str, &comm_str_root);
87 if (!comm->comm_str) { 88 if (!comm->comm_str) {
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp)
94 return comm; 95 return comm;
95} 96}
96 97
97int comm__override(struct comm *comm, const char *str, u64 timestamp) 98int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
98{ 99{
99 struct comm_str *new, *old = comm->comm_str; 100 struct comm_str *new, *old = comm->comm_str;
100 101
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp)
106 comm_str__put(old); 107 comm_str__put(old);
107 comm->comm_str = new; 108 comm->comm_str = new;
108 comm->start = timestamp; 109 comm->start = timestamp;
110 if (exec)
111 comm->exec = true;
109 112
110 return 0; 113 return 0;
111} 114}
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
index fac5bd51befc..51c10ab257f8 100644
--- a/tools/perf/util/comm.h
+++ b/tools/perf/util/comm.h
@@ -11,11 +11,13 @@ struct comm {
11 struct comm_str *comm_str; 11 struct comm_str *comm_str;
12 u64 start; 12 u64 start;
13 struct list_head list; 13 struct list_head list;
14 bool exec;
14}; 15};
15 16
16void comm__free(struct comm *comm); 17void comm__free(struct comm *comm);
17struct comm *comm__new(const char *str, u64 timestamp); 18struct comm *comm__new(const char *str, u64 timestamp, bool exec);
18const char *comm__str(const struct comm *comm); 19const char *comm__str(const struct comm *comm);
19int comm__override(struct comm *comm, const char *str, u64 timestamp); 20int comm__override(struct comm *comm, const char *str, u64 timestamp,
21 bool exec);
20 22
21#endif /* __PERF_COMM_H */ 23#endif /* __PERF_COMM_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 1e5e2e5af6b1..57ff826f150b 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -222,7 +222,8 @@ static int perf_parse_file(config_fn_t fn, void *data)
222 const unsigned char *bomptr = utf8_bom; 222 const unsigned char *bomptr = utf8_bom;
223 223
224 for (;;) { 224 for (;;) {
225 int c = get_next_char(); 225 int line, c = get_next_char();
226
226 if (bomptr && *bomptr) { 227 if (bomptr && *bomptr) {
227 /* We are at the file beginning; skip UTF8-encoded BOM 228 /* We are at the file beginning; skip UTF8-encoded BOM
228 * if present. Sane editors won't put this in on their 229 * if present. Sane editors won't put this in on their
@@ -261,8 +262,16 @@ static int perf_parse_file(config_fn_t fn, void *data)
261 if (!isalpha(c)) 262 if (!isalpha(c))
262 break; 263 break;
263 var[baselen] = tolower(c); 264 var[baselen] = tolower(c);
264 if (get_value(fn, data, var, baselen+1) < 0) 265
266 /*
267 * The get_value function might or might not reach the '\n',
268 * so saving the current line number for error reporting.
269 */
270 line = config_linenr;
271 if (get_value(fn, data, var, baselen+1) < 0) {
272 config_linenr = line;
265 break; 273 break;
274 }
266 } 275 }
267 die("bad config file line %d in %s", config_linenr, config_file_name); 276 die("bad config file line %d in %s", config_linenr, config_file_name);
268} 277}
@@ -286,6 +295,21 @@ static int parse_unit_factor(const char *end, unsigned long *val)
286 return 0; 295 return 0;
287} 296}
288 297
298static int perf_parse_llong(const char *value, long long *ret)
299{
300 if (value && *value) {
301 char *end;
302 long long val = strtoll(value, &end, 0);
303 unsigned long factor = 1;
304
305 if (!parse_unit_factor(end, &factor))
306 return 0;
307 *ret = val * factor;
308 return 1;
309 }
310 return 0;
311}
312
289static int perf_parse_long(const char *value, long *ret) 313static int perf_parse_long(const char *value, long *ret)
290{ 314{
291 if (value && *value) { 315 if (value && *value) {
@@ -307,6 +331,15 @@ static void die_bad_config(const char *name)
307 die("bad config value for '%s'", name); 331 die("bad config value for '%s'", name);
308} 332}
309 333
334u64 perf_config_u64(const char *name, const char *value)
335{
336 long long ret = 0;
337
338 if (!perf_parse_llong(value, &ret))
339 die_bad_config(name);
340 return (u64) ret;
341}
342
310int perf_config_int(const char *name, const char *value) 343int perf_config_int(const char *name, const char *value)
311{ 344{
312 long ret = 0; 345 long ret = 0;
@@ -372,6 +405,9 @@ int perf_default_config(const char *var, const char *value,
372 if (!prefixcmp(var, "ui.")) 405 if (!prefixcmp(var, "ui."))
373 return perf_ui_config(var, value); 406 return perf_ui_config(var, value);
374 407
408 if (!prefixcmp(var, "call-graph."))
409 return perf_callchain_config(var, value);
410
375 /* Add other config variables here. */ 411 /* Add other config variables here. */
376 return 0; 412 return 0;
377} 413}
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 29d720cf5844..1921942fc2e0 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -50,12 +50,14 @@ static int open_file_read(struct perf_data_file *file)
50{ 50{
51 struct stat st; 51 struct stat st;
52 int fd; 52 int fd;
53 char sbuf[STRERR_BUFSIZE];
53 54
54 fd = open(file->path, O_RDONLY); 55 fd = open(file->path, O_RDONLY);
55 if (fd < 0) { 56 if (fd < 0) {
56 int err = errno; 57 int err = errno;
57 58
58 pr_err("failed to open %s: %s", file->path, strerror(err)); 59 pr_err("failed to open %s: %s", file->path,
60 strerror_r(err, sbuf, sizeof(sbuf)));
59 if (err == ENOENT && !strcmp(file->path, "perf.data")) 61 if (err == ENOENT && !strcmp(file->path, "perf.data"))
60 pr_err(" (try 'perf record' first)"); 62 pr_err(" (try 'perf record' first)");
61 pr_err("\n"); 63 pr_err("\n");
@@ -88,6 +90,7 @@ static int open_file_read(struct perf_data_file *file)
88static int open_file_write(struct perf_data_file *file) 90static int open_file_write(struct perf_data_file *file)
89{ 91{
90 int fd; 92 int fd;
93 char sbuf[STRERR_BUFSIZE];
91 94
92 if (check_backup(file)) 95 if (check_backup(file))
93 return -1; 96 return -1;
@@ -95,7 +98,8 @@ static int open_file_write(struct perf_data_file *file)
95 fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); 98 fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
96 99
97 if (fd < 0) 100 if (fd < 0)
98 pr_err("failed to open %s : %s\n", file->path, strerror(errno)); 101 pr_err("failed to open %s : %s\n", file->path,
102 strerror_r(errno, sbuf, sizeof(sbuf)));
99 103
100 return fd; 104 return fd;
101} 105}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 71d419362634..ba357f3226c6 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -13,8 +13,12 @@
13#include "util.h" 13#include "util.h"
14#include "target.h" 14#include "target.h"
15 15
16#define NSECS_PER_SEC 1000000000ULL
17#define NSECS_PER_USEC 1000ULL
18
16int verbose; 19int verbose;
17bool dump_trace = false, quiet = false; 20bool dump_trace = false, quiet = false;
21int debug_ordered_events;
18 22
19static int _eprintf(int level, int var, const char *fmt, va_list args) 23static int _eprintf(int level, int var, const char *fmt, va_list args)
20{ 24{
@@ -42,6 +46,35 @@ int eprintf(int level, int var, const char *fmt, ...)
42 return ret; 46 return ret;
43} 47}
44 48
49static int __eprintf_time(u64 t, const char *fmt, va_list args)
50{
51 int ret = 0;
52 u64 secs, usecs, nsecs = t;
53
54 secs = nsecs / NSECS_PER_SEC;
55 nsecs -= secs * NSECS_PER_SEC;
56 usecs = nsecs / NSECS_PER_USEC;
57
58 ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
59 secs, usecs);
60 ret += vfprintf(stderr, fmt, args);
61 return ret;
62}
63
64int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
65{
66 int ret = 0;
67 va_list args;
68
69 if (var >= level) {
70 va_start(args, fmt);
71 ret = __eprintf_time(t, fmt, args);
72 va_end(args);
73 }
74
75 return ret;
76}
77
45/* 78/*
46 * Overloading libtraceevent standard info print 79 * Overloading libtraceevent standard info print
47 * function, display with -v in perf. 80 * function, display with -v in perf.
@@ -110,7 +143,8 @@ static struct debug_variable {
110 const char *name; 143 const char *name;
111 int *ptr; 144 int *ptr;
112} debug_variables[] = { 145} debug_variables[] = {
113 { .name = "verbose", .ptr = &verbose }, 146 { .name = "verbose", .ptr = &verbose },
147 { .name = "ordered-events", .ptr = &debug_ordered_events},
114 { .name = NULL, } 148 { .name = NULL, }
115}; 149};
116 150
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 89fb6b0f7ab2..be264d6f3b30 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -3,6 +3,7 @@
3#define __PERF_DEBUG_H 3#define __PERF_DEBUG_H
4 4
5#include <stdbool.h> 5#include <stdbool.h>
6#include <string.h>
6#include "event.h" 7#include "event.h"
7#include "../ui/helpline.h" 8#include "../ui/helpline.h"
8#include "../ui/progress.h" 9#include "../ui/progress.h"
@@ -10,6 +11,7 @@
10 11
11extern int verbose; 12extern int verbose;
12extern bool quiet, dump_trace; 13extern bool quiet, dump_trace;
14extern int debug_ordered_events;
13 15
14#ifndef pr_fmt 16#ifndef pr_fmt
15#define pr_fmt(fmt) fmt 17#define pr_fmt(fmt) fmt
@@ -29,6 +31,14 @@ extern bool quiet, dump_trace;
29#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 31#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
30#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) 32#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
31 33
34#define pr_time_N(n, var, t, fmt, ...) \
35 eprintf_time(n, var, t, fmt, ##__VA_ARGS__)
36
37#define pr_oe_time(t, fmt, ...) pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
38#define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
39
40#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */
41
32int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 42int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
33void trace_event(union perf_event *event); 43void trace_event(union perf_event *event);
34 44
@@ -38,6 +48,7 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
38void pr_stat(const char *fmt, ...); 48void pr_stat(const char *fmt, ...);
39 49
40int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); 50int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
51int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
41 52
42int perf_debug_option(const char *str); 53int perf_debug_option(const char *str);
43 54
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 90d02c661dd4..0247acfdfaca 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
37{ 37{
38 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 38 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
39 int ret = 0; 39 int ret = 0;
40 size_t len;
40 41
41 switch (type) { 42 switch (type) {
42 case DSO_BINARY_TYPE__DEBUGLINK: { 43 case DSO_BINARY_TYPE__DEBUGLINK: {
@@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso,
60 break; 61 break;
61 62
62 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 63 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
63 snprintf(filename, size, "%s/usr/lib/debug%s.debug", 64 len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
64 symbol_conf.symfs, dso->long_name); 65 snprintf(filename + len, size - len, "%s.debug", dso->long_name);
65 break; 66 break;
66 67
67 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 68 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
68 snprintf(filename, size, "%s/usr/lib/debug%s", 69 len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
69 symbol_conf.symfs, dso->long_name); 70 snprintf(filename + len, size - len, "%s", dso->long_name);
70 break; 71 break;
71 72
72 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 73 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
73 { 74 {
74 const char *last_slash; 75 const char *last_slash;
75 size_t len;
76 size_t dir_size; 76 size_t dir_size;
77 77
78 last_slash = dso->long_name + dso->long_name_len; 78 last_slash = dso->long_name + dso->long_name_len;
79 while (last_slash != dso->long_name && *last_slash != '/') 79 while (last_slash != dso->long_name && *last_slash != '/')
80 last_slash--; 80 last_slash--;
81 81
82 len = scnprintf(filename, size, "%s", symbol_conf.symfs); 82 len = __symbol__join_symfs(filename, size, "");
83 dir_size = last_slash - dso->long_name + 2; 83 dir_size = last_slash - dso->long_name + 2;
84 if (dir_size > (size - len)) { 84 if (dir_size > (size - len)) {
85 ret = -1; 85 ret = -1;
@@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso,
100 build_id__sprintf(dso->build_id, 100 build_id__sprintf(dso->build_id,
101 sizeof(dso->build_id), 101 sizeof(dso->build_id),
102 build_id_hex); 102 build_id_hex);
103 snprintf(filename, size, 103 len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
104 "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 104 snprintf(filename + len, size - len, "%.2s/%s.debug",
105 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 105 build_id_hex, build_id_hex + 2);
106 break; 106 break;
107 107
108 case DSO_BINARY_TYPE__VMLINUX: 108 case DSO_BINARY_TYPE__VMLINUX:
109 case DSO_BINARY_TYPE__GUEST_VMLINUX: 109 case DSO_BINARY_TYPE__GUEST_VMLINUX:
110 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 110 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
111 snprintf(filename, size, "%s%s", 111 __symbol__join_symfs(filename, size, dso->long_name);
112 symbol_conf.symfs, dso->long_name);
113 break; 112 break;
114 113
115 case DSO_BINARY_TYPE__GUEST_KMODULE: 114 case DSO_BINARY_TYPE__GUEST_KMODULE:
116 snprintf(filename, size, "%s%s%s", symbol_conf.symfs, 115 path__join3(filename, size, symbol_conf.symfs,
117 root_dir, dso->long_name); 116 root_dir, dso->long_name);
118 break; 117 break;
119 118
120 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 119 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
121 snprintf(filename, size, "%s%s", symbol_conf.symfs, 120 __symbol__join_symfs(filename, size, dso->long_name);
122 dso->long_name);
123 break; 121 break;
124 122
125 case DSO_BINARY_TYPE__KCORE: 123 case DSO_BINARY_TYPE__KCORE:
@@ -164,13 +162,15 @@ static void close_first_dso(void);
164static int do_open(char *name) 162static int do_open(char *name)
165{ 163{
166 int fd; 164 int fd;
165 char sbuf[STRERR_BUFSIZE];
167 166
168 do { 167 do {
169 fd = open(name, O_RDONLY); 168 fd = open(name, O_RDONLY);
170 if (fd >= 0) 169 if (fd >= 0)
171 return fd; 170 return fd;
172 171
173 pr_debug("dso open failed, mmap: %s\n", strerror(errno)); 172 pr_debug("dso open failed, mmap: %s\n",
173 strerror_r(errno, sbuf, sizeof(sbuf)));
174 if (!dso__data_open_cnt || errno != EMFILE) 174 if (!dso__data_open_cnt || errno != EMFILE)
175 break; 175 break;
176 176
@@ -532,10 +532,12 @@ static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
532static int data_file_size(struct dso *dso) 532static int data_file_size(struct dso *dso)
533{ 533{
534 struct stat st; 534 struct stat st;
535 char sbuf[STRERR_BUFSIZE];
535 536
536 if (!dso->data.file_size) { 537 if (!dso->data.file_size) {
537 if (fstat(dso->data.fd, &st)) { 538 if (fstat(dso->data.fd, &st)) {
538 pr_err("dso mmap failed, fstat: %s\n", strerror(errno)); 539 pr_err("dso mmap failed, fstat: %s\n",
540 strerror_r(errno, sbuf, sizeof(sbuf)));
539 return -1; 541 return -1;
540 } 542 }
541 dso->data.file_size = st.st_size; 543 dso->data.file_size = st.st_size;
@@ -651,6 +653,65 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
651 return dso; 653 return dso;
652} 654}
653 655
656/*
657 * Find a matching entry and/or link current entry to RB tree.
658 * Either one of the dso or name parameter must be non-NULL or the
659 * function will not work.
660 */
661static struct dso *dso__findlink_by_longname(struct rb_root *root,
662 struct dso *dso, const char *name)
663{
664 struct rb_node **p = &root->rb_node;
665 struct rb_node *parent = NULL;
666
667 if (!name)
668 name = dso->long_name;
669 /*
670 * Find node with the matching name
671 */
672 while (*p) {
673 struct dso *this = rb_entry(*p, struct dso, rb_node);
674 int rc = strcmp(name, this->long_name);
675
676 parent = *p;
677 if (rc == 0) {
678 /*
679 * In case the new DSO is a duplicate of an existing
680 * one, print an one-time warning & put the new entry
681 * at the end of the list of duplicates.
682 */
683 if (!dso || (dso == this))
684 return this; /* Find matching dso */
685 /*
686 * The core kernel DSOs may have duplicated long name.
687 * In this case, the short name should be different.
688 * Comparing the short names to differentiate the DSOs.
689 */
690 rc = strcmp(dso->short_name, this->short_name);
691 if (rc == 0) {
692 pr_err("Duplicated dso name: %s\n", name);
693 return NULL;
694 }
695 }
696 if (rc < 0)
697 p = &parent->rb_left;
698 else
699 p = &parent->rb_right;
700 }
701 if (dso) {
702 /* Add new node and rebalance tree */
703 rb_link_node(&dso->rb_node, parent, p);
704 rb_insert_color(&dso->rb_node, root);
705 }
706 return NULL;
707}
708
709static inline struct dso *
710dso__find_by_longname(const struct rb_root *root, const char *name)
711{
712 return dso__findlink_by_longname((struct rb_root *)root, NULL, name);
713}
714
654void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) 715void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
655{ 716{
656 if (name == NULL) 717 if (name == NULL)
@@ -753,6 +814,7 @@ struct dso *dso__new(const char *name)
753 dso->a2l_fails = 1; 814 dso->a2l_fails = 1;
754 dso->kernel = DSO_TYPE_USER; 815 dso->kernel = DSO_TYPE_USER;
755 dso->needs_swap = DSO_SWAP__UNSET; 816 dso->needs_swap = DSO_SWAP__UNSET;
817 RB_CLEAR_NODE(&dso->rb_node);
756 INIT_LIST_HEAD(&dso->node); 818 INIT_LIST_HEAD(&dso->node);
757 INIT_LIST_HEAD(&dso->data.open_entry); 819 INIT_LIST_HEAD(&dso->data.open_entry);
758 } 820 }
@@ -763,6 +825,10 @@ struct dso *dso__new(const char *name)
763void dso__delete(struct dso *dso) 825void dso__delete(struct dso *dso)
764{ 826{
765 int i; 827 int i;
828
829 if (!RB_EMPTY_NODE(&dso->rb_node))
830 pr_err("DSO %s is still in rbtree when being deleted!\n",
831 dso->long_name);
766 for (i = 0; i < MAP__NR_TYPES; ++i) 832 for (i = 0; i < MAP__NR_TYPES; ++i)
767 symbols__delete(&dso->symbols[i]); 833 symbols__delete(&dso->symbols[i]);
768 834
@@ -849,35 +915,34 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
849 return have_build_id; 915 return have_build_id;
850} 916}
851 917
852void dsos__add(struct list_head *head, struct dso *dso) 918void dsos__add(struct dsos *dsos, struct dso *dso)
853{ 919{
854 list_add_tail(&dso->node, head); 920 list_add_tail(&dso->node, &dsos->head);
921 dso__findlink_by_longname(&dsos->root, dso, NULL);
855} 922}
856 923
857struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short) 924struct dso *dsos__find(const struct dsos *dsos, const char *name,
925 bool cmp_short)
858{ 926{
859 struct dso *pos; 927 struct dso *pos;
860 928
861 if (cmp_short) { 929 if (cmp_short) {
862 list_for_each_entry(pos, head, node) 930 list_for_each_entry(pos, &dsos->head, node)
863 if (strcmp(pos->short_name, name) == 0) 931 if (strcmp(pos->short_name, name) == 0)
864 return pos; 932 return pos;
865 return NULL; 933 return NULL;
866 } 934 }
867 list_for_each_entry(pos, head, node) 935 return dso__find_by_longname(&dsos->root, name);
868 if (strcmp(pos->long_name, name) == 0)
869 return pos;
870 return NULL;
871} 936}
872 937
873struct dso *__dsos__findnew(struct list_head *head, const char *name) 938struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
874{ 939{
875 struct dso *dso = dsos__find(head, name, false); 940 struct dso *dso = dsos__find(dsos, name, false);
876 941
877 if (!dso) { 942 if (!dso) {
878 dso = dso__new(name); 943 dso = dso__new(name);
879 if (dso != NULL) { 944 if (dso != NULL) {
880 dsos__add(head, dso); 945 dsos__add(dsos, dso);
881 dso__set_basename(dso); 946 dso__set_basename(dso);
882 } 947 }
883 } 948 }
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 5e463c0964d4..acb651acc7fd 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -90,8 +90,18 @@ struct dso_cache {
90 char data[0]; 90 char data[0];
91}; 91};
92 92
93/*
94 * DSOs are put into both a list for fast iteration and rbtree for fast
95 * long name lookup.
96 */
97struct dsos {
98 struct list_head head;
99 struct rb_root root; /* rbtree root sorted by long name */
100};
101
93struct dso { 102struct dso {
94 struct list_head node; 103 struct list_head node;
104 struct rb_node rb_node; /* rbtree node sorted by long name */
95 struct rb_root symbols[MAP__NR_TYPES]; 105 struct rb_root symbols[MAP__NR_TYPES];
96 struct rb_root symbol_names[MAP__NR_TYPES]; 106 struct rb_root symbol_names[MAP__NR_TYPES];
97 void *a2l; 107 void *a2l;
@@ -224,10 +234,10 @@ struct map *dso__new_map(const char *name);
224struct dso *dso__kernel_findnew(struct machine *machine, const char *name, 234struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
225 const char *short_name, int dso_type); 235 const char *short_name, int dso_type);
226 236
227void dsos__add(struct list_head *head, struct dso *dso); 237void dsos__add(struct dsos *dsos, struct dso *dso);
228struct dso *dsos__find(const struct list_head *head, const char *name, 238struct dso *dsos__find(const struct dsos *dsos, const char *name,
229 bool cmp_short); 239 bool cmp_short);
230struct dso *__dsos__findnew(struct list_head *head, const char *name); 240struct dso *__dsos__findnew(struct dsos *dsos, const char *name);
231bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 241bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
232 242
233size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 243size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1398c83d896d..4af6b279e34a 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -558,13 +558,17 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
558 struct map *map; 558 struct map *map;
559 struct kmap *kmap; 559 struct kmap *kmap;
560 int err; 560 int err;
561 union perf_event *event;
562
563 if (machine->vmlinux_maps[0] == NULL)
564 return -1;
565
561 /* 566 /*
562 * We should get this from /sys/kernel/sections/.text, but till that is 567 * We should get this from /sys/kernel/sections/.text, but till that is
563 * available use this, and after it is use this as a fallback for older 568 * available use this, and after it is use this as a fallback for older
564 * kernels. 569 * kernels.
565 */ 570 */
566 union perf_event *event = zalloc((sizeof(event->mmap) + 571 event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
567 machine->id_hdr_size));
568 if (event == NULL) { 572 if (event == NULL) {
569 pr_debug("Not enough memory synthesizing mmap event " 573 pr_debug("Not enough memory synthesizing mmap event "
570 "for kernel modules\n"); 574 "for kernel modules\n");
@@ -784,9 +788,9 @@ try_again:
784 * "[vdso]" dso, but for now lets use the old trick of looking 788 * "[vdso]" dso, but for now lets use the old trick of looking
785 * in the whole kernel symbol list. 789 * in the whole kernel symbol list.
786 */ 790 */
787 if ((long long)al->addr < 0 && 791 if (cpumode == PERF_RECORD_MISC_USER && machine &&
788 cpumode == PERF_RECORD_MISC_USER && 792 mg != &machine->kmaps &&
789 machine && mg != &machine->kmaps) { 793 machine__kernel_ip(machine, al->addr)) {
790 mg = &machine->kmaps; 794 mg = &machine->kmaps;
791 load_map = true; 795 load_map = true;
792 goto try_again; 796 goto try_again;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 94d6976180da..7eb7107731ec 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -156,6 +156,8 @@ struct perf_sample {
156 u32 cpu; 156 u32 cpu;
157 u32 raw_size; 157 u32 raw_size;
158 u64 data_src; 158 u64 data_src;
159 u32 flags;
160 u16 insn_len;
159 void *raw_data; 161 void *raw_data;
160 struct ip_callchain *callchain; 162 struct ip_callchain *callchain;
161 struct branch_stack *branch_stack; 163 struct branch_stack *branch_stack;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 814e954c1318..3cebc9a8d52e 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -25,6 +25,9 @@
25#include <linux/bitops.h> 25#include <linux/bitops.h>
26#include <linux/hash.h> 26#include <linux/hash.h>
27 27
28static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx);
29static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx);
30
28#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 31#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
29#define SID(e, x, y) xyarray__entry(e->sample_id, x, y) 32#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
30 33
@@ -37,6 +40,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
37 INIT_HLIST_HEAD(&evlist->heads[i]); 40 INIT_HLIST_HEAD(&evlist->heads[i]);
38 INIT_LIST_HEAD(&evlist->entries); 41 INIT_LIST_HEAD(&evlist->entries);
39 perf_evlist__set_maps(evlist, cpus, threads); 42 perf_evlist__set_maps(evlist, cpus, threads);
43 fdarray__init(&evlist->pollfd, 64);
40 evlist->workload.pid = -1; 44 evlist->workload.pid = -1;
41} 45}
42 46
@@ -102,7 +106,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
102void perf_evlist__exit(struct perf_evlist *evlist) 106void perf_evlist__exit(struct perf_evlist *evlist)
103{ 107{
104 zfree(&evlist->mmap); 108 zfree(&evlist->mmap);
105 zfree(&evlist->pollfd); 109 fdarray__exit(&evlist->pollfd);
106} 110}
107 111
108void perf_evlist__delete(struct perf_evlist *evlist) 112void perf_evlist__delete(struct perf_evlist *evlist)
@@ -122,6 +126,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
122{ 126{
123 list_add_tail(&entry->node, &evlist->entries); 127 list_add_tail(&entry->node, &evlist->entries);
124 entry->idx = evlist->nr_entries; 128 entry->idx = evlist->nr_entries;
129 entry->tracking = !entry->idx;
125 130
126 if (!evlist->nr_entries++) 131 if (!evlist->nr_entries++)
127 perf_evlist__set_id_pos(evlist); 132 perf_evlist__set_id_pos(evlist);
@@ -265,17 +270,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist,
265 return 0; 270 return 0;
266} 271}
267 272
273static int perf_evlist__nr_threads(struct perf_evlist *evlist,
274 struct perf_evsel *evsel)
275{
276 if (evsel->system_wide)
277 return 1;
278 else
279 return thread_map__nr(evlist->threads);
280}
281
268void perf_evlist__disable(struct perf_evlist *evlist) 282void perf_evlist__disable(struct perf_evlist *evlist)
269{ 283{
270 int cpu, thread; 284 int cpu, thread;
271 struct perf_evsel *pos; 285 struct perf_evsel *pos;
272 int nr_cpus = cpu_map__nr(evlist->cpus); 286 int nr_cpus = cpu_map__nr(evlist->cpus);
273 int nr_threads = thread_map__nr(evlist->threads); 287 int nr_threads;
274 288
275 for (cpu = 0; cpu < nr_cpus; cpu++) { 289 for (cpu = 0; cpu < nr_cpus; cpu++) {
276 evlist__for_each(evlist, pos) { 290 evlist__for_each(evlist, pos) {
277 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 291 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
278 continue; 292 continue;
293 nr_threads = perf_evlist__nr_threads(evlist, pos);
279 for (thread = 0; thread < nr_threads; thread++) 294 for (thread = 0; thread < nr_threads; thread++)
280 ioctl(FD(pos, cpu, thread), 295 ioctl(FD(pos, cpu, thread),
281 PERF_EVENT_IOC_DISABLE, 0); 296 PERF_EVENT_IOC_DISABLE, 0);
@@ -288,12 +303,13 @@ void perf_evlist__enable(struct perf_evlist *evlist)
288 int cpu, thread; 303 int cpu, thread;
289 struct perf_evsel *pos; 304 struct perf_evsel *pos;
290 int nr_cpus = cpu_map__nr(evlist->cpus); 305 int nr_cpus = cpu_map__nr(evlist->cpus);
291 int nr_threads = thread_map__nr(evlist->threads); 306 int nr_threads;
292 307
293 for (cpu = 0; cpu < nr_cpus; cpu++) { 308 for (cpu = 0; cpu < nr_cpus; cpu++) {
294 evlist__for_each(evlist, pos) { 309 evlist__for_each(evlist, pos) {
295 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 310 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
296 continue; 311 continue;
312 nr_threads = perf_evlist__nr_threads(evlist, pos);
297 for (thread = 0; thread < nr_threads; thread++) 313 for (thread = 0; thread < nr_threads; thread++)
298 ioctl(FD(pos, cpu, thread), 314 ioctl(FD(pos, cpu, thread),
299 PERF_EVENT_IOC_ENABLE, 0); 315 PERF_EVENT_IOC_ENABLE, 0);
@@ -305,12 +321,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
305 struct perf_evsel *evsel) 321 struct perf_evsel *evsel)
306{ 322{
307 int cpu, thread, err; 323 int cpu, thread, err;
324 int nr_cpus = cpu_map__nr(evlist->cpus);
325 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
308 326
309 if (!evsel->fd) 327 if (!evsel->fd)
310 return 0; 328 return 0;
311 329
312 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 330 for (cpu = 0; cpu < nr_cpus; cpu++) {
313 for (thread = 0; thread < evlist->threads->nr; thread++) { 331 for (thread = 0; thread < nr_threads; thread++) {
314 err = ioctl(FD(evsel, cpu, thread), 332 err = ioctl(FD(evsel, cpu, thread),
315 PERF_EVENT_IOC_DISABLE, 0); 333 PERF_EVENT_IOC_DISABLE, 0);
316 if (err) 334 if (err)
@@ -324,12 +342,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
324 struct perf_evsel *evsel) 342 struct perf_evsel *evsel)
325{ 343{
326 int cpu, thread, err; 344 int cpu, thread, err;
345 int nr_cpus = cpu_map__nr(evlist->cpus);
346 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
327 347
328 if (!evsel->fd) 348 if (!evsel->fd)
329 return -EINVAL; 349 return -EINVAL;
330 350
331 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 351 for (cpu = 0; cpu < nr_cpus; cpu++) {
332 for (thread = 0; thread < evlist->threads->nr; thread++) { 352 for (thread = 0; thread < nr_threads; thread++) {
333 err = ioctl(FD(evsel, cpu, thread), 353 err = ioctl(FD(evsel, cpu, thread),
334 PERF_EVENT_IOC_ENABLE, 0); 354 PERF_EVENT_IOC_ENABLE, 0);
335 if (err) 355 if (err)
@@ -339,21 +359,111 @@ int perf_evlist__enable_event(struct perf_evlist *evlist,
339 return 0; 359 return 0;
340} 360}
341 361
342static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 362static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
363 struct perf_evsel *evsel, int cpu)
364{
365 int thread, err;
366 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
367
368 if (!evsel->fd)
369 return -EINVAL;
370
371 for (thread = 0; thread < nr_threads; thread++) {
372 err = ioctl(FD(evsel, cpu, thread),
373 PERF_EVENT_IOC_ENABLE, 0);
374 if (err)
375 return err;
376 }
377 return 0;
378}
379
380static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
381 struct perf_evsel *evsel,
382 int thread)
383{
384 int cpu, err;
385 int nr_cpus = cpu_map__nr(evlist->cpus);
386
387 if (!evsel->fd)
388 return -EINVAL;
389
390 for (cpu = 0; cpu < nr_cpus; cpu++) {
391 err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
392 if (err)
393 return err;
394 }
395 return 0;
396}
397
398int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
399 struct perf_evsel *evsel, int idx)
400{
401 bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus);
402
403 if (per_cpu_mmaps)
404 return perf_evlist__enable_event_cpu(evlist, evsel, idx);
405 else
406 return perf_evlist__enable_event_thread(evlist, evsel, idx);
407}
408
409int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
343{ 410{
344 int nr_cpus = cpu_map__nr(evlist->cpus); 411 int nr_cpus = cpu_map__nr(evlist->cpus);
345 int nr_threads = thread_map__nr(evlist->threads); 412 int nr_threads = thread_map__nr(evlist->threads);
346 int nfds = nr_cpus * nr_threads * evlist->nr_entries; 413 int nfds = 0;
347 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 414 struct perf_evsel *evsel;
348 return evlist->pollfd != NULL ? 0 : -ENOMEM; 415
416 list_for_each_entry(evsel, &evlist->entries, node) {
417 if (evsel->system_wide)
418 nfds += nr_cpus;
419 else
420 nfds += nr_cpus * nr_threads;
421 }
422
423 if (fdarray__available_entries(&evlist->pollfd) < nfds &&
424 fdarray__grow(&evlist->pollfd, nfds) < 0)
425 return -ENOMEM;
426
427 return 0;
428}
429
430static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx)
431{
432 int pos = fdarray__add(&evlist->pollfd, fd, POLLIN | POLLERR | POLLHUP);
433 /*
434 * Save the idx so that when we filter out fds POLLHUP'ed we can
435 * close the associated evlist->mmap[] entry.
436 */
437 if (pos >= 0) {
438 evlist->pollfd.priv[pos].idx = idx;
439
440 fcntl(fd, F_SETFL, O_NONBLOCK);
441 }
442
443 return pos;
444}
445
446int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd)
447{
448 return __perf_evlist__add_pollfd(evlist, fd, -1);
449}
450
451static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd)
452{
453 struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd);
454
455 perf_evlist__mmap_put(evlist, fda->priv[fd].idx);
456}
457
458int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask)
459{
460 return fdarray__filter(&evlist->pollfd, revents_and_mask,
461 perf_evlist__munmap_filtered);
349} 462}
350 463
351void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) 464int perf_evlist__poll(struct perf_evlist *evlist, int timeout)
352{ 465{
353 fcntl(fd, F_SETFL, O_NONBLOCK); 466 return fdarray__poll(&evlist->pollfd, timeout);
354 evlist->pollfd[evlist->nr_fds].fd = fd;
355 evlist->pollfd[evlist->nr_fds].events = POLLIN;
356 evlist->nr_fds++;
357} 467}
358 468
359static void perf_evlist__id_hash(struct perf_evlist *evlist, 469static void perf_evlist__id_hash(struct perf_evlist *evlist,
@@ -566,14 +676,36 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
566 return event; 676 return event;
567} 677}
568 678
679static bool perf_mmap__empty(struct perf_mmap *md)
680{
681 return perf_mmap__read_head(md) != md->prev;
682}
683
684static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx)
685{
686 ++evlist->mmap[idx].refcnt;
687}
688
689static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx)
690{
691 BUG_ON(evlist->mmap[idx].refcnt == 0);
692
693 if (--evlist->mmap[idx].refcnt == 0)
694 __perf_evlist__munmap(evlist, idx);
695}
696
569void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) 697void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
570{ 698{
699 struct perf_mmap *md = &evlist->mmap[idx];
700
571 if (!evlist->overwrite) { 701 if (!evlist->overwrite) {
572 struct perf_mmap *md = &evlist->mmap[idx];
573 unsigned int old = md->prev; 702 unsigned int old = md->prev;
574 703
575 perf_mmap__write_tail(md, old); 704 perf_mmap__write_tail(md, old);
576 } 705 }
706
707 if (md->refcnt == 1 && perf_mmap__empty(md))
708 perf_evlist__mmap_put(evlist, idx);
577} 709}
578 710
579static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) 711static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
@@ -581,6 +713,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
581 if (evlist->mmap[idx].base != NULL) { 713 if (evlist->mmap[idx].base != NULL) {
582 munmap(evlist->mmap[idx].base, evlist->mmap_len); 714 munmap(evlist->mmap[idx].base, evlist->mmap_len);
583 evlist->mmap[idx].base = NULL; 715 evlist->mmap[idx].base = NULL;
716 evlist->mmap[idx].refcnt = 0;
584 } 717 }
585} 718}
586 719
@@ -614,6 +747,20 @@ struct mmap_params {
614static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, 747static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
615 struct mmap_params *mp, int fd) 748 struct mmap_params *mp, int fd)
616{ 749{
750 /*
751 * The last one will be done at perf_evlist__mmap_consume(), so that we
752 * make sure we don't prevent tools from consuming every last event in
753 * the ring buffer.
754 *
755 * I.e. we can get the POLLHUP meaning that the fd doesn't exist
756 * anymore, but the last events for it are still in the ring buffer,
757 * waiting to be consumed.
758 *
759 * Tools can chose to ignore this at their own discretion, but the
760 * evlist layer can't just drop it when filtering events in
761 * perf_evlist__filter_pollfd().
762 */
763 evlist->mmap[idx].refcnt = 2;
617 evlist->mmap[idx].prev = 0; 764 evlist->mmap[idx].prev = 0;
618 evlist->mmap[idx].mask = mp->mask; 765 evlist->mmap[idx].mask = mp->mask;
619 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, 766 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
@@ -625,7 +772,6 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
625 return -1; 772 return -1;
626 } 773 }
627 774
628 perf_evlist__add_pollfd(evlist, fd);
629 return 0; 775 return 0;
630} 776}
631 777
@@ -636,7 +782,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
636 struct perf_evsel *evsel; 782 struct perf_evsel *evsel;
637 783
638 evlist__for_each(evlist, evsel) { 784 evlist__for_each(evlist, evsel) {
639 int fd = FD(evsel, cpu, thread); 785 int fd;
786
787 if (evsel->system_wide && thread)
788 continue;
789
790 fd = FD(evsel, cpu, thread);
640 791
641 if (*output == -1) { 792 if (*output == -1) {
642 *output = fd; 793 *output = fd;
@@ -645,6 +796,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
645 } else { 796 } else {
646 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) 797 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
647 return -1; 798 return -1;
799
800 perf_evlist__mmap_get(evlist, idx);
801 }
802
803 if (__perf_evlist__add_pollfd(evlist, fd, idx) < 0) {
804 perf_evlist__mmap_put(evlist, idx);
805 return -1;
648 } 806 }
649 807
650 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 808 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -804,7 +962,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
804 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 962 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
805 return -ENOMEM; 963 return -ENOMEM;
806 964
807 if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0) 965 if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
808 return -ENOMEM; 966 return -ENOMEM;
809 967
810 evlist->overwrite = overwrite; 968 evlist->overwrite = overwrite;
@@ -1061,6 +1219,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
1061 } 1219 }
1062 1220
1063 if (!evlist->workload.pid) { 1221 if (!evlist->workload.pid) {
1222 int ret;
1223
1064 if (pipe_output) 1224 if (pipe_output)
1065 dup2(2, 1); 1225 dup2(2, 1);
1066 1226
@@ -1078,8 +1238,22 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
1078 /* 1238 /*
1079 * Wait until the parent tells us to go. 1239 * Wait until the parent tells us to go.
1080 */ 1240 */
1081 if (read(go_pipe[0], &bf, 1) == -1) 1241 ret = read(go_pipe[0], &bf, 1);
1082 perror("unable to read pipe"); 1242 /*
1243 * The parent will ask for the execvp() to be performed by
1244 * writing exactly one byte, in workload.cork_fd, usually via
1245 * perf_evlist__start_workload().
1246 *
1247 * For cancelling the workload without actuallin running it,
1248 * the parent will just close workload.cork_fd, without writing
1249 * anything, i.e. read will return zero and we just exit()
1250 * here.
1251 */
1252 if (ret != 1) {
1253 if (ret == -1)
1254 perror("unable to read pipe");
1255 exit(ret);
1256 }
1083 1257
1084 execvp(argv[0], (char **)argv); 1258 execvp(argv[0], (char **)argv);
1085 1259
@@ -1202,7 +1376,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1202 int err, char *buf, size_t size) 1376 int err, char *buf, size_t size)
1203{ 1377{
1204 int printed, value; 1378 int printed, value;
1205 char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf)); 1379 char sbuf[STRERR_BUFSIZE], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
1206 1380
1207 switch (err) { 1381 switch (err) {
1208 case EACCES: 1382 case EACCES:
@@ -1250,3 +1424,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
1250 1424
1251 list_splice(&move, &evlist->entries); 1425 list_splice(&move, &evlist->entries);
1252} 1426}
1427
1428void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
1429 struct perf_evsel *tracking_evsel)
1430{
1431 struct perf_evsel *evsel;
1432
1433 if (tracking_evsel->tracking)
1434 return;
1435
1436 evlist__for_each(evlist, evsel) {
1437 if (evsel != tracking_evsel)
1438 evsel->tracking = false;
1439 }
1440
1441 tracking_evsel->tracking = true;
1442}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index f5173cd63693..bd312b01e876 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -2,6 +2,7 @@
2#define __PERF_EVLIST_H 1 2#define __PERF_EVLIST_H 1
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include <api/fd/array.h>
5#include <stdio.h> 6#include <stdio.h>
6#include "../perf.h" 7#include "../perf.h"
7#include "event.h" 8#include "event.h"
@@ -17,9 +18,15 @@ struct record_opts;
17#define PERF_EVLIST__HLIST_BITS 8 18#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 19#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
19 20
21/**
22 * struct perf_mmap - perf's ring buffer mmap details
23 *
24 * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this
25 */
20struct perf_mmap { 26struct perf_mmap {
21 void *base; 27 void *base;
22 int mask; 28 int mask;
29 int refcnt;
23 unsigned int prev; 30 unsigned int prev;
24 char event_copy[PERF_SAMPLE_MAX_SIZE]; 31 char event_copy[PERF_SAMPLE_MAX_SIZE];
25}; 32};
@@ -29,7 +36,6 @@ struct perf_evlist {
29 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; 36 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
30 int nr_entries; 37 int nr_entries;
31 int nr_groups; 38 int nr_groups;
32 int nr_fds;
33 int nr_mmaps; 39 int nr_mmaps;
34 size_t mmap_len; 40 size_t mmap_len;
35 int id_pos; 41 int id_pos;
@@ -40,8 +46,8 @@ struct perf_evlist {
40 pid_t pid; 46 pid_t pid;
41 } workload; 47 } workload;
42 bool overwrite; 48 bool overwrite;
49 struct fdarray pollfd;
43 struct perf_mmap *mmap; 50 struct perf_mmap *mmap;
44 struct pollfd *pollfd;
45 struct thread_map *threads; 51 struct thread_map *threads;
46 struct cpu_map *cpus; 52 struct cpu_map *cpus;
47 struct perf_evsel *selected; 53 struct perf_evsel *selected;
@@ -82,7 +88,11 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
82void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 88void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
83 int cpu, int thread, u64 id); 89 int cpu, int thread, u64 id);
84 90
85void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); 91int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
92int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
93int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask);
94
95int perf_evlist__poll(struct perf_evlist *evlist, int timeout);
86 96
87struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); 97struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
88 98
@@ -122,6 +132,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist,
122 struct perf_evsel *evsel); 132 struct perf_evsel *evsel);
123int perf_evlist__enable_event(struct perf_evlist *evlist, 133int perf_evlist__enable_event(struct perf_evlist *evlist,
124 struct perf_evsel *evsel); 134 struct perf_evsel *evsel);
135int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
136 struct perf_evsel *evsel, int idx);
125 137
126void perf_evlist__set_selected(struct perf_evlist *evlist, 138void perf_evlist__set_selected(struct perf_evlist *evlist,
127 struct perf_evsel *evsel); 139 struct perf_evsel *evsel);
@@ -262,4 +274,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
262#define evlist__for_each_safe(evlist, tmp, evsel) \ 274#define evlist__for_each_safe(evlist, tmp, evsel) \
263 __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) 275 __evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
264 276
277void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
278 struct perf_evsel *tracking_evsel);
279
265#endif /* __PERF_EVLIST_H */ 280#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 21a373ebea22..e0868a901c4a 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
162 struct perf_event_attr *attr, int idx) 162 struct perf_event_attr *attr, int idx)
163{ 163{
164 evsel->idx = idx; 164 evsel->idx = idx;
165 evsel->tracking = !idx;
165 evsel->attr = *attr; 166 evsel->attr = *attr;
166 evsel->leader = evsel; 167 evsel->leader = evsel;
167 evsel->unit = ""; 168 evsel->unit = "";
@@ -502,20 +503,19 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
502} 503}
503 504
504static void 505static void
505perf_evsel__config_callgraph(struct perf_evsel *evsel, 506perf_evsel__config_callgraph(struct perf_evsel *evsel)
506 struct record_opts *opts)
507{ 507{
508 bool function = perf_evsel__is_function_event(evsel); 508 bool function = perf_evsel__is_function_event(evsel);
509 struct perf_event_attr *attr = &evsel->attr; 509 struct perf_event_attr *attr = &evsel->attr;
510 510
511 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 511 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
512 512
513 if (opts->call_graph == CALLCHAIN_DWARF) { 513 if (callchain_param.record_mode == CALLCHAIN_DWARF) {
514 if (!function) { 514 if (!function) {
515 perf_evsel__set_sample_bit(evsel, REGS_USER); 515 perf_evsel__set_sample_bit(evsel, REGS_USER);
516 perf_evsel__set_sample_bit(evsel, STACK_USER); 516 perf_evsel__set_sample_bit(evsel, STACK_USER);
517 attr->sample_regs_user = PERF_REGS_MASK; 517 attr->sample_regs_user = PERF_REGS_MASK;
518 attr->sample_stack_user = opts->stack_dump_size; 518 attr->sample_stack_user = callchain_param.dump_size;
519 attr->exclude_callchain_user = 1; 519 attr->exclude_callchain_user = 1;
520 } else { 520 } else {
521 pr_info("Cannot use DWARF unwind for function trace event," 521 pr_info("Cannot use DWARF unwind for function trace event,"
@@ -561,7 +561,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
561{ 561{
562 struct perf_evsel *leader = evsel->leader; 562 struct perf_evsel *leader = evsel->leader;
563 struct perf_event_attr *attr = &evsel->attr; 563 struct perf_event_attr *attr = &evsel->attr;
564 int track = !evsel->idx; /* only the first counter needs these */ 564 int track = evsel->tracking;
565 bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; 565 bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
566 566
567 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; 567 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
@@ -624,8 +624,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
624 attr->mmap_data = track; 624 attr->mmap_data = track;
625 } 625 }
626 626
627 if (opts->call_graph_enabled && !evsel->no_aux_samples) 627 if (callchain_param.enabled && !evsel->no_aux_samples)
628 perf_evsel__config_callgraph(evsel, opts); 628 perf_evsel__config_callgraph(evsel);
629 629
630 if (target__has_cpu(&opts->target)) 630 if (target__has_cpu(&opts->target))
631 perf_evsel__set_sample_bit(evsel, CPU); 631 perf_evsel__set_sample_bit(evsel, CPU);
@@ -633,9 +633,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
633 if (opts->period) 633 if (opts->period)
634 perf_evsel__set_sample_bit(evsel, PERIOD); 634 perf_evsel__set_sample_bit(evsel, PERIOD);
635 635
636 if (!perf_missing_features.sample_id_all && 636 /*
637 (opts->sample_time || !opts->no_inherit || 637 * When the user explicitely disabled time don't force it here.
638 target__has_cpu(&opts->target) || per_cpu)) 638 */
639 if (opts->sample_time &&
640 (!perf_missing_features.sample_id_all &&
641 (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu)))
639 perf_evsel__set_sample_bit(evsel, TIME); 642 perf_evsel__set_sample_bit(evsel, TIME);
640 643
641 if (opts->raw_samples && !evsel->no_aux_samples) { 644 if (opts->raw_samples && !evsel->no_aux_samples) {
@@ -692,6 +695,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
692int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 695int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
693{ 696{
694 int cpu, thread; 697 int cpu, thread;
698
699 if (evsel->system_wide)
700 nthreads = 1;
701
695 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 702 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
696 703
697 if (evsel->fd) { 704 if (evsel->fd) {
@@ -710,6 +717,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
710{ 717{
711 int cpu, thread; 718 int cpu, thread;
712 719
720 if (evsel->system_wide)
721 nthreads = 1;
722
713 for (cpu = 0; cpu < ncpus; cpu++) { 723 for (cpu = 0; cpu < ncpus; cpu++) {
714 for (thread = 0; thread < nthreads; thread++) { 724 for (thread = 0; thread < nthreads; thread++) {
715 int fd = FD(evsel, cpu, thread), 725 int fd = FD(evsel, cpu, thread),
@@ -740,6 +750,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
740 750
741int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 751int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
742{ 752{
753 if (evsel->system_wide)
754 nthreads = 1;
755
743 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); 756 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
744 if (evsel->sample_id == NULL) 757 if (evsel->sample_id == NULL)
745 return -ENOMEM; 758 return -ENOMEM;
@@ -784,6 +797,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
784{ 797{
785 int cpu, thread; 798 int cpu, thread;
786 799
800 if (evsel->system_wide)
801 nthreads = 1;
802
787 for (cpu = 0; cpu < ncpus; cpu++) 803 for (cpu = 0; cpu < ncpus; cpu++)
788 for (thread = 0; thread < nthreads; ++thread) { 804 for (thread = 0; thread < nthreads; ++thread) {
789 close(FD(evsel, cpu, thread)); 805 close(FD(evsel, cpu, thread));
@@ -872,6 +888,9 @@ int __perf_evsel__read(struct perf_evsel *evsel,
872 int cpu, thread; 888 int cpu, thread;
873 struct perf_counts_values *aggr = &evsel->counts->aggr, count; 889 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
874 890
891 if (evsel->system_wide)
892 nthreads = 1;
893
875 aggr->val = aggr->ena = aggr->run = 0; 894 aggr->val = aggr->ena = aggr->run = 0;
876 895
877 for (cpu = 0; cpu < ncpus; cpu++) { 896 for (cpu = 0; cpu < ncpus; cpu++) {
@@ -994,13 +1013,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
994static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 1013static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
995 struct thread_map *threads) 1014 struct thread_map *threads)
996{ 1015{
997 int cpu, thread; 1016 int cpu, thread, nthreads;
998 unsigned long flags = PERF_FLAG_FD_CLOEXEC; 1017 unsigned long flags = PERF_FLAG_FD_CLOEXEC;
999 int pid = -1, err; 1018 int pid = -1, err;
1000 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; 1019 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
1001 1020
1021 if (evsel->system_wide)
1022 nthreads = 1;
1023 else
1024 nthreads = threads->nr;
1025
1002 if (evsel->fd == NULL && 1026 if (evsel->fd == NULL &&
1003 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 1027 perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0)
1004 return -ENOMEM; 1028 return -ENOMEM;
1005 1029
1006 if (evsel->cgrp) { 1030 if (evsel->cgrp) {
@@ -1024,10 +1048,10 @@ retry_sample_id:
1024 1048
1025 for (cpu = 0; cpu < cpus->nr; cpu++) { 1049 for (cpu = 0; cpu < cpus->nr; cpu++) {
1026 1050
1027 for (thread = 0; thread < threads->nr; thread++) { 1051 for (thread = 0; thread < nthreads; thread++) {
1028 int group_fd; 1052 int group_fd;
1029 1053
1030 if (!evsel->cgrp) 1054 if (!evsel->cgrp && !evsel->system_wide)
1031 pid = threads->map[thread]; 1055 pid = threads->map[thread];
1032 1056
1033 group_fd = get_group_fd(evsel, cpu, thread); 1057 group_fd = get_group_fd(evsel, cpu, thread);
@@ -1100,7 +1124,7 @@ out_close:
1100 close(FD(evsel, cpu, thread)); 1124 close(FD(evsel, cpu, thread));
1101 FD(evsel, cpu, thread) = -1; 1125 FD(evsel, cpu, thread) = -1;
1102 } 1126 }
1103 thread = threads->nr; 1127 thread = nthreads;
1104 } while (--cpu >= 0); 1128 } while (--cpu >= 0);
1105 return err; 1129 return err;
1106} 1130}
@@ -2002,6 +2026,8 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
2002int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, 2026int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2003 int err, char *msg, size_t size) 2027 int err, char *msg, size_t size)
2004{ 2028{
2029 char sbuf[STRERR_BUFSIZE];
2030
2005 switch (err) { 2031 switch (err) {
2006 case EPERM: 2032 case EPERM:
2007 case EACCES: 2033 case EACCES:
@@ -2036,13 +2062,20 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2036 "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); 2062 "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
2037#endif 2063#endif
2038 break; 2064 break;
2065 case EBUSY:
2066 if (find_process("oprofiled"))
2067 return scnprintf(msg, size,
2068 "The PMU counters are busy/taken by another profiler.\n"
2069 "We found oprofile daemon running, please stop it and try again.");
2070 break;
2039 default: 2071 default:
2040 break; 2072 break;
2041 } 2073 }
2042 2074
2043 return scnprintf(msg, size, 2075 return scnprintf(msg, size,
2044 "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n" 2076 "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n"
2045 "/bin/dmesg may provide additional information.\n" 2077 "/bin/dmesg may provide additional information.\n"
2046 "No CONFIG_PERF_EVENTS=y kernel support configured?\n", 2078 "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
2047 err, strerror(err), perf_evsel__name(evsel)); 2079 err, strerror_r(err, sbuf, sizeof(sbuf)),
2080 perf_evsel__name(evsel));
2048} 2081}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index d7f93ce0ebc1..7bc314be6a7b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -85,6 +85,8 @@ struct perf_evsel {
85 bool needs_swap; 85 bool needs_swap;
86 bool no_aux_samples; 86 bool no_aux_samples;
87 bool immediate; 87 bool immediate;
88 bool system_wide;
89 bool tracking;
88 /* parse modifier helper */ 90 /* parse modifier helper */
89 int exclude_GH; 91 int exclude_GH;
90 int nr_members; 92 int nr_members;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 158c787ce0c4..ce0de00399da 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -214,11 +214,11 @@ static int machine__hit_all_dsos(struct machine *machine)
214{ 214{
215 int err; 215 int err;
216 216
217 err = __dsos__hit_all(&machine->kernel_dsos); 217 err = __dsos__hit_all(&machine->kernel_dsos.head);
218 if (err) 218 if (err)
219 return err; 219 return err;
220 220
221 return __dsos__hit_all(&machine->user_dsos); 221 return __dsos__hit_all(&machine->user_dsos.head);
222} 222}
223 223
224int dsos__hit_all(struct perf_session *session) 224int dsos__hit_all(struct perf_session *session)
@@ -288,11 +288,12 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
288 umisc = PERF_RECORD_MISC_GUEST_USER; 288 umisc = PERF_RECORD_MISC_GUEST_USER;
289 } 289 }
290 290
291 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine, 291 err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
292 machine->pid, kmisc, fd); 292 machine->pid, kmisc, fd);
293 if (err == 0) 293 if (err == 0)
294 err = __dsos__write_buildid_table(&machine->user_dsos, machine, 294 err = __dsos__write_buildid_table(&machine->user_dsos.head,
295 machine->pid, umisc, fd); 295 machine, machine->pid, umisc,
296 fd);
296 return err; 297 return err;
297} 298}
298 299
@@ -455,9 +456,10 @@ static int __dsos__cache_build_ids(struct list_head *head,
455 456
456static int machine__cache_build_ids(struct machine *machine, const char *debugdir) 457static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
457{ 458{
458 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine, 459 int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
459 debugdir); 460 debugdir);
460 ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir); 461 ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
462 debugdir);
461 return ret; 463 return ret;
462} 464}
463 465
@@ -483,8 +485,10 @@ static int perf_session__cache_build_ids(struct perf_session *session)
483 485
484static bool machine__read_build_ids(struct machine *machine, bool with_hits) 486static bool machine__read_build_ids(struct machine *machine, bool with_hits)
485{ 487{
486 bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); 488 bool ret;
487 ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); 489
490 ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
491 ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
488 return ret; 492 return ret;
489} 493}
490 494
@@ -1548,7 +1552,7 @@ static int __event_process_build_id(struct build_id_event *bev,
1548 struct perf_session *session) 1552 struct perf_session *session)
1549{ 1553{
1550 int err = -1; 1554 int err = -1;
1551 struct list_head *head; 1555 struct dsos *dsos;
1552 struct machine *machine; 1556 struct machine *machine;
1553 u16 misc; 1557 u16 misc;
1554 struct dso *dso; 1558 struct dso *dso;
@@ -1563,22 +1567,22 @@ static int __event_process_build_id(struct build_id_event *bev,
1563 switch (misc) { 1567 switch (misc) {
1564 case PERF_RECORD_MISC_KERNEL: 1568 case PERF_RECORD_MISC_KERNEL:
1565 dso_type = DSO_TYPE_KERNEL; 1569 dso_type = DSO_TYPE_KERNEL;
1566 head = &machine->kernel_dsos; 1570 dsos = &machine->kernel_dsos;
1567 break; 1571 break;
1568 case PERF_RECORD_MISC_GUEST_KERNEL: 1572 case PERF_RECORD_MISC_GUEST_KERNEL:
1569 dso_type = DSO_TYPE_GUEST_KERNEL; 1573 dso_type = DSO_TYPE_GUEST_KERNEL;
1570 head = &machine->kernel_dsos; 1574 dsos = &machine->kernel_dsos;
1571 break; 1575 break;
1572 case PERF_RECORD_MISC_USER: 1576 case PERF_RECORD_MISC_USER:
1573 case PERF_RECORD_MISC_GUEST_USER: 1577 case PERF_RECORD_MISC_GUEST_USER:
1574 dso_type = DSO_TYPE_USER; 1578 dso_type = DSO_TYPE_USER;
1575 head = &machine->user_dsos; 1579 dsos = &machine->user_dsos;
1576 break; 1580 break;
1577 default: 1581 default:
1578 goto out; 1582 goto out;
1579 } 1583 }
1580 1584
1581 dso = __dsos__findnew(head, filename); 1585 dso = __dsos__findnew(dsos, filename);
1582 if (dso != NULL) { 1586 if (dso != NULL) {
1583 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1587 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1584 1588
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 30df6187ee02..86569fa3651d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -277,6 +277,28 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
277 } 277 }
278} 278}
279 279
280void hists__delete_entries(struct hists *hists)
281{
282 struct rb_node *next = rb_first(&hists->entries);
283 struct hist_entry *n;
284
285 while (next) {
286 n = rb_entry(next, struct hist_entry, rb_node);
287 next = rb_next(&n->rb_node);
288
289 rb_erase(&n->rb_node, &hists->entries);
290
291 if (sort__need_collapse)
292 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
293
294 --hists->nr_entries;
295 if (!n->filtered)
296 --hists->nr_non_filtered_entries;
297
298 hist_entry__free(n);
299 }
300}
301
280/* 302/*
281 * histogram, sorted on item, collects periods 303 * histogram, sorted on item, collects periods
282 */ 304 */
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 742f49a85725..8c9c70e18cbb 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -152,6 +152,7 @@ void hists__output_resort(struct hists *hists);
152void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); 152void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
153 153
154void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 154void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
155void hists__delete_entries(struct hists *hists);
155void hists__output_recalc_col_len(struct hists *hists, int max_rows); 156void hists__output_recalc_col_len(struct hists *hists, int max_rows);
156 157
157u64 hists__total_period(struct hists *hists); 158u64 hists__total_period(struct hists *hists);
@@ -192,6 +193,7 @@ struct perf_hpp {
192}; 193};
193 194
194struct perf_hpp_fmt { 195struct perf_hpp_fmt {
196 const char *name;
195 int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 197 int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
196 struct perf_evsel *evsel); 198 struct perf_evsel *evsel);
197 int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 199 int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -207,6 +209,8 @@ struct perf_hpp_fmt {
207 struct list_head list; 209 struct list_head list;
208 struct list_head sort_list; 210 struct list_head sort_list;
209 bool elide; 211 bool elide;
212 int len;
213 int user_len;
210}; 214};
211 215
212extern struct list_head perf_hpp__list; 216extern struct list_head perf_hpp__list;
@@ -261,17 +265,19 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
261} 265}
262 266
263void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); 267void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
268void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists);
269void perf_hpp__set_user_width(const char *width_list_str);
264 270
265typedef u64 (*hpp_field_fn)(struct hist_entry *he); 271typedef u64 (*hpp_field_fn)(struct hist_entry *he);
266typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); 272typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
267typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); 273typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
268 274
269int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 275int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
270 hpp_field_fn get_field, const char *fmt, 276 struct hist_entry *he, hpp_field_fn get_field,
271 hpp_snprint_fn print_fn, bool fmt_percent); 277 const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
272int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, 278int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
273 hpp_field_fn get_field, const char *fmt, 279 struct hist_entry *he, hpp_field_fn get_field,
274 hpp_snprint_fn print_fn, bool fmt_percent); 280 const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
275 281
276static inline void advance_hpp(struct perf_hpp *hpp, int inc) 282static inline void advance_hpp(struct perf_hpp *hpp, int inc)
277{ 283{
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index 0b5a8cd2ee79..cf1d7913783b 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -92,7 +92,6 @@ struct perf_kvm_stat {
92 u64 lost_events; 92 u64 lost_events;
93 u64 duration; 93 u64 duration;
94 94
95 const char *pid_str;
96 struct intlist *pid_list; 95 struct intlist *pid_list;
97 96
98 struct rb_root result; 97 struct rb_root result;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 16bba9fff2c8..b7d477fbda02 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -17,8 +17,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
17{ 17{
18 map_groups__init(&machine->kmaps); 18 map_groups__init(&machine->kmaps);
19 RB_CLEAR_NODE(&machine->rb_node); 19 RB_CLEAR_NODE(&machine->rb_node);
20 INIT_LIST_HEAD(&machine->user_dsos); 20 INIT_LIST_HEAD(&machine->user_dsos.head);
21 INIT_LIST_HEAD(&machine->kernel_dsos); 21 INIT_LIST_HEAD(&machine->kernel_dsos.head);
22 22
23 machine->threads = RB_ROOT; 23 machine->threads = RB_ROOT;
24 INIT_LIST_HEAD(&machine->dead_threads); 24 INIT_LIST_HEAD(&machine->dead_threads);
@@ -31,6 +31,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
31 31
32 machine->symbol_filter = NULL; 32 machine->symbol_filter = NULL;
33 machine->id_hdr_size = 0; 33 machine->id_hdr_size = 0;
34 machine->comm_exec = false;
35 machine->kernel_start = 0;
34 36
35 machine->root_dir = strdup(root_dir); 37 machine->root_dir = strdup(root_dir);
36 if (machine->root_dir == NULL) 38 if (machine->root_dir == NULL)
@@ -70,11 +72,12 @@ out_delete:
70 return NULL; 72 return NULL;
71} 73}
72 74
73static void dsos__delete(struct list_head *dsos) 75static void dsos__delete(struct dsos *dsos)
74{ 76{
75 struct dso *pos, *n; 77 struct dso *pos, *n;
76 78
77 list_for_each_entry_safe(pos, n, dsos, node) { 79 list_for_each_entry_safe(pos, n, &dsos->head, node) {
80 RB_CLEAR_NODE(&pos->rb_node);
78 list_del(&pos->node); 81 list_del(&pos->node);
79 dso__delete(pos); 82 dso__delete(pos);
80 } 83 }
@@ -179,6 +182,19 @@ void machines__set_symbol_filter(struct machines *machines,
179 } 182 }
180} 183}
181 184
185void machines__set_comm_exec(struct machines *machines, bool comm_exec)
186{
187 struct rb_node *nd;
188
189 machines->host.comm_exec = comm_exec;
190
191 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
192 struct machine *machine = rb_entry(nd, struct machine, rb_node);
193
194 machine->comm_exec = comm_exec;
195 }
196}
197
182struct machine *machines__find(struct machines *machines, pid_t pid) 198struct machine *machines__find(struct machines *machines, pid_t pid)
183{ 199{
184 struct rb_node **p = &machines->guests.rb_node; 200 struct rb_node **p = &machines->guests.rb_node;
@@ -398,17 +414,31 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
398 return __machine__findnew_thread(machine, pid, tid, false); 414 return __machine__findnew_thread(machine, pid, tid, false);
399} 415}
400 416
417struct comm *machine__thread_exec_comm(struct machine *machine,
418 struct thread *thread)
419{
420 if (machine->comm_exec)
421 return thread__exec_comm(thread);
422 else
423 return thread__comm(thread);
424}
425
401int machine__process_comm_event(struct machine *machine, union perf_event *event, 426int machine__process_comm_event(struct machine *machine, union perf_event *event,
402 struct perf_sample *sample) 427 struct perf_sample *sample)
403{ 428{
404 struct thread *thread = machine__findnew_thread(machine, 429 struct thread *thread = machine__findnew_thread(machine,
405 event->comm.pid, 430 event->comm.pid,
406 event->comm.tid); 431 event->comm.tid);
432 bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC;
433
434 if (exec)
435 machine->comm_exec = true;
407 436
408 if (dump_trace) 437 if (dump_trace)
409 perf_event__fprintf_comm(event, stdout); 438 perf_event__fprintf_comm(event, stdout);
410 439
411 if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) { 440 if (thread == NULL ||
441 __thread__set_comm(thread, event->comm.comm, sample->time, exec)) {
412 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 442 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
413 return -1; 443 return -1;
414 } 444 }
@@ -448,23 +478,23 @@ struct map *machine__new_module(struct machine *machine, u64 start,
448size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) 478size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
449{ 479{
450 struct rb_node *nd; 480 struct rb_node *nd;
451 size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + 481 size_t ret = __dsos__fprintf(&machines->host.kernel_dsos.head, fp) +
452 __dsos__fprintf(&machines->host.user_dsos, fp); 482 __dsos__fprintf(&machines->host.user_dsos.head, fp);
453 483
454 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { 484 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
455 struct machine *pos = rb_entry(nd, struct machine, rb_node); 485 struct machine *pos = rb_entry(nd, struct machine, rb_node);
456 ret += __dsos__fprintf(&pos->kernel_dsos, fp); 486 ret += __dsos__fprintf(&pos->kernel_dsos.head, fp);
457 ret += __dsos__fprintf(&pos->user_dsos, fp); 487 ret += __dsos__fprintf(&pos->user_dsos.head, fp);
458 } 488 }
459 489
460 return ret; 490 return ret;
461} 491}
462 492
463size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 493size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp,
464 bool (skip)(struct dso *dso, int parm), int parm) 494 bool (skip)(struct dso *dso, int parm), int parm)
465{ 495{
466 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + 496 return __dsos__fprintf_buildid(&m->kernel_dsos.head, fp, skip, parm) +
467 __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); 497 __dsos__fprintf_buildid(&m->user_dsos.head, fp, skip, parm);
468} 498}
469 499
470size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, 500size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
@@ -565,8 +595,8 @@ const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
565 * Returns the name of the start symbol in *symbol_name. Pass in NULL as 595 * Returns the name of the start symbol in *symbol_name. Pass in NULL as
566 * symbol_name if it's not that important. 596 * symbol_name if it's not that important.
567 */ 597 */
568static u64 machine__get_kernel_start_addr(struct machine *machine, 598static u64 machine__get_running_kernel_start(struct machine *machine,
569 const char **symbol_name) 599 const char **symbol_name)
570{ 600{
571 char filename[PATH_MAX]; 601 char filename[PATH_MAX];
572 int i; 602 int i;
@@ -593,7 +623,7 @@ static u64 machine__get_kernel_start_addr(struct machine *machine,
593int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 623int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
594{ 624{
595 enum map_type type; 625 enum map_type type;
596 u64 start = machine__get_kernel_start_addr(machine, NULL); 626 u64 start = machine__get_running_kernel_start(machine, NULL);
597 627
598 for (type = 0; type < MAP__NR_TYPES; ++type) { 628 for (type = 0; type < MAP__NR_TYPES; ++type) {
599 struct kmap *kmap; 629 struct kmap *kmap;
@@ -912,7 +942,7 @@ int machine__create_kernel_maps(struct machine *machine)
912{ 942{
913 struct dso *kernel = machine__get_kernel(machine); 943 struct dso *kernel = machine__get_kernel(machine);
914 const char *name; 944 const char *name;
915 u64 addr = machine__get_kernel_start_addr(machine, &name); 945 u64 addr = machine__get_running_kernel_start(machine, &name);
916 if (!addr) 946 if (!addr)
917 return -1; 947 return -1;
918 948
@@ -965,7 +995,7 @@ static bool machine__uses_kcore(struct machine *machine)
965{ 995{
966 struct dso *dso; 996 struct dso *dso;
967 997
968 list_for_each_entry(dso, &machine->kernel_dsos, node) { 998 list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
969 if (dso__is_kcore(dso)) 999 if (dso__is_kcore(dso))
970 return true; 1000 return true;
971 } 1001 }
@@ -1285,6 +1315,16 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
1285 1315
1286 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, 1316 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
1287 &al); 1317 &al);
1318 if (al.map == NULL) {
1319 /*
1320 * some shared data regions have execute bit set which puts
1321 * their mapping in the MAP__FUNCTION type array.
1322 * Check there as a fallback option before dropping the sample.
1323 */
1324 thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr,
1325 &al);
1326 }
1327
1288 ams->addr = addr; 1328 ams->addr = addr;
1289 ams->al_addr = al.addr; 1329 ams->al_addr = al.addr;
1290 ams->sym = al.sym; 1330 ams->sym = al.sym;
@@ -1531,3 +1571,25 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
1531 1571
1532 return 0; 1572 return 0;
1533} 1573}
1574
1575int machine__get_kernel_start(struct machine *machine)
1576{
1577 struct map *map = machine__kernel_map(machine, MAP__FUNCTION);
1578 int err = 0;
1579
1580 /*
1581 * The only addresses above 2^63 are kernel addresses of a 64-bit
1582 * kernel. Note that addresses are unsigned so that on a 32-bit system
1583 * all addresses including kernel addresses are less than 2^32. In
1584 * that case (32-bit system), if the kernel mapping is unknown, all
1585 * addresses will be assumed to be in user space - see
1586 * machine__kernel_ip().
1587 */
1588 machine->kernel_start = 1ULL << 63;
1589 if (map) {
1590 err = map__load(map, machine->symbol_filter);
1591 if (map->start)
1592 machine->kernel_start = map->start;
1593 }
1594 return err;
1595}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index b972824e6294..2b651a7f5d0d 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -4,6 +4,7 @@
4#include <sys/types.h> 4#include <sys/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include "map.h" 6#include "map.h"
7#include "dso.h"
7#include "event.h" 8#include "event.h"
8 9
9struct addr_location; 10struct addr_location;
@@ -26,15 +27,17 @@ struct machine {
26 struct rb_node rb_node; 27 struct rb_node rb_node;
27 pid_t pid; 28 pid_t pid;
28 u16 id_hdr_size; 29 u16 id_hdr_size;
30 bool comm_exec;
29 char *root_dir; 31 char *root_dir;
30 struct rb_root threads; 32 struct rb_root threads;
31 struct list_head dead_threads; 33 struct list_head dead_threads;
32 struct thread *last_match; 34 struct thread *last_match;
33 struct vdso_info *vdso_info; 35 struct vdso_info *vdso_info;
34 struct list_head user_dsos; 36 struct dsos user_dsos;
35 struct list_head kernel_dsos; 37 struct dsos kernel_dsos;
36 struct map_groups kmaps; 38 struct map_groups kmaps;
37 struct map *vmlinux_maps[MAP__NR_TYPES]; 39 struct map *vmlinux_maps[MAP__NR_TYPES];
40 u64 kernel_start;
38 symbol_filter_t symbol_filter; 41 symbol_filter_t symbol_filter;
39 pid_t *current_tid; 42 pid_t *current_tid;
40}; 43};
@@ -45,8 +48,26 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
45 return machine->vmlinux_maps[type]; 48 return machine->vmlinux_maps[type];
46} 49}
47 50
51int machine__get_kernel_start(struct machine *machine);
52
53static inline u64 machine__kernel_start(struct machine *machine)
54{
55 if (!machine->kernel_start)
56 machine__get_kernel_start(machine);
57 return machine->kernel_start;
58}
59
60static inline bool machine__kernel_ip(struct machine *machine, u64 ip)
61{
62 u64 kernel_start = machine__kernel_start(machine);
63
64 return ip >= kernel_start;
65}
66
48struct thread *machine__find_thread(struct machine *machine, pid_t pid, 67struct thread *machine__find_thread(struct machine *machine, pid_t pid,
49 pid_t tid); 68 pid_t tid);
69struct comm *machine__thread_exec_comm(struct machine *machine,
70 struct thread *thread);
50 71
51int machine__process_comm_event(struct machine *machine, union perf_event *event, 72int machine__process_comm_event(struct machine *machine, union perf_event *event,
52 struct perf_sample *sample); 73 struct perf_sample *sample);
@@ -88,6 +109,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
88 109
89void machines__set_symbol_filter(struct machines *machines, 110void machines__set_symbol_filter(struct machines *machines,
90 symbol_filter_t symbol_filter); 111 symbol_filter_t symbol_filter);
112void machines__set_comm_exec(struct machines *machines, bool comm_exec);
91 113
92struct machine *machine__new_host(void); 114struct machine *machine__new_host(void);
93int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 115int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 31b8905dd863..b7090596ac50 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -31,6 +31,7 @@ static inline int is_anon_memory(const char *filename)
31static inline int is_no_dso_memory(const char *filename) 31static inline int is_no_dso_memory(const char *filename)
32{ 32{
33 return !strncmp(filename, "[stack", 6) || 33 return !strncmp(filename, "[stack", 6) ||
34 !strncmp(filename, "/SYSV",5) ||
34 !strcmp(filename, "[heap]"); 35 !strcmp(filename, "[heap]");
35} 36}
36 37
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
new file mode 100644
index 000000000000..706ce1a66169
--- /dev/null
+++ b/tools/perf/util/ordered-events.c
@@ -0,0 +1,245 @@
1#include <linux/list.h>
2#include <linux/compiler.h>
3#include "ordered-events.h"
4#include "evlist.h"
5#include "session.h"
6#include "asm/bug.h"
7#include "debug.h"
8
9#define pr_N(n, fmt, ...) \
10 eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__)
11
12#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
13
14static void queue_event(struct ordered_events *oe, struct ordered_event *new)
15{
16 struct ordered_event *last = oe->last;
17 u64 timestamp = new->timestamp;
18 struct list_head *p;
19
20 ++oe->nr_events;
21 oe->last = new;
22
23 pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events);
24
25 if (!last) {
26 list_add(&new->list, &oe->events);
27 oe->max_timestamp = timestamp;
28 return;
29 }
30
31 /*
32 * last event might point to some random place in the list as it's
33 * the last queued event. We expect that the new event is close to
34 * this.
35 */
36 if (last->timestamp <= timestamp) {
37 while (last->timestamp <= timestamp) {
38 p = last->list.next;
39 if (p == &oe->events) {
40 list_add_tail(&new->list, &oe->events);
41 oe->max_timestamp = timestamp;
42 return;
43 }
44 last = list_entry(p, struct ordered_event, list);
45 }
46 list_add_tail(&new->list, &last->list);
47 } else {
48 while (last->timestamp > timestamp) {
49 p = last->list.prev;
50 if (p == &oe->events) {
51 list_add(&new->list, &oe->events);
52 return;
53 }
54 last = list_entry(p, struct ordered_event, list);
55 }
56 list_add(&new->list, &last->list);
57 }
58}
59
60#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event))
61static struct ordered_event *alloc_event(struct ordered_events *oe)
62{
63 struct list_head *cache = &oe->cache;
64 struct ordered_event *new = NULL;
65
66 if (!list_empty(cache)) {
67 new = list_entry(cache->next, struct ordered_event, list);
68 list_del(&new->list);
69 } else if (oe->buffer) {
70 new = oe->buffer + oe->buffer_idx;
71 if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
72 oe->buffer = NULL;
73 } else if (oe->cur_alloc_size < oe->max_alloc_size) {
74 size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
75
76 oe->buffer = malloc(size);
77 if (!oe->buffer)
78 return NULL;
79
80 pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n",
81 oe->cur_alloc_size, size, oe->max_alloc_size);
82
83 oe->cur_alloc_size += size;
84 list_add(&oe->buffer->list, &oe->to_free);
85
86 /* First entry is abused to maintain the to_free list. */
87 oe->buffer_idx = 2;
88 new = oe->buffer + 1;
89 } else {
90 pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
91 }
92
93 return new;
94}
95
96struct ordered_event *
97ordered_events__new(struct ordered_events *oe, u64 timestamp)
98{
99 struct ordered_event *new;
100
101 new = alloc_event(oe);
102 if (new) {
103 new->timestamp = timestamp;
104 queue_event(oe, new);
105 }
106
107 return new;
108}
109
110void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event)
111{
112 list_move(&event->list, &oe->cache);
113 oe->nr_events--;
114}
115
116static int __ordered_events__flush(struct perf_session *s,
117 struct perf_tool *tool)
118{
119 struct ordered_events *oe = &s->ordered_events;
120 struct list_head *head = &oe->events;
121 struct ordered_event *tmp, *iter;
122 struct perf_sample sample;
123 u64 limit = oe->next_flush;
124 u64 last_ts = oe->last ? oe->last->timestamp : 0ULL;
125 bool show_progress = limit == ULLONG_MAX;
126 struct ui_progress prog;
127 int ret;
128
129 if (!tool->ordered_events || !limit)
130 return 0;
131
132 if (show_progress)
133 ui_progress__init(&prog, oe->nr_events, "Processing time ordered events...");
134
135 list_for_each_entry_safe(iter, tmp, head, list) {
136 if (session_done())
137 return 0;
138
139 if (iter->timestamp > limit)
140 break;
141
142 ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
143 if (ret)
144 pr_err("Can't parse sample, err = %d\n", ret);
145 else {
146 ret = perf_session__deliver_event(s, iter->event, &sample, tool,
147 iter->file_offset);
148 if (ret)
149 return ret;
150 }
151
152 ordered_events__delete(oe, iter);
153 oe->last_flush = iter->timestamp;
154
155 if (show_progress)
156 ui_progress__update(&prog, 1);
157 }
158
159 if (list_empty(head))
160 oe->last = NULL;
161 else if (last_ts <= limit)
162 oe->last = list_entry(head->prev, struct ordered_event, list);
163
164 return 0;
165}
166
167int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
168 enum oe_flush how)
169{
170 struct ordered_events *oe = &s->ordered_events;
171 static const char * const str[] = {
172 "NONE",
173 "FINAL",
174 "ROUND",
175 "HALF ",
176 };
177 int err;
178
179 switch (how) {
180 case OE_FLUSH__FINAL:
181 oe->next_flush = ULLONG_MAX;
182 break;
183
184 case OE_FLUSH__HALF:
185 {
186 struct ordered_event *first, *last;
187 struct list_head *head = &oe->events;
188
189 first = list_entry(head->next, struct ordered_event, list);
190 last = oe->last;
191
192 /* Warn if we are called before any event got allocated. */
193 if (WARN_ONCE(!last || list_empty(head), "empty queue"))
194 return 0;
195
196 oe->next_flush = first->timestamp;
197 oe->next_flush += (last->timestamp - first->timestamp) / 2;
198 break;
199 }
200
201 case OE_FLUSH__ROUND:
202 case OE_FLUSH__NONE:
203 default:
204 break;
205 };
206
207 pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE %s, nr_events %u\n",
208 str[how], oe->nr_events);
209 pr_oe_time(oe->max_timestamp, "max_timestamp\n");
210
211 err = __ordered_events__flush(s, tool);
212
213 if (!err) {
214 if (how == OE_FLUSH__ROUND)
215 oe->next_flush = oe->max_timestamp;
216
217 oe->last_flush_type = how;
218 }
219
220 pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n",
221 str[how], oe->nr_events);
222 pr_oe_time(oe->last_flush, "last_flush\n");
223
224 return err;
225}
226
227void ordered_events__init(struct ordered_events *oe)
228{
229 INIT_LIST_HEAD(&oe->events);
230 INIT_LIST_HEAD(&oe->cache);
231 INIT_LIST_HEAD(&oe->to_free);
232 oe->max_alloc_size = (u64) -1;
233 oe->cur_alloc_size = 0;
234}
235
236void ordered_events__free(struct ordered_events *oe)
237{
238 while (!list_empty(&oe->to_free)) {
239 struct ordered_event *event;
240
241 event = list_entry(oe->to_free.next, struct ordered_event, list);
242 list_del(&event->list);
243 free(event);
244 }
245}
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h
new file mode 100644
index 000000000000..3b2f20542a01
--- /dev/null
+++ b/tools/perf/util/ordered-events.h
@@ -0,0 +1,51 @@
1#ifndef __ORDERED_EVENTS_H
2#define __ORDERED_EVENTS_H
3
4#include <linux/types.h>
5#include "tool.h"
6
7struct perf_session;
8
9struct ordered_event {
10 u64 timestamp;
11 u64 file_offset;
12 union perf_event *event;
13 struct list_head list;
14};
15
16enum oe_flush {
17 OE_FLUSH__NONE,
18 OE_FLUSH__FINAL,
19 OE_FLUSH__ROUND,
20 OE_FLUSH__HALF,
21};
22
23struct ordered_events {
24 u64 last_flush;
25 u64 next_flush;
26 u64 max_timestamp;
27 u64 max_alloc_size;
28 u64 cur_alloc_size;
29 struct list_head events;
30 struct list_head cache;
31 struct list_head to_free;
32 struct ordered_event *buffer;
33 struct ordered_event *last;
34 int buffer_idx;
35 unsigned int nr_events;
36 enum oe_flush last_flush_type;
37};
38
39struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp);
40void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event);
41int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
42 enum oe_flush how);
43void ordered_events__init(struct ordered_events *oe);
44void ordered_events__free(struct ordered_events *oe);
45
46static inline
47void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size)
48{
49 oe->max_alloc_size = size;
50}
51#endif /* __ORDERED_EVENTS_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 1e15df10a88c..d76aa30cb1fb 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -10,6 +10,7 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include "debug.h"
13#include <api/fs/debugfs.h> 14#include <api/fs/debugfs.h>
14#include "parse-events-bison.h" 15#include "parse-events-bison.h"
15#define YY_EXTRA_TYPE int 16#define YY_EXTRA_TYPE int
@@ -633,18 +634,28 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
633 char *name, struct list_head *head_config) 634 char *name, struct list_head *head_config)
634{ 635{
635 struct perf_event_attr attr; 636 struct perf_event_attr attr;
637 struct perf_pmu_info info;
636 struct perf_pmu *pmu; 638 struct perf_pmu *pmu;
637 struct perf_evsel *evsel; 639 struct perf_evsel *evsel;
638 const char *unit;
639 double scale;
640 640
641 pmu = perf_pmu__find(name); 641 pmu = perf_pmu__find(name);
642 if (!pmu) 642 if (!pmu)
643 return -EINVAL; 643 return -EINVAL;
644 644
645 memset(&attr, 0, sizeof(attr)); 645 if (pmu->default_config) {
646 memcpy(&attr, pmu->default_config,
647 sizeof(struct perf_event_attr));
648 } else {
649 memset(&attr, 0, sizeof(attr));
650 }
651
652 if (!head_config) {
653 attr.type = pmu->type;
654 evsel = __add_event(list, idx, &attr, NULL, pmu->cpus);
655 return evsel ? 0 : -ENOMEM;
656 }
646 657
647 if (perf_pmu__check_alias(pmu, head_config, &unit, &scale)) 658 if (perf_pmu__check_alias(pmu, head_config, &info))
648 return -EINVAL; 659 return -EINVAL;
649 660
650 /* 661 /*
@@ -659,8 +670,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
659 evsel = __add_event(list, idx, &attr, pmu_event_name(head_config), 670 evsel = __add_event(list, idx, &attr, pmu_event_name(head_config),
660 pmu->cpus); 671 pmu->cpus);
661 if (evsel) { 672 if (evsel) {
662 evsel->unit = unit; 673 evsel->unit = info.unit;
663 evsel->scale = scale; 674 evsel->scale = info.scale;
664 } 675 }
665 676
666 return evsel ? 0 : -ENOMEM; 677 return evsel ? 0 : -ENOMEM;
@@ -973,7 +984,7 @@ int parse_filter(const struct option *opt, const char *str,
973 984
974 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { 985 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
975 fprintf(stderr, 986 fprintf(stderr,
976 "-F option should follow a -e tracepoint option\n"); 987 "--filter option should follow a -e tracepoint option\n");
977 return -1; 988 return -1;
978 } 989 }
979 990
@@ -1006,9 +1017,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
1006 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 1017 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
1007 char evt_path[MAXPATHLEN]; 1018 char evt_path[MAXPATHLEN];
1008 char dir_path[MAXPATHLEN]; 1019 char dir_path[MAXPATHLEN];
1020 char sbuf[STRERR_BUFSIZE];
1009 1021
1010 if (debugfs_valid_mountpoint(tracing_events_path)) { 1022 if (debugfs_valid_mountpoint(tracing_events_path)) {
1011 printf(" [ Tracepoints not available: %s ]\n", strerror(errno)); 1023 printf(" [ Tracepoints not available: %s ]\n",
1024 strerror_r(errno, sbuf, sizeof(sbuf)));
1012 return; 1025 return;
1013 } 1026 }
1014 1027
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 0bc87ba46bf3..55fab6ad609a 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/'
210 parse_events__free_terms($3); 210 parse_events__free_terms($3);
211 $$ = list; 211 $$ = list;
212} 212}
213|
214PE_NAME '/' '/'
215{
216 struct parse_events_evlist *data = _data;
217 struct list_head *list;
218
219 ALLOC_LIST(list);
220 ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL));
221 $$ = list;
222}
213 223
214value_sym: 224value_sym:
215PE_VALUE_SYM_HW 225PE_VALUE_SYM_HW
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 7a811eb61f75..93a41ca96b8e 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -2,6 +2,8 @@
2#include <sys/types.h> 2#include <sys/types.h>
3#include <unistd.h> 3#include <unistd.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <stdbool.h>
6#include <stdarg.h>
5#include <dirent.h> 7#include <dirent.h>
6#include <api/fs/fs.h> 8#include <api/fs/fs.h>
7#include <locale.h> 9#include <locale.h>
@@ -14,8 +16,8 @@
14 16
15struct perf_pmu_alias { 17struct perf_pmu_alias {
16 char *name; 18 char *name;
17 struct list_head terms; 19 struct list_head terms; /* HEAD struct parse_events_term -> list */
18 struct list_head list; 20 struct list_head list; /* ELEM */
19 char unit[UNIT_MAX_LEN+1]; 21 char unit[UNIT_MAX_LEN+1];
20 double scale; 22 double scale;
21}; 23};
@@ -208,6 +210,19 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
208 return 0; 210 return 0;
209} 211}
210 212
213static inline bool pmu_alias_info_file(char *name)
214{
215 size_t len;
216
217 len = strlen(name);
218 if (len > 5 && !strcmp(name + len - 5, ".unit"))
219 return true;
220 if (len > 6 && !strcmp(name + len - 6, ".scale"))
221 return true;
222
223 return false;
224}
225
211/* 226/*
212 * Process all the sysfs attributes located under the directory 227 * Process all the sysfs attributes located under the directory
213 * specified in 'dir' parameter. 228 * specified in 'dir' parameter.
@@ -216,7 +231,6 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
216{ 231{
217 struct dirent *evt_ent; 232 struct dirent *evt_ent;
218 DIR *event_dir; 233 DIR *event_dir;
219 size_t len;
220 int ret = 0; 234 int ret = 0;
221 235
222 event_dir = opendir(dir); 236 event_dir = opendir(dir);
@@ -232,13 +246,9 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
232 continue; 246 continue;
233 247
234 /* 248 /*
235 * skip .unit and .scale info files 249 * skip info files parsed in perf_pmu__new_alias()
236 * parsed in perf_pmu__new_alias()
237 */ 250 */
238 len = strlen(name); 251 if (pmu_alias_info_file(name))
239 if (len > 5 && !strcmp(name + len - 5, ".unit"))
240 continue;
241 if (len > 6 && !strcmp(name + len - 6, ".scale"))
242 continue; 252 continue;
243 253
244 snprintf(path, PATH_MAX, "%s/%s", dir, name); 254 snprintf(path, PATH_MAX, "%s/%s", dir, name);
@@ -387,6 +397,12 @@ static struct cpu_map *pmu_cpumask(const char *name)
387 return cpus; 397 return cpus;
388} 398}
389 399
400struct perf_event_attr *__attribute__((weak))
401perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
402{
403 return NULL;
404}
405
390static struct perf_pmu *pmu_lookup(const char *name) 406static struct perf_pmu *pmu_lookup(const char *name)
391{ 407{
392 struct perf_pmu *pmu; 408 struct perf_pmu *pmu;
@@ -421,6 +437,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
421 pmu->name = strdup(name); 437 pmu->name = strdup(name);
422 pmu->type = type; 438 pmu->type = type;
423 list_add_tail(&pmu->list, &pmus); 439 list_add_tail(&pmu->list, &pmus);
440
441 pmu->default_config = perf_pmu__get_default_config(pmu);
442
424 return pmu; 443 return pmu;
425} 444}
426 445
@@ -479,28 +498,24 @@ pmu_find_format(struct list_head *formats, char *name)
479} 498}
480 499
481/* 500/*
482 * Returns value based on the format definition (format parameter) 501 * Sets value based on the format definition (format parameter)
483 * and unformated value (value parameter). 502 * and unformated value (value parameter).
484 *
485 * TODO maybe optimize a little ;)
486 */ 503 */
487static __u64 pmu_format_value(unsigned long *format, __u64 value) 504static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
505 bool zero)
488{ 506{
489 unsigned long fbit, vbit; 507 unsigned long fbit, vbit;
490 __u64 v = 0;
491 508
492 for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { 509 for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
493 510
494 if (!test_bit(fbit, format)) 511 if (!test_bit(fbit, format))
495 continue; 512 continue;
496 513
497 if (!(value & (1llu << vbit++))) 514 if (value & (1llu << vbit++))
498 continue; 515 *v |= (1llu << fbit);
499 516 else if (zero)
500 v |= (1llu << fbit); 517 *v &= ~(1llu << fbit);
501 } 518 }
502
503 return v;
504} 519}
505 520
506/* 521/*
@@ -509,7 +524,8 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
509 */ 524 */
510static int pmu_config_term(struct list_head *formats, 525static int pmu_config_term(struct list_head *formats,
511 struct perf_event_attr *attr, 526 struct perf_event_attr *attr,
512 struct parse_events_term *term) 527 struct parse_events_term *term,
528 bool zero)
513{ 529{
514 struct perf_pmu_format *format; 530 struct perf_pmu_format *format;
515 __u64 *vp; 531 __u64 *vp;
@@ -548,18 +564,19 @@ static int pmu_config_term(struct list_head *formats,
548 * non-hardcoded terms, here's the place to translate 564 * non-hardcoded terms, here's the place to translate
549 * them into value. 565 * them into value.
550 */ 566 */
551 *vp |= pmu_format_value(format->bits, term->val.num); 567 pmu_format_value(format->bits, term->val.num, vp, zero);
552 return 0; 568 return 0;
553} 569}
554 570
555int perf_pmu__config_terms(struct list_head *formats, 571int perf_pmu__config_terms(struct list_head *formats,
556 struct perf_event_attr *attr, 572 struct perf_event_attr *attr,
557 struct list_head *head_terms) 573 struct list_head *head_terms,
574 bool zero)
558{ 575{
559 struct parse_events_term *term; 576 struct parse_events_term *term;
560 577
561 list_for_each_entry(term, head_terms, list) 578 list_for_each_entry(term, head_terms, list)
562 if (pmu_config_term(formats, attr, term)) 579 if (pmu_config_term(formats, attr, term, zero))
563 return -EINVAL; 580 return -EINVAL;
564 581
565 return 0; 582 return 0;
@@ -573,8 +590,10 @@ int perf_pmu__config_terms(struct list_head *formats,
573int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 590int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
574 struct list_head *head_terms) 591 struct list_head *head_terms)
575{ 592{
593 bool zero = !!pmu->default_config;
594
576 attr->type = pmu->type; 595 attr->type = pmu->type;
577 return perf_pmu__config_terms(&pmu->format, attr, head_terms); 596 return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero);
578} 597}
579 598
580static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, 599static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
@@ -634,7 +653,7 @@ static int check_unit_scale(struct perf_pmu_alias *alias,
634 * defined for the alias 653 * defined for the alias
635 */ 654 */
636int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 655int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
637 const char **unit, double *scale) 656 struct perf_pmu_info *info)
638{ 657{
639 struct parse_events_term *term, *h; 658 struct parse_events_term *term, *h;
640 struct perf_pmu_alias *alias; 659 struct perf_pmu_alias *alias;
@@ -644,8 +663,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
644 * Mark unit and scale as not set 663 * Mark unit and scale as not set
645 * (different from default values, see below) 664 * (different from default values, see below)
646 */ 665 */
647 *unit = NULL; 666 info->unit = NULL;
648 *scale = 0.0; 667 info->scale = 0.0;
649 668
650 list_for_each_entry_safe(term, h, head_terms, list) { 669 list_for_each_entry_safe(term, h, head_terms, list) {
651 alias = pmu_find_alias(pmu, term); 670 alias = pmu_find_alias(pmu, term);
@@ -655,7 +674,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
655 if (ret) 674 if (ret)
656 return ret; 675 return ret;
657 676
658 ret = check_unit_scale(alias, unit, scale); 677 ret = check_unit_scale(alias, &info->unit, &info->scale);
659 if (ret) 678 if (ret)
660 return ret; 679 return ret;
661 680
@@ -668,11 +687,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
668 * set defaults as for evsel 687 * set defaults as for evsel
669 * unit cannot left to NULL 688 * unit cannot left to NULL
670 */ 689 */
671 if (*unit == NULL) 690 if (info->unit == NULL)
672 *unit = ""; 691 info->unit = "";
673 692
674 if (*scale == 0.0) 693 if (info->scale == 0.0)
675 *scale = 1.0; 694 info->scale = 1.0;
676 695
677 return 0; 696 return 0;
678} 697}
@@ -794,3 +813,39 @@ bool pmu_have_event(const char *pname, const char *name)
794 } 813 }
795 return false; 814 return false;
796} 815}
816
817static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name)
818{
819 struct stat st;
820 char path[PATH_MAX];
821 const char *sysfs;
822
823 sysfs = sysfs__mountpoint();
824 if (!sysfs)
825 return NULL;
826
827 snprintf(path, PATH_MAX,
828 "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name);
829
830 if (stat(path, &st) < 0)
831 return NULL;
832
833 return fopen(path, "r");
834}
835
836int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
837 ...)
838{
839 va_list args;
840 FILE *file;
841 int ret = EOF;
842
843 va_start(args, fmt);
844 file = perf_pmu__open_file(pmu, name);
845 if (file) {
846 ret = vfscanf(file, fmt, args);
847 fclose(file);
848 }
849 va_end(args);
850 return ret;
851}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index c14a543ce1f3..fe90a012c003 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -13,13 +13,21 @@ enum {
13 13
14#define PERF_PMU_FORMAT_BITS 64 14#define PERF_PMU_FORMAT_BITS 64
15 15
16struct perf_event_attr;
17
16struct perf_pmu { 18struct perf_pmu {
17 char *name; 19 char *name;
18 __u32 type; 20 __u32 type;
21 struct perf_event_attr *default_config;
19 struct cpu_map *cpus; 22 struct cpu_map *cpus;
20 struct list_head format; 23 struct list_head format; /* HEAD struct perf_pmu_format -> list */
21 struct list_head aliases; 24 struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */
22 struct list_head list; 25 struct list_head list; /* ELEM */
26};
27
28struct perf_pmu_info {
29 const char *unit;
30 double scale;
23}; 31};
24 32
25struct perf_pmu *perf_pmu__find(const char *name); 33struct perf_pmu *perf_pmu__find(const char *name);
@@ -27,9 +35,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
27 struct list_head *head_terms); 35 struct list_head *head_terms);
28int perf_pmu__config_terms(struct list_head *formats, 36int perf_pmu__config_terms(struct list_head *formats,
29 struct perf_event_attr *attr, 37 struct perf_event_attr *attr,
30 struct list_head *head_terms); 38 struct list_head *head_terms,
39 bool zero);
31int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, 40int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
32 const char **unit, double *scale); 41 struct perf_pmu_info *info);
33struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 42struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
34 struct list_head *head_terms); 43 struct list_head *head_terms);
35int perf_pmu_wrap(void); 44int perf_pmu_wrap(void);
@@ -45,5 +54,11 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
45void print_pmu_events(const char *event_glob, bool name_only); 54void print_pmu_events(const char *event_glob, bool name_only);
46bool pmu_have_event(const char *pname, const char *name); 55bool pmu_have_event(const char *pname, const char *name);
47 56
57int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
58 ...) __attribute__((format(scanf, 3, 4)));
59
48int perf_pmu__test(void); 60int perf_pmu__test(void);
61
62struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu);
63
49#endif /* __PMU_H */ 64#endif /* __PMU_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 9a0a1839a377..c150ca4343eb 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -79,7 +79,7 @@ static int init_symbol_maps(bool user_only)
79 int ret; 79 int ret;
80 80
81 symbol_conf.sort_by_name = true; 81 symbol_conf.sort_by_name = true;
82 ret = symbol__init(); 82 ret = symbol__init(NULL);
83 if (ret < 0) { 83 if (ret < 0) {
84 pr_debug("Failed to init symbol map.\n"); 84 pr_debug("Failed to init symbol map.\n");
85 goto out; 85 goto out;
@@ -184,7 +184,8 @@ static struct dso *kernel_get_module_dso(const char *module)
184 const char *vmlinux_name; 184 const char *vmlinux_name;
185 185
186 if (module) { 186 if (module) {
187 list_for_each_entry(dso, &host_machine->kernel_dsos, node) { 187 list_for_each_entry(dso, &host_machine->kernel_dsos.head,
188 node) {
188 if (strncmp(dso->short_name + 1, module, 189 if (strncmp(dso->short_name + 1, module,
189 dso->short_name_len - 2) == 0) 190 dso->short_name_len - 2) == 0)
190 goto found; 191 goto found;
@@ -258,21 +259,33 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
258#ifdef HAVE_DWARF_SUPPORT 259#ifdef HAVE_DWARF_SUPPORT
259 260
260/* Open new debuginfo of given module */ 261/* Open new debuginfo of given module */
261static struct debuginfo *open_debuginfo(const char *module) 262static struct debuginfo *open_debuginfo(const char *module, bool silent)
262{ 263{
263 const char *path = module; 264 const char *path = module;
265 struct debuginfo *ret;
264 266
265 if (!module || !strchr(module, '/')) { 267 if (!module || !strchr(module, '/')) {
266 path = kernel_get_module_path(module); 268 path = kernel_get_module_path(module);
267 if (!path) { 269 if (!path) {
268 pr_err("Failed to find path of %s module.\n", 270 if (!silent)
269 module ?: "kernel"); 271 pr_err("Failed to find path of %s module.\n",
272 module ?: "kernel");
270 return NULL; 273 return NULL;
271 } 274 }
272 } 275 }
273 return debuginfo__new(path); 276 ret = debuginfo__new(path);
277 if (!ret && !silent) {
278 pr_warning("The %s file has no debug information.\n", path);
279 if (!module || !strtailcmp(path, ".ko"))
280 pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, ");
281 else
282 pr_warning("Rebuild with -g, ");
283 pr_warning("or install an appropriate debuginfo package.\n");
284 }
285 return ret;
274} 286}
275 287
288
276static int get_text_start_address(const char *exec, unsigned long *address) 289static int get_text_start_address(const char *exec, unsigned long *address)
277{ 290{
278 Elf *elf; 291 Elf *elf;
@@ -333,15 +346,13 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
333 pr_debug("try to find information at %" PRIx64 " in %s\n", addr, 346 pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
334 tp->module ? : "kernel"); 347 tp->module ? : "kernel");
335 348
336 dinfo = open_debuginfo(tp->module); 349 dinfo = open_debuginfo(tp->module, verbose == 0);
337 if (dinfo) { 350 if (dinfo) {
338 ret = debuginfo__find_probe_point(dinfo, 351 ret = debuginfo__find_probe_point(dinfo,
339 (unsigned long)addr, pp); 352 (unsigned long)addr, pp);
340 debuginfo__delete(dinfo); 353 debuginfo__delete(dinfo);
341 } else { 354 } else
342 pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
343 ret = -ENOENT; 355 ret = -ENOENT;
344 }
345 356
346 if (ret > 0) { 357 if (ret > 0) {
347 pp->retprobe = tp->retprobe; 358 pp->retprobe = tp->retprobe;
@@ -457,13 +468,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
457 struct debuginfo *dinfo; 468 struct debuginfo *dinfo;
458 int ntevs, ret = 0; 469 int ntevs, ret = 0;
459 470
460 dinfo = open_debuginfo(target); 471 dinfo = open_debuginfo(target, !need_dwarf);
461 472
462 if (!dinfo) { 473 if (!dinfo) {
463 if (need_dwarf) { 474 if (need_dwarf)
464 pr_warning("Failed to open debuginfo file.\n");
465 return -ENOENT; 475 return -ENOENT;
466 }
467 pr_debug("Could not open debuginfo. Try to use symbols.\n"); 476 pr_debug("Could not open debuginfo. Try to use symbols.\n");
468 return 0; 477 return 0;
469 } 478 }
@@ -565,7 +574,7 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
565 574
566static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) 575static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
567{ 576{
568 char buf[LINEBUF_SIZE]; 577 char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE];
569 const char *color = show_num ? "" : PERF_COLOR_BLUE; 578 const char *color = show_num ? "" : PERF_COLOR_BLUE;
570 const char *prefix = NULL; 579 const char *prefix = NULL;
571 580
@@ -585,7 +594,8 @@ static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
585 return 1; 594 return 1;
586error: 595error:
587 if (ferror(fp)) { 596 if (ferror(fp)) {
588 pr_warning("File read error: %s\n", strerror(errno)); 597 pr_warning("File read error: %s\n",
598 strerror_r(errno, sbuf, sizeof(sbuf)));
589 return -1; 599 return -1;
590 } 600 }
591 return 0; 601 return 0;
@@ -618,13 +628,12 @@ static int __show_line_range(struct line_range *lr, const char *module)
618 FILE *fp; 628 FILE *fp;
619 int ret; 629 int ret;
620 char *tmp; 630 char *tmp;
631 char sbuf[STRERR_BUFSIZE];
621 632
622 /* Search a line range */ 633 /* Search a line range */
623 dinfo = open_debuginfo(module); 634 dinfo = open_debuginfo(module, false);
624 if (!dinfo) { 635 if (!dinfo)
625 pr_warning("Failed to open debuginfo file.\n");
626 return -ENOENT; 636 return -ENOENT;
627 }
628 637
629 ret = debuginfo__find_line_range(dinfo, lr); 638 ret = debuginfo__find_line_range(dinfo, lr);
630 debuginfo__delete(dinfo); 639 debuginfo__delete(dinfo);
@@ -656,7 +665,7 @@ static int __show_line_range(struct line_range *lr, const char *module)
656 fp = fopen(lr->path, "r"); 665 fp = fopen(lr->path, "r");
657 if (fp == NULL) { 666 if (fp == NULL) {
658 pr_warning("Failed to open %s: %s\n", lr->path, 667 pr_warning("Failed to open %s: %s\n", lr->path,
659 strerror(errno)); 668 strerror_r(errno, sbuf, sizeof(sbuf)));
660 return -errno; 669 return -errno;
661 } 670 }
662 /* Skip to starting line number */ 671 /* Skip to starting line number */
@@ -689,11 +698,11 @@ end:
689 return ret; 698 return ret;
690} 699}
691 700
692int show_line_range(struct line_range *lr, const char *module) 701int show_line_range(struct line_range *lr, const char *module, bool user)
693{ 702{
694 int ret; 703 int ret;
695 704
696 ret = init_symbol_maps(false); 705 ret = init_symbol_maps(user);
697 if (ret < 0) 706 if (ret < 0)
698 return ret; 707 return ret;
699 ret = __show_line_range(lr, module); 708 ret = __show_line_range(lr, module);
@@ -768,13 +777,12 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
768 int i, ret = 0; 777 int i, ret = 0;
769 struct debuginfo *dinfo; 778 struct debuginfo *dinfo;
770 779
771 ret = init_symbol_maps(false); 780 ret = init_symbol_maps(pevs->uprobes);
772 if (ret < 0) 781 if (ret < 0)
773 return ret; 782 return ret;
774 783
775 dinfo = open_debuginfo(module); 784 dinfo = open_debuginfo(module, false);
776 if (!dinfo) { 785 if (!dinfo) {
777 pr_warning("Failed to open debuginfo file.\n");
778 ret = -ENOENT; 786 ret = -ENOENT;
779 goto out; 787 goto out;
780 } 788 }
@@ -815,7 +823,8 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
815} 823}
816 824
817int show_line_range(struct line_range *lr __maybe_unused, 825int show_line_range(struct line_range *lr __maybe_unused,
818 const char *module __maybe_unused) 826 const char *module __maybe_unused,
827 bool user __maybe_unused)
819{ 828{
820 pr_warning("Debuginfo-analysis is not supported.\n"); 829 pr_warning("Debuginfo-analysis is not supported.\n");
821 return -ENOSYS; 830 return -ENOSYS;
@@ -1405,8 +1414,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
1405 1414
1406 return tmp - buf; 1415 return tmp - buf;
1407error: 1416error:
1408 pr_debug("Failed to synthesize perf probe argument: %s\n", 1417 pr_debug("Failed to synthesize perf probe argument: %d\n", ret);
1409 strerror(-ret));
1410 return ret; 1418 return ret;
1411} 1419}
1412 1420
@@ -1455,8 +1463,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
1455 1463
1456 return buf; 1464 return buf;
1457error: 1465error:
1458 pr_debug("Failed to synthesize perf probe point: %s\n", 1466 pr_debug("Failed to synthesize perf probe point: %d\n", ret);
1459 strerror(-ret));
1460 free(buf); 1467 free(buf);
1461 return NULL; 1468 return NULL;
1462} 1469}
@@ -1780,10 +1787,11 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1780 memset(tev, 0, sizeof(*tev)); 1787 memset(tev, 0, sizeof(*tev));
1781} 1788}
1782 1789
1783static void print_warn_msg(const char *file, bool is_kprobe) 1790static void print_open_warning(int err, bool is_kprobe)
1784{ 1791{
1792 char sbuf[STRERR_BUFSIZE];
1785 1793
1786 if (errno == ENOENT) { 1794 if (err == -ENOENT) {
1787 const char *config; 1795 const char *config;
1788 1796
1789 if (!is_kprobe) 1797 if (!is_kprobe)
@@ -1791,25 +1799,43 @@ static void print_warn_msg(const char *file, bool is_kprobe)
1791 else 1799 else
1792 config = "CONFIG_KPROBE_EVENTS"; 1800 config = "CONFIG_KPROBE_EVENTS";
1793 1801
1794 pr_warning("%s file does not exist - please rebuild kernel" 1802 pr_warning("%cprobe_events file does not exist"
1795 " with %s.\n", file, config); 1803 " - please rebuild kernel with %s.\n",
1796 } else 1804 is_kprobe ? 'k' : 'u', config);
1797 pr_warning("Failed to open %s file: %s\n", file, 1805 } else if (err == -ENOTSUP)
1798 strerror(errno)); 1806 pr_warning("Debugfs is not mounted.\n");
1807 else
1808 pr_warning("Failed to open %cprobe_events: %s\n",
1809 is_kprobe ? 'k' : 'u',
1810 strerror_r(-err, sbuf, sizeof(sbuf)));
1811}
1812
1813static void print_both_open_warning(int kerr, int uerr)
1814{
1815 /* Both kprobes and uprobes are disabled, warn it. */
1816 if (kerr == -ENOTSUP && uerr == -ENOTSUP)
1817 pr_warning("Debugfs is not mounted.\n");
1818 else if (kerr == -ENOENT && uerr == -ENOENT)
1819 pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
1820 "or/and CONFIG_UPROBE_EVENTS.\n");
1821 else {
1822 char sbuf[STRERR_BUFSIZE];
1823 pr_warning("Failed to open kprobe events: %s.\n",
1824 strerror_r(-kerr, sbuf, sizeof(sbuf)));
1825 pr_warning("Failed to open uprobe events: %s.\n",
1826 strerror_r(-uerr, sbuf, sizeof(sbuf)));
1827 }
1799} 1828}
1800 1829
1801static int open_probe_events(const char *trace_file, bool readwrite, 1830static int open_probe_events(const char *trace_file, bool readwrite)
1802 bool is_kprobe)
1803{ 1831{
1804 char buf[PATH_MAX]; 1832 char buf[PATH_MAX];
1805 const char *__debugfs; 1833 const char *__debugfs;
1806 int ret; 1834 int ret;
1807 1835
1808 __debugfs = debugfs_find_mountpoint(); 1836 __debugfs = debugfs_find_mountpoint();
1809 if (__debugfs == NULL) { 1837 if (__debugfs == NULL)
1810 pr_warning("Debugfs is not mounted.\n"); 1838 return -ENOTSUP;
1811 return -ENOENT;
1812 }
1813 1839
1814 ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); 1840 ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
1815 if (ret >= 0) { 1841 if (ret >= 0) {
@@ -1820,19 +1846,19 @@ static int open_probe_events(const char *trace_file, bool readwrite,
1820 ret = open(buf, O_RDONLY, 0); 1846 ret = open(buf, O_RDONLY, 0);
1821 1847
1822 if (ret < 0) 1848 if (ret < 0)
1823 print_warn_msg(buf, is_kprobe); 1849 ret = -errno;
1824 } 1850 }
1825 return ret; 1851 return ret;
1826} 1852}
1827 1853
1828static int open_kprobe_events(bool readwrite) 1854static int open_kprobe_events(bool readwrite)
1829{ 1855{
1830 return open_probe_events("tracing/kprobe_events", readwrite, true); 1856 return open_probe_events("tracing/kprobe_events", readwrite);
1831} 1857}
1832 1858
1833static int open_uprobe_events(bool readwrite) 1859static int open_uprobe_events(bool readwrite)
1834{ 1860{
1835 return open_probe_events("tracing/uprobe_events", readwrite, false); 1861 return open_probe_events("tracing/uprobe_events", readwrite);
1836} 1862}
1837 1863
1838/* Get raw string list of current kprobe_events or uprobe_events */ 1864/* Get raw string list of current kprobe_events or uprobe_events */
@@ -1857,7 +1883,7 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
1857 p[idx] = '\0'; 1883 p[idx] = '\0';
1858 ret = strlist__add(sl, buf); 1884 ret = strlist__add(sl, buf);
1859 if (ret < 0) { 1885 if (ret < 0) {
1860 pr_debug("strlist__add failed: %s\n", strerror(-ret)); 1886 pr_debug("strlist__add failed (%d)\n", ret);
1861 strlist__delete(sl); 1887 strlist__delete(sl);
1862 return NULL; 1888 return NULL;
1863 } 1889 }
@@ -1916,7 +1942,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
1916 1942
1917 rawlist = get_probe_trace_command_rawlist(fd); 1943 rawlist = get_probe_trace_command_rawlist(fd);
1918 if (!rawlist) 1944 if (!rawlist)
1919 return -ENOENT; 1945 return -ENOMEM;
1920 1946
1921 strlist__for_each(ent, rawlist) { 1947 strlist__for_each(ent, rawlist) {
1922 ret = parse_probe_trace_command(ent->s, &tev); 1948 ret = parse_probe_trace_command(ent->s, &tev);
@@ -1940,27 +1966,34 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
1940/* List up current perf-probe events */ 1966/* List up current perf-probe events */
1941int show_perf_probe_events(void) 1967int show_perf_probe_events(void)
1942{ 1968{
1943 int fd, ret; 1969 int kp_fd, up_fd, ret;
1944 1970
1945 setup_pager(); 1971 setup_pager();
1946 fd = open_kprobe_events(false);
1947
1948 if (fd < 0)
1949 return fd;
1950 1972
1951 ret = init_symbol_maps(false); 1973 ret = init_symbol_maps(false);
1952 if (ret < 0) 1974 if (ret < 0)
1953 return ret; 1975 return ret;
1954 1976
1955 ret = __show_perf_probe_events(fd, true); 1977 kp_fd = open_kprobe_events(false);
1956 close(fd); 1978 if (kp_fd >= 0) {
1979 ret = __show_perf_probe_events(kp_fd, true);
1980 close(kp_fd);
1981 if (ret < 0)
1982 goto out;
1983 }
1957 1984
1958 fd = open_uprobe_events(false); 1985 up_fd = open_uprobe_events(false);
1959 if (fd >= 0) { 1986 if (kp_fd < 0 && up_fd < 0) {
1960 ret = __show_perf_probe_events(fd, false); 1987 print_both_open_warning(kp_fd, up_fd);
1961 close(fd); 1988 ret = kp_fd;
1989 goto out;
1962 } 1990 }
1963 1991
1992 if (up_fd >= 0) {
1993 ret = __show_perf_probe_events(up_fd, false);
1994 close(up_fd);
1995 }
1996out:
1964 exit_symbol_maps(); 1997 exit_symbol_maps();
1965 return ret; 1998 return ret;
1966} 1999}
@@ -1976,6 +2009,8 @@ static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1976 2009
1977 memset(&tev, 0, sizeof(tev)); 2010 memset(&tev, 0, sizeof(tev));
1978 rawlist = get_probe_trace_command_rawlist(fd); 2011 rawlist = get_probe_trace_command_rawlist(fd);
2012 if (!rawlist)
2013 return NULL;
1979 sl = strlist__new(true, NULL); 2014 sl = strlist__new(true, NULL);
1980 strlist__for_each(ent, rawlist) { 2015 strlist__for_each(ent, rawlist) {
1981 ret = parse_probe_trace_command(ent->s, &tev); 2016 ret = parse_probe_trace_command(ent->s, &tev);
@@ -2005,6 +2040,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
2005{ 2040{
2006 int ret = 0; 2041 int ret = 0;
2007 char *buf = synthesize_probe_trace_command(tev); 2042 char *buf = synthesize_probe_trace_command(tev);
2043 char sbuf[STRERR_BUFSIZE];
2008 2044
2009 if (!buf) { 2045 if (!buf) {
2010 pr_debug("Failed to synthesize probe trace event.\n"); 2046 pr_debug("Failed to synthesize probe trace event.\n");
@@ -2016,7 +2052,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
2016 ret = write(fd, buf, strlen(buf)); 2052 ret = write(fd, buf, strlen(buf));
2017 if (ret <= 0) 2053 if (ret <= 0)
2018 pr_warning("Failed to write event: %s\n", 2054 pr_warning("Failed to write event: %s\n",
2019 strerror(errno)); 2055 strerror_r(errno, sbuf, sizeof(sbuf)));
2020 } 2056 }
2021 free(buf); 2057 free(buf);
2022 return ret; 2058 return ret;
@@ -2030,7 +2066,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
2030 /* Try no suffix */ 2066 /* Try no suffix */
2031 ret = e_snprintf(buf, len, "%s", base); 2067 ret = e_snprintf(buf, len, "%s", base);
2032 if (ret < 0) { 2068 if (ret < 0) {
2033 pr_debug("snprintf() failed: %s\n", strerror(-ret)); 2069 pr_debug("snprintf() failed: %d\n", ret);
2034 return ret; 2070 return ret;
2035 } 2071 }
2036 if (!strlist__has_entry(namelist, buf)) 2072 if (!strlist__has_entry(namelist, buf))
@@ -2046,7 +2082,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
2046 for (i = 1; i < MAX_EVENT_INDEX; i++) { 2082 for (i = 1; i < MAX_EVENT_INDEX; i++) {
2047 ret = e_snprintf(buf, len, "%s_%d", base, i); 2083 ret = e_snprintf(buf, len, "%s_%d", base, i);
2048 if (ret < 0) { 2084 if (ret < 0) {
2049 pr_debug("snprintf() failed: %s\n", strerror(-ret)); 2085 pr_debug("snprintf() failed: %d\n", ret);
2050 return ret; 2086 return ret;
2051 } 2087 }
2052 if (!strlist__has_entry(namelist, buf)) 2088 if (!strlist__has_entry(namelist, buf))
@@ -2075,8 +2111,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
2075 else 2111 else
2076 fd = open_kprobe_events(true); 2112 fd = open_kprobe_events(true);
2077 2113
2078 if (fd < 0) 2114 if (fd < 0) {
2115 print_open_warning(fd, !pev->uprobes);
2079 return fd; 2116 return fd;
2117 }
2118
2080 /* Get current event names */ 2119 /* Get current event names */
2081 namelist = get_probe_trace_event_names(fd, false); 2120 namelist = get_probe_trace_event_names(fd, false);
2082 if (!namelist) { 2121 if (!namelist) {
@@ -2408,7 +2447,8 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
2408 printf("Removed event: %s\n", ent->s); 2447 printf("Removed event: %s\n", ent->s);
2409 return 0; 2448 return 0;
2410error: 2449error:
2411 pr_warning("Failed to delete event: %s\n", strerror(-ret)); 2450 pr_warning("Failed to delete event: %s\n",
2451 strerror_r(-ret, buf, sizeof(buf)));
2412 return ret; 2452 return ret;
2413} 2453}
2414 2454
@@ -2449,15 +2489,18 @@ int del_perf_probe_events(struct strlist *dellist)
2449 2489
2450 /* Get current event names */ 2490 /* Get current event names */
2451 kfd = open_kprobe_events(true); 2491 kfd = open_kprobe_events(true);
2452 if (kfd < 0) 2492 if (kfd >= 0)
2453 return kfd; 2493 namelist = get_probe_trace_event_names(kfd, true);
2454 2494
2455 namelist = get_probe_trace_event_names(kfd, true);
2456 ufd = open_uprobe_events(true); 2495 ufd = open_uprobe_events(true);
2457
2458 if (ufd >= 0) 2496 if (ufd >= 0)
2459 unamelist = get_probe_trace_event_names(ufd, true); 2497 unamelist = get_probe_trace_event_names(ufd, true);
2460 2498
2499 if (kfd < 0 && ufd < 0) {
2500 print_both_open_warning(kfd, ufd);
2501 goto error;
2502 }
2503
2461 if (namelist == NULL && unamelist == NULL) 2504 if (namelist == NULL && unamelist == NULL)
2462 goto error; 2505 goto error;
2463 2506
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 776c9347a3b6..e01e9943139f 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -128,7 +128,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
128 bool force_add); 128 bool force_add);
129extern int del_perf_probe_events(struct strlist *dellist); 129extern int del_perf_probe_events(struct strlist *dellist);
130extern int show_perf_probe_events(void); 130extern int show_perf_probe_events(void);
131extern int show_line_range(struct line_range *lr, const char *module); 131extern int show_line_range(struct line_range *lr, const char *module,
132 bool user);
132extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 133extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
133 int max_probe_points, const char *module, 134 int max_probe_points, const char *module,
134 struct strfilter *filter, bool externs); 135 struct strfilter *filter, bool externs);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index dca9145d704c..c7918f83b300 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -281,6 +281,7 @@ static int convert_variable_type(Dwarf_Die *vr_die,
281 struct probe_trace_arg_ref **ref_ptr = &tvar->ref; 281 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
282 Dwarf_Die type; 282 Dwarf_Die type;
283 char buf[16]; 283 char buf[16];
284 char sbuf[STRERR_BUFSIZE];
284 int bsize, boffs, total; 285 int bsize, boffs, total;
285 int ret; 286 int ret;
286 287
@@ -367,7 +368,7 @@ formatted:
367 if (ret >= 16) 368 if (ret >= 16)
368 ret = -E2BIG; 369 ret = -E2BIG;
369 pr_warning("Failed to convert variable type: %s\n", 370 pr_warning("Failed to convert variable type: %s\n",
370 strerror(-ret)); 371 strerror_r(-ret, sbuf, sizeof(sbuf)));
371 return ret; 372 return ret;
372 } 373 }
373 tvar->type = strdup(buf); 374 tvar->type = strdup(buf);
@@ -608,14 +609,18 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
608 return -EINVAL; 609 return -EINVAL;
609 } 610 }
610 611
611 /* Get an appropriate symbol from symtab */ 612 symbol = dwarf_diename(sp_die);
612 symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
613 if (!symbol) { 613 if (!symbol) {
614 pr_warning("Failed to find symbol at 0x%lx\n", 614 /* Try to get the symbol name from symtab */
615 (unsigned long)paddr); 615 symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
616 return -ENOENT; 616 if (!symbol) {
617 pr_warning("Failed to find symbol at 0x%lx\n",
618 (unsigned long)paddr);
619 return -ENOENT;
620 }
621 eaddr = sym.st_value;
617 } 622 }
618 tp->offset = (unsigned long)(paddr - sym.st_value); 623 tp->offset = (unsigned long)(paddr - eaddr);
619 tp->address = (unsigned long)paddr; 624 tp->address = (unsigned long)paddr;
620 tp->symbol = strdup(symbol); 625 tp->symbol = strdup(symbol);
621 if (!tp->symbol) 626 if (!tp->symbol)
@@ -779,10 +784,12 @@ static int find_lazy_match_lines(struct intlist *list,
779 size_t line_len; 784 size_t line_len;
780 ssize_t len; 785 ssize_t len;
781 int count = 0, linenum = 1; 786 int count = 0, linenum = 1;
787 char sbuf[STRERR_BUFSIZE];
782 788
783 fp = fopen(fname, "r"); 789 fp = fopen(fname, "r");
784 if (!fp) { 790 if (!fp) {
785 pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); 791 pr_warning("Failed to open %s: %s\n", fname,
792 strerror_r(errno, sbuf, sizeof(sbuf)));
786 return -errno; 793 return -errno;
787 } 794 }
788 795
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 12aa9b0d0ba1..3dda85ca50c1 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -736,7 +736,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
736 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)) 736 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
737 return NULL; 737 return NULL;
738 738
739 n = poll(evlist->pollfd, evlist->nr_fds, timeout); 739 n = perf_evlist__poll(evlist, timeout);
740 if (n < 0) { 740 if (n < 0) {
741 PyErr_SetFromErrno(PyExc_OSError); 741 PyErr_SetFromErrno(PyExc_OSError);
742 return NULL; 742 return NULL;
@@ -753,9 +753,9 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
753 PyObject *list = PyList_New(0); 753 PyObject *list = PyList_New(0);
754 int i; 754 int i;
755 755
756 for (i = 0; i < evlist->nr_fds; ++i) { 756 for (i = 0; i < evlist->pollfd.nr; ++i) {
757 PyObject *file; 757 PyObject *file;
758 FILE *fp = fdopen(evlist->pollfd[i].fd, "r"); 758 FILE *fp = fdopen(evlist->pollfd.entries[i].fd, "r");
759 759
760 if (fp == NULL) 760 if (fp == NULL)
761 goto free_list; 761 goto free_list;
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index fe8079edbdc1..cf69325b985f 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -14,6 +14,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
14 struct perf_evsel *evsel; 14 struct perf_evsel *evsel;
15 unsigned long flags = perf_event_open_cloexec_flag(); 15 unsigned long flags = perf_event_open_cloexec_flag();
16 int err = -EAGAIN, fd; 16 int err = -EAGAIN, fd;
17 static pid_t pid = -1;
17 18
18 evlist = perf_evlist__new(); 19 evlist = perf_evlist__new();
19 if (!evlist) 20 if (!evlist)
@@ -24,14 +25,22 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
24 25
25 evsel = perf_evlist__first(evlist); 26 evsel = perf_evlist__first(evlist);
26 27
27 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); 28 while (1) {
28 if (fd < 0) 29 fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
29 goto out_delete; 30 if (fd < 0) {
31 if (pid == -1 && errno == EACCES) {
32 pid = 0;
33 continue;
34 }
35 goto out_delete;
36 }
37 break;
38 }
30 close(fd); 39 close(fd);
31 40
32 fn(evsel); 41 fn(evsel);
33 42
34 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); 43 fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
35 if (fd < 0) { 44 if (fd < 0) {
36 if (errno == EINVAL) 45 if (errno == EINVAL)
37 err = -EINVAL; 46 err = -EINVAL;
@@ -47,7 +56,7 @@ out_delete:
47 56
48static bool perf_probe_api(setup_probe_fn_t fn) 57static bool perf_probe_api(setup_probe_fn_t fn)
49{ 58{
50 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL}; 59 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
51 struct cpu_map *cpus; 60 struct cpu_map *cpus;
52 int cpu, ret, i = 0; 61 int cpu, ret, i = 0;
53 62
@@ -106,7 +115,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
106 115
107 evlist__for_each(evlist, evsel) { 116 evlist__for_each(evlist, evsel) {
108 perf_evsel__config(evsel, opts); 117 perf_evsel__config(evsel, opts);
109 if (!evsel->idx && use_comm_exec) 118 if (evsel->tracking && use_comm_exec)
110 evsel->attr.comm_exec = 1; 119 evsel->attr.comm_exec = 1;
111 } 120 }
112 121
@@ -201,6 +210,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
201 struct perf_evsel *evsel; 210 struct perf_evsel *evsel;
202 int err, fd, cpu; 211 int err, fd, cpu;
203 bool ret = false; 212 bool ret = false;
213 pid_t pid = -1;
204 214
205 temp_evlist = perf_evlist__new(); 215 temp_evlist = perf_evlist__new();
206 if (!temp_evlist) 216 if (!temp_evlist)
@@ -221,12 +231,20 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
221 cpu = evlist->cpus->map[0]; 231 cpu = evlist->cpus->map[0];
222 } 232 }
223 233
224 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 234 while (1) {
225 perf_event_open_cloexec_flag()); 235 fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1,
226 if (fd >= 0) { 236 perf_event_open_cloexec_flag());
227 close(fd); 237 if (fd < 0) {
228 ret = true; 238 if (pid == -1 && errno == EACCES) {
239 pid = 0;
240 continue;
241 }
242 goto out_delete;
243 }
244 break;
229 } 245 }
246 close(fd);
247 ret = true;
230 248
231out_delete: 249out_delete:
232 perf_evlist__delete(temp_evlist); 250 perf_evlist__delete(temp_evlist);
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
index da8e9b285f51..34622b53e733 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/perf/util/run-command.c
@@ -1,6 +1,7 @@
1#include "cache.h" 1#include "cache.h"
2#include "run-command.h" 2#include "run-command.h"
3#include "exec_cmd.h" 3#include "exec_cmd.h"
4#include "debug.h"
4 5
5static inline void close_pair(int fd[2]) 6static inline void close_pair(int fd[2])
6{ 7{
@@ -19,6 +20,7 @@ int start_command(struct child_process *cmd)
19{ 20{
20 int need_in, need_out, need_err; 21 int need_in, need_out, need_err;
21 int fdin[2], fdout[2], fderr[2]; 22 int fdin[2], fdout[2], fderr[2];
23 char sbuf[STRERR_BUFSIZE];
22 24
23 /* 25 /*
24 * In case of errors we must keep the promise to close FDs 26 * In case of errors we must keep the promise to close FDs
@@ -99,7 +101,7 @@ int start_command(struct child_process *cmd)
99 101
100 if (cmd->dir && chdir(cmd->dir)) 102 if (cmd->dir && chdir(cmd->dir))
101 die("exec %s: cd to %s failed (%s)", cmd->argv[0], 103 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
102 cmd->dir, strerror(errno)); 104 cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf)));
103 if (cmd->env) { 105 if (cmd->env) {
104 for (; *cmd->env; cmd->env++) { 106 for (; *cmd->env; cmd->env++) {
105 if (strchr(*cmd->env, '=')) 107 if (strchr(*cmd->env, '='))
@@ -153,6 +155,8 @@ int start_command(struct child_process *cmd)
153 155
154static int wait_or_whine(pid_t pid) 156static int wait_or_whine(pid_t pid)
155{ 157{
158 char sbuf[STRERR_BUFSIZE];
159
156 for (;;) { 160 for (;;) {
157 int status, code; 161 int status, code;
158 pid_t waiting = waitpid(pid, &status, 0); 162 pid_t waiting = waitpid(pid, &status, 0);
@@ -160,7 +164,8 @@ static int wait_or_whine(pid_t pid)
160 if (waiting < 0) { 164 if (waiting < 0) {
161 if (errno == EINTR) 165 if (errno == EINTR)
162 continue; 166 continue;
163 error("waitpid failed (%s)", strerror(errno)); 167 error("waitpid failed (%s)",
168 strerror_r(errno, sbuf, sizeof(sbuf)));
164 return -ERR_RUN_COMMAND_WAITPID; 169 return -ERR_RUN_COMMAND_WAITPID;
165 } 170 }
166 if (waiting != pid) 171 if (waiting != pid)
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index b2dba9c0a3a1..0a01bac4ce02 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -432,6 +432,11 @@ error:
432 return err; 432 return err;
433} 433}
434 434
435static int perl_flush_script(void)
436{
437 return 0;
438}
439
435/* 440/*
436 * Stop trace script 441 * Stop trace script
437 */ 442 */
@@ -633,6 +638,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)
633struct scripting_ops perl_scripting_ops = { 638struct scripting_ops perl_scripting_ops = {
634 .name = "Perl", 639 .name = "Perl",
635 .start_script = perl_start_script, 640 .start_script = perl_start_script,
641 .flush_script = perl_flush_script,
636 .stop_script = perl_stop_script, 642 .stop_script = perl_stop_script,
637 .process_event = perl_process_event, 643 .process_event = perl_process_event,
638 .generate_script = perl_generate_script, 644 .generate_script = perl_generate_script,
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cbce2545da45..56ba07cce549 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj
73 Py_DECREF(val); 73 Py_DECREF(val);
74} 74}
75 75
76static PyObject *get_handler(const char *handler_name)
77{
78 PyObject *handler;
79
80 handler = PyDict_GetItemString(main_dict, handler_name);
81 if (handler && !PyCallable_Check(handler))
82 return NULL;
83 return handler;
84}
85
86static void call_object(PyObject *handler, PyObject *args, const char *die_msg)
87{
88 PyObject *retval;
89
90 retval = PyObject_CallObject(handler, args);
91 if (retval == NULL)
92 handler_call_die(die_msg);
93 Py_DECREF(retval);
94}
95
96static void try_call_object(const char *handler_name, PyObject *args)
97{
98 PyObject *handler;
99
100 handler = get_handler(handler_name);
101 if (handler)
102 call_object(handler, args, handler_name);
103}
104
76static void define_value(enum print_arg_type field_type, 105static void define_value(enum print_arg_type field_type,
77 const char *ev_name, 106 const char *ev_name,
78 const char *field_name, 107 const char *field_name,
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type,
80 const char *field_str) 109 const char *field_str)
81{ 110{
82 const char *handler_name = "define_flag_value"; 111 const char *handler_name = "define_flag_value";
83 PyObject *handler, *t, *retval; 112 PyObject *t;
84 unsigned long long value; 113 unsigned long long value;
85 unsigned n = 0; 114 unsigned n = 0;
86 115
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type,
98 PyTuple_SetItem(t, n++, PyInt_FromLong(value)); 127 PyTuple_SetItem(t, n++, PyInt_FromLong(value));
99 PyTuple_SetItem(t, n++, PyString_FromString(field_str)); 128 PyTuple_SetItem(t, n++, PyString_FromString(field_str));
100 129
101 handler = PyDict_GetItemString(main_dict, handler_name); 130 try_call_object(handler_name, t);
102 if (handler && PyCallable_Check(handler)) {
103 retval = PyObject_CallObject(handler, t);
104 if (retval == NULL)
105 handler_call_die(handler_name);
106 Py_DECREF(retval);
107 }
108 131
109 Py_DECREF(t); 132 Py_DECREF(t);
110} 133}
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type,
127 const char *delim) 150 const char *delim)
128{ 151{
129 const char *handler_name = "define_flag_field"; 152 const char *handler_name = "define_flag_field";
130 PyObject *handler, *t, *retval; 153 PyObject *t;
131 unsigned n = 0; 154 unsigned n = 0;
132 155
133 if (field_type == PRINT_SYMBOL) 156 if (field_type == PRINT_SYMBOL)
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type,
145 if (field_type == PRINT_FLAGS) 168 if (field_type == PRINT_FLAGS)
146 PyTuple_SetItem(t, n++, PyString_FromString(delim)); 169 PyTuple_SetItem(t, n++, PyString_FromString(delim));
147 170
148 handler = PyDict_GetItemString(main_dict, handler_name); 171 try_call_object(handler_name, t);
149 if (handler && PyCallable_Check(handler)) {
150 retval = PyObject_CallObject(handler, t);
151 if (retval == NULL)
152 handler_call_die(handler_name);
153 Py_DECREF(retval);
154 }
155 172
156 Py_DECREF(t); 173 Py_DECREF(t);
157} 174}
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
362 struct thread *thread, 379 struct thread *thread,
363 struct addr_location *al) 380 struct addr_location *al)
364{ 381{
365 PyObject *handler, *retval, *context, *t, *obj, *callchain; 382 PyObject *handler, *context, *t, *obj, *callchain;
366 PyObject *dict = NULL; 383 PyObject *dict = NULL;
367 static char handler_name[256]; 384 static char handler_name[256];
368 struct format_field *field; 385 struct format_field *field;
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
387 404
388 sprintf(handler_name, "%s__%s", event->system, event->name); 405 sprintf(handler_name, "%s__%s", event->system, event->name);
389 406
390 handler = PyDict_GetItemString(main_dict, handler_name); 407 handler = get_handler(handler_name);
391 if (handler && !PyCallable_Check(handler))
392 handler = NULL;
393 if (!handler) { 408 if (!handler) {
394 dict = PyDict_New(); 409 dict = PyDict_New();
395 if (!dict) 410 if (!dict)
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
450 Py_FatalError("error resizing Python tuple"); 465 Py_FatalError("error resizing Python tuple");
451 466
452 if (handler) { 467 if (handler) {
453 retval = PyObject_CallObject(handler, t); 468 call_object(handler, t, handler_name);
454 if (retval == NULL)
455 handler_call_die(handler_name);
456 Py_DECREF(retval);
457 } else { 469 } else {
458 handler = PyDict_GetItemString(main_dict, "trace_unhandled"); 470 try_call_object("trace_unhandled", t);
459 if (handler && PyCallable_Check(handler)) {
460
461 retval = PyObject_CallObject(handler, t);
462 if (retval == NULL)
463 handler_call_die("trace_unhandled");
464 Py_DECREF(retval);
465 }
466 Py_DECREF(dict); 471 Py_DECREF(dict);
467 } 472 }
468 473
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample,
474 struct thread *thread, 479 struct thread *thread,
475 struct addr_location *al) 480 struct addr_location *al)
476{ 481{
477 PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample; 482 PyObject *handler, *t, *dict, *callchain, *dict_sample;
478 static char handler_name[64]; 483 static char handler_name[64];
479 unsigned n = 0; 484 unsigned n = 0;
480 485
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample,
496 501
497 snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); 502 snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
498 503
499 handler = PyDict_GetItemString(main_dict, handler_name); 504 handler = get_handler(handler_name);
500 if (!handler || !PyCallable_Check(handler)) 505 if (!handler)
501 goto exit; 506 goto exit;
502 507
503 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); 508 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample,
539 if (_PyTuple_Resize(&t, n) == -1) 544 if (_PyTuple_Resize(&t, n) == -1)
540 Py_FatalError("error resizing Python tuple"); 545 Py_FatalError("error resizing Python tuple");
541 546
542 retval = PyObject_CallObject(handler, t); 547 call_object(handler, t, handler_name);
543 if (retval == NULL)
544 handler_call_die(handler_name);
545 Py_DECREF(retval);
546exit: 548exit:
547 Py_DECREF(dict); 549 Py_DECREF(dict);
548 Py_DECREF(t); 550 Py_DECREF(t);
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused,
566 568
567static int run_start_sub(void) 569static int run_start_sub(void)
568{ 570{
569 PyObject *handler, *retval;
570 int err = 0;
571
572 main_module = PyImport_AddModule("__main__"); 571 main_module = PyImport_AddModule("__main__");
573 if (main_module == NULL) 572 if (main_module == NULL)
574 return -1; 573 return -1;
575 Py_INCREF(main_module); 574 Py_INCREF(main_module);
576 575
577 main_dict = PyModule_GetDict(main_module); 576 main_dict = PyModule_GetDict(main_module);
578 if (main_dict == NULL) { 577 if (main_dict == NULL)
579 err = -1;
580 goto error; 578 goto error;
581 }
582 Py_INCREF(main_dict); 579 Py_INCREF(main_dict);
583 580
584 handler = PyDict_GetItemString(main_dict, "trace_begin"); 581 try_call_object("trace_begin", NULL);
585 if (handler == NULL || !PyCallable_Check(handler))
586 goto out;
587 582
588 retval = PyObject_CallObject(handler, NULL); 583 return 0;
589 if (retval == NULL)
590 handler_call_die("trace_begin");
591 584
592 Py_DECREF(retval);
593 return err;
594error: 585error:
595 Py_XDECREF(main_dict); 586 Py_XDECREF(main_dict);
596 Py_XDECREF(main_module); 587 Py_XDECREF(main_module);
597out: 588 return -1;
598 return err;
599} 589}
600 590
601/* 591/*
@@ -649,28 +639,23 @@ error:
649 return err; 639 return err;
650} 640}
651 641
642static int python_flush_script(void)
643{
644 return 0;
645}
646
652/* 647/*
653 * Stop trace script 648 * Stop trace script
654 */ 649 */
655static int python_stop_script(void) 650static int python_stop_script(void)
656{ 651{
657 PyObject *handler, *retval; 652 try_call_object("trace_end", NULL);
658 int err = 0;
659 653
660 handler = PyDict_GetItemString(main_dict, "trace_end");
661 if (handler == NULL || !PyCallable_Check(handler))
662 goto out;
663
664 retval = PyObject_CallObject(handler, NULL);
665 if (retval == NULL)
666 handler_call_die("trace_end");
667 Py_DECREF(retval);
668out:
669 Py_XDECREF(main_dict); 654 Py_XDECREF(main_dict);
670 Py_XDECREF(main_module); 655 Py_XDECREF(main_module);
671 Py_Finalize(); 656 Py_Finalize();
672 657
673 return err; 658 return 0;
674} 659}
675 660
676static int python_generate_script(struct pevent *pevent, const char *outfile) 661static int python_generate_script(struct pevent *pevent, const char *outfile)
@@ -843,6 +828,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
843struct scripting_ops python_scripting_ops = { 828struct scripting_ops python_scripting_ops = {
844 .name = "Python", 829 .name = "Python",
845 .start_script = python_start_script, 830 .start_script = python_start_script,
831 .flush_script = python_flush_script,
846 .stop_script = python_stop_script, 832 .stop_script = python_stop_script,
847 .process_event = python_process_event, 833 .process_event = python_process_event,
848 .generate_script = python_generate_script, 834 .generate_script = python_generate_script,
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 88dfef70c13d..883406f4b381 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -14,6 +14,7 @@
14#include "util.h" 14#include "util.h"
15#include "cpumap.h" 15#include "cpumap.h"
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "asm/bug.h"
17 18
18static int perf_session__open(struct perf_session *session) 19static int perf_session__open(struct perf_session *session)
19{ 20{
@@ -66,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session)
66 machines__destroy_kernel_maps(&session->machines); 67 machines__destroy_kernel_maps(&session->machines);
67} 68}
68 69
70static bool perf_session__has_comm_exec(struct perf_session *session)
71{
72 struct perf_evsel *evsel;
73
74 evlist__for_each(session->evlist, evsel) {
75 if (evsel->attr.comm_exec)
76 return true;
77 }
78
79 return false;
80}
81
82static void perf_session__set_comm_exec(struct perf_session *session)
83{
84 bool comm_exec = perf_session__has_comm_exec(session);
85
86 machines__set_comm_exec(&session->machines, comm_exec);
87}
88
69struct perf_session *perf_session__new(struct perf_data_file *file, 89struct perf_session *perf_session__new(struct perf_data_file *file,
70 bool repipe, struct perf_tool *tool) 90 bool repipe, struct perf_tool *tool)
71{ 91{
@@ -75,9 +95,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
75 goto out; 95 goto out;
76 96
77 session->repipe = repipe; 97 session->repipe = repipe;
78 INIT_LIST_HEAD(&session->ordered_samples.samples); 98 ordered_events__init(&session->ordered_events);
79 INIT_LIST_HEAD(&session->ordered_samples.sample_cache);
80 INIT_LIST_HEAD(&session->ordered_samples.to_free);
81 machines__init(&session->machines); 99 machines__init(&session->machines);
82 100
83 if (file) { 101 if (file) {
@@ -91,6 +109,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
91 goto out_close; 109 goto out_close;
92 110
93 perf_session__set_id_hdr_size(session); 111 perf_session__set_id_hdr_size(session);
112 perf_session__set_comm_exec(session);
94 } 113 }
95 } 114 }
96 115
@@ -100,13 +119,13 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
100 * kernel MMAP event, in perf_event__process_mmap(). 119 * kernel MMAP event, in perf_event__process_mmap().
101 */ 120 */
102 if (perf_session__create_kernel_maps(session) < 0) 121 if (perf_session__create_kernel_maps(session) < 0)
103 goto out_delete; 122 pr_warning("Cannot read kernel map\n");
104 } 123 }
105 124
106 if (tool && tool->ordering_requires_timestamps && 125 if (tool && tool->ordering_requires_timestamps &&
107 tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) { 126 tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
108 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 127 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
109 tool->ordered_samples = false; 128 tool->ordered_events = false;
110 } 129 }
111 130
112 return session; 131 return session;
@@ -238,7 +257,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
238 if (tool->build_id == NULL) 257 if (tool->build_id == NULL)
239 tool->build_id = process_finished_round_stub; 258 tool->build_id = process_finished_round_stub;
240 if (tool->finished_round == NULL) { 259 if (tool->finished_round == NULL) {
241 if (tool->ordered_samples) 260 if (tool->ordered_events)
242 tool->finished_round = process_finished_round; 261 tool->finished_round = process_finished_round;
243 else 262 else
244 tool->finished_round = process_finished_round_stub; 263 tool->finished_round = process_finished_round_stub;
@@ -444,87 +463,6 @@ static perf_event__swap_op perf_event__swap_ops[] = {
444 [PERF_RECORD_HEADER_MAX] = NULL, 463 [PERF_RECORD_HEADER_MAX] = NULL,
445}; 464};
446 465
447struct sample_queue {
448 u64 timestamp;
449 u64 file_offset;
450 union perf_event *event;
451 struct list_head list;
452};
453
454static void perf_session_free_sample_buffers(struct perf_session *session)
455{
456 struct ordered_samples *os = &session->ordered_samples;
457
458 while (!list_empty(&os->to_free)) {
459 struct sample_queue *sq;
460
461 sq = list_entry(os->to_free.next, struct sample_queue, list);
462 list_del(&sq->list);
463 free(sq);
464 }
465}
466
467static int perf_session_deliver_event(struct perf_session *session,
468 union perf_event *event,
469 struct perf_sample *sample,
470 struct perf_tool *tool,
471 u64 file_offset);
472
473static int flush_sample_queue(struct perf_session *s,
474 struct perf_tool *tool)
475{
476 struct ordered_samples *os = &s->ordered_samples;
477 struct list_head *head = &os->samples;
478 struct sample_queue *tmp, *iter;
479 struct perf_sample sample;
480 u64 limit = os->next_flush;
481 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
482 bool show_progress = limit == ULLONG_MAX;
483 struct ui_progress prog;
484 int ret;
485
486 if (!tool->ordered_samples || !limit)
487 return 0;
488
489 if (show_progress)
490 ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
491
492 list_for_each_entry_safe(iter, tmp, head, list) {
493 if (session_done())
494 return 0;
495
496 if (iter->timestamp > limit)
497 break;
498
499 ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
500 if (ret)
501 pr_err("Can't parse sample, err = %d\n", ret);
502 else {
503 ret = perf_session_deliver_event(s, iter->event, &sample, tool,
504 iter->file_offset);
505 if (ret)
506 return ret;
507 }
508
509 os->last_flush = iter->timestamp;
510 list_del(&iter->list);
511 list_add(&iter->list, &os->sample_cache);
512 os->nr_samples--;
513
514 if (show_progress)
515 ui_progress__update(&prog, 1);
516 }
517
518 if (list_empty(head)) {
519 os->last_sample = NULL;
520 } else if (last_ts <= limit) {
521 os->last_sample =
522 list_entry(head->prev, struct sample_queue, list);
523 }
524
525 return 0;
526}
527
528/* 466/*
529 * When perf record finishes a pass on every buffers, it records this pseudo 467 * When perf record finishes a pass on every buffers, it records this pseudo
530 * event. 468 * event.
@@ -568,99 +506,43 @@ static int process_finished_round(struct perf_tool *tool,
568 union perf_event *event __maybe_unused, 506 union perf_event *event __maybe_unused,
569 struct perf_session *session) 507 struct perf_session *session)
570{ 508{
571 int ret = flush_sample_queue(session, tool); 509 return ordered_events__flush(session, tool, OE_FLUSH__ROUND);
572 if (!ret)
573 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
574
575 return ret;
576}
577
578/* The queue is ordered by time */
579static void __queue_event(struct sample_queue *new, struct perf_session *s)
580{
581 struct ordered_samples *os = &s->ordered_samples;
582 struct sample_queue *sample = os->last_sample;
583 u64 timestamp = new->timestamp;
584 struct list_head *p;
585
586 ++os->nr_samples;
587 os->last_sample = new;
588
589 if (!sample) {
590 list_add(&new->list, &os->samples);
591 os->max_timestamp = timestamp;
592 return;
593 }
594
595 /*
596 * last_sample might point to some random place in the list as it's
597 * the last queued event. We expect that the new event is close to
598 * this.
599 */
600 if (sample->timestamp <= timestamp) {
601 while (sample->timestamp <= timestamp) {
602 p = sample->list.next;
603 if (p == &os->samples) {
604 list_add_tail(&new->list, &os->samples);
605 os->max_timestamp = timestamp;
606 return;
607 }
608 sample = list_entry(p, struct sample_queue, list);
609 }
610 list_add_tail(&new->list, &sample->list);
611 } else {
612 while (sample->timestamp > timestamp) {
613 p = sample->list.prev;
614 if (p == &os->samples) {
615 list_add(&new->list, &os->samples);
616 return;
617 }
618 sample = list_entry(p, struct sample_queue, list);
619 }
620 list_add(&new->list, &sample->list);
621 }
622} 510}
623 511
624#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
625
626int perf_session_queue_event(struct perf_session *s, union perf_event *event, 512int perf_session_queue_event(struct perf_session *s, union perf_event *event,
627 struct perf_sample *sample, u64 file_offset) 513 struct perf_tool *tool, struct perf_sample *sample,
514 u64 file_offset)
628{ 515{
629 struct ordered_samples *os = &s->ordered_samples; 516 struct ordered_events *oe = &s->ordered_events;
630 struct list_head *sc = &os->sample_cache;
631 u64 timestamp = sample->time; 517 u64 timestamp = sample->time;
632 struct sample_queue *new; 518 struct ordered_event *new;
633 519
634 if (!timestamp || timestamp == ~0ULL) 520 if (!timestamp || timestamp == ~0ULL)
635 return -ETIME; 521 return -ETIME;
636 522
637 if (timestamp < s->ordered_samples.last_flush) { 523 if (timestamp < oe->last_flush) {
638 printf("Warning: Timestamp below last timeslice flush\n"); 524 WARN_ONCE(1, "Timestamp below last timeslice flush\n");
639 return -EINVAL; 525
526 pr_oe_time(timestamp, "out of order event");
527 pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n",
528 oe->last_flush_type);
529
530 /* We could get out of order messages after forced flush. */
531 if (oe->last_flush_type != OE_FLUSH__HALF)
532 return -EINVAL;
640 } 533 }
641 534
642 if (!list_empty(sc)) { 535 new = ordered_events__new(oe, timestamp);
643 new = list_entry(sc->next, struct sample_queue, list); 536 if (!new) {
644 list_del(&new->list); 537 ordered_events__flush(s, tool, OE_FLUSH__HALF);
645 } else if (os->sample_buffer) { 538 new = ordered_events__new(oe, timestamp);
646 new = os->sample_buffer + os->sample_buffer_idx;
647 if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
648 os->sample_buffer = NULL;
649 } else {
650 os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
651 if (!os->sample_buffer)
652 return -ENOMEM;
653 list_add(&os->sample_buffer->list, &os->to_free);
654 os->sample_buffer_idx = 2;
655 new = os->sample_buffer + 1;
656 } 539 }
657 540
658 new->timestamp = timestamp; 541 if (!new)
542 return -ENOMEM;
543
659 new->file_offset = file_offset; 544 new->file_offset = file_offset;
660 new->event = event; 545 new->event = event;
661
662 __queue_event(new, s);
663
664 return 0; 546 return 0;
665} 547}
666 548
@@ -920,11 +802,10 @@ perf_session__deliver_sample(struct perf_session *session,
920 &sample->read.one, machine); 802 &sample->read.one, machine);
921} 803}
922 804
923static int perf_session_deliver_event(struct perf_session *session, 805int perf_session__deliver_event(struct perf_session *session,
924 union perf_event *event, 806 union perf_event *event,
925 struct perf_sample *sample, 807 struct perf_sample *sample,
926 struct perf_tool *tool, 808 struct perf_tool *tool, u64 file_offset)
927 u64 file_offset)
928{ 809{
929 struct perf_evsel *evsel; 810 struct perf_evsel *evsel;
930 struct machine *machine; 811 struct machine *machine;
@@ -1005,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session,
1005 switch (event->header.type) { 886 switch (event->header.type) {
1006 case PERF_RECORD_HEADER_ATTR: 887 case PERF_RECORD_HEADER_ATTR:
1007 err = tool->attr(tool, event, &session->evlist); 888 err = tool->attr(tool, event, &session->evlist);
1008 if (err == 0) 889 if (err == 0) {
1009 perf_session__set_id_hdr_size(session); 890 perf_session__set_id_hdr_size(session);
891 perf_session__set_comm_exec(session);
892 }
1010 return err; 893 return err;
1011 case PERF_RECORD_HEADER_EVENT_TYPE: 894 case PERF_RECORD_HEADER_EVENT_TYPE:
1012 /* 895 /*
@@ -1036,6 +919,61 @@ static void event_swap(union perf_event *event, bool sample_id_all)
1036 swap(event, sample_id_all); 919 swap(event, sample_id_all);
1037} 920}
1038 921
922int perf_session__peek_event(struct perf_session *session, off_t file_offset,
923 void *buf, size_t buf_sz,
924 union perf_event **event_ptr,
925 struct perf_sample *sample)
926{
927 union perf_event *event;
928 size_t hdr_sz, rest;
929 int fd;
930
931 if (session->one_mmap && !session->header.needs_swap) {
932 event = file_offset - session->one_mmap_offset +
933 session->one_mmap_addr;
934 goto out_parse_sample;
935 }
936
937 if (perf_data_file__is_pipe(session->file))
938 return -1;
939
940 fd = perf_data_file__fd(session->file);
941 hdr_sz = sizeof(struct perf_event_header);
942
943 if (buf_sz < hdr_sz)
944 return -1;
945
946 if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 ||
947 readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz)
948 return -1;
949
950 event = (union perf_event *)buf;
951
952 if (session->header.needs_swap)
953 perf_event_header__bswap(&event->header);
954
955 if (event->header.size < hdr_sz)
956 return -1;
957
958 rest = event->header.size - hdr_sz;
959
960 if (readn(fd, &buf, rest) != (ssize_t)rest)
961 return -1;
962
963 if (session->header.needs_swap)
964 event_swap(event, perf_evlist__sample_id_all(session->evlist));
965
966out_parse_sample:
967
968 if (sample && event->header.type < PERF_RECORD_USER_TYPE_START &&
969 perf_evlist__parse_sample(session->evlist, event, sample))
970 return -1;
971
972 *event_ptr = event;
973
974 return 0;
975}
976
1039static s64 perf_session__process_event(struct perf_session *session, 977static s64 perf_session__process_event(struct perf_session *session,
1040 union perf_event *event, 978 union perf_event *event,
1041 struct perf_tool *tool, 979 struct perf_tool *tool,
@@ -1062,15 +1000,15 @@ static s64 perf_session__process_event(struct perf_session *session,
1062 if (ret) 1000 if (ret)
1063 return ret; 1001 return ret;
1064 1002
1065 if (tool->ordered_samples) { 1003 if (tool->ordered_events) {
1066 ret = perf_session_queue_event(session, event, &sample, 1004 ret = perf_session_queue_event(session, event, tool, &sample,
1067 file_offset); 1005 file_offset);
1068 if (ret != -ETIME) 1006 if (ret != -ETIME)
1069 return ret; 1007 return ret;
1070 } 1008 }
1071 1009
1072 return perf_session_deliver_event(session, event, &sample, tool, 1010 return perf_session__deliver_event(session, event, &sample, tool,
1073 file_offset); 1011 file_offset);
1074} 1012}
1075 1013
1076void perf_event_header__bswap(struct perf_event_header *hdr) 1014void perf_event_header__bswap(struct perf_event_header *hdr)
@@ -1222,12 +1160,11 @@ more:
1222 goto more; 1160 goto more;
1223done: 1161done:
1224 /* do the final flush for ordered samples */ 1162 /* do the final flush for ordered samples */
1225 session->ordered_samples.next_flush = ULLONG_MAX; 1163 err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
1226 err = flush_sample_queue(session, tool);
1227out_err: 1164out_err:
1228 free(buf); 1165 free(buf);
1229 perf_session__warn_about_errors(session, tool); 1166 perf_session__warn_about_errors(session, tool);
1230 perf_session_free_sample_buffers(session); 1167 ordered_events__free(&session->ordered_events);
1231 return err; 1168 return err;
1232} 1169}
1233 1170
@@ -1368,12 +1305,11 @@ more:
1368 1305
1369out: 1306out:
1370 /* do the final flush for ordered samples */ 1307 /* do the final flush for ordered samples */
1371 session->ordered_samples.next_flush = ULLONG_MAX; 1308 err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
1372 err = flush_sample_queue(session, tool);
1373out_err: 1309out_err:
1374 ui_progress__finish(); 1310 ui_progress__finish();
1375 perf_session__warn_about_errors(session, tool); 1311 perf_session__warn_about_errors(session, tool);
1376 perf_session_free_sample_buffers(session); 1312 ordered_events__free(&session->ordered_events);
1377 session->one_mmap = false; 1313 session->one_mmap = false;
1378 return err; 1314 return err;
1379} 1315}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 0321013bd9fd..ffb440462008 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -9,26 +9,13 @@
9#include "symbol.h" 9#include "symbol.h"
10#include "thread.h" 10#include "thread.h"
11#include "data.h" 11#include "data.h"
12#include "ordered-events.h"
12#include <linux/rbtree.h> 13#include <linux/rbtree.h>
13#include <linux/perf_event.h> 14#include <linux/perf_event.h>
14 15
15struct sample_queue;
16struct ip_callchain; 16struct ip_callchain;
17struct thread; 17struct thread;
18 18
19struct ordered_samples {
20 u64 last_flush;
21 u64 next_flush;
22 u64 max_timestamp;
23 struct list_head samples;
24 struct list_head sample_cache;
25 struct list_head to_free;
26 struct sample_queue *sample_buffer;
27 struct sample_queue *last_sample;
28 int sample_buffer_idx;
29 unsigned int nr_samples;
30};
31
32struct perf_session { 19struct perf_session {
33 struct perf_header header; 20 struct perf_header header;
34 struct machines machines; 21 struct machines machines;
@@ -39,7 +26,7 @@ struct perf_session {
39 bool one_mmap; 26 bool one_mmap;
40 void *one_mmap_addr; 27 void *one_mmap_addr;
41 u64 one_mmap_offset; 28 u64 one_mmap_offset;
42 struct ordered_samples ordered_samples; 29 struct ordered_events ordered_events;
43 struct perf_data_file *file; 30 struct perf_data_file *file;
44}; 31};
45 32
@@ -58,6 +45,11 @@ void perf_session__delete(struct perf_session *session);
58 45
59void perf_event_header__bswap(struct perf_event_header *hdr); 46void perf_event_header__bswap(struct perf_event_header *hdr);
60 47
48int perf_session__peek_event(struct perf_session *session, off_t file_offset,
49 void *buf, size_t buf_sz,
50 union perf_event **event_ptr,
51 struct perf_sample *sample);
52
61int __perf_session__process_events(struct perf_session *session, 53int __perf_session__process_events(struct perf_session *session,
62 u64 data_offset, u64 data_size, u64 size, 54 u64 data_offset, u64 data_size, u64 size,
63 struct perf_tool *tool); 55 struct perf_tool *tool);
@@ -65,10 +57,16 @@ int perf_session__process_events(struct perf_session *session,
65 struct perf_tool *tool); 57 struct perf_tool *tool);
66 58
67int perf_session_queue_event(struct perf_session *s, union perf_event *event, 59int perf_session_queue_event(struct perf_session *s, union perf_event *event,
68 struct perf_sample *sample, u64 file_offset); 60 struct perf_tool *tool, struct perf_sample *sample,
61 u64 file_offset);
69 62
70void perf_tool__fill_defaults(struct perf_tool *tool); 63void perf_tool__fill_defaults(struct perf_tool *tool);
71 64
65int perf_session__deliver_event(struct perf_session *session,
66 union perf_event *event,
67 struct perf_sample *sample,
68 struct perf_tool *tool, u64 file_offset);
69
72int perf_session__resolve_callchain(struct perf_session *session, 70int perf_session__resolve_callchain(struct perf_session *session,
73 struct perf_evsel *evsel, 71 struct perf_evsel *evsel,
74 struct thread *thread, 72 struct thread *thread,
@@ -128,5 +126,5 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
128 126
129extern volatile int session_done; 127extern volatile int session_done;
130 128
131#define session_done() (*(volatile int *)(&session_done)) 129#define session_done() ACCESS_ONCE(session_done)
132#endif /* __PERF_SESSION_H */ 130#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 14e5a039bc45..289df9d1e65a 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -70,12 +70,14 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
70 size_t size, unsigned int width) 70 size_t size, unsigned int width)
71{ 71{
72 const char *comm = thread__comm_str(he->thread); 72 const char *comm = thread__comm_str(he->thread);
73 return repsep_snprintf(bf, size, "%*s:%5d", width - 6, 73
74 comm ?: "", he->thread->tid); 74 width = max(7U, width) - 6;
75 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
76 width, width, comm ?: "");
75} 77}
76 78
77struct sort_entry sort_thread = { 79struct sort_entry sort_thread = {
78 .se_header = "Command: Pid", 80 .se_header = " Pid:Command",
79 .se_cmp = sort__thread_cmp, 81 .se_cmp = sort__thread_cmp,
80 .se_snprintf = hist_entry__thread_snprintf, 82 .se_snprintf = hist_entry__thread_snprintf,
81 .se_width_idx = HISTC_THREAD, 83 .se_width_idx = HISTC_THREAD,
@@ -106,7 +108,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
106static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 108static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
107 size_t size, unsigned int width) 109 size_t size, unsigned int width)
108{ 110{
109 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm)); 111 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
110} 112}
111 113
112struct sort_entry sort_comm = { 114struct sort_entry sort_comm = {
@@ -152,10 +154,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152 if (map && map->dso) { 154 if (map && map->dso) {
153 const char *dso_name = !verbose ? map->dso->short_name : 155 const char *dso_name = !verbose ? map->dso->short_name :
154 map->dso->long_name; 156 map->dso->long_name;
155 return repsep_snprintf(bf, size, "%-*s", width, dso_name); 157 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
156 } 158 }
157 159
158 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 160 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
159} 161}
160 162
161static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, 163static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
@@ -257,7 +259,10 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
257 width - ret, ""); 259 width - ret, "");
258 } 260 }
259 261
260 return ret; 262 if (ret > width)
263 bf[width] = '\0';
264
265 return width;
261} 266}
262 267
263static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, 268static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -302,10 +307,9 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
302} 307}
303 308
304static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 309static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
305 size_t size, 310 size_t size, unsigned int width)
306 unsigned int width __maybe_unused)
307{ 311{
308 return repsep_snprintf(bf, size, "%s", he->srcline); 312 return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
309} 313}
310 314
311struct sort_entry sort_srcline = { 315struct sort_entry sort_srcline = {
@@ -332,7 +336,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
332static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 336static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
333 size_t size, unsigned int width) 337 size_t size, unsigned int width)
334{ 338{
335 return repsep_snprintf(bf, size, "%-*s", width, 339 return repsep_snprintf(bf, size, "%-*.*s", width, width,
336 he->parent ? he->parent->name : "[other]"); 340 he->parent ? he->parent->name : "[other]");
337} 341}
338 342
@@ -354,7 +358,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
354static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, 358static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
355 size_t size, unsigned int width) 359 size_t size, unsigned int width)
356{ 360{
357 return repsep_snprintf(bf, size, "%*d", width, he->cpu); 361 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
358} 362}
359 363
360struct sort_entry sort_cpu = { 364struct sort_entry sort_cpu = {
@@ -484,7 +488,7 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
484 else if (he->branch_info->flags.mispred) 488 else if (he->branch_info->flags.mispred)
485 out = "Y"; 489 out = "Y";
486 490
487 return repsep_snprintf(bf, size, "%-*s", width, out); 491 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
488} 492}
489 493
490/* --sort daddr_sym */ 494/* --sort daddr_sym */
@@ -1194,7 +1198,7 @@ bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1194 return hse_a->se == hse_b->se; 1198 return hse_a->se == hse_b->se;
1195} 1199}
1196 1200
1197void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) 1201void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1198{ 1202{
1199 struct hpp_sort_entry *hse; 1203 struct hpp_sort_entry *hse;
1200 1204
@@ -1202,20 +1206,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1202 return; 1206 return;
1203 1207
1204 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1208 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1205 hists__new_col_len(hists, hse->se->se_width_idx, 1209 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
1206 strlen(hse->se->se_header));
1207} 1210}
1208 1211
1209static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1212static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1210 struct perf_evsel *evsel) 1213 struct perf_evsel *evsel)
1211{ 1214{
1212 struct hpp_sort_entry *hse; 1215 struct hpp_sort_entry *hse;
1213 size_t len; 1216 size_t len = fmt->user_len;
1214 1217
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1218 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217 1219
1218 return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header); 1220 if (!len)
1221 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1222
1223 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
1219} 1224}
1220 1225
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1226static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
@@ -1223,20 +1228,26 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1223 struct perf_evsel *evsel) 1228 struct perf_evsel *evsel)
1224{ 1229{
1225 struct hpp_sort_entry *hse; 1230 struct hpp_sort_entry *hse;
1231 size_t len = fmt->user_len;
1226 1232
1227 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1233 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1228 1234
1229 return hists__col_len(&evsel->hists, hse->se->se_width_idx); 1235 if (!len)
1236 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1237
1238 return len;
1230} 1239}
1231 1240
1232static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1241static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1233 struct hist_entry *he) 1242 struct hist_entry *he)
1234{ 1243{
1235 struct hpp_sort_entry *hse; 1244 struct hpp_sort_entry *hse;
1236 size_t len; 1245 size_t len = fmt->user_len;
1237 1246
1238 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1247 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1239 len = hists__col_len(he->hists, hse->se->se_width_idx); 1248
1249 if (!len)
1250 len = hists__col_len(he->hists, hse->se->se_width_idx);
1240 1251
1241 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); 1252 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1242} 1253}
@@ -1253,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1253 } 1264 }
1254 1265
1255 hse->se = sd->entry; 1266 hse->se = sd->entry;
1267 hse->hpp.name = sd->entry->se_header;
1256 hse->hpp.header = __sort__hpp_header; 1268 hse->hpp.header = __sort__hpp_header;
1257 hse->hpp.width = __sort__hpp_width; 1269 hse->hpp.width = __sort__hpp_width;
1258 hse->hpp.entry = __sort__hpp_entry; 1270 hse->hpp.entry = __sort__hpp_entry;
@@ -1265,6 +1277,8 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1265 INIT_LIST_HEAD(&hse->hpp.list); 1277 INIT_LIST_HEAD(&hse->hpp.list);
1266 INIT_LIST_HEAD(&hse->hpp.sort_list); 1278 INIT_LIST_HEAD(&hse->hpp.sort_list);
1267 hse->hpp.elide = false; 1279 hse->hpp.elide = false;
1280 hse->hpp.len = 0;
1281 hse->hpp.user_len = 0;
1268 1282
1269 return hse; 1283 return hse;
1270} 1284}
@@ -1432,14 +1446,49 @@ static const char *get_default_sort_order(void)
1432 return default_sort_orders[sort__mode]; 1446 return default_sort_orders[sort__mode];
1433} 1447}
1434 1448
1449static int setup_sort_order(void)
1450{
1451 char *new_sort_order;
1452
1453 /*
1454 * Append '+'-prefixed sort order to the default sort
1455 * order string.
1456 */
1457 if (!sort_order || is_strict_order(sort_order))
1458 return 0;
1459
1460 if (sort_order[1] == '\0') {
1461 error("Invalid --sort key: `+'");
1462 return -EINVAL;
1463 }
1464
1465 /*
1466 * We allocate new sort_order string, but we never free it,
1467 * because it's checked over the rest of the code.
1468 */
1469 if (asprintf(&new_sort_order, "%s,%s",
1470 get_default_sort_order(), sort_order + 1) < 0) {
1471 error("Not enough memory to set up --sort");
1472 return -ENOMEM;
1473 }
1474
1475 sort_order = new_sort_order;
1476 return 0;
1477}
1478
1435static int __setup_sorting(void) 1479static int __setup_sorting(void)
1436{ 1480{
1437 char *tmp, *tok, *str; 1481 char *tmp, *tok, *str;
1438 const char *sort_keys = sort_order; 1482 const char *sort_keys;
1439 int ret = 0; 1483 int ret = 0;
1440 1484
1485 ret = setup_sort_order();
1486 if (ret)
1487 return ret;
1488
1489 sort_keys = sort_order;
1441 if (sort_keys == NULL) { 1490 if (sort_keys == NULL) {
1442 if (field_order) { 1491 if (is_strict_order(field_order)) {
1443 /* 1492 /*
1444 * If user specified field order but no sort order, 1493 * If user specified field order but no sort order,
1445 * we'll honor it and not add default sort orders. 1494 * we'll honor it and not add default sort orders.
@@ -1625,23 +1674,36 @@ static void reset_dimensions(void)
1625 memory_sort_dimensions[i].taken = 0; 1674 memory_sort_dimensions[i].taken = 0;
1626} 1675}
1627 1676
1677bool is_strict_order(const char *order)
1678{
1679 return order && (*order != '+');
1680}
1681
1628static int __setup_output_field(void) 1682static int __setup_output_field(void)
1629{ 1683{
1630 char *tmp, *tok, *str; 1684 char *tmp, *tok, *str, *strp;
1631 int ret = 0; 1685 int ret = -EINVAL;
1632 1686
1633 if (field_order == NULL) 1687 if (field_order == NULL)
1634 return 0; 1688 return 0;
1635 1689
1636 reset_dimensions(); 1690 reset_dimensions();
1637 1691
1638 str = strdup(field_order); 1692 strp = str = strdup(field_order);
1639 if (str == NULL) { 1693 if (str == NULL) {
1640 error("Not enough memory to setup output fields"); 1694 error("Not enough memory to setup output fields");
1641 return -ENOMEM; 1695 return -ENOMEM;
1642 } 1696 }
1643 1697
1644 for (tok = strtok_r(str, ", ", &tmp); 1698 if (!is_strict_order(field_order))
1699 strp++;
1700
1701 if (!strlen(strp)) {
1702 error("Invalid --fields key: `+'");
1703 goto out;
1704 }
1705
1706 for (tok = strtok_r(strp, ", ", &tmp);
1645 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1707 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1646 ret = output_field_add(tok); 1708 ret = output_field_add(tok);
1647 if (ret == -EINVAL) { 1709 if (ret == -EINVAL) {
@@ -1653,6 +1715,7 @@ static int __setup_output_field(void)
1653 } 1715 }
1654 } 1716 }
1655 1717
1718out:
1656 free(str); 1719 free(str);
1657 return ret; 1720 return ret;
1658} 1721}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 041f0c9cea2b..c03e4ff8beff 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -218,4 +218,5 @@ void perf_hpp__set_elide(int idx, bool elide);
218 218
219int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); 219int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
220 220
221bool is_strict_order(const char *order);
221#endif /* __PERF_SORT_H */ 222#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 2553e5b55b89..d87767f76903 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -9,78 +9,48 @@
9 */ 9 */
10s64 perf_atoll(const char *str) 10s64 perf_atoll(const char *str)
11{ 11{
12 unsigned int i; 12 s64 length;
13 s64 length = -1, unit = 1; 13 char *p;
14 char c;
14 15
15 if (!isdigit(str[0])) 16 if (!isdigit(str[0]))
16 goto out_err; 17 goto out_err;
17 18
18 for (i = 1; i < strlen(str); i++) { 19 length = strtoll(str, &p, 10);
19 switch (str[i]) { 20 switch (c = *p++) {
20 case 'B': 21 case 'b': case 'B':
21 case 'b': 22 if (*p)
22 break;
23 case 'K':
24 if (str[i + 1] != 'B')
25 goto out_err;
26 else
27 goto kilo;
28 case 'k':
29 if (str[i + 1] != 'b')
30 goto out_err;
31kilo:
32 unit = K;
33 break;
34 case 'M':
35 if (str[i + 1] != 'B')
36 goto out_err;
37 else
38 goto mega;
39 case 'm':
40 if (str[i + 1] != 'b')
41 goto out_err; 23 goto out_err;
42mega: 24 case '\0':
43 unit = K * K; 25 return length;
26 default:
27 goto out_err;
28 /* two-letter suffices */
29 case 'k': case 'K':
30 length <<= 10;
44 break; 31 break;
45 case 'G': 32 case 'm': case 'M':
46 if (str[i + 1] != 'B') 33 length <<= 20;
47 goto out_err;
48 else
49 goto giga;
50 case 'g':
51 if (str[i + 1] != 'b')
52 goto out_err;
53giga:
54 unit = K * K * K;
55 break; 34 break;
56 case 'T': 35 case 'g': case 'G':
57 if (str[i + 1] != 'B') 36 length <<= 30;
58 goto out_err;
59 else
60 goto tera;
61 case 't':
62 if (str[i + 1] != 'b')
63 goto out_err;
64tera:
65 unit = K * K * K * K;
66 break; 37 break;
67 case '\0': /* only specified figures */ 38 case 't': case 'T':
68 unit = 1; 39 length <<= 40;
69 break; 40 break;
70 default:
71 if (!isdigit(str[i]))
72 goto out_err;
73 break;
74 }
75 } 41 }
76 42 /* we want the cases to match */
77 length = atoll(str) * unit; 43 if (islower(c)) {
78 goto out; 44 if (strcmp(p, "b") != 0)
45 goto out_err;
46 } else {
47 if (strcmp(p, "B") != 0)
48 goto out_err;
49 }
50 return length;
79 51
80out_err: 52out_err:
81 length = -1; 53 return -1;
82out:
83 return length;
84} 54}
85 55
86/* 56/*
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index d75349979e65..1e23a5bfb044 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -6,6 +6,7 @@
6#include <inttypes.h> 6#include <inttypes.h>
7 7
8#include "symbol.h" 8#include "symbol.h"
9#include "machine.h"
9#include "vdso.h" 10#include "vdso.h"
10#include <symbol/kallsyms.h> 11#include <symbol/kallsyms.h>
11#include "debug.h" 12#include "debug.h"
@@ -680,6 +681,11 @@ static u64 ref_reloc(struct kmap *kmap)
680 return 0; 681 return 0;
681} 682}
682 683
684static bool want_demangle(bool is_kernel_sym)
685{
686 return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
687}
688
683int dso__load_sym(struct dso *dso, struct map *map, 689int dso__load_sym(struct dso *dso, struct map *map,
684 struct symsrc *syms_ss, struct symsrc *runtime_ss, 690 struct symsrc *syms_ss, struct symsrc *runtime_ss,
685 symbol_filter_t filter, int kmodule) 691 symbol_filter_t filter, int kmodule)
@@ -712,6 +718,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
712 symbols__delete(&dso->symbols[map->type]); 718 symbols__delete(&dso->symbols[map->type]);
713 719
714 if (!syms_ss->symtab) { 720 if (!syms_ss->symtab) {
721 /*
722 * If the vmlinux is stripped, fail so we will fall back
723 * to using kallsyms. The vmlinux runtime symbols aren't
724 * of much use.
725 */
726 if (dso->kernel)
727 goto out_elf_end;
728
715 syms_ss->symtab = syms_ss->dynsym; 729 syms_ss->symtab = syms_ss->dynsym;
716 syms_ss->symshdr = syms_ss->dynshdr; 730 syms_ss->symshdr = syms_ss->dynshdr;
717 } 731 }
@@ -736,7 +750,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
736 if (symstrs == NULL) 750 if (symstrs == NULL)
737 goto out_elf_end; 751 goto out_elf_end;
738 752
739 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 753 sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx);
740 if (sec_strndx == NULL) 754 if (sec_strndx == NULL)
741 goto out_elf_end; 755 goto out_elf_end;
742 756
@@ -916,7 +930,11 @@ int dso__load_sym(struct dso *dso, struct map *map,
916 } 930 }
917 curr_dso->symtab_type = dso->symtab_type; 931 curr_dso->symtab_type = dso->symtab_type;
918 map_groups__insert(kmap->kmaps, curr_map); 932 map_groups__insert(kmap->kmaps, curr_map);
919 dsos__add(&dso->node, curr_dso); 933 /*
934 * The new DSO should go to the kernel DSOS
935 */
936 dsos__add(&map->groups->machine->kernel_dsos,
937 curr_dso);
920 dso__set_loaded(curr_dso, map->type); 938 dso__set_loaded(curr_dso, map->type);
921 } else 939 } else
922 curr_dso = curr_map->dso; 940 curr_dso = curr_map->dso;
@@ -938,9 +956,12 @@ new_symbol:
938 * DWARF DW_compile_unit has this, but we don't always have access 956 * DWARF DW_compile_unit has this, but we don't always have access
939 * to it... 957 * to it...
940 */ 958 */
941 if (symbol_conf.demangle) { 959 if (want_demangle(dso->kernel || kmodule)) {
942 demangled = bfd_demangle(NULL, elf_name, 960 int demangle_flags = DMGL_NO_OPTS;
943 DMGL_PARAMS | DMGL_ANSI); 961 if (verbose)
962 demangle_flags = DMGL_PARAMS | DMGL_ANSI;
963
964 demangled = bfd_demangle(NULL, elf_name, demangle_flags);
944 if (demangled != NULL) 965 if (demangled != NULL)
945 elf_name = demangled; 966 elf_name = demangled;
946 } 967 }
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index eb06746b06b2..be84f7a9838b 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -15,6 +15,7 @@
15#include "machine.h" 15#include "machine.h"
16#include "symbol.h" 16#include "symbol.h"
17#include "strlist.h" 17#include "strlist.h"
18#include "header.h"
18 19
19#include <elf.h> 20#include <elf.h>
20#include <limits.h> 21#include <limits.h>
@@ -33,6 +34,7 @@ struct symbol_conf symbol_conf = {
33 .try_vmlinux_path = true, 34 .try_vmlinux_path = true,
34 .annotate_src = true, 35 .annotate_src = true,
35 .demangle = true, 36 .demangle = true,
37 .demangle_kernel = false,
36 .cumulate_callchain = true, 38 .cumulate_callchain = true,
37 .show_hist_headers = true, 39 .show_hist_headers = true,
38 .symfs = "", 40 .symfs = "",
@@ -523,10 +525,15 @@ struct process_kallsyms_args {
523 struct dso *dso; 525 struct dso *dso;
524}; 526};
525 527
528/*
529 * These are symbols in the kernel image, so make sure that
530 * sym is from a kernel DSO.
531 */
526bool symbol__is_idle(struct symbol *sym) 532bool symbol__is_idle(struct symbol *sym)
527{ 533{
528 const char * const idle_symbols[] = { 534 const char * const idle_symbols[] = {
529 "cpu_idle", 535 "cpu_idle",
536 "cpu_startup_entry",
530 "intel_idle", 537 "intel_idle",
531 "default_idle", 538 "default_idle",
532 "native_safe_halt", 539 "native_safe_halt",
@@ -1468,8 +1475,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
1468 if (vmlinux[0] == '/') 1475 if (vmlinux[0] == '/')
1469 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 1476 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
1470 else 1477 else
1471 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1478 symbol__join_symfs(symfs_vmlinux, vmlinux);
1472 symbol_conf.symfs, vmlinux);
1473 1479
1474 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1480 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1475 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 1481 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
@@ -1745,12 +1751,13 @@ static void vmlinux_path__exit(void)
1745 zfree(&vmlinux_path); 1751 zfree(&vmlinux_path);
1746} 1752}
1747 1753
1748static int vmlinux_path__init(void) 1754static int vmlinux_path__init(struct perf_session_env *env)
1749{ 1755{
1750 struct utsname uts; 1756 struct utsname uts;
1751 char bf[PATH_MAX]; 1757 char bf[PATH_MAX];
1758 char *kernel_version;
1752 1759
1753 vmlinux_path = malloc(sizeof(char *) * 5); 1760 vmlinux_path = malloc(sizeof(char *) * 6);
1754 if (vmlinux_path == NULL) 1761 if (vmlinux_path == NULL)
1755 return -1; 1762 return -1;
1756 1763
@@ -1763,25 +1770,37 @@ static int vmlinux_path__init(void)
1763 goto out_fail; 1770 goto out_fail;
1764 ++vmlinux_path__nr_entries; 1771 ++vmlinux_path__nr_entries;
1765 1772
1766 /* only try running kernel version if no symfs was given */ 1773 /* only try kernel version if no symfs was given */
1767 if (symbol_conf.symfs[0] != 0) 1774 if (symbol_conf.symfs[0] != 0)
1768 return 0; 1775 return 0;
1769 1776
1770 if (uname(&uts) < 0) 1777 if (env) {
1771 return -1; 1778 kernel_version = env->os_release;
1779 } else {
1780 if (uname(&uts) < 0)
1781 goto out_fail;
1772 1782
1773 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1783 kernel_version = uts.release;
1784 }
1785
1786 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
1774 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1787 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1775 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1788 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1776 goto out_fail; 1789 goto out_fail;
1777 ++vmlinux_path__nr_entries; 1790 ++vmlinux_path__nr_entries;
1778 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1791 snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
1792 kernel_version);
1793 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1794 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1795 goto out_fail;
1796 ++vmlinux_path__nr_entries;
1797 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
1779 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1798 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1780 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1799 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1781 goto out_fail; 1800 goto out_fail;
1782 ++vmlinux_path__nr_entries; 1801 ++vmlinux_path__nr_entries;
1783 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1802 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1784 uts.release); 1803 kernel_version);
1785 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1804 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1786 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1805 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1787 goto out_fail; 1806 goto out_fail;
@@ -1827,7 +1846,7 @@ static bool symbol__read_kptr_restrict(void)
1827 return value; 1846 return value;
1828} 1847}
1829 1848
1830int symbol__init(void) 1849int symbol__init(struct perf_session_env *env)
1831{ 1850{
1832 const char *symfs; 1851 const char *symfs;
1833 1852
@@ -1842,7 +1861,7 @@ int symbol__init(void)
1842 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 1861 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1843 sizeof(struct symbol)); 1862 sizeof(struct symbol));
1844 1863
1845 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 1864 if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0)
1846 return -1; 1865 return -1;
1847 1866
1848 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1867 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index e7295e93cff9..bec4b7bd09de 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -13,6 +13,7 @@
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h" 14#include "build-id.h"
15#include "event.h" 15#include "event.h"
16#include "util.h"
16 17
17#ifdef HAVE_LIBELF_SUPPORT 18#ifdef HAVE_LIBELF_SUPPORT
18#include <libelf.h> 19#include <libelf.h>
@@ -59,6 +60,7 @@ extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
59#endif 60#endif
60 61
61#ifndef DMGL_PARAMS 62#ifndef DMGL_PARAMS
63#define DMGL_NO_OPTS 0 /* For readability... */
62#define DMGL_PARAMS (1 << 0) /* Include function args */ 64#define DMGL_PARAMS (1 << 0) /* Include function args */
63#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 65#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
64#endif 66#endif
@@ -118,6 +120,7 @@ struct symbol_conf {
118 annotate_src, 120 annotate_src,
119 event_group, 121 event_group,
120 demangle, 122 demangle,
123 demangle_kernel,
121 filter_relative, 124 filter_relative,
122 show_hist_headers; 125 show_hist_headers;
123 const char *vmlinux_name, 126 const char *vmlinux_name,
@@ -143,6 +146,14 @@ struct symbol_conf {
143}; 146};
144 147
145extern struct symbol_conf symbol_conf; 148extern struct symbol_conf symbol_conf;
149
150static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
151{
152 return path__join(bf, size, symbol_conf.symfs, path);
153}
154
155#define symbol__join_symfs(bf, path) __symbol__join_symfs(bf, sizeof(bf), path)
156
146extern int vmlinux_path__nr_entries; 157extern int vmlinux_path__nr_entries;
147extern char **vmlinux_path; 158extern char **vmlinux_path;
148 159
@@ -253,7 +264,8 @@ int modules__parse(const char *filename, void *arg,
253int filename__read_debuglink(const char *filename, char *debuglink, 264int filename__read_debuglink(const char *filename, char *debuglink,
254 size_t size); 265 size_t size);
255 266
256int symbol__init(void); 267struct perf_session_env;
268int symbol__init(struct perf_session_env *env);
257void symbol__exit(void); 269void symbol__exit(void);
258void symbol__elf_init(void); 270void symbol__elf_init(void);
259struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); 271struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 12c7a253a63c..a9df7f2c6dc9 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -42,7 +42,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
42 goto err_thread; 42 goto err_thread;
43 43
44 snprintf(comm_str, 32, ":%d", tid); 44 snprintf(comm_str, 32, ":%d", tid);
45 comm = comm__new(comm_str, 0); 45 comm = comm__new(comm_str, 0, false);
46 free(comm_str); 46 free(comm_str);
47 if (!comm) 47 if (!comm)
48 goto err_thread; 48 goto err_thread;
@@ -81,19 +81,33 @@ struct comm *thread__comm(const struct thread *thread)
81 return list_first_entry(&thread->comm_list, struct comm, list); 81 return list_first_entry(&thread->comm_list, struct comm, list);
82} 82}
83 83
84struct comm *thread__exec_comm(const struct thread *thread)
85{
86 struct comm *comm, *last = NULL;
87
88 list_for_each_entry(comm, &thread->comm_list, list) {
89 if (comm->exec)
90 return comm;
91 last = comm;
92 }
93
94 return last;
95}
96
84/* CHECKME: time should always be 0 if event aren't ordered */ 97/* CHECKME: time should always be 0 if event aren't ordered */
85int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) 98int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
99 bool exec)
86{ 100{
87 struct comm *new, *curr = thread__comm(thread); 101 struct comm *new, *curr = thread__comm(thread);
88 int err; 102 int err;
89 103
90 /* Override latest entry if it had no specific time coverage */ 104 /* Override latest entry if it had no specific time coverage */
91 if (!curr->start) { 105 if (!curr->start && !curr->exec) {
92 err = comm__override(curr, str, timestamp); 106 err = comm__override(curr, str, timestamp, exec);
93 if (err) 107 if (err)
94 return err; 108 return err;
95 } else { 109 } else {
96 new = comm__new(str, timestamp); 110 new = comm__new(str, timestamp, exec);
97 if (!new) 111 if (!new)
98 return -ENOMEM; 112 return -ENOMEM;
99 list_add(&new->list, &thread->comm_list); 113 list_add(&new->list, &thread->comm_list);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 716b7723cce2..8c75fa774706 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread)
38 thread->dead = true; 38 thread->dead = true;
39} 39}
40 40
41int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp); 41int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
42 bool exec);
43static inline int thread__set_comm(struct thread *thread, const char *comm,
44 u64 timestamp)
45{
46 return __thread__set_comm(thread, comm, timestamp, false);
47}
48
42int thread__comm_len(struct thread *thread); 49int thread__comm_len(struct thread *thread);
43struct comm *thread__comm(const struct thread *thread); 50struct comm *thread__comm(const struct thread *thread);
51struct comm *thread__exec_comm(const struct thread *thread);
44const char *thread__comm_str(const struct thread *thread); 52const char *thread__comm_str(const struct thread *thread);
45void thread__insert_map(struct thread *thread, struct map *map); 53void thread__insert_map(struct thread *thread, struct map *map);
46int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); 54int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index 4385816d3d49..f11636966a0f 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -40,7 +40,7 @@ struct perf_tool {
40 event_op2 tracing_data; 40 event_op2 tracing_data;
41 event_op2 finished_round, 41 event_op2 finished_round,
42 build_id; 42 build_id;
43 bool ordered_samples; 43 bool ordered_events;
44 bool ordering_requires_timestamps; 44 bool ordering_requires_timestamps;
45}; 45};
46 46
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 57aaccc1692e..5c9bdd1591a9 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -30,6 +30,11 @@
30 30
31struct scripting_context *scripting_context; 31struct scripting_context *scripting_context;
32 32
33static int flush_script_unsupported(void)
34{
35 return 0;
36}
37
33static int stop_script_unsupported(void) 38static int stop_script_unsupported(void)
34{ 39{
35 return 0; 40 return 0;
@@ -74,6 +79,7 @@ static int python_generate_script_unsupported(struct pevent *pevent
74struct scripting_ops python_scripting_unsupported_ops = { 79struct scripting_ops python_scripting_unsupported_ops = {
75 .name = "Python", 80 .name = "Python",
76 .start_script = python_start_script_unsupported, 81 .start_script = python_start_script_unsupported,
82 .flush_script = flush_script_unsupported,
77 .stop_script = stop_script_unsupported, 83 .stop_script = stop_script_unsupported,
78 .process_event = process_event_unsupported, 84 .process_event = process_event_unsupported,
79 .generate_script = python_generate_script_unsupported, 85 .generate_script = python_generate_script_unsupported,
@@ -137,6 +143,7 @@ static int perl_generate_script_unsupported(struct pevent *pevent
137struct scripting_ops perl_scripting_unsupported_ops = { 143struct scripting_ops perl_scripting_unsupported_ops = {
138 .name = "Perl", 144 .name = "Perl",
139 .start_script = perl_start_script_unsupported, 145 .start_script = perl_start_script_unsupported,
146 .flush_script = flush_script_unsupported,
140 .stop_script = stop_script_unsupported, 147 .stop_script = stop_script_unsupported,
141 .process_event = process_event_unsupported, 148 .process_event = process_event_unsupported,
142 .generate_script = perl_generate_script_unsupported, 149 .generate_script = perl_generate_script_unsupported,
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 7b6d68688327..52aaa19e1eb1 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -64,6 +64,7 @@ struct perf_session;
64struct scripting_ops { 64struct scripting_ops {
65 const char *name; 65 const char *name;
66 int (*start_script) (const char *script, int argc, const char **argv); 66 int (*start_script) (const char *script, int argc, const char **argv);
67 int (*flush_script) (void);
67 int (*stop_script) (void); 68 int (*stop_script) (void);
68 void (*process_event) (union perf_event *event, 69 void (*process_event) (union perf_event *event,
69 struct perf_sample *sample, 70 struct perf_sample *sample,
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index e52e7461911b..24e8d871b74e 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -13,6 +13,7 @@
13#include <limits.h> 13#include <limits.h>
14#include <byteswap.h> 14#include <byteswap.h>
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <unistd.h>
16 17
17/* 18/*
18 * XXX We need to find a better place for these things... 19 * XXX We need to find a better place for these things...
@@ -282,6 +283,18 @@ void get_term_dimensions(struct winsize *ws)
282 ws->ws_col = 80; 283 ws->ws_col = 80;
283} 284}
284 285
286void set_term_quiet_input(struct termios *old)
287{
288 struct termios tc;
289
290 tcgetattr(0, old);
291 tc = *old;
292 tc.c_lflag &= ~(ICANON | ECHO);
293 tc.c_cc[VMIN] = 0;
294 tc.c_cc[VTIME] = 0;
295 tcsetattr(0, TCSANOW, &tc);
296}
297
285static void set_tracing_events_path(const char *mountpoint) 298static void set_tracing_events_path(const char *mountpoint)
286{ 299{
287 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", 300 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
@@ -443,6 +456,7 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep)
443 size_t size = 0, alloc_size = 0; 456 size_t size = 0, alloc_size = 0;
444 void *bf = NULL, *nbf; 457 void *bf = NULL, *nbf;
445 int fd, n, err = 0; 458 int fd, n, err = 0;
459 char sbuf[STRERR_BUFSIZE];
446 460
447 fd = open(filename, O_RDONLY); 461 fd = open(filename, O_RDONLY);
448 if (fd < 0) 462 if (fd < 0)
@@ -463,8 +477,8 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep)
463 n = read(fd, bf + size, alloc_size - size); 477 n = read(fd, bf + size, alloc_size - size);
464 if (n < 0) { 478 if (n < 0) {
465 if (size) { 479 if (size) {
466 pr_warning("read failed %d: %s\n", 480 pr_warning("read failed %d: %s\n", errno,
467 errno, strerror(errno)); 481 strerror_r(errno, sbuf, sizeof(sbuf)));
468 err = 0; 482 err = 0;
469 } else 483 } else
470 err = -errno; 484 err = -errno;
@@ -536,3 +550,39 @@ void mem_bswap_64(void *src, int byte_size)
536 ++m; 550 ++m;
537 } 551 }
538} 552}
553
554bool find_process(const char *name)
555{
556 size_t len = strlen(name);
557 DIR *dir;
558 struct dirent *d;
559 int ret = -1;
560
561 dir = opendir(procfs__mountpoint());
562 if (!dir)
563 return -1;
564
565 /* Walk through the directory. */
566 while (ret && (d = readdir(dir)) != NULL) {
567 char path[PATH_MAX];
568 char *data;
569 size_t size;
570
571 if ((d->d_type != DT_DIR) ||
572 !strcmp(".", d->d_name) ||
573 !strcmp("..", d->d_name))
574 continue;
575
576 scnprintf(path, sizeof(path), "%s/%s/comm",
577 procfs__mountpoint(), d->d_name);
578
579 if (filename__read_str(path, &data, &size))
580 continue;
581
582 ret = strncmp(name, data, len);
583 free(data);
584 }
585
586 closedir(dir);
587 return ret ? false : true;
588}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 66864364ccb4..80bfdaa0e2a4 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -39,6 +39,8 @@
39 39
40#define _ALL_SOURCE 1 40#define _ALL_SOURCE 1
41#define _BSD_SOURCE 1 41#define _BSD_SOURCE 1
42/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
43#define _DEFAULT_SOURCE 1
42#define HAS_BOOL 44#define HAS_BOOL
43 45
44#include <unistd.h> 46#include <unistd.h>
@@ -64,16 +66,18 @@
64#include <regex.h> 66#include <regex.h>
65#include <utime.h> 67#include <utime.h>
66#include <sys/wait.h> 68#include <sys/wait.h>
67#include <sys/poll.h> 69#include <poll.h>
68#include <sys/socket.h> 70#include <sys/socket.h>
69#include <sys/ioctl.h> 71#include <sys/ioctl.h>
70#include <inttypes.h> 72#include <inttypes.h>
73#include <linux/kernel.h>
71#include <linux/magic.h> 74#include <linux/magic.h>
72#include <linux/types.h> 75#include <linux/types.h>
73#include <sys/ttydefaults.h> 76#include <sys/ttydefaults.h>
74#include <api/fs/debugfs.h> 77#include <api/fs/debugfs.h>
75#include <termios.h> 78#include <termios.h>
76#include <linux/bitops.h> 79#include <linux/bitops.h>
80#include <termios.h>
77 81
78extern const char *graph_line; 82extern const char *graph_line;
79extern const char *graph_dotted_line; 83extern const char *graph_dotted_line;
@@ -307,6 +311,7 @@ extern unsigned int page_size;
307extern int cacheline_size; 311extern int cacheline_size;
308 312
309void get_term_dimensions(struct winsize *ws); 313void get_term_dimensions(struct winsize *ws);
314void set_term_quiet_input(struct termios *old);
310 315
311struct parse_tag { 316struct parse_tag {
312 char tag; 317 char tag;
@@ -317,6 +322,21 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
317 322
318#define SRCLINE_UNKNOWN ((char *) "??:0") 323#define SRCLINE_UNKNOWN ((char *) "??:0")
319 324
325static inline int path__join(char *bf, size_t size,
326 const char *path1, const char *path2)
327{
328 return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
329}
330
331static inline int path__join3(char *bf, size_t size,
332 const char *path1, const char *path2,
333 const char *path3)
334{
335 return scnprintf(bf, size, "%s%s%s%s%s",
336 path1, path1[0] ? "/" : "",
337 path2, path2[0] ? "/" : "", path3);
338}
339
320struct dso; 340struct dso;
321 341
322char *get_srcline(struct dso *dso, unsigned long addr); 342char *get_srcline(struct dso *dso, unsigned long addr);
@@ -330,4 +350,5 @@ void mem_bswap_64(void *src, int byte_size);
330void mem_bswap_32(void *src, int byte_size); 350void mem_bswap_32(void *src, int byte_size);
331 351
332const char *get_filename_for_perf_kvm(void); 352const char *get_filename_for_perf_kvm(void);
353bool find_process(const char *name);
333#endif /* GIT_COMPAT_UTIL_H */ 354#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 55ab700f6ba5..bf1398180785 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -194,6 +194,7 @@ my $config_bisect_check;
194 194
195my $patchcheck_type; 195my $patchcheck_type;
196my $patchcheck_start; 196my $patchcheck_start;
197my $patchcheck_cherry;
197my $patchcheck_end; 198my $patchcheck_end;
198 199
199# set when a test is something other that just building or install 200# set when a test is something other that just building or install
@@ -320,6 +321,7 @@ my %option_map = (
320 321
321 "PATCHCHECK_TYPE" => \$patchcheck_type, 322 "PATCHCHECK_TYPE" => \$patchcheck_type,
322 "PATCHCHECK_START" => \$patchcheck_start, 323 "PATCHCHECK_START" => \$patchcheck_start,
324 "PATCHCHECK_CHERRY" => \$patchcheck_cherry,
323 "PATCHCHECK_END" => \$patchcheck_end, 325 "PATCHCHECK_END" => \$patchcheck_end,
324); 326);
325 327
@@ -1448,6 +1450,12 @@ sub wait_for_monitor {
1448 } 1450 }
1449 } 1451 }
1450 print "** Monitor flushed **\n"; 1452 print "** Monitor flushed **\n";
1453
1454 # if stop is defined but wasn't hit, return error
1455 # used by reboot (which wants to see a reboot)
1456 if (defined($stop) && !$booted) {
1457 $bug = 1;
1458 }
1451 return $bug; 1459 return $bug;
1452} 1460}
1453 1461
@@ -2336,15 +2344,17 @@ sub success {
2336 2344
2337sub answer_bisect { 2345sub answer_bisect {
2338 for (;;) { 2346 for (;;) {
2339 doprint "Pass or fail? [p/f]"; 2347 doprint "Pass, fail, or skip? [p/f/s]";
2340 my $ans = <STDIN>; 2348 my $ans = <STDIN>;
2341 chomp $ans; 2349 chomp $ans;
2342 if ($ans eq "p" || $ans eq "P") { 2350 if ($ans eq "p" || $ans eq "P") {
2343 return 1; 2351 return 1;
2344 } elsif ($ans eq "f" || $ans eq "F") { 2352 } elsif ($ans eq "f" || $ans eq "F") {
2345 return 0; 2353 return 0;
2354 } elsif ($ans eq "s" || $ans eq "S") {
2355 return -1;
2346 } else { 2356 } else {
2347 print "Please answer 'P' or 'F'\n"; 2357 print "Please answer 'p', 'f', or 's'\n";
2348 } 2358 }
2349 } 2359 }
2350} 2360}
@@ -2726,15 +2736,17 @@ sub bisect {
2726 run_command "git bisect start$start_files" or 2736 run_command "git bisect start$start_files" or
2727 dodie "could not start bisect"; 2737 dodie "could not start bisect";
2728 2738
2729 run_command "git bisect good $good" or
2730 dodie "could not set bisect good to $good";
2731
2732 run_git_bisect "git bisect bad $bad" or
2733 dodie "could not set bisect bad to $bad";
2734
2735 if (defined($replay)) { 2739 if (defined($replay)) {
2736 run_command "git bisect replay $replay" or 2740 run_command "git bisect replay $replay" or
2737 dodie "failed to run replay"; 2741 dodie "failed to run replay";
2742 } else {
2743
2744 run_command "git bisect good $good" or
2745 dodie "could not set bisect good to $good";
2746
2747 run_git_bisect "git bisect bad $bad" or
2748 dodie "could not set bisect bad to $bad";
2749
2738 } 2750 }
2739 2751
2740 if (defined($start)) { 2752 if (defined($start)) {
@@ -3181,9 +3193,16 @@ sub patchcheck {
3181 3193
3182 my $start = $patchcheck_start; 3194 my $start = $patchcheck_start;
3183 3195
3196 my $cherry = $patchcheck_cherry;
3197 if (!defined($cherry)) {
3198 $cherry = 0;
3199 }
3200
3184 my $end = "HEAD"; 3201 my $end = "HEAD";
3185 if (defined($patchcheck_end)) { 3202 if (defined($patchcheck_end)) {
3186 $end = $patchcheck_end; 3203 $end = $patchcheck_end;
3204 } elsif ($cherry) {
3205 die "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n";
3187 } 3206 }
3188 3207
3189 # Get the true sha1's since we can use things like HEAD~3 3208 # Get the true sha1's since we can use things like HEAD~3
@@ -3197,24 +3216,38 @@ sub patchcheck {
3197 $type = "boot"; 3216 $type = "boot";
3198 } 3217 }
3199 3218
3200 open (IN, "git log --pretty=oneline $end|") or 3219 if ($cherry) {
3201 dodie "could not get git list"; 3220 open (IN, "git cherry -v $start $end|") or
3221 dodie "could not get git list";
3222 } else {
3223 open (IN, "git log --pretty=oneline $end|") or
3224 dodie "could not get git list";
3225 }
3202 3226
3203 my @list; 3227 my @list;
3204 3228
3205 while (<IN>) { 3229 while (<IN>) {
3206 chomp; 3230 chomp;
3231 # git cherry adds a '+' we want to remove
3232 s/^\+ //;
3207 $list[$#list+1] = $_; 3233 $list[$#list+1] = $_;
3208 last if (/^$start/); 3234 last if (/^$start/);
3209 } 3235 }
3210 close(IN); 3236 close(IN);
3211 3237
3212 if ($list[$#list] !~ /^$start/) { 3238 if (!$cherry) {
3213 fail "SHA1 $start not found"; 3239 if ($list[$#list] !~ /^$start/) {
3240 fail "SHA1 $start not found";
3241 }
3242
3243 # go backwards in the list
3244 @list = reverse @list;
3214 } 3245 }
3215 3246
3216 # go backwards in the list 3247 doprint("Going to test the following commits:\n");
3217 @list = reverse @list; 3248 foreach my $l (@list) {
3249 doprint "$l\n";
3250 }
3218 3251
3219 my $save_clean = $noclean; 3252 my $save_clean = $noclean;
3220 my %ignored_warnings; 3253 my %ignored_warnings;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 911e45ad657a..6c58cd8bbbae 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -906,6 +906,16 @@
906# 906#
907# PATCHCHECK_END is the last patch to check (default HEAD) 907# PATCHCHECK_END is the last patch to check (default HEAD)
908# 908#
909# PATCHCHECK_CHERRY if set to non zero, then git cherry will be
910# performed against PATCHCHECK_START and PATCHCHECK_END. That is
911#
912# git cherry ${PATCHCHECK_START} ${PATCHCHECK_END}
913#
914# Then the changes found will be tested.
915#
916# Note, PATCHCHECK_CHERRY requires PATCHCHECK_END to be defined.
917# (default 0)
918#
909# PATCHCHECK_TYPE is required and is the type of test to run: 919# PATCHCHECK_TYPE is required and is the type of test to run:
910# build, boot, test. 920# build, boot, test.
911# 921#
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 36ff2e4c7b6f..45f145c6f843 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -14,6 +14,7 @@ TARGETS += powerpc
14TARGETS += user 14TARGETS += user
15TARGETS += sysctl 15TARGETS += sysctl
16TARGETS += firmware 16TARGETS += firmware
17TARGETS += ftrace
17 18
18TARGETS_HOTPLUG = cpu-hotplug 19TARGETS_HOTPLUG = cpu-hotplug
19TARGETS_HOTPLUG += memory-hotplug 20TARGETS_HOTPLUG += memory-hotplug
diff --git a/tools/testing/selftests/ftrace/Makefile b/tools/testing/selftests/ftrace/Makefile
new file mode 100644
index 000000000000..76cc9f156267
--- /dev/null
+++ b/tools/testing/selftests/ftrace/Makefile
@@ -0,0 +1,7 @@
1all:
2
3run_tests:
4 @/bin/sh ./ftracetest || echo "ftrace selftests: [FAIL]"
5
6clean:
7 rm -rf logs/*
diff --git a/tools/testing/selftests/ftrace/README b/tools/testing/selftests/ftrace/README
new file mode 100644
index 000000000000..182e76fa4b82
--- /dev/null
+++ b/tools/testing/selftests/ftrace/README
@@ -0,0 +1,82 @@
1Linux Ftrace Testcases
2
3This is a collection of testcases for ftrace tracing feature in the Linux
4kernel. Since ftrace exports interfaces via the debugfs, we just need
5shell scripts for testing. Feel free to add new test cases.
6
7Running the ftrace testcases
8============================
9
10At first, you need to be the root user to run this script.
11To run all testcases:
12
13 $ sudo ./ftracetest
14
15To run specific testcases:
16
17 # ./ftracetest test.d/basic3.tc
18
19Or you can also run testcases under given directory:
20
21 # ./ftracetest test.d/kprobe/
22
23Contributing new testcases
24==========================
25
26Copy test.d/template to your testcase (whose filename must have *.tc
27extension) and rewrite the test description line.
28
29 * The working directory of the script is <debugfs>/tracing/.
30
31 * Take care with side effects as the tests are run with root privilege.
32
33 * The tests should not run for a long period of time (more than 1 min.)
34 These are to be unit tests.
35
36 * You can add a directory for your testcases under test.d/ if needed.
37
38 * The test cases should run on dash (busybox shell) for testing on
39 minimal cross-build environments.
40
41 * Note that the tests are run with "set -e" (errexit) option. If any
42 command fails, the test will be terminated immediately.
43
44 * The tests can return some result codes instead of pass or fail by
45 using exit_unresolved, exit_untested, exit_unsupported and exit_xfail.
46
47Result code
48===========
49
50Ftracetest supports following result codes.
51
52 * PASS: The test succeeded as expected. The test which exits with 0 is
53 counted as passed test.
54
55 * FAIL: The test failed, but was expected to succeed. The test which exits
56 with !0 is counted as failed test.
57
58 * UNRESOLVED: The test produced unclear or intermidiate results.
59 for example, the test was interrupted
60 or the test depends on a previous test, which failed.
61 or the test was set up incorrectly
62 The test which is in above situation, must call exit_unresolved.
63
64 * UNTESTED: The test was not run, currently just a placeholder.
65 In this case, the test must call exit_untested.
66
67 * UNSUPPORTED: The test failed because of lack of feature.
68 In this case, the test must call exit_unsupported.
69
70 * XFAIL: The test failed, and was expected to fail.
71 To return XFAIL, call exit_xfail from the test.
72
73There are some sample test scripts for result code under samples/.
74You can also run samples as below:
75
76 # ./ftracetest samples/
77
78TODO
79====
80
81 * Fancy colored output :)
82
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
new file mode 100755
index 000000000000..a8f81c782856
--- /dev/null
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -0,0 +1,253 @@
1#!/bin/sh
2
3# ftracetest - Ftrace test shell scripts
4#
5# Copyright (C) Hitachi Ltd., 2014
6# Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
7#
8# Released under the terms of the GPL v2.
9
10usage() { # errno [message]
11[ "$2" ] && echo $2
12echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]"
13echo " Options:"
14echo " -h|--help Show help message"
15echo " -k|--keep Keep passed test logs"
16echo " -d|--debug Debug mode (trace all shell commands)"
17exit $1
18}
19
20errexit() { # message
21 echo "Error: $1" 1>&2
22 exit 1
23}
24
25# Ensuring user privilege
26if [ `id -u` -ne 0 ]; then
27 errexit "this must be run by root user"
28fi
29
30# Utilities
31absdir() { # file_path
32 (cd `dirname $1`; pwd)
33}
34
35abspath() {
36 echo `absdir $1`/`basename $1`
37}
38
39find_testcases() { #directory
40 echo `find $1 -name \*.tc`
41}
42
43parse_opts() { # opts
44 local OPT_TEST_CASES=
45 local OPT_TEST_DIR=
46
47 while [ "$1" ]; do
48 case "$1" in
49 --help|-h)
50 usage 0
51 ;;
52 --keep|-k)
53 KEEP_LOG=1
54 shift 1
55 ;;
56 --debug|-d)
57 DEBUG=1
58 shift 1
59 ;;
60 *.tc)
61 if [ -f "$1" ]; then
62 OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
63 shift 1
64 else
65 usage 1 "$1 is not a testcase"
66 fi
67 ;;
68 *)
69 if [ -d "$1" ]; then
70 OPT_TEST_DIR=`abspath $1`
71 OPT_TEST_CASES="$OPT_TEST_CASES `find_testcases $OPT_TEST_DIR`"
72 shift 1
73 else
74 usage 1 "Invalid option ($1)"
75 fi
76 ;;
77 esac
78 done
79 if [ "$OPT_TEST_CASES" ]; then
80 TEST_CASES=$OPT_TEST_CASES
81 fi
82}
83
84# Parameters
85DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' '`
86TRACING_DIR=$DEBUGFS_DIR/tracing
87TOP_DIR=`absdir $0`
88TEST_DIR=$TOP_DIR/test.d
89TEST_CASES=`find_testcases $TEST_DIR`
90LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`/
91KEEP_LOG=0
92DEBUG=0
93# Parse command-line options
94parse_opts $*
95
96[ $DEBUG -ne 0 ] && set -x
97
98# Verify parameters
99if [ -z "$DEBUGFS_DIR" -o ! -d "$TRACING_DIR" ]; then
100 errexit "No ftrace directory found"
101fi
102
103# Preparing logs
104LOG_FILE=$LOG_DIR/ftracetest.log
105mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR"
106date > $LOG_FILE
107prlog() { # messages
108 echo "$@" | tee -a $LOG_FILE
109}
110catlog() { #file
111 cat $1 | tee -a $LOG_FILE
112}
113prlog "=== Ftrace unit tests ==="
114
115
116# Testcase management
117# Test result codes - Dejagnu extended code
118PASS=0 # The test succeeded.
119FAIL=1 # The test failed, but was expected to succeed.
120UNRESOLVED=2 # The test produced indeterminate results. (e.g. interrupted)
121UNTESTED=3 # The test was not run, currently just a placeholder.
122UNSUPPORTED=4 # The test failed because of lack of feature.
123XFAIL=5 # The test failed, and was expected to fail.
124
125# Accumulations
126PASSED_CASES=
127FAILED_CASES=
128UNRESOLVED_CASES=
129UNTESTED_CASES=
130UNSUPPORTED_CASES=
131XFAILED_CASES=
132UNDEFINED_CASES=
133TOTAL_RESULT=0
134
135CASENO=0
136testcase() { # testfile
137 CASENO=$((CASENO+1))
138 prlog -n "[$CASENO]"`grep "^#[ \t]*description:" $1 | cut -f2 -d:`
139}
140
141eval_result() { # retval sigval
142 local retval=$2
143 if [ $2 -eq 0 ]; then
144 test $1 -ne 0 && retval=$FAIL
145 fi
146 case $retval in
147 $PASS)
148 prlog " [PASS]"
149 PASSED_CASES="$PASSED_CASES $CASENO"
150 return 0
151 ;;
152 $FAIL)
153 prlog " [FAIL]"
154 FAILED_CASES="$FAILED_CASES $CASENO"
155 return 1 # this is a bug.
156 ;;
157 $UNRESOLVED)
158 prlog " [UNRESOLVED]"
159 UNRESOLVED_CASES="$UNRESOLVED_CASES $CASENO"
160 return 1 # this is a kind of bug.. something happened.
161 ;;
162 $UNTESTED)
163 prlog " [UNTESTED]"
164 UNTESTED_CASES="$UNTESTED_CASES $CASENO"
165 return 0
166 ;;
167 $UNSUPPORTED)
168 prlog " [UNSUPPORTED]"
169 UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO"
170 return 1 # this is not a bug, but the result should be reported.
171 ;;
172 $XFAIL)
173 prlog " [XFAIL]"
174 XFAILED_CASES="$XFAILED_CASES $CASENO"
175 return 0
176 ;;
177 *)
178 prlog " [UNDEFINED]"
179 UNDEFINED_CASES="$UNDEFINED_CASES $CASENO"
180 return 1 # this must be a test bug
181 ;;
182 esac
183}
184
185# Signal handling for result codes
186SIG_RESULT=
187SIG_BASE=36 # Use realtime signals
188SIG_PID=$$
189
190SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED))
191exit_unresolved () {
192 kill -s $SIG_UNRESOLVED $SIG_PID
193 exit 0
194}
195trap 'SIG_RESULT=$UNRESOLVED' $SIG_UNRESOLVED
196
197SIG_UNTESTED=$((SIG_BASE + UNTESTED))
198exit_untested () {
199 kill -s $SIG_UNTESTED $SIG_PID
200 exit 0
201}
202trap 'SIG_RESULT=$UNTESTED' $SIG_UNTESTED
203
204SIG_UNSUPPORTED=$((SIG_BASE + UNSUPPORTED))
205exit_unsupported () {
206 kill -s $SIG_UNSUPPORTED $SIG_PID
207 exit 0
208}
209trap 'SIG_RESULT=$UNSUPPORTED' $SIG_UNSUPPORTED
210
211SIG_XFAIL=$((SIG_BASE + XFAIL))
212exit_xfail () {
213 kill -s $SIG_XFAIL $SIG_PID
214 exit 0
215}
216trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL
217
218# Run one test case
219run_test() { # testfile
220 local testname=`basename $1`
221 local testlog=`mktemp --tmpdir=$LOG_DIR ${testname}-XXXXXX.log`
222 testcase $1
223 echo "execute: "$1 > $testlog
224 SIG_RESULT=0
225 # setup PID and PPID, $$ is not updated.
226 (cd $TRACING_DIR; read PID _ < /proc/self/stat ;
227 set -e; set -x; . $1) >> $testlog 2>&1
228 eval_result $? $SIG_RESULT
229 if [ $? -eq 0 ]; then
230 # Remove test log if the test was done as it was expected.
231 [ $KEEP_LOG -eq 0 ] && rm $testlog
232 else
233 catlog $testlog
234 TOTAL_RESULT=1
235 fi
236}
237
238# Main loop
239for t in $TEST_CASES; do
240 run_test $t
241done
242
243prlog ""
244prlog "# of passed: " `echo $PASSED_CASES | wc -w`
245prlog "# of failed: " `echo $FAILED_CASES | wc -w`
246prlog "# of unresolved: " `echo $UNRESOLVED_CASES | wc -w`
247prlog "# of untested: " `echo $UNTESTED_CASES | wc -w`
248prlog "# of unsupported: " `echo $UNSUPPORTED_CASES | wc -w`
249prlog "# of xfailed: " `echo $XFAILED_CASES | wc -w`
250prlog "# of undefined(test bug): " `echo $UNDEFINED_CASES | wc -w`
251
252# if no error, return 0
253exit $TOTAL_RESULT
diff --git a/tools/testing/selftests/ftrace/samples/fail.tc b/tools/testing/selftests/ftrace/samples/fail.tc
new file mode 100644
index 000000000000..15e35b956e05
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/fail.tc
@@ -0,0 +1,4 @@
1#!/bin/sh
2# description: failure-case example
3cat non-exist-file
4echo "this is not executed"
diff --git a/tools/testing/selftests/ftrace/samples/pass.tc b/tools/testing/selftests/ftrace/samples/pass.tc
new file mode 100644
index 000000000000..d01549370041
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/pass.tc
@@ -0,0 +1,3 @@
1#!/bin/sh
2# description: pass-case example
3return 0
diff --git a/tools/testing/selftests/ftrace/samples/unresolved.tc b/tools/testing/selftests/ftrace/samples/unresolved.tc
new file mode 100644
index 000000000000..41e99d3358d1
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/unresolved.tc
@@ -0,0 +1,4 @@
1#!/bin/sh
2# description: unresolved-case example
3trap exit_unresolved INT
4kill -INT $PID
diff --git a/tools/testing/selftests/ftrace/samples/unsupported.tc b/tools/testing/selftests/ftrace/samples/unsupported.tc
new file mode 100644
index 000000000000..45910ff13328
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/unsupported.tc
@@ -0,0 +1,3 @@
1#!/bin/sh
2# description: unsupported-case example
3exit_unsupported
diff --git a/tools/testing/selftests/ftrace/samples/untested.tc b/tools/testing/selftests/ftrace/samples/untested.tc
new file mode 100644
index 000000000000..35a45946ec60
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/untested.tc
@@ -0,0 +1,3 @@
1#!/bin/sh
2# description: untested-case example
3exit_untested
diff --git a/tools/testing/selftests/ftrace/samples/xfail.tc b/tools/testing/selftests/ftrace/samples/xfail.tc
new file mode 100644
index 000000000000..9dd395323259
--- /dev/null
+++ b/tools/testing/selftests/ftrace/samples/xfail.tc
@@ -0,0 +1,3 @@
1#!/bin/sh
2# description: xfail-case example
3cat non-exist-file || exit_xfail
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc
new file mode 100644
index 000000000000..9980ff14ae44
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc
@@ -0,0 +1,3 @@
1#!/bin/sh
2# description: Basic trace file check
3test -f README -a -f trace -a -f tracing_on -a -f trace_pipe
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
new file mode 100644
index 000000000000..bf9a7b037924
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
@@ -0,0 +1,7 @@
1#!/bin/sh
2# description: Basic test for tracers
3test -f available_tracers
4for t in `cat available_tracers`; do
5 echo $t > current_tracer
6done
7echo nop > current_tracer
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
new file mode 100644
index 000000000000..bde6625d9785
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
@@ -0,0 +1,8 @@
1#!/bin/sh
2# description: Basic trace clock test
3test -f trace_clock
4for c in `cat trace_clock | tr -d \[\]`; do
5 echo $c > trace_clock
6 grep '\['$c'\]' trace_clock
7done
8echo local > trace_clock
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
new file mode 100644
index 000000000000..1b8b665ab2b3
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
@@ -0,0 +1,11 @@
1#!/bin/sh
2# description: Kprobe dynamic event - adding and removing
3
4[ -f kprobe_events ] || exit_unsupported # this is configurable
5
6echo 0 > events/enable
7echo > kprobe_events
8echo p:myevent do_fork > kprobe_events
9grep myevent kprobe_events
10test -d events/kprobes/myevent
11echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
new file mode 100644
index 000000000000..b55c84003587
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
@@ -0,0 +1,13 @@
1#!/bin/sh
2# description: Kprobe dynamic event - busy event check
3
4[ -f kprobe_events ] || exit_unsupported
5
6echo 0 > events/enable
7echo > kprobe_events
8echo p:myevent do_fork > kprobe_events
9test -d events/kprobes/myevent
10echo 1 > events/kprobes/myevent/enable
11echo > kprobe_events && exit 1 # this must fail
12echo 0 > events/kprobes/myevent/enable
13echo > kprobe_events # this must succeed
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
new file mode 100644
index 000000000000..a603d3f8db7b
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
@@ -0,0 +1,16 @@
1#!/bin/sh
2# description: Kprobe dynamic event with arguments
3
4[ -f kprobe_events ] || exit_unsupported # this is configurable
5
6echo 0 > events/enable
7echo > kprobe_events
8echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events
9grep testprobe kprobe_events
10test -d events/kprobes/testprobe
11echo 1 > events/kprobes/testprobe/enable
12( echo "forked")
13echo 0 > events/kprobes/testprobe/enable
14echo "-:testprobe" >> kprobe_events
15test -d events/kprobes/testprobe && exit 1 || exit 0
16
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
new file mode 100644
index 000000000000..283c29e7f7c4
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
@@ -0,0 +1,15 @@
1#!/bin/sh
2# description: Kretprobe dynamic event with arguments
3
4[ -f kprobe_events ] || exit_unsupported # this is configurable
5
6echo 0 > events/enable
7echo > kprobe_events
8echo 'r:testprobe2 do_fork $retval' > kprobe_events
9grep testprobe2 kprobe_events
10test -d events/kprobes/testprobe2
11echo 1 > events/kprobes/testprobe2/enable
12( echo "forked")
13echo 0 > events/kprobes/testprobe2/enable
14echo '-:testprobe2' >> kprobe_events
15test -d events/kprobes/testprobe2 && exit 1 || exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/template b/tools/testing/selftests/ftrace/test.d/template
new file mode 100644
index 000000000000..5448f7abad5f
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/template
@@ -0,0 +1,9 @@
1#!/bin/sh
2# description: %HERE DESCRIBE WHAT THIS DOES%
3# you have to add ".tc" extention for your testcase file
4# Note that all tests are run with "errexit" option.
5
6exit 0 # Return 0 if the test is passed, otherwise return !0
7# If the test could not run because of lack of feature, call exit_unsupported
8# If the test returned unclear results, call exit_unresolved
9# If the test is a dummy, or a placeholder, call exit_untested
diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile
index 5386fd7c43ae..74bbefdeaf4c 100644
--- a/tools/testing/selftests/ipc/Makefile
+++ b/tools/testing/selftests/ipc/Makefile
@@ -1,18 +1,18 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not) 1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) 2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386) 3ifeq ($(ARCH),i386)
4 ARCH := X86 4 ARCH := x86
5 CFLAGS := -DCONFIG_X86_32 -D__i386__ 5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif 6endif
7ifeq ($(ARCH),x86_64) 7ifeq ($(ARCH),x86_64)
8 ARCH := X86 8 ARCH := x86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__ 9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif 10endif
11 11
12CFLAGS += -I../../../../usr/include/ 12CFLAGS += -I../../../../usr/include/
13 13
14all: 14all:
15ifeq ($(ARCH),X86) 15ifeq ($(ARCH),x86)
16 gcc $(CFLAGS) msgque.c -o msgque_test 16 gcc $(CFLAGS) msgque.c -o msgque_test
17else 17else
18 echo "Not an x86 target, can't build msgque selftest" 18 echo "Not an x86 target, can't build msgque selftest"
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
index d7d6bbeeff2f..8aabd82db9e4 100644
--- a/tools/testing/selftests/kcmp/Makefile
+++ b/tools/testing/selftests/kcmp/Makefile
@@ -1,11 +1,11 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not) 1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) 2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386) 3ifeq ($(ARCH),i386)
4 ARCH := X86 4 ARCH := x86
5 CFLAGS := -DCONFIG_X86_32 -D__i386__ 5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif 6endif
7ifeq ($(ARCH),x86_64) 7ifeq ($(ARCH),x86_64)
8 ARCH := X86 8 ARCH := x86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__ 9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif 10endif
11 11
@@ -15,7 +15,7 @@ CFLAGS += -I../../../../usr/include/
15CFLAGS += -I../../../../arch/x86/include/ 15CFLAGS += -I../../../../arch/x86/include/
16 16
17all: 17all:
18ifeq ($(ARCH),X86) 18ifeq ($(ARCH),x86)
19 gcc $(CFLAGS) kcmp_test.c -o kcmp_test 19 gcc $(CFLAGS) kcmp_test.c -o kcmp_test
20else 20else
21 echo "Not an x86 target, can't build kcmp selftest" 21 echo "Not an x86 target, can't build kcmp selftest"
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile
index 6816c491c5ff..b80cd10d53ba 100644
--- a/tools/testing/selftests/memfd/Makefile
+++ b/tools/testing/selftests/memfd/Makefile
@@ -1,38 +1,17 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386)
4 ARCH := X86
5endif
6ifeq ($(ARCH),x86_64)
7 ARCH := X86
8endif
9
10CFLAGS += -D_FILE_OFFSET_BITS=64 1CFLAGS += -D_FILE_OFFSET_BITS=64
11CFLAGS += -I../../../../arch/x86/include/generated/uapi/
12CFLAGS += -I../../../../arch/x86/include/uapi/
13CFLAGS += -I../../../../include/uapi/ 2CFLAGS += -I../../../../include/uapi/
14CFLAGS += -I../../../../include/ 3CFLAGS += -I../../../../include/
15 4
16all: 5all:
17ifeq ($(ARCH),X86)
18 gcc $(CFLAGS) memfd_test.c -o memfd_test 6 gcc $(CFLAGS) memfd_test.c -o memfd_test
19else
20 echo "Not an x86 target, can't build memfd selftest"
21endif
22 7
23run_tests: all 8run_tests: all
24ifeq ($(ARCH),X86)
25 gcc $(CFLAGS) memfd_test.c -o memfd_test 9 gcc $(CFLAGS) memfd_test.c -o memfd_test
26endif
27 @./memfd_test || echo "memfd_test: [FAIL]" 10 @./memfd_test || echo "memfd_test: [FAIL]"
28 11
29build_fuse: 12build_fuse:
30ifeq ($(ARCH),X86)
31 gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt 13 gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
32 gcc $(CFLAGS) fuse_test.c -o fuse_test 14 gcc $(CFLAGS) fuse_test.c -o fuse_test
33else
34 echo "Not an x86 target, can't build memfd selftest"
35endif
36 15
37run_fuse: build_fuse 16run_fuse: build_fuse
38 @./run_fuse_test.sh || echo "fuse_test: [FAIL]" 17 @./run_fuse_test.sh || echo "fuse_test: [FAIL]"
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
index 3634c909b1b0..0b9eafb7ab7b 100644
--- a/tools/testing/selftests/memfd/memfd_test.c
+++ b/tools/testing/selftests/memfd/memfd_test.c
@@ -59,9 +59,9 @@ static void mfd_fail_new(const char *name, unsigned int flags)
59 } 59 }
60} 60}
61 61
62static __u64 mfd_assert_get_seals(int fd) 62static unsigned int mfd_assert_get_seals(int fd)
63{ 63{
64 long r; 64 int r;
65 65
66 r = fcntl(fd, F_GET_SEALS); 66 r = fcntl(fd, F_GET_SEALS);
67 if (r < 0) { 67 if (r < 0) {
@@ -69,50 +69,48 @@ static __u64 mfd_assert_get_seals(int fd)
69 abort(); 69 abort();
70 } 70 }
71 71
72 return r; 72 return (unsigned int)r;
73} 73}
74 74
75static void mfd_assert_has_seals(int fd, __u64 seals) 75static void mfd_assert_has_seals(int fd, unsigned int seals)
76{ 76{
77 __u64 s; 77 unsigned int s;
78 78
79 s = mfd_assert_get_seals(fd); 79 s = mfd_assert_get_seals(fd);
80 if (s != seals) { 80 if (s != seals) {
81 printf("%llu != %llu = GET_SEALS(%d)\n", 81 printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd);
82 (unsigned long long)seals, (unsigned long long)s, fd);
83 abort(); 82 abort();
84 } 83 }
85} 84}
86 85
87static void mfd_assert_add_seals(int fd, __u64 seals) 86static void mfd_assert_add_seals(int fd, unsigned int seals)
88{ 87{
89 long r; 88 int r;
90 __u64 s; 89 unsigned int s;
91 90
92 s = mfd_assert_get_seals(fd); 91 s = mfd_assert_get_seals(fd);
93 r = fcntl(fd, F_ADD_SEALS, seals); 92 r = fcntl(fd, F_ADD_SEALS, seals);
94 if (r < 0) { 93 if (r < 0) {
95 printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n", 94 printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals);
96 fd, (unsigned long long)s, (unsigned long long)seals);
97 abort(); 95 abort();
98 } 96 }
99} 97}
100 98
101static void mfd_fail_add_seals(int fd, __u64 seals) 99static void mfd_fail_add_seals(int fd, unsigned int seals)
102{ 100{
103 long r; 101 int r;
104 __u64 s; 102 unsigned int s;
105 103
106 r = fcntl(fd, F_GET_SEALS); 104 r = fcntl(fd, F_GET_SEALS);
107 if (r < 0) 105 if (r < 0)
108 s = 0; 106 s = 0;
109 else 107 else
110 s = r; 108 s = (unsigned int)r;
111 109
112 r = fcntl(fd, F_ADD_SEALS, seals); 110 r = fcntl(fd, F_ADD_SEALS, seals);
113 if (r >= 0) { 111 if (r >= 0) {
114 printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected\n", 112 printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n",
115 fd, (unsigned long long)s, (unsigned long long)seals); 113 fd, s, seals);
116 abort(); 114 abort();
117 } 115 }
118} 116}
@@ -205,7 +203,7 @@ static void mfd_fail_open(int fd, int flags, mode_t mode)
205 sprintf(buf, "/proc/self/fd/%d", fd); 203 sprintf(buf, "/proc/self/fd/%d", fd);
206 r = open(buf, flags, mode); 204 r = open(buf, flags, mode);
207 if (r >= 0) { 205 if (r >= 0) {
208 printf("open(%s) didn't fail as expected\n"); 206 printf("open(%s) didn't fail as expected\n", buf);
209 abort(); 207 abort();
210 } 208 }
211} 209}
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 74a78cedce37..f6ff90a76bd7 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
13 13
14export CC CFLAGS 14export CC CFLAGS
15 15
16TARGETS = pmu copyloops mm tm 16TARGETS = pmu copyloops mm tm primitives
17 17
18endif 18endif
19 19
diff --git a/tools/testing/selftests/powerpc/primitives/Makefile b/tools/testing/selftests/powerpc/primitives/Makefile
new file mode 100644
index 000000000000..ea737ca01732
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/Makefile
@@ -0,0 +1,17 @@
1CFLAGS += -I$(CURDIR)
2
3PROGS := load_unaligned_zeropad
4
5all: $(PROGS)
6
7$(PROGS): ../harness.c
8
9run_tests: all
10 @-for PROG in $(PROGS); do \
11 ./$$PROG; \
12 done;
13
14clean:
15 rm -f $(PROGS) *.o
16
17.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h b/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h
new file mode 120000
index 000000000000..b14255e15a25
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h
@@ -0,0 +1 @@
../.././../../../../arch/powerpc/include/asm/asm-compat.h \ No newline at end of file
diff --git a/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h b/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
new file mode 100644
index 000000000000..d1b647509596
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c
@@ -0,0 +1,147 @@
1/*
2 * Userspace test harness for load_unaligned_zeropad. Creates two
3 * pages and uses mprotect to prevent access to the second page and
4 * a SEGV handler that walks the exception tables and runs the fixup
5 * routine.
6 *
7 * The results are compared against a normal load that is that is
8 * performed while access to the second page is enabled via mprotect.
9 *
10 * Copyright (C) 2014 Anton Blanchard <anton@au.ibm.com>, IBM
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18#include <stdlib.h>
19#include <string.h>
20#include <stdio.h>
21#include <stdbool.h>
22#include <signal.h>
23#include <unistd.h>
24#include <sys/mman.h>
25
26#define FIXUP_SECTION ".ex_fixup"
27
28#include "word-at-a-time.h"
29
30#include "utils.h"
31
32
33static int page_size;
34static char *mem_region;
35
36static int protect_region(void)
37{
38 if (mprotect(mem_region + page_size, page_size, PROT_NONE)) {
39 perror("mprotect");
40 return 1;
41 }
42
43 return 0;
44}
45
46static int unprotect_region(void)
47{
48 if (mprotect(mem_region + page_size, page_size, PROT_READ|PROT_WRITE)) {
49 perror("mprotect");
50 return 1;
51 }
52
53 return 0;
54}
55
56extern char __start___ex_table[];
57extern char __stop___ex_table[];
58
59#if defined(__powerpc64__)
60#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP]
61#elif defined(__powerpc__)
62#define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP]
63#else
64#error implement UCONTEXT_NIA
65#endif
66
67static int segv_error;
68
69static void segv_handler(int signr, siginfo_t *info, void *ptr)
70{
71 ucontext_t *uc = (ucontext_t *)ptr;
72 unsigned long addr = (unsigned long)info->si_addr;
73 unsigned long *ip = &UCONTEXT_NIA(uc);
74 unsigned long *ex_p = (unsigned long *)__start___ex_table;
75
76 while (ex_p < (unsigned long *)__stop___ex_table) {
77 unsigned long insn, fixup;
78
79 insn = *ex_p++;
80 fixup = *ex_p++;
81
82 if (insn == *ip) {
83 *ip = fixup;
84 return;
85 }
86 }
87
88 printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr);
89 segv_error++;
90}
91
92static void setup_segv_handler(void)
93{
94 struct sigaction action;
95
96 memset(&action, 0, sizeof(action));
97 action.sa_sigaction = segv_handler;
98 action.sa_flags = SA_SIGINFO;
99 sigaction(SIGSEGV, &action, NULL);
100}
101
102static int do_one_test(char *p, int page_offset)
103{
104 unsigned long should;
105 unsigned long got;
106
107 FAIL_IF(unprotect_region());
108 should = *(unsigned long *)p;
109 FAIL_IF(protect_region());
110
111 got = load_unaligned_zeropad(p);
112
113 if (should != got)
114 printf("offset %u load_unaligned_zeropad returned 0x%lx, should be 0x%lx\n", page_offset, got, should);
115
116 return 0;
117}
118
119static int test_body(void)
120{
121 unsigned long i;
122
123 page_size = getpagesize();
124 mem_region = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
125 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
126
127 FAIL_IF(mem_region == MAP_FAILED);
128
129 for (i = 0; i < page_size; i++)
130 mem_region[i] = i;
131
132 memset(mem_region+page_size, 0, page_size);
133
134 setup_segv_handler();
135
136 for (i = 0; i < page_size; i++)
137 FAIL_IF(do_one_test(mem_region+i, i));
138
139 FAIL_IF(segv_error);
140
141 return 0;
142}
143
144int main(void)
145{
146 return test_harness(test_body, "load_unaligned_zeropad");
147}
diff --git a/tools/testing/selftests/powerpc/primitives/word-at-a-time.h b/tools/testing/selftests/powerpc/primitives/word-at-a-time.h
new file mode 120000
index 000000000000..eb74401b591f
--- /dev/null
+++ b/tools/testing/selftests/powerpc/primitives/word-at-a-time.h
@@ -0,0 +1 @@
../../../../../arch/powerpc/include/asm/word-at-a-time.h \ No newline at end of file
diff --git a/tools/testing/selftests/rcutorture/bin/config2frag.sh b/tools/testing/selftests/rcutorture/bin/config2frag.sh
index 9f9ffcd427d3..56f51ae13d73 100644..100755
--- a/tools/testing/selftests/rcutorture/bin/config2frag.sh
+++ b/tools/testing/selftests/rcutorture/bin/config2frag.sh
@@ -1,5 +1,5 @@
1#!/bin/sh 1#!/bin/bash
2# Usage: sh config2frag.sh < .config > configfrag 2# Usage: config2frag.sh < .config > configfrag
3# 3#
4# Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the 4# Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the
5# resulting file becomes a legitimate Kconfig fragment. 5# resulting file becomes a legitimate Kconfig fragment.
diff --git a/tools/testing/selftests/rcutorture/bin/configcheck.sh b/tools/testing/selftests/rcutorture/bin/configcheck.sh
index d686537dd55c..eee31e261bf7 100755
--- a/tools/testing/selftests/rcutorture/bin/configcheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/configcheck.sh
@@ -1,5 +1,5 @@
1#!/bin/sh 1#!/bin/bash
2# Usage: sh configcheck.sh .config .config-template 2# Usage: configcheck.sh .config .config-template
3# 3#
4# This program is free software; you can redistribute it and/or modify 4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/configinit.sh b/tools/testing/selftests/rcutorture/bin/configinit.sh
index 9c3f3d39b934..15f1a17ca96e 100755
--- a/tools/testing/selftests/rcutorture/bin/configinit.sh
+++ b/tools/testing/selftests/rcutorture/bin/configinit.sh
@@ -1,6 +1,6 @@
1#!/bin/sh 1#!/bin/bash
2# 2#
3# sh configinit.sh config-spec-file [ build output dir ] 3# Usage: configinit.sh config-spec-file [ build output dir ]
4# 4#
5# Create a .config file from the spec file. Run from the kernel source tree. 5# Create a .config file from the spec file. Run from the kernel source tree.
6# Exits with 0 if all went well, with 1 if all went well but the config 6# Exits with 0 if all went well, with 1 if all went well but the config
diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh
index d01b865bb100..b325470c01b3 100644
--- a/tools/testing/selftests/rcutorture/bin/functions.sh
+++ b/tools/testing/selftests/rcutorture/bin/functions.sh
@@ -64,6 +64,26 @@ configfrag_boot_params () {
64 fi 64 fi
65} 65}
66 66
67# configfrag_boot_cpus bootparam-string config-fragment-file config-cpus
68#
69# Decreases number of CPUs based on any maxcpus= boot parameters specified.
70configfrag_boot_cpus () {
71 local bootargs="`configfrag_boot_params "$1" "$2"`"
72 local maxcpus
73 if echo "${bootargs}" | grep -q 'maxcpus=[0-9]'
74 then
75 maxcpus="`echo "${bootargs}" | sed -e 's/^.*maxcpus=\([0-9]*\).*$/\1/'`"
76 if test "$3" -gt "$maxcpus"
77 then
78 echo $maxcpus
79 else
80 echo $3
81 fi
82 else
83 echo $3
84 fi
85}
86
67# configfrag_hotplug_cpu config-fragment-file 87# configfrag_hotplug_cpu config-fragment-file
68# 88#
69# Returns 1 if the config fragment specifies hotplug CPU. 89# Returns 1 if the config fragment specifies hotplug CPU.
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-build.sh b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
index 7c1e56b46de4..00cb0db2643d 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-build.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-build.sh
@@ -2,7 +2,7 @@
2# 2#
3# Build a kvm-ready Linux kernel from the tree in the current directory. 3# Build a kvm-ready Linux kernel from the tree in the current directory.
4# 4#
5# Usage: sh kvm-build.sh config-template build-dir more-configs 5# Usage: kvm-build.sh config-template build-dir more-configs
6# 6#
7# This program is free software; you can redistribute it and/or modify 7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by 8# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
index 7f1ff1a8fc4b..43f764098e50 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-lock.sh
@@ -2,7 +2,7 @@
2# 2#
3# Analyze a given results directory for locktorture progress. 3# Analyze a given results directory for locktorture progress.
4# 4#
5# Usage: sh kvm-recheck-lock.sh resdir 5# Usage: kvm-recheck-lock.sh resdir
6# 6#
7# This program is free software; you can redistribute it and/or modify 7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by 8# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
index 307c4b95f325..d6cc07fc137f 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcu.sh
@@ -2,7 +2,7 @@
2# 2#
3# Analyze a given results directory for rcutorture progress. 3# Analyze a given results directory for rcutorture progress.
4# 4#
5# Usage: sh kvm-recheck-rcu.sh resdir 5# Usage: kvm-recheck-rcu.sh resdir
6# 6#
7# This program is free software; you can redistribute it and/or modify 7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by 8# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index 3f6c9b78d177..4f5b20f367a9 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -4,7 +4,7 @@
4# check the build and console output for errors. Given a directory 4# check the build and console output for errors. Given a directory
5# containing results directories, this recursively checks them all. 5# containing results directories, this recursively checks them all.
6# 6#
7# Usage: sh kvm-recheck.sh resdir ... 7# Usage: kvm-recheck.sh resdir ...
8# 8#
9# This program is free software; you can redistribute it and/or modify 9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by 10# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 0f69dcbf9def..f6b2b4771b78 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -6,7 +6,7 @@
6# Execute this in the source tree. Do not run it as a background task 6# Execute this in the source tree. Do not run it as a background task
7# because qemu does not seem to like that much. 7# because qemu does not seem to like that much.
8# 8#
9# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args 9# Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args
10# 10#
11# qemu-args defaults to "-nographic", along with arguments specifying the 11# qemu-args defaults to "-nographic", along with arguments specifying the
12# number of CPUs and other options generated from 12# number of CPUs and other options generated from
@@ -140,6 +140,7 @@ fi
140# Generate -smp qemu argument. 140# Generate -smp qemu argument.
141qemu_args="-nographic $qemu_args" 141qemu_args="-nographic $qemu_args"
142cpu_count=`configNR_CPUS.sh $config_template` 142cpu_count=`configNR_CPUS.sh $config_template`
143cpu_count=`configfrag_boot_cpus "$boot_args" "$config_template" "$cpu_count"`
143vcpus=`identify_qemu_vcpus` 144vcpus=`identify_qemu_vcpus`
144if test $cpu_count -gt $vcpus 145if test $cpu_count -gt $vcpus
145then 146then
@@ -214,7 +215,7 @@ then
214 fi 215 fi
215 if test $kruntime -ge $((seconds + grace)) 216 if test $kruntime -ge $((seconds + grace))
216 then 217 then
217 echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1 218 echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
218 kill -KILL $qemu_pid 219 kill -KILL $qemu_pid
219 break 220 break
220 fi 221 fi
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 589e9c38413b..e527dc952eb0 100644..100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -7,7 +7,7 @@
7# Edit the definitions below to set the locations of the various directories, 7# Edit the definitions below to set the locations of the various directories,
8# as well as the test duration. 8# as well as the test duration.
9# 9#
10# Usage: sh kvm.sh [ options ] 10# Usage: kvm.sh [ options ]
11# 11#
12# This program is free software; you can redistribute it and/or modify 12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by 13# it under the terms of the GNU General Public License as published by
@@ -188,7 +188,9 @@ for CF in $configs
188do 188do
189 if test -f "$CONFIGFRAG/$kversion/$CF" 189 if test -f "$CONFIGFRAG/$kversion/$CF"
190 then 190 then
191 echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu 191 cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF`
192 cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$kversion/$CF" "$cpu_count"`
193 echo $CF $cpu_count >> $T/cfgcpu
192 else 194 else
193 echo "The --configs file $CF does not exist, terminating." 195 echo "The --configs file $CF does not exist, terminating."
194 exit 1 196 exit 1
diff --git a/tools/testing/selftests/rcutorture/bin/parse-build.sh b/tools/testing/selftests/rcutorture/bin/parse-build.sh
index 543230951c38..499d1e598e42 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-build.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-build.sh
@@ -1,4 +1,4 @@
1#!/bin/sh 1#!/bin/bash
2# 2#
3# Check the build output from an rcutorture run for goodness. 3# Check the build output from an rcutorture run for goodness.
4# The "file" is a pathname on the local system, and "title" is 4# The "file" is a pathname on the local system, and "title" is
@@ -6,8 +6,7 @@
6# 6#
7# The file must contain kernel build output. 7# The file must contain kernel build output.
8# 8#
9# Usage: 9# Usage: parse-build.sh file title
10# sh parse-build.sh file title
11# 10#
12# This program is free software; you can redistribute it and/or modify 11# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by 12# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh
index 4185d4cab32e..f962ba4cf68b 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-console.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh
@@ -1,11 +1,10 @@
1#!/bin/sh 1#!/bin/bash
2# 2#
3# Check the console output from an rcutorture run for oopses. 3# Check the console output from an rcutorture run for oopses.
4# The "file" is a pathname on the local system, and "title" is 4# The "file" is a pathname on the local system, and "title" is
5# a text string for error-message purposes. 5# a text string for error-message purposes.
6# 6#
7# Usage: 7# Usage: parse-console.sh file title
8# sh parse-console.sh file title
9# 8#
10# This program is free software; you can redistribute it and/or modify 9# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by 10# it under the terms of the GNU General Public License as published by
@@ -33,6 +32,10 @@ title="$2"
33 32
34. functions.sh 33. functions.sh
35 34
35if grep -Pq '\x00' < $file
36then
37 print_warning Console output contains nul bytes, old qemu still running?
38fi
36egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T 39egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T
37if test -s $T 40if test -s $T
38then 41then
diff --git a/tools/testing/selftests/rcutorture/bin/parse-torture.sh b/tools/testing/selftests/rcutorture/bin/parse-torture.sh
index 3455560ab4e4..e3c5f0705696 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-torture.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-torture.sh
@@ -1,4 +1,4 @@
1#!/bin/sh 1#!/bin/bash
2# 2#
3# Check the console output from a torture run for goodness. 3# Check the console output from a torture run for goodness.
4# The "file" is a pathname on the local system, and "title" is 4# The "file" is a pathname on the local system, and "title" is
@@ -7,8 +7,7 @@
7# The file must contain torture output, but can be interspersed 7# The file must contain torture output, but can be interspersed
8# with other dmesg text, as in console-log output. 8# with other dmesg text, as in console-log output.
9# 9#
10# Usage: 10# Usage: parse-torture.sh file title
11# sh parse-torture.sh file title
12# 11#
13# This program is free software; you can redistribute it and/or modify 12# This program is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License as published by 13# it under the terms of the GNU General Public License as published by
diff --git a/tools/testing/selftests/rcutorture/configs/lock/CFLIST b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
index a061b22d1892..6910b7370761 100644
--- a/tools/testing/selftests/rcutorture/configs/lock/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/lock/CFLIST
@@ -1 +1,4 @@
1LOCK01 1LOCK01
2LOCK02
3LOCK03
4LOCK04 \ No newline at end of file
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK02 b/tools/testing/selftests/rcutorture/configs/lock/LOCK02
new file mode 100644
index 000000000000..1d1da1477fc3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK02
@@ -0,0 +1,6 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=4
3CONFIG_HOTPLUG_CPU=y
4CONFIG_PREEMPT_NONE=n
5CONFIG_PREEMPT_VOLUNTARY=n
6CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot
new file mode 100644
index 000000000000..5aa44b4f1b51
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK02.boot
@@ -0,0 +1 @@
locktorture.torture_type=mutex_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK03 b/tools/testing/selftests/rcutorture/configs/lock/LOCK03
new file mode 100644
index 000000000000..1d1da1477fc3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK03
@@ -0,0 +1,6 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=4
3CONFIG_HOTPLUG_CPU=y
4CONFIG_PREEMPT_NONE=n
5CONFIG_PREEMPT_VOLUNTARY=n
6CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot
new file mode 100644
index 000000000000..a67bbe0245c9
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK03.boot
@@ -0,0 +1 @@
locktorture.torture_type=rwsem_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04 b/tools/testing/selftests/rcutorture/configs/lock/LOCK04
new file mode 100644
index 000000000000..1d1da1477fc3
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK04
@@ -0,0 +1,6 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=4
3CONFIG_HOTPLUG_CPU=y
4CONFIG_PREEMPT_NONE=n
5CONFIG_PREEMPT_VOLUNTARY=n
6CONFIG_PREEMPT=y
diff --git a/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot b/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot
new file mode 100644
index 000000000000..48c04fe47fb4
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/lock/LOCK04.boot
@@ -0,0 +1 @@
locktorture.torture_type=rw_lock
diff --git a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
index 9746ea1cd6c7..252aae618984 100644
--- a/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/lock/ver_functions.sh
@@ -38,6 +38,6 @@ per_version_boot_params () {
38 echo $1 `locktorture_param_onoff "$1" "$2"` \ 38 echo $1 `locktorture_param_onoff "$1" "$2"` \
39 locktorture.stat_interval=15 \ 39 locktorture.stat_interval=15 \
40 locktorture.shutdown_secs=$3 \ 40 locktorture.shutdown_secs=$3 \
41 locktorture.locktorture_runnable=1 \ 41 locktorture.torture_runnable=1 \
42 locktorture.verbose=1 42 locktorture.verbose=1
43} 43}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
index cd3d29cb0a47..a3a1a05a2b5c 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
+++ b/tools/testing/selftests/rcutorture/configs/rcu/CFLIST
@@ -11,3 +11,6 @@ SRCU-N
11SRCU-P 11SRCU-P
12TINY01 12TINY01
13TINY02 13TINY02
14TASKS01
15TASKS02
16TASKS03
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS01 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01
new file mode 100644
index 000000000000..97f0a0b27ef7
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01
@@ -0,0 +1,9 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=2
3CONFIG_HOTPLUG_CPU=y
4CONFIG_PREEMPT_NONE=n
5CONFIG_PREEMPT_VOLUNTARY=n
6CONFIG_PREEMPT=y
7CONFIG_DEBUG_LOCK_ALLOC=y
8CONFIG_PROVE_RCU=y
9CONFIG_TASKS_RCU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot
new file mode 100644
index 000000000000..cd2a188eeb6d
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS01.boot
@@ -0,0 +1 @@
rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
new file mode 100644
index 000000000000..696d2ea74d13
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
@@ -0,0 +1,5 @@
1CONFIG_SMP=n
2CONFIG_PREEMPT_NONE=y
3CONFIG_PREEMPT_VOLUNTARY=n
4CONFIG_PREEMPT=n
5CONFIG_TASKS_RCU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot
new file mode 100644
index 000000000000..cd2a188eeb6d
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02.boot
@@ -0,0 +1 @@
rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
new file mode 100644
index 000000000000..9c60da5b5d1d
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03
@@ -0,0 +1,13 @@
1CONFIG_SMP=y
2CONFIG_NR_CPUS=2
3CONFIG_HOTPLUG_CPU=n
4CONFIG_SUSPEND=n
5CONFIG_HIBERNATION=n
6CONFIG_PREEMPT_NONE=n
7CONFIG_PREEMPT_VOLUNTARY=n
8CONFIG_PREEMPT=y
9CONFIG_TASKS_RCU=y
10CONFIG_HZ_PERIODIC=n
11CONFIG_NO_HZ_IDLE=n
12CONFIG_NO_HZ_FULL=y
13CONFIG_NO_HZ_FULL_ALL=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
new file mode 100644
index 000000000000..cd2a188eeb6d
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot
@@ -0,0 +1 @@
rcutorture.torture_type=tasks
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
index 063b7079c621..38e3895759dd 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
@@ -1,5 +1,4 @@
1CONFIG_SMP=y 1CONFIG_SMP=y
2CONFIG_NR_CPUS=8
3CONFIG_PREEMPT_NONE=n 2CONFIG_PREEMPT_NONE=n
4CONFIG_PREEMPT_VOLUNTARY=n 3CONFIG_PREEMPT_VOLUNTARY=n
5CONFIG_PREEMPT=y 4CONFIG_PREEMPT=y
@@ -10,8 +9,7 @@ CONFIG_NO_HZ_FULL=n
10CONFIG_RCU_FAST_NO_HZ=y 9CONFIG_RCU_FAST_NO_HZ=y
11CONFIG_RCU_TRACE=y 10CONFIG_RCU_TRACE=y
12CONFIG_HOTPLUG_CPU=y 11CONFIG_HOTPLUG_CPU=y
13CONFIG_RCU_FANOUT=8 12CONFIG_MAXSMP=y
14CONFIG_RCU_FANOUT_EXACT=n
15CONFIG_RCU_NOCB_CPU=y 13CONFIG_RCU_NOCB_CPU=y
16CONFIG_RCU_NOCB_CPU_ZERO=y 14CONFIG_RCU_NOCB_CPU_ZERO=y
17CONFIG_DEBUG_LOCK_ALLOC=n 15CONFIG_DEBUG_LOCK_ALLOC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
index 0fc8a3428938..adc3abc82fb8 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01.boot
@@ -1 +1 @@
rcutorture.torture_type=rcu_bh rcutorture.torture_type=rcu_bh maxcpus=8
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
index ab6225506909..8f1017666aa7 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
@@ -1,5 +1,6 @@
1CONFIG_SMP=y 1CONFIG_SMP=y
2CONFIG_NR_CPUS=16 2CONFIG_NR_CPUS=16
3CONFIG_CPUMASK_OFFSTACK=y
3CONFIG_PREEMPT_NONE=y 4CONFIG_PREEMPT_NONE=y
4CONFIG_PREEMPT_VOLUNTARY=n 5CONFIG_PREEMPT_VOLUNTARY=n
5CONFIG_PREEMPT=n 6CONFIG_PREEMPT=n
@@ -7,7 +8,7 @@ CONFIG_PREEMPT=n
7CONFIG_HZ_PERIODIC=n 8CONFIG_HZ_PERIODIC=n
8CONFIG_NO_HZ_IDLE=n 9CONFIG_NO_HZ_IDLE=n
9CONFIG_NO_HZ_FULL=y 10CONFIG_NO_HZ_FULL=y
10CONFIG_NO_HZ_FULL_ALL=y 11CONFIG_NO_HZ_FULL_ALL=n
11CONFIG_NO_HZ_FULL_SYSIDLE=y 12CONFIG_NO_HZ_FULL_SYSIDLE=y
12CONFIG_RCU_FAST_NO_HZ=n 13CONFIG_RCU_FAST_NO_HZ=n
13CONFIG_RCU_TRACE=y 14CONFIG_RCU_TRACE=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
new file mode 100644
index 000000000000..d44609937503
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
@@ -0,0 +1 @@
nohz_full=2-9
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
index 8977d8d31b19..ffb85ed786fa 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
+++ b/tools/testing/selftests/rcutorture/configs/rcu/ver_functions.sh
@@ -51,7 +51,7 @@ per_version_boot_params () {
51 `rcutorture_param_n_barrier_cbs "$1"` \ 51 `rcutorture_param_n_barrier_cbs "$1"` \
52 rcutorture.stat_interval=15 \ 52 rcutorture.stat_interval=15 \
53 rcutorture.shutdown_secs=$3 \ 53 rcutorture.shutdown_secs=$3 \
54 rcutorture.rcutorture_runnable=1 \ 54 rcutorture.torture_runnable=1 \
55 rcutorture.test_no_idle_hz=1 \ 55 rcutorture.test_no_idle_hz=1 \
56 rcutorture.verbose=1 56 rcutorture.verbose=1
57} 57}
diff --git a/tools/testing/selftests/rcutorture/doc/initrd.txt b/tools/testing/selftests/rcutorture/doc/initrd.txt
index 49d134c25c04..4170e714f044 100644
--- a/tools/testing/selftests/rcutorture/doc/initrd.txt
+++ b/tools/testing/selftests/rcutorture/doc/initrd.txt
@@ -6,6 +6,7 @@ this case. There are probably much better ways of doing this.
6That said, here are the commands: 6That said, here are the commands:
7 7
8------------------------------------------------------------------------ 8------------------------------------------------------------------------
9cd tools/testing/selftests/rcutorture
9zcat /initrd.img > /tmp/initrd.img.zcat 10zcat /initrd.img > /tmp/initrd.img.zcat
10mkdir initrd 11mkdir initrd
11cd initrd 12cd initrd
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index 3f94e1afd6cf..4c4b1f631ecf 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -3,6 +3,7 @@
3CC = $(CROSS_COMPILE)gcc 3CC = $(CROSS_COMPILE)gcc
4CFLAGS = -Wall 4CFLAGS = -Wall
5BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest 5BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest
6BINARIES += transhuge-stress
6 7
7all: $(BINARIES) 8all: $(BINARIES)
8%: %.c 9%: %.c
diff --git a/tools/testing/selftests/vm/transhuge-stress.c b/tools/testing/selftests/vm/transhuge-stress.c
new file mode 100644
index 000000000000..fd7f1b4a96f9
--- /dev/null
+++ b/tools/testing/selftests/vm/transhuge-stress.c
@@ -0,0 +1,144 @@
1/*
2 * Stress test for transparent huge pages, memory compaction and migration.
3 *
4 * Authors: Konstantin Khlebnikov <koct9i@gmail.com>
5 *
6 * This is free and unencumbered software released into the public domain.
7 */
8
9#include <stdlib.h>
10#include <stdio.h>
11#include <stdint.h>
12#include <err.h>
13#include <time.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <string.h>
17#include <sys/mman.h>
18
19#define PAGE_SHIFT 12
20#define HPAGE_SHIFT 21
21
22#define PAGE_SIZE (1 << PAGE_SHIFT)
23#define HPAGE_SIZE (1 << HPAGE_SHIFT)
24
25#define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0)
26#define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1))
27
28int pagemap_fd;
29
30int64_t allocate_transhuge(void *ptr)
31{
32 uint64_t ent[2];
33
34 /* drop pmd */
35 if (mmap(ptr, HPAGE_SIZE, PROT_READ | PROT_WRITE,
36 MAP_FIXED | MAP_ANONYMOUS |
37 MAP_NORESERVE | MAP_PRIVATE, -1, 0) != ptr)
38 errx(2, "mmap transhuge");
39
40 if (madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE))
41 err(2, "MADV_HUGEPAGE");
42
43 /* allocate transparent huge page */
44 *(volatile void **)ptr = ptr;
45
46 if (pread(pagemap_fd, ent, sizeof(ent),
47 (uintptr_t)ptr >> (PAGE_SHIFT - 3)) != sizeof(ent))
48 err(2, "read pagemap");
49
50 if (PAGEMAP_PRESENT(ent[0]) && PAGEMAP_PRESENT(ent[1]) &&
51 PAGEMAP_PFN(ent[0]) + 1 == PAGEMAP_PFN(ent[1]) &&
52 !(PAGEMAP_PFN(ent[0]) & ((1 << (HPAGE_SHIFT - PAGE_SHIFT)) - 1)))
53 return PAGEMAP_PFN(ent[0]);
54
55 return -1;
56}
57
58int main(int argc, char **argv)
59{
60 size_t ram, len;
61 void *ptr, *p;
62 struct timespec a, b;
63 double s;
64 uint8_t *map;
65 size_t map_len;
66
67 ram = sysconf(_SC_PHYS_PAGES);
68 if (ram > SIZE_MAX / sysconf(_SC_PAGESIZE) / 4)
69 ram = SIZE_MAX / 4;
70 else
71 ram *= sysconf(_SC_PAGESIZE);
72
73 if (argc == 1)
74 len = ram;
75 else if (!strcmp(argv[1], "-h"))
76 errx(1, "usage: %s [size in MiB]", argv[0]);
77 else
78 len = atoll(argv[1]) << 20;
79
80 warnx("allocate %zd transhuge pages, using %zd MiB virtual memory"
81 " and %zd MiB of ram", len >> HPAGE_SHIFT, len >> 20,
82 len >> (20 + HPAGE_SHIFT - PAGE_SHIFT - 1));
83
84 pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
85 if (pagemap_fd < 0)
86 err(2, "open pagemap");
87
88 len -= len % HPAGE_SIZE;
89 ptr = mmap(NULL, len + HPAGE_SIZE, PROT_READ | PROT_WRITE,
90 MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
91 if (ptr == MAP_FAILED)
92 err(2, "initial mmap");
93 ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE;
94
95 if (madvise(ptr, len, MADV_HUGEPAGE))
96 err(2, "MADV_HUGEPAGE");
97
98 map_len = ram >> (HPAGE_SHIFT - 1);
99 map = malloc(map_len);
100 if (!map)
101 errx(2, "map malloc");
102
103 while (1) {
104 int nr_succeed = 0, nr_failed = 0, nr_pages = 0;
105
106 memset(map, 0, map_len);
107
108 clock_gettime(CLOCK_MONOTONIC, &a);
109 for (p = ptr; p < ptr + len; p += HPAGE_SIZE) {
110 int64_t pfn;
111
112 pfn = allocate_transhuge(p);
113
114 if (pfn < 0) {
115 nr_failed++;
116 } else {
117 size_t idx = pfn >> (HPAGE_SHIFT - PAGE_SHIFT);
118
119 nr_succeed++;
120 if (idx >= map_len) {
121 map = realloc(map, idx + 1);
122 if (!map)
123 errx(2, "map realloc");
124 memset(map + map_len, 0, idx + 1 - map_len);
125 map_len = idx + 1;
126 }
127 if (!map[idx])
128 nr_pages++;
129 map[idx] = 1;
130 }
131
132 /* split transhuge page, keep last page */
133 if (madvise(p, HPAGE_SIZE - PAGE_SIZE, MADV_DONTNEED))
134 err(2, "MADV_DONTNEED");
135 }
136 clock_gettime(CLOCK_MONOTONIC, &b);
137 s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.;
138
139 warnx("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t"
140 "%4d succeed, %4d failed, %4d different pages",
141 s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20),
142 nr_succeed, nr_failed, nr_pages);
143 }
144}
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index a87e99f37c52..88d5e71be044 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * ffs-test.c.c -- user mode filesystem api for usb composite function 2 * ffs-test.c -- user mode filesystem api for usb composite function
3 * 3 *
4 * Copyright (C) 2010 Samsung Electronics 4 * Copyright (C) 2010 Samsung Electronics
5 * Author: Michal Nazarewicz <mina86@mina86.com> 5 * Author: Michal Nazarewicz <mina86@mina86.com>
@@ -29,6 +29,7 @@
29#include <fcntl.h> 29#include <fcntl.h>
30#include <pthread.h> 30#include <pthread.h>
31#include <stdarg.h> 31#include <stdarg.h>
32#include <stdbool.h>
32#include <stdio.h> 33#include <stdio.h>
33#include <stdlib.h> 34#include <stdlib.h>
34#include <string.h> 35#include <string.h>
@@ -106,7 +107,9 @@ static void _msg(unsigned level, const char *fmt, ...)
106/******************** Descriptors and Strings *******************************/ 107/******************** Descriptors and Strings *******************************/
107 108
108static const struct { 109static const struct {
109 struct usb_functionfs_descs_head header; 110 struct usb_functionfs_descs_head_v2 header;
111 __le32 fs_count;
112 __le32 hs_count;
110 struct { 113 struct {
111 struct usb_interface_descriptor intf; 114 struct usb_interface_descriptor intf;
112 struct usb_endpoint_descriptor_no_audio sink; 115 struct usb_endpoint_descriptor_no_audio sink;
@@ -114,11 +117,12 @@ static const struct {
114 } __attribute__((packed)) fs_descs, hs_descs; 117 } __attribute__((packed)) fs_descs, hs_descs;
115} __attribute__((packed)) descriptors = { 118} __attribute__((packed)) descriptors = {
116 .header = { 119 .header = {
117 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), 120 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
121 .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC |
122 FUNCTIONFS_HAS_HS_DESC),
118 .length = cpu_to_le32(sizeof descriptors), 123 .length = cpu_to_le32(sizeof descriptors),
119 .fs_count = cpu_to_le32(3),
120 .hs_count = cpu_to_le32(3),
121 }, 124 },
125 .fs_count = cpu_to_le32(3),
122 .fs_descs = { 126 .fs_descs = {
123 .intf = { 127 .intf = {
124 .bLength = sizeof descriptors.fs_descs.intf, 128 .bLength = sizeof descriptors.fs_descs.intf,
@@ -142,6 +146,7 @@ static const struct {
142 /* .wMaxPacketSize = autoconfiguration (kernel) */ 146 /* .wMaxPacketSize = autoconfiguration (kernel) */
143 }, 147 },
144 }, 148 },
149 .hs_count = cpu_to_le32(3),
145 .hs_descs = { 150 .hs_descs = {
146 .intf = { 151 .intf = {
147 .bLength = sizeof descriptors.fs_descs.intf, 152 .bLength = sizeof descriptors.fs_descs.intf,
@@ -168,6 +173,89 @@ static const struct {
168 }, 173 },
169}; 174};
170 175
176static size_t descs_to_legacy(void **legacy, const void *descriptors_v2)
177{
178 const unsigned char *descs_end, *descs_start;
179 __u32 length, fs_count = 0, hs_count = 0, count;
180
181 /* Read v2 header */
182 {
183 const struct {
184 const struct usb_functionfs_descs_head_v2 header;
185 const __le32 counts[];
186 } __attribute__((packed)) *const in = descriptors_v2;
187 const __le32 *counts = in->counts;
188 __u32 flags;
189
190 if (le32_to_cpu(in->header.magic) !=
191 FUNCTIONFS_DESCRIPTORS_MAGIC_V2)
192 return 0;
193 length = le32_to_cpu(in->header.length);
194 if (length <= sizeof in->header)
195 return 0;
196 length -= sizeof in->header;
197 flags = le32_to_cpu(in->header.flags);
198 if (flags & ~(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
199 FUNCTIONFS_HAS_SS_DESC))
200 return 0;
201
202#define GET_NEXT_COUNT_IF_FLAG(ret, flg) do { \
203 if (!(flags & (flg))) \
204 break; \
205 if (length < 4) \
206 return 0; \
207 ret = le32_to_cpu(*counts); \
208 length -= 4; \
209 ++counts; \
210 } while (0)
211
212 GET_NEXT_COUNT_IF_FLAG(fs_count, FUNCTIONFS_HAS_FS_DESC);
213 GET_NEXT_COUNT_IF_FLAG(hs_count, FUNCTIONFS_HAS_HS_DESC);
214 GET_NEXT_COUNT_IF_FLAG(count, FUNCTIONFS_HAS_SS_DESC);
215
216 count = fs_count + hs_count;
217 if (!count)
218 return 0;
219 descs_start = (const void *)counts;
220
221#undef GET_NEXT_COUNT_IF_FLAG
222 }
223
224 /*
225 * Find the end of FS and HS USB descriptors. SS descriptors
226 * are ignored since legacy format does not support them.
227 */
228 descs_end = descs_start;
229 do {
230 if (length < *descs_end)
231 return 0;
232 length -= *descs_end;
233 descs_end += *descs_end;
234 } while (--count);
235
236 /* Allocate legacy descriptors and copy the data. */
237 {
238#pragma GCC diagnostic push
239#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
240 struct {
241 struct usb_functionfs_descs_head header;
242 __u8 descriptors[];
243 } __attribute__((packed)) *out;
244#pragma GCC diagnostic pop
245
246 length = sizeof out->header + (descs_end - descs_start);
247 out = malloc(length);
248 out->header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
249 out->header.length = cpu_to_le32(length);
250 out->header.fs_count = cpu_to_le32(fs_count);
251 out->header.hs_count = cpu_to_le32(hs_count);
252 memcpy(out->descriptors, descs_start, descs_end - descs_start);
253 *legacy = out;
254 }
255
256 return length;
257}
258
171 259
172#define STR_INTERFACE_ "Source/Sink" 260#define STR_INTERFACE_ "Source/Sink"
173 261
@@ -487,12 +575,29 @@ ep0_consume(struct thread *ignore, const void *buf, size_t nbytes)
487 return nbytes; 575 return nbytes;
488} 576}
489 577
490static void ep0_init(struct thread *t) 578static void ep0_init(struct thread *t, bool legacy_descriptors)
491{ 579{
580 void *legacy;
492 ssize_t ret; 581 ssize_t ret;
582 size_t len;
583
584 if (legacy_descriptors) {
585 info("%s: writing descriptors\n", t->filename);
586 goto legacy;
587 }
493 588
494 info("%s: writing descriptors\n", t->filename); 589 info("%s: writing descriptors (in v2 format)\n", t->filename);
495 ret = write(t->fd, &descriptors, sizeof descriptors); 590 ret = write(t->fd, &descriptors, sizeof descriptors);
591
592 if (ret < 0 && errno == EINVAL) {
593 warn("%s: new format rejected, trying legacy\n", t->filename);
594legacy:
595 len = descs_to_legacy(&legacy, &descriptors);
596 if (len) {
597 ret = write(t->fd, legacy, len);
598 free(legacy);
599 }
600 }
496 die_on(ret < 0, "%s: write: descriptors", t->filename); 601 die_on(ret < 0, "%s: write: descriptors", t->filename);
497 602
498 info("%s: writing strings\n", t->filename); 603 info("%s: writing strings\n", t->filename);
@@ -503,14 +608,15 @@ static void ep0_init(struct thread *t)
503 608
504/******************** Main **************************************************/ 609/******************** Main **************************************************/
505 610
506int main(void) 611int main(int argc, char **argv)
507{ 612{
613 bool legacy_descriptors;
508 unsigned i; 614 unsigned i;
509 615
510 /* XXX TODO: Argument parsing missing */ 616 legacy_descriptors = argc > 2 && !strcmp(argv[1], "-l");
511 617
512 init_thread(threads); 618 init_thread(threads);
513 ep0_init(threads); 619 ep0_init(threads, legacy_descriptors);
514 620
515 for (i = 1; i < sizeof threads / sizeof *threads; ++i) 621 for (i = 1; i < sizeof threads / sizeof *threads; ++i)
516 init_thread(threads + i); 622 init_thread(threads + i);
diff --git a/tools/usb/usbip/.gitignore b/tools/usb/usbip/.gitignore
new file mode 100644
index 000000000000..9aad9e30a8ba
--- /dev/null
+++ b/tools/usb/usbip/.gitignore
@@ -0,0 +1,28 @@
1Makefile
2Makefile.in
3aclocal.m4
4autom4te.cache/
5config.guess
6config.h
7config.h.in
8config.log
9config.status
10config.sub
11configure
12depcomp
13install-sh
14libsrc/Makefile
15libsrc/Makefile.in
16libtool
17ltmain.sh
18missing
19src/Makefile
20src/Makefile.in
21stamp-h1
22libsrc/libusbip.la
23libsrc/libusbip_la-names.lo
24libsrc/libusbip_la-usbip_common.lo
25libsrc/libusbip_la-usbip_host_driver.lo
26libsrc/libusbip_la-vhci_driver.lo
27src/usbip
28src/usbipd
diff --git a/tools/usb/usbip/AUTHORS b/tools/usb/usbip/AUTHORS
new file mode 100644
index 000000000000..a27ea8d03aec
--- /dev/null
+++ b/tools/usb/usbip/AUTHORS
@@ -0,0 +1,3 @@
1Takahiro Hirofuchi
2Robert Leibl
3matt mooney <mfm@muteddisk.com>
diff --git a/tools/usb/usbip/COPYING b/tools/usb/usbip/COPYING
new file mode 100644
index 000000000000..c5611e48a8e1
--- /dev/null
+++ b/tools/usb/usbip/COPYING
@@ -0,0 +1,340 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Library General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License
307 along with this program; if not, write to the Free Software
308 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
309
310
311Also add information on how to contact you by electronic and paper mail.
312
313If the program is interactive, make it output a short notice like this
314when it starts in an interactive mode:
315
316 Gnomovision version 69, Copyright (C) year name of author
317 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
318 This is free software, and you are welcome to redistribute it
319 under certain conditions; type `show c' for details.
320
321The hypothetical commands `show w' and `show c' should show the appropriate
322parts of the General Public License. Of course, the commands you use may
323be called something other than `show w' and `show c'; they could even be
324mouse-clicks or menu items--whatever suits your program.
325
326You should also get your employer (if you work as a programmer) or your
327school, if any, to sign a "copyright disclaimer" for the program, if
328necessary. Here is a sample; alter the names:
329
330 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
331 `Gnomovision' (which makes passes at compilers) written by James Hacker.
332
333 <signature of Ty Coon>, 1 April 1989
334 Ty Coon, President of Vice
335
336This General Public License does not permit incorporating your program into
337proprietary programs. If your program is a subroutine library, you may
338consider it more useful to permit linking proprietary applications with the
339library. If this is what you want to do, use the GNU Library General
340Public License instead of this License.
diff --git a/tools/usb/usbip/INSTALL b/tools/usb/usbip/INSTALL
new file mode 100644
index 000000000000..d3c5b40a9409
--- /dev/null
+++ b/tools/usb/usbip/INSTALL
@@ -0,0 +1,237 @@
1Installation Instructions
2*************************
3
4Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
52006, 2007 Free Software Foundation, Inc.
6
7This file is free documentation; the Free Software Foundation gives
8unlimited permission to copy, distribute and modify it.
9
10Basic Installation
11==================
12
13Briefly, the shell commands `./configure; make; make install' should
14configure, build, and install this package. The following
15more-detailed instructions are generic; see the `README' file for
16instructions specific to this package.
17
18 The `configure' shell script attempts to guess correct values for
19various system-dependent variables used during compilation. It uses
20those values to create a `Makefile' in each directory of the package.
21It may also create one or more `.h' files containing system-dependent
22definitions. Finally, it creates a shell script `config.status' that
23you can run in the future to recreate the current configuration, and a
24file `config.log' containing compiler output (useful mainly for
25debugging `configure').
26
27 It can also use an optional file (typically called `config.cache'
28and enabled with `--cache-file=config.cache' or simply `-C') that saves
29the results of its tests to speed up reconfiguring. Caching is
30disabled by default to prevent problems with accidental use of stale
31cache files.
32
33 If you need to do unusual things to compile the package, please try
34to figure out how `configure' could check whether to do them, and mail
35diffs or instructions to the address given in the `README' so they can
36be considered for the next release. If you are using the cache, and at
37some point `config.cache' contains results you don't want to keep, you
38may remove or edit it.
39
40 The file `configure.ac' (or `configure.in') is used to create
41`configure' by a program called `autoconf'. You need `configure.ac' if
42you want to change it or regenerate `configure' using a newer version
43of `autoconf'.
44
45The simplest way to compile this package is:
46
47 1. `cd' to the directory containing the package's source code and type
48 `./configure' to configure the package for your system.
49
50 Running `configure' might take a while. While running, it prints
51 some messages telling which features it is checking for.
52
53 2. Type `make' to compile the package.
54
55 3. Optionally, type `make check' to run any self-tests that come with
56 the package.
57
58 4. Type `make install' to install the programs and any data files and
59 documentation.
60
61 5. You can remove the program binaries and object files from the
62 source code directory by typing `make clean'. To also remove the
63 files that `configure' created (so you can compile the package for
64 a different kind of computer), type `make distclean'. There is
65 also a `make maintainer-clean' target, but that is intended mainly
66 for the package's developers. If you use it, you may have to get
67 all sorts of other programs in order to regenerate files that came
68 with the distribution.
69
70 6. Often, you can also type `make uninstall' to remove the installed
71 files again.
72
73Compilers and Options
74=====================
75
76Some systems require unusual options for compilation or linking that the
77`configure' script does not know about. Run `./configure --help' for
78details on some of the pertinent environment variables.
79
80 You can give `configure' initial values for configuration parameters
81by setting variables in the command line or in the environment. Here
82is an example:
83
84 ./configure CC=c99 CFLAGS=-g LIBS=-lposix
85
86 *Note Defining Variables::, for more details.
87
88Compiling For Multiple Architectures
89====================================
90
91You can compile the package for more than one kind of computer at the
92same time, by placing the object files for each architecture in their
93own directory. To do this, you can use GNU `make'. `cd' to the
94directory where you want the object files and executables to go and run
95the `configure' script. `configure' automatically checks for the
96source code in the directory that `configure' is in and in `..'.
97
98 With a non-GNU `make', it is safer to compile the package for one
99architecture at a time in the source code directory. After you have
100installed the package for one architecture, use `make distclean' before
101reconfiguring for another architecture.
102
103Installation Names
104==================
105
106By default, `make install' installs the package's commands under
107`/usr/local/bin', include files under `/usr/local/include', etc. You
108can specify an installation prefix other than `/usr/local' by giving
109`configure' the option `--prefix=PREFIX'.
110
111 You can specify separate installation prefixes for
112architecture-specific files and architecture-independent files. If you
113pass the option `--exec-prefix=PREFIX' to `configure', the package uses
114PREFIX as the prefix for installing programs and libraries.
115Documentation and other data files still use the regular prefix.
116
117 In addition, if you use an unusual directory layout you can give
118options like `--bindir=DIR' to specify different values for particular
119kinds of files. Run `configure --help' for a list of the directories
120you can set and what kinds of files go in them.
121
122 If the package supports it, you can cause programs to be installed
123with an extra prefix or suffix on their names by giving `configure' the
124option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
125
126Optional Features
127=================
128
129Some packages pay attention to `--enable-FEATURE' options to
130`configure', where FEATURE indicates an optional part of the package.
131They may also pay attention to `--with-PACKAGE' options, where PACKAGE
132is something like `gnu-as' or `x' (for the X Window System). The
133`README' should mention any `--enable-' and `--with-' options that the
134package recognizes.
135
136 For packages that use the X Window System, `configure' can usually
137find the X include and library files automatically, but if it doesn't,
138you can use the `configure' options `--x-includes=DIR' and
139`--x-libraries=DIR' to specify their locations.
140
141Specifying the System Type
142==========================
143
144There may be some features `configure' cannot figure out automatically,
145but needs to determine by the type of machine the package will run on.
146Usually, assuming the package is built to be run on the _same_
147architectures, `configure' can figure that out, but if it prints a
148message saying it cannot guess the machine type, give it the
149`--build=TYPE' option. TYPE can either be a short name for the system
150type, such as `sun4', or a canonical name which has the form:
151
152 CPU-COMPANY-SYSTEM
153
154where SYSTEM can have one of these forms:
155
156 OS KERNEL-OS
157
158 See the file `config.sub' for the possible values of each field. If
159`config.sub' isn't included in this package, then this package doesn't
160need to know the machine type.
161
162 If you are _building_ compiler tools for cross-compiling, you should
163use the option `--target=TYPE' to select the type of system they will
164produce code for.
165
166 If you want to _use_ a cross compiler, that generates code for a
167platform different from the build platform, you should specify the
168"host" platform (i.e., that on which the generated programs will
169eventually be run) with `--host=TYPE'.
170
171Sharing Defaults
172================
173
174If you want to set default values for `configure' scripts to share, you
175can create a site shell script called `config.site' that gives default
176values for variables like `CC', `cache_file', and `prefix'.
177`configure' looks for `PREFIX/share/config.site' if it exists, then
178`PREFIX/etc/config.site' if it exists. Or, you can set the
179`CONFIG_SITE' environment variable to the location of the site script.
180A warning: not all `configure' scripts look for a site script.
181
182Defining Variables
183==================
184
185Variables not defined in a site shell script can be set in the
186environment passed to `configure'. However, some packages may run
187configure again during the build, and the customized values of these
188variables may be lost. In order to avoid this problem, you should set
189them in the `configure' command line, using `VAR=value'. For example:
190
191 ./configure CC=/usr/local2/bin/gcc
192
193causes the specified `gcc' to be used as the C compiler (unless it is
194overridden in the site shell script).
195
196Unfortunately, this technique does not work for `CONFIG_SHELL' due to
197an Autoconf bug. Until the bug is fixed you can use this workaround:
198
199 CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
200
201`configure' Invocation
202======================
203
204`configure' recognizes the following options to control how it operates.
205
206`--help'
207`-h'
208 Print a summary of the options to `configure', and exit.
209
210`--version'
211`-V'
212 Print the version of Autoconf used to generate the `configure'
213 script, and exit.
214
215`--cache-file=FILE'
216 Enable the cache: use and save the results of the tests in FILE,
217 traditionally `config.cache'. FILE defaults to `/dev/null' to
218 disable caching.
219
220`--config-cache'
221`-C'
222 Alias for `--cache-file=config.cache'.
223
224`--quiet'
225`--silent'
226`-q'
227 Do not print messages saying which checks are being made. To
228 suppress all normal output, redirect it to `/dev/null' (any error
229 messages will still be shown).
230
231`--srcdir=DIR'
232 Look for the package's source code in directory DIR. Usually
233 `configure' can determine that directory automatically.
234
235`configure' also accepts some other, not widely useful, options. Run
236`configure --help' for more details.
237
diff --git a/tools/usb/usbip/Makefile.am b/tools/usb/usbip/Makefile.am
new file mode 100644
index 000000000000..66f8bf038c9f
--- /dev/null
+++ b/tools/usb/usbip/Makefile.am
@@ -0,0 +1,6 @@
1SUBDIRS := libsrc src
2includedir = @includedir@/usbip
3include_HEADERS := $(addprefix libsrc/, \
4 usbip_common.h vhci_driver.h usbip_host_driver.h)
5
6dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8)
diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README
new file mode 100644
index 000000000000..831f49fea3ce
--- /dev/null
+++ b/tools/usb/usbip/README
@@ -0,0 +1,202 @@
1#
2# README for usbip-utils
3#
4# Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
5# 2005-2008 Takahiro Hirofuchi
6
7
8[Requirements]
9 - USB/IP device drivers
10 Found in the staging directory of the Linux kernel.
11
12 - libudev >= 2.0
13 libudev library
14
15 - libwrap0-dev
16 tcp wrapper library
17
18 - gcc >= 4.0
19
20 - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config
21
22[Optional]
23 - hwdata
24 Contains USB device identification data.
25
26
27[Install]
28 0. Generate configuration scripts.
29 $ ./autogen.sh
30
31 1. Compile & install the userspace utilities.
32 $ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=<dir>]
33 $ make install
34
35 2. Compile & install USB/IP drivers.
36
37
38[Usage]
39 server:# (Physically attach your USB device.)
40
41 server:# insmod usbip-core.ko
42 server:# insmod usbip-host.ko
43
44 server:# usbipd -D
45 - Start usbip daemon.
46
47 server:# usbip list -l
48 - List driver assignments for USB devices.
49
50 server:# usbip bind --busid 1-2
51 - Bind usbip-host.ko to the device with busid 1-2.
52 - The USB device 1-2 is now exportable to other hosts!
53 - Use `usbip unbind --busid 1-2' to stop exporting the device.
54
55 client:# insmod usbip-core.ko
56 client:# insmod vhci-hcd.ko
57
58 client:# usbip list --remote <host>
59 - List exported USB devices on the <host>.
60
61 client:# usbip attach --remote <host> --busid 1-2
62 - Connect the remote USB device.
63
64 client:# usbip port
65 - Show virtual port status.
66
67 client:# usbip detach --port <port>
68 - Detach the USB device.
69
70
71[Example]
72---------------------------
73 SERVER SIDE
74---------------------------
75Physically attach your USB devices to this host.
76
77 trois:# insmod path/to/usbip-core.ko
78 trois:# insmod path/to/usbip-host.ko
79 trois:# usbipd -D
80
81In another terminal, let's look up what USB devices are physically
82attached to this host.
83
84 trois:# usbip list -l
85 Local USB devices
86 =================
87 - busid 1-1 (05a9:a511)
88 1-1:1.0 -> ov511
89
90 - busid 3-2 (0711:0902)
91 3-2:1.0 -> none
92
93 - busid 3-3.1 (08bb:2702)
94 3-3.1:1.0 -> snd-usb-audio
95 3-3.1:1.1 -> snd-usb-audio
96
97 - busid 3-3.2 (04bb:0206)
98 3-3.2:1.0 -> usb-storage
99
100 - busid 3-3 (0409:0058)
101 3-3:1.0 -> hub
102
103 - busid 4-1 (046d:08b2)
104 4-1:1.0 -> none
105 4-1:1.1 -> none
106 4-1:1.2 -> none
107
108 - busid 5-2 (058f:9254)
109 5-2:1.0 -> hub
110
111A USB storage device of busid 3-3.2 is now bound to the usb-storage
112driver. To export this device, we first mark the device as
113"exportable"; the device is bound to the usbip-host driver. Please
114remember you can not export a USB hub.
115
116Mark the device of busid 3-3.2 as exportable:
117
118 trois:# usbip --debug bind --busid 3-3.2
119 ...
120 usbip debug: usbip_bind.c:162:[unbind_other] 3-3.2:1.0 -> usb-storage
121 ...
122 bind device on busid 3-3.2: complete
123
124 trois:# usbip list -l
125 Local USB devices
126 =================
127 ...
128
129 - busid 3-3.2 (04bb:0206)
130 3-3.2:1.0 -> usbip-host
131 ...
132
133---------------------------
134 CLIENT SIDE
135---------------------------
136First, let's list available remote devices that are marked as
137exportable on the host.
138
139 deux:# insmod path/to/usbip-core.ko
140 deux:# insmod path/to/vhci-hcd.ko
141
142 deux:# usbip list --remote 10.0.0.3
143 Exportable USB devices
144 ======================
145 - 10.0.0.3
146 1-1: Prolific Technology, Inc. : unknown product (067b:3507)
147 : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-1
148 : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
149 : 0 - Mass Storage / SCSI / Bulk (Zip) (08/06/50)
150
151 1-2.2.1: Apple Computer, Inc. : unknown product (05ac:0203)
152 : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.1
153 : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
154 : 0 - Human Interface Devices / Boot Interface Subclass / Keyboard (03/01/01)
155
156 1-2.2.3: OmniVision Technologies, Inc. : OV511+ WebCam (05a9:a511)
157 : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.3
158 : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
159 : 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00)
160
161 3-1: Logitech, Inc. : QuickCam Pro 4000 (046d:08b2)
162 : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.0/usb3/3-1
163 : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
164 : 0 - Data / unknown subclass / unknown protocol (0a/ff/00)
165 : 1 - Audio / Control Device / unknown protocol (01/01/00)
166 : 2 - Audio / Streaming / unknown protocol (01/02/00)
167
168Attach a remote USB device:
169
170 deux:# usbip attach --remote 10.0.0.3 --busid 1-1
171 port 0 attached
172
173Show the devices attached to this client:
174
175 deux:# usbip port
176 Port 00: <Port in Use> at Full Speed(12Mbps)
177 Prolific Technology, Inc. : unknown product (067b:3507)
178 6-1 -> usbip://10.0.0.3:3240/1-1 (remote bus/dev 001/004)
179 6-1:1.0 used by usb-storage
180 /sys/class/scsi_device/0:0:0:0/device
181 /sys/class/scsi_host/host0/device
182 /sys/block/sda/device
183
184Detach the imported device:
185
186 deux:# usbip detach --port 0
187 port 0 detached
188
189
190[Checklist]
191 - See 'Debug Tips' on the project wiki.
192 - http://usbip.wiki.sourceforge.net/how-to-debug-usbip
193 - usbip-host.ko must be bound to the target device.
194 - See /proc/bus/usb/devices and find "Driver=..." lines of the device.
195 - Shutdown firewall.
196 - usbip now uses TCP port 3240.
197 - Disable SELinux.
198 - Check the kernel and daemon messages.
199
200
201[Contact]
202 Mailing List: linux-usb@vger.kernel.org
diff --git a/tools/usb/usbip/autogen.sh b/tools/usb/usbip/autogen.sh
new file mode 100755
index 000000000000..e1112d3fcbf6
--- /dev/null
+++ b/tools/usb/usbip/autogen.sh
@@ -0,0 +1,9 @@
1#!/bin/sh -x
2
3#aclocal
4#autoheader
5#libtoolize --copy --force
6#automake-1.9 -acf
7#autoconf
8
9autoreconf -i -f -v
diff --git a/tools/usb/usbip/cleanup.sh b/tools/usb/usbip/cleanup.sh
new file mode 100755
index 000000000000..955c3ccb729a
--- /dev/null
+++ b/tools/usb/usbip/cleanup.sh
@@ -0,0 +1,12 @@
1#!/bin/sh
2
3if [ -r Makefile ]; then
4 make distclean
5fi
6
7FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \
8 config.status config.sub configure cscope.out depcomp install-sh \
9 libsrc/Makefile libsrc/Makefile.in libtool ltmain.sh Makefile \
10 Makefile.in missing src/Makefile src/Makefile.in"
11
12rm -vRf $FILES
diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac
new file mode 100644
index 000000000000..607d05c5ccfd
--- /dev/null
+++ b/tools/usb/usbip/configure.ac
@@ -0,0 +1,111 @@
1dnl Process this file with autoconf to produce a configure script.
2
3AC_PREREQ(2.59)
4AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org])
5AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number])
6
7CURRENT=0
8REVISION=1
9AGE=0
10AC_SUBST([LIBUSBIP_VERSION], [$CURRENT:$REVISION:$AGE], [library version])
11
12AC_CONFIG_SRCDIR([src/usbipd.c])
13AC_CONFIG_HEADERS([config.h])
14
15AM_INIT_AUTOMAKE([foreign])
16LT_INIT
17
18# Silent build for automake >= 1.11
19m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
20
21AC_SUBST([EXTRA_CFLAGS], ["-Wall -Werror -Wextra -std=gnu99"])
22
23# Checks for programs.
24AC_PROG_CC
25AC_PROG_INSTALL
26AC_PROG_MAKE_SET
27
28# Checks for header files.
29AC_HEADER_DIRENT
30AC_HEADER_STDC
31AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h dnl
32 string.h sys/socket.h syslog.h unistd.h])
33
34# Checks for typedefs, structures, and compiler characteristics.
35AC_TYPE_INT32_T
36AC_TYPE_SIZE_T
37AC_TYPE_SSIZE_T
38AC_TYPE_UINT16_T
39AC_TYPE_UINT32_T
40AC_TYPE_UINT8_T
41
42# Checks for library functions.
43AC_FUNC_REALLOC
44AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl
45 strtoul])
46
47AC_CHECK_HEADER([libudev.h],
48 [AC_CHECK_LIB([udev], [udev_new],
49 [LIBS="$LIBS -ludev"],
50 [AC_MSG_ERROR([Missing udev library!])])],
51 [AC_MSG_ERROR([Missing /usr/include/libudev.h])])
52
53# Checks for libwrap library.
54AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library])
55AC_ARG_WITH([tcp-wrappers],
56 [AS_HELP_STRING([--with-tcp-wrappers],
57 [use the libwrap (TCP wrappers) library])],
58 dnl [ACTION-IF-GIVEN]
59 [if test "$withval" = "yes"; then
60 AC_MSG_RESULT([yes])
61 AC_MSG_CHECKING([for hosts_access in -lwrap])
62 saved_LIBS="$LIBS"
63 LIBS="-lwrap $saved_LIBS"
64 AC_TRY_LINK(
65 [int hosts_access(); int allow_severity, deny_severity;],
66 [hosts_access()],
67 [AC_MSG_RESULT([yes]);
68 AC_DEFINE([HAVE_LIBWRAP], [1],
69 [use tcp wrapper]) wrap_LIB="-lwrap"],
70 [AC_MSG_RESULT([not found]); exit 1])
71 else
72 AC_MSG_RESULT([no]);
73 fi],
74 dnl [ACTION-IF-NOT-GIVEN]
75 [AC_MSG_RESULT([(default)])
76 AC_MSG_CHECKING([for hosts_access in -lwrap])
77 saved_LIBS="$LIBS"
78 LIBS="-lwrap $saved_LIBS"
79 AC_TRY_LINK(
80 [int hosts_access(); int allow_severity, deny_severity;],
81 [hosts_access()],
82 [AC_MSG_RESULT([yes]);
83 AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])],
84 [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])])
85
86# Sets directory containing usb.ids.
87AC_ARG_WITH([usbids-dir],
88 [AS_HELP_STRING([--with-usbids-dir=DIR],
89 [where usb.ids is found (default /usr/share/hwdata/)])],
90 [USBIDS_DIR=$withval], [USBIDS_DIR="/usr/share/hwdata/"])
91AC_SUBST([USBIDS_DIR])
92
93# use _FORTIFY_SOURCE
94AC_MSG_CHECKING([whether to use fortify])
95AC_ARG_WITH([fortify],
96 [AS_HELP_STRING([--with-fortify],
97 [use _FORTIFY_SROUCE option when compiling)])],
98 dnl [ACTION-IF-GIVEN]
99 [if test "$withval" = "yes"; then
100 AC_MSG_RESULT([yes])
101 CFLAGS="$CFLAGS -D_FORTIFY_SOURCE -O"
102 else
103 AC_MSG_RESULT([no])
104 CFLAGS="$CFLAGS -U_FORTIFY_SOURCE"
105 fi
106 ],
107 dnl [ACTION-IF-NOT-GIVEN]
108 [AC_MSG_RESULT([default])])
109
110AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile])
111AC_OUTPUT
diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
new file mode 100644
index 000000000000..a6097be25d28
--- /dev/null
+++ b/tools/usb/usbip/doc/usbip.8
@@ -0,0 +1,95 @@
1.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
2.SH NAME
3usbip \- manage USB/IP devices
4.SH SYNOPSIS
5.B usbip
6[\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR>
7
8.SH DESCRIPTION
9On a USB/IP server, devices can be listed, bound, and unbound using
10this program. On a USB/IP client, devices exported by USB/IP servers
11can be listed, attached and detached.
12
13.SH OPTIONS
14.HP
15\fB\-\-debug\fR
16.IP
17Print debugging information.
18.PP
19
20.HP
21\fB\-\-log\fR
22.IP
23Log to syslog.
24.PP
25
26.HP
27\fB\-\-tcp-port PORT\fR
28.IP
29Connect to PORT on remote host (used for attach and list --remote).
30.PP
31
32.SH COMMANDS
33.HP
34\fBversion\fR
35.IP
36Show version and exit.
37.PP
38
39.HP
40\fBhelp\fR [\fIcommand\fR]
41.IP
42Print the program help message, or help on a specific command, and
43then exit.
44.PP
45
46.HP
47\fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR>
48.IP
49Attach a remote USB device.
50.PP
51
52.HP
53\fBdetach\fR \-\-port=<\fIport\fR>
54.IP
55Detach an imported USB device.
56.PP
57
58.HP
59\fBbind\fR \-\-busid=<\fIbusid\fR>
60.IP
61Make a device exportable.
62.PP
63
64.HP
65\fBunbind\fR \-\-busid=<\fIbusid\fR>
66.IP
67Stop exporting a device so it can be used by a local driver.
68.PP
69
70.HP
71\fBlist\fR \-\-remote=<\fIhost\fR>
72.IP
73List USB devices exported by a remote host.
74.PP
75
76.HP
77\fBlist\fR \-\-local
78.IP
79List local USB devices.
80.PP
81
82
83.SH EXAMPLES
84
85 client:# usbip list --remote=server
86 - List exportable usb devices on the server.
87
88 client:# usbip attach --remote=server --busid=1-2
89 - Connect the remote USB device.
90
91 client:# usbip detach --port=0
92 - Detach the usb device.
93
94.SH "SEE ALSO"
95\fBusbipd\fP\fB(8)\fB\fP
diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8
new file mode 100644
index 000000000000..ac4635db3f03
--- /dev/null
+++ b/tools/usb/usbip/doc/usbipd.8
@@ -0,0 +1,91 @@
1.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
2.SH NAME
3usbipd \- USB/IP server daemon
4.SH SYNOPSIS
5.B usbipd
6[\fIoptions\fR]
7
8.SH DESCRIPTION
9.B usbipd
10provides USB/IP clients access to exported USB devices.
11
12Devices have to explicitly be exported using
13.B usbip bind
14before usbipd makes them available to other hosts.
15
16The daemon accepts connections from USB/IP clients
17on TCP port 3240 by default.
18
19.SH OPTIONS
20.HP
21\fB\-4\fR, \fB\-\-ipv4\fR
22.IP
23Bind to IPv4. Default is both.
24.PP
25
26.HP
27\fB\-6\fR, \fB\-\-ipv6\fR
28.IP
29Bind to IPv6. Default is both.
30.PP
31
32.HP
33\fB\-D\fR, \fB\-\-daemon\fR
34.IP
35Run as a daemon process.
36.PP
37
38.HP
39\fB\-d\fR, \fB\-\-debug\fR
40.IP
41Print debugging information.
42.PP
43
44.HP
45\fB\-PFILE\fR, \fB\-\-pid FILE\fR
46.IP
47Write process id to FILE.
48.br
49If no FILE specified, use /var/run/usbipd.pid
50.PP
51
52\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR
53.IP
54Listen on TCP/IP port PORT.
55.PP
56
57\fB\-h\fR, \fB\-\-help\fR
58.IP
59Print the program help message and exit.
60.PP
61
62.HP
63\fB\-v\fR, \fB\-\-version\fR
64.IP
65Show version.
66.PP
67
68.SH LIMITATIONS
69
70.B usbipd
71offers no authentication or authorization for USB/IP. Any
72USB/IP client can connect and use exported devices.
73
74.SH EXAMPLES
75
76 server:# modprobe usbip
77
78 server:# usbipd -D
79 - Start usbip daemon.
80
81 server:# usbip list --local
82 - List driver assignments for usb devices.
83
84 server:# usbip bind --busid=1-2
85 - Bind usbip-host.ko to the device of busid 1-2.
86 - A usb device 1-2 is now exportable to other hosts!
87 - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally.
88
89.SH "SEE ALSO"
90\fBusbip\fP\fB(8)\fB\fP
91
diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am
new file mode 100644
index 000000000000..7c8f8a4d54e4
--- /dev/null
+++ b/tools/usb/usbip/libsrc/Makefile.am
@@ -0,0 +1,8 @@
1libusbip_la_CPPFLAGS = -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
2libusbip_la_CFLAGS = @EXTRA_CFLAGS@
3libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@
4
5lib_LTLIBRARIES := libusbip.la
6libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \
7 usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \
8 sysfs_utils.c sysfs_utils.h
diff --git a/tools/usb/usbip/libsrc/list.h b/tools/usb/usbip/libsrc/list.h
new file mode 100644
index 000000000000..8d0c936e184f
--- /dev/null
+++ b/tools/usb/usbip/libsrc/list.h
@@ -0,0 +1,136 @@
1#ifndef _LIST_H
2#define _LIST_H
3
4/* Stripped down implementation of linked list taken
5 * from the Linux Kernel.
6 */
7
8/*
9 * Simple doubly linked list implementation.
10 *
11 * Some of the internal functions ("__xxx") are useful when
12 * manipulating whole lists rather than single entries, as
13 * sometimes we already know the next/prev entries and we can
14 * generate better code by using them directly rather than
15 * using the generic single-entry routines.
16 */
17
18struct list_head {
19 struct list_head *next, *prev;
20};
21
22#define LIST_HEAD_INIT(name) { &(name), &(name) }
23
24#define LIST_HEAD(name) \
25 struct list_head name = LIST_HEAD_INIT(name)
26
27static inline void INIT_LIST_HEAD(struct list_head *list)
28{
29 list->next = list;
30 list->prev = list;
31}
32
33/*
34 * Insert a new entry between two known consecutive entries.
35 *
36 * This is only for internal list manipulation where we know
37 * the prev/next entries already!
38 */
39static inline void __list_add(struct list_head *new,
40 struct list_head *prev,
41 struct list_head *next)
42{
43 next->prev = new;
44 new->next = next;
45 new->prev = prev;
46 prev->next = new;
47}
48
49/**
50 * list_add - add a new entry
51 * @new: new entry to be added
52 * @head: list head to add it after
53 *
54 * Insert a new entry after the specified head.
55 * This is good for implementing stacks.
56 */
57static inline void list_add(struct list_head *new, struct list_head *head)
58{
59 __list_add(new, head, head->next);
60}
61
62/*
63 * Delete a list entry by making the prev/next entries
64 * point to each other.
65 *
66 * This is only for internal list manipulation where we know
67 * the prev/next entries already!
68 */
69static inline void __list_del(struct list_head * prev, struct list_head * next)
70{
71 next->prev = prev;
72 prev->next = next;
73}
74
75#define POISON_POINTER_DELTA 0
76#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
77#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)
78
79/**
80 * list_del - deletes entry from list.
81 * @entry: the element to delete from the list.
82 * Note: list_empty() on entry does not return true after this, the entry is
83 * in an undefined state.
84 */
85static inline void __list_del_entry(struct list_head *entry)
86{
87 __list_del(entry->prev, entry->next);
88}
89
90static inline void list_del(struct list_head *entry)
91{
92 __list_del(entry->prev, entry->next);
93 entry->next = LIST_POISON1;
94 entry->prev = LIST_POISON2;
95}
96
97/**
98 * list_entry - get the struct for this entry
99 * @ptr: the &struct list_head pointer.
100 * @type: the type of the struct this is embedded in.
101 * @member: the name of the list_struct within the struct.
102 */
103#define list_entry(ptr, type, member) \
104 container_of(ptr, type, member)
105/**
106 * list_for_each - iterate over a list
107 * @pos: the &struct list_head to use as a loop cursor.
108 * @head: the head for your list.
109 */
110#define list_for_each(pos, head) \
111 for (pos = (head)->next; pos != (head); pos = pos->next)
112
113/**
114 * list_for_each_safe - iterate over a list safe against removal of list entry
115 * @pos: the &struct list_head to use as a loop cursor.
116 * @n: another &struct list_head to use as temporary storage
117 * @head: the head for your list.
118 */
119#define list_for_each_safe(pos, n, head) \
120 for (pos = (head)->next, n = pos->next; pos != (head); \
121 pos = n, n = pos->next)
122
123#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
124
125/**
126 * container_of - cast a member of a structure out to the containing structure
127 * @ptr: the pointer to the member.
128 * @type: the type of the container struct this is embedded in.
129 * @member: the name of the member within the struct.
130 *
131 */
132#define container_of(ptr, type, member) ({ \
133 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
134 (type *)( (char *)__mptr - offsetof(type,member) );})
135
136#endif
diff --git a/tools/usb/usbip/libsrc/names.c b/tools/usb/usbip/libsrc/names.c
new file mode 100644
index 000000000000..81ff8522405c
--- /dev/null
+++ b/tools/usb/usbip/libsrc/names.c
@@ -0,0 +1,504 @@
1/*
2 * names.c -- USB name database manipulation routines
3 *
4 * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 *
21 *
22 *
23 *
24 * Copyright (C) 2005 Takahiro Hirofuchi
25 * - names_deinit() is added.
26 *
27 */
28
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <dirent.h>
33#include <string.h>
34#include <errno.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <stdio.h>
38#include <ctype.h>
39
40#include "names.h"
41#include "usbip_common.h"
42
43struct vendor {
44 struct vendor *next;
45 u_int16_t vendorid;
46 char name[1];
47};
48
49struct product {
50 struct product *next;
51 u_int16_t vendorid, productid;
52 char name[1];
53};
54
55struct class {
56 struct class *next;
57 u_int8_t classid;
58 char name[1];
59};
60
61struct subclass {
62 struct subclass *next;
63 u_int8_t classid, subclassid;
64 char name[1];
65};
66
67struct protocol {
68 struct protocol *next;
69 u_int8_t classid, subclassid, protocolid;
70 char name[1];
71};
72
73struct genericstrtable {
74 struct genericstrtable *next;
75 unsigned int num;
76 char name[1];
77};
78
79
80#define HASH1 0x10
81#define HASH2 0x02
82#define HASHSZ 16
83
84static unsigned int hashnum(unsigned int num)
85{
86 unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
87
88 for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
89 if (num & mask1)
90 num ^= mask2;
91 return num & (HASHSZ-1);
92}
93
94
95static struct vendor *vendors[HASHSZ] = { NULL, };
96static struct product *products[HASHSZ] = { NULL, };
97static struct class *classes[HASHSZ] = { NULL, };
98static struct subclass *subclasses[HASHSZ] = { NULL, };
99static struct protocol *protocols[HASHSZ] = { NULL, };
100
101const char *names_vendor(u_int16_t vendorid)
102{
103 struct vendor *v;
104
105 v = vendors[hashnum(vendorid)];
106 for (; v; v = v->next)
107 if (v->vendorid == vendorid)
108 return v->name;
109 return NULL;
110}
111
112const char *names_product(u_int16_t vendorid, u_int16_t productid)
113{
114 struct product *p;
115
116 p = products[hashnum((vendorid << 16) | productid)];
117 for (; p; p = p->next)
118 if (p->vendorid == vendorid && p->productid == productid)
119 return p->name;
120 return NULL;
121}
122
123const char *names_class(u_int8_t classid)
124{
125 struct class *c;
126
127 c = classes[hashnum(classid)];
128 for (; c; c = c->next)
129 if (c->classid == classid)
130 return c->name;
131 return NULL;
132}
133
134const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
135{
136 struct subclass *s;
137
138 s = subclasses[hashnum((classid << 8) | subclassid)];
139 for (; s; s = s->next)
140 if (s->classid == classid && s->subclassid == subclassid)
141 return s->name;
142 return NULL;
143}
144
145const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
146 u_int8_t protocolid)
147{
148 struct protocol *p;
149
150 p = protocols[hashnum((classid << 16) | (subclassid << 8)
151 | protocolid)];
152 for (; p; p = p->next)
153 if (p->classid == classid && p->subclassid == subclassid &&
154 p->protocolid == protocolid)
155 return p->name;
156 return NULL;
157}
158
159/* add a cleanup function by takahiro */
160struct pool {
161 struct pool *next;
162 void *mem;
163};
164
165static struct pool *pool_head;
166
167static void *my_malloc(size_t size)
168{
169 struct pool *p;
170
171 p = calloc(1, sizeof(struct pool));
172 if (!p)
173 return NULL;
174
175 p->mem = calloc(1, size);
176 if (!p->mem) {
177 free(p);
178 return NULL;
179 }
180
181 p->next = pool_head;
182 pool_head = p;
183
184 return p->mem;
185}
186
187void names_free(void)
188{
189 struct pool *pool;
190
191 if (!pool_head)
192 return;
193
194 for (pool = pool_head; pool != NULL; ) {
195 struct pool *tmp;
196
197 if (pool->mem)
198 free(pool->mem);
199
200 tmp = pool;
201 pool = pool->next;
202 free(tmp);
203 }
204}
205
206static int new_vendor(const char *name, u_int16_t vendorid)
207{
208 struct vendor *v;
209 unsigned int h = hashnum(vendorid);
210
211 v = vendors[h];
212 for (; v; v = v->next)
213 if (v->vendorid == vendorid)
214 return -1;
215 v = my_malloc(sizeof(struct vendor) + strlen(name));
216 if (!v)
217 return -1;
218 strcpy(v->name, name);
219 v->vendorid = vendorid;
220 v->next = vendors[h];
221 vendors[h] = v;
222 return 0;
223}
224
225static int new_product(const char *name, u_int16_t vendorid,
226 u_int16_t productid)
227{
228 struct product *p;
229 unsigned int h = hashnum((vendorid << 16) | productid);
230
231 p = products[h];
232 for (; p; p = p->next)
233 if (p->vendorid == vendorid && p->productid == productid)
234 return -1;
235 p = my_malloc(sizeof(struct product) + strlen(name));
236 if (!p)
237 return -1;
238 strcpy(p->name, name);
239 p->vendorid = vendorid;
240 p->productid = productid;
241 p->next = products[h];
242 products[h] = p;
243 return 0;
244}
245
246static int new_class(const char *name, u_int8_t classid)
247{
248 struct class *c;
249 unsigned int h = hashnum(classid);
250
251 c = classes[h];
252 for (; c; c = c->next)
253 if (c->classid == classid)
254 return -1;
255 c = my_malloc(sizeof(struct class) + strlen(name));
256 if (!c)
257 return -1;
258 strcpy(c->name, name);
259 c->classid = classid;
260 c->next = classes[h];
261 classes[h] = c;
262 return 0;
263}
264
265static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
266{
267 struct subclass *s;
268 unsigned int h = hashnum((classid << 8) | subclassid);
269
270 s = subclasses[h];
271 for (; s; s = s->next)
272 if (s->classid == classid && s->subclassid == subclassid)
273 return -1;
274 s = my_malloc(sizeof(struct subclass) + strlen(name));
275 if (!s)
276 return -1;
277 strcpy(s->name, name);
278 s->classid = classid;
279 s->subclassid = subclassid;
280 s->next = subclasses[h];
281 subclasses[h] = s;
282 return 0;
283}
284
285static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
286 u_int8_t protocolid)
287{
288 struct protocol *p;
289 unsigned int h = hashnum((classid << 16) | (subclassid << 8)
290 | protocolid);
291
292 p = protocols[h];
293 for (; p; p = p->next)
294 if (p->classid == classid && p->subclassid == subclassid
295 && p->protocolid == protocolid)
296 return -1;
297 p = my_malloc(sizeof(struct protocol) + strlen(name));
298 if (!p)
299 return -1;
300 strcpy(p->name, name);
301 p->classid = classid;
302 p->subclassid = subclassid;
303 p->protocolid = protocolid;
304 p->next = protocols[h];
305 protocols[h] = p;
306 return 0;
307}
308
309static void parse(FILE *f)
310{
311 char buf[512], *cp;
312 unsigned int linectr = 0;
313 int lastvendor = -1;
314 int lastclass = -1;
315 int lastsubclass = -1;
316 int lasthut = -1;
317 int lastlang = -1;
318 unsigned int u;
319
320 while (fgets(buf, sizeof(buf), f)) {
321 linectr++;
322 /* remove line ends */
323 cp = strchr(buf, '\r');
324 if (cp)
325 *cp = 0;
326 cp = strchr(buf, '\n');
327 if (cp)
328 *cp = 0;
329 if (buf[0] == '#' || !buf[0])
330 continue;
331 cp = buf;
332 if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
333 buf[3] == 'S' && buf[4] == 'D' &&
334 buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
335 buf[7] == ' ') {
336 continue;
337 }
338 if (buf[0] == 'P' && buf[1] == 'H' &&
339 buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
340 continue;
341 }
342 if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
343 buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
344 continue;
345 }
346 if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
347 lasthut = lastclass = lastvendor = lastsubclass = -1;
348 /*
349 * set 1 as pseudo-id to indicate that the parser is
350 * in a `L' section.
351 */
352 lastlang = 1;
353 continue;
354 }
355 if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
356 /* class spec */
357 cp = buf+2;
358 while (isspace(*cp))
359 cp++;
360 if (!isxdigit(*cp)) {
361 err("Invalid class spec at line %u", linectr);
362 continue;
363 }
364 u = strtoul(cp, &cp, 16);
365 while (isspace(*cp))
366 cp++;
367 if (!*cp) {
368 err("Invalid class spec at line %u", linectr);
369 continue;
370 }
371 if (new_class(cp, u))
372 err("Duplicate class spec at line %u class %04x %s",
373 linectr, u, cp);
374 dbg("line %5u class %02x %s", linectr, u, cp);
375 lasthut = lastlang = lastvendor = lastsubclass = -1;
376 lastclass = u;
377 continue;
378 }
379 if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
380 /* audio terminal type spec */
381 continue;
382 }
383 if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
384 && isspace(buf[3])) {
385 /* HID Descriptor bCountryCode */
386 continue;
387 }
388 if (isxdigit(*cp)) {
389 /* vendor */
390 u = strtoul(cp, &cp, 16);
391 while (isspace(*cp))
392 cp++;
393 if (!*cp) {
394 err("Invalid vendor spec at line %u", linectr);
395 continue;
396 }
397 if (new_vendor(cp, u))
398 err("Duplicate vendor spec at line %u vendor %04x %s",
399 linectr, u, cp);
400 dbg("line %5u vendor %04x %s", linectr, u, cp);
401 lastvendor = u;
402 lasthut = lastlang = lastclass = lastsubclass = -1;
403 continue;
404 }
405 if (buf[0] == '\t' && isxdigit(buf[1])) {
406 /* product or subclass spec */
407 u = strtoul(buf+1, &cp, 16);
408 while (isspace(*cp))
409 cp++;
410 if (!*cp) {
411 err("Invalid product/subclass spec at line %u",
412 linectr);
413 continue;
414 }
415 if (lastvendor != -1) {
416 if (new_product(cp, lastvendor, u))
417 err("Duplicate product spec at line %u product %04x:%04x %s",
418 linectr, lastvendor, u, cp);
419 dbg("line %5u product %04x:%04x %s", linectr,
420 lastvendor, u, cp);
421 continue;
422 }
423 if (lastclass != -1) {
424 if (new_subclass(cp, lastclass, u))
425 err("Duplicate subclass spec at line %u class %02x:%02x %s",
426 linectr, lastclass, u, cp);
427 dbg("line %5u subclass %02x:%02x %s", linectr,
428 lastclass, u, cp);
429 lastsubclass = u;
430 continue;
431 }
432 if (lasthut != -1) {
433 /* do not store hut */
434 continue;
435 }
436 if (lastlang != -1) {
437 /* do not store langid */
438 continue;
439 }
440 err("Product/Subclass spec without prior Vendor/Class spec at line %u",
441 linectr);
442 continue;
443 }
444 if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
445 /* protocol spec */
446 u = strtoul(buf+2, &cp, 16);
447 while (isspace(*cp))
448 cp++;
449 if (!*cp) {
450 err("Invalid protocol spec at line %u",
451 linectr);
452 continue;
453 }
454 if (lastclass != -1 && lastsubclass != -1) {
455 if (new_protocol(cp, lastclass, lastsubclass,
456 u))
457 err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
458 linectr, lastclass, lastsubclass,
459 u, cp);
460 dbg("line %5u protocol %02x:%02x:%02x %s",
461 linectr, lastclass, lastsubclass, u, cp);
462 continue;
463 }
464 err("Protocol spec without prior Class and Subclass spec at line %u",
465 linectr);
466 continue;
467 }
468 if (buf[0] == 'H' && buf[1] == 'I' &&
469 buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
470 continue;
471 }
472 if (buf[0] == 'H' && buf[1] == 'U' &&
473 buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
474 lastlang = lastclass = lastvendor = lastsubclass = -1;
475 /*
476 * set 1 as pseudo-id to indicate that the parser is
477 * in a `HUT' section.
478 */
479 lasthut = 1;
480 continue;
481 }
482 if (buf[0] == 'R' && buf[1] == ' ')
483 continue;
484
485 if (buf[0] == 'V' && buf[1] == 'T')
486 continue;
487
488 err("Unknown line at line %u", linectr);
489 }
490}
491
492
493int names_init(char *n)
494{
495 FILE *f;
496
497 f = fopen(n, "r");
498 if (!f)
499 return errno;
500
501 parse(f);
502 fclose(f);
503 return 0;
504}
diff --git a/tools/usb/usbip/libsrc/names.h b/tools/usb/usbip/libsrc/names.h
new file mode 100644
index 000000000000..680926512de2
--- /dev/null
+++ b/tools/usb/usbip/libsrc/names.h
@@ -0,0 +1,41 @@
1/*
2 * names.h -- USB name database manipulation routines
3 *
4 * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 *
21 *
22 * Copyright (C) 2005 Takahiro Hirofuchi
23 * - names_free() is added.
24 */
25
26#ifndef _NAMES_H
27#define _NAMES_H
28
29#include <sys/types.h>
30
31/* used by usbip_common.c */
32extern const char *names_vendor(u_int16_t vendorid);
33extern const char *names_product(u_int16_t vendorid, u_int16_t productid);
34extern const char *names_class(u_int8_t classid);
35extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid);
36extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
37 u_int8_t protocolid);
38extern int names_init(char *n);
39extern void names_free(void);
40
41#endif /* _NAMES_H */
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.c b/tools/usb/usbip/libsrc/sysfs_utils.c
new file mode 100644
index 000000000000..36ac88ece0b8
--- /dev/null
+++ b/tools/usb/usbip/libsrc/sysfs_utils.c
@@ -0,0 +1,31 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <fcntl.h>
4#include <errno.h>
5
6#include "sysfs_utils.h"
7#include "usbip_common.h"
8
9int write_sysfs_attribute(const char *attr_path, const char *new_value,
10 size_t len)
11{
12 int fd;
13 int length;
14
15 fd = open(attr_path, O_WRONLY);
16 if (fd < 0) {
17 dbg("error opening attribute %s", attr_path);
18 return -1;
19 }
20
21 length = write(fd, new_value, len);
22 if (length < 0) {
23 dbg("error writing to attribute %s", attr_path);
24 close(fd);
25 return -1;
26 }
27
28 close(fd);
29
30 return 0;
31}
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.h b/tools/usb/usbip/libsrc/sysfs_utils.h
new file mode 100644
index 000000000000..32ac1d105d18
--- /dev/null
+++ b/tools/usb/usbip/libsrc/sysfs_utils.h
@@ -0,0 +1,8 @@
1
2#ifndef __SYSFS_UTILS_H
3#define __SYSFS_UTILS_H
4
5int write_sysfs_attribute(const char *attr_path, const char *new_value,
6 size_t len);
7
8#endif
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
new file mode 100644
index 000000000000..ac73710473de
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -0,0 +1,285 @@
1/*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
4
5#include <libudev.h>
6#include "usbip_common.h"
7#include "names.h"
8
9#undef PROGNAME
10#define PROGNAME "libusbip"
11
12int usbip_use_syslog;
13int usbip_use_stderr;
14int usbip_use_debug;
15
16extern struct udev *udev_context;
17
18struct speed_string {
19 int num;
20 char *speed;
21 char *desc;
22};
23
24static const struct speed_string speed_strings[] = {
25 { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"},
26 { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" },
27 { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" },
28 { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
29 { USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
30 { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
31 { 0, NULL, NULL }
32};
33
34struct portst_string {
35 int num;
36 char *desc;
37};
38
39static struct portst_string portst_strings[] = {
40 { SDEV_ST_AVAILABLE, "Device Available" },
41 { SDEV_ST_USED, "Device in Use" },
42 { SDEV_ST_ERROR, "Device Error"},
43 { VDEV_ST_NULL, "Port Available"},
44 { VDEV_ST_NOTASSIGNED, "Port Initializing"},
45 { VDEV_ST_USED, "Port in Use"},
46 { VDEV_ST_ERROR, "Port Error"},
47 { 0, NULL}
48};
49
50const char *usbip_status_string(int32_t status)
51{
52 for (int i = 0; portst_strings[i].desc != NULL; i++)
53 if (portst_strings[i].num == status)
54 return portst_strings[i].desc;
55
56 return "Unknown Status";
57}
58
59const char *usbip_speed_string(int num)
60{
61 for (int i = 0; speed_strings[i].speed != NULL; i++)
62 if (speed_strings[i].num == num)
63 return speed_strings[i].desc;
64
65 return "Unknown Speed";
66}
67
68
69#define DBG_UDEV_INTEGER(name)\
70 dbg("%-20s = %x", to_string(name), (int) udev->name)
71
72#define DBG_UINF_INTEGER(name)\
73 dbg("%-20s = %x", to_string(name), (int) uinf->name)
74
75void dump_usb_interface(struct usbip_usb_interface *uinf)
76{
77 char buff[100];
78
79 usbip_names_get_class(buff, sizeof(buff),
80 uinf->bInterfaceClass,
81 uinf->bInterfaceSubClass,
82 uinf->bInterfaceProtocol);
83 dbg("%-20s = %s", "Interface(C/SC/P)", buff);
84}
85
86void dump_usb_device(struct usbip_usb_device *udev)
87{
88 char buff[100];
89
90 dbg("%-20s = %s", "path", udev->path);
91 dbg("%-20s = %s", "busid", udev->busid);
92
93 usbip_names_get_class(buff, sizeof(buff),
94 udev->bDeviceClass,
95 udev->bDeviceSubClass,
96 udev->bDeviceProtocol);
97 dbg("%-20s = %s", "Device(C/SC/P)", buff);
98
99 DBG_UDEV_INTEGER(bcdDevice);
100
101 usbip_names_get_product(buff, sizeof(buff),
102 udev->idVendor,
103 udev->idProduct);
104 dbg("%-20s = %s", "Vendor/Product", buff);
105
106 DBG_UDEV_INTEGER(bNumConfigurations);
107 DBG_UDEV_INTEGER(bNumInterfaces);
108
109 dbg("%-20s = %s", "speed",
110 usbip_speed_string(udev->speed));
111
112 DBG_UDEV_INTEGER(busnum);
113 DBG_UDEV_INTEGER(devnum);
114}
115
116
117int read_attr_value(struct udev_device *dev, const char *name,
118 const char *format)
119{
120 const char *attr;
121 int num = 0;
122 int ret;
123
124 attr = udev_device_get_sysattr_value(dev, name);
125 if (!attr) {
126 err("udev_device_get_sysattr_value failed");
127 goto err;
128 }
129
130 /* The client chooses the device configuration
131 * when attaching it so right after being bound
132 * to usbip-host on the server the device will
133 * have no configuration.
134 * Therefore, attributes such as bConfigurationValue
135 * and bNumInterfaces will not exist and sscanf will
136 * fail. Check for these cases and don't treat them
137 * as errors.
138 */
139
140 ret = sscanf(attr, format, &num);
141 if (ret < 1) {
142 if (strcmp(name, "bConfigurationValue") &&
143 strcmp(name, "bNumInterfaces")) {
144 err("sscanf failed for attribute %s", name);
145 goto err;
146 }
147 }
148
149err:
150
151 return num;
152}
153
154
155int read_attr_speed(struct udev_device *dev)
156{
157 const char *speed;
158
159 speed = udev_device_get_sysattr_value(dev, "speed");
160 if (!speed) {
161 err("udev_device_get_sysattr_value failed");
162 goto err;
163 }
164
165 for (int i = 0; speed_strings[i].speed != NULL; i++) {
166 if (!strcmp(speed, speed_strings[i].speed))
167 return speed_strings[i].num;
168 }
169
170err:
171
172 return USB_SPEED_UNKNOWN;
173}
174
175#define READ_ATTR(object, type, dev, name, format) \
176 do { \
177 (object)->name = (type) read_attr_value(dev, to_string(name), \
178 format); \
179 } while (0)
180
181
182int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev)
183{
184 uint32_t busnum, devnum;
185 const char *path, *name;
186
187 READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n");
188 READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n");
189 READ_ATTR(udev, uint8_t, sdev, bDeviceProtocol, "%02x\n");
190
191 READ_ATTR(udev, uint16_t, sdev, idVendor, "%04x\n");
192 READ_ATTR(udev, uint16_t, sdev, idProduct, "%04x\n");
193 READ_ATTR(udev, uint16_t, sdev, bcdDevice, "%04x\n");
194
195 READ_ATTR(udev, uint8_t, sdev, bConfigurationValue, "%02x\n");
196 READ_ATTR(udev, uint8_t, sdev, bNumConfigurations, "%02x\n");
197 READ_ATTR(udev, uint8_t, sdev, bNumInterfaces, "%02x\n");
198
199 READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n");
200 udev->speed = read_attr_speed(sdev);
201
202 path = udev_device_get_syspath(sdev);
203 name = udev_device_get_sysname(sdev);
204
205 strncpy(udev->path, path, SYSFS_PATH_MAX);
206 strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);
207
208 sscanf(name, "%u-%u", &busnum, &devnum);
209 udev->busnum = busnum;
210
211 return 0;
212}
213
214int read_usb_interface(struct usbip_usb_device *udev, int i,
215 struct usbip_usb_interface *uinf)
216{
217 char busid[SYSFS_BUS_ID_SIZE];
218 struct udev_device *sif;
219
220 sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
221
222 sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
223 if (!sif) {
224 err("udev_device_new_from_subsystem_sysname %s failed", busid);
225 return -1;
226 }
227
228 READ_ATTR(uinf, uint8_t, sif, bInterfaceClass, "%02x\n");
229 READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n");
230 READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n");
231
232 return 0;
233}
234
235int usbip_names_init(char *f)
236{
237 return names_init(f);
238}
239
240void usbip_names_free(void)
241{
242 names_free();
243}
244
245void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
246 uint16_t product)
247{
248 const char *prod, *vend;
249
250 prod = names_product(vendor, product);
251 if (!prod)
252 prod = "unknown product";
253
254
255 vend = names_vendor(vendor);
256 if (!vend)
257 vend = "unknown vendor";
258
259 snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product);
260}
261
262void usbip_names_get_class(char *buff, size_t size, uint8_t class,
263 uint8_t subclass, uint8_t protocol)
264{
265 const char *c, *s, *p;
266
267 if (class == 0 && subclass == 0 && protocol == 0) {
268 snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol);
269 return;
270 }
271
272 p = names_protocol(class, subclass, protocol);
273 if (!p)
274 p = "unknown protocol";
275
276 s = names_subclass(class, subclass);
277 if (!s)
278 s = "unknown subclass";
279
280 c = names_class(class);
281 if (!c)
282 c = "unknown class";
283
284 snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol);
285}
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h
new file mode 100644
index 000000000000..15fe792e1e96
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_common.h
@@ -0,0 +1,137 @@
1/*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
4
5#ifndef __USBIP_COMMON_H
6#define __USBIP_COMMON_H
7
8#include <libudev.h>
9
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include <syslog.h>
16#include <unistd.h>
17#include <linux/usb/ch9.h>
18#include <linux/usbip.h>
19
20#ifndef USBIDS_FILE
21#define USBIDS_FILE "/usr/share/hwdata/usb.ids"
22#endif
23
24#ifndef VHCI_STATE_PATH
25#define VHCI_STATE_PATH "/var/run/vhci_hcd"
26#endif
27
28/* kernel module names */
29#define USBIP_CORE_MOD_NAME "usbip-core"
30#define USBIP_HOST_DRV_NAME "usbip-host"
31#define USBIP_VHCI_DRV_NAME "vhci_hcd"
32
33/* sysfs constants */
34#define SYSFS_MNT_PATH "/sys"
35#define SYSFS_BUS_NAME "bus"
36#define SYSFS_BUS_TYPE "usb"
37#define SYSFS_DRIVERS_NAME "drivers"
38
39#define SYSFS_PATH_MAX 256
40#define SYSFS_BUS_ID_SIZE 32
41
42extern int usbip_use_syslog;
43extern int usbip_use_stderr;
44extern int usbip_use_debug ;
45
46#define PROGNAME "usbip"
47
48#define pr_fmt(fmt) "%s: %s: " fmt "\n", PROGNAME
49#define dbg_fmt(fmt) pr_fmt("%s:%d:[%s] " fmt), "debug", \
50 __FILE__, __LINE__, __func__
51
52#define err(fmt, args...) \
53 do { \
54 if (usbip_use_syslog) { \
55 syslog(LOG_ERR, pr_fmt(fmt), "error", ##args); \
56 } \
57 if (usbip_use_stderr) { \
58 fprintf(stderr, pr_fmt(fmt), "error", ##args); \
59 } \
60 } while (0)
61
62#define info(fmt, args...) \
63 do { \
64 if (usbip_use_syslog) { \
65 syslog(LOG_INFO, pr_fmt(fmt), "info", ##args); \
66 } \
67 if (usbip_use_stderr) { \
68 fprintf(stderr, pr_fmt(fmt), "info", ##args); \
69 } \
70 } while (0)
71
72#define dbg(fmt, args...) \
73 do { \
74 if (usbip_use_debug) { \
75 if (usbip_use_syslog) { \
76 syslog(LOG_DEBUG, dbg_fmt(fmt), ##args); \
77 } \
78 if (usbip_use_stderr) { \
79 fprintf(stderr, dbg_fmt(fmt), ##args); \
80 } \
81 } \
82 } while (0)
83
84#define BUG() \
85 do { \
86 err("sorry, it's a bug!"); \
87 abort(); \
88 } while (0)
89
90struct usbip_usb_interface {
91 uint8_t bInterfaceClass;
92 uint8_t bInterfaceSubClass;
93 uint8_t bInterfaceProtocol;
94 uint8_t padding; /* alignment */
95} __attribute__((packed));
96
97struct usbip_usb_device {
98 char path[SYSFS_PATH_MAX];
99 char busid[SYSFS_BUS_ID_SIZE];
100
101 uint32_t busnum;
102 uint32_t devnum;
103 uint32_t speed;
104
105 uint16_t idVendor;
106 uint16_t idProduct;
107 uint16_t bcdDevice;
108
109 uint8_t bDeviceClass;
110 uint8_t bDeviceSubClass;
111 uint8_t bDeviceProtocol;
112 uint8_t bConfigurationValue;
113 uint8_t bNumConfigurations;
114 uint8_t bNumInterfaces;
115} __attribute__((packed));
116
117#define to_string(s) #s
118
119void dump_usb_interface(struct usbip_usb_interface *);
120void dump_usb_device(struct usbip_usb_device *);
121int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev);
122int read_attr_value(struct udev_device *dev, const char *name,
123 const char *format);
124int read_usb_interface(struct usbip_usb_device *udev, int i,
125 struct usbip_usb_interface *uinf);
126
127const char *usbip_speed_string(int num);
128const char *usbip_status_string(int32_t status);
129
130int usbip_names_init(char *);
131void usbip_names_free(void);
132void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
133 uint16_t product);
134void usbip_names_get_class(char *buff, size_t size, uint8_t class,
135 uint8_t subclass, uint8_t protocol);
136
137#endif /* __USBIP_COMMON_H */
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c
new file mode 100644
index 000000000000..bef08d5c44e8
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_host_driver.c
@@ -0,0 +1,280 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22
23#include <errno.h>
24#include <unistd.h>
25
26#include <libudev.h>
27
28#include "usbip_common.h"
29#include "usbip_host_driver.h"
30#include "list.h"
31#include "sysfs_utils.h"
32
33#undef PROGNAME
34#define PROGNAME "libusbip"
35
36struct usbip_host_driver *host_driver;
37struct udev *udev_context;
38
39static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
40{
41 char status_attr_path[SYSFS_PATH_MAX];
42 int fd;
43 int length;
44 char status;
45 int value = 0;
46
47 snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
48 udev->path);
49
50 fd = open(status_attr_path, O_RDONLY);
51 if (fd < 0) {
52 err("error opening attribute %s", status_attr_path);
53 return -1;
54 }
55
56 length = read(fd, &status, 1);
57 if (length < 0) {
58 err("error reading attribute %s", status_attr_path);
59 close(fd);
60 return -1;
61 }
62
63 value = atoi(&status);
64
65 return value;
66}
67
68static
69struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath)
70{
71 struct usbip_exported_device *edev = NULL;
72 struct usbip_exported_device *edev_old;
73 size_t size;
74 int i;
75
76 edev = calloc(1, sizeof(struct usbip_exported_device));
77
78 edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath);
79 if (!edev->sudev) {
80 err("udev_device_new_from_syspath: %s", sdevpath);
81 goto err;
82 }
83
84 read_usb_device(edev->sudev, &edev->udev);
85
86 edev->status = read_attr_usbip_status(&edev->udev);
87 if (edev->status < 0)
88 goto err;
89
90 /* reallocate buffer to include usb interface data */
91 size = sizeof(struct usbip_exported_device) +
92 edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface);
93
94 edev_old = edev;
95 edev = realloc(edev, size);
96 if (!edev) {
97 edev = edev_old;
98 dbg("realloc failed");
99 goto err;
100 }
101
102 for (i = 0; i < edev->udev.bNumInterfaces; i++)
103 read_usb_interface(&edev->udev, i, &edev->uinf[i]);
104
105 return edev;
106err:
107 if (edev->sudev)
108 udev_device_unref(edev->sudev);
109 if (edev)
110 free(edev);
111
112 return NULL;
113}
114
115static int refresh_exported_devices(void)
116{
117 struct usbip_exported_device *edev;
118 struct udev_enumerate *enumerate;
119 struct udev_list_entry *devices, *dev_list_entry;
120 struct udev_device *dev;
121 const char *path;
122 const char *driver;
123
124 enumerate = udev_enumerate_new(udev_context);
125 udev_enumerate_add_match_subsystem(enumerate, "usb");
126 udev_enumerate_scan_devices(enumerate);
127
128 devices = udev_enumerate_get_list_entry(enumerate);
129
130 udev_list_entry_foreach(dev_list_entry, devices) {
131 path = udev_list_entry_get_name(dev_list_entry);
132 dev = udev_device_new_from_syspath(udev_context, path);
133 if (dev == NULL)
134 continue;
135
136 /* Check whether device uses usbip-host driver. */
137 driver = udev_device_get_driver(dev);
138 if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) {
139 edev = usbip_exported_device_new(path);
140 if (!edev) {
141 dbg("usbip_exported_device_new failed");
142 continue;
143 }
144
145 list_add(&edev->node, &host_driver->edev_list);
146 host_driver->ndevs++;
147 }
148 }
149
150 return 0;
151}
152
153static void usbip_exported_device_destroy(void)
154{
155 struct list_head *i, *tmp;
156 struct usbip_exported_device *edev;
157
158 list_for_each_safe(i, tmp, &host_driver->edev_list) {
159 edev = list_entry(i, struct usbip_exported_device, node);
160 list_del(i);
161 free(edev);
162 }
163}
164
165int usbip_host_driver_open(void)
166{
167 int rc;
168
169 udev_context = udev_new();
170 if (!udev_context) {
171 err("udev_new failed");
172 return -1;
173 }
174
175 host_driver = calloc(1, sizeof(*host_driver));
176
177 host_driver->ndevs = 0;
178 INIT_LIST_HEAD(&host_driver->edev_list);
179
180 rc = refresh_exported_devices();
181 if (rc < 0)
182 goto err_free_host_driver;
183
184 return 0;
185
186err_free_host_driver:
187 free(host_driver);
188 host_driver = NULL;
189
190 udev_unref(udev_context);
191
192 return -1;
193}
194
195void usbip_host_driver_close(void)
196{
197 if (!host_driver)
198 return;
199
200 usbip_exported_device_destroy();
201
202 free(host_driver);
203 host_driver = NULL;
204
205 udev_unref(udev_context);
206}
207
208int usbip_host_refresh_device_list(void)
209{
210 int rc;
211
212 usbip_exported_device_destroy();
213
214 host_driver->ndevs = 0;
215 INIT_LIST_HEAD(&host_driver->edev_list);
216
217 rc = refresh_exported_devices();
218 if (rc < 0)
219 return -1;
220
221 return 0;
222}
223
224int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
225{
226 char attr_name[] = "usbip_sockfd";
227 char sockfd_attr_path[SYSFS_PATH_MAX];
228 char sockfd_buff[30];
229 int ret;
230
231 if (edev->status != SDEV_ST_AVAILABLE) {
232 dbg("device not available: %s", edev->udev.busid);
233 switch (edev->status) {
234 case SDEV_ST_ERROR:
235 dbg("status SDEV_ST_ERROR");
236 break;
237 case SDEV_ST_USED:
238 dbg("status SDEV_ST_USED");
239 break;
240 default:
241 dbg("status unknown: 0x%x", edev->status);
242 }
243 return -1;
244 }
245
246 /* only the first interface is true */
247 snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
248 edev->udev.path, attr_name);
249
250 snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
251
252 ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
253 strlen(sockfd_buff));
254 if (ret < 0) {
255 err("write_sysfs_attribute failed: sockfd %s to %s",
256 sockfd_buff, sockfd_attr_path);
257 return ret;
258 }
259
260 info("connect: %s", edev->udev.busid);
261
262 return ret;
263}
264
265struct usbip_exported_device *usbip_host_get_device(int num)
266{
267 struct list_head *i;
268 struct usbip_exported_device *edev;
269 int cnt = 0;
270
271 list_for_each(i, &host_driver->edev_list) {
272 edev = list_entry(i, struct usbip_exported_device, node);
273 if (num == cnt)
274 return edev;
275 else
276 cnt++;
277 }
278
279 return NULL;
280}
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.h b/tools/usb/usbip/libsrc/usbip_host_driver.h
new file mode 100644
index 000000000000..2a31f855c616
--- /dev/null
+++ b/tools/usb/usbip/libsrc/usbip_host_driver.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __USBIP_HOST_DRIVER_H
20#define __USBIP_HOST_DRIVER_H
21
22#include <stdint.h>
23#include "usbip_common.h"
24#include "list.h"
25
26struct usbip_host_driver {
27 int ndevs;
28 /* list of exported device */
29 struct list_head edev_list;
30};
31
32struct usbip_exported_device {
33 struct udev_device *sudev;
34 int32_t status;
35 struct usbip_usb_device udev;
36 struct list_head node;
37 struct usbip_usb_interface uinf[];
38};
39
40extern struct usbip_host_driver *host_driver;
41
42int usbip_host_driver_open(void);
43void usbip_host_driver_close(void);
44
45int usbip_host_refresh_device_list(void);
46int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd);
47struct usbip_exported_device *usbip_host_get_device(int num);
48
49#endif /* __USBIP_HOST_DRIVER_H */
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
new file mode 100644
index 000000000000..ad9204773533
--- /dev/null
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -0,0 +1,411 @@
1/*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
4
5#include "usbip_common.h"
6#include "vhci_driver.h"
7#include <limits.h>
8#include <netdb.h>
9#include <libudev.h>
10#include "sysfs_utils.h"
11
12#undef PROGNAME
13#define PROGNAME "libusbip"
14
15struct usbip_vhci_driver *vhci_driver;
16struct udev *udev_context;
17
18static struct usbip_imported_device *
19imported_device_init(struct usbip_imported_device *idev, char *busid)
20{
21 struct udev_device *sudev;
22
23 sudev = udev_device_new_from_subsystem_sysname(udev_context,
24 "usb", busid);
25 if (!sudev) {
26 dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
27 goto err;
28 }
29 read_usb_device(sudev, &idev->udev);
30 udev_device_unref(sudev);
31
32 return idev;
33
34err:
35 return NULL;
36}
37
38
39
40static int parse_status(const char *value)
41{
42 int ret = 0;
43 char *c;
44
45
46 for (int i = 0; i < vhci_driver->nports; i++)
47 memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
48
49
50 /* skip a header line */
51 c = strchr(value, '\n');
52 if (!c)
53 return -1;
54 c++;
55
56 while (*c != '\0') {
57 int port, status, speed, devid;
58 unsigned long socket;
59 char lbusid[SYSFS_BUS_ID_SIZE];
60
61 ret = sscanf(c, "%d %d %d %x %lx %31s\n",
62 &port, &status, &speed,
63 &devid, &socket, lbusid);
64
65 if (ret < 5) {
66 dbg("sscanf failed: %d", ret);
67 BUG();
68 }
69
70 dbg("port %d status %d speed %d devid %x",
71 port, status, speed, devid);
72 dbg("socket %lx lbusid %s", socket, lbusid);
73
74
75 /* if a device is connected, look at it */
76 {
77 struct usbip_imported_device *idev = &vhci_driver->idev[port];
78
79 idev->port = port;
80 idev->status = status;
81
82 idev->devid = devid;
83
84 idev->busnum = (devid >> 16);
85 idev->devnum = (devid & 0x0000ffff);
86
87 if (idev->status != VDEV_ST_NULL
88 && idev->status != VDEV_ST_NOTASSIGNED) {
89 idev = imported_device_init(idev, lbusid);
90 if (!idev) {
91 dbg("imported_device_init failed");
92 return -1;
93 }
94 }
95 }
96
97
98 /* go to the next line */
99 c = strchr(c, '\n');
100 if (!c)
101 break;
102 c++;
103 }
104
105 dbg("exit");
106
107 return 0;
108}
109
110static int refresh_imported_device_list(void)
111{
112 const char *attr_status;
113
114 attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
115 "status");
116 if (!attr_status) {
117 err("udev_device_get_sysattr_value failed");
118 return -1;
119 }
120
121 return parse_status(attr_status);
122}
123
124static int get_nports(void)
125{
126 char *c;
127 int nports = 0;
128 const char *attr_status;
129
130 attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
131 "status");
132 if (!attr_status) {
133 err("udev_device_get_sysattr_value failed");
134 return -1;
135 }
136
137 /* skip a header line */
138 c = strchr(attr_status, '\n');
139 if (!c)
140 return 0;
141 c++;
142
143 while (*c != '\0') {
144 /* go to the next line */
145 c = strchr(c, '\n');
146 if (!c)
147 return nports;
148 c++;
149 nports += 1;
150 }
151
152 return nports;
153}
154
155/*
156 * Read the given port's record.
157 *
158 * To avoid buffer overflow we will read the entire line and
159 * validate each part's size. The initial buffer is padded by 4 to
160 * accommodate the 2 spaces, 1 newline and an additional character
161 * which is needed to properly validate the 3rd part without it being
162 * truncated to an acceptable length.
163 */
164static int read_record(int rhport, char *host, unsigned long host_len,
165 char *port, unsigned long port_len, char *busid)
166{
167 int part;
168 FILE *file;
169 char path[PATH_MAX+1];
170 char *buffer, *start, *end;
171 char delim[] = {' ', ' ', '\n'};
172 int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
173 size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
174
175 buffer = malloc(buffer_len);
176 if (!buffer)
177 return -1;
178
179 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
180
181 file = fopen(path, "r");
182 if (!file) {
183 err("fopen");
184 free(buffer);
185 return -1;
186 }
187
188 if (fgets(buffer, buffer_len, file) == NULL) {
189 err("fgets");
190 free(buffer);
191 fclose(file);
192 return -1;
193 }
194 fclose(file);
195
196 /* validate the length of each of the 3 parts */
197 start = buffer;
198 for (part = 0; part < 3; part++) {
199 end = strchr(start, delim[part]);
200 if (end == NULL || (end - start) > max_len[part]) {
201 free(buffer);
202 return -1;
203 }
204 start = end + 1;
205 }
206
207 if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
208 err("sscanf");
209 free(buffer);
210 return -1;
211 }
212
213 free(buffer);
214
215 return 0;
216}
217
218/* ---------------------------------------------------------------------- */
219
220int usbip_vhci_driver_open(void)
221{
222 udev_context = udev_new();
223 if (!udev_context) {
224 err("udev_new failed");
225 return -1;
226 }
227
228 vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver));
229
230 /* will be freed in usbip_driver_close() */
231 vhci_driver->hc_device =
232 udev_device_new_from_subsystem_sysname(udev_context,
233 USBIP_VHCI_BUS_TYPE,
234 USBIP_VHCI_DRV_NAME);
235 if (!vhci_driver->hc_device) {
236 err("udev_device_new_from_subsystem_sysname failed");
237 goto err;
238 }
239
240 vhci_driver->nports = get_nports();
241
242 dbg("available ports: %d", vhci_driver->nports);
243
244 if (refresh_imported_device_list())
245 goto err;
246
247 return 0;
248
249err:
250 udev_device_unref(vhci_driver->hc_device);
251
252 if (vhci_driver)
253 free(vhci_driver);
254
255 vhci_driver = NULL;
256
257 udev_unref(udev_context);
258
259 return -1;
260}
261
262
263void usbip_vhci_driver_close(void)
264{
265 if (!vhci_driver)
266 return;
267
268 udev_device_unref(vhci_driver->hc_device);
269
270 free(vhci_driver);
271
272 vhci_driver = NULL;
273
274 udev_unref(udev_context);
275}
276
277
278int usbip_vhci_refresh_device_list(void)
279{
280
281 if (refresh_imported_device_list())
282 goto err;
283
284 return 0;
285err:
286 dbg("failed to refresh device list");
287 return -1;
288}
289
290
291int usbip_vhci_get_free_port(void)
292{
293 for (int i = 0; i < vhci_driver->nports; i++) {
294 if (vhci_driver->idev[i].status == VDEV_ST_NULL)
295 return i;
296 }
297
298 return -1;
299}
300
301int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
302 uint32_t speed) {
303 char buff[200]; /* what size should be ? */
304 char attach_attr_path[SYSFS_PATH_MAX];
305 char attr_attach[] = "attach";
306 const char *path;
307 int ret;
308
309 snprintf(buff, sizeof(buff), "%u %d %u %u",
310 port, sockfd, devid, speed);
311 dbg("writing: %s", buff);
312
313 path = udev_device_get_syspath(vhci_driver->hc_device);
314 snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
315 path, attr_attach);
316 dbg("attach attribute path: %s", attach_attr_path);
317
318 ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
319 if (ret < 0) {
320 dbg("write_sysfs_attribute failed");
321 return -1;
322 }
323
324 dbg("attached port: %d", port);
325
326 return 0;
327}
328
329static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
330{
331 return (busnum << 16) | devnum;
332}
333
334/* will be removed */
335int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
336 uint8_t devnum, uint32_t speed)
337{
338 int devid = get_devid(busnum, devnum);
339
340 return usbip_vhci_attach_device2(port, sockfd, devid, speed);
341}
342
343int usbip_vhci_detach_device(uint8_t port)
344{
345 char detach_attr_path[SYSFS_PATH_MAX];
346 char attr_detach[] = "detach";
347 char buff[200]; /* what size should be ? */
348 const char *path;
349 int ret;
350
351 snprintf(buff, sizeof(buff), "%u", port);
352 dbg("writing: %s", buff);
353
354 path = udev_device_get_syspath(vhci_driver->hc_device);
355 snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
356 path, attr_detach);
357 dbg("detach attribute path: %s", detach_attr_path);
358
359 ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
360 if (ret < 0) {
361 dbg("write_sysfs_attribute failed");
362 return -1;
363 }
364
365 dbg("detached port: %d", port);
366
367 return 0;
368}
369
370int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
371{
372 char product_name[100];
373 char host[NI_MAXHOST] = "unknown host";
374 char serv[NI_MAXSERV] = "unknown port";
375 char remote_busid[SYSFS_BUS_ID_SIZE];
376 int ret;
377 int read_record_error = 0;
378
379 if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
380 return 0;
381
382 ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
383 remote_busid);
384 if (ret) {
385 err("read_record");
386 read_record_error = 1;
387 }
388
389 printf("Port %02d: <%s> at %s\n", idev->port,
390 usbip_status_string(idev->status),
391 usbip_speed_string(idev->udev.speed));
392
393 usbip_names_get_product(product_name, sizeof(product_name),
394 idev->udev.idVendor, idev->udev.idProduct);
395
396 printf(" %s\n", product_name);
397
398 if (!read_record_error) {
399 printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
400 host, serv, remote_busid);
401 printf("%10s -> remote bus/dev %03d/%03d\n", " ",
402 idev->busnum, idev->devnum);
403 } else {
404 printf("%10s -> unknown host, remote port and remote busid\n",
405 idev->udev.busid);
406 printf("%10s -> remote bus/dev %03d/%03d\n", " ",
407 idev->busnum, idev->devnum);
408 }
409
410 return 0;
411}
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h
new file mode 100644
index 000000000000..fa2316cf2cac
--- /dev/null
+++ b/tools/usb/usbip/libsrc/vhci_driver.h
@@ -0,0 +1,59 @@
1/*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
4
5#ifndef __VHCI_DRIVER_H
6#define __VHCI_DRIVER_H
7
8#include <libudev.h>
9#include <stdint.h>
10
11#include "usbip_common.h"
12
13#define USBIP_VHCI_BUS_TYPE "platform"
14#define MAXNPORT 128
15
16struct usbip_imported_device {
17 uint8_t port;
18 uint32_t status;
19
20 uint32_t devid;
21
22 uint8_t busnum;
23 uint8_t devnum;
24
25 /* usbip_class_device list */
26 struct usbip_usb_device udev;
27};
28
29struct usbip_vhci_driver {
30
31 /* /sys/devices/platform/vhci_hcd */
32 struct udev_device *hc_device;
33
34 int nports;
35 struct usbip_imported_device idev[MAXNPORT];
36};
37
38
39extern struct usbip_vhci_driver *vhci_driver;
40
41int usbip_vhci_driver_open(void);
42void usbip_vhci_driver_close(void);
43
44int usbip_vhci_refresh_device_list(void);
45
46
47int usbip_vhci_get_free_port(void);
48int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
49 uint32_t speed);
50
51/* will be removed */
52int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
53 uint8_t devnum, uint32_t speed);
54
55int usbip_vhci_detach_device(uint8_t port);
56
57int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev);
58
59#endif /* __VHCI_DRIVER_H */
diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
new file mode 100644
index 000000000000..e81a4ebadeff
--- /dev/null
+++ b/tools/usb/usbip/src/Makefile.am
@@ -0,0 +1,11 @@
1AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
2AM_CFLAGS = @EXTRA_CFLAGS@
3LDADD = $(top_builddir)/libsrc/libusbip.la
4
5sbin_PROGRAMS := usbip usbipd
6
7usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
8 usbip_attach.c usbip_detach.c usbip_list.c \
9 usbip_bind.c usbip_unbind.c usbip_port.c
10
11usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
new file mode 100644
index 000000000000..d7599d943529
--- /dev/null
+++ b/tools/usb/usbip/src/usbip.c
@@ -0,0 +1,201 @@
1/*
2 * command structure borrowed from udev
3 * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
4 *
5 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
6 * 2005-2007 Takahiro Hirofuchi
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24
25#include <getopt.h>
26#include <syslog.h>
27
28#include "usbip_common.h"
29#include "usbip_network.h"
30#include "usbip.h"
31
32static int usbip_help(int argc, char *argv[]);
33static int usbip_version(int argc, char *argv[]);
34
35static const char usbip_version_string[] = PACKAGE_STRING;
36
37static const char usbip_usage_string[] =
38 "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
39 " [help] <command> <args>\n";
40
41static void usbip_usage(void)
42{
43 printf("usage: %s", usbip_usage_string);
44}
45
46struct command {
47 const char *name;
48 int (*fn)(int argc, char *argv[]);
49 const char *help;
50 void (*usage)(void);
51};
52
53static const struct command cmds[] = {
54 {
55 .name = "help",
56 .fn = usbip_help,
57 .help = NULL,
58 .usage = NULL
59 },
60 {
61 .name = "version",
62 .fn = usbip_version,
63 .help = NULL,
64 .usage = NULL
65 },
66 {
67 .name = "attach",
68 .fn = usbip_attach,
69 .help = "Attach a remote USB device",
70 .usage = usbip_attach_usage
71 },
72 {
73 .name = "detach",
74 .fn = usbip_detach,
75 .help = "Detach a remote USB device",
76 .usage = usbip_detach_usage
77 },
78 {
79 .name = "list",
80 .fn = usbip_list,
81 .help = "List exportable or local USB devices",
82 .usage = usbip_list_usage
83 },
84 {
85 .name = "bind",
86 .fn = usbip_bind,
87 .help = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
88 .usage = usbip_bind_usage
89 },
90 {
91 .name = "unbind",
92 .fn = usbip_unbind,
93 .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
94 .usage = usbip_unbind_usage
95 },
96 {
97 .name = "port",
98 .fn = usbip_port_show,
99 .help = "Show imported USB devices",
100 .usage = NULL
101 },
102 { NULL, NULL, NULL, NULL }
103};
104
105static int usbip_help(int argc, char *argv[])
106{
107 const struct command *cmd;
108 int i;
109 int ret = 0;
110
111 if (argc > 1 && argv++) {
112 for (i = 0; cmds[i].name != NULL; i++)
113 if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
114 cmds[i].usage();
115 goto done;
116 }
117 ret = -1;
118 }
119
120 usbip_usage();
121 printf("\n");
122 for (cmd = cmds; cmd->name != NULL; cmd++)
123 if (cmd->help != NULL)
124 printf(" %-10s %s\n", cmd->name, cmd->help);
125 printf("\n");
126done:
127 return ret;
128}
129
130static int usbip_version(int argc, char *argv[])
131{
132 (void) argc;
133 (void) argv;
134
135 printf(PROGNAME " (%s)\n", usbip_version_string);
136 return 0;
137}
138
139static int run_command(const struct command *cmd, int argc, char *argv[])
140{
141 dbg("running command: `%s'", cmd->name);
142 return cmd->fn(argc, argv);
143}
144
145int main(int argc, char *argv[])
146{
147 static const struct option opts[] = {
148 { "debug", no_argument, NULL, 'd' },
149 { "log", no_argument, NULL, 'l' },
150 { "tcp-port", required_argument, NULL, 't' },
151 { NULL, 0, NULL, 0 }
152 };
153
154 char *cmd;
155 int opt;
156 int i, rc = -1;
157
158 usbip_use_stderr = 1;
159 opterr = 0;
160 for (;;) {
161 opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
162
163 if (opt == -1)
164 break;
165
166 switch (opt) {
167 case 'd':
168 usbip_use_debug = 1;
169 break;
170 case 'l':
171 usbip_use_syslog = 1;
172 openlog("", LOG_PID, LOG_USER);
173 break;
174 case 't':
175 usbip_setup_port_number(optarg);
176 break;
177 case '?':
178 printf("usbip: invalid option\n");
179 default:
180 usbip_usage();
181 goto out;
182 }
183 }
184
185 cmd = argv[optind];
186 if (cmd) {
187 for (i = 0; cmds[i].name != NULL; i++)
188 if (!strcmp(cmds[i].name, cmd)) {
189 argc -= optind;
190 argv += optind;
191 optind = 0;
192 rc = run_command(&cmds[i], argc, argv);
193 goto out;
194 }
195 }
196
197 /* invalid command */
198 usbip_help(0, NULL);
199out:
200 return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
201}
diff --git a/tools/usb/usbip/src/usbip.h b/tools/usb/usbip/src/usbip.h
new file mode 100644
index 000000000000..84fe66a9d8ad
--- /dev/null
+++ b/tools/usb/usbip/src/usbip.h
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __USBIP_H
20#define __USBIP_H
21
22#ifdef HAVE_CONFIG_H
23#include "../config.h"
24#endif
25
26/* usbip commands */
27int usbip_attach(int argc, char *argv[]);
28int usbip_detach(int argc, char *argv[]);
29int usbip_list(int argc, char *argv[]);
30int usbip_bind(int argc, char *argv[]);
31int usbip_unbind(int argc, char *argv[]);
32int usbip_port_show(int argc, char *argv[]);
33
34void usbip_attach_usage(void);
35void usbip_detach_usage(void);
36void usbip_list_usage(void);
37void usbip_bind_usage(void);
38void usbip_unbind_usage(void);
39
40#endif /* __USBIP_H */
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
new file mode 100644
index 000000000000..d58a14dfc094
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -0,0 +1,241 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <sys/stat.h>
20
21#include <limits.h>
22#include <stdint.h>
23#include <stdio.h>
24#include <string.h>
25
26#include <fcntl.h>
27#include <getopt.h>
28#include <unistd.h>
29#include <errno.h>
30
31#include "vhci_driver.h"
32#include "usbip_common.h"
33#include "usbip_network.h"
34#include "usbip.h"
35
36static const char usbip_attach_usage_string[] =
37 "usbip attach <args>\n"
38 " -r, --remote=<host> The machine with exported USB devices\n"
39 " -b, --busid=<busid> Busid of the device on <host>\n";
40
41void usbip_attach_usage(void)
42{
43 printf("usage: %s", usbip_attach_usage_string);
44}
45
46#define MAX_BUFF 100
47static int record_connection(char *host, char *port, char *busid, int rhport)
48{
49 int fd;
50 char path[PATH_MAX+1];
51 char buff[MAX_BUFF+1];
52 int ret;
53
54 ret = mkdir(VHCI_STATE_PATH, 0700);
55 if (ret < 0) {
56 /* if VHCI_STATE_PATH exists, then it better be a directory */
57 if (errno == EEXIST) {
58 struct stat s;
59
60 ret = stat(VHCI_STATE_PATH, &s);
61 if (ret < 0)
62 return -1;
63 if (!(s.st_mode & S_IFDIR))
64 return -1;
65 } else
66 return -1;
67 }
68
69 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
70
71 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
72 if (fd < 0)
73 return -1;
74
75 snprintf(buff, MAX_BUFF, "%s %s %s\n",
76 host, port, busid);
77
78 ret = write(fd, buff, strlen(buff));
79 if (ret != (ssize_t) strlen(buff)) {
80 close(fd);
81 return -1;
82 }
83
84 close(fd);
85
86 return 0;
87}
88
89static int import_device(int sockfd, struct usbip_usb_device *udev)
90{
91 int rc;
92 int port;
93
94 rc = usbip_vhci_driver_open();
95 if (rc < 0) {
96 err("open vhci_driver");
97 return -1;
98 }
99
100 port = usbip_vhci_get_free_port();
101 if (port < 0) {
102 err("no free port");
103 usbip_vhci_driver_close();
104 return -1;
105 }
106
107 rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
108 udev->devnum, udev->speed);
109 if (rc < 0) {
110 err("import device");
111 usbip_vhci_driver_close();
112 return -1;
113 }
114
115 usbip_vhci_driver_close();
116
117 return port;
118}
119
120static int query_import_device(int sockfd, char *busid)
121{
122 int rc;
123 struct op_import_request request;
124 struct op_import_reply reply;
125 uint16_t code = OP_REP_IMPORT;
126
127 memset(&request, 0, sizeof(request));
128 memset(&reply, 0, sizeof(reply));
129
130 /* send a request */
131 rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
132 if (rc < 0) {
133 err("send op_common");
134 return -1;
135 }
136
137 strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
138
139 PACK_OP_IMPORT_REQUEST(0, &request);
140
141 rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
142 if (rc < 0) {
143 err("send op_import_request");
144 return -1;
145 }
146
147 /* receive a reply */
148 rc = usbip_net_recv_op_common(sockfd, &code);
149 if (rc < 0) {
150 err("recv op_common");
151 return -1;
152 }
153
154 rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
155 if (rc < 0) {
156 err("recv op_import_reply");
157 return -1;
158 }
159
160 PACK_OP_IMPORT_REPLY(0, &reply);
161
162 /* check the reply */
163 if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
164 err("recv different busid %s", reply.udev.busid);
165 return -1;
166 }
167
168 /* import a device */
169 return import_device(sockfd, &reply.udev);
170}
171
172static int attach_device(char *host, char *busid)
173{
174 int sockfd;
175 int rc;
176 int rhport;
177
178 sockfd = usbip_net_tcp_connect(host, usbip_port_string);
179 if (sockfd < 0) {
180 err("tcp connect");
181 return -1;
182 }
183
184 rhport = query_import_device(sockfd, busid);
185 if (rhport < 0) {
186 err("query");
187 return -1;
188 }
189
190 close(sockfd);
191
192 rc = record_connection(host, usbip_port_string, busid, rhport);
193 if (rc < 0) {
194 err("record connection");
195 return -1;
196 }
197
198 return 0;
199}
200
201int usbip_attach(int argc, char *argv[])
202{
203 static const struct option opts[] = {
204 { "remote", required_argument, NULL, 'r' },
205 { "busid", required_argument, NULL, 'b' },
206 { NULL, 0, NULL, 0 }
207 };
208 char *host = NULL;
209 char *busid = NULL;
210 int opt;
211 int ret = -1;
212
213 for (;;) {
214 opt = getopt_long(argc, argv, "r:b:", opts, NULL);
215
216 if (opt == -1)
217 break;
218
219 switch (opt) {
220 case 'r':
221 host = optarg;
222 break;
223 case 'b':
224 busid = optarg;
225 break;
226 default:
227 goto err_out;
228 }
229 }
230
231 if (!host || !busid)
232 goto err_out;
233
234 ret = attach_device(host, busid);
235 goto out;
236
237err_out:
238 usbip_attach_usage();
239out:
240 return ret;
241}
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
new file mode 100644
index 000000000000..fa46141ae68b
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -0,0 +1,214 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <libudev.h>
20
21#include <errno.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <getopt.h>
27
28#include "usbip_common.h"
29#include "utils.h"
30#include "usbip.h"
31#include "sysfs_utils.h"
32
33enum unbind_status {
34 UNBIND_ST_OK,
35 UNBIND_ST_USBIP_HOST,
36 UNBIND_ST_FAILED
37};
38
39static const char usbip_bind_usage_string[] =
40 "usbip bind <args>\n"
41 " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device "
42 "on <busid>\n";
43
44void usbip_bind_usage(void)
45{
46 printf("usage: %s", usbip_bind_usage_string);
47}
48
49/* call at unbound state */
50static int bind_usbip(char *busid)
51{
52 char attr_name[] = "bind";
53 char bind_attr_path[SYSFS_PATH_MAX];
54 int rc = -1;
55
56 snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
57 SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
58 SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
59
60 rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
61 if (rc < 0) {
62 err("error binding device %s to driver: %s", busid,
63 strerror(errno));
64 return -1;
65 }
66
67 return 0;
68}
69
70/* buggy driver may cause dead lock */
71static int unbind_other(char *busid)
72{
73 enum unbind_status status = UNBIND_ST_OK;
74
75 char attr_name[] = "unbind";
76 char unbind_attr_path[SYSFS_PATH_MAX];
77 int rc = -1;
78
79 struct udev *udev;
80 struct udev_device *dev;
81 const char *driver;
82 const char *bDevClass;
83
84 /* Create libudev context. */
85 udev = udev_new();
86
87 /* Get the device. */
88 dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
89 if (!dev) {
90 dbg("unable to find device with bus ID %s", busid);
91 goto err_close_busid_dev;
92 }
93
94 /* Check what kind of device it is. */
95 bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
96 if (!bDevClass) {
97 dbg("unable to get bDevClass device attribute");
98 goto err_close_busid_dev;
99 }
100
101 if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
102 dbg("skip unbinding of hub");
103 goto err_close_busid_dev;
104 }
105
106 /* Get the device driver. */
107 driver = udev_device_get_driver(dev);
108 if (!driver) {
109 /* No driver bound to this device. */
110 goto out;
111 }
112
113 if (!strncmp(USBIP_HOST_DRV_NAME, driver,
114 strlen(USBIP_HOST_DRV_NAME))) {
115 /* Already bound to usbip-host. */
116 status = UNBIND_ST_USBIP_HOST;
117 goto out;
118 }
119
120 /* Unbind device from driver. */
121 snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
122 SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
123 SYSFS_DRIVERS_NAME, driver, attr_name);
124
125 rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
126 if (rc < 0) {
127 err("error unbinding device %s from driver", busid);
128 goto err_close_busid_dev;
129 }
130
131 goto out;
132
133err_close_busid_dev:
134 status = UNBIND_ST_FAILED;
135out:
136 udev_device_unref(dev);
137 udev_unref(udev);
138
139 return status;
140}
141
142static int bind_device(char *busid)
143{
144 int rc;
145 struct udev *udev;
146 struct udev_device *dev;
147
148 /* Check whether the device with this bus ID exists. */
149 udev = udev_new();
150 dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
151 if (!dev) {
152 err("device with the specified bus ID does not exist");
153 return -1;
154 }
155 udev_unref(udev);
156
157 rc = unbind_other(busid);
158 if (rc == UNBIND_ST_FAILED) {
159 err("could not unbind driver from device on busid %s", busid);
160 return -1;
161 } else if (rc == UNBIND_ST_USBIP_HOST) {
162 err("device on busid %s is already bound to %s", busid,
163 USBIP_HOST_DRV_NAME);
164 return -1;
165 }
166
167 rc = modify_match_busid(busid, 1);
168 if (rc < 0) {
169 err("unable to bind device on %s", busid);
170 return -1;
171 }
172
173 rc = bind_usbip(busid);
174 if (rc < 0) {
175 err("could not bind device to %s", USBIP_HOST_DRV_NAME);
176 modify_match_busid(busid, 0);
177 return -1;
178 }
179
180 info("bind device on busid %s: complete", busid);
181
182 return 0;
183}
184
185int usbip_bind(int argc, char *argv[])
186{
187 static const struct option opts[] = {
188 { "busid", required_argument, NULL, 'b' },
189 { NULL, 0, NULL, 0 }
190 };
191
192 int opt;
193 int ret = -1;
194
195 for (;;) {
196 opt = getopt_long(argc, argv, "b:", opts, NULL);
197
198 if (opt == -1)
199 break;
200
201 switch (opt) {
202 case 'b':
203 ret = bind_device(optarg);
204 goto out;
205 default:
206 goto err_out;
207 }
208 }
209
210err_out:
211 usbip_bind_usage();
212out:
213 return ret;
214}
diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c
new file mode 100644
index 000000000000..05c6d15856eb
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_detach.c
@@ -0,0 +1,110 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <ctype.h>
20#include <limits.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <getopt.h>
27#include <unistd.h>
28
29#include "vhci_driver.h"
30#include "usbip_common.h"
31#include "usbip_network.h"
32#include "usbip.h"
33
34static const char usbip_detach_usage_string[] =
35 "usbip detach <args>\n"
36 " -p, --port=<port> " USBIP_VHCI_DRV_NAME
37 " port the device is on\n";
38
39void usbip_detach_usage(void)
40{
41 printf("usage: %s", usbip_detach_usage_string);
42}
43
44static int detach_port(char *port)
45{
46 int ret;
47 uint8_t portnum;
48 char path[PATH_MAX+1];
49
50 for (unsigned int i = 0; i < strlen(port); i++)
51 if (!isdigit(port[i])) {
52 err("invalid port %s", port);
53 return -1;
54 }
55
56 /* check max port */
57
58 portnum = atoi(port);
59
60 /* remove the port state file */
61
62 snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum);
63
64 remove(path);
65 rmdir(VHCI_STATE_PATH);
66
67 ret = usbip_vhci_driver_open();
68 if (ret < 0) {
69 err("open vhci_driver");
70 return -1;
71 }
72
73 ret = usbip_vhci_detach_device(portnum);
74 if (ret < 0)
75 return -1;
76
77 usbip_vhci_driver_close();
78
79 return ret;
80}
81
82int usbip_detach(int argc, char *argv[])
83{
84 static const struct option opts[] = {
85 { "port", required_argument, NULL, 'p' },
86 { NULL, 0, NULL, 0 }
87 };
88 int opt;
89 int ret = -1;
90
91 for (;;) {
92 opt = getopt_long(argc, argv, "p:", opts, NULL);
93
94 if (opt == -1)
95 break;
96
97 switch (opt) {
98 case 'p':
99 ret = detach_port(optarg);
100 goto out;
101 default:
102 goto err_out;
103 }
104 }
105
106err_out:
107 usbip_detach_usage();
108out:
109 return ret;
110}
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
new file mode 100644
index 000000000000..d5ce34a410e7
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -0,0 +1,283 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <sys/types.h>
20#include <libudev.h>
21
22#include <errno.h>
23#include <stdbool.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <getopt.h>
30#include <netdb.h>
31#include <unistd.h>
32
33#include "usbip_common.h"
34#include "usbip_network.h"
35#include "usbip.h"
36
37static const char usbip_list_usage_string[] =
38 "usbip list [-p|--parsable] <args>\n"
39 " -p, --parsable Parsable list format\n"
40 " -r, --remote=<host> List the exportable USB devices on <host>\n"
41 " -l, --local List the local USB devices\n";
42
43void usbip_list_usage(void)
44{
45 printf("usage: %s", usbip_list_usage_string);
46}
47
48static int get_exported_devices(char *host, int sockfd)
49{
50 char product_name[100];
51 char class_name[100];
52 struct op_devlist_reply reply;
53 uint16_t code = OP_REP_DEVLIST;
54 struct usbip_usb_device udev;
55 struct usbip_usb_interface uintf;
56 unsigned int i;
57 int rc, j;
58
59 rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
60 if (rc < 0) {
61 dbg("usbip_net_send_op_common failed");
62 return -1;
63 }
64
65 rc = usbip_net_recv_op_common(sockfd, &code);
66 if (rc < 0) {
67 dbg("usbip_net_recv_op_common failed");
68 return -1;
69 }
70
71 memset(&reply, 0, sizeof(reply));
72 rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
73 if (rc < 0) {
74 dbg("usbip_net_recv_op_devlist failed");
75 return -1;
76 }
77 PACK_OP_DEVLIST_REPLY(0, &reply);
78 dbg("exportable devices: %d\n", reply.ndev);
79
80 if (reply.ndev == 0) {
81 info("no exportable devices found on %s", host);
82 return 0;
83 }
84
85 printf("Exportable USB devices\n");
86 printf("======================\n");
87 printf(" - %s\n", host);
88
89 for (i = 0; i < reply.ndev; i++) {
90 memset(&udev, 0, sizeof(udev));
91 rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
92 if (rc < 0) {
93 dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
94 return -1;
95 }
96 usbip_net_pack_usb_device(0, &udev);
97
98 usbip_names_get_product(product_name, sizeof(product_name),
99 udev.idVendor, udev.idProduct);
100 usbip_names_get_class(class_name, sizeof(class_name),
101 udev.bDeviceClass, udev.bDeviceSubClass,
102 udev.bDeviceProtocol);
103 printf("%11s: %s\n", udev.busid, product_name);
104 printf("%11s: %s\n", "", udev.path);
105 printf("%11s: %s\n", "", class_name);
106
107 for (j = 0; j < udev.bNumInterfaces; j++) {
108 rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
109 if (rc < 0) {
110 err("usbip_net_recv failed: usbip_usb_intf[%d]",
111 j);
112
113 return -1;
114 }
115 usbip_net_pack_usb_interface(0, &uintf);
116
117 usbip_names_get_class(class_name, sizeof(class_name),
118 uintf.bInterfaceClass,
119 uintf.bInterfaceSubClass,
120 uintf.bInterfaceProtocol);
121 printf("%11s: %2d - %s\n", "", j, class_name);
122 }
123
124 printf("\n");
125 }
126
127 return 0;
128}
129
130static int list_exported_devices(char *host)
131{
132 int rc;
133 int sockfd;
134
135 sockfd = usbip_net_tcp_connect(host, usbip_port_string);
136 if (sockfd < 0) {
137 err("could not connect to %s:%s: %s", host,
138 usbip_port_string, gai_strerror(sockfd));
139 return -1;
140 }
141 dbg("connected to %s:%s", host, usbip_port_string);
142
143 rc = get_exported_devices(host, sockfd);
144 if (rc < 0) {
145 err("failed to get device list from %s", host);
146 return -1;
147 }
148
149 close(sockfd);
150
151 return 0;
152}
153
154static void print_device(const char *busid, const char *vendor,
155 const char *product, bool parsable)
156{
157 if (parsable)
158 printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
159 else
160 printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
161}
162
163static void print_product_name(char *product_name, bool parsable)
164{
165 if (!parsable)
166 printf(" %s\n", product_name);
167}
168
169static int list_devices(bool parsable)
170{
171 struct udev *udev;
172 struct udev_enumerate *enumerate;
173 struct udev_list_entry *devices, *dev_list_entry;
174 struct udev_device *dev;
175 const char *path;
176 const char *idVendor;
177 const char *idProduct;
178 const char *bConfValue;
179 const char *bNumIntfs;
180 const char *busid;
181 char product_name[128];
182 int ret = -1;
183
184 /* Create libudev context. */
185 udev = udev_new();
186
187 /* Create libudev device enumeration. */
188 enumerate = udev_enumerate_new(udev);
189
190 /* Take only USB devices that are not hubs and do not have
191 * the bInterfaceNumber attribute, i.e. are not interfaces.
192 */
193 udev_enumerate_add_match_subsystem(enumerate, "usb");
194 udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
195 udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
196 udev_enumerate_scan_devices(enumerate);
197
198 devices = udev_enumerate_get_list_entry(enumerate);
199
200 /* Show information about each device. */
201 udev_list_entry_foreach(dev_list_entry, devices) {
202 path = udev_list_entry_get_name(dev_list_entry);
203 dev = udev_device_new_from_syspath(udev, path);
204
205 /* Get device information. */
206 idVendor = udev_device_get_sysattr_value(dev, "idVendor");
207 idProduct = udev_device_get_sysattr_value(dev, "idProduct");
208 bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue");
209 bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces");
210 busid = udev_device_get_sysname(dev);
211 if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
212 err("problem getting device attributes: %s",
213 strerror(errno));
214 goto err_out;
215 }
216
217 /* Get product name. */
218 usbip_names_get_product(product_name, sizeof(product_name),
219 strtol(idVendor, NULL, 16),
220 strtol(idProduct, NULL, 16));
221
222 /* Print information. */
223 print_device(busid, idVendor, idProduct, parsable);
224 print_product_name(product_name, parsable);
225
226 printf("\n");
227
228 udev_device_unref(dev);
229 }
230
231 ret = 0;
232
233err_out:
234 udev_enumerate_unref(enumerate);
235 udev_unref(udev);
236
237 return ret;
238}
239
240int usbip_list(int argc, char *argv[])
241{
242 static const struct option opts[] = {
243 { "parsable", no_argument, NULL, 'p' },
244 { "remote", required_argument, NULL, 'r' },
245 { "local", no_argument, NULL, 'l' },
246 { NULL, 0, NULL, 0 }
247 };
248
249 bool parsable = false;
250 int opt;
251 int ret = -1;
252
253 if (usbip_names_init(USBIDS_FILE))
254 err("failed to open %s", USBIDS_FILE);
255
256 for (;;) {
257 opt = getopt_long(argc, argv, "pr:l", opts, NULL);
258
259 if (opt == -1)
260 break;
261
262 switch (opt) {
263 case 'p':
264 parsable = true;
265 break;
266 case 'r':
267 ret = list_exported_devices(optarg);
268 goto out;
269 case 'l':
270 ret = list_devices(parsable);
271 goto out;
272 default:
273 goto err_out;
274 }
275 }
276
277err_out:
278 usbip_list_usage();
279out:
280 usbip_names_free();
281
282 return ret;
283}
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
new file mode 100644
index 000000000000..b4c37e76a6e0
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -0,0 +1,303 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <sys/socket.h>
20
21#include <string.h>
22
23#include <arpa/inet.h>
24#include <netdb.h>
25#include <netinet/tcp.h>
26#include <unistd.h>
27
28#ifdef HAVE_LIBWRAP
29#include <tcpd.h>
30#endif
31
32#include "usbip_common.h"
33#include "usbip_network.h"
34
35int usbip_port = 3240;
36char *usbip_port_string = "3240";
37
38void usbip_setup_port_number(char *arg)
39{
40 dbg("parsing port arg '%s'", arg);
41 char *end;
42 unsigned long int port = strtoul(arg, &end, 10);
43
44 if (end == arg) {
45 err("port: could not parse '%s' as a decimal integer", arg);
46 return;
47 }
48
49 if (*end != '\0') {
50 err("port: garbage at end of '%s'", arg);
51 return;
52 }
53
54 if (port > UINT16_MAX) {
55 err("port: %s too high (max=%d)",
56 arg, UINT16_MAX);
57 return;
58 }
59
60 usbip_port = port;
61 usbip_port_string = arg;
62 info("using port %d (\"%s\")", usbip_port, usbip_port_string);
63}
64
65void usbip_net_pack_uint32_t(int pack, uint32_t *num)
66{
67 uint32_t i;
68
69 if (pack)
70 i = htonl(*num);
71 else
72 i = ntohl(*num);
73
74 *num = i;
75}
76
77void usbip_net_pack_uint16_t(int pack, uint16_t *num)
78{
79 uint16_t i;
80
81 if (pack)
82 i = htons(*num);
83 else
84 i = ntohs(*num);
85
86 *num = i;
87}
88
89void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
90{
91 usbip_net_pack_uint32_t(pack, &udev->busnum);
92 usbip_net_pack_uint32_t(pack, &udev->devnum);
93 usbip_net_pack_uint32_t(pack, &udev->speed);
94
95 usbip_net_pack_uint16_t(pack, &udev->idVendor);
96 usbip_net_pack_uint16_t(pack, &udev->idProduct);
97 usbip_net_pack_uint16_t(pack, &udev->bcdDevice);
98}
99
100void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
101 struct usbip_usb_interface *udev
102 __attribute__((unused)))
103{
104 /* uint8_t members need nothing */
105}
106
107static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
108 int sending)
109{
110 ssize_t nbytes;
111 ssize_t total = 0;
112
113 if (!bufflen)
114 return 0;
115
116 do {
117 if (sending)
118 nbytes = send(sockfd, buff, bufflen, 0);
119 else
120 nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
121
122 if (nbytes <= 0)
123 return -1;
124
125 buff = (void *)((intptr_t) buff + nbytes);
126 bufflen -= nbytes;
127 total += nbytes;
128
129 } while (bufflen > 0);
130
131 return total;
132}
133
134ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
135{
136 return usbip_net_xmit(sockfd, buff, bufflen, 0);
137}
138
139ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
140{
141 return usbip_net_xmit(sockfd, buff, bufflen, 1);
142}
143
144int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
145{
146 struct op_common op_common;
147 int rc;
148
149 memset(&op_common, 0, sizeof(op_common));
150
151 op_common.version = USBIP_VERSION;
152 op_common.code = code;
153 op_common.status = status;
154
155 PACK_OP_COMMON(1, &op_common);
156
157 rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
158 if (rc < 0) {
159 dbg("usbip_net_send failed: %d", rc);
160 return -1;
161 }
162
163 return 0;
164}
165
166int usbip_net_recv_op_common(int sockfd, uint16_t *code)
167{
168 struct op_common op_common;
169 int rc;
170
171 memset(&op_common, 0, sizeof(op_common));
172
173 rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
174 if (rc < 0) {
175 dbg("usbip_net_recv failed: %d", rc);
176 goto err;
177 }
178
179 PACK_OP_COMMON(0, &op_common);
180
181 if (op_common.version != USBIP_VERSION) {
182 dbg("version mismatch: %d %d", op_common.version,
183 USBIP_VERSION);
184 goto err;
185 }
186
187 switch (*code) {
188 case OP_UNSPEC:
189 break;
190 default:
191 if (op_common.code != *code) {
192 dbg("unexpected pdu %#0x for %#0x", op_common.code,
193 *code);
194 goto err;
195 }
196 }
197
198 if (op_common.status != ST_OK) {
199 dbg("request failed at peer: %d", op_common.status);
200 goto err;
201 }
202
203 *code = op_common.code;
204
205 return 0;
206err:
207 return -1;
208}
209
210int usbip_net_set_reuseaddr(int sockfd)
211{
212 const int val = 1;
213 int ret;
214
215 ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
216 if (ret < 0)
217 dbg("setsockopt: SO_REUSEADDR");
218
219 return ret;
220}
221
222int usbip_net_set_nodelay(int sockfd)
223{
224 const int val = 1;
225 int ret;
226
227 ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
228 if (ret < 0)
229 dbg("setsockopt: TCP_NODELAY");
230
231 return ret;
232}
233
234int usbip_net_set_keepalive(int sockfd)
235{
236 const int val = 1;
237 int ret;
238
239 ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
240 if (ret < 0)
241 dbg("setsockopt: SO_KEEPALIVE");
242
243 return ret;
244}
245
246int usbip_net_set_v6only(int sockfd)
247{
248 const int val = 1;
249 int ret;
250
251 ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
252 if (ret < 0)
253 dbg("setsockopt: IPV6_V6ONLY");
254
255 return ret;
256}
257
258/*
259 * IPv6 Ready
260 */
261int usbip_net_tcp_connect(char *hostname, char *service)
262{
263 struct addrinfo hints, *res, *rp;
264 int sockfd;
265 int ret;
266
267 memset(&hints, 0, sizeof(hints));
268 hints.ai_family = AF_UNSPEC;
269 hints.ai_socktype = SOCK_STREAM;
270
271 /* get all possible addresses */
272 ret = getaddrinfo(hostname, service, &hints, &res);
273 if (ret < 0) {
274 dbg("getaddrinfo: %s service %s: %s", hostname, service,
275 gai_strerror(ret));
276 return ret;
277 }
278
279 /* try the addresses */
280 for (rp = res; rp; rp = rp->ai_next) {
281 sockfd = socket(rp->ai_family, rp->ai_socktype,
282 rp->ai_protocol);
283 if (sockfd < 0)
284 continue;
285
286 /* should set TCP_NODELAY for usbip */
287 usbip_net_set_nodelay(sockfd);
288 /* TODO: write code for heartbeat */
289 usbip_net_set_keepalive(sockfd);
290
291 if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
292 break;
293
294 close(sockfd);
295 }
296
297 freeaddrinfo(res);
298
299 if (!rp)
300 return EAI_SYSTEM;
301
302 return sockfd;
303}
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
new file mode 100644
index 000000000000..c1e875cf1078
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -0,0 +1,185 @@
1/*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
4
5#ifndef __USBIP_NETWORK_H
6#define __USBIP_NETWORK_H
7
8#ifdef HAVE_CONFIG_H
9#include "../config.h"
10#endif
11
12#include <sys/types.h>
13
14#include <stdint.h>
15
16extern int usbip_port;
17extern char *usbip_port_string;
18void usbip_setup_port_number(char *arg);
19
20/* ---------------------------------------------------------------------- */
21/* Common header for all the kinds of PDUs. */
22struct op_common {
23 uint16_t version;
24
25#define OP_REQUEST (0x80 << 8)
26#define OP_REPLY (0x00 << 8)
27 uint16_t code;
28
29 /* add more error code */
30#define ST_OK 0x00
31#define ST_NA 0x01
32 uint32_t status; /* op_code status (for reply) */
33
34} __attribute__((packed));
35
36#define PACK_OP_COMMON(pack, op_common) do {\
37 usbip_net_pack_uint16_t(pack, &(op_common)->version);\
38 usbip_net_pack_uint16_t(pack, &(op_common)->code);\
39 usbip_net_pack_uint32_t(pack, &(op_common)->status);\
40} while (0)
41
42/* ---------------------------------------------------------------------- */
43/* Dummy Code */
44#define OP_UNSPEC 0x00
45#define OP_REQ_UNSPEC OP_UNSPEC
46#define OP_REP_UNSPEC OP_UNSPEC
47
48/* ---------------------------------------------------------------------- */
49/* Retrieve USB device information. (still not used) */
50#define OP_DEVINFO 0x02
51#define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO)
52#define OP_REP_DEVINFO (OP_REPLY | OP_DEVINFO)
53
54struct op_devinfo_request {
55 char busid[SYSFS_BUS_ID_SIZE];
56} __attribute__((packed));
57
58struct op_devinfo_reply {
59 struct usbip_usb_device udev;
60 struct usbip_usb_interface uinf[];
61} __attribute__((packed));
62
63/* ---------------------------------------------------------------------- */
64/* Import a remote USB device. */
65#define OP_IMPORT 0x03
66#define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT)
67#define OP_REP_IMPORT (OP_REPLY | OP_IMPORT)
68
69struct op_import_request {
70 char busid[SYSFS_BUS_ID_SIZE];
71} __attribute__((packed));
72
73struct op_import_reply {
74 struct usbip_usb_device udev;
75// struct usbip_usb_interface uinf[];
76} __attribute__((packed));
77
78#define PACK_OP_IMPORT_REQUEST(pack, request) do {\
79} while (0)
80
81#define PACK_OP_IMPORT_REPLY(pack, reply) do {\
82 usbip_net_pack_usb_device(pack, &(reply)->udev);\
83} while (0)
84
85/* ---------------------------------------------------------------------- */
86/* Export a USB device to a remote host. */
87#define OP_EXPORT 0x06
88#define OP_REQ_EXPORT (OP_REQUEST | OP_EXPORT)
89#define OP_REP_EXPORT (OP_REPLY | OP_EXPORT)
90
91struct op_export_request {
92 struct usbip_usb_device udev;
93} __attribute__((packed));
94
95struct op_export_reply {
96 int returncode;
97} __attribute__((packed));
98
99
100#define PACK_OP_EXPORT_REQUEST(pack, request) do {\
101 usbip_net_pack_usb_device(pack, &(request)->udev);\
102} while (0)
103
104#define PACK_OP_EXPORT_REPLY(pack, reply) do {\
105} while (0)
106
107/* ---------------------------------------------------------------------- */
108/* un-Export a USB device from a remote host. */
109#define OP_UNEXPORT 0x07
110#define OP_REQ_UNEXPORT (OP_REQUEST | OP_UNEXPORT)
111#define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT)
112
113struct op_unexport_request {
114 struct usbip_usb_device udev;
115} __attribute__((packed));
116
117struct op_unexport_reply {
118 int returncode;
119} __attribute__((packed));
120
121#define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\
122 usbip_net_pack_usb_device(pack, &(request)->udev);\
123} while (0)
124
125#define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\
126} while (0)
127
128/* ---------------------------------------------------------------------- */
129/* Negotiate IPSec encryption key. (still not used) */
130#define OP_CRYPKEY 0x04
131#define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY)
132#define OP_REP_CRYPKEY (OP_REPLY | OP_CRYPKEY)
133
134struct op_crypkey_request {
135 /* 128bit key */
136 uint32_t key[4];
137} __attribute__((packed));
138
139struct op_crypkey_reply {
140 uint32_t __reserved;
141} __attribute__((packed));
142
143
144/* ---------------------------------------------------------------------- */
145/* Retrieve the list of exported USB devices. */
146#define OP_DEVLIST 0x05
147#define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST)
148#define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST)
149
150struct op_devlist_request {
151} __attribute__((packed));
152
153struct op_devlist_reply {
154 uint32_t ndev;
155 /* followed by reply_extra[] */
156} __attribute__((packed));
157
158struct op_devlist_reply_extra {
159 struct usbip_usb_device udev;
160 struct usbip_usb_interface uinf[];
161} __attribute__((packed));
162
163#define PACK_OP_DEVLIST_REQUEST(pack, request) do {\
164} while (0)
165
166#define PACK_OP_DEVLIST_REPLY(pack, reply) do {\
167 usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
168} while (0)
169
170void usbip_net_pack_uint32_t(int pack, uint32_t *num);
171void usbip_net_pack_uint16_t(int pack, uint16_t *num);
172void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
173void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
174
175ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
176ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
177int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
178int usbip_net_recv_op_common(int sockfd, uint16_t *code);
179int usbip_net_set_reuseaddr(int sockfd);
180int usbip_net_set_nodelay(int sockfd);
181int usbip_net_set_keepalive(int sockfd);
182int usbip_net_set_v6only(int sockfd);
183int usbip_net_tcp_connect(char *hostname, char *port);
184
185#endif /* __USBIP_NETWORK_H */
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c
new file mode 100644
index 000000000000..a2e884fd9226
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_port.c
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include "vhci_driver.h"
17#include "usbip_common.h"
18
19static int list_imported_devices(void)
20{
21 int i;
22 struct usbip_imported_device *idev;
23 int ret;
24
25 ret = usbip_vhci_driver_open();
26 if (ret < 0) {
27 err("open vhci_driver");
28 return -1;
29 }
30
31 printf("Imported USB devices\n");
32 printf("====================\n");
33
34 for (i = 0; i < vhci_driver->nports; i++) {
35 idev = &vhci_driver->idev[i];
36
37 if (usbip_vhci_imported_device_dump(idev) < 0)
38 ret = -1;
39 }
40
41 usbip_vhci_driver_close();
42
43 return ret;
44
45}
46
47int usbip_port_show(__attribute__((unused)) int argc,
48 __attribute__((unused)) char *argv[])
49{
50 int ret;
51
52 ret = list_imported_devices();
53 if (ret < 0)
54 err("list imported devices");
55
56 return ret;
57}
diff --git a/tools/usb/usbip/src/usbip_unbind.c b/tools/usb/usbip/src/usbip_unbind.c
new file mode 100644
index 000000000000..a4a496c9cbaf
--- /dev/null
+++ b/tools/usb/usbip/src/usbip_unbind.c
@@ -0,0 +1,141 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <libudev.h>
20
21#include <errno.h>
22#include <stdio.h>
23#include <string.h>
24
25#include <getopt.h>
26
27#include "usbip_common.h"
28#include "utils.h"
29#include "usbip.h"
30#include "sysfs_utils.h"
31
32static const char usbip_unbind_usage_string[] =
33 "usbip unbind <args>\n"
34 " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from "
35 "device on <busid>\n";
36
37void usbip_unbind_usage(void)
38{
39 printf("usage: %s", usbip_unbind_usage_string);
40}
41
42static int unbind_device(char *busid)
43{
44 char bus_type[] = "usb";
45 int rc, ret = -1;
46
47 char unbind_attr_name[] = "unbind";
48 char unbind_attr_path[SYSFS_PATH_MAX];
49 char rebind_attr_name[] = "rebind";
50 char rebind_attr_path[SYSFS_PATH_MAX];
51
52 struct udev *udev;
53 struct udev_device *dev;
54 const char *driver;
55
56 /* Create libudev context. */
57 udev = udev_new();
58
59 /* Check whether the device with this bus ID exists. */
60 dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
61 if (!dev) {
62 err("device with the specified bus ID does not exist");
63 goto err_close_udev;
64 }
65
66 /* Check whether the device is using usbip-host driver. */
67 driver = udev_device_get_driver(dev);
68 if (!driver || strcmp(driver, "usbip-host")) {
69 err("device is not bound to usbip-host driver");
70 goto err_close_udev;
71 }
72
73 /* Unbind device from driver. */
74 snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
75 SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
76 USBIP_HOST_DRV_NAME, unbind_attr_name);
77
78 rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
79 if (rc < 0) {
80 err("error unbinding device %s from driver", busid);
81 goto err_close_udev;
82 }
83
84 /* Notify driver of unbind. */
85 rc = modify_match_busid(busid, 0);
86 if (rc < 0) {
87 err("unable to unbind device on %s", busid);
88 goto err_close_udev;
89 }
90
91 /* Trigger new probing. */
92 snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
93 SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
94 USBIP_HOST_DRV_NAME, rebind_attr_name);
95
96 rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid));
97 if (rc < 0) {
98 err("error rebinding");
99 goto err_close_udev;
100 }
101
102 ret = 0;
103 info("unbind device on busid %s: complete", busid);
104
105err_close_udev:
106 udev_device_unref(dev);
107 udev_unref(udev);
108
109 return ret;
110}
111
112int usbip_unbind(int argc, char *argv[])
113{
114 static const struct option opts[] = {
115 { "busid", required_argument, NULL, 'b' },
116 { NULL, 0, NULL, 0 }
117 };
118
119 int opt;
120 int ret = -1;
121
122 for (;;) {
123 opt = getopt_long(argc, argv, "b:", opts, NULL);
124
125 if (opt == -1)
126 break;
127
128 switch (opt) {
129 case 'b':
130 ret = unbind_device(optarg);
131 goto out;
132 default:
133 goto err_out;
134 }
135 }
136
137err_out:
138 usbip_unbind_usage();
139out:
140 return ret;
141}
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
new file mode 100644
index 000000000000..2f87f2d348ba
--- /dev/null
+++ b/tools/usb/usbip/src/usbipd.c
@@ -0,0 +1,679 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include "../config.h"
21#endif
22
23#define _GNU_SOURCE
24#include <errno.h>
25#include <unistd.h>
26#include <netdb.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <arpa/inet.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
34
35#ifdef HAVE_LIBWRAP
36#include <tcpd.h>
37#endif
38
39#include <getopt.h>
40#include <signal.h>
41#include <poll.h>
42
43#include "usbip_host_driver.h"
44#include "usbip_common.h"
45#include "usbip_network.h"
46#include "list.h"
47
48#undef PROGNAME
49#define PROGNAME "usbipd"
50#define MAXSOCKFD 20
51
52#define MAIN_LOOP_TIMEOUT 10
53
54#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
55
56static const char usbip_version_string[] = PACKAGE_STRING;
57
58static const char usbipd_help_string[] =
59 "usage: usbipd [options]\n"
60 "\n"
61 " -4, --ipv4\n"
62 " Bind to IPv4. Default is both.\n"
63 "\n"
64 " -6, --ipv6\n"
65 " Bind to IPv6. Default is both.\n"
66 "\n"
67 " -D, --daemon\n"
68 " Run as a daemon process.\n"
69 "\n"
70 " -d, --debug\n"
71 " Print debugging information.\n"
72 "\n"
73 " -PFILE, --pid FILE\n"
74 " Write process id to FILE.\n"
75 " If no FILE specified, use " DEFAULT_PID_FILE "\n"
76 "\n"
77 " -tPORT, --tcp-port PORT\n"
78 " Listen on TCP/IP port PORT.\n"
79 "\n"
80 " -h, --help\n"
81 " Print this help.\n"
82 "\n"
83 " -v, --version\n"
84 " Show version.\n";
85
86static void usbipd_help(void)
87{
88 printf("%s\n", usbipd_help_string);
89}
90
91static int recv_request_import(int sockfd)
92{
93 struct op_import_request req;
94 struct op_common reply;
95 struct usbip_exported_device *edev;
96 struct usbip_usb_device pdu_udev;
97 struct list_head *i;
98 int found = 0;
99 int error = 0;
100 int rc;
101
102 memset(&req, 0, sizeof(req));
103 memset(&reply, 0, sizeof(reply));
104
105 rc = usbip_net_recv(sockfd, &req, sizeof(req));
106 if (rc < 0) {
107 dbg("usbip_net_recv failed: import request");
108 return -1;
109 }
110 PACK_OP_IMPORT_REQUEST(0, &req);
111
112 list_for_each(i, &host_driver->edev_list) {
113 edev = list_entry(i, struct usbip_exported_device, node);
114 if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
115 info("found requested device: %s", req.busid);
116 found = 1;
117 break;
118 }
119 }
120
121 if (found) {
122 /* should set TCP_NODELAY for usbip */
123 usbip_net_set_nodelay(sockfd);
124
125 /* export device needs a TCP/IP socket descriptor */
126 rc = usbip_host_export_device(edev, sockfd);
127 if (rc < 0)
128 error = 1;
129 } else {
130 info("requested device not found: %s", req.busid);
131 error = 1;
132 }
133
134 rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
135 (!error ? ST_OK : ST_NA));
136 if (rc < 0) {
137 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
138 return -1;
139 }
140
141 if (error) {
142 dbg("import request busid %s: failed", req.busid);
143 return -1;
144 }
145
146 memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
147 usbip_net_pack_usb_device(1, &pdu_udev);
148
149 rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
150 if (rc < 0) {
151 dbg("usbip_net_send failed: devinfo");
152 return -1;
153 }
154
155 dbg("import request busid %s: complete", req.busid);
156
157 return 0;
158}
159
160static int send_reply_devlist(int connfd)
161{
162 struct usbip_exported_device *edev;
163 struct usbip_usb_device pdu_udev;
164 struct usbip_usb_interface pdu_uinf;
165 struct op_devlist_reply reply;
166 struct list_head *j;
167 int rc, i;
168
169 reply.ndev = 0;
170 /* number of exported devices */
171 list_for_each(j, &host_driver->edev_list) {
172 reply.ndev += 1;
173 }
174 info("exportable devices: %d", reply.ndev);
175
176 rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
177 if (rc < 0) {
178 dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
179 return -1;
180 }
181 PACK_OP_DEVLIST_REPLY(1, &reply);
182
183 rc = usbip_net_send(connfd, &reply, sizeof(reply));
184 if (rc < 0) {
185 dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
186 return -1;
187 }
188
189 list_for_each(j, &host_driver->edev_list) {
190 edev = list_entry(j, struct usbip_exported_device, node);
191 dump_usb_device(&edev->udev);
192 memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
193 usbip_net_pack_usb_device(1, &pdu_udev);
194
195 rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
196 if (rc < 0) {
197 dbg("usbip_net_send failed: pdu_udev");
198 return -1;
199 }
200
201 for (i = 0; i < edev->udev.bNumInterfaces; i++) {
202 dump_usb_interface(&edev->uinf[i]);
203 memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
204 usbip_net_pack_usb_interface(1, &pdu_uinf);
205
206 rc = usbip_net_send(connfd, &pdu_uinf,
207 sizeof(pdu_uinf));
208 if (rc < 0) {
209 err("usbip_net_send failed: pdu_uinf");
210 return -1;
211 }
212 }
213 }
214
215 return 0;
216}
217
218static int recv_request_devlist(int connfd)
219{
220 struct op_devlist_request req;
221 int rc;
222
223 memset(&req, 0, sizeof(req));
224
225 rc = usbip_net_recv(connfd, &req, sizeof(req));
226 if (rc < 0) {
227 dbg("usbip_net_recv failed: devlist request");
228 return -1;
229 }
230
231 rc = send_reply_devlist(connfd);
232 if (rc < 0) {
233 dbg("send_reply_devlist failed");
234 return -1;
235 }
236
237 return 0;
238}
239
240static int recv_pdu(int connfd)
241{
242 uint16_t code = OP_UNSPEC;
243 int ret;
244
245 ret = usbip_net_recv_op_common(connfd, &code);
246 if (ret < 0) {
247 dbg("could not receive opcode: %#0x", code);
248 return -1;
249 }
250
251 ret = usbip_host_refresh_device_list();
252 if (ret < 0) {
253 dbg("could not refresh device list: %d", ret);
254 return -1;
255 }
256
257 info("received request: %#0x(%d)", code, connfd);
258 switch (code) {
259 case OP_REQ_DEVLIST:
260 ret = recv_request_devlist(connfd);
261 break;
262 case OP_REQ_IMPORT:
263 ret = recv_request_import(connfd);
264 break;
265 case OP_REQ_DEVINFO:
266 case OP_REQ_CRYPKEY:
267 default:
268 err("received an unknown opcode: %#0x", code);
269 ret = -1;
270 }
271
272 if (ret == 0)
273 info("request %#0x(%d): complete", code, connfd);
274 else
275 info("request %#0x(%d): failed", code, connfd);
276
277 return ret;
278}
279
280#ifdef HAVE_LIBWRAP
281static int tcpd_auth(int connfd)
282{
283 struct request_info request;
284 int rc;
285
286 request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
287 fromhost(&request);
288 rc = hosts_access(&request);
289 if (rc == 0)
290 return -1;
291
292 return 0;
293}
294#endif
295
296static int do_accept(int listenfd)
297{
298 int connfd;
299 struct sockaddr_storage ss;
300 socklen_t len = sizeof(ss);
301 char host[NI_MAXHOST], port[NI_MAXSERV];
302 int rc;
303
304 memset(&ss, 0, sizeof(ss));
305
306 connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
307 if (connfd < 0) {
308 err("failed to accept connection");
309 return -1;
310 }
311
312 rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
313 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
314 if (rc)
315 err("getnameinfo: %s", gai_strerror(rc));
316
317#ifdef HAVE_LIBWRAP
318 rc = tcpd_auth(connfd);
319 if (rc < 0) {
320 info("denied access from %s", host);
321 close(connfd);
322 return -1;
323 }
324#endif
325 info("connection from %s:%s", host, port);
326
327 return connfd;
328}
329
330int process_request(int listenfd)
331{
332 pid_t childpid;
333 int connfd;
334
335 connfd = do_accept(listenfd);
336 if (connfd < 0)
337 return -1;
338 childpid = fork();
339 if (childpid == 0) {
340 close(listenfd);
341 recv_pdu(connfd);
342 exit(0);
343 }
344 close(connfd);
345 return 0;
346}
347
348static void addrinfo_to_text(struct addrinfo *ai, char buf[],
349 const size_t buf_size)
350{
351 char hbuf[NI_MAXHOST];
352 char sbuf[NI_MAXSERV];
353 int rc;
354
355 buf[0] = '\0';
356
357 rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
358 sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
359 if (rc)
360 err("getnameinfo: %s", gai_strerror(rc));
361
362 snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
363}
364
365static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[],
366 int maxsockfd)
367{
368 struct addrinfo *ai;
369 int ret, nsockfd = 0;
370 const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
371 char ai_buf[ai_buf_size];
372
373 for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) {
374 int sock;
375
376 addrinfo_to_text(ai, ai_buf, ai_buf_size);
377 dbg("opening %s", ai_buf);
378 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
379 if (sock < 0) {
380 err("socket: %s: %d (%s)",
381 ai_buf, errno, strerror(errno));
382 continue;
383 }
384
385 usbip_net_set_reuseaddr(sock);
386 usbip_net_set_nodelay(sock);
387 /* We use seperate sockets for IPv4 and IPv6
388 * (see do_standalone_mode()) */
389 usbip_net_set_v6only(sock);
390
391 if (sock >= FD_SETSIZE) {
392 err("FD_SETSIZE: %s: sock=%d, max=%d",
393 ai_buf, sock, FD_SETSIZE);
394 close(sock);
395 continue;
396 }
397
398 ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
399 if (ret < 0) {
400 err("bind: %s: %d (%s)",
401 ai_buf, errno, strerror(errno));
402 close(sock);
403 continue;
404 }
405
406 ret = listen(sock, SOMAXCONN);
407 if (ret < 0) {
408 err("listen: %s: %d (%s)",
409 ai_buf, errno, strerror(errno));
410 close(sock);
411 continue;
412 }
413
414 info("listening on %s", ai_buf);
415 sockfdlist[nsockfd++] = sock;
416 }
417
418 return nsockfd;
419}
420
421static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
422{
423 struct addrinfo hints, *ai_head;
424 int rc;
425
426 memset(&hints, 0, sizeof(hints));
427 hints.ai_family = ai_family;
428 hints.ai_socktype = SOCK_STREAM;
429 hints.ai_flags = AI_PASSIVE;
430
431 rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
432 if (rc) {
433 err("failed to get a network address %s: %s", usbip_port_string,
434 gai_strerror(rc));
435 return NULL;
436 }
437
438 return ai_head;
439}
440
441static void signal_handler(int i)
442{
443 dbg("received '%s' signal", strsignal(i));
444}
445
446static void set_signal(void)
447{
448 struct sigaction act;
449
450 memset(&act, 0, sizeof(act));
451 act.sa_handler = signal_handler;
452 sigemptyset(&act.sa_mask);
453 sigaction(SIGTERM, &act, NULL);
454 sigaction(SIGINT, &act, NULL);
455 act.sa_handler = SIG_IGN;
456 sigaction(SIGCLD, &act, NULL);
457}
458
459static const char *pid_file;
460
461static void write_pid_file(void)
462{
463 if (pid_file) {
464 dbg("creating pid file %s", pid_file);
465 FILE *fp;
466
467 fp = fopen(pid_file, "w");
468 if (!fp) {
469 err("pid_file: %s: %d (%s)",
470 pid_file, errno, strerror(errno));
471 return;
472 }
473 fprintf(fp, "%d\n", getpid());
474 fclose(fp);
475 }
476}
477
478static void remove_pid_file(void)
479{
480 if (pid_file) {
481 dbg("removing pid file %s", pid_file);
482 unlink(pid_file);
483 }
484}
485
486static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
487{
488 struct addrinfo *ai_head;
489 int sockfdlist[MAXSOCKFD];
490 int nsockfd, family;
491 int i, terminate;
492 struct pollfd *fds;
493 struct timespec timeout;
494 sigset_t sigmask;
495
496 if (usbip_host_driver_open()) {
497 err("please load " USBIP_CORE_MOD_NAME ".ko and "
498 USBIP_HOST_DRV_NAME ".ko!");
499 return -1;
500 }
501
502 if (daemonize) {
503 if (daemon(0, 0) < 0) {
504 err("daemonizing failed: %s", strerror(errno));
505 usbip_host_driver_close();
506 return -1;
507 }
508 umask(0);
509 usbip_use_syslog = 1;
510 }
511 set_signal();
512 write_pid_file();
513
514 info("starting " PROGNAME " (%s)", usbip_version_string);
515
516 /*
517 * To suppress warnings on systems with bindv6only disabled
518 * (default), we use seperate sockets for IPv6 and IPv4 and set
519 * IPV6_V6ONLY on the IPv6 sockets.
520 */
521 if (ipv4 && ipv6)
522 family = AF_UNSPEC;
523 else if (ipv4)
524 family = AF_INET;
525 else
526 family = AF_INET6;
527
528 ai_head = do_getaddrinfo(NULL, family);
529 if (!ai_head) {
530 usbip_host_driver_close();
531 return -1;
532 }
533 nsockfd = listen_all_addrinfo(ai_head, sockfdlist,
534 sizeof(sockfdlist) / sizeof(*sockfdlist));
535 freeaddrinfo(ai_head);
536 if (nsockfd <= 0) {
537 err("failed to open a listening socket");
538 usbip_host_driver_close();
539 return -1;
540 }
541
542 dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
543
544 fds = calloc(nsockfd, sizeof(struct pollfd));
545 for (i = 0; i < nsockfd; i++) {
546 fds[i].fd = sockfdlist[i];
547 fds[i].events = POLLIN;
548 }
549 timeout.tv_sec = MAIN_LOOP_TIMEOUT;
550 timeout.tv_nsec = 0;
551
552 sigfillset(&sigmask);
553 sigdelset(&sigmask, SIGTERM);
554 sigdelset(&sigmask, SIGINT);
555
556 terminate = 0;
557 while (!terminate) {
558 int r;
559
560 r = ppoll(fds, nsockfd, &timeout, &sigmask);
561 if (r < 0) {
562 dbg("%s", strerror(errno));
563 terminate = 1;
564 } else if (r) {
565 for (i = 0; i < nsockfd; i++) {
566 if (fds[i].revents & POLLIN) {
567 dbg("read event on fd[%d]=%d",
568 i, sockfdlist[i]);
569 process_request(sockfdlist[i]);
570 }
571 }
572 } else {
573 dbg("heartbeat timeout on ppoll()");
574 }
575 }
576
577 info("shutting down " PROGNAME);
578 free(fds);
579 usbip_host_driver_close();
580
581 return 0;
582}
583
584int main(int argc, char *argv[])
585{
586 static const struct option longopts[] = {
587 { "ipv4", no_argument, NULL, '4' },
588 { "ipv6", no_argument, NULL, '6' },
589 { "daemon", no_argument, NULL, 'D' },
590 { "daemon", no_argument, NULL, 'D' },
591 { "debug", no_argument, NULL, 'd' },
592 { "pid", optional_argument, NULL, 'P' },
593 { "tcp-port", required_argument, NULL, 't' },
594 { "help", no_argument, NULL, 'h' },
595 { "version", no_argument, NULL, 'v' },
596 { NULL, 0, NULL, 0 }
597 };
598
599 enum {
600 cmd_standalone_mode = 1,
601 cmd_help,
602 cmd_version
603 } cmd;
604
605 int daemonize = 0;
606 int ipv4 = 0, ipv6 = 0;
607 int opt, rc = -1;
608
609 pid_file = NULL;
610
611 usbip_use_stderr = 1;
612 usbip_use_syslog = 0;
613
614 if (geteuid() != 0)
615 err("not running as root?");
616
617 cmd = cmd_standalone_mode;
618 for (;;) {
619 opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
620
621 if (opt == -1)
622 break;
623
624 switch (opt) {
625 case '4':
626 ipv4 = 1;
627 break;
628 case '6':
629 ipv6 = 1;
630 break;
631 case 'D':
632 daemonize = 1;
633 break;
634 case 'd':
635 usbip_use_debug = 1;
636 break;
637 case 'h':
638 cmd = cmd_help;
639 break;
640 case 'P':
641 pid_file = optarg ? optarg : DEFAULT_PID_FILE;
642 break;
643 case 't':
644 usbip_setup_port_number(optarg);
645 break;
646 case 'v':
647 cmd = cmd_version;
648 break;
649 case '?':
650 usbipd_help();
651 default:
652 goto err_out;
653 }
654 }
655
656 if (!ipv4 && !ipv6)
657 ipv4 = ipv6 = 1;
658
659 switch (cmd) {
660 case cmd_standalone_mode:
661 rc = do_standalone_mode(daemonize, ipv4, ipv6);
662 remove_pid_file();
663 break;
664 case cmd_version:
665 printf(PROGNAME " (%s)\n", usbip_version_string);
666 rc = 0;
667 break;
668 case cmd_help:
669 usbipd_help();
670 rc = 0;
671 break;
672 default:
673 usbipd_help();
674 goto err_out;
675 }
676
677err_out:
678 return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
679}
diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c
new file mode 100644
index 000000000000..2b3d6d235015
--- /dev/null
+++ b/tools/usb/usbip/src/utils.c
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <errno.h>
20#include <stdio.h>
21#include <string.h>
22
23#include "usbip_common.h"
24#include "utils.h"
25#include "sysfs_utils.h"
26
27int modify_match_busid(char *busid, int add)
28{
29 char attr_name[] = "match_busid";
30 char command[SYSFS_BUS_ID_SIZE + 4];
31 char match_busid_attr_path[SYSFS_PATH_MAX];
32 int rc;
33
34 snprintf(match_busid_attr_path, sizeof(match_busid_attr_path),
35 "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME,
36 SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME,
37 attr_name);
38
39 if (add)
40 snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
41 else
42 snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
43
44 rc = write_sysfs_attribute(match_busid_attr_path, command,
45 sizeof(command));
46 if (rc < 0) {
47 dbg("failed to write match_busid: %s", strerror(errno));
48 return -1;
49 }
50
51 return 0;
52}
diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h
new file mode 100644
index 000000000000..5916fd3e02a6
--- /dev/null
+++ b/tools/usb/usbip/src/utils.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
3 * 2005-2007 Takahiro Hirofuchi
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __UTILS_H
20#define __UTILS_H
21
22int modify_match_busid(char *busid, int add);
23
24#endif /* __UTILS_H */
25
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index c4d6d2e20e0d..264fbc297e0b 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -132,6 +132,7 @@ static const char * const page_flag_names[] = {
132 [KPF_NOPAGE] = "n:nopage", 132 [KPF_NOPAGE] = "n:nopage",
133 [KPF_KSM] = "x:ksm", 133 [KPF_KSM] = "x:ksm",
134 [KPF_THP] = "t:thp", 134 [KPF_THP] = "t:thp",
135 [KPF_BALLOON] = "o:balloon",
135 136
136 [KPF_RESERVED] = "r:reserved", 137 [KPF_RESERVED] = "r:reserved",
137 [KPF_MLOCKED] = "m:mlocked", 138 [KPF_MLOCKED] = "m:mlocked",