Commit a12b51c478899fe0b7e874a559b05ba35f1128ee
Committed by
Ingo Molnar
1 parent
220b140b52
Exists in
master
and in
39 other branches
perf tools: Fix sparse CPU numbering related bugs
At present, the perf subcommands that do system-wide monitoring (perf stat, perf record and perf top) don't work properly unless the online cpus are numbered 0, 1, ..., N-1. These tools ask for the number of online cpus with sysconf(_SC_NPROCESSORS_ONLN) and then try to create events for cpus 0, 1, ..., N-1. This creates problems for systems where the online cpus are numbered sparsely. For example, a POWER6 system in single-threaded mode (i.e. only running 1 hardware thread per core) will have only even-numbered cpus online. This fixes the problem by reading the /sys/devices/system/cpu/online file to find out which cpus are online. The code that does that is in tools/perf/util/cpumap.[ch], and consists of a read_cpu_map() function that sets up a cpumap[] array and returns the number of online cpus. If /sys/devices/system/cpu/online can't be read or can't be parsed successfully, it falls back to using sysconf to ask how many cpus are online and sets up an identity map in cpumap[]. The perf record, perf stat and perf top code then calls read_cpu_map() in the system-wide monitoring case (instead of sysconf) and uses cpumap[] to get the cpu numbers to pass to perf_event_open. Signed-off-by: Paul Mackerras <paulus@samba.org> Cc: Anton Blanchard <anton@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> LKML-Reference: <20100310093609.GA3959@brick.ozlabs.ibm.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Showing 6 changed files with 81 additions and 13 deletions Inline Diff
tools/perf/Makefile
1 | # The default target of this Makefile is... | 1 | # The default target of this Makefile is... |
2 | all:: | 2 | all:: |
3 | 3 | ||
4 | # Define V=1 to have a more verbose compile. | 4 | # Define V=1 to have a more verbose compile. |
5 | # Define V=2 to have an even more verbose compile. | 5 | # Define V=2 to have an even more verbose compile. |
6 | # | 6 | # |
7 | # Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() | 7 | # Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() |
8 | # or vsnprintf() return -1 instead of number of characters which would | 8 | # or vsnprintf() return -1 instead of number of characters which would |
9 | # have been written to the final string if enough space had been available. | 9 | # have been written to the final string if enough space had been available. |
10 | # | 10 | # |
11 | # Define FREAD_READS_DIRECTORIES if your are on a system which succeeds | 11 | # Define FREAD_READS_DIRECTORIES if your are on a system which succeeds |
12 | # when attempting to read from an fopen'ed directory. | 12 | # when attempting to read from an fopen'ed directory. |
13 | # | 13 | # |
14 | # Define NO_OPENSSL environment variable if you do not have OpenSSL. | 14 | # Define NO_OPENSSL environment variable if you do not have OpenSSL. |
15 | # This also implies MOZILLA_SHA1. | 15 | # This also implies MOZILLA_SHA1. |
16 | # | 16 | # |
17 | # Define CURLDIR=/foo/bar if your curl header and library files are in | 17 | # Define CURLDIR=/foo/bar if your curl header and library files are in |
18 | # /foo/bar/include and /foo/bar/lib directories. | 18 | # /foo/bar/include and /foo/bar/lib directories. |
19 | # | 19 | # |
20 | # Define EXPATDIR=/foo/bar if your expat header and library files are in | 20 | # Define EXPATDIR=/foo/bar if your expat header and library files are in |
21 | # /foo/bar/include and /foo/bar/lib directories. | 21 | # /foo/bar/include and /foo/bar/lib directories. |
22 | # | 22 | # |
23 | # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent. | 23 | # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent. |
24 | # | 24 | # |
25 | # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks | 25 | # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks |
26 | # d_type in struct dirent (latest Cygwin -- will be fixed soonish). | 26 | # d_type in struct dirent (latest Cygwin -- will be fixed soonish). |
27 | # | 27 | # |
28 | # Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) | 28 | # Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) |
29 | # do not support the 'size specifiers' introduced by C99, namely ll, hh, | 29 | # do not support the 'size specifiers' introduced by C99, namely ll, hh, |
30 | # j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). | 30 | # j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). |
31 | # some C compilers supported these specifiers prior to C99 as an extension. | 31 | # some C compilers supported these specifiers prior to C99 as an extension. |
32 | # | 32 | # |
33 | # Define NO_STRCASESTR if you don't have strcasestr. | 33 | # Define NO_STRCASESTR if you don't have strcasestr. |
34 | # | 34 | # |
35 | # Define NO_MEMMEM if you don't have memmem. | 35 | # Define NO_MEMMEM if you don't have memmem. |
36 | # | 36 | # |
37 | # Define NO_STRTOUMAX if you don't have strtoumax in the C library. | 37 | # Define NO_STRTOUMAX if you don't have strtoumax in the C library. |
38 | # If your compiler also does not support long long or does not have | 38 | # If your compiler also does not support long long or does not have |
39 | # strtoull, define NO_STRTOULL. | 39 | # strtoull, define NO_STRTOULL. |
40 | # | 40 | # |
41 | # Define NO_SETENV if you don't have setenv in the C library. | 41 | # Define NO_SETENV if you don't have setenv in the C library. |
42 | # | 42 | # |
43 | # Define NO_UNSETENV if you don't have unsetenv in the C library. | 43 | # Define NO_UNSETENV if you don't have unsetenv in the C library. |
44 | # | 44 | # |
45 | # Define NO_MKDTEMP if you don't have mkdtemp in the C library. | 45 | # Define NO_MKDTEMP if you don't have mkdtemp in the C library. |
46 | # | 46 | # |
47 | # Define NO_SYS_SELECT_H if you don't have sys/select.h. | 47 | # Define NO_SYS_SELECT_H if you don't have sys/select.h. |
48 | # | 48 | # |
49 | # Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link. | 49 | # Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link. |
50 | # Enable it on Windows. By default, symrefs are still used. | 50 | # Enable it on Windows. By default, symrefs are still used. |
51 | # | 51 | # |
52 | # Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability | 52 | # Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability |
53 | # tests. These tests take up a significant amount of the total test time | 53 | # tests. These tests take up a significant amount of the total test time |
54 | # but are not needed unless you plan to talk to SVN repos. | 54 | # but are not needed unless you plan to talk to SVN repos. |
55 | # | 55 | # |
56 | # Define NO_FINK if you are building on Darwin/Mac OS X, have Fink | 56 | # Define NO_FINK if you are building on Darwin/Mac OS X, have Fink |
57 | # installed in /sw, but don't want PERF to link against any libraries | 57 | # installed in /sw, but don't want PERF to link against any libraries |
58 | # installed there. If defined you may specify your own (or Fink's) | 58 | # installed there. If defined you may specify your own (or Fink's) |
59 | # include directories and library directories by defining CFLAGS | 59 | # include directories and library directories by defining CFLAGS |
60 | # and LDFLAGS appropriately. | 60 | # and LDFLAGS appropriately. |
61 | # | 61 | # |
62 | # Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, | 62 | # Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, |
63 | # have DarwinPorts installed in /opt/local, but don't want PERF to | 63 | # have DarwinPorts installed in /opt/local, but don't want PERF to |
64 | # link against any libraries installed there. If defined you may | 64 | # link against any libraries installed there. If defined you may |
65 | # specify your own (or DarwinPort's) include directories and | 65 | # specify your own (or DarwinPort's) include directories and |
66 | # library directories by defining CFLAGS and LDFLAGS appropriately. | 66 | # library directories by defining CFLAGS and LDFLAGS appropriately. |
67 | # | 67 | # |
68 | # Define PPC_SHA1 environment variable when running make to make use of | 68 | # Define PPC_SHA1 environment variable when running make to make use of |
69 | # a bundled SHA1 routine optimized for PowerPC. | 69 | # a bundled SHA1 routine optimized for PowerPC. |
70 | # | 70 | # |
71 | # Define ARM_SHA1 environment variable when running make to make use of | 71 | # Define ARM_SHA1 environment variable when running make to make use of |
72 | # a bundled SHA1 routine optimized for ARM. | 72 | # a bundled SHA1 routine optimized for ARM. |
73 | # | 73 | # |
74 | # Define MOZILLA_SHA1 environment variable when running make to make use of | 74 | # Define MOZILLA_SHA1 environment variable when running make to make use of |
75 | # a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast | 75 | # a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast |
76 | # on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default | 76 | # on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default |
77 | # choice) has very fast version optimized for i586. | 77 | # choice) has very fast version optimized for i586. |
78 | # | 78 | # |
79 | # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). | 79 | # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). |
80 | # | 80 | # |
81 | # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). | 81 | # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). |
82 | # | 82 | # |
83 | # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, | 83 | # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, |
84 | # Patrick Mauritz). | 84 | # Patrick Mauritz). |
85 | # | 85 | # |
86 | # Define NO_MMAP if you want to avoid mmap. | 86 | # Define NO_MMAP if you want to avoid mmap. |
87 | # | 87 | # |
88 | # Define NO_PTHREADS if you do not have or do not want to use Pthreads. | 88 | # Define NO_PTHREADS if you do not have or do not want to use Pthreads. |
89 | # | 89 | # |
90 | # Define NO_PREAD if you have a problem with pread() system call (e.g. | 90 | # Define NO_PREAD if you have a problem with pread() system call (e.g. |
91 | # cygwin.dll before v1.5.22). | 91 | # cygwin.dll before v1.5.22). |
92 | # | 92 | # |
93 | # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is | 93 | # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is |
94 | # generally faster on your platform than accessing the working directory. | 94 | # generally faster on your platform than accessing the working directory. |
95 | # | 95 | # |
96 | # Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support | 96 | # Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support |
97 | # the executable mode bit, but doesn't really do so. | 97 | # the executable mode bit, but doesn't really do so. |
98 | # | 98 | # |
99 | # Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). | 99 | # Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). |
100 | # | 100 | # |
101 | # Define NO_SOCKADDR_STORAGE if your platform does not have struct | 101 | # Define NO_SOCKADDR_STORAGE if your platform does not have struct |
102 | # sockaddr_storage. | 102 | # sockaddr_storage. |
103 | # | 103 | # |
104 | # Define NO_ICONV if your libc does not properly support iconv. | 104 | # Define NO_ICONV if your libc does not properly support iconv. |
105 | # | 105 | # |
106 | # Define OLD_ICONV if your library has an old iconv(), where the second | 106 | # Define OLD_ICONV if your library has an old iconv(), where the second |
107 | # (input buffer pointer) parameter is declared with type (const char **). | 107 | # (input buffer pointer) parameter is declared with type (const char **). |
108 | # | 108 | # |
109 | # Define NO_DEFLATE_BOUND if your zlib does not have deflateBound. | 109 | # Define NO_DEFLATE_BOUND if your zlib does not have deflateBound. |
110 | # | 110 | # |
111 | # Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib" | 111 | # Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib" |
112 | # that tells runtime paths to dynamic libraries; | 112 | # that tells runtime paths to dynamic libraries; |
113 | # "-Wl,-rpath=/path/lib" is used instead. | 113 | # "-Wl,-rpath=/path/lib" is used instead. |
114 | # | 114 | # |
115 | # Define USE_NSEC below if you want perf to care about sub-second file mtimes | 115 | # Define USE_NSEC below if you want perf to care about sub-second file mtimes |
116 | # and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and | 116 | # and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and |
117 | # it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely | 117 | # it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely |
118 | # randomly break unless your underlying filesystem supports those sub-second | 118 | # randomly break unless your underlying filesystem supports those sub-second |
119 | # times (my ext3 doesn't). | 119 | # times (my ext3 doesn't). |
120 | # | 120 | # |
121 | # Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of | 121 | # Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of |
122 | # "st_ctim" | 122 | # "st_ctim" |
123 | # | 123 | # |
124 | # Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" | 124 | # Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" |
125 | # available. This automatically turns USE_NSEC off. | 125 | # available. This automatically turns USE_NSEC off. |
126 | # | 126 | # |
127 | # Define USE_STDEV below if you want perf to care about the underlying device | 127 | # Define USE_STDEV below if you want perf to care about the underlying device |
128 | # change being considered an inode change from the update-index perspective. | 128 | # change being considered an inode change from the update-index perspective. |
129 | # | 129 | # |
130 | # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks | 130 | # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks |
131 | # field that counts the on-disk footprint in 512-byte blocks. | 131 | # field that counts the on-disk footprint in 512-byte blocks. |
132 | # | 132 | # |
133 | # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 | 133 | # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 |
134 | # | 134 | # |
135 | # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. | 135 | # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. |
136 | # | 136 | # |
137 | # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's | 137 | # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's |
138 | # MakeMaker (e.g. using ActiveState under Cygwin). | 138 | # MakeMaker (e.g. using ActiveState under Cygwin). |
139 | # | 139 | # |
140 | # Define NO_PERL if you do not want Perl scripts or libraries at all. | 140 | # Define NO_PERL if you do not want Perl scripts or libraries at all. |
141 | # | 141 | # |
142 | # Define INTERNAL_QSORT to use Git's implementation of qsort(), which | 142 | # Define INTERNAL_QSORT to use Git's implementation of qsort(), which |
143 | # is a simplified version of the merge sort used in glibc. This is | 143 | # is a simplified version of the merge sort used in glibc. This is |
144 | # recommended if Git triggers O(n^2) behavior in your platform's qsort(). | 144 | # recommended if Git triggers O(n^2) behavior in your platform's qsort(). |
145 | # | 145 | # |
146 | # Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call | 146 | # Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call |
147 | # your external grep (e.g., if your system lacks grep, if its grep is | 147 | # your external grep (e.g., if your system lacks grep, if its grep is |
148 | # broken, or spawning external process is slower than built-in grep perf has). | 148 | # broken, or spawning external process is slower than built-in grep perf has). |
149 | # | 149 | # |
150 | # Define LDFLAGS=-static to build a static binary. | 150 | # Define LDFLAGS=-static to build a static binary. |
151 | # | 151 | # |
152 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. | 152 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. |
153 | 153 | ||
154 | PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 154 | PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
155 | @$(SHELL_PATH) util/PERF-VERSION-GEN | 155 | @$(SHELL_PATH) util/PERF-VERSION-GEN |
156 | -include PERF-VERSION-FILE | 156 | -include PERF-VERSION-FILE |
157 | 157 | ||
158 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') | 158 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') |
159 | uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not') | 159 | uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not') |
160 | uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') | 160 | uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') |
161 | uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') | 161 | uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') |
162 | uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') | 162 | uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') |
163 | uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') | 163 | uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') |
164 | 164 | ||
165 | # CFLAGS and LDFLAGS are for the users to override from the command line. | 165 | # CFLAGS and LDFLAGS are for the users to override from the command line. |
166 | 166 | ||
167 | # | 167 | # |
168 | # Include saner warnings here, which can catch bugs: | 168 | # Include saner warnings here, which can catch bugs: |
169 | # | 169 | # |
170 | 170 | ||
171 | EXTRA_WARNINGS := -Wformat | 171 | EXTRA_WARNINGS := -Wformat |
172 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security | 172 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security |
173 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k | 173 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k |
174 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow | 174 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow |
175 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self | 175 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self |
176 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked | 176 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked |
177 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls | 177 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls |
178 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector | 178 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector |
179 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3 | 179 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3 |
180 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default | 180 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default |
181 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum | 181 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum |
182 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers | 182 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers |
183 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef | 183 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef |
184 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var | 184 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var |
185 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings | 185 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings |
186 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast | 186 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast |
187 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations | 187 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations |
188 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes | 188 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes |
189 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs | 189 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs |
190 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition | 190 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition |
191 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes | 191 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes |
192 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement | 192 | EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement |
193 | 193 | ||
194 | ifeq ("$(origin DEBUG)", "command line") | 194 | ifeq ("$(origin DEBUG)", "command line") |
195 | PERF_DEBUG = $(DEBUG) | 195 | PERF_DEBUG = $(DEBUG) |
196 | endif | 196 | endif |
197 | ifndef PERF_DEBUG | 197 | ifndef PERF_DEBUG |
198 | CFLAGS_OPTIMIZE = -O6 | 198 | CFLAGS_OPTIMIZE = -O6 |
199 | endif | 199 | endif |
200 | 200 | ||
201 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) | 201 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) |
202 | EXTLIBS = -lpthread -lrt -lelf -lm | 202 | EXTLIBS = -lpthread -lrt -lelf -lm |
203 | ALL_CFLAGS = $(CFLAGS) | 203 | ALL_CFLAGS = $(CFLAGS) |
204 | ALL_LDFLAGS = $(LDFLAGS) | 204 | ALL_LDFLAGS = $(LDFLAGS) |
205 | STRIP ?= strip | 205 | STRIP ?= strip |
206 | 206 | ||
207 | # Among the variables below, these: | 207 | # Among the variables below, these: |
208 | # perfexecdir | 208 | # perfexecdir |
209 | # template_dir | 209 | # template_dir |
210 | # mandir | 210 | # mandir |
211 | # infodir | 211 | # infodir |
212 | # htmldir | 212 | # htmldir |
213 | # ETC_PERFCONFIG (but not sysconfdir) | 213 | # ETC_PERFCONFIG (but not sysconfdir) |
214 | # can be specified as a relative path some/where/else; | 214 | # can be specified as a relative path some/where/else; |
215 | # this is interpreted as relative to $(prefix) and "perf" at | 215 | # this is interpreted as relative to $(prefix) and "perf" at |
216 | # runtime figures out where they are based on the path to the executable. | 216 | # runtime figures out where they are based on the path to the executable. |
217 | # This can help installing the suite in a relocatable way. | 217 | # This can help installing the suite in a relocatable way. |
218 | 218 | ||
219 | prefix = $(HOME) | 219 | prefix = $(HOME) |
220 | bindir_relative = bin | 220 | bindir_relative = bin |
221 | bindir = $(prefix)/$(bindir_relative) | 221 | bindir = $(prefix)/$(bindir_relative) |
222 | mandir = share/man | 222 | mandir = share/man |
223 | infodir = share/info | 223 | infodir = share/info |
224 | perfexecdir = libexec/perf-core | 224 | perfexecdir = libexec/perf-core |
225 | sharedir = $(prefix)/share | 225 | sharedir = $(prefix)/share |
226 | template_dir = share/perf-core/templates | 226 | template_dir = share/perf-core/templates |
227 | htmldir = share/doc/perf-doc | 227 | htmldir = share/doc/perf-doc |
228 | ifeq ($(prefix),/usr) | 228 | ifeq ($(prefix),/usr) |
229 | sysconfdir = /etc | 229 | sysconfdir = /etc |
230 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig | 230 | ETC_PERFCONFIG = $(sysconfdir)/perfconfig |
231 | else | 231 | else |
232 | sysconfdir = $(prefix)/etc | 232 | sysconfdir = $(prefix)/etc |
233 | ETC_PERFCONFIG = etc/perfconfig | 233 | ETC_PERFCONFIG = etc/perfconfig |
234 | endif | 234 | endif |
235 | lib = lib | 235 | lib = lib |
236 | # DESTDIR= | 236 | # DESTDIR= |
237 | 237 | ||
238 | export prefix bindir sharedir sysconfdir | 238 | export prefix bindir sharedir sysconfdir |
239 | 239 | ||
240 | CC = $(CROSS_COMPILE)gcc | 240 | CC = $(CROSS_COMPILE)gcc |
241 | AR = $(CROSS_COMPILE)ar | 241 | AR = $(CROSS_COMPILE)ar |
242 | RM = rm -f | 242 | RM = rm -f |
243 | TAR = tar | 243 | TAR = tar |
244 | FIND = find | 244 | FIND = find |
245 | INSTALL = install | 245 | INSTALL = install |
246 | RPMBUILD = rpmbuild | 246 | RPMBUILD = rpmbuild |
247 | PTHREAD_LIBS = -lpthread | 247 | PTHREAD_LIBS = -lpthread |
248 | 248 | ||
249 | # sparse is architecture-neutral, which means that we need to tell it | 249 | # sparse is architecture-neutral, which means that we need to tell it |
250 | # explicitly what architecture to check for. Fix this up for yours.. | 250 | # explicitly what architecture to check for. Fix this up for yours.. |
251 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ | 251 | SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ |
252 | 252 | ||
253 | ifeq ($(V), 2) | 253 | ifeq ($(V), 2) |
254 | QUIET_STDERR = ">/dev/null" | 254 | QUIET_STDERR = ">/dev/null" |
255 | else | 255 | else |
256 | QUIET_STDERR = ">/dev/null 2>&1" | 256 | QUIET_STDERR = ">/dev/null 2>&1" |
257 | endif | 257 | endif |
258 | 258 | ||
259 | BITBUCKET = "/dev/null" | 259 | BITBUCKET = "/dev/null" |
260 | 260 | ||
261 | ifneq ($(shell sh -c "(echo '\#include <stdio.h>'; echo 'int main(void) { return puts(\"hi\"); }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y) | 261 | ifneq ($(shell sh -c "(echo '\#include <stdio.h>'; echo 'int main(void) { return puts(\"hi\"); }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y) |
262 | BITBUCKET = .perf.dev.null | 262 | BITBUCKET = .perf.dev.null |
263 | endif | 263 | endif |
264 | 264 | ||
265 | ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y) | 265 | ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y) |
266 | CFLAGS := $(CFLAGS) -fstack-protector-all | 266 | CFLAGS := $(CFLAGS) -fstack-protector-all |
267 | endif | 267 | endif |
268 | 268 | ||
269 | 269 | ||
270 | ### --- END CONFIGURATION SECTION --- | 270 | ### --- END CONFIGURATION SECTION --- |
271 | 271 | ||
272 | # Those must not be GNU-specific; they are shared with perl/ which may | 272 | # Those must not be GNU-specific; they are shared with perl/ which may |
273 | # be built by a different compiler. (Note that this is an artifact now | 273 | # be built by a different compiler. (Note that this is an artifact now |
274 | # but it still might be nice to keep that distinction.) | 274 | # but it still might be nice to keep that distinction.) |
275 | BASIC_CFLAGS = -Iutil/include | 275 | BASIC_CFLAGS = -Iutil/include |
276 | BASIC_LDFLAGS = | 276 | BASIC_LDFLAGS = |
277 | 277 | ||
278 | # Guard against environment variables | 278 | # Guard against environment variables |
279 | BUILTIN_OBJS = | 279 | BUILTIN_OBJS = |
280 | BUILT_INS = | 280 | BUILT_INS = |
281 | COMPAT_CFLAGS = | 281 | COMPAT_CFLAGS = |
282 | COMPAT_OBJS = | 282 | COMPAT_OBJS = |
283 | LIB_H = | 283 | LIB_H = |
284 | LIB_OBJS = | 284 | LIB_OBJS = |
285 | SCRIPT_PERL = | 285 | SCRIPT_PERL = |
286 | SCRIPT_SH = | 286 | SCRIPT_SH = |
287 | TEST_PROGRAMS = | 287 | TEST_PROGRAMS = |
288 | 288 | ||
289 | SCRIPT_SH += perf-archive.sh | 289 | SCRIPT_SH += perf-archive.sh |
290 | 290 | ||
291 | # | 291 | # |
292 | # No Perl scripts right now: | 292 | # No Perl scripts right now: |
293 | # | 293 | # |
294 | 294 | ||
295 | # SCRIPT_PERL += perf-add--interactive.perl | 295 | # SCRIPT_PERL += perf-add--interactive.perl |
296 | 296 | ||
297 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ | 297 | SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ |
298 | $(patsubst %.perl,%,$(SCRIPT_PERL)) | 298 | $(patsubst %.perl,%,$(SCRIPT_PERL)) |
299 | 299 | ||
300 | # Empty... | 300 | # Empty... |
301 | EXTRA_PROGRAMS = | 301 | EXTRA_PROGRAMS = |
302 | 302 | ||
303 | # ... and all the rest that could be moved out of bindir to perfexecdir | 303 | # ... and all the rest that could be moved out of bindir to perfexecdir |
304 | PROGRAMS += $(EXTRA_PROGRAMS) | 304 | PROGRAMS += $(EXTRA_PROGRAMS) |
305 | 305 | ||
306 | # | 306 | # |
307 | # Single 'perf' binary right now: | 307 | # Single 'perf' binary right now: |
308 | # | 308 | # |
309 | PROGRAMS += perf | 309 | PROGRAMS += perf |
310 | 310 | ||
311 | # List built-in command $C whose implementation cmd_$C() is not in | 311 | # List built-in command $C whose implementation cmd_$C() is not in |
312 | # builtin-$C.o but is linked in as part of some other command. | 312 | # builtin-$C.o but is linked in as part of some other command. |
313 | # | 313 | # |
314 | 314 | ||
315 | # what 'all' will build and 'install' will install, in perfexecdir | 315 | # what 'all' will build and 'install' will install, in perfexecdir |
316 | ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) | 316 | ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) |
317 | 317 | ||
318 | # what 'all' will build but not install in perfexecdir | 318 | # what 'all' will build but not install in perfexecdir |
319 | OTHER_PROGRAMS = perf$X | 319 | OTHER_PROGRAMS = perf$X |
320 | 320 | ||
321 | # Set paths to tools early so that they can be used for version tests. | 321 | # Set paths to tools early so that they can be used for version tests. |
322 | ifndef SHELL_PATH | 322 | ifndef SHELL_PATH |
323 | SHELL_PATH = /bin/sh | 323 | SHELL_PATH = /bin/sh |
324 | endif | 324 | endif |
325 | ifndef PERL_PATH | 325 | ifndef PERL_PATH |
326 | PERL_PATH = /usr/bin/perl | 326 | PERL_PATH = /usr/bin/perl |
327 | endif | 327 | endif |
328 | 328 | ||
329 | export PERL_PATH | 329 | export PERL_PATH |
330 | 330 | ||
331 | LIB_FILE=libperf.a | 331 | LIB_FILE=libperf.a |
332 | 332 | ||
333 | LIB_H += ../../include/linux/perf_event.h | 333 | LIB_H += ../../include/linux/perf_event.h |
334 | LIB_H += ../../include/linux/rbtree.h | 334 | LIB_H += ../../include/linux/rbtree.h |
335 | LIB_H += ../../include/linux/list.h | 335 | LIB_H += ../../include/linux/list.h |
336 | LIB_H += ../../include/linux/hash.h | 336 | LIB_H += ../../include/linux/hash.h |
337 | LIB_H += ../../include/linux/stringify.h | 337 | LIB_H += ../../include/linux/stringify.h |
338 | LIB_H += util/include/linux/bitmap.h | 338 | LIB_H += util/include/linux/bitmap.h |
339 | LIB_H += util/include/linux/bitops.h | 339 | LIB_H += util/include/linux/bitops.h |
340 | LIB_H += util/include/linux/compiler.h | 340 | LIB_H += util/include/linux/compiler.h |
341 | LIB_H += util/include/linux/ctype.h | 341 | LIB_H += util/include/linux/ctype.h |
342 | LIB_H += util/include/linux/kernel.h | 342 | LIB_H += util/include/linux/kernel.h |
343 | LIB_H += util/include/linux/list.h | 343 | LIB_H += util/include/linux/list.h |
344 | LIB_H += util/include/linux/module.h | 344 | LIB_H += util/include/linux/module.h |
345 | LIB_H += util/include/linux/poison.h | 345 | LIB_H += util/include/linux/poison.h |
346 | LIB_H += util/include/linux/prefetch.h | 346 | LIB_H += util/include/linux/prefetch.h |
347 | LIB_H += util/include/linux/rbtree.h | 347 | LIB_H += util/include/linux/rbtree.h |
348 | LIB_H += util/include/linux/string.h | 348 | LIB_H += util/include/linux/string.h |
349 | LIB_H += util/include/linux/types.h | 349 | LIB_H += util/include/linux/types.h |
350 | LIB_H += util/include/asm/asm-offsets.h | 350 | LIB_H += util/include/asm/asm-offsets.h |
351 | LIB_H += util/include/asm/bitops.h | 351 | LIB_H += util/include/asm/bitops.h |
352 | LIB_H += util/include/asm/bug.h | 352 | LIB_H += util/include/asm/bug.h |
353 | LIB_H += util/include/asm/byteorder.h | 353 | LIB_H += util/include/asm/byteorder.h |
354 | LIB_H += util/include/asm/swab.h | 354 | LIB_H += util/include/asm/swab.h |
355 | LIB_H += util/include/asm/system.h | 355 | LIB_H += util/include/asm/system.h |
356 | LIB_H += util/include/asm/uaccess.h | 356 | LIB_H += util/include/asm/uaccess.h |
357 | LIB_H += perf.h | 357 | LIB_H += perf.h |
358 | LIB_H += util/cache.h | 358 | LIB_H += util/cache.h |
359 | LIB_H += util/callchain.h | 359 | LIB_H += util/callchain.h |
360 | LIB_H += util/build-id.h | 360 | LIB_H += util/build-id.h |
361 | LIB_H += util/debug.h | 361 | LIB_H += util/debug.h |
362 | LIB_H += util/debugfs.h | 362 | LIB_H += util/debugfs.h |
363 | LIB_H += util/event.h | 363 | LIB_H += util/event.h |
364 | LIB_H += util/exec_cmd.h | 364 | LIB_H += util/exec_cmd.h |
365 | LIB_H += util/types.h | 365 | LIB_H += util/types.h |
366 | LIB_H += util/levenshtein.h | 366 | LIB_H += util/levenshtein.h |
367 | LIB_H += util/map.h | 367 | LIB_H += util/map.h |
368 | LIB_H += util/parse-options.h | 368 | LIB_H += util/parse-options.h |
369 | LIB_H += util/parse-events.h | 369 | LIB_H += util/parse-events.h |
370 | LIB_H += util/quote.h | 370 | LIB_H += util/quote.h |
371 | LIB_H += util/util.h | 371 | LIB_H += util/util.h |
372 | LIB_H += util/header.h | 372 | LIB_H += util/header.h |
373 | LIB_H += util/help.h | 373 | LIB_H += util/help.h |
374 | LIB_H += util/session.h | 374 | LIB_H += util/session.h |
375 | LIB_H += util/strbuf.h | 375 | LIB_H += util/strbuf.h |
376 | LIB_H += util/string.h | 376 | LIB_H += util/string.h |
377 | LIB_H += util/strlist.h | 377 | LIB_H += util/strlist.h |
378 | LIB_H += util/svghelper.h | 378 | LIB_H += util/svghelper.h |
379 | LIB_H += util/run-command.h | 379 | LIB_H += util/run-command.h |
380 | LIB_H += util/sigchain.h | 380 | LIB_H += util/sigchain.h |
381 | LIB_H += util/symbol.h | 381 | LIB_H += util/symbol.h |
382 | LIB_H += util/color.h | 382 | LIB_H += util/color.h |
383 | LIB_H += util/values.h | 383 | LIB_H += util/values.h |
384 | LIB_H += util/sort.h | 384 | LIB_H += util/sort.h |
385 | LIB_H += util/hist.h | 385 | LIB_H += util/hist.h |
386 | LIB_H += util/thread.h | 386 | LIB_H += util/thread.h |
387 | LIB_H += util/trace-event.h | 387 | LIB_H += util/trace-event.h |
388 | LIB_H += util/probe-finder.h | 388 | LIB_H += util/probe-finder.h |
389 | LIB_H += util/probe-event.h | 389 | LIB_H += util/probe-event.h |
390 | LIB_H += util/cpumap.h | ||
390 | 391 | ||
391 | LIB_OBJS += util/abspath.o | 392 | LIB_OBJS += util/abspath.o |
392 | LIB_OBJS += util/alias.o | 393 | LIB_OBJS += util/alias.o |
393 | LIB_OBJS += util/build-id.o | 394 | LIB_OBJS += util/build-id.o |
394 | LIB_OBJS += util/config.o | 395 | LIB_OBJS += util/config.o |
395 | LIB_OBJS += util/ctype.o | 396 | LIB_OBJS += util/ctype.o |
396 | LIB_OBJS += util/debugfs.o | 397 | LIB_OBJS += util/debugfs.o |
397 | LIB_OBJS += util/environment.o | 398 | LIB_OBJS += util/environment.o |
398 | LIB_OBJS += util/event.o | 399 | LIB_OBJS += util/event.o |
399 | LIB_OBJS += util/exec_cmd.o | 400 | LIB_OBJS += util/exec_cmd.o |
400 | LIB_OBJS += util/help.o | 401 | LIB_OBJS += util/help.o |
401 | LIB_OBJS += util/levenshtein.o | 402 | LIB_OBJS += util/levenshtein.o |
402 | LIB_OBJS += util/parse-options.o | 403 | LIB_OBJS += util/parse-options.o |
403 | LIB_OBJS += util/parse-events.o | 404 | LIB_OBJS += util/parse-events.o |
404 | LIB_OBJS += util/path.o | 405 | LIB_OBJS += util/path.o |
405 | LIB_OBJS += util/rbtree.o | 406 | LIB_OBJS += util/rbtree.o |
406 | LIB_OBJS += util/bitmap.o | 407 | LIB_OBJS += util/bitmap.o |
407 | LIB_OBJS += util/hweight.o | 408 | LIB_OBJS += util/hweight.o |
408 | LIB_OBJS += util/find_next_bit.o | 409 | LIB_OBJS += util/find_next_bit.o |
409 | LIB_OBJS += util/run-command.o | 410 | LIB_OBJS += util/run-command.o |
410 | LIB_OBJS += util/quote.o | 411 | LIB_OBJS += util/quote.o |
411 | LIB_OBJS += util/strbuf.o | 412 | LIB_OBJS += util/strbuf.o |
412 | LIB_OBJS += util/string.o | 413 | LIB_OBJS += util/string.o |
413 | LIB_OBJS += util/strlist.o | 414 | LIB_OBJS += util/strlist.o |
414 | LIB_OBJS += util/usage.o | 415 | LIB_OBJS += util/usage.o |
415 | LIB_OBJS += util/wrapper.o | 416 | LIB_OBJS += util/wrapper.o |
416 | LIB_OBJS += util/sigchain.o | 417 | LIB_OBJS += util/sigchain.o |
417 | LIB_OBJS += util/symbol.o | 418 | LIB_OBJS += util/symbol.o |
418 | LIB_OBJS += util/color.o | 419 | LIB_OBJS += util/color.o |
419 | LIB_OBJS += util/pager.o | 420 | LIB_OBJS += util/pager.o |
420 | LIB_OBJS += util/header.o | 421 | LIB_OBJS += util/header.o |
421 | LIB_OBJS += util/callchain.o | 422 | LIB_OBJS += util/callchain.o |
422 | LIB_OBJS += util/values.o | 423 | LIB_OBJS += util/values.o |
423 | LIB_OBJS += util/debug.o | 424 | LIB_OBJS += util/debug.o |
424 | LIB_OBJS += util/map.o | 425 | LIB_OBJS += util/map.o |
425 | LIB_OBJS += util/session.o | 426 | LIB_OBJS += util/session.o |
426 | LIB_OBJS += util/thread.o | 427 | LIB_OBJS += util/thread.o |
427 | LIB_OBJS += util/trace-event-parse.o | 428 | LIB_OBJS += util/trace-event-parse.o |
428 | LIB_OBJS += util/trace-event-read.o | 429 | LIB_OBJS += util/trace-event-read.o |
429 | LIB_OBJS += util/trace-event-info.o | 430 | LIB_OBJS += util/trace-event-info.o |
430 | LIB_OBJS += util/trace-event-scripting.o | 431 | LIB_OBJS += util/trace-event-scripting.o |
431 | LIB_OBJS += util/svghelper.o | 432 | LIB_OBJS += util/svghelper.o |
432 | LIB_OBJS += util/sort.o | 433 | LIB_OBJS += util/sort.o |
433 | LIB_OBJS += util/hist.o | 434 | LIB_OBJS += util/hist.o |
434 | LIB_OBJS += util/probe-event.o | 435 | LIB_OBJS += util/probe-event.o |
435 | LIB_OBJS += util/util.o | 436 | LIB_OBJS += util/util.o |
437 | LIB_OBJS += util/cpumap.o | ||
436 | 438 | ||
437 | BUILTIN_OBJS += builtin-annotate.o | 439 | BUILTIN_OBJS += builtin-annotate.o |
438 | 440 | ||
439 | BUILTIN_OBJS += builtin-bench.o | 441 | BUILTIN_OBJS += builtin-bench.o |
440 | 442 | ||
441 | # Benchmark modules | 443 | # Benchmark modules |
442 | BUILTIN_OBJS += bench/sched-messaging.o | 444 | BUILTIN_OBJS += bench/sched-messaging.o |
443 | BUILTIN_OBJS += bench/sched-pipe.o | 445 | BUILTIN_OBJS += bench/sched-pipe.o |
444 | BUILTIN_OBJS += bench/mem-memcpy.o | 446 | BUILTIN_OBJS += bench/mem-memcpy.o |
445 | 447 | ||
446 | BUILTIN_OBJS += builtin-diff.o | 448 | BUILTIN_OBJS += builtin-diff.o |
447 | BUILTIN_OBJS += builtin-help.o | 449 | BUILTIN_OBJS += builtin-help.o |
448 | BUILTIN_OBJS += builtin-sched.o | 450 | BUILTIN_OBJS += builtin-sched.o |
449 | BUILTIN_OBJS += builtin-buildid-list.o | 451 | BUILTIN_OBJS += builtin-buildid-list.o |
450 | BUILTIN_OBJS += builtin-buildid-cache.o | 452 | BUILTIN_OBJS += builtin-buildid-cache.o |
451 | BUILTIN_OBJS += builtin-list.o | 453 | BUILTIN_OBJS += builtin-list.o |
452 | BUILTIN_OBJS += builtin-record.o | 454 | BUILTIN_OBJS += builtin-record.o |
453 | BUILTIN_OBJS += builtin-report.o | 455 | BUILTIN_OBJS += builtin-report.o |
454 | BUILTIN_OBJS += builtin-stat.o | 456 | BUILTIN_OBJS += builtin-stat.o |
455 | BUILTIN_OBJS += builtin-timechart.o | 457 | BUILTIN_OBJS += builtin-timechart.o |
456 | BUILTIN_OBJS += builtin-top.o | 458 | BUILTIN_OBJS += builtin-top.o |
457 | BUILTIN_OBJS += builtin-trace.o | 459 | BUILTIN_OBJS += builtin-trace.o |
458 | BUILTIN_OBJS += builtin-probe.o | 460 | BUILTIN_OBJS += builtin-probe.o |
459 | BUILTIN_OBJS += builtin-kmem.o | 461 | BUILTIN_OBJS += builtin-kmem.o |
460 | BUILTIN_OBJS += builtin-lock.o | 462 | BUILTIN_OBJS += builtin-lock.o |
461 | 463 | ||
462 | PERFLIBS = $(LIB_FILE) | 464 | PERFLIBS = $(LIB_FILE) |
463 | 465 | ||
464 | # | 466 | # |
465 | # Platform specific tweaks | 467 | # Platform specific tweaks |
466 | # | 468 | # |
467 | 469 | ||
468 | # We choose to avoid "if .. else if .. else .. endif endif" | 470 | # We choose to avoid "if .. else if .. else .. endif endif" |
469 | # because maintaining the nesting to match is a pain. If | 471 | # because maintaining the nesting to match is a pain. If |
470 | # we had "elif" things would have been much nicer... | 472 | # we had "elif" things would have been much nicer... |
471 | 473 | ||
472 | -include config.mak.autogen | 474 | -include config.mak.autogen |
473 | -include config.mak | 475 | -include config.mak |
474 | 476 | ||
475 | ifeq ($(uname_S),Darwin) | 477 | ifeq ($(uname_S),Darwin) |
476 | ifndef NO_FINK | 478 | ifndef NO_FINK |
477 | ifeq ($(shell test -d /sw/lib && echo y),y) | 479 | ifeq ($(shell test -d /sw/lib && echo y),y) |
478 | BASIC_CFLAGS += -I/sw/include | 480 | BASIC_CFLAGS += -I/sw/include |
479 | BASIC_LDFLAGS += -L/sw/lib | 481 | BASIC_LDFLAGS += -L/sw/lib |
480 | endif | 482 | endif |
481 | endif | 483 | endif |
482 | ifndef NO_DARWIN_PORTS | 484 | ifndef NO_DARWIN_PORTS |
483 | ifeq ($(shell test -d /opt/local/lib && echo y),y) | 485 | ifeq ($(shell test -d /opt/local/lib && echo y),y) |
484 | BASIC_CFLAGS += -I/opt/local/include | 486 | BASIC_CFLAGS += -I/opt/local/include |
485 | BASIC_LDFLAGS += -L/opt/local/lib | 487 | BASIC_LDFLAGS += -L/opt/local/lib |
486 | endif | 488 | endif |
487 | endif | 489 | endif |
488 | PTHREAD_LIBS = | 490 | PTHREAD_LIBS = |
489 | endif | 491 | endif |
490 | 492 | ||
491 | ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 493 | ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
492 | ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 494 | ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
493 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); | 495 | msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); |
494 | endif | 496 | endif |
495 | 497 | ||
496 | ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 498 | ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
497 | BASIC_CFLAGS += -DLIBELF_NO_MMAP | 499 | BASIC_CFLAGS += -DLIBELF_NO_MMAP |
498 | endif | 500 | endif |
499 | else | 501 | else |
500 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); | 502 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); |
501 | endif | 503 | endif |
502 | 504 | ||
503 | ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 505 | ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
504 | msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); | 506 | msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); |
505 | BASIC_CFLAGS += -DNO_DWARF_SUPPORT | 507 | BASIC_CFLAGS += -DNO_DWARF_SUPPORT |
506 | else | 508 | else |
507 | BASIC_CFLAGS += -I/usr/include/elfutils | 509 | BASIC_CFLAGS += -I/usr/include/elfutils |
508 | EXTLIBS += -lelf -ldw | 510 | EXTLIBS += -lelf -ldw |
509 | LIB_OBJS += util/probe-finder.o | 511 | LIB_OBJS += util/probe-finder.o |
510 | endif | 512 | endif |
511 | 513 | ||
512 | ifndef NO_LIBPERL | 514 | ifndef NO_LIBPERL |
513 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` | 515 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` |
514 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | 516 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` |
515 | endif | 517 | endif |
516 | 518 | ||
517 | ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o $(BITBUCKET) $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) | 519 | ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o $(BITBUCKET) $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) |
518 | BASIC_CFLAGS += -DNO_LIBPERL | 520 | BASIC_CFLAGS += -DNO_LIBPERL |
519 | else | 521 | else |
520 | ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) | 522 | ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) |
521 | LIB_OBJS += util/scripting-engines/trace-event-perl.o | 523 | LIB_OBJS += util/scripting-engines/trace-event-perl.o |
522 | LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o | 524 | LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o |
523 | endif | 525 | endif |
524 | 526 | ||
525 | ifndef NO_LIBPYTHON | 527 | ifndef NO_LIBPYTHON |
526 | PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null` | 528 | PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null` |
527 | PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` | 529 | PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` |
528 | endif | 530 | endif |
529 | 531 | ||
530 | ifneq ($(shell sh -c "(echo '\#include <Python.h>'; echo 'int main(void) { Py_Initialize(); return 0; }') | $(CC) -x c - $(PYTHON_EMBED_CCOPTS) -o /dev/null $(PYTHON_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) | 532 | ifneq ($(shell sh -c "(echo '\#include <Python.h>'; echo 'int main(void) { Py_Initialize(); return 0; }') | $(CC) -x c - $(PYTHON_EMBED_CCOPTS) -o /dev/null $(PYTHON_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) |
531 | BASIC_CFLAGS += -DNO_LIBPYTHON | 533 | BASIC_CFLAGS += -DNO_LIBPYTHON |
532 | else | 534 | else |
533 | ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS) | 535 | ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS) |
534 | LIB_OBJS += util/scripting-engines/trace-event-python.o | 536 | LIB_OBJS += util/scripting-engines/trace-event-python.o |
535 | LIB_OBJS += scripts/python/Perf-Trace-Util/Context.o | 537 | LIB_OBJS += scripts/python/Perf-Trace-Util/Context.o |
536 | endif | 538 | endif |
537 | 539 | ||
538 | ifdef NO_DEMANGLE | 540 | ifdef NO_DEMANGLE |
539 | BASIC_CFLAGS += -DNO_DEMANGLE | 541 | BASIC_CFLAGS += -DNO_DEMANGLE |
540 | else | 542 | else |
541 | has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y") | 543 | has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y") |
542 | 544 | ||
543 | ifeq ($(has_bfd),y) | 545 | ifeq ($(has_bfd),y) |
544 | EXTLIBS += -lbfd | 546 | EXTLIBS += -lbfd |
545 | else | 547 | else |
546 | has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y") | 548 | has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y") |
547 | ifeq ($(has_bfd_iberty),y) | 549 | ifeq ($(has_bfd_iberty),y) |
548 | EXTLIBS += -lbfd -liberty | 550 | EXTLIBS += -lbfd -liberty |
549 | else | 551 | else |
550 | has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y") | 552 | has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y") |
551 | ifeq ($(has_bfd_iberty_z),y) | 553 | ifeq ($(has_bfd_iberty_z),y) |
552 | EXTLIBS += -lbfd -liberty -lz | 554 | EXTLIBS += -lbfd -liberty -lz |
553 | else | 555 | else |
554 | has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y") | 556 | has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y") |
555 | ifeq ($(has_cplus_demangle),y) | 557 | ifeq ($(has_cplus_demangle),y) |
556 | EXTLIBS += -liberty | 558 | EXTLIBS += -liberty |
557 | BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE | 559 | BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE |
558 | else | 560 | else |
559 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) | 561 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) |
560 | BASIC_CFLAGS += -DNO_DEMANGLE | 562 | BASIC_CFLAGS += -DNO_DEMANGLE |
561 | endif | 563 | endif |
562 | endif | 564 | endif |
563 | endif | 565 | endif |
564 | endif | 566 | endif |
565 | endif | 567 | endif |
566 | 568 | ||
567 | ifndef CC_LD_DYNPATH | 569 | ifndef CC_LD_DYNPATH |
568 | ifdef NO_R_TO_GCC_LINKER | 570 | ifdef NO_R_TO_GCC_LINKER |
569 | # Some gcc does not accept and pass -R to the linker to specify | 571 | # Some gcc does not accept and pass -R to the linker to specify |
570 | # the runtime dynamic library path. | 572 | # the runtime dynamic library path. |
571 | CC_LD_DYNPATH = -Wl,-rpath, | 573 | CC_LD_DYNPATH = -Wl,-rpath, |
572 | else | 574 | else |
573 | CC_LD_DYNPATH = -R | 575 | CC_LD_DYNPATH = -R |
574 | endif | 576 | endif |
575 | endif | 577 | endif |
576 | 578 | ||
577 | ifdef NEEDS_SOCKET | 579 | ifdef NEEDS_SOCKET |
578 | EXTLIBS += -lsocket | 580 | EXTLIBS += -lsocket |
579 | endif | 581 | endif |
580 | ifdef NEEDS_NSL | 582 | ifdef NEEDS_NSL |
581 | EXTLIBS += -lnsl | 583 | EXTLIBS += -lnsl |
582 | endif | 584 | endif |
583 | ifdef NO_D_TYPE_IN_DIRENT | 585 | ifdef NO_D_TYPE_IN_DIRENT |
584 | BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT | 586 | BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT |
585 | endif | 587 | endif |
586 | ifdef NO_D_INO_IN_DIRENT | 588 | ifdef NO_D_INO_IN_DIRENT |
587 | BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT | 589 | BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT |
588 | endif | 590 | endif |
589 | ifdef NO_ST_BLOCKS_IN_STRUCT_STAT | 591 | ifdef NO_ST_BLOCKS_IN_STRUCT_STAT |
590 | BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT | 592 | BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT |
591 | endif | 593 | endif |
592 | ifdef USE_NSEC | 594 | ifdef USE_NSEC |
593 | BASIC_CFLAGS += -DUSE_NSEC | 595 | BASIC_CFLAGS += -DUSE_NSEC |
594 | endif | 596 | endif |
595 | ifdef USE_ST_TIMESPEC | 597 | ifdef USE_ST_TIMESPEC |
596 | BASIC_CFLAGS += -DUSE_ST_TIMESPEC | 598 | BASIC_CFLAGS += -DUSE_ST_TIMESPEC |
597 | endif | 599 | endif |
598 | ifdef NO_NSEC | 600 | ifdef NO_NSEC |
599 | BASIC_CFLAGS += -DNO_NSEC | 601 | BASIC_CFLAGS += -DNO_NSEC |
600 | endif | 602 | endif |
601 | ifdef NO_C99_FORMAT | 603 | ifdef NO_C99_FORMAT |
602 | BASIC_CFLAGS += -DNO_C99_FORMAT | 604 | BASIC_CFLAGS += -DNO_C99_FORMAT |
603 | endif | 605 | endif |
604 | ifdef SNPRINTF_RETURNS_BOGUS | 606 | ifdef SNPRINTF_RETURNS_BOGUS |
605 | COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS | 607 | COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS |
606 | COMPAT_OBJS += compat/snprintf.o | 608 | COMPAT_OBJS += compat/snprintf.o |
607 | endif | 609 | endif |
608 | ifdef FREAD_READS_DIRECTORIES | 610 | ifdef FREAD_READS_DIRECTORIES |
609 | COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES | 611 | COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES |
610 | COMPAT_OBJS += compat/fopen.o | 612 | COMPAT_OBJS += compat/fopen.o |
611 | endif | 613 | endif |
612 | ifdef NO_SYMLINK_HEAD | 614 | ifdef NO_SYMLINK_HEAD |
613 | BASIC_CFLAGS += -DNO_SYMLINK_HEAD | 615 | BASIC_CFLAGS += -DNO_SYMLINK_HEAD |
614 | endif | 616 | endif |
615 | ifdef NO_STRCASESTR | 617 | ifdef NO_STRCASESTR |
616 | COMPAT_CFLAGS += -DNO_STRCASESTR | 618 | COMPAT_CFLAGS += -DNO_STRCASESTR |
617 | COMPAT_OBJS += compat/strcasestr.o | 619 | COMPAT_OBJS += compat/strcasestr.o |
618 | endif | 620 | endif |
619 | ifdef NO_STRTOUMAX | 621 | ifdef NO_STRTOUMAX |
620 | COMPAT_CFLAGS += -DNO_STRTOUMAX | 622 | COMPAT_CFLAGS += -DNO_STRTOUMAX |
621 | COMPAT_OBJS += compat/strtoumax.o | 623 | COMPAT_OBJS += compat/strtoumax.o |
622 | endif | 624 | endif |
623 | ifdef NO_STRTOULL | 625 | ifdef NO_STRTOULL |
624 | COMPAT_CFLAGS += -DNO_STRTOULL | 626 | COMPAT_CFLAGS += -DNO_STRTOULL |
625 | endif | 627 | endif |
626 | ifdef NO_SETENV | 628 | ifdef NO_SETENV |
627 | COMPAT_CFLAGS += -DNO_SETENV | 629 | COMPAT_CFLAGS += -DNO_SETENV |
628 | COMPAT_OBJS += compat/setenv.o | 630 | COMPAT_OBJS += compat/setenv.o |
629 | endif | 631 | endif |
630 | ifdef NO_MKDTEMP | 632 | ifdef NO_MKDTEMP |
631 | COMPAT_CFLAGS += -DNO_MKDTEMP | 633 | COMPAT_CFLAGS += -DNO_MKDTEMP |
632 | COMPAT_OBJS += compat/mkdtemp.o | 634 | COMPAT_OBJS += compat/mkdtemp.o |
633 | endif | 635 | endif |
634 | ifdef NO_UNSETENV | 636 | ifdef NO_UNSETENV |
635 | COMPAT_CFLAGS += -DNO_UNSETENV | 637 | COMPAT_CFLAGS += -DNO_UNSETENV |
636 | COMPAT_OBJS += compat/unsetenv.o | 638 | COMPAT_OBJS += compat/unsetenv.o |
637 | endif | 639 | endif |
638 | ifdef NO_SYS_SELECT_H | 640 | ifdef NO_SYS_SELECT_H |
639 | BASIC_CFLAGS += -DNO_SYS_SELECT_H | 641 | BASIC_CFLAGS += -DNO_SYS_SELECT_H |
640 | endif | 642 | endif |
641 | ifdef NO_MMAP | 643 | ifdef NO_MMAP |
642 | COMPAT_CFLAGS += -DNO_MMAP | 644 | COMPAT_CFLAGS += -DNO_MMAP |
643 | COMPAT_OBJS += compat/mmap.o | 645 | COMPAT_OBJS += compat/mmap.o |
644 | else | 646 | else |
645 | ifdef USE_WIN32_MMAP | 647 | ifdef USE_WIN32_MMAP |
646 | COMPAT_CFLAGS += -DUSE_WIN32_MMAP | 648 | COMPAT_CFLAGS += -DUSE_WIN32_MMAP |
647 | COMPAT_OBJS += compat/win32mmap.o | 649 | COMPAT_OBJS += compat/win32mmap.o |
648 | endif | 650 | endif |
649 | endif | 651 | endif |
650 | ifdef NO_PREAD | 652 | ifdef NO_PREAD |
651 | COMPAT_CFLAGS += -DNO_PREAD | 653 | COMPAT_CFLAGS += -DNO_PREAD |
652 | COMPAT_OBJS += compat/pread.o | 654 | COMPAT_OBJS += compat/pread.o |
653 | endif | 655 | endif |
654 | ifdef NO_FAST_WORKING_DIRECTORY | 656 | ifdef NO_FAST_WORKING_DIRECTORY |
655 | BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY | 657 | BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY |
656 | endif | 658 | endif |
657 | ifdef NO_TRUSTABLE_FILEMODE | 659 | ifdef NO_TRUSTABLE_FILEMODE |
658 | BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE | 660 | BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE |
659 | endif | 661 | endif |
660 | ifdef NO_IPV6 | 662 | ifdef NO_IPV6 |
661 | BASIC_CFLAGS += -DNO_IPV6 | 663 | BASIC_CFLAGS += -DNO_IPV6 |
662 | endif | 664 | endif |
663 | ifdef NO_UINTMAX_T | 665 | ifdef NO_UINTMAX_T |
664 | BASIC_CFLAGS += -Duintmax_t=uint32_t | 666 | BASIC_CFLAGS += -Duintmax_t=uint32_t |
665 | endif | 667 | endif |
666 | ifdef NO_SOCKADDR_STORAGE | 668 | ifdef NO_SOCKADDR_STORAGE |
667 | ifdef NO_IPV6 | 669 | ifdef NO_IPV6 |
668 | BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in | 670 | BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in |
669 | else | 671 | else |
670 | BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6 | 672 | BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6 |
671 | endif | 673 | endif |
672 | endif | 674 | endif |
673 | ifdef NO_INET_NTOP | 675 | ifdef NO_INET_NTOP |
674 | LIB_OBJS += compat/inet_ntop.o | 676 | LIB_OBJS += compat/inet_ntop.o |
675 | endif | 677 | endif |
676 | ifdef NO_INET_PTON | 678 | ifdef NO_INET_PTON |
677 | LIB_OBJS += compat/inet_pton.o | 679 | LIB_OBJS += compat/inet_pton.o |
678 | endif | 680 | endif |
679 | 681 | ||
680 | ifdef NO_ICONV | 682 | ifdef NO_ICONV |
681 | BASIC_CFLAGS += -DNO_ICONV | 683 | BASIC_CFLAGS += -DNO_ICONV |
682 | endif | 684 | endif |
683 | 685 | ||
684 | ifdef OLD_ICONV | 686 | ifdef OLD_ICONV |
685 | BASIC_CFLAGS += -DOLD_ICONV | 687 | BASIC_CFLAGS += -DOLD_ICONV |
686 | endif | 688 | endif |
687 | 689 | ||
688 | ifdef NO_DEFLATE_BOUND | 690 | ifdef NO_DEFLATE_BOUND |
689 | BASIC_CFLAGS += -DNO_DEFLATE_BOUND | 691 | BASIC_CFLAGS += -DNO_DEFLATE_BOUND |
690 | endif | 692 | endif |
691 | 693 | ||
692 | ifdef PPC_SHA1 | 694 | ifdef PPC_SHA1 |
693 | SHA1_HEADER = "ppc/sha1.h" | 695 | SHA1_HEADER = "ppc/sha1.h" |
694 | LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o | 696 | LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o |
695 | else | 697 | else |
696 | ifdef ARM_SHA1 | 698 | ifdef ARM_SHA1 |
697 | SHA1_HEADER = "arm/sha1.h" | 699 | SHA1_HEADER = "arm/sha1.h" |
698 | LIB_OBJS += arm/sha1.o arm/sha1_arm.o | 700 | LIB_OBJS += arm/sha1.o arm/sha1_arm.o |
699 | else | 701 | else |
700 | ifdef MOZILLA_SHA1 | 702 | ifdef MOZILLA_SHA1 |
701 | SHA1_HEADER = "mozilla-sha1/sha1.h" | 703 | SHA1_HEADER = "mozilla-sha1/sha1.h" |
702 | LIB_OBJS += mozilla-sha1/sha1.o | 704 | LIB_OBJS += mozilla-sha1/sha1.o |
703 | else | 705 | else |
704 | SHA1_HEADER = <openssl/sha.h> | 706 | SHA1_HEADER = <openssl/sha.h> |
705 | EXTLIBS += $(LIB_4_CRYPTO) | 707 | EXTLIBS += $(LIB_4_CRYPTO) |
706 | endif | 708 | endif |
707 | endif | 709 | endif |
708 | endif | 710 | endif |
709 | ifdef NO_PERL_MAKEMAKER | 711 | ifdef NO_PERL_MAKEMAKER |
710 | export NO_PERL_MAKEMAKER | 712 | export NO_PERL_MAKEMAKER |
711 | endif | 713 | endif |
712 | ifdef NO_HSTRERROR | 714 | ifdef NO_HSTRERROR |
713 | COMPAT_CFLAGS += -DNO_HSTRERROR | 715 | COMPAT_CFLAGS += -DNO_HSTRERROR |
714 | COMPAT_OBJS += compat/hstrerror.o | 716 | COMPAT_OBJS += compat/hstrerror.o |
715 | endif | 717 | endif |
716 | ifdef NO_MEMMEM | 718 | ifdef NO_MEMMEM |
717 | COMPAT_CFLAGS += -DNO_MEMMEM | 719 | COMPAT_CFLAGS += -DNO_MEMMEM |
718 | COMPAT_OBJS += compat/memmem.o | 720 | COMPAT_OBJS += compat/memmem.o |
719 | endif | 721 | endif |
720 | ifdef INTERNAL_QSORT | 722 | ifdef INTERNAL_QSORT |
721 | COMPAT_CFLAGS += -DINTERNAL_QSORT | 723 | COMPAT_CFLAGS += -DINTERNAL_QSORT |
722 | COMPAT_OBJS += compat/qsort.o | 724 | COMPAT_OBJS += compat/qsort.o |
723 | endif | 725 | endif |
724 | ifdef RUNTIME_PREFIX | 726 | ifdef RUNTIME_PREFIX |
725 | COMPAT_CFLAGS += -DRUNTIME_PREFIX | 727 | COMPAT_CFLAGS += -DRUNTIME_PREFIX |
726 | endif | 728 | endif |
727 | 729 | ||
728 | ifdef DIR_HAS_BSD_GROUP_SEMANTICS | 730 | ifdef DIR_HAS_BSD_GROUP_SEMANTICS |
729 | COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS | 731 | COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS |
730 | endif | 732 | endif |
731 | ifdef NO_EXTERNAL_GREP | 733 | ifdef NO_EXTERNAL_GREP |
732 | BASIC_CFLAGS += -DNO_EXTERNAL_GREP | 734 | BASIC_CFLAGS += -DNO_EXTERNAL_GREP |
733 | endif | 735 | endif |
734 | 736 | ||
735 | ifeq ($(PERL_PATH),) | 737 | ifeq ($(PERL_PATH),) |
736 | NO_PERL=NoThanks | 738 | NO_PERL=NoThanks |
737 | endif | 739 | endif |
738 | 740 | ||
739 | QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir | 741 | QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir |
740 | QUIET_SUBDIR1 = | 742 | QUIET_SUBDIR1 = |
741 | 743 | ||
742 | ifneq ($(findstring $(MAKEFLAGS),w),w) | 744 | ifneq ($(findstring $(MAKEFLAGS),w),w) |
743 | PRINT_DIR = --no-print-directory | 745 | PRINT_DIR = --no-print-directory |
744 | else # "make -w" | 746 | else # "make -w" |
745 | NO_SUBDIR = : | 747 | NO_SUBDIR = : |
746 | endif | 748 | endif |
747 | 749 | ||
748 | ifneq ($(findstring $(MAKEFLAGS),s),s) | 750 | ifneq ($(findstring $(MAKEFLAGS),s),s) |
749 | ifndef V | 751 | ifndef V |
750 | QUIET_CC = @echo ' ' CC $@; | 752 | QUIET_CC = @echo ' ' CC $@; |
751 | QUIET_AR = @echo ' ' AR $@; | 753 | QUIET_AR = @echo ' ' AR $@; |
752 | QUIET_LINK = @echo ' ' LINK $@; | 754 | QUIET_LINK = @echo ' ' LINK $@; |
753 | QUIET_BUILT_IN = @echo ' ' BUILTIN $@; | 755 | QUIET_BUILT_IN = @echo ' ' BUILTIN $@; |
754 | QUIET_GEN = @echo ' ' GEN $@; | 756 | QUIET_GEN = @echo ' ' GEN $@; |
755 | QUIET_SUBDIR0 = +@subdir= | 757 | QUIET_SUBDIR0 = +@subdir= |
756 | QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ | 758 | QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ |
757 | $(MAKE) $(PRINT_DIR) -C $$subdir | 759 | $(MAKE) $(PRINT_DIR) -C $$subdir |
758 | export V | 760 | export V |
759 | export QUIET_GEN | 761 | export QUIET_GEN |
760 | export QUIET_BUILT_IN | 762 | export QUIET_BUILT_IN |
761 | endif | 763 | endif |
762 | endif | 764 | endif |
763 | 765 | ||
764 | ifdef ASCIIDOC8 | 766 | ifdef ASCIIDOC8 |
765 | export ASCIIDOC8 | 767 | export ASCIIDOC8 |
766 | endif | 768 | endif |
767 | 769 | ||
768 | # Shell quote (do not use $(call) to accommodate ancient setups); | 770 | # Shell quote (do not use $(call) to accommodate ancient setups); |
769 | 771 | ||
770 | SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) | 772 | SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) |
771 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) | 773 | ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) |
772 | 774 | ||
773 | DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) | 775 | DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) |
774 | bindir_SQ = $(subst ','\'',$(bindir)) | 776 | bindir_SQ = $(subst ','\'',$(bindir)) |
775 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) | 777 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) |
776 | mandir_SQ = $(subst ','\'',$(mandir)) | 778 | mandir_SQ = $(subst ','\'',$(mandir)) |
777 | infodir_SQ = $(subst ','\'',$(infodir)) | 779 | infodir_SQ = $(subst ','\'',$(infodir)) |
778 | perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) | 780 | perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) |
779 | template_dir_SQ = $(subst ','\'',$(template_dir)) | 781 | template_dir_SQ = $(subst ','\'',$(template_dir)) |
780 | htmldir_SQ = $(subst ','\'',$(htmldir)) | 782 | htmldir_SQ = $(subst ','\'',$(htmldir)) |
781 | prefix_SQ = $(subst ','\'',$(prefix)) | 783 | prefix_SQ = $(subst ','\'',$(prefix)) |
782 | 784 | ||
783 | SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) | 785 | SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) |
784 | PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) | 786 | PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) |
785 | 787 | ||
786 | LIBS = $(PERFLIBS) $(EXTLIBS) | 788 | LIBS = $(PERFLIBS) $(EXTLIBS) |
787 | 789 | ||
788 | BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ | 790 | BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ |
789 | $(COMPAT_CFLAGS) | 791 | $(COMPAT_CFLAGS) |
790 | LIB_OBJS += $(COMPAT_OBJS) | 792 | LIB_OBJS += $(COMPAT_OBJS) |
791 | 793 | ||
792 | ALL_CFLAGS += $(BASIC_CFLAGS) | 794 | ALL_CFLAGS += $(BASIC_CFLAGS) |
793 | ALL_LDFLAGS += $(BASIC_LDFLAGS) | 795 | ALL_LDFLAGS += $(BASIC_LDFLAGS) |
794 | 796 | ||
795 | export TAR INSTALL DESTDIR SHELL_PATH | 797 | export TAR INSTALL DESTDIR SHELL_PATH |
796 | 798 | ||
797 | 799 | ||
798 | ### Build rules | 800 | ### Build rules |
799 | 801 | ||
800 | SHELL = $(SHELL_PATH) | 802 | SHELL = $(SHELL_PATH) |
801 | 803 | ||
802 | all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS | 804 | all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS |
803 | ifneq (,$X) | 805 | ifneq (,$X) |
804 | $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) | 806 | $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) |
805 | endif | 807 | endif |
806 | 808 | ||
807 | all:: | 809 | all:: |
808 | 810 | ||
809 | please_set_SHELL_PATH_to_a_more_modern_shell: | 811 | please_set_SHELL_PATH_to_a_more_modern_shell: |
810 | @$$(:) | 812 | @$$(:) |
811 | 813 | ||
812 | shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell | 814 | shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell |
813 | 815 | ||
814 | strip: $(PROGRAMS) perf$X | 816 | strip: $(PROGRAMS) perf$X |
815 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X | 817 | $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X |
816 | 818 | ||
817 | perf.o: perf.c common-cmds.h PERF-CFLAGS | 819 | perf.o: perf.c common-cmds.h PERF-CFLAGS |
818 | $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ | 820 | $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ |
819 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 821 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
820 | $(ALL_CFLAGS) -c $(filter %.c,$^) | 822 | $(ALL_CFLAGS) -c $(filter %.c,$^) |
821 | 823 | ||
822 | perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS) | 824 | perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS) |
823 | $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \ | 825 | $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \ |
824 | $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) | 826 | $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) |
825 | 827 | ||
826 | builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS | 828 | builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS |
827 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ | 829 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ |
828 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 830 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
829 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ | 831 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ |
830 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< | 832 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< |
831 | 833 | ||
832 | builtin-timechart.o: builtin-timechart.c common-cmds.h PERF-CFLAGS | 834 | builtin-timechart.o: builtin-timechart.c common-cmds.h PERF-CFLAGS |
833 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ | 835 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ |
834 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ | 836 | '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ |
835 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ | 837 | '-DPERF_MAN_PATH="$(mandir_SQ)"' \ |
836 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< | 838 | '-DPERF_INFO_PATH="$(infodir_SQ)"' $< |
837 | 839 | ||
838 | $(BUILT_INS): perf$X | 840 | $(BUILT_INS): perf$X |
839 | $(QUIET_BUILT_IN)$(RM) $@ && \ | 841 | $(QUIET_BUILT_IN)$(RM) $@ && \ |
840 | ln perf$X $@ 2>/dev/null || \ | 842 | ln perf$X $@ 2>/dev/null || \ |
841 | ln -s perf$X $@ 2>/dev/null || \ | 843 | ln -s perf$X $@ 2>/dev/null || \ |
842 | cp perf$X $@ | 844 | cp perf$X $@ |
843 | 845 | ||
844 | common-cmds.h: util/generate-cmdlist.sh command-list.txt | 846 | common-cmds.h: util/generate-cmdlist.sh command-list.txt |
845 | 847 | ||
846 | common-cmds.h: $(wildcard Documentation/perf-*.txt) | 848 | common-cmds.h: $(wildcard Documentation/perf-*.txt) |
847 | $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ | 849 | $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ |
848 | 850 | ||
849 | $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh | 851 | $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh |
850 | $(QUIET_GEN)$(RM) $@ $@+ && \ | 852 | $(QUIET_GEN)$(RM) $@ $@+ && \ |
851 | sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ | 853 | sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ |
852 | -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ | 854 | -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ |
853 | -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ | 855 | -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ |
854 | -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ | 856 | -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ |
855 | -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ | 857 | -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ |
856 | $@.sh >$@+ && \ | 858 | $@.sh >$@+ && \ |
857 | chmod +x $@+ && \ | 859 | chmod +x $@+ && \ |
858 | mv $@+ $@ | 860 | mv $@+ $@ |
859 | 861 | ||
860 | configure: configure.ac | 862 | configure: configure.ac |
861 | $(QUIET_GEN)$(RM) $@ $<+ && \ | 863 | $(QUIET_GEN)$(RM) $@ $<+ && \ |
862 | sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ | 864 | sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ |
863 | $< > $<+ && \ | 865 | $< > $<+ && \ |
864 | autoconf -o $@ $<+ && \ | 866 | autoconf -o $@ $<+ && \ |
865 | $(RM) $<+ | 867 | $(RM) $<+ |
866 | 868 | ||
867 | # These can record PERF_VERSION | 869 | # These can record PERF_VERSION |
868 | perf.o perf.spec \ | 870 | perf.o perf.spec \ |
869 | $(patsubst %.sh,%,$(SCRIPT_SH)) \ | 871 | $(patsubst %.sh,%,$(SCRIPT_SH)) \ |
870 | $(patsubst %.perl,%,$(SCRIPT_PERL)) \ | 872 | $(patsubst %.perl,%,$(SCRIPT_PERL)) \ |
871 | : PERF-VERSION-FILE | 873 | : PERF-VERSION-FILE |
872 | 874 | ||
873 | %.o: %.c PERF-CFLAGS | 875 | %.o: %.c PERF-CFLAGS |
874 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< | 876 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< |
875 | %.s: %.c PERF-CFLAGS | 877 | %.s: %.c PERF-CFLAGS |
876 | $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< | 878 | $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< |
877 | %.o: %.S | 879 | %.o: %.S |
878 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< | 880 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< |
879 | 881 | ||
880 | util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS | 882 | util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS |
881 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ | 883 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ |
882 | '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ | 884 | '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ |
883 | '-DBINDIR="$(bindir_relative_SQ)"' \ | 885 | '-DBINDIR="$(bindir_relative_SQ)"' \ |
884 | '-DPREFIX="$(prefix_SQ)"' \ | 886 | '-DPREFIX="$(prefix_SQ)"' \ |
885 | $< | 887 | $< |
886 | 888 | ||
887 | builtin-init-db.o: builtin-init-db.c PERF-CFLAGS | 889 | builtin-init-db.o: builtin-init-db.c PERF-CFLAGS |
888 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $< | 890 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $< |
889 | 891 | ||
890 | util/config.o: util/config.c PERF-CFLAGS | 892 | util/config.o: util/config.c PERF-CFLAGS |
891 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 893 | $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
892 | 894 | ||
893 | util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS | 895 | util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS |
894 | $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 896 | $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
895 | 897 | ||
896 | # some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing | 898 | # some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing |
897 | # from <string.h> that comes from kernel headers wrapping. | 899 | # from <string.h> that comes from kernel headers wrapping. |
898 | KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//` | 900 | KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//` |
899 | 901 | ||
900 | util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS | 902 | util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS |
901 | $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 903 | $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
902 | 904 | ||
903 | util/hweight.o: ../../lib/hweight.c PERF-CFLAGS | 905 | util/hweight.o: ../../lib/hweight.c PERF-CFLAGS |
904 | $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 906 | $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
905 | 907 | ||
906 | util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS | 908 | util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS |
907 | $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 909 | $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
908 | 910 | ||
909 | util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c PERF-CFLAGS | 911 | util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c PERF-CFLAGS |
910 | $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | 912 | $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< |
911 | 913 | ||
912 | scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS | 914 | scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS |
913 | $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< | 915 | $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< |
914 | 916 | ||
915 | util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c PERF-CFLAGS | 917 | util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c PERF-CFLAGS |
916 | $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-python.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | 918 | $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-python.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< |
917 | 919 | ||
918 | scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c PERF-CFLAGS | 920 | scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c PERF-CFLAGS |
919 | $(QUIET_CC)$(CC) -o scripts/python/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< | 921 | $(QUIET_CC)$(CC) -o scripts/python/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< |
920 | 922 | ||
921 | perf-%$X: %.o $(PERFLIBS) | 923 | perf-%$X: %.o $(PERFLIBS) |
922 | $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) | 924 | $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) |
923 | 925 | ||
924 | $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) | 926 | $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) |
925 | $(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) | 927 | $(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) |
926 | builtin-revert.o wt-status.o: wt-status.h | 928 | builtin-revert.o wt-status.o: wt-status.h |
927 | 929 | ||
928 | $(LIB_FILE): $(LIB_OBJS) | 930 | $(LIB_FILE): $(LIB_OBJS) |
929 | $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) | 931 | $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) |
930 | 932 | ||
931 | doc: | 933 | doc: |
932 | $(MAKE) -C Documentation all | 934 | $(MAKE) -C Documentation all |
933 | 935 | ||
934 | man: | 936 | man: |
935 | $(MAKE) -C Documentation man | 937 | $(MAKE) -C Documentation man |
936 | 938 | ||
937 | html: | 939 | html: |
938 | $(MAKE) -C Documentation html | 940 | $(MAKE) -C Documentation html |
939 | 941 | ||
940 | info: | 942 | info: |
941 | $(MAKE) -C Documentation info | 943 | $(MAKE) -C Documentation info |
942 | 944 | ||
943 | pdf: | 945 | pdf: |
944 | $(MAKE) -C Documentation pdf | 946 | $(MAKE) -C Documentation pdf |
945 | 947 | ||
946 | TAGS: | 948 | TAGS: |
947 | $(RM) TAGS | 949 | $(RM) TAGS |
948 | $(FIND) . -name '*.[hcS]' -print | xargs etags -a | 950 | $(FIND) . -name '*.[hcS]' -print | xargs etags -a |
949 | 951 | ||
950 | tags: | 952 | tags: |
951 | $(RM) tags | 953 | $(RM) tags |
952 | $(FIND) . -name '*.[hcS]' -print | xargs ctags -a | 954 | $(FIND) . -name '*.[hcS]' -print | xargs ctags -a |
953 | 955 | ||
954 | cscope: | 956 | cscope: |
955 | $(RM) cscope* | 957 | $(RM) cscope* |
956 | $(FIND) . -name '*.[hcS]' -print | xargs cscope -b | 958 | $(FIND) . -name '*.[hcS]' -print | xargs cscope -b |
957 | 959 | ||
958 | ### Detect prefix changes | 960 | ### Detect prefix changes |
959 | TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ | 961 | TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ |
960 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) | 962 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) |
961 | 963 | ||
962 | PERF-CFLAGS: .FORCE-PERF-CFLAGS | 964 | PERF-CFLAGS: .FORCE-PERF-CFLAGS |
963 | @FLAGS='$(TRACK_CFLAGS)'; \ | 965 | @FLAGS='$(TRACK_CFLAGS)'; \ |
964 | if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \ | 966 | if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \ |
965 | echo 1>&2 " * new build flags or prefix"; \ | 967 | echo 1>&2 " * new build flags or prefix"; \ |
966 | echo "$$FLAGS" >PERF-CFLAGS; \ | 968 | echo "$$FLAGS" >PERF-CFLAGS; \ |
967 | fi | 969 | fi |
968 | 970 | ||
969 | # We need to apply sq twice, once to protect from the shell | 971 | # We need to apply sq twice, once to protect from the shell |
970 | # that runs PERF-BUILD-OPTIONS, and then again to protect it | 972 | # that runs PERF-BUILD-OPTIONS, and then again to protect it |
971 | # and the first level quoting from the shell that runs "echo". | 973 | # and the first level quoting from the shell that runs "echo". |
972 | PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS | 974 | PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS |
973 | @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ | 975 | @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ |
974 | @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ | 976 | @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ |
975 | @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ | 977 | @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ |
976 | @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@ | 978 | @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@ |
977 | 979 | ||
978 | ### Testing rules | 980 | ### Testing rules |
979 | 981 | ||
980 | # | 982 | # |
981 | # None right now: | 983 | # None right now: |
982 | # | 984 | # |
983 | # TEST_PROGRAMS += test-something$X | 985 | # TEST_PROGRAMS += test-something$X |
984 | 986 | ||
985 | all:: $(TEST_PROGRAMS) | 987 | all:: $(TEST_PROGRAMS) |
986 | 988 | ||
987 | # GNU make supports exporting all variables by "export" without parameters. | 989 | # GNU make supports exporting all variables by "export" without parameters. |
988 | # However, the environment gets quite big, and some programs have problems | 990 | # However, the environment gets quite big, and some programs have problems |
989 | # with that. | 991 | # with that. |
990 | 992 | ||
991 | export NO_SVN_TESTS | 993 | export NO_SVN_TESTS |
992 | 994 | ||
993 | check: common-cmds.h | 995 | check: common-cmds.h |
994 | if sparse; \ | 996 | if sparse; \ |
995 | then \ | 997 | then \ |
996 | for i in *.c */*.c; \ | 998 | for i in *.c */*.c; \ |
997 | do \ | 999 | do \ |
998 | sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ | 1000 | sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ |
999 | done; \ | 1001 | done; \ |
1000 | else \ | 1002 | else \ |
1001 | echo 2>&1 "Did you mean 'make test'?"; \ | 1003 | echo 2>&1 "Did you mean 'make test'?"; \ |
1002 | exit 1; \ | 1004 | exit 1; \ |
1003 | fi | 1005 | fi |
1004 | 1006 | ||
1005 | remove-dashes: | 1007 | remove-dashes: |
1006 | ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS) | 1008 | ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS) |
1007 | 1009 | ||
1008 | ### Installation rules | 1010 | ### Installation rules |
1009 | 1011 | ||
1010 | ifneq ($(filter /%,$(firstword $(template_dir))),) | 1012 | ifneq ($(filter /%,$(firstword $(template_dir))),) |
1011 | template_instdir = $(template_dir) | 1013 | template_instdir = $(template_dir) |
1012 | else | 1014 | else |
1013 | template_instdir = $(prefix)/$(template_dir) | 1015 | template_instdir = $(prefix)/$(template_dir) |
1014 | endif | 1016 | endif |
1015 | export template_instdir | 1017 | export template_instdir |
1016 | 1018 | ||
1017 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) | 1019 | ifneq ($(filter /%,$(firstword $(perfexecdir))),) |
1018 | perfexec_instdir = $(perfexecdir) | 1020 | perfexec_instdir = $(perfexecdir) |
1019 | else | 1021 | else |
1020 | perfexec_instdir = $(prefix)/$(perfexecdir) | 1022 | perfexec_instdir = $(prefix)/$(perfexecdir) |
1021 | endif | 1023 | endif |
1022 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | 1024 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) |
1023 | export perfexec_instdir | 1025 | export perfexec_instdir |
1024 | 1026 | ||
1025 | install: all | 1027 | install: all |
1026 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' | 1028 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' |
1027 | $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' | 1029 | $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' |
1028 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' | 1030 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' |
1029 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' | 1031 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' |
1030 | $(INSTALL) perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 1032 | $(INSTALL) perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
1031 | $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' | 1033 | $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' |
1032 | $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' | 1034 | $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' |
1033 | $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' | 1035 | $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' |
1034 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' | 1036 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' |
1035 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' | 1037 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
1036 | $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' | 1038 | $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' |
1037 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' | 1039 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' |
1038 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' | 1040 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
1039 | 1041 | ||
1040 | ifdef BUILT_INS | 1042 | ifdef BUILT_INS |
1041 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 1043 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
1042 | $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 1044 | $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
1043 | ifneq (,$X) | 1045 | ifneq (,$X) |
1044 | $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';) | 1046 | $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';) |
1045 | endif | 1047 | endif |
1046 | endif | 1048 | endif |
1047 | 1049 | ||
1048 | install-doc: | 1050 | install-doc: |
1049 | $(MAKE) -C Documentation install | 1051 | $(MAKE) -C Documentation install |
1050 | 1052 | ||
1051 | install-man: | 1053 | install-man: |
1052 | $(MAKE) -C Documentation install-man | 1054 | $(MAKE) -C Documentation install-man |
1053 | 1055 | ||
1054 | install-html: | 1056 | install-html: |
1055 | $(MAKE) -C Documentation install-html | 1057 | $(MAKE) -C Documentation install-html |
1056 | 1058 | ||
1057 | install-info: | 1059 | install-info: |
1058 | $(MAKE) -C Documentation install-info | 1060 | $(MAKE) -C Documentation install-info |
1059 | 1061 | ||
1060 | install-pdf: | 1062 | install-pdf: |
1061 | $(MAKE) -C Documentation install-pdf | 1063 | $(MAKE) -C Documentation install-pdf |
1062 | 1064 | ||
1063 | quick-install-doc: | 1065 | quick-install-doc: |
1064 | $(MAKE) -C Documentation quick-install | 1066 | $(MAKE) -C Documentation quick-install |
1065 | 1067 | ||
1066 | quick-install-man: | 1068 | quick-install-man: |
1067 | $(MAKE) -C Documentation quick-install-man | 1069 | $(MAKE) -C Documentation quick-install-man |
1068 | 1070 | ||
1069 | quick-install-html: | 1071 | quick-install-html: |
1070 | $(MAKE) -C Documentation quick-install-html | 1072 | $(MAKE) -C Documentation quick-install-html |
1071 | 1073 | ||
1072 | 1074 | ||
1073 | ### Maintainer's dist rules | 1075 | ### Maintainer's dist rules |
1074 | # | 1076 | # |
1075 | # None right now | 1077 | # None right now |
1076 | # | 1078 | # |
1077 | # | 1079 | # |
1078 | # perf.spec: perf.spec.in | 1080 | # perf.spec: perf.spec.in |
1079 | # sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+ | 1081 | # sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+ |
1080 | # mv $@+ $@ | 1082 | # mv $@+ $@ |
1081 | # | 1083 | # |
1082 | # PERF_TARNAME=perf-$(PERF_VERSION) | 1084 | # PERF_TARNAME=perf-$(PERF_VERSION) |
1083 | # dist: perf.spec perf-archive$(X) configure | 1085 | # dist: perf.spec perf-archive$(X) configure |
1084 | # ./perf-archive --format=tar \ | 1086 | # ./perf-archive --format=tar \ |
1085 | # --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar | 1087 | # --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar |
1086 | # @mkdir -p $(PERF_TARNAME) | 1088 | # @mkdir -p $(PERF_TARNAME) |
1087 | # @cp perf.spec configure $(PERF_TARNAME) | 1089 | # @cp perf.spec configure $(PERF_TARNAME) |
1088 | # @echo $(PERF_VERSION) > $(PERF_TARNAME)/version | 1090 | # @echo $(PERF_VERSION) > $(PERF_TARNAME)/version |
1089 | # $(TAR) rf $(PERF_TARNAME).tar \ | 1091 | # $(TAR) rf $(PERF_TARNAME).tar \ |
1090 | # $(PERF_TARNAME)/perf.spec \ | 1092 | # $(PERF_TARNAME)/perf.spec \ |
1091 | # $(PERF_TARNAME)/configure \ | 1093 | # $(PERF_TARNAME)/configure \ |
1092 | # $(PERF_TARNAME)/version | 1094 | # $(PERF_TARNAME)/version |
1093 | # @$(RM) -r $(PERF_TARNAME) | 1095 | # @$(RM) -r $(PERF_TARNAME) |
1094 | # gzip -f -9 $(PERF_TARNAME).tar | 1096 | # gzip -f -9 $(PERF_TARNAME).tar |
1095 | # | 1097 | # |
1096 | # htmldocs = perf-htmldocs-$(PERF_VERSION) | 1098 | # htmldocs = perf-htmldocs-$(PERF_VERSION) |
1097 | # manpages = perf-manpages-$(PERF_VERSION) | 1099 | # manpages = perf-manpages-$(PERF_VERSION) |
1098 | # dist-doc: | 1100 | # dist-doc: |
1099 | # $(RM) -r .doc-tmp-dir | 1101 | # $(RM) -r .doc-tmp-dir |
1100 | # mkdir .doc-tmp-dir | 1102 | # mkdir .doc-tmp-dir |
1101 | # $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc | 1103 | # $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc |
1102 | # cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar . | 1104 | # cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar . |
1103 | # gzip -n -9 -f $(htmldocs).tar | 1105 | # gzip -n -9 -f $(htmldocs).tar |
1104 | # : | 1106 | # : |
1105 | # $(RM) -r .doc-tmp-dir | 1107 | # $(RM) -r .doc-tmp-dir |
1106 | # mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7 | 1108 | # mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7 |
1107 | # $(MAKE) -C Documentation DESTDIR=./ \ | 1109 | # $(MAKE) -C Documentation DESTDIR=./ \ |
1108 | # man1dir=../.doc-tmp-dir/man1 \ | 1110 | # man1dir=../.doc-tmp-dir/man1 \ |
1109 | # man5dir=../.doc-tmp-dir/man5 \ | 1111 | # man5dir=../.doc-tmp-dir/man5 \ |
1110 | # man7dir=../.doc-tmp-dir/man7 \ | 1112 | # man7dir=../.doc-tmp-dir/man7 \ |
1111 | # install | 1113 | # install |
1112 | # cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar . | 1114 | # cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar . |
1113 | # gzip -n -9 -f $(manpages).tar | 1115 | # gzip -n -9 -f $(manpages).tar |
1114 | # $(RM) -r .doc-tmp-dir | 1116 | # $(RM) -r .doc-tmp-dir |
1115 | # | 1117 | # |
1116 | # rpm: dist | 1118 | # rpm: dist |
1117 | # $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz | 1119 | # $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz |
1118 | 1120 | ||
1119 | ### Cleaning rules | 1121 | ### Cleaning rules |
1120 | 1122 | ||
1121 | distclean: clean | 1123 | distclean: clean |
1122 | # $(RM) configure | 1124 | # $(RM) configure |
1123 | 1125 | ||
1124 | clean: | 1126 | clean: |
1125 | $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) | 1127 | $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) |
1126 | $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X | 1128 | $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X |
1127 | $(RM) $(TEST_PROGRAMS) | 1129 | $(RM) $(TEST_PROGRAMS) |
1128 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* | 1130 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* |
1129 | $(RM) -r autom4te.cache | 1131 | $(RM) -r autom4te.cache |
1130 | $(RM) config.log config.mak.autogen config.mak.append config.status config.cache | 1132 | $(RM) config.log config.mak.autogen config.mak.append config.status config.cache |
1131 | $(RM) -r $(PERF_TARNAME) .doc-tmp-dir | 1133 | $(RM) -r $(PERF_TARNAME) .doc-tmp-dir |
1132 | $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz | 1134 | $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz |
1133 | $(RM) $(htmldocs).tar.gz $(manpages).tar.gz | 1135 | $(RM) $(htmldocs).tar.gz $(manpages).tar.gz |
1134 | $(MAKE) -C Documentation/ clean | 1136 | $(MAKE) -C Documentation/ clean |
1135 | $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS | 1137 | $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS |
1136 | 1138 | ||
1137 | .PHONY: all install clean strip | 1139 | .PHONY: all install clean strip |
1138 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell | 1140 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell |
1139 | .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS | 1141 | .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS |
1140 | .PHONY: .FORCE-PERF-BUILD-OPTIONS | 1142 | .PHONY: .FORCE-PERF-BUILD-OPTIONS |
1141 | 1143 | ||
1142 | .perf.dev.null: | 1144 | .perf.dev.null: |
1143 | touch .perf.dev.null | 1145 | touch .perf.dev.null |
1144 | 1146 | ||
1145 | .INTERMEDIATE: .perf.dev.null | 1147 | .INTERMEDIATE: .perf.dev.null |
1146 | 1148 | ||
1147 | ### Make sure built-ins do not have dups and listed in perf.c | 1149 | ### Make sure built-ins do not have dups and listed in perf.c |
1148 | # | 1150 | # |
1149 | check-builtins:: | 1151 | check-builtins:: |
1150 | ./check-builtins.sh | 1152 | ./check-builtins.sh |
1151 | 1153 | ||
1152 | ### Test suite coverage testing | 1154 | ### Test suite coverage testing |
1153 | # | 1155 | # |
1154 | # None right now | 1156 | # None right now |
1155 | # | 1157 | # |
1156 | # .PHONY: coverage coverage-clean coverage-build coverage-report | 1158 | # .PHONY: coverage coverage-clean coverage-build coverage-report |
1157 | # | 1159 | # |
1158 | # coverage: | 1160 | # coverage: |
1159 | # $(MAKE) coverage-build | 1161 | # $(MAKE) coverage-build |
1160 | # $(MAKE) coverage-report | 1162 | # $(MAKE) coverage-report |
1161 | # | 1163 | # |
1162 | # coverage-clean: | 1164 | # coverage-clean: |
1163 | # rm -f *.gcda *.gcno | 1165 | # rm -f *.gcda *.gcno |
1164 | # | 1166 | # |
1165 | # COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs | 1167 | # COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs |
1166 | # COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov | 1168 | # COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov |
1167 | # | 1169 | # |
1168 | # coverage-build: coverage-clean | 1170 | # coverage-build: coverage-clean |
1169 | # $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all | 1171 | # $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all |
1170 | # $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \ | 1172 | # $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \ |
1171 | # -j1 test | 1173 | # -j1 test |
1172 | # | 1174 | # |
1173 | # coverage-report: | 1175 | # coverage-report: |
1174 | # gcov -b *.c */*.c | 1176 | # gcov -b *.c */*.c |
1175 | # grep '^function.*called 0 ' *.c.gcov */*.c.gcov \ | 1177 | # grep '^function.*called 0 ' *.c.gcov */*.c.gcov \ |
1176 | # | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \ | 1178 | # | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \ |
1177 | # | tee coverage-untested-functions | 1179 | # | tee coverage-untested-functions |
1178 | 1180 |
tools/perf/builtin-record.c
1 | /* | 1 | /* |
2 | * builtin-record.c | 2 | * builtin-record.c |
3 | * | 3 | * |
4 | * Builtin record command: Record the profile of a workload | 4 | * Builtin record command: Record the profile of a workload |
5 | * (or a CPU, or a PID) into the perf.data output file - for | 5 | * (or a CPU, or a PID) into the perf.data output file - for |
6 | * later analysis via perf report. | 6 | * later analysis via perf report. |
7 | */ | 7 | */ |
8 | #define _FILE_OFFSET_BITS 64 | 8 | #define _FILE_OFFSET_BITS 64 |
9 | 9 | ||
10 | #include "builtin.h" | 10 | #include "builtin.h" |
11 | 11 | ||
12 | #include "perf.h" | 12 | #include "perf.h" |
13 | 13 | ||
14 | #include "util/build-id.h" | 14 | #include "util/build-id.h" |
15 | #include "util/util.h" | 15 | #include "util/util.h" |
16 | #include "util/parse-options.h" | 16 | #include "util/parse-options.h" |
17 | #include "util/parse-events.h" | 17 | #include "util/parse-events.h" |
18 | #include "util/string.h" | 18 | #include "util/string.h" |
19 | 19 | ||
20 | #include "util/header.h" | 20 | #include "util/header.h" |
21 | #include "util/event.h" | 21 | #include "util/event.h" |
22 | #include "util/debug.h" | 22 | #include "util/debug.h" |
23 | #include "util/session.h" | 23 | #include "util/session.h" |
24 | #include "util/symbol.h" | 24 | #include "util/symbol.h" |
25 | #include "util/cpumap.h" | ||
25 | 26 | ||
26 | #include <unistd.h> | 27 | #include <unistd.h> |
27 | #include <sched.h> | 28 | #include <sched.h> |
28 | 29 | ||
29 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; | 30 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; |
30 | 31 | ||
31 | static long default_interval = 0; | 32 | static long default_interval = 0; |
32 | 33 | ||
33 | static int nr_cpus = 0; | 34 | static int nr_cpus = 0; |
34 | static unsigned int page_size; | 35 | static unsigned int page_size; |
35 | static unsigned int mmap_pages = 128; | 36 | static unsigned int mmap_pages = 128; |
36 | static int freq = 1000; | 37 | static int freq = 1000; |
37 | static int output; | 38 | static int output; |
38 | static const char *output_name = "perf.data"; | 39 | static const char *output_name = "perf.data"; |
39 | static int group = 0; | 40 | static int group = 0; |
40 | static unsigned int realtime_prio = 0; | 41 | static unsigned int realtime_prio = 0; |
41 | static int raw_samples = 0; | 42 | static int raw_samples = 0; |
42 | static int system_wide = 0; | 43 | static int system_wide = 0; |
43 | static int profile_cpu = -1; | 44 | static int profile_cpu = -1; |
44 | static pid_t target_pid = -1; | 45 | static pid_t target_pid = -1; |
45 | static pid_t child_pid = -1; | 46 | static pid_t child_pid = -1; |
46 | static int inherit = 1; | 47 | static int inherit = 1; |
47 | static int force = 0; | 48 | static int force = 0; |
48 | static int append_file = 0; | 49 | static int append_file = 0; |
49 | static int call_graph = 0; | 50 | static int call_graph = 0; |
50 | static int inherit_stat = 0; | 51 | static int inherit_stat = 0; |
51 | static int no_samples = 0; | 52 | static int no_samples = 0; |
52 | static int sample_address = 0; | 53 | static int sample_address = 0; |
53 | static int multiplex = 0; | 54 | static int multiplex = 0; |
54 | static int multiplex_fd = -1; | 55 | static int multiplex_fd = -1; |
55 | 56 | ||
56 | static long samples = 0; | 57 | static long samples = 0; |
57 | static struct timeval last_read; | 58 | static struct timeval last_read; |
58 | static struct timeval this_read; | 59 | static struct timeval this_read; |
59 | 60 | ||
60 | static u64 bytes_written = 0; | 61 | static u64 bytes_written = 0; |
61 | 62 | ||
62 | static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; | 63 | static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; |
63 | 64 | ||
64 | static int nr_poll = 0; | 65 | static int nr_poll = 0; |
65 | static int nr_cpu = 0; | 66 | static int nr_cpu = 0; |
66 | 67 | ||
67 | static int file_new = 1; | 68 | static int file_new = 1; |
68 | static off_t post_processing_offset; | 69 | static off_t post_processing_offset; |
69 | 70 | ||
70 | static struct perf_session *session; | 71 | static struct perf_session *session; |
71 | 72 | ||
72 | struct mmap_data { | 73 | struct mmap_data { |
73 | int counter; | 74 | int counter; |
74 | void *base; | 75 | void *base; |
75 | unsigned int mask; | 76 | unsigned int mask; |
76 | unsigned int prev; | 77 | unsigned int prev; |
77 | }; | 78 | }; |
78 | 79 | ||
79 | static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | 80 | static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; |
80 | 81 | ||
81 | static unsigned long mmap_read_head(struct mmap_data *md) | 82 | static unsigned long mmap_read_head(struct mmap_data *md) |
82 | { | 83 | { |
83 | struct perf_event_mmap_page *pc = md->base; | 84 | struct perf_event_mmap_page *pc = md->base; |
84 | long head; | 85 | long head; |
85 | 86 | ||
86 | head = pc->data_head; | 87 | head = pc->data_head; |
87 | rmb(); | 88 | rmb(); |
88 | 89 | ||
89 | return head; | 90 | return head; |
90 | } | 91 | } |
91 | 92 | ||
92 | static void mmap_write_tail(struct mmap_data *md, unsigned long tail) | 93 | static void mmap_write_tail(struct mmap_data *md, unsigned long tail) |
93 | { | 94 | { |
94 | struct perf_event_mmap_page *pc = md->base; | 95 | struct perf_event_mmap_page *pc = md->base; |
95 | 96 | ||
96 | /* | 97 | /* |
97 | * ensure all reads are done before we write the tail out. | 98 | * ensure all reads are done before we write the tail out. |
98 | */ | 99 | */ |
99 | /* mb(); */ | 100 | /* mb(); */ |
100 | pc->data_tail = tail; | 101 | pc->data_tail = tail; |
101 | } | 102 | } |
102 | 103 | ||
103 | static void write_output(void *buf, size_t size) | 104 | static void write_output(void *buf, size_t size) |
104 | { | 105 | { |
105 | while (size) { | 106 | while (size) { |
106 | int ret = write(output, buf, size); | 107 | int ret = write(output, buf, size); |
107 | 108 | ||
108 | if (ret < 0) | 109 | if (ret < 0) |
109 | die("failed to write"); | 110 | die("failed to write"); |
110 | 111 | ||
111 | size -= ret; | 112 | size -= ret; |
112 | buf += ret; | 113 | buf += ret; |
113 | 114 | ||
114 | bytes_written += ret; | 115 | bytes_written += ret; |
115 | } | 116 | } |
116 | } | 117 | } |
117 | 118 | ||
118 | static int process_synthesized_event(event_t *event, | 119 | static int process_synthesized_event(event_t *event, |
119 | struct perf_session *self __used) | 120 | struct perf_session *self __used) |
120 | { | 121 | { |
121 | write_output(event, event->header.size); | 122 | write_output(event, event->header.size); |
122 | return 0; | 123 | return 0; |
123 | } | 124 | } |
124 | 125 | ||
125 | static void mmap_read(struct mmap_data *md) | 126 | static void mmap_read(struct mmap_data *md) |
126 | { | 127 | { |
127 | unsigned int head = mmap_read_head(md); | 128 | unsigned int head = mmap_read_head(md); |
128 | unsigned int old = md->prev; | 129 | unsigned int old = md->prev; |
129 | unsigned char *data = md->base + page_size; | 130 | unsigned char *data = md->base + page_size; |
130 | unsigned long size; | 131 | unsigned long size; |
131 | void *buf; | 132 | void *buf; |
132 | int diff; | 133 | int diff; |
133 | 134 | ||
134 | gettimeofday(&this_read, NULL); | 135 | gettimeofday(&this_read, NULL); |
135 | 136 | ||
136 | /* | 137 | /* |
137 | * If we're further behind than half the buffer, there's a chance | 138 | * If we're further behind than half the buffer, there's a chance |
138 | * the writer will bite our tail and mess up the samples under us. | 139 | * the writer will bite our tail and mess up the samples under us. |
139 | * | 140 | * |
140 | * If we somehow ended up ahead of the head, we got messed up. | 141 | * If we somehow ended up ahead of the head, we got messed up. |
141 | * | 142 | * |
142 | * In either case, truncate and restart at head. | 143 | * In either case, truncate and restart at head. |
143 | */ | 144 | */ |
144 | diff = head - old; | 145 | diff = head - old; |
145 | if (diff < 0) { | 146 | if (diff < 0) { |
146 | struct timeval iv; | 147 | struct timeval iv; |
147 | unsigned long msecs; | 148 | unsigned long msecs; |
148 | 149 | ||
149 | timersub(&this_read, &last_read, &iv); | 150 | timersub(&this_read, &last_read, &iv); |
150 | msecs = iv.tv_sec*1000 + iv.tv_usec/1000; | 151 | msecs = iv.tv_sec*1000 + iv.tv_usec/1000; |
151 | 152 | ||
152 | fprintf(stderr, "WARNING: failed to keep up with mmap data." | 153 | fprintf(stderr, "WARNING: failed to keep up with mmap data." |
153 | " Last read %lu msecs ago.\n", msecs); | 154 | " Last read %lu msecs ago.\n", msecs); |
154 | 155 | ||
155 | /* | 156 | /* |
156 | * head points to a known good entry, start there. | 157 | * head points to a known good entry, start there. |
157 | */ | 158 | */ |
158 | old = head; | 159 | old = head; |
159 | } | 160 | } |
160 | 161 | ||
161 | last_read = this_read; | 162 | last_read = this_read; |
162 | 163 | ||
163 | if (old != head) | 164 | if (old != head) |
164 | samples++; | 165 | samples++; |
165 | 166 | ||
166 | size = head - old; | 167 | size = head - old; |
167 | 168 | ||
168 | if ((old & md->mask) + size != (head & md->mask)) { | 169 | if ((old & md->mask) + size != (head & md->mask)) { |
169 | buf = &data[old & md->mask]; | 170 | buf = &data[old & md->mask]; |
170 | size = md->mask + 1 - (old & md->mask); | 171 | size = md->mask + 1 - (old & md->mask); |
171 | old += size; | 172 | old += size; |
172 | 173 | ||
173 | write_output(buf, size); | 174 | write_output(buf, size); |
174 | } | 175 | } |
175 | 176 | ||
176 | buf = &data[old & md->mask]; | 177 | buf = &data[old & md->mask]; |
177 | size = head - old; | 178 | size = head - old; |
178 | old += size; | 179 | old += size; |
179 | 180 | ||
180 | write_output(buf, size); | 181 | write_output(buf, size); |
181 | 182 | ||
182 | md->prev = old; | 183 | md->prev = old; |
183 | mmap_write_tail(md, old); | 184 | mmap_write_tail(md, old); |
184 | } | 185 | } |
185 | 186 | ||
186 | static volatile int done = 0; | 187 | static volatile int done = 0; |
187 | static volatile int signr = -1; | 188 | static volatile int signr = -1; |
188 | 189 | ||
189 | static void sig_handler(int sig) | 190 | static void sig_handler(int sig) |
190 | { | 191 | { |
191 | done = 1; | 192 | done = 1; |
192 | signr = sig; | 193 | signr = sig; |
193 | } | 194 | } |
194 | 195 | ||
195 | static void sig_atexit(void) | 196 | static void sig_atexit(void) |
196 | { | 197 | { |
197 | if (child_pid != -1) | 198 | if (child_pid != -1) |
198 | kill(child_pid, SIGTERM); | 199 | kill(child_pid, SIGTERM); |
199 | 200 | ||
200 | if (signr == -1) | 201 | if (signr == -1) |
201 | return; | 202 | return; |
202 | 203 | ||
203 | signal(signr, SIG_DFL); | 204 | signal(signr, SIG_DFL); |
204 | kill(getpid(), signr); | 205 | kill(getpid(), signr); |
205 | } | 206 | } |
206 | 207 | ||
207 | static int group_fd; | 208 | static int group_fd; |
208 | 209 | ||
209 | static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) | 210 | static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) |
210 | { | 211 | { |
211 | struct perf_header_attr *h_attr; | 212 | struct perf_header_attr *h_attr; |
212 | 213 | ||
213 | if (nr < session->header.attrs) { | 214 | if (nr < session->header.attrs) { |
214 | h_attr = session->header.attr[nr]; | 215 | h_attr = session->header.attr[nr]; |
215 | } else { | 216 | } else { |
216 | h_attr = perf_header_attr__new(a); | 217 | h_attr = perf_header_attr__new(a); |
217 | if (h_attr != NULL) | 218 | if (h_attr != NULL) |
218 | if (perf_header__add_attr(&session->header, h_attr) < 0) { | 219 | if (perf_header__add_attr(&session->header, h_attr) < 0) { |
219 | perf_header_attr__delete(h_attr); | 220 | perf_header_attr__delete(h_attr); |
220 | h_attr = NULL; | 221 | h_attr = NULL; |
221 | } | 222 | } |
222 | } | 223 | } |
223 | 224 | ||
224 | return h_attr; | 225 | return h_attr; |
225 | } | 226 | } |
226 | 227 | ||
227 | static void create_counter(int counter, int cpu, pid_t pid) | 228 | static void create_counter(int counter, int cpu, pid_t pid) |
228 | { | 229 | { |
229 | char *filter = filters[counter]; | 230 | char *filter = filters[counter]; |
230 | struct perf_event_attr *attr = attrs + counter; | 231 | struct perf_event_attr *attr = attrs + counter; |
231 | struct perf_header_attr *h_attr; | 232 | struct perf_header_attr *h_attr; |
232 | int track = !counter; /* only the first counter needs these */ | 233 | int track = !counter; /* only the first counter needs these */ |
233 | int ret; | 234 | int ret; |
234 | struct { | 235 | struct { |
235 | u64 count; | 236 | u64 count; |
236 | u64 time_enabled; | 237 | u64 time_enabled; |
237 | u64 time_running; | 238 | u64 time_running; |
238 | u64 id; | 239 | u64 id; |
239 | } read_data; | 240 | } read_data; |
240 | 241 | ||
241 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 242 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
242 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 243 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
243 | PERF_FORMAT_ID; | 244 | PERF_FORMAT_ID; |
244 | 245 | ||
245 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 246 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
246 | 247 | ||
247 | if (nr_counters > 1) | 248 | if (nr_counters > 1) |
248 | attr->sample_type |= PERF_SAMPLE_ID; | 249 | attr->sample_type |= PERF_SAMPLE_ID; |
249 | 250 | ||
250 | if (freq) { | 251 | if (freq) { |
251 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 252 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
252 | attr->freq = 1; | 253 | attr->freq = 1; |
253 | attr->sample_freq = freq; | 254 | attr->sample_freq = freq; |
254 | } | 255 | } |
255 | 256 | ||
256 | if (no_samples) | 257 | if (no_samples) |
257 | attr->sample_freq = 0; | 258 | attr->sample_freq = 0; |
258 | 259 | ||
259 | if (inherit_stat) | 260 | if (inherit_stat) |
260 | attr->inherit_stat = 1; | 261 | attr->inherit_stat = 1; |
261 | 262 | ||
262 | if (sample_address) | 263 | if (sample_address) |
263 | attr->sample_type |= PERF_SAMPLE_ADDR; | 264 | attr->sample_type |= PERF_SAMPLE_ADDR; |
264 | 265 | ||
265 | if (call_graph) | 266 | if (call_graph) |
266 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 267 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
267 | 268 | ||
268 | if (raw_samples) { | 269 | if (raw_samples) { |
269 | attr->sample_type |= PERF_SAMPLE_TIME; | 270 | attr->sample_type |= PERF_SAMPLE_TIME; |
270 | attr->sample_type |= PERF_SAMPLE_RAW; | 271 | attr->sample_type |= PERF_SAMPLE_RAW; |
271 | attr->sample_type |= PERF_SAMPLE_CPU; | 272 | attr->sample_type |= PERF_SAMPLE_CPU; |
272 | } | 273 | } |
273 | 274 | ||
274 | attr->mmap = track; | 275 | attr->mmap = track; |
275 | attr->comm = track; | 276 | attr->comm = track; |
276 | attr->inherit = inherit; | 277 | attr->inherit = inherit; |
277 | attr->disabled = 1; | 278 | attr->disabled = 1; |
278 | 279 | ||
279 | try_again: | 280 | try_again: |
280 | fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0); | 281 | fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0); |
281 | 282 | ||
282 | if (fd[nr_cpu][counter] < 0) { | 283 | if (fd[nr_cpu][counter] < 0) { |
283 | int err = errno; | 284 | int err = errno; |
284 | 285 | ||
285 | if (err == EPERM || err == EACCES) | 286 | if (err == EPERM || err == EACCES) |
286 | die("Permission error - are you root?\n"); | 287 | die("Permission error - are you root?\n"); |
287 | else if (err == ENODEV && profile_cpu != -1) | 288 | else if (err == ENODEV && profile_cpu != -1) |
288 | die("No such device - did you specify an out-of-range profile CPU?\n"); | 289 | die("No such device - did you specify an out-of-range profile CPU?\n"); |
289 | 290 | ||
290 | /* | 291 | /* |
291 | * If it's cycles then fall back to hrtimer | 292 | * If it's cycles then fall back to hrtimer |
292 | * based cpu-clock-tick sw counter, which | 293 | * based cpu-clock-tick sw counter, which |
293 | * is always available even if no PMU support: | 294 | * is always available even if no PMU support: |
294 | */ | 295 | */ |
295 | if (attr->type == PERF_TYPE_HARDWARE | 296 | if (attr->type == PERF_TYPE_HARDWARE |
296 | && attr->config == PERF_COUNT_HW_CPU_CYCLES) { | 297 | && attr->config == PERF_COUNT_HW_CPU_CYCLES) { |
297 | 298 | ||
298 | if (verbose) | 299 | if (verbose) |
299 | warning(" ... trying to fall back to cpu-clock-ticks\n"); | 300 | warning(" ... trying to fall back to cpu-clock-ticks\n"); |
300 | attr->type = PERF_TYPE_SOFTWARE; | 301 | attr->type = PERF_TYPE_SOFTWARE; |
301 | attr->config = PERF_COUNT_SW_CPU_CLOCK; | 302 | attr->config = PERF_COUNT_SW_CPU_CLOCK; |
302 | goto try_again; | 303 | goto try_again; |
303 | } | 304 | } |
304 | printf("\n"); | 305 | printf("\n"); |
305 | error("perfcounter syscall returned with %d (%s)\n", | 306 | error("perfcounter syscall returned with %d (%s)\n", |
306 | fd[nr_cpu][counter], strerror(err)); | 307 | fd[nr_cpu][counter], strerror(err)); |
307 | 308 | ||
308 | #if defined(__i386__) || defined(__x86_64__) | 309 | #if defined(__i386__) || defined(__x86_64__) |
309 | if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) | 310 | if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) |
310 | die("No hardware sampling interrupt available. No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.\n"); | 311 | die("No hardware sampling interrupt available. No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.\n"); |
311 | #endif | 312 | #endif |
312 | 313 | ||
313 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 314 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
314 | exit(-1); | 315 | exit(-1); |
315 | } | 316 | } |
316 | 317 | ||
317 | h_attr = get_header_attr(attr, counter); | 318 | h_attr = get_header_attr(attr, counter); |
318 | if (h_attr == NULL) | 319 | if (h_attr == NULL) |
319 | die("nomem\n"); | 320 | die("nomem\n"); |
320 | 321 | ||
321 | if (!file_new) { | 322 | if (!file_new) { |
322 | if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { | 323 | if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { |
323 | fprintf(stderr, "incompatible append\n"); | 324 | fprintf(stderr, "incompatible append\n"); |
324 | exit(-1); | 325 | exit(-1); |
325 | } | 326 | } |
326 | } | 327 | } |
327 | 328 | ||
328 | if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) { | 329 | if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) { |
329 | perror("Unable to read perf file descriptor\n"); | 330 | perror("Unable to read perf file descriptor\n"); |
330 | exit(-1); | 331 | exit(-1); |
331 | } | 332 | } |
332 | 333 | ||
333 | if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { | 334 | if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { |
334 | pr_warning("Not enough memory to add id\n"); | 335 | pr_warning("Not enough memory to add id\n"); |
335 | exit(-1); | 336 | exit(-1); |
336 | } | 337 | } |
337 | 338 | ||
338 | assert(fd[nr_cpu][counter] >= 0); | 339 | assert(fd[nr_cpu][counter] >= 0); |
339 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); | 340 | fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); |
340 | 341 | ||
341 | /* | 342 | /* |
342 | * First counter acts as the group leader: | 343 | * First counter acts as the group leader: |
343 | */ | 344 | */ |
344 | if (group && group_fd == -1) | 345 | if (group && group_fd == -1) |
345 | group_fd = fd[nr_cpu][counter]; | 346 | group_fd = fd[nr_cpu][counter]; |
346 | if (multiplex && multiplex_fd == -1) | 347 | if (multiplex && multiplex_fd == -1) |
347 | multiplex_fd = fd[nr_cpu][counter]; | 348 | multiplex_fd = fd[nr_cpu][counter]; |
348 | 349 | ||
349 | if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { | 350 | if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { |
350 | 351 | ||
351 | ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); | 352 | ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); |
352 | assert(ret != -1); | 353 | assert(ret != -1); |
353 | } else { | 354 | } else { |
354 | event_array[nr_poll].fd = fd[nr_cpu][counter]; | 355 | event_array[nr_poll].fd = fd[nr_cpu][counter]; |
355 | event_array[nr_poll].events = POLLIN; | 356 | event_array[nr_poll].events = POLLIN; |
356 | nr_poll++; | 357 | nr_poll++; |
357 | 358 | ||
358 | mmap_array[nr_cpu][counter].counter = counter; | 359 | mmap_array[nr_cpu][counter].counter = counter; |
359 | mmap_array[nr_cpu][counter].prev = 0; | 360 | mmap_array[nr_cpu][counter].prev = 0; |
360 | mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; | 361 | mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; |
361 | mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, | 362 | mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, |
362 | PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); | 363 | PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); |
363 | if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { | 364 | if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { |
364 | error("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 365 | error("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
365 | exit(-1); | 366 | exit(-1); |
366 | } | 367 | } |
367 | } | 368 | } |
368 | 369 | ||
369 | if (filter != NULL) { | 370 | if (filter != NULL) { |
370 | ret = ioctl(fd[nr_cpu][counter], | 371 | ret = ioctl(fd[nr_cpu][counter], |
371 | PERF_EVENT_IOC_SET_FILTER, filter); | 372 | PERF_EVENT_IOC_SET_FILTER, filter); |
372 | if (ret) { | 373 | if (ret) { |
373 | error("failed to set filter with %d (%s)\n", errno, | 374 | error("failed to set filter with %d (%s)\n", errno, |
374 | strerror(errno)); | 375 | strerror(errno)); |
375 | exit(-1); | 376 | exit(-1); |
376 | } | 377 | } |
377 | } | 378 | } |
378 | 379 | ||
379 | ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); | 380 | ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); |
380 | } | 381 | } |
381 | 382 | ||
382 | static void open_counters(int cpu, pid_t pid) | 383 | static void open_counters(int cpu, pid_t pid) |
383 | { | 384 | { |
384 | int counter; | 385 | int counter; |
385 | 386 | ||
386 | group_fd = -1; | 387 | group_fd = -1; |
387 | for (counter = 0; counter < nr_counters; counter++) | 388 | for (counter = 0; counter < nr_counters; counter++) |
388 | create_counter(counter, cpu, pid); | 389 | create_counter(counter, cpu, pid); |
389 | 390 | ||
390 | nr_cpu++; | 391 | nr_cpu++; |
391 | } | 392 | } |
392 | 393 | ||
393 | static int process_buildids(void) | 394 | static int process_buildids(void) |
394 | { | 395 | { |
395 | u64 size = lseek(output, 0, SEEK_CUR); | 396 | u64 size = lseek(output, 0, SEEK_CUR); |
396 | 397 | ||
397 | session->fd = output; | 398 | session->fd = output; |
398 | return __perf_session__process_events(session, post_processing_offset, | 399 | return __perf_session__process_events(session, post_processing_offset, |
399 | size - post_processing_offset, | 400 | size - post_processing_offset, |
400 | size, &build_id__mark_dso_hit_ops); | 401 | size, &build_id__mark_dso_hit_ops); |
401 | } | 402 | } |
402 | 403 | ||
403 | static void atexit_header(void) | 404 | static void atexit_header(void) |
404 | { | 405 | { |
405 | session->header.data_size += bytes_written; | 406 | session->header.data_size += bytes_written; |
406 | 407 | ||
407 | process_buildids(); | 408 | process_buildids(); |
408 | perf_header__write(&session->header, output, true); | 409 | perf_header__write(&session->header, output, true); |
409 | } | 410 | } |
410 | 411 | ||
411 | static int __cmd_record(int argc, const char **argv) | 412 | static int __cmd_record(int argc, const char **argv) |
412 | { | 413 | { |
413 | int i, counter; | 414 | int i, counter; |
414 | struct stat st; | 415 | struct stat st; |
415 | pid_t pid = 0; | 416 | pid_t pid = 0; |
416 | int flags; | 417 | int flags; |
417 | int err; | 418 | int err; |
418 | unsigned long waking = 0; | 419 | unsigned long waking = 0; |
419 | int child_ready_pipe[2], go_pipe[2]; | 420 | int child_ready_pipe[2], go_pipe[2]; |
420 | const bool forks = target_pid == -1 && argc > 0; | 421 | const bool forks = target_pid == -1 && argc > 0; |
421 | char buf; | 422 | char buf; |
422 | 423 | ||
423 | page_size = sysconf(_SC_PAGE_SIZE); | 424 | page_size = sysconf(_SC_PAGE_SIZE); |
424 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
425 | assert(nr_cpus <= MAX_NR_CPUS); | ||
426 | assert(nr_cpus >= 0); | ||
427 | 425 | ||
428 | atexit(sig_atexit); | 426 | atexit(sig_atexit); |
429 | signal(SIGCHLD, sig_handler); | 427 | signal(SIGCHLD, sig_handler); |
430 | signal(SIGINT, sig_handler); | 428 | signal(SIGINT, sig_handler); |
431 | 429 | ||
432 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { | 430 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { |
433 | perror("failed to create pipes"); | 431 | perror("failed to create pipes"); |
434 | exit(-1); | 432 | exit(-1); |
435 | } | 433 | } |
436 | 434 | ||
437 | if (!stat(output_name, &st) && st.st_size) { | 435 | if (!stat(output_name, &st) && st.st_size) { |
438 | if (!force) { | 436 | if (!force) { |
439 | if (!append_file) { | 437 | if (!append_file) { |
440 | pr_err("Error, output file %s exists, use -A " | 438 | pr_err("Error, output file %s exists, use -A " |
441 | "to append or -f to overwrite.\n", | 439 | "to append or -f to overwrite.\n", |
442 | output_name); | 440 | output_name); |
443 | exit(-1); | 441 | exit(-1); |
444 | } | 442 | } |
445 | } else { | 443 | } else { |
446 | char oldname[PATH_MAX]; | 444 | char oldname[PATH_MAX]; |
447 | snprintf(oldname, sizeof(oldname), "%s.old", | 445 | snprintf(oldname, sizeof(oldname), "%s.old", |
448 | output_name); | 446 | output_name); |
449 | unlink(oldname); | 447 | unlink(oldname); |
450 | rename(output_name, oldname); | 448 | rename(output_name, oldname); |
451 | } | 449 | } |
452 | } else { | 450 | } else { |
453 | append_file = 0; | 451 | append_file = 0; |
454 | } | 452 | } |
455 | 453 | ||
456 | flags = O_CREAT|O_RDWR; | 454 | flags = O_CREAT|O_RDWR; |
457 | if (append_file) | 455 | if (append_file) |
458 | file_new = 0; | 456 | file_new = 0; |
459 | else | 457 | else |
460 | flags |= O_TRUNC; | 458 | flags |= O_TRUNC; |
461 | 459 | ||
462 | output = open(output_name, flags, S_IRUSR|S_IWUSR); | 460 | output = open(output_name, flags, S_IRUSR|S_IWUSR); |
463 | if (output < 0) { | 461 | if (output < 0) { |
464 | perror("failed to create output file"); | 462 | perror("failed to create output file"); |
465 | exit(-1); | 463 | exit(-1); |
466 | } | 464 | } |
467 | 465 | ||
468 | session = perf_session__new(output_name, O_WRONLY, force); | 466 | session = perf_session__new(output_name, O_WRONLY, force); |
469 | if (session == NULL) { | 467 | if (session == NULL) { |
470 | pr_err("Not enough memory for reading perf file header\n"); | 468 | pr_err("Not enough memory for reading perf file header\n"); |
471 | return -1; | 469 | return -1; |
472 | } | 470 | } |
473 | 471 | ||
474 | if (!file_new) { | 472 | if (!file_new) { |
475 | err = perf_header__read(&session->header, output); | 473 | err = perf_header__read(&session->header, output); |
476 | if (err < 0) | 474 | if (err < 0) |
477 | return err; | 475 | return err; |
478 | } | 476 | } |
479 | 477 | ||
480 | if (raw_samples) { | 478 | if (raw_samples) { |
481 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); | 479 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); |
482 | } else { | 480 | } else { |
483 | for (i = 0; i < nr_counters; i++) { | 481 | for (i = 0; i < nr_counters; i++) { |
484 | if (attrs[i].sample_type & PERF_SAMPLE_RAW) { | 482 | if (attrs[i].sample_type & PERF_SAMPLE_RAW) { |
485 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); | 483 | perf_header__set_feat(&session->header, HEADER_TRACE_INFO); |
486 | break; | 484 | break; |
487 | } | 485 | } |
488 | } | 486 | } |
489 | } | 487 | } |
490 | 488 | ||
491 | atexit(atexit_header); | 489 | atexit(atexit_header); |
492 | 490 | ||
493 | if (forks) { | 491 | if (forks) { |
494 | pid = fork(); | 492 | pid = fork(); |
495 | if (pid < 0) { | 493 | if (pid < 0) { |
496 | perror("failed to fork"); | 494 | perror("failed to fork"); |
497 | exit(-1); | 495 | exit(-1); |
498 | } | 496 | } |
499 | 497 | ||
500 | if (!pid) { | 498 | if (!pid) { |
501 | close(child_ready_pipe[0]); | 499 | close(child_ready_pipe[0]); |
502 | close(go_pipe[1]); | 500 | close(go_pipe[1]); |
503 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); | 501 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); |
504 | 502 | ||
505 | /* | 503 | /* |
506 | * Do a dummy execvp to get the PLT entry resolved, | 504 | * Do a dummy execvp to get the PLT entry resolved, |
507 | * so we avoid the resolver overhead on the real | 505 | * so we avoid the resolver overhead on the real |
508 | * execvp call. | 506 | * execvp call. |
509 | */ | 507 | */ |
510 | execvp("", (char **)argv); | 508 | execvp("", (char **)argv); |
511 | 509 | ||
512 | /* | 510 | /* |
513 | * Tell the parent we're ready to go | 511 | * Tell the parent we're ready to go |
514 | */ | 512 | */ |
515 | close(child_ready_pipe[1]); | 513 | close(child_ready_pipe[1]); |
516 | 514 | ||
517 | /* | 515 | /* |
518 | * Wait until the parent tells us to go. | 516 | * Wait until the parent tells us to go. |
519 | */ | 517 | */ |
520 | if (read(go_pipe[0], &buf, 1) == -1) | 518 | if (read(go_pipe[0], &buf, 1) == -1) |
521 | perror("unable to read pipe"); | 519 | perror("unable to read pipe"); |
522 | 520 | ||
523 | execvp(argv[0], (char **)argv); | 521 | execvp(argv[0], (char **)argv); |
524 | 522 | ||
525 | perror(argv[0]); | 523 | perror(argv[0]); |
526 | exit(-1); | 524 | exit(-1); |
527 | } | 525 | } |
528 | 526 | ||
529 | child_pid = pid; | 527 | child_pid = pid; |
530 | 528 | ||
531 | if (!system_wide) | 529 | if (!system_wide) |
532 | target_pid = pid; | 530 | target_pid = pid; |
533 | 531 | ||
534 | close(child_ready_pipe[1]); | 532 | close(child_ready_pipe[1]); |
535 | close(go_pipe[0]); | 533 | close(go_pipe[0]); |
536 | /* | 534 | /* |
537 | * wait for child to settle | 535 | * wait for child to settle |
538 | */ | 536 | */ |
539 | if (read(child_ready_pipe[0], &buf, 1) == -1) { | 537 | if (read(child_ready_pipe[0], &buf, 1) == -1) { |
540 | perror("unable to read pipe"); | 538 | perror("unable to read pipe"); |
541 | exit(-1); | 539 | exit(-1); |
542 | } | 540 | } |
543 | close(child_ready_pipe[0]); | 541 | close(child_ready_pipe[0]); |
544 | } | 542 | } |
545 | 543 | ||
546 | 544 | ||
547 | if ((!system_wide && !inherit) || profile_cpu != -1) { | 545 | if ((!system_wide && !inherit) || profile_cpu != -1) { |
548 | open_counters(profile_cpu, target_pid); | 546 | open_counters(profile_cpu, target_pid); |
549 | } else { | 547 | } else { |
548 | nr_cpus = read_cpu_map(); | ||
550 | for (i = 0; i < nr_cpus; i++) | 549 | for (i = 0; i < nr_cpus; i++) |
551 | open_counters(i, target_pid); | 550 | open_counters(cpumap[i], target_pid); |
552 | } | 551 | } |
553 | 552 | ||
554 | if (file_new) { | 553 | if (file_new) { |
555 | err = perf_header__write(&session->header, output, false); | 554 | err = perf_header__write(&session->header, output, false); |
556 | if (err < 0) | 555 | if (err < 0) |
557 | return err; | 556 | return err; |
558 | } | 557 | } |
559 | 558 | ||
560 | post_processing_offset = lseek(output, 0, SEEK_CUR); | 559 | post_processing_offset = lseek(output, 0, SEEK_CUR); |
561 | 560 | ||
562 | err = event__synthesize_kernel_mmap(process_synthesized_event, | 561 | err = event__synthesize_kernel_mmap(process_synthesized_event, |
563 | session, "_text"); | 562 | session, "_text"); |
564 | if (err < 0) { | 563 | if (err < 0) { |
565 | pr_err("Couldn't record kernel reference relocation symbol.\n"); | 564 | pr_err("Couldn't record kernel reference relocation symbol.\n"); |
566 | return err; | 565 | return err; |
567 | } | 566 | } |
568 | 567 | ||
569 | err = event__synthesize_modules(process_synthesized_event, session); | 568 | err = event__synthesize_modules(process_synthesized_event, session); |
570 | if (err < 0) { | 569 | if (err < 0) { |
571 | pr_err("Couldn't record kernel reference relocation symbol.\n"); | 570 | pr_err("Couldn't record kernel reference relocation symbol.\n"); |
572 | return err; | 571 | return err; |
573 | } | 572 | } |
574 | 573 | ||
575 | if (!system_wide && profile_cpu == -1) | 574 | if (!system_wide && profile_cpu == -1) |
576 | event__synthesize_thread(target_pid, process_synthesized_event, | 575 | event__synthesize_thread(target_pid, process_synthesized_event, |
577 | session); | 576 | session); |
578 | else | 577 | else |
579 | event__synthesize_threads(process_synthesized_event, session); | 578 | event__synthesize_threads(process_synthesized_event, session); |
580 | 579 | ||
581 | if (realtime_prio) { | 580 | if (realtime_prio) { |
582 | struct sched_param param; | 581 | struct sched_param param; |
583 | 582 | ||
584 | param.sched_priority = realtime_prio; | 583 | param.sched_priority = realtime_prio; |
585 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 584 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
586 | pr_err("Could not set realtime priority.\n"); | 585 | pr_err("Could not set realtime priority.\n"); |
587 | exit(-1); | 586 | exit(-1); |
588 | } | 587 | } |
589 | } | 588 | } |
590 | 589 | ||
591 | /* | 590 | /* |
592 | * Let the child rip | 591 | * Let the child rip |
593 | */ | 592 | */ |
594 | if (forks) | 593 | if (forks) |
595 | close(go_pipe[1]); | 594 | close(go_pipe[1]); |
596 | 595 | ||
597 | for (;;) { | 596 | for (;;) { |
598 | int hits = samples; | 597 | int hits = samples; |
599 | 598 | ||
600 | for (i = 0; i < nr_cpu; i++) { | 599 | for (i = 0; i < nr_cpu; i++) { |
601 | for (counter = 0; counter < nr_counters; counter++) { | 600 | for (counter = 0; counter < nr_counters; counter++) { |
602 | if (mmap_array[i][counter].base) | 601 | if (mmap_array[i][counter].base) |
603 | mmap_read(&mmap_array[i][counter]); | 602 | mmap_read(&mmap_array[i][counter]); |
604 | } | 603 | } |
605 | } | 604 | } |
606 | 605 | ||
607 | if (hits == samples) { | 606 | if (hits == samples) { |
608 | if (done) | 607 | if (done) |
609 | break; | 608 | break; |
610 | err = poll(event_array, nr_poll, -1); | 609 | err = poll(event_array, nr_poll, -1); |
611 | waking++; | 610 | waking++; |
612 | } | 611 | } |
613 | 612 | ||
614 | if (done) { | 613 | if (done) { |
615 | for (i = 0; i < nr_cpu; i++) { | 614 | for (i = 0; i < nr_cpu; i++) { |
616 | for (counter = 0; counter < nr_counters; counter++) | 615 | for (counter = 0; counter < nr_counters; counter++) |
617 | ioctl(fd[i][counter], PERF_EVENT_IOC_DISABLE); | 616 | ioctl(fd[i][counter], PERF_EVENT_IOC_DISABLE); |
618 | } | 617 | } |
619 | } | 618 | } |
620 | } | 619 | } |
621 | 620 | ||
622 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); | 621 | fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); |
623 | 622 | ||
624 | /* | 623 | /* |
625 | * Approximate RIP event size: 24 bytes. | 624 | * Approximate RIP event size: 24 bytes. |
626 | */ | 625 | */ |
627 | fprintf(stderr, | 626 | fprintf(stderr, |
628 | "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n", | 627 | "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n", |
629 | (double)bytes_written / 1024.0 / 1024.0, | 628 | (double)bytes_written / 1024.0 / 1024.0, |
630 | output_name, | 629 | output_name, |
631 | bytes_written / 24); | 630 | bytes_written / 24); |
632 | 631 | ||
633 | return 0; | 632 | return 0; |
634 | } | 633 | } |
635 | 634 | ||
636 | static const char * const record_usage[] = { | 635 | static const char * const record_usage[] = { |
637 | "perf record [<options>] [<command>]", | 636 | "perf record [<options>] [<command>]", |
638 | "perf record [<options>] -- <command> [<options>]", | 637 | "perf record [<options>] -- <command> [<options>]", |
639 | NULL | 638 | NULL |
640 | }; | 639 | }; |
641 | 640 | ||
642 | static const struct option options[] = { | 641 | static const struct option options[] = { |
643 | OPT_CALLBACK('e', "event", NULL, "event", | 642 | OPT_CALLBACK('e', "event", NULL, "event", |
644 | "event selector. use 'perf list' to list available events", | 643 | "event selector. use 'perf list' to list available events", |
645 | parse_events), | 644 | parse_events), |
646 | OPT_CALLBACK(0, "filter", NULL, "filter", | 645 | OPT_CALLBACK(0, "filter", NULL, "filter", |
647 | "event filter", parse_filter), | 646 | "event filter", parse_filter), |
648 | OPT_INTEGER('p', "pid", &target_pid, | 647 | OPT_INTEGER('p', "pid", &target_pid, |
649 | "record events on existing pid"), | 648 | "record events on existing pid"), |
650 | OPT_INTEGER('r', "realtime", &realtime_prio, | 649 | OPT_INTEGER('r', "realtime", &realtime_prio, |
651 | "collect data with this RT SCHED_FIFO priority"), | 650 | "collect data with this RT SCHED_FIFO priority"), |
652 | OPT_BOOLEAN('R', "raw-samples", &raw_samples, | 651 | OPT_BOOLEAN('R', "raw-samples", &raw_samples, |
653 | "collect raw sample records from all opened counters"), | 652 | "collect raw sample records from all opened counters"), |
654 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 653 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
655 | "system-wide collection from all CPUs"), | 654 | "system-wide collection from all CPUs"), |
656 | OPT_BOOLEAN('A', "append", &append_file, | 655 | OPT_BOOLEAN('A', "append", &append_file, |
657 | "append to the output file to do incremental profiling"), | 656 | "append to the output file to do incremental profiling"), |
658 | OPT_INTEGER('C', "profile_cpu", &profile_cpu, | 657 | OPT_INTEGER('C', "profile_cpu", &profile_cpu, |
659 | "CPU to profile on"), | 658 | "CPU to profile on"), |
660 | OPT_BOOLEAN('f', "force", &force, | 659 | OPT_BOOLEAN('f', "force", &force, |
661 | "overwrite existing data file"), | 660 | "overwrite existing data file"), |
662 | OPT_LONG('c', "count", &default_interval, | 661 | OPT_LONG('c', "count", &default_interval, |
663 | "event period to sample"), | 662 | "event period to sample"), |
664 | OPT_STRING('o', "output", &output_name, "file", | 663 | OPT_STRING('o', "output", &output_name, "file", |
665 | "output file name"), | 664 | "output file name"), |
666 | OPT_BOOLEAN('i', "inherit", &inherit, | 665 | OPT_BOOLEAN('i', "inherit", &inherit, |
667 | "child tasks inherit counters"), | 666 | "child tasks inherit counters"), |
668 | OPT_INTEGER('F', "freq", &freq, | 667 | OPT_INTEGER('F', "freq", &freq, |
669 | "profile at this frequency"), | 668 | "profile at this frequency"), |
670 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, | 669 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, |
671 | "number of mmap data pages"), | 670 | "number of mmap data pages"), |
672 | OPT_BOOLEAN('g', "call-graph", &call_graph, | 671 | OPT_BOOLEAN('g', "call-graph", &call_graph, |
673 | "do call-graph (stack chain/backtrace) recording"), | 672 | "do call-graph (stack chain/backtrace) recording"), |
674 | OPT_BOOLEAN('v', "verbose", &verbose, | 673 | OPT_BOOLEAN('v', "verbose", &verbose, |
675 | "be more verbose (show counter open errors, etc)"), | 674 | "be more verbose (show counter open errors, etc)"), |
676 | OPT_BOOLEAN('s', "stat", &inherit_stat, | 675 | OPT_BOOLEAN('s', "stat", &inherit_stat, |
677 | "per thread counts"), | 676 | "per thread counts"), |
678 | OPT_BOOLEAN('d', "data", &sample_address, | 677 | OPT_BOOLEAN('d', "data", &sample_address, |
679 | "Sample addresses"), | 678 | "Sample addresses"), |
680 | OPT_BOOLEAN('n', "no-samples", &no_samples, | 679 | OPT_BOOLEAN('n', "no-samples", &no_samples, |
681 | "don't sample"), | 680 | "don't sample"), |
682 | OPT_BOOLEAN('M', "multiplex", &multiplex, | 681 | OPT_BOOLEAN('M', "multiplex", &multiplex, |
683 | "multiplex counter output in a single channel"), | 682 | "multiplex counter output in a single channel"), |
684 | OPT_END() | 683 | OPT_END() |
685 | }; | 684 | }; |
686 | 685 | ||
687 | int cmd_record(int argc, const char **argv, const char *prefix __used) | 686 | int cmd_record(int argc, const char **argv, const char *prefix __used) |
688 | { | 687 | { |
689 | int counter; | 688 | int counter; |
690 | 689 | ||
691 | argc = parse_options(argc, argv, options, record_usage, | 690 | argc = parse_options(argc, argv, options, record_usage, |
692 | PARSE_OPT_STOP_AT_NON_OPTION); | 691 | PARSE_OPT_STOP_AT_NON_OPTION); |
693 | if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1) | 692 | if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1) |
694 | usage_with_options(record_usage, options); | 693 | usage_with_options(record_usage, options); |
695 | 694 | ||
696 | symbol__init(); | 695 | symbol__init(); |
697 | 696 | ||
698 | if (!nr_counters) { | 697 | if (!nr_counters) { |
699 | nr_counters = 1; | 698 | nr_counters = 1; |
700 | attrs[0].type = PERF_TYPE_HARDWARE; | 699 | attrs[0].type = PERF_TYPE_HARDWARE; |
701 | attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; | 700 | attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; |
702 | } | 701 | } |
703 | 702 | ||
704 | /* | 703 | /* |
705 | * User specified count overrides default frequency. | 704 | * User specified count overrides default frequency. |
706 | */ | 705 | */ |
707 | if (default_interval) | 706 | if (default_interval) |
708 | freq = 0; | 707 | freq = 0; |
709 | else if (freq) { | 708 | else if (freq) { |
710 | default_interval = freq; | 709 | default_interval = freq; |
711 | } else { | 710 | } else { |
712 | fprintf(stderr, "frequency and count are zero, aborting\n"); | 711 | fprintf(stderr, "frequency and count are zero, aborting\n"); |
713 | exit(EXIT_FAILURE); | 712 | exit(EXIT_FAILURE); |
714 | } | 713 | } |
715 | 714 | ||
716 | for (counter = 0; counter < nr_counters; counter++) { | 715 | for (counter = 0; counter < nr_counters; counter++) { |
717 | if (attrs[counter].sample_period) | 716 | if (attrs[counter].sample_period) |
718 | continue; | 717 | continue; |
719 | 718 | ||
720 | attrs[counter].sample_period = default_interval; | 719 | attrs[counter].sample_period = default_interval; |
721 | } | 720 | } |
722 | 721 | ||
723 | return __cmd_record(argc, argv); | 722 | return __cmd_record(argc, argv); |
tools/perf/builtin-stat.c
1 | /* | 1 | /* |
2 | * builtin-stat.c | 2 | * builtin-stat.c |
3 | * | 3 | * |
4 | * Builtin stat command: Give a precise performance counters summary | 4 | * Builtin stat command: Give a precise performance counters summary |
5 | * overview about any workload, CPU or specific PID. | 5 | * overview about any workload, CPU or specific PID. |
6 | * | 6 | * |
7 | * Sample output: | 7 | * Sample output: |
8 | 8 | ||
9 | $ perf stat ~/hackbench 10 | 9 | $ perf stat ~/hackbench 10 |
10 | Time: 0.104 | 10 | Time: 0.104 |
11 | 11 | ||
12 | Performance counter stats for '/home/mingo/hackbench': | 12 | Performance counter stats for '/home/mingo/hackbench': |
13 | 13 | ||
14 | 1255.538611 task clock ticks # 10.143 CPU utilization factor | 14 | 1255.538611 task clock ticks # 10.143 CPU utilization factor |
15 | 54011 context switches # 0.043 M/sec | 15 | 54011 context switches # 0.043 M/sec |
16 | 385 CPU migrations # 0.000 M/sec | 16 | 385 CPU migrations # 0.000 M/sec |
17 | 17755 pagefaults # 0.014 M/sec | 17 | 17755 pagefaults # 0.014 M/sec |
18 | 3808323185 CPU cycles # 3033.219 M/sec | 18 | 3808323185 CPU cycles # 3033.219 M/sec |
19 | 1575111190 instructions # 1254.530 M/sec | 19 | 1575111190 instructions # 1254.530 M/sec |
20 | 17367895 cache references # 13.833 M/sec | 20 | 17367895 cache references # 13.833 M/sec |
21 | 7674421 cache misses # 6.112 M/sec | 21 | 7674421 cache misses # 6.112 M/sec |
22 | 22 | ||
23 | Wall-clock time elapsed: 123.786620 msecs | 23 | Wall-clock time elapsed: 123.786620 msecs |
24 | 24 | ||
25 | * | 25 | * |
26 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> | 26 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> |
27 | * | 27 | * |
28 | * Improvements and fixes by: | 28 | * Improvements and fixes by: |
29 | * | 29 | * |
30 | * Arjan van de Ven <arjan@linux.intel.com> | 30 | * Arjan van de Ven <arjan@linux.intel.com> |
31 | * Yanmin Zhang <yanmin.zhang@intel.com> | 31 | * Yanmin Zhang <yanmin.zhang@intel.com> |
32 | * Wu Fengguang <fengguang.wu@intel.com> | 32 | * Wu Fengguang <fengguang.wu@intel.com> |
33 | * Mike Galbraith <efault@gmx.de> | 33 | * Mike Galbraith <efault@gmx.de> |
34 | * Paul Mackerras <paulus@samba.org> | 34 | * Paul Mackerras <paulus@samba.org> |
35 | * Jaswinder Singh Rajput <jaswinder@kernel.org> | 35 | * Jaswinder Singh Rajput <jaswinder@kernel.org> |
36 | * | 36 | * |
37 | * Released under the GPL v2. (and only v2, not any later version) | 37 | * Released under the GPL v2. (and only v2, not any later version) |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include "perf.h" | 40 | #include "perf.h" |
41 | #include "builtin.h" | 41 | #include "builtin.h" |
42 | #include "util/util.h" | 42 | #include "util/util.h" |
43 | #include "util/parse-options.h" | 43 | #include "util/parse-options.h" |
44 | #include "util/parse-events.h" | 44 | #include "util/parse-events.h" |
45 | #include "util/event.h" | 45 | #include "util/event.h" |
46 | #include "util/debug.h" | 46 | #include "util/debug.h" |
47 | #include "util/header.h" | 47 | #include "util/header.h" |
48 | #include "util/cpumap.h" | ||
48 | 49 | ||
49 | #include <sys/prctl.h> | 50 | #include <sys/prctl.h> |
50 | #include <math.h> | 51 | #include <math.h> |
51 | 52 | ||
52 | static struct perf_event_attr default_attrs[] = { | 53 | static struct perf_event_attr default_attrs[] = { |
53 | 54 | ||
54 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, | 55 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, |
55 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, | 56 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, |
56 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, | 57 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, |
57 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, | 58 | { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, |
58 | 59 | ||
59 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, | 60 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, |
60 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, | 61 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, |
61 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, | 62 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, |
62 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, | 63 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, |
63 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES }, | 64 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES }, |
64 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, | 65 | { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, |
65 | 66 | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | static int system_wide = 0; | 69 | static int system_wide = 0; |
69 | static unsigned int nr_cpus = 0; | 70 | static unsigned int nr_cpus = 0; |
70 | static int run_idx = 0; | 71 | static int run_idx = 0; |
71 | 72 | ||
72 | static int run_count = 1; | 73 | static int run_count = 1; |
73 | static int inherit = 1; | 74 | static int inherit = 1; |
74 | static int scale = 1; | 75 | static int scale = 1; |
75 | static pid_t target_pid = -1; | 76 | static pid_t target_pid = -1; |
76 | static pid_t child_pid = -1; | 77 | static pid_t child_pid = -1; |
77 | static int null_run = 0; | 78 | static int null_run = 0; |
78 | 79 | ||
79 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; | 80 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; |
80 | 81 | ||
81 | static int event_scaled[MAX_COUNTERS]; | 82 | static int event_scaled[MAX_COUNTERS]; |
82 | 83 | ||
83 | static volatile int done = 0; | 84 | static volatile int done = 0; |
84 | 85 | ||
85 | struct stats | 86 | struct stats |
86 | { | 87 | { |
87 | double n, mean, M2; | 88 | double n, mean, M2; |
88 | }; | 89 | }; |
89 | 90 | ||
90 | static void update_stats(struct stats *stats, u64 val) | 91 | static void update_stats(struct stats *stats, u64 val) |
91 | { | 92 | { |
92 | double delta; | 93 | double delta; |
93 | 94 | ||
94 | stats->n++; | 95 | stats->n++; |
95 | delta = val - stats->mean; | 96 | delta = val - stats->mean; |
96 | stats->mean += delta / stats->n; | 97 | stats->mean += delta / stats->n; |
97 | stats->M2 += delta*(val - stats->mean); | 98 | stats->M2 += delta*(val - stats->mean); |
98 | } | 99 | } |
99 | 100 | ||
100 | static double avg_stats(struct stats *stats) | 101 | static double avg_stats(struct stats *stats) |
101 | { | 102 | { |
102 | return stats->mean; | 103 | return stats->mean; |
103 | } | 104 | } |
104 | 105 | ||
105 | /* | 106 | /* |
106 | * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance | 107 | * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance |
107 | * | 108 | * |
108 | * (\Sum n_i^2) - ((\Sum n_i)^2)/n | 109 | * (\Sum n_i^2) - ((\Sum n_i)^2)/n |
109 | * s^2 = ------------------------------- | 110 | * s^2 = ------------------------------- |
110 | * n - 1 | 111 | * n - 1 |
111 | * | 112 | * |
112 | * http://en.wikipedia.org/wiki/Stddev | 113 | * http://en.wikipedia.org/wiki/Stddev |
113 | * | 114 | * |
114 | * The std dev of the mean is related to the std dev by: | 115 | * The std dev of the mean is related to the std dev by: |
115 | * | 116 | * |
116 | * s | 117 | * s |
117 | * s_mean = ------- | 118 | * s_mean = ------- |
118 | * sqrt(n) | 119 | * sqrt(n) |
119 | * | 120 | * |
120 | */ | 121 | */ |
121 | static double stddev_stats(struct stats *stats) | 122 | static double stddev_stats(struct stats *stats) |
122 | { | 123 | { |
123 | double variance = stats->M2 / (stats->n - 1); | 124 | double variance = stats->M2 / (stats->n - 1); |
124 | double variance_mean = variance / stats->n; | 125 | double variance_mean = variance / stats->n; |
125 | 126 | ||
126 | return sqrt(variance_mean); | 127 | return sqrt(variance_mean); |
127 | } | 128 | } |
128 | 129 | ||
129 | struct stats event_res_stats[MAX_COUNTERS][3]; | 130 | struct stats event_res_stats[MAX_COUNTERS][3]; |
130 | struct stats runtime_nsecs_stats; | 131 | struct stats runtime_nsecs_stats; |
131 | struct stats walltime_nsecs_stats; | 132 | struct stats walltime_nsecs_stats; |
132 | struct stats runtime_cycles_stats; | 133 | struct stats runtime_cycles_stats; |
133 | struct stats runtime_branches_stats; | 134 | struct stats runtime_branches_stats; |
134 | 135 | ||
135 | #define MATCH_EVENT(t, c, counter) \ | 136 | #define MATCH_EVENT(t, c, counter) \ |
136 | (attrs[counter].type == PERF_TYPE_##t && \ | 137 | (attrs[counter].type == PERF_TYPE_##t && \ |
137 | attrs[counter].config == PERF_COUNT_##c) | 138 | attrs[counter].config == PERF_COUNT_##c) |
138 | 139 | ||
139 | #define ERR_PERF_OPEN \ | 140 | #define ERR_PERF_OPEN \ |
140 | "Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n" | 141 | "Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n" |
141 | 142 | ||
142 | static void create_perf_stat_counter(int counter, int pid) | 143 | static void create_perf_stat_counter(int counter, int pid) |
143 | { | 144 | { |
144 | struct perf_event_attr *attr = attrs + counter; | 145 | struct perf_event_attr *attr = attrs + counter; |
145 | 146 | ||
146 | if (scale) | 147 | if (scale) |
147 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 148 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
148 | PERF_FORMAT_TOTAL_TIME_RUNNING; | 149 | PERF_FORMAT_TOTAL_TIME_RUNNING; |
149 | 150 | ||
150 | if (system_wide) { | 151 | if (system_wide) { |
151 | unsigned int cpu; | 152 | unsigned int cpu; |
152 | 153 | ||
153 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 154 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
154 | fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0); | 155 | fd[cpu][counter] = sys_perf_event_open(attr, -1, cpumap[cpu], -1, 0); |
155 | if (fd[cpu][counter] < 0 && verbose) | 156 | if (fd[cpu][counter] < 0 && verbose) |
156 | fprintf(stderr, ERR_PERF_OPEN, counter, | 157 | fprintf(stderr, ERR_PERF_OPEN, counter, |
157 | fd[cpu][counter], strerror(errno)); | 158 | fd[cpu][counter], strerror(errno)); |
158 | } | 159 | } |
159 | } else { | 160 | } else { |
160 | attr->inherit = inherit; | 161 | attr->inherit = inherit; |
161 | attr->disabled = 1; | 162 | attr->disabled = 1; |
162 | attr->enable_on_exec = 1; | 163 | attr->enable_on_exec = 1; |
163 | 164 | ||
164 | fd[0][counter] = sys_perf_event_open(attr, pid, -1, -1, 0); | 165 | fd[0][counter] = sys_perf_event_open(attr, pid, -1, -1, 0); |
165 | if (fd[0][counter] < 0 && verbose) | 166 | if (fd[0][counter] < 0 && verbose) |
166 | fprintf(stderr, ERR_PERF_OPEN, counter, | 167 | fprintf(stderr, ERR_PERF_OPEN, counter, |
167 | fd[0][counter], strerror(errno)); | 168 | fd[0][counter], strerror(errno)); |
168 | } | 169 | } |
169 | } | 170 | } |
170 | 171 | ||
171 | /* | 172 | /* |
172 | * Does the counter have nsecs as a unit? | 173 | * Does the counter have nsecs as a unit? |
173 | */ | 174 | */ |
174 | static inline int nsec_counter(int counter) | 175 | static inline int nsec_counter(int counter) |
175 | { | 176 | { |
176 | if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || | 177 | if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || |
177 | MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) | 178 | MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) |
178 | return 1; | 179 | return 1; |
179 | 180 | ||
180 | return 0; | 181 | return 0; |
181 | } | 182 | } |
182 | 183 | ||
183 | /* | 184 | /* |
184 | * Read out the results of a single counter: | 185 | * Read out the results of a single counter: |
185 | */ | 186 | */ |
186 | static void read_counter(int counter) | 187 | static void read_counter(int counter) |
187 | { | 188 | { |
188 | u64 count[3], single_count[3]; | 189 | u64 count[3], single_count[3]; |
189 | unsigned int cpu; | 190 | unsigned int cpu; |
190 | size_t res, nv; | 191 | size_t res, nv; |
191 | int scaled; | 192 | int scaled; |
192 | int i; | 193 | int i; |
193 | 194 | ||
194 | count[0] = count[1] = count[2] = 0; | 195 | count[0] = count[1] = count[2] = 0; |
195 | 196 | ||
196 | nv = scale ? 3 : 1; | 197 | nv = scale ? 3 : 1; |
197 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 198 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
198 | if (fd[cpu][counter] < 0) | 199 | if (fd[cpu][counter] < 0) |
199 | continue; | 200 | continue; |
200 | 201 | ||
201 | res = read(fd[cpu][counter], single_count, nv * sizeof(u64)); | 202 | res = read(fd[cpu][counter], single_count, nv * sizeof(u64)); |
202 | assert(res == nv * sizeof(u64)); | 203 | assert(res == nv * sizeof(u64)); |
203 | 204 | ||
204 | close(fd[cpu][counter]); | 205 | close(fd[cpu][counter]); |
205 | fd[cpu][counter] = -1; | 206 | fd[cpu][counter] = -1; |
206 | 207 | ||
207 | count[0] += single_count[0]; | 208 | count[0] += single_count[0]; |
208 | if (scale) { | 209 | if (scale) { |
209 | count[1] += single_count[1]; | 210 | count[1] += single_count[1]; |
210 | count[2] += single_count[2]; | 211 | count[2] += single_count[2]; |
211 | } | 212 | } |
212 | } | 213 | } |
213 | 214 | ||
214 | scaled = 0; | 215 | scaled = 0; |
215 | if (scale) { | 216 | if (scale) { |
216 | if (count[2] == 0) { | 217 | if (count[2] == 0) { |
217 | event_scaled[counter] = -1; | 218 | event_scaled[counter] = -1; |
218 | count[0] = 0; | 219 | count[0] = 0; |
219 | return; | 220 | return; |
220 | } | 221 | } |
221 | 222 | ||
222 | if (count[2] < count[1]) { | 223 | if (count[2] < count[1]) { |
223 | event_scaled[counter] = 1; | 224 | event_scaled[counter] = 1; |
224 | count[0] = (unsigned long long) | 225 | count[0] = (unsigned long long) |
225 | ((double)count[0] * count[1] / count[2] + 0.5); | 226 | ((double)count[0] * count[1] / count[2] + 0.5); |
226 | } | 227 | } |
227 | } | 228 | } |
228 | 229 | ||
229 | for (i = 0; i < 3; i++) | 230 | for (i = 0; i < 3; i++) |
230 | update_stats(&event_res_stats[counter][i], count[i]); | 231 | update_stats(&event_res_stats[counter][i], count[i]); |
231 | 232 | ||
232 | if (verbose) { | 233 | if (verbose) { |
233 | fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), | 234 | fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), |
234 | count[0], count[1], count[2]); | 235 | count[0], count[1], count[2]); |
235 | } | 236 | } |
236 | 237 | ||
237 | /* | 238 | /* |
238 | * Save the full runtime - to allow normalization during printout: | 239 | * Save the full runtime - to allow normalization during printout: |
239 | */ | 240 | */ |
240 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) | 241 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) |
241 | update_stats(&runtime_nsecs_stats, count[0]); | 242 | update_stats(&runtime_nsecs_stats, count[0]); |
242 | if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) | 243 | if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) |
243 | update_stats(&runtime_cycles_stats, count[0]); | 244 | update_stats(&runtime_cycles_stats, count[0]); |
244 | if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) | 245 | if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) |
245 | update_stats(&runtime_branches_stats, count[0]); | 246 | update_stats(&runtime_branches_stats, count[0]); |
246 | } | 247 | } |
247 | 248 | ||
248 | static int run_perf_stat(int argc __used, const char **argv) | 249 | static int run_perf_stat(int argc __used, const char **argv) |
249 | { | 250 | { |
250 | unsigned long long t0, t1; | 251 | unsigned long long t0, t1; |
251 | int status = 0; | 252 | int status = 0; |
252 | int counter; | 253 | int counter; |
253 | int pid = target_pid; | 254 | int pid = target_pid; |
254 | int child_ready_pipe[2], go_pipe[2]; | 255 | int child_ready_pipe[2], go_pipe[2]; |
255 | const bool forks = (target_pid == -1 && argc > 0); | 256 | const bool forks = (target_pid == -1 && argc > 0); |
256 | char buf; | 257 | char buf; |
257 | 258 | ||
258 | if (!system_wide) | 259 | if (!system_wide) |
259 | nr_cpus = 1; | 260 | nr_cpus = 1; |
260 | 261 | ||
261 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { | 262 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { |
262 | perror("failed to create pipes"); | 263 | perror("failed to create pipes"); |
263 | exit(1); | 264 | exit(1); |
264 | } | 265 | } |
265 | 266 | ||
266 | if (forks) { | 267 | if (forks) { |
267 | if ((pid = fork()) < 0) | 268 | if ((pid = fork()) < 0) |
268 | perror("failed to fork"); | 269 | perror("failed to fork"); |
269 | 270 | ||
270 | if (!pid) { | 271 | if (!pid) { |
271 | close(child_ready_pipe[0]); | 272 | close(child_ready_pipe[0]); |
272 | close(go_pipe[1]); | 273 | close(go_pipe[1]); |
273 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); | 274 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); |
274 | 275 | ||
275 | /* | 276 | /* |
276 | * Do a dummy execvp to get the PLT entry resolved, | 277 | * Do a dummy execvp to get the PLT entry resolved, |
277 | * so we avoid the resolver overhead on the real | 278 | * so we avoid the resolver overhead on the real |
278 | * execvp call. | 279 | * execvp call. |
279 | */ | 280 | */ |
280 | execvp("", (char **)argv); | 281 | execvp("", (char **)argv); |
281 | 282 | ||
282 | /* | 283 | /* |
283 | * Tell the parent we're ready to go | 284 | * Tell the parent we're ready to go |
284 | */ | 285 | */ |
285 | close(child_ready_pipe[1]); | 286 | close(child_ready_pipe[1]); |
286 | 287 | ||
287 | /* | 288 | /* |
288 | * Wait until the parent tells us to go. | 289 | * Wait until the parent tells us to go. |
289 | */ | 290 | */ |
290 | if (read(go_pipe[0], &buf, 1) == -1) | 291 | if (read(go_pipe[0], &buf, 1) == -1) |
291 | perror("unable to read pipe"); | 292 | perror("unable to read pipe"); |
292 | 293 | ||
293 | execvp(argv[0], (char **)argv); | 294 | execvp(argv[0], (char **)argv); |
294 | 295 | ||
295 | perror(argv[0]); | 296 | perror(argv[0]); |
296 | exit(-1); | 297 | exit(-1); |
297 | } | 298 | } |
298 | 299 | ||
299 | child_pid = pid; | 300 | child_pid = pid; |
300 | 301 | ||
301 | /* | 302 | /* |
302 | * Wait for the child to be ready to exec. | 303 | * Wait for the child to be ready to exec. |
303 | */ | 304 | */ |
304 | close(child_ready_pipe[1]); | 305 | close(child_ready_pipe[1]); |
305 | close(go_pipe[0]); | 306 | close(go_pipe[0]); |
306 | if (read(child_ready_pipe[0], &buf, 1) == -1) | 307 | if (read(child_ready_pipe[0], &buf, 1) == -1) |
307 | perror("unable to read pipe"); | 308 | perror("unable to read pipe"); |
308 | close(child_ready_pipe[0]); | 309 | close(child_ready_pipe[0]); |
309 | } | 310 | } |
310 | 311 | ||
311 | for (counter = 0; counter < nr_counters; counter++) | 312 | for (counter = 0; counter < nr_counters; counter++) |
312 | create_perf_stat_counter(counter, pid); | 313 | create_perf_stat_counter(counter, pid); |
313 | 314 | ||
314 | /* | 315 | /* |
315 | * Enable counters and exec the command: | 316 | * Enable counters and exec the command: |
316 | */ | 317 | */ |
317 | t0 = rdclock(); | 318 | t0 = rdclock(); |
318 | 319 | ||
319 | if (forks) { | 320 | if (forks) { |
320 | close(go_pipe[1]); | 321 | close(go_pipe[1]); |
321 | wait(&status); | 322 | wait(&status); |
322 | } else { | 323 | } else { |
323 | while(!done); | 324 | while(!done); |
324 | } | 325 | } |
325 | 326 | ||
326 | t1 = rdclock(); | 327 | t1 = rdclock(); |
327 | 328 | ||
328 | update_stats(&walltime_nsecs_stats, t1 - t0); | 329 | update_stats(&walltime_nsecs_stats, t1 - t0); |
329 | 330 | ||
330 | for (counter = 0; counter < nr_counters; counter++) | 331 | for (counter = 0; counter < nr_counters; counter++) |
331 | read_counter(counter); | 332 | read_counter(counter); |
332 | 333 | ||
333 | return WEXITSTATUS(status); | 334 | return WEXITSTATUS(status); |
334 | } | 335 | } |
335 | 336 | ||
336 | static void print_noise(int counter, double avg) | 337 | static void print_noise(int counter, double avg) |
337 | { | 338 | { |
338 | if (run_count == 1) | 339 | if (run_count == 1) |
339 | return; | 340 | return; |
340 | 341 | ||
341 | fprintf(stderr, " ( +- %7.3f%% )", | 342 | fprintf(stderr, " ( +- %7.3f%% )", |
342 | 100 * stddev_stats(&event_res_stats[counter][0]) / avg); | 343 | 100 * stddev_stats(&event_res_stats[counter][0]) / avg); |
343 | } | 344 | } |
344 | 345 | ||
345 | static void nsec_printout(int counter, double avg) | 346 | static void nsec_printout(int counter, double avg) |
346 | { | 347 | { |
347 | double msecs = avg / 1e6; | 348 | double msecs = avg / 1e6; |
348 | 349 | ||
349 | fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); | 350 | fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); |
350 | 351 | ||
351 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { | 352 | if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { |
352 | fprintf(stderr, " # %10.3f CPUs ", | 353 | fprintf(stderr, " # %10.3f CPUs ", |
353 | avg / avg_stats(&walltime_nsecs_stats)); | 354 | avg / avg_stats(&walltime_nsecs_stats)); |
354 | } | 355 | } |
355 | } | 356 | } |
356 | 357 | ||
357 | static void abs_printout(int counter, double avg) | 358 | static void abs_printout(int counter, double avg) |
358 | { | 359 | { |
359 | double total, ratio = 0.0; | 360 | double total, ratio = 0.0; |
360 | 361 | ||
361 | fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); | 362 | fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); |
362 | 363 | ||
363 | if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { | 364 | if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { |
364 | total = avg_stats(&runtime_cycles_stats); | 365 | total = avg_stats(&runtime_cycles_stats); |
365 | 366 | ||
366 | if (total) | 367 | if (total) |
367 | ratio = avg / total; | 368 | ratio = avg / total; |
368 | 369 | ||
369 | fprintf(stderr, " # %10.3f IPC ", ratio); | 370 | fprintf(stderr, " # %10.3f IPC ", ratio); |
370 | } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && | 371 | } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && |
371 | runtime_branches_stats.n != 0) { | 372 | runtime_branches_stats.n != 0) { |
372 | total = avg_stats(&runtime_branches_stats); | 373 | total = avg_stats(&runtime_branches_stats); |
373 | 374 | ||
374 | if (total) | 375 | if (total) |
375 | ratio = avg * 100 / total; | 376 | ratio = avg * 100 / total; |
376 | 377 | ||
377 | fprintf(stderr, " # %10.3f %% ", ratio); | 378 | fprintf(stderr, " # %10.3f %% ", ratio); |
378 | 379 | ||
379 | } else if (runtime_nsecs_stats.n != 0) { | 380 | } else if (runtime_nsecs_stats.n != 0) { |
380 | total = avg_stats(&runtime_nsecs_stats); | 381 | total = avg_stats(&runtime_nsecs_stats); |
381 | 382 | ||
382 | if (total) | 383 | if (total) |
383 | ratio = 1000.0 * avg / total; | 384 | ratio = 1000.0 * avg / total; |
384 | 385 | ||
385 | fprintf(stderr, " # %10.3f M/sec", ratio); | 386 | fprintf(stderr, " # %10.3f M/sec", ratio); |
386 | } | 387 | } |
387 | } | 388 | } |
388 | 389 | ||
389 | /* | 390 | /* |
390 | * Print out the results of a single counter: | 391 | * Print out the results of a single counter: |
391 | */ | 392 | */ |
392 | static void print_counter(int counter) | 393 | static void print_counter(int counter) |
393 | { | 394 | { |
394 | double avg = avg_stats(&event_res_stats[counter][0]); | 395 | double avg = avg_stats(&event_res_stats[counter][0]); |
395 | int scaled = event_scaled[counter]; | 396 | int scaled = event_scaled[counter]; |
396 | 397 | ||
397 | if (scaled == -1) { | 398 | if (scaled == -1) { |
398 | fprintf(stderr, " %14s %-24s\n", | 399 | fprintf(stderr, " %14s %-24s\n", |
399 | "<not counted>", event_name(counter)); | 400 | "<not counted>", event_name(counter)); |
400 | return; | 401 | return; |
401 | } | 402 | } |
402 | 403 | ||
403 | if (nsec_counter(counter)) | 404 | if (nsec_counter(counter)) |
404 | nsec_printout(counter, avg); | 405 | nsec_printout(counter, avg); |
405 | else | 406 | else |
406 | abs_printout(counter, avg); | 407 | abs_printout(counter, avg); |
407 | 408 | ||
408 | print_noise(counter, avg); | 409 | print_noise(counter, avg); |
409 | 410 | ||
410 | if (scaled) { | 411 | if (scaled) { |
411 | double avg_enabled, avg_running; | 412 | double avg_enabled, avg_running; |
412 | 413 | ||
413 | avg_enabled = avg_stats(&event_res_stats[counter][1]); | 414 | avg_enabled = avg_stats(&event_res_stats[counter][1]); |
414 | avg_running = avg_stats(&event_res_stats[counter][2]); | 415 | avg_running = avg_stats(&event_res_stats[counter][2]); |
415 | 416 | ||
416 | fprintf(stderr, " (scaled from %.2f%%)", | 417 | fprintf(stderr, " (scaled from %.2f%%)", |
417 | 100 * avg_running / avg_enabled); | 418 | 100 * avg_running / avg_enabled); |
418 | } | 419 | } |
419 | 420 | ||
420 | fprintf(stderr, "\n"); | 421 | fprintf(stderr, "\n"); |
421 | } | 422 | } |
422 | 423 | ||
423 | static void print_stat(int argc, const char **argv) | 424 | static void print_stat(int argc, const char **argv) |
424 | { | 425 | { |
425 | int i, counter; | 426 | int i, counter; |
426 | 427 | ||
427 | fflush(stdout); | 428 | fflush(stdout); |
428 | 429 | ||
429 | fprintf(stderr, "\n"); | 430 | fprintf(stderr, "\n"); |
430 | fprintf(stderr, " Performance counter stats for "); | 431 | fprintf(stderr, " Performance counter stats for "); |
431 | if(target_pid == -1) { | 432 | if(target_pid == -1) { |
432 | fprintf(stderr, "\'%s", argv[0]); | 433 | fprintf(stderr, "\'%s", argv[0]); |
433 | for (i = 1; i < argc; i++) | 434 | for (i = 1; i < argc; i++) |
434 | fprintf(stderr, " %s", argv[i]); | 435 | fprintf(stderr, " %s", argv[i]); |
435 | }else | 436 | }else |
436 | fprintf(stderr, "task pid \'%d", target_pid); | 437 | fprintf(stderr, "task pid \'%d", target_pid); |
437 | 438 | ||
438 | fprintf(stderr, "\'"); | 439 | fprintf(stderr, "\'"); |
439 | if (run_count > 1) | 440 | if (run_count > 1) |
440 | fprintf(stderr, " (%d runs)", run_count); | 441 | fprintf(stderr, " (%d runs)", run_count); |
441 | fprintf(stderr, ":\n\n"); | 442 | fprintf(stderr, ":\n\n"); |
442 | 443 | ||
443 | for (counter = 0; counter < nr_counters; counter++) | 444 | for (counter = 0; counter < nr_counters; counter++) |
444 | print_counter(counter); | 445 | print_counter(counter); |
445 | 446 | ||
446 | fprintf(stderr, "\n"); | 447 | fprintf(stderr, "\n"); |
447 | fprintf(stderr, " %14.9f seconds time elapsed", | 448 | fprintf(stderr, " %14.9f seconds time elapsed", |
448 | avg_stats(&walltime_nsecs_stats)/1e9); | 449 | avg_stats(&walltime_nsecs_stats)/1e9); |
449 | if (run_count > 1) { | 450 | if (run_count > 1) { |
450 | fprintf(stderr, " ( +- %7.3f%% )", | 451 | fprintf(stderr, " ( +- %7.3f%% )", |
451 | 100*stddev_stats(&walltime_nsecs_stats) / | 452 | 100*stddev_stats(&walltime_nsecs_stats) / |
452 | avg_stats(&walltime_nsecs_stats)); | 453 | avg_stats(&walltime_nsecs_stats)); |
453 | } | 454 | } |
454 | fprintf(stderr, "\n\n"); | 455 | fprintf(stderr, "\n\n"); |
455 | } | 456 | } |
456 | 457 | ||
457 | static volatile int signr = -1; | 458 | static volatile int signr = -1; |
458 | 459 | ||
459 | static void skip_signal(int signo) | 460 | static void skip_signal(int signo) |
460 | { | 461 | { |
461 | if(target_pid != -1) | 462 | if(target_pid != -1) |
462 | done = 1; | 463 | done = 1; |
463 | 464 | ||
464 | signr = signo; | 465 | signr = signo; |
465 | } | 466 | } |
466 | 467 | ||
467 | static void sig_atexit(void) | 468 | static void sig_atexit(void) |
468 | { | 469 | { |
469 | if (child_pid != -1) | 470 | if (child_pid != -1) |
470 | kill(child_pid, SIGTERM); | 471 | kill(child_pid, SIGTERM); |
471 | 472 | ||
472 | if (signr == -1) | 473 | if (signr == -1) |
473 | return; | 474 | return; |
474 | 475 | ||
475 | signal(signr, SIG_DFL); | 476 | signal(signr, SIG_DFL); |
476 | kill(getpid(), signr); | 477 | kill(getpid(), signr); |
477 | } | 478 | } |
478 | 479 | ||
479 | static const char * const stat_usage[] = { | 480 | static const char * const stat_usage[] = { |
480 | "perf stat [<options>] [<command>]", | 481 | "perf stat [<options>] [<command>]", |
481 | NULL | 482 | NULL |
482 | }; | 483 | }; |
483 | 484 | ||
484 | static const struct option options[] = { | 485 | static const struct option options[] = { |
485 | OPT_CALLBACK('e', "event", NULL, "event", | 486 | OPT_CALLBACK('e', "event", NULL, "event", |
486 | "event selector. use 'perf list' to list available events", | 487 | "event selector. use 'perf list' to list available events", |
487 | parse_events), | 488 | parse_events), |
488 | OPT_BOOLEAN('i', "inherit", &inherit, | 489 | OPT_BOOLEAN('i', "inherit", &inherit, |
489 | "child tasks inherit counters"), | 490 | "child tasks inherit counters"), |
490 | OPT_INTEGER('p', "pid", &target_pid, | 491 | OPT_INTEGER('p', "pid", &target_pid, |
491 | "stat events on existing pid"), | 492 | "stat events on existing pid"), |
492 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 493 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
493 | "system-wide collection from all CPUs"), | 494 | "system-wide collection from all CPUs"), |
494 | OPT_BOOLEAN('c', "scale", &scale, | 495 | OPT_BOOLEAN('c', "scale", &scale, |
495 | "scale/normalize counters"), | 496 | "scale/normalize counters"), |
496 | OPT_BOOLEAN('v', "verbose", &verbose, | 497 | OPT_BOOLEAN('v', "verbose", &verbose, |
497 | "be more verbose (show counter open errors, etc)"), | 498 | "be more verbose (show counter open errors, etc)"), |
498 | OPT_INTEGER('r', "repeat", &run_count, | 499 | OPT_INTEGER('r', "repeat", &run_count, |
499 | "repeat command and print average + stddev (max: 100)"), | 500 | "repeat command and print average + stddev (max: 100)"), |
500 | OPT_BOOLEAN('n', "null", &null_run, | 501 | OPT_BOOLEAN('n', "null", &null_run, |
501 | "null run - dont start any counters"), | 502 | "null run - dont start any counters"), |
502 | OPT_END() | 503 | OPT_END() |
503 | }; | 504 | }; |
504 | 505 | ||
505 | int cmd_stat(int argc, const char **argv, const char *prefix __used) | 506 | int cmd_stat(int argc, const char **argv, const char *prefix __used) |
506 | { | 507 | { |
507 | int status; | 508 | int status; |
508 | 509 | ||
509 | argc = parse_options(argc, argv, options, stat_usage, | 510 | argc = parse_options(argc, argv, options, stat_usage, |
510 | PARSE_OPT_STOP_AT_NON_OPTION); | 511 | PARSE_OPT_STOP_AT_NON_OPTION); |
511 | if (!argc && target_pid == -1) | 512 | if (!argc && target_pid == -1) |
512 | usage_with_options(stat_usage, options); | 513 | usage_with_options(stat_usage, options); |
513 | if (run_count <= 0) | 514 | if (run_count <= 0) |
514 | usage_with_options(stat_usage, options); | 515 | usage_with_options(stat_usage, options); |
515 | 516 | ||
516 | /* Set attrs and nr_counters if no event is selected and !null_run */ | 517 | /* Set attrs and nr_counters if no event is selected and !null_run */ |
517 | if (!null_run && !nr_counters) { | 518 | if (!null_run && !nr_counters) { |
518 | memcpy(attrs, default_attrs, sizeof(default_attrs)); | 519 | memcpy(attrs, default_attrs, sizeof(default_attrs)); |
519 | nr_counters = ARRAY_SIZE(default_attrs); | 520 | nr_counters = ARRAY_SIZE(default_attrs); |
520 | } | 521 | } |
521 | 522 | ||
522 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | 523 | if (system_wide) |
523 | assert(nr_cpus <= MAX_NR_CPUS); | 524 | nr_cpus = read_cpu_map(); |
524 | assert((int)nr_cpus >= 0); | 525 | else |
526 | nr_cpus = 1; | ||
525 | 527 | ||
526 | /* | 528 | /* |
527 | * We dont want to block the signals - that would cause | 529 | * We dont want to block the signals - that would cause |
528 | * child tasks to inherit that and Ctrl-C would not work. | 530 | * child tasks to inherit that and Ctrl-C would not work. |
529 | * What we want is for Ctrl-C to work in the exec()-ed | 531 | * What we want is for Ctrl-C to work in the exec()-ed |
530 | * task, but being ignored by perf stat itself: | 532 | * task, but being ignored by perf stat itself: |
531 | */ | 533 | */ |
532 | atexit(sig_atexit); | 534 | atexit(sig_atexit); |
533 | signal(SIGINT, skip_signal); | 535 | signal(SIGINT, skip_signal); |
534 | signal(SIGALRM, skip_signal); | 536 | signal(SIGALRM, skip_signal); |
535 | signal(SIGABRT, skip_signal); | 537 | signal(SIGABRT, skip_signal); |
536 | 538 | ||
537 | status = 0; | 539 | status = 0; |
538 | for (run_idx = 0; run_idx < run_count; run_idx++) { | 540 | for (run_idx = 0; run_idx < run_count; run_idx++) { |
539 | if (run_count != 1 && verbose) | 541 | if (run_count != 1 && verbose) |
540 | fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); | 542 | fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); |
541 | status = run_perf_stat(argc, argv); | 543 | status = run_perf_stat(argc, argv); |
542 | } | 544 | } |
543 | 545 | ||
544 | print_stat(argc, argv); | 546 | print_stat(argc, argv); |
545 | 547 | ||
546 | return status; | 548 | return status; |
547 | } | 549 | } |
548 | 550 |
tools/perf/builtin-top.c
1 | /* | 1 | /* |
2 | * builtin-top.c | 2 | * builtin-top.c |
3 | * | 3 | * |
4 | * Builtin top command: Display a continuously updated profile of | 4 | * Builtin top command: Display a continuously updated profile of |
5 | * any workload, CPU or specific PID. | 5 | * any workload, CPU or specific PID. |
6 | * | 6 | * |
7 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> | 7 | * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> |
8 | * | 8 | * |
9 | * Improvements and fixes by: | 9 | * Improvements and fixes by: |
10 | * | 10 | * |
11 | * Arjan van de Ven <arjan@linux.intel.com> | 11 | * Arjan van de Ven <arjan@linux.intel.com> |
12 | * Yanmin Zhang <yanmin.zhang@intel.com> | 12 | * Yanmin Zhang <yanmin.zhang@intel.com> |
13 | * Wu Fengguang <fengguang.wu@intel.com> | 13 | * Wu Fengguang <fengguang.wu@intel.com> |
14 | * Mike Galbraith <efault@gmx.de> | 14 | * Mike Galbraith <efault@gmx.de> |
15 | * Paul Mackerras <paulus@samba.org> | 15 | * Paul Mackerras <paulus@samba.org> |
16 | * | 16 | * |
17 | * Released under the GPL v2. (and only v2, not any later version) | 17 | * Released under the GPL v2. (and only v2, not any later version) |
18 | */ | 18 | */ |
19 | #include "builtin.h" | 19 | #include "builtin.h" |
20 | 20 | ||
21 | #include "perf.h" | 21 | #include "perf.h" |
22 | 22 | ||
23 | #include "util/color.h" | 23 | #include "util/color.h" |
24 | #include "util/session.h" | 24 | #include "util/session.h" |
25 | #include "util/symbol.h" | 25 | #include "util/symbol.h" |
26 | #include "util/thread.h" | 26 | #include "util/thread.h" |
27 | #include "util/util.h" | 27 | #include "util/util.h" |
28 | #include <linux/rbtree.h> | 28 | #include <linux/rbtree.h> |
29 | #include "util/parse-options.h" | 29 | #include "util/parse-options.h" |
30 | #include "util/parse-events.h" | 30 | #include "util/parse-events.h" |
31 | #include "util/cpumap.h" | ||
31 | 32 | ||
32 | #include "util/debug.h" | 33 | #include "util/debug.h" |
33 | 34 | ||
34 | #include <assert.h> | 35 | #include <assert.h> |
35 | #include <fcntl.h> | 36 | #include <fcntl.h> |
36 | 37 | ||
37 | #include <stdio.h> | 38 | #include <stdio.h> |
38 | #include <termios.h> | 39 | #include <termios.h> |
39 | #include <unistd.h> | 40 | #include <unistd.h> |
40 | 41 | ||
41 | #include <errno.h> | 42 | #include <errno.h> |
42 | #include <time.h> | 43 | #include <time.h> |
43 | #include <sched.h> | 44 | #include <sched.h> |
44 | #include <pthread.h> | 45 | #include <pthread.h> |
45 | 46 | ||
46 | #include <sys/syscall.h> | 47 | #include <sys/syscall.h> |
47 | #include <sys/ioctl.h> | 48 | #include <sys/ioctl.h> |
48 | #include <sys/poll.h> | 49 | #include <sys/poll.h> |
49 | #include <sys/prctl.h> | 50 | #include <sys/prctl.h> |
50 | #include <sys/wait.h> | 51 | #include <sys/wait.h> |
51 | #include <sys/uio.h> | 52 | #include <sys/uio.h> |
52 | #include <sys/mman.h> | 53 | #include <sys/mman.h> |
53 | 54 | ||
54 | #include <linux/unistd.h> | 55 | #include <linux/unistd.h> |
55 | #include <linux/types.h> | 56 | #include <linux/types.h> |
56 | 57 | ||
57 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; | 58 | static int fd[MAX_NR_CPUS][MAX_COUNTERS]; |
58 | 59 | ||
59 | static int system_wide = 0; | 60 | static int system_wide = 0; |
60 | 61 | ||
61 | static int default_interval = 0; | 62 | static int default_interval = 0; |
62 | 63 | ||
63 | static int count_filter = 5; | 64 | static int count_filter = 5; |
64 | static int print_entries; | 65 | static int print_entries; |
65 | 66 | ||
66 | static int target_pid = -1; | 67 | static int target_pid = -1; |
67 | static int inherit = 0; | 68 | static int inherit = 0; |
68 | static int profile_cpu = -1; | 69 | static int profile_cpu = -1; |
69 | static int nr_cpus = 0; | 70 | static int nr_cpus = 0; |
70 | static unsigned int realtime_prio = 0; | 71 | static unsigned int realtime_prio = 0; |
71 | static int group = 0; | 72 | static int group = 0; |
72 | static unsigned int page_size; | 73 | static unsigned int page_size; |
73 | static unsigned int mmap_pages = 16; | 74 | static unsigned int mmap_pages = 16; |
74 | static int freq = 1000; /* 1 KHz */ | 75 | static int freq = 1000; /* 1 KHz */ |
75 | 76 | ||
76 | static int delay_secs = 2; | 77 | static int delay_secs = 2; |
77 | static int zero = 0; | 78 | static int zero = 0; |
78 | static int dump_symtab = 0; | 79 | static int dump_symtab = 0; |
79 | 80 | ||
80 | static bool hide_kernel_symbols = false; | 81 | static bool hide_kernel_symbols = false; |
81 | static bool hide_user_symbols = false; | 82 | static bool hide_user_symbols = false; |
82 | static struct winsize winsize; | 83 | static struct winsize winsize; |
83 | 84 | ||
84 | /* | 85 | /* |
85 | * Source | 86 | * Source |
86 | */ | 87 | */ |
87 | 88 | ||
88 | struct source_line { | 89 | struct source_line { |
89 | u64 eip; | 90 | u64 eip; |
90 | unsigned long count[MAX_COUNTERS]; | 91 | unsigned long count[MAX_COUNTERS]; |
91 | char *line; | 92 | char *line; |
92 | struct source_line *next; | 93 | struct source_line *next; |
93 | }; | 94 | }; |
94 | 95 | ||
95 | static char *sym_filter = NULL; | 96 | static char *sym_filter = NULL; |
96 | struct sym_entry *sym_filter_entry = NULL; | 97 | struct sym_entry *sym_filter_entry = NULL; |
97 | struct sym_entry *sym_filter_entry_sched = NULL; | 98 | struct sym_entry *sym_filter_entry_sched = NULL; |
98 | static int sym_pcnt_filter = 5; | 99 | static int sym_pcnt_filter = 5; |
99 | static int sym_counter = 0; | 100 | static int sym_counter = 0; |
100 | static int display_weighted = -1; | 101 | static int display_weighted = -1; |
101 | 102 | ||
102 | /* | 103 | /* |
103 | * Symbols | 104 | * Symbols |
104 | */ | 105 | */ |
105 | 106 | ||
106 | struct sym_entry_source { | 107 | struct sym_entry_source { |
107 | struct source_line *source; | 108 | struct source_line *source; |
108 | struct source_line *lines; | 109 | struct source_line *lines; |
109 | struct source_line **lines_tail; | 110 | struct source_line **lines_tail; |
110 | pthread_mutex_t lock; | 111 | pthread_mutex_t lock; |
111 | }; | 112 | }; |
112 | 113 | ||
113 | struct sym_entry { | 114 | struct sym_entry { |
114 | struct rb_node rb_node; | 115 | struct rb_node rb_node; |
115 | struct list_head node; | 116 | struct list_head node; |
116 | unsigned long snap_count; | 117 | unsigned long snap_count; |
117 | double weight; | 118 | double weight; |
118 | int skip; | 119 | int skip; |
119 | u16 name_len; | 120 | u16 name_len; |
120 | u8 origin; | 121 | u8 origin; |
121 | struct map *map; | 122 | struct map *map; |
122 | struct sym_entry_source *src; | 123 | struct sym_entry_source *src; |
123 | unsigned long count[0]; | 124 | unsigned long count[0]; |
124 | }; | 125 | }; |
125 | 126 | ||
126 | /* | 127 | /* |
127 | * Source functions | 128 | * Source functions |
128 | */ | 129 | */ |
129 | 130 | ||
130 | static inline struct symbol *sym_entry__symbol(struct sym_entry *self) | 131 | static inline struct symbol *sym_entry__symbol(struct sym_entry *self) |
131 | { | 132 | { |
132 | return ((void *)self) + symbol_conf.priv_size; | 133 | return ((void *)self) + symbol_conf.priv_size; |
133 | } | 134 | } |
134 | 135 | ||
135 | static void get_term_dimensions(struct winsize *ws) | 136 | static void get_term_dimensions(struct winsize *ws) |
136 | { | 137 | { |
137 | char *s = getenv("LINES"); | 138 | char *s = getenv("LINES"); |
138 | 139 | ||
139 | if (s != NULL) { | 140 | if (s != NULL) { |
140 | ws->ws_row = atoi(s); | 141 | ws->ws_row = atoi(s); |
141 | s = getenv("COLUMNS"); | 142 | s = getenv("COLUMNS"); |
142 | if (s != NULL) { | 143 | if (s != NULL) { |
143 | ws->ws_col = atoi(s); | 144 | ws->ws_col = atoi(s); |
144 | if (ws->ws_row && ws->ws_col) | 145 | if (ws->ws_row && ws->ws_col) |
145 | return; | 146 | return; |
146 | } | 147 | } |
147 | } | 148 | } |
148 | #ifdef TIOCGWINSZ | 149 | #ifdef TIOCGWINSZ |
149 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && | 150 | if (ioctl(1, TIOCGWINSZ, ws) == 0 && |
150 | ws->ws_row && ws->ws_col) | 151 | ws->ws_row && ws->ws_col) |
151 | return; | 152 | return; |
152 | #endif | 153 | #endif |
153 | ws->ws_row = 25; | 154 | ws->ws_row = 25; |
154 | ws->ws_col = 80; | 155 | ws->ws_col = 80; |
155 | } | 156 | } |
156 | 157 | ||
157 | static void update_print_entries(struct winsize *ws) | 158 | static void update_print_entries(struct winsize *ws) |
158 | { | 159 | { |
159 | print_entries = ws->ws_row; | 160 | print_entries = ws->ws_row; |
160 | 161 | ||
161 | if (print_entries > 9) | 162 | if (print_entries > 9) |
162 | print_entries -= 9; | 163 | print_entries -= 9; |
163 | } | 164 | } |
164 | 165 | ||
165 | static void sig_winch_handler(int sig __used) | 166 | static void sig_winch_handler(int sig __used) |
166 | { | 167 | { |
167 | get_term_dimensions(&winsize); | 168 | get_term_dimensions(&winsize); |
168 | update_print_entries(&winsize); | 169 | update_print_entries(&winsize); |
169 | } | 170 | } |
170 | 171 | ||
171 | static void parse_source(struct sym_entry *syme) | 172 | static void parse_source(struct sym_entry *syme) |
172 | { | 173 | { |
173 | struct symbol *sym; | 174 | struct symbol *sym; |
174 | struct sym_entry_source *source; | 175 | struct sym_entry_source *source; |
175 | struct map *map; | 176 | struct map *map; |
176 | FILE *file; | 177 | FILE *file; |
177 | char command[PATH_MAX*2]; | 178 | char command[PATH_MAX*2]; |
178 | const char *path; | 179 | const char *path; |
179 | u64 len; | 180 | u64 len; |
180 | 181 | ||
181 | if (!syme) | 182 | if (!syme) |
182 | return; | 183 | return; |
183 | 184 | ||
184 | if (syme->src == NULL) { | 185 | if (syme->src == NULL) { |
185 | syme->src = zalloc(sizeof(*source)); | 186 | syme->src = zalloc(sizeof(*source)); |
186 | if (syme->src == NULL) | 187 | if (syme->src == NULL) |
187 | return; | 188 | return; |
188 | pthread_mutex_init(&syme->src->lock, NULL); | 189 | pthread_mutex_init(&syme->src->lock, NULL); |
189 | } | 190 | } |
190 | 191 | ||
191 | source = syme->src; | 192 | source = syme->src; |
192 | 193 | ||
193 | if (source->lines) { | 194 | if (source->lines) { |
194 | pthread_mutex_lock(&source->lock); | 195 | pthread_mutex_lock(&source->lock); |
195 | goto out_assign; | 196 | goto out_assign; |
196 | } | 197 | } |
197 | 198 | ||
198 | sym = sym_entry__symbol(syme); | 199 | sym = sym_entry__symbol(syme); |
199 | map = syme->map; | 200 | map = syme->map; |
200 | path = map->dso->long_name; | 201 | path = map->dso->long_name; |
201 | 202 | ||
202 | len = sym->end - sym->start; | 203 | len = sym->end - sym->start; |
203 | 204 | ||
204 | sprintf(command, | 205 | sprintf(command, |
205 | "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s", | 206 | "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s", |
206 | BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start), | 207 | BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start), |
207 | BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path); | 208 | BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path); |
208 | 209 | ||
209 | file = popen(command, "r"); | 210 | file = popen(command, "r"); |
210 | if (!file) | 211 | if (!file) |
211 | return; | 212 | return; |
212 | 213 | ||
213 | pthread_mutex_lock(&source->lock); | 214 | pthread_mutex_lock(&source->lock); |
214 | source->lines_tail = &source->lines; | 215 | source->lines_tail = &source->lines; |
215 | while (!feof(file)) { | 216 | while (!feof(file)) { |
216 | struct source_line *src; | 217 | struct source_line *src; |
217 | size_t dummy = 0; | 218 | size_t dummy = 0; |
218 | char *c, *sep; | 219 | char *c, *sep; |
219 | 220 | ||
220 | src = malloc(sizeof(struct source_line)); | 221 | src = malloc(sizeof(struct source_line)); |
221 | assert(src != NULL); | 222 | assert(src != NULL); |
222 | memset(src, 0, sizeof(struct source_line)); | 223 | memset(src, 0, sizeof(struct source_line)); |
223 | 224 | ||
224 | if (getline(&src->line, &dummy, file) < 0) | 225 | if (getline(&src->line, &dummy, file) < 0) |
225 | break; | 226 | break; |
226 | if (!src->line) | 227 | if (!src->line) |
227 | break; | 228 | break; |
228 | 229 | ||
229 | c = strchr(src->line, '\n'); | 230 | c = strchr(src->line, '\n'); |
230 | if (c) | 231 | if (c) |
231 | *c = 0; | 232 | *c = 0; |
232 | 233 | ||
233 | src->next = NULL; | 234 | src->next = NULL; |
234 | *source->lines_tail = src; | 235 | *source->lines_tail = src; |
235 | source->lines_tail = &src->next; | 236 | source->lines_tail = &src->next; |
236 | 237 | ||
237 | src->eip = strtoull(src->line, &sep, 16); | 238 | src->eip = strtoull(src->line, &sep, 16); |
238 | if (*sep == ':') | 239 | if (*sep == ':') |
239 | src->eip = map__objdump_2ip(map, src->eip); | 240 | src->eip = map__objdump_2ip(map, src->eip); |
240 | else /* this line has no ip info (e.g. source line) */ | 241 | else /* this line has no ip info (e.g. source line) */ |
241 | src->eip = 0; | 242 | src->eip = 0; |
242 | } | 243 | } |
243 | pclose(file); | 244 | pclose(file); |
244 | out_assign: | 245 | out_assign: |
245 | sym_filter_entry = syme; | 246 | sym_filter_entry = syme; |
246 | pthread_mutex_unlock(&source->lock); | 247 | pthread_mutex_unlock(&source->lock); |
247 | } | 248 | } |
248 | 249 | ||
249 | static void __zero_source_counters(struct sym_entry *syme) | 250 | static void __zero_source_counters(struct sym_entry *syme) |
250 | { | 251 | { |
251 | int i; | 252 | int i; |
252 | struct source_line *line; | 253 | struct source_line *line; |
253 | 254 | ||
254 | line = syme->src->lines; | 255 | line = syme->src->lines; |
255 | while (line) { | 256 | while (line) { |
256 | for (i = 0; i < nr_counters; i++) | 257 | for (i = 0; i < nr_counters; i++) |
257 | line->count[i] = 0; | 258 | line->count[i] = 0; |
258 | line = line->next; | 259 | line = line->next; |
259 | } | 260 | } |
260 | } | 261 | } |
261 | 262 | ||
262 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | 263 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) |
263 | { | 264 | { |
264 | struct source_line *line; | 265 | struct source_line *line; |
265 | 266 | ||
266 | if (syme != sym_filter_entry) | 267 | if (syme != sym_filter_entry) |
267 | return; | 268 | return; |
268 | 269 | ||
269 | if (pthread_mutex_trylock(&syme->src->lock)) | 270 | if (pthread_mutex_trylock(&syme->src->lock)) |
270 | return; | 271 | return; |
271 | 272 | ||
272 | if (syme->src == NULL || syme->src->source == NULL) | 273 | if (syme->src == NULL || syme->src->source == NULL) |
273 | goto out_unlock; | 274 | goto out_unlock; |
274 | 275 | ||
275 | for (line = syme->src->lines; line; line = line->next) { | 276 | for (line = syme->src->lines; line; line = line->next) { |
276 | /* skip lines without IP info */ | 277 | /* skip lines without IP info */ |
277 | if (line->eip == 0) | 278 | if (line->eip == 0) |
278 | continue; | 279 | continue; |
279 | if (line->eip == ip) { | 280 | if (line->eip == ip) { |
280 | line->count[counter]++; | 281 | line->count[counter]++; |
281 | break; | 282 | break; |
282 | } | 283 | } |
283 | if (line->eip > ip) | 284 | if (line->eip > ip) |
284 | break; | 285 | break; |
285 | } | 286 | } |
286 | out_unlock: | 287 | out_unlock: |
287 | pthread_mutex_unlock(&syme->src->lock); | 288 | pthread_mutex_unlock(&syme->src->lock); |
288 | } | 289 | } |
289 | 290 | ||
290 | #define PATTERN_LEN (BITS_PER_LONG / 4 + 2) | 291 | #define PATTERN_LEN (BITS_PER_LONG / 4 + 2) |
291 | 292 | ||
292 | static void lookup_sym_source(struct sym_entry *syme) | 293 | static void lookup_sym_source(struct sym_entry *syme) |
293 | { | 294 | { |
294 | struct symbol *symbol = sym_entry__symbol(syme); | 295 | struct symbol *symbol = sym_entry__symbol(syme); |
295 | struct source_line *line; | 296 | struct source_line *line; |
296 | char pattern[PATTERN_LEN + 1]; | 297 | char pattern[PATTERN_LEN + 1]; |
297 | 298 | ||
298 | sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4, | 299 | sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4, |
299 | map__rip_2objdump(syme->map, symbol->start)); | 300 | map__rip_2objdump(syme->map, symbol->start)); |
300 | 301 | ||
301 | pthread_mutex_lock(&syme->src->lock); | 302 | pthread_mutex_lock(&syme->src->lock); |
302 | for (line = syme->src->lines; line; line = line->next) { | 303 | for (line = syme->src->lines; line; line = line->next) { |
303 | if (memcmp(line->line, pattern, PATTERN_LEN) == 0) { | 304 | if (memcmp(line->line, pattern, PATTERN_LEN) == 0) { |
304 | syme->src->source = line; | 305 | syme->src->source = line; |
305 | break; | 306 | break; |
306 | } | 307 | } |
307 | } | 308 | } |
308 | pthread_mutex_unlock(&syme->src->lock); | 309 | pthread_mutex_unlock(&syme->src->lock); |
309 | } | 310 | } |
310 | 311 | ||
311 | static void show_lines(struct source_line *queue, int count, int total) | 312 | static void show_lines(struct source_line *queue, int count, int total) |
312 | { | 313 | { |
313 | int i; | 314 | int i; |
314 | struct source_line *line; | 315 | struct source_line *line; |
315 | 316 | ||
316 | line = queue; | 317 | line = queue; |
317 | for (i = 0; i < count; i++) { | 318 | for (i = 0; i < count; i++) { |
318 | float pcnt = 100.0*(float)line->count[sym_counter]/(float)total; | 319 | float pcnt = 100.0*(float)line->count[sym_counter]/(float)total; |
319 | 320 | ||
320 | printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); | 321 | printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); |
321 | line = line->next; | 322 | line = line->next; |
322 | } | 323 | } |
323 | } | 324 | } |
324 | 325 | ||
325 | #define TRACE_COUNT 3 | 326 | #define TRACE_COUNT 3 |
326 | 327 | ||
327 | static void show_details(struct sym_entry *syme) | 328 | static void show_details(struct sym_entry *syme) |
328 | { | 329 | { |
329 | struct symbol *symbol; | 330 | struct symbol *symbol; |
330 | struct source_line *line; | 331 | struct source_line *line; |
331 | struct source_line *line_queue = NULL; | 332 | struct source_line *line_queue = NULL; |
332 | int displayed = 0; | 333 | int displayed = 0; |
333 | int line_queue_count = 0, total = 0, more = 0; | 334 | int line_queue_count = 0, total = 0, more = 0; |
334 | 335 | ||
335 | if (!syme) | 336 | if (!syme) |
336 | return; | 337 | return; |
337 | 338 | ||
338 | if (!syme->src->source) | 339 | if (!syme->src->source) |
339 | lookup_sym_source(syme); | 340 | lookup_sym_source(syme); |
340 | 341 | ||
341 | if (!syme->src->source) | 342 | if (!syme->src->source) |
342 | return; | 343 | return; |
343 | 344 | ||
344 | symbol = sym_entry__symbol(syme); | 345 | symbol = sym_entry__symbol(syme); |
345 | printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); | 346 | printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); |
346 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); | 347 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); |
347 | 348 | ||
348 | pthread_mutex_lock(&syme->src->lock); | 349 | pthread_mutex_lock(&syme->src->lock); |
349 | line = syme->src->source; | 350 | line = syme->src->source; |
350 | while (line) { | 351 | while (line) { |
351 | total += line->count[sym_counter]; | 352 | total += line->count[sym_counter]; |
352 | line = line->next; | 353 | line = line->next; |
353 | } | 354 | } |
354 | 355 | ||
355 | line = syme->src->source; | 356 | line = syme->src->source; |
356 | while (line) { | 357 | while (line) { |
357 | float pcnt = 0.0; | 358 | float pcnt = 0.0; |
358 | 359 | ||
359 | if (!line_queue_count) | 360 | if (!line_queue_count) |
360 | line_queue = line; | 361 | line_queue = line; |
361 | line_queue_count++; | 362 | line_queue_count++; |
362 | 363 | ||
363 | if (line->count[sym_counter]) | 364 | if (line->count[sym_counter]) |
364 | pcnt = 100.0 * line->count[sym_counter] / (float)total; | 365 | pcnt = 100.0 * line->count[sym_counter] / (float)total; |
365 | if (pcnt >= (float)sym_pcnt_filter) { | 366 | if (pcnt >= (float)sym_pcnt_filter) { |
366 | if (displayed <= print_entries) | 367 | if (displayed <= print_entries) |
367 | show_lines(line_queue, line_queue_count, total); | 368 | show_lines(line_queue, line_queue_count, total); |
368 | else more++; | 369 | else more++; |
369 | displayed += line_queue_count; | 370 | displayed += line_queue_count; |
370 | line_queue_count = 0; | 371 | line_queue_count = 0; |
371 | line_queue = NULL; | 372 | line_queue = NULL; |
372 | } else if (line_queue_count > TRACE_COUNT) { | 373 | } else if (line_queue_count > TRACE_COUNT) { |
373 | line_queue = line_queue->next; | 374 | line_queue = line_queue->next; |
374 | line_queue_count--; | 375 | line_queue_count--; |
375 | } | 376 | } |
376 | 377 | ||
377 | line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; | 378 | line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; |
378 | line = line->next; | 379 | line = line->next; |
379 | } | 380 | } |
380 | pthread_mutex_unlock(&syme->src->lock); | 381 | pthread_mutex_unlock(&syme->src->lock); |
381 | if (more) | 382 | if (more) |
382 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); | 383 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); |
383 | } | 384 | } |
384 | 385 | ||
385 | /* | 386 | /* |
386 | * Symbols will be added here in event__process_sample and will get out | 387 | * Symbols will be added here in event__process_sample and will get out |
387 | * after decayed. | 388 | * after decayed. |
388 | */ | 389 | */ |
389 | static LIST_HEAD(active_symbols); | 390 | static LIST_HEAD(active_symbols); |
390 | static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; | 391 | static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; |
391 | 392 | ||
392 | /* | 393 | /* |
393 | * Ordering weight: count-1 * count-2 * ... / count-n | 394 | * Ordering weight: count-1 * count-2 * ... / count-n |
394 | */ | 395 | */ |
395 | static double sym_weight(const struct sym_entry *sym) | 396 | static double sym_weight(const struct sym_entry *sym) |
396 | { | 397 | { |
397 | double weight = sym->snap_count; | 398 | double weight = sym->snap_count; |
398 | int counter; | 399 | int counter; |
399 | 400 | ||
400 | if (!display_weighted) | 401 | if (!display_weighted) |
401 | return weight; | 402 | return weight; |
402 | 403 | ||
403 | for (counter = 1; counter < nr_counters-1; counter++) | 404 | for (counter = 1; counter < nr_counters-1; counter++) |
404 | weight *= sym->count[counter]; | 405 | weight *= sym->count[counter]; |
405 | 406 | ||
406 | weight /= (sym->count[counter] + 1); | 407 | weight /= (sym->count[counter] + 1); |
407 | 408 | ||
408 | return weight; | 409 | return weight; |
409 | } | 410 | } |
410 | 411 | ||
411 | static long samples; | 412 | static long samples; |
412 | static long userspace_samples; | 413 | static long userspace_samples; |
413 | static const char CONSOLE_CLEAR[] = "[H[2J"; | 414 | static const char CONSOLE_CLEAR[] = "[H[2J"; |
414 | 415 | ||
415 | static void __list_insert_active_sym(struct sym_entry *syme) | 416 | static void __list_insert_active_sym(struct sym_entry *syme) |
416 | { | 417 | { |
417 | list_add(&syme->node, &active_symbols); | 418 | list_add(&syme->node, &active_symbols); |
418 | } | 419 | } |
419 | 420 | ||
420 | static void list_remove_active_sym(struct sym_entry *syme) | 421 | static void list_remove_active_sym(struct sym_entry *syme) |
421 | { | 422 | { |
422 | pthread_mutex_lock(&active_symbols_lock); | 423 | pthread_mutex_lock(&active_symbols_lock); |
423 | list_del_init(&syme->node); | 424 | list_del_init(&syme->node); |
424 | pthread_mutex_unlock(&active_symbols_lock); | 425 | pthread_mutex_unlock(&active_symbols_lock); |
425 | } | 426 | } |
426 | 427 | ||
427 | static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | 428 | static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) |
428 | { | 429 | { |
429 | struct rb_node **p = &tree->rb_node; | 430 | struct rb_node **p = &tree->rb_node; |
430 | struct rb_node *parent = NULL; | 431 | struct rb_node *parent = NULL; |
431 | struct sym_entry *iter; | 432 | struct sym_entry *iter; |
432 | 433 | ||
433 | while (*p != NULL) { | 434 | while (*p != NULL) { |
434 | parent = *p; | 435 | parent = *p; |
435 | iter = rb_entry(parent, struct sym_entry, rb_node); | 436 | iter = rb_entry(parent, struct sym_entry, rb_node); |
436 | 437 | ||
437 | if (se->weight > iter->weight) | 438 | if (se->weight > iter->weight) |
438 | p = &(*p)->rb_left; | 439 | p = &(*p)->rb_left; |
439 | else | 440 | else |
440 | p = &(*p)->rb_right; | 441 | p = &(*p)->rb_right; |
441 | } | 442 | } |
442 | 443 | ||
443 | rb_link_node(&se->rb_node, parent, p); | 444 | rb_link_node(&se->rb_node, parent, p); |
444 | rb_insert_color(&se->rb_node, tree); | 445 | rb_insert_color(&se->rb_node, tree); |
445 | } | 446 | } |
446 | 447 | ||
447 | static void print_sym_table(void) | 448 | static void print_sym_table(void) |
448 | { | 449 | { |
449 | int printed = 0, j; | 450 | int printed = 0, j; |
450 | int counter, snap = !display_weighted ? sym_counter : 0; | 451 | int counter, snap = !display_weighted ? sym_counter : 0; |
451 | float samples_per_sec = samples/delay_secs; | 452 | float samples_per_sec = samples/delay_secs; |
452 | float ksamples_per_sec = (samples-userspace_samples)/delay_secs; | 453 | float ksamples_per_sec = (samples-userspace_samples)/delay_secs; |
453 | float sum_ksamples = 0.0; | 454 | float sum_ksamples = 0.0; |
454 | struct sym_entry *syme, *n; | 455 | struct sym_entry *syme, *n; |
455 | struct rb_root tmp = RB_ROOT; | 456 | struct rb_root tmp = RB_ROOT; |
456 | struct rb_node *nd; | 457 | struct rb_node *nd; |
457 | int sym_width = 0, dso_width = 0, max_dso_width; | 458 | int sym_width = 0, dso_width = 0, max_dso_width; |
458 | const int win_width = winsize.ws_col - 1; | 459 | const int win_width = winsize.ws_col - 1; |
459 | 460 | ||
460 | samples = userspace_samples = 0; | 461 | samples = userspace_samples = 0; |
461 | 462 | ||
462 | /* Sort the active symbols */ | 463 | /* Sort the active symbols */ |
463 | pthread_mutex_lock(&active_symbols_lock); | 464 | pthread_mutex_lock(&active_symbols_lock); |
464 | syme = list_entry(active_symbols.next, struct sym_entry, node); | 465 | syme = list_entry(active_symbols.next, struct sym_entry, node); |
465 | pthread_mutex_unlock(&active_symbols_lock); | 466 | pthread_mutex_unlock(&active_symbols_lock); |
466 | 467 | ||
467 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { | 468 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { |
468 | syme->snap_count = syme->count[snap]; | 469 | syme->snap_count = syme->count[snap]; |
469 | if (syme->snap_count != 0) { | 470 | if (syme->snap_count != 0) { |
470 | 471 | ||
471 | if ((hide_user_symbols && | 472 | if ((hide_user_symbols && |
472 | syme->origin == PERF_RECORD_MISC_USER) || | 473 | syme->origin == PERF_RECORD_MISC_USER) || |
473 | (hide_kernel_symbols && | 474 | (hide_kernel_symbols && |
474 | syme->origin == PERF_RECORD_MISC_KERNEL)) { | 475 | syme->origin == PERF_RECORD_MISC_KERNEL)) { |
475 | list_remove_active_sym(syme); | 476 | list_remove_active_sym(syme); |
476 | continue; | 477 | continue; |
477 | } | 478 | } |
478 | syme->weight = sym_weight(syme); | 479 | syme->weight = sym_weight(syme); |
479 | rb_insert_active_sym(&tmp, syme); | 480 | rb_insert_active_sym(&tmp, syme); |
480 | sum_ksamples += syme->snap_count; | 481 | sum_ksamples += syme->snap_count; |
481 | 482 | ||
482 | for (j = 0; j < nr_counters; j++) | 483 | for (j = 0; j < nr_counters; j++) |
483 | syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; | 484 | syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; |
484 | } else | 485 | } else |
485 | list_remove_active_sym(syme); | 486 | list_remove_active_sym(syme); |
486 | } | 487 | } |
487 | 488 | ||
488 | puts(CONSOLE_CLEAR); | 489 | puts(CONSOLE_CLEAR); |
489 | 490 | ||
490 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 491 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
491 | printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", | 492 | printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", |
492 | samples_per_sec, | 493 | samples_per_sec, |
493 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); | 494 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); |
494 | 495 | ||
495 | if (nr_counters == 1 || !display_weighted) { | 496 | if (nr_counters == 1 || !display_weighted) { |
496 | printf("%Ld", (u64)attrs[0].sample_period); | 497 | printf("%Ld", (u64)attrs[0].sample_period); |
497 | if (freq) | 498 | if (freq) |
498 | printf("Hz "); | 499 | printf("Hz "); |
499 | else | 500 | else |
500 | printf(" "); | 501 | printf(" "); |
501 | } | 502 | } |
502 | 503 | ||
503 | if (!display_weighted) | 504 | if (!display_weighted) |
504 | printf("%s", event_name(sym_counter)); | 505 | printf("%s", event_name(sym_counter)); |
505 | else for (counter = 0; counter < nr_counters; counter++) { | 506 | else for (counter = 0; counter < nr_counters; counter++) { |
506 | if (counter) | 507 | if (counter) |
507 | printf("/"); | 508 | printf("/"); |
508 | 509 | ||
509 | printf("%s", event_name(counter)); | 510 | printf("%s", event_name(counter)); |
510 | } | 511 | } |
511 | 512 | ||
512 | printf( "], "); | 513 | printf( "], "); |
513 | 514 | ||
514 | if (target_pid != -1) | 515 | if (target_pid != -1) |
515 | printf(" (target_pid: %d", target_pid); | 516 | printf(" (target_pid: %d", target_pid); |
516 | else | 517 | else |
517 | printf(" (all"); | 518 | printf(" (all"); |
518 | 519 | ||
519 | if (profile_cpu != -1) | 520 | if (profile_cpu != -1) |
520 | printf(", cpu: %d)\n", profile_cpu); | 521 | printf(", cpu: %d)\n", profile_cpu); |
521 | else { | 522 | else { |
522 | if (target_pid != -1) | 523 | if (target_pid != -1) |
523 | printf(")\n"); | 524 | printf(")\n"); |
524 | else | 525 | else |
525 | printf(", %d CPUs)\n", nr_cpus); | 526 | printf(", %d CPUs)\n", nr_cpus); |
526 | } | 527 | } |
527 | 528 | ||
528 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 529 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
529 | 530 | ||
530 | if (sym_filter_entry) { | 531 | if (sym_filter_entry) { |
531 | show_details(sym_filter_entry); | 532 | show_details(sym_filter_entry); |
532 | return; | 533 | return; |
533 | } | 534 | } |
534 | 535 | ||
535 | /* | 536 | /* |
536 | * Find the longest symbol name that will be displayed | 537 | * Find the longest symbol name that will be displayed |
537 | */ | 538 | */ |
538 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { | 539 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { |
539 | syme = rb_entry(nd, struct sym_entry, rb_node); | 540 | syme = rb_entry(nd, struct sym_entry, rb_node); |
540 | if (++printed > print_entries || | 541 | if (++printed > print_entries || |
541 | (int)syme->snap_count < count_filter) | 542 | (int)syme->snap_count < count_filter) |
542 | continue; | 543 | continue; |
543 | 544 | ||
544 | if (syme->map->dso->long_name_len > dso_width) | 545 | if (syme->map->dso->long_name_len > dso_width) |
545 | dso_width = syme->map->dso->long_name_len; | 546 | dso_width = syme->map->dso->long_name_len; |
546 | 547 | ||
547 | if (syme->name_len > sym_width) | 548 | if (syme->name_len > sym_width) |
548 | sym_width = syme->name_len; | 549 | sym_width = syme->name_len; |
549 | } | 550 | } |
550 | 551 | ||
551 | printed = 0; | 552 | printed = 0; |
552 | 553 | ||
553 | max_dso_width = winsize.ws_col - sym_width - 29; | 554 | max_dso_width = winsize.ws_col - sym_width - 29; |
554 | if (dso_width > max_dso_width) | 555 | if (dso_width > max_dso_width) |
555 | dso_width = max_dso_width; | 556 | dso_width = max_dso_width; |
556 | putchar('\n'); | 557 | putchar('\n'); |
557 | if (nr_counters == 1) | 558 | if (nr_counters == 1) |
558 | printf(" samples pcnt"); | 559 | printf(" samples pcnt"); |
559 | else | 560 | else |
560 | printf(" weight samples pcnt"); | 561 | printf(" weight samples pcnt"); |
561 | 562 | ||
562 | if (verbose) | 563 | if (verbose) |
563 | printf(" RIP "); | 564 | printf(" RIP "); |
564 | printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); | 565 | printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); |
565 | printf(" %s _______ _____", | 566 | printf(" %s _______ _____", |
566 | nr_counters == 1 ? " " : "______"); | 567 | nr_counters == 1 ? " " : "______"); |
567 | if (verbose) | 568 | if (verbose) |
568 | printf(" ________________"); | 569 | printf(" ________________"); |
569 | printf(" %-*.*s", sym_width, sym_width, graph_line); | 570 | printf(" %-*.*s", sym_width, sym_width, graph_line); |
570 | printf(" %-*.*s", dso_width, dso_width, graph_line); | 571 | printf(" %-*.*s", dso_width, dso_width, graph_line); |
571 | puts("\n"); | 572 | puts("\n"); |
572 | 573 | ||
573 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { | 574 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { |
574 | struct symbol *sym; | 575 | struct symbol *sym; |
575 | double pcnt; | 576 | double pcnt; |
576 | 577 | ||
577 | syme = rb_entry(nd, struct sym_entry, rb_node); | 578 | syme = rb_entry(nd, struct sym_entry, rb_node); |
578 | sym = sym_entry__symbol(syme); | 579 | sym = sym_entry__symbol(syme); |
579 | 580 | ||
580 | if (++printed > print_entries || (int)syme->snap_count < count_filter) | 581 | if (++printed > print_entries || (int)syme->snap_count < count_filter) |
581 | continue; | 582 | continue; |
582 | 583 | ||
583 | pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / | 584 | pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / |
584 | sum_ksamples)); | 585 | sum_ksamples)); |
585 | 586 | ||
586 | if (nr_counters == 1 || !display_weighted) | 587 | if (nr_counters == 1 || !display_weighted) |
587 | printf("%20.2f ", syme->weight); | 588 | printf("%20.2f ", syme->weight); |
588 | else | 589 | else |
589 | printf("%9.1f %10ld ", syme->weight, syme->snap_count); | 590 | printf("%9.1f %10ld ", syme->weight, syme->snap_count); |
590 | 591 | ||
591 | percent_color_fprintf(stdout, "%4.1f%%", pcnt); | 592 | percent_color_fprintf(stdout, "%4.1f%%", pcnt); |
592 | if (verbose) | 593 | if (verbose) |
593 | printf(" %016llx", sym->start); | 594 | printf(" %016llx", sym->start); |
594 | printf(" %-*.*s", sym_width, sym_width, sym->name); | 595 | printf(" %-*.*s", sym_width, sym_width, sym->name); |
595 | printf(" %-*.*s\n", dso_width, dso_width, | 596 | printf(" %-*.*s\n", dso_width, dso_width, |
596 | dso_width >= syme->map->dso->long_name_len ? | 597 | dso_width >= syme->map->dso->long_name_len ? |
597 | syme->map->dso->long_name : | 598 | syme->map->dso->long_name : |
598 | syme->map->dso->short_name); | 599 | syme->map->dso->short_name); |
599 | } | 600 | } |
600 | } | 601 | } |
601 | 602 | ||
602 | static void prompt_integer(int *target, const char *msg) | 603 | static void prompt_integer(int *target, const char *msg) |
603 | { | 604 | { |
604 | char *buf = malloc(0), *p; | 605 | char *buf = malloc(0), *p; |
605 | size_t dummy = 0; | 606 | size_t dummy = 0; |
606 | int tmp; | 607 | int tmp; |
607 | 608 | ||
608 | fprintf(stdout, "\n%s: ", msg); | 609 | fprintf(stdout, "\n%s: ", msg); |
609 | if (getline(&buf, &dummy, stdin) < 0) | 610 | if (getline(&buf, &dummy, stdin) < 0) |
610 | return; | 611 | return; |
611 | 612 | ||
612 | p = strchr(buf, '\n'); | 613 | p = strchr(buf, '\n'); |
613 | if (p) | 614 | if (p) |
614 | *p = 0; | 615 | *p = 0; |
615 | 616 | ||
616 | p = buf; | 617 | p = buf; |
617 | while(*p) { | 618 | while(*p) { |
618 | if (!isdigit(*p)) | 619 | if (!isdigit(*p)) |
619 | goto out_free; | 620 | goto out_free; |
620 | p++; | 621 | p++; |
621 | } | 622 | } |
622 | tmp = strtoul(buf, NULL, 10); | 623 | tmp = strtoul(buf, NULL, 10); |
623 | *target = tmp; | 624 | *target = tmp; |
624 | out_free: | 625 | out_free: |
625 | free(buf); | 626 | free(buf); |
626 | } | 627 | } |
627 | 628 | ||
628 | static void prompt_percent(int *target, const char *msg) | 629 | static void prompt_percent(int *target, const char *msg) |
629 | { | 630 | { |
630 | int tmp = 0; | 631 | int tmp = 0; |
631 | 632 | ||
632 | prompt_integer(&tmp, msg); | 633 | prompt_integer(&tmp, msg); |
633 | if (tmp >= 0 && tmp <= 100) | 634 | if (tmp >= 0 && tmp <= 100) |
634 | *target = tmp; | 635 | *target = tmp; |
635 | } | 636 | } |
636 | 637 | ||
637 | static void prompt_symbol(struct sym_entry **target, const char *msg) | 638 | static void prompt_symbol(struct sym_entry **target, const char *msg) |
638 | { | 639 | { |
639 | char *buf = malloc(0), *p; | 640 | char *buf = malloc(0), *p; |
640 | struct sym_entry *syme = *target, *n, *found = NULL; | 641 | struct sym_entry *syme = *target, *n, *found = NULL; |
641 | size_t dummy = 0; | 642 | size_t dummy = 0; |
642 | 643 | ||
643 | /* zero counters of active symbol */ | 644 | /* zero counters of active symbol */ |
644 | if (syme) { | 645 | if (syme) { |
645 | pthread_mutex_lock(&syme->src->lock); | 646 | pthread_mutex_lock(&syme->src->lock); |
646 | __zero_source_counters(syme); | 647 | __zero_source_counters(syme); |
647 | *target = NULL; | 648 | *target = NULL; |
648 | pthread_mutex_unlock(&syme->src->lock); | 649 | pthread_mutex_unlock(&syme->src->lock); |
649 | } | 650 | } |
650 | 651 | ||
651 | fprintf(stdout, "\n%s: ", msg); | 652 | fprintf(stdout, "\n%s: ", msg); |
652 | if (getline(&buf, &dummy, stdin) < 0) | 653 | if (getline(&buf, &dummy, stdin) < 0) |
653 | goto out_free; | 654 | goto out_free; |
654 | 655 | ||
655 | p = strchr(buf, '\n'); | 656 | p = strchr(buf, '\n'); |
656 | if (p) | 657 | if (p) |
657 | *p = 0; | 658 | *p = 0; |
658 | 659 | ||
659 | pthread_mutex_lock(&active_symbols_lock); | 660 | pthread_mutex_lock(&active_symbols_lock); |
660 | syme = list_entry(active_symbols.next, struct sym_entry, node); | 661 | syme = list_entry(active_symbols.next, struct sym_entry, node); |
661 | pthread_mutex_unlock(&active_symbols_lock); | 662 | pthread_mutex_unlock(&active_symbols_lock); |
662 | 663 | ||
663 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { | 664 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { |
664 | struct symbol *sym = sym_entry__symbol(syme); | 665 | struct symbol *sym = sym_entry__symbol(syme); |
665 | 666 | ||
666 | if (!strcmp(buf, sym->name)) { | 667 | if (!strcmp(buf, sym->name)) { |
667 | found = syme; | 668 | found = syme; |
668 | break; | 669 | break; |
669 | } | 670 | } |
670 | } | 671 | } |
671 | 672 | ||
672 | if (!found) { | 673 | if (!found) { |
673 | fprintf(stderr, "Sorry, %s is not active.\n", buf); | 674 | fprintf(stderr, "Sorry, %s is not active.\n", buf); |
674 | sleep(1); | 675 | sleep(1); |
675 | return; | 676 | return; |
676 | } else | 677 | } else |
677 | parse_source(found); | 678 | parse_source(found); |
678 | 679 | ||
679 | out_free: | 680 | out_free: |
680 | free(buf); | 681 | free(buf); |
681 | } | 682 | } |
682 | 683 | ||
683 | static void print_mapped_keys(void) | 684 | static void print_mapped_keys(void) |
684 | { | 685 | { |
685 | char *name = NULL; | 686 | char *name = NULL; |
686 | 687 | ||
687 | if (sym_filter_entry) { | 688 | if (sym_filter_entry) { |
688 | struct symbol *sym = sym_entry__symbol(sym_filter_entry); | 689 | struct symbol *sym = sym_entry__symbol(sym_filter_entry); |
689 | name = sym->name; | 690 | name = sym->name; |
690 | } | 691 | } |
691 | 692 | ||
692 | fprintf(stdout, "\nMapped keys:\n"); | 693 | fprintf(stdout, "\nMapped keys:\n"); |
693 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); | 694 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); |
694 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); | 695 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); |
695 | 696 | ||
696 | if (nr_counters > 1) | 697 | if (nr_counters > 1) |
697 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); | 698 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); |
698 | 699 | ||
699 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); | 700 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); |
700 | 701 | ||
701 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); | 702 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); |
702 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); | 703 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); |
703 | fprintf(stdout, "\t[S] stop annotation.\n"); | 704 | fprintf(stdout, "\t[S] stop annotation.\n"); |
704 | 705 | ||
705 | if (nr_counters > 1) | 706 | if (nr_counters > 1) |
706 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); | 707 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); |
707 | 708 | ||
708 | fprintf(stdout, | 709 | fprintf(stdout, |
709 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", | 710 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", |
710 | hide_kernel_symbols ? "yes" : "no"); | 711 | hide_kernel_symbols ? "yes" : "no"); |
711 | fprintf(stdout, | 712 | fprintf(stdout, |
712 | "\t[U] hide user symbols. \t(%s)\n", | 713 | "\t[U] hide user symbols. \t(%s)\n", |
713 | hide_user_symbols ? "yes" : "no"); | 714 | hide_user_symbols ? "yes" : "no"); |
714 | fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); | 715 | fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); |
715 | fprintf(stdout, "\t[qQ] quit.\n"); | 716 | fprintf(stdout, "\t[qQ] quit.\n"); |
716 | } | 717 | } |
717 | 718 | ||
718 | static int key_mapped(int c) | 719 | static int key_mapped(int c) |
719 | { | 720 | { |
720 | switch (c) { | 721 | switch (c) { |
721 | case 'd': | 722 | case 'd': |
722 | case 'e': | 723 | case 'e': |
723 | case 'f': | 724 | case 'f': |
724 | case 'z': | 725 | case 'z': |
725 | case 'q': | 726 | case 'q': |
726 | case 'Q': | 727 | case 'Q': |
727 | case 'K': | 728 | case 'K': |
728 | case 'U': | 729 | case 'U': |
729 | case 'F': | 730 | case 'F': |
730 | case 's': | 731 | case 's': |
731 | case 'S': | 732 | case 'S': |
732 | return 1; | 733 | return 1; |
733 | case 'E': | 734 | case 'E': |
734 | case 'w': | 735 | case 'w': |
735 | return nr_counters > 1 ? 1 : 0; | 736 | return nr_counters > 1 ? 1 : 0; |
736 | default: | 737 | default: |
737 | break; | 738 | break; |
738 | } | 739 | } |
739 | 740 | ||
740 | return 0; | 741 | return 0; |
741 | } | 742 | } |
742 | 743 | ||
743 | static void handle_keypress(int c) | 744 | static void handle_keypress(int c) |
744 | { | 745 | { |
745 | if (!key_mapped(c)) { | 746 | if (!key_mapped(c)) { |
746 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 747 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
747 | struct termios tc, save; | 748 | struct termios tc, save; |
748 | 749 | ||
749 | print_mapped_keys(); | 750 | print_mapped_keys(); |
750 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); | 751 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); |
751 | fflush(stdout); | 752 | fflush(stdout); |
752 | 753 | ||
753 | tcgetattr(0, &save); | 754 | tcgetattr(0, &save); |
754 | tc = save; | 755 | tc = save; |
755 | tc.c_lflag &= ~(ICANON | ECHO); | 756 | tc.c_lflag &= ~(ICANON | ECHO); |
756 | tc.c_cc[VMIN] = 0; | 757 | tc.c_cc[VMIN] = 0; |
757 | tc.c_cc[VTIME] = 0; | 758 | tc.c_cc[VTIME] = 0; |
758 | tcsetattr(0, TCSANOW, &tc); | 759 | tcsetattr(0, TCSANOW, &tc); |
759 | 760 | ||
760 | poll(&stdin_poll, 1, -1); | 761 | poll(&stdin_poll, 1, -1); |
761 | c = getc(stdin); | 762 | c = getc(stdin); |
762 | 763 | ||
763 | tcsetattr(0, TCSAFLUSH, &save); | 764 | tcsetattr(0, TCSAFLUSH, &save); |
764 | if (!key_mapped(c)) | 765 | if (!key_mapped(c)) |
765 | return; | 766 | return; |
766 | } | 767 | } |
767 | 768 | ||
768 | switch (c) { | 769 | switch (c) { |
769 | case 'd': | 770 | case 'd': |
770 | prompt_integer(&delay_secs, "Enter display delay"); | 771 | prompt_integer(&delay_secs, "Enter display delay"); |
771 | if (delay_secs < 1) | 772 | if (delay_secs < 1) |
772 | delay_secs = 1; | 773 | delay_secs = 1; |
773 | break; | 774 | break; |
774 | case 'e': | 775 | case 'e': |
775 | prompt_integer(&print_entries, "Enter display entries (lines)"); | 776 | prompt_integer(&print_entries, "Enter display entries (lines)"); |
776 | if (print_entries == 0) { | 777 | if (print_entries == 0) { |
777 | sig_winch_handler(SIGWINCH); | 778 | sig_winch_handler(SIGWINCH); |
778 | signal(SIGWINCH, sig_winch_handler); | 779 | signal(SIGWINCH, sig_winch_handler); |
779 | } else | 780 | } else |
780 | signal(SIGWINCH, SIG_DFL); | 781 | signal(SIGWINCH, SIG_DFL); |
781 | break; | 782 | break; |
782 | case 'E': | 783 | case 'E': |
783 | if (nr_counters > 1) { | 784 | if (nr_counters > 1) { |
784 | int i; | 785 | int i; |
785 | 786 | ||
786 | fprintf(stderr, "\nAvailable events:"); | 787 | fprintf(stderr, "\nAvailable events:"); |
787 | for (i = 0; i < nr_counters; i++) | 788 | for (i = 0; i < nr_counters; i++) |
788 | fprintf(stderr, "\n\t%d %s", i, event_name(i)); | 789 | fprintf(stderr, "\n\t%d %s", i, event_name(i)); |
789 | 790 | ||
790 | prompt_integer(&sym_counter, "Enter details event counter"); | 791 | prompt_integer(&sym_counter, "Enter details event counter"); |
791 | 792 | ||
792 | if (sym_counter >= nr_counters) { | 793 | if (sym_counter >= nr_counters) { |
793 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); | 794 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); |
794 | sym_counter = 0; | 795 | sym_counter = 0; |
795 | sleep(1); | 796 | sleep(1); |
796 | } | 797 | } |
797 | } else sym_counter = 0; | 798 | } else sym_counter = 0; |
798 | break; | 799 | break; |
799 | case 'f': | 800 | case 'f': |
800 | prompt_integer(&count_filter, "Enter display event count filter"); | 801 | prompt_integer(&count_filter, "Enter display event count filter"); |
801 | break; | 802 | break; |
802 | case 'F': | 803 | case 'F': |
803 | prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); | 804 | prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); |
804 | break; | 805 | break; |
805 | case 'K': | 806 | case 'K': |
806 | hide_kernel_symbols = !hide_kernel_symbols; | 807 | hide_kernel_symbols = !hide_kernel_symbols; |
807 | break; | 808 | break; |
808 | case 'q': | 809 | case 'q': |
809 | case 'Q': | 810 | case 'Q': |
810 | printf("exiting.\n"); | 811 | printf("exiting.\n"); |
811 | if (dump_symtab) | 812 | if (dump_symtab) |
812 | dsos__fprintf(stderr); | 813 | dsos__fprintf(stderr); |
813 | exit(0); | 814 | exit(0); |
814 | case 's': | 815 | case 's': |
815 | prompt_symbol(&sym_filter_entry, "Enter details symbol"); | 816 | prompt_symbol(&sym_filter_entry, "Enter details symbol"); |
816 | break; | 817 | break; |
817 | case 'S': | 818 | case 'S': |
818 | if (!sym_filter_entry) | 819 | if (!sym_filter_entry) |
819 | break; | 820 | break; |
820 | else { | 821 | else { |
821 | struct sym_entry *syme = sym_filter_entry; | 822 | struct sym_entry *syme = sym_filter_entry; |
822 | 823 | ||
823 | pthread_mutex_lock(&syme->src->lock); | 824 | pthread_mutex_lock(&syme->src->lock); |
824 | sym_filter_entry = NULL; | 825 | sym_filter_entry = NULL; |
825 | __zero_source_counters(syme); | 826 | __zero_source_counters(syme); |
826 | pthread_mutex_unlock(&syme->src->lock); | 827 | pthread_mutex_unlock(&syme->src->lock); |
827 | } | 828 | } |
828 | break; | 829 | break; |
829 | case 'U': | 830 | case 'U': |
830 | hide_user_symbols = !hide_user_symbols; | 831 | hide_user_symbols = !hide_user_symbols; |
831 | break; | 832 | break; |
832 | case 'w': | 833 | case 'w': |
833 | display_weighted = ~display_weighted; | 834 | display_weighted = ~display_weighted; |
834 | break; | 835 | break; |
835 | case 'z': | 836 | case 'z': |
836 | zero = ~zero; | 837 | zero = ~zero; |
837 | break; | 838 | break; |
838 | default: | 839 | default: |
839 | break; | 840 | break; |
840 | } | 841 | } |
841 | } | 842 | } |
842 | 843 | ||
843 | static void *display_thread(void *arg __used) | 844 | static void *display_thread(void *arg __used) |
844 | { | 845 | { |
845 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 846 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
846 | struct termios tc, save; | 847 | struct termios tc, save; |
847 | int delay_msecs, c; | 848 | int delay_msecs, c; |
848 | 849 | ||
849 | tcgetattr(0, &save); | 850 | tcgetattr(0, &save); |
850 | tc = save; | 851 | tc = save; |
851 | tc.c_lflag &= ~(ICANON | ECHO); | 852 | tc.c_lflag &= ~(ICANON | ECHO); |
852 | tc.c_cc[VMIN] = 0; | 853 | tc.c_cc[VMIN] = 0; |
853 | tc.c_cc[VTIME] = 0; | 854 | tc.c_cc[VTIME] = 0; |
854 | 855 | ||
855 | repeat: | 856 | repeat: |
856 | delay_msecs = delay_secs * 1000; | 857 | delay_msecs = delay_secs * 1000; |
857 | tcsetattr(0, TCSANOW, &tc); | 858 | tcsetattr(0, TCSANOW, &tc); |
858 | /* trash return*/ | 859 | /* trash return*/ |
859 | getc(stdin); | 860 | getc(stdin); |
860 | 861 | ||
861 | do { | 862 | do { |
862 | print_sym_table(); | 863 | print_sym_table(); |
863 | } while (!poll(&stdin_poll, 1, delay_msecs) == 1); | 864 | } while (!poll(&stdin_poll, 1, delay_msecs) == 1); |
864 | 865 | ||
865 | c = getc(stdin); | 866 | c = getc(stdin); |
866 | tcsetattr(0, TCSAFLUSH, &save); | 867 | tcsetattr(0, TCSAFLUSH, &save); |
867 | 868 | ||
868 | handle_keypress(c); | 869 | handle_keypress(c); |
869 | goto repeat; | 870 | goto repeat; |
870 | 871 | ||
871 | return NULL; | 872 | return NULL; |
872 | } | 873 | } |
873 | 874 | ||
874 | /* Tag samples to be skipped. */ | 875 | /* Tag samples to be skipped. */ |
875 | static const char *skip_symbols[] = { | 876 | static const char *skip_symbols[] = { |
876 | "default_idle", | 877 | "default_idle", |
877 | "cpu_idle", | 878 | "cpu_idle", |
878 | "enter_idle", | 879 | "enter_idle", |
879 | "exit_idle", | 880 | "exit_idle", |
880 | "mwait_idle", | 881 | "mwait_idle", |
881 | "mwait_idle_with_hints", | 882 | "mwait_idle_with_hints", |
882 | "poll_idle", | 883 | "poll_idle", |
883 | "ppc64_runlatch_off", | 884 | "ppc64_runlatch_off", |
884 | "pseries_dedicated_idle_sleep", | 885 | "pseries_dedicated_idle_sleep", |
885 | NULL | 886 | NULL |
886 | }; | 887 | }; |
887 | 888 | ||
888 | static int symbol_filter(struct map *map, struct symbol *sym) | 889 | static int symbol_filter(struct map *map, struct symbol *sym) |
889 | { | 890 | { |
890 | struct sym_entry *syme; | 891 | struct sym_entry *syme; |
891 | const char *name = sym->name; | 892 | const char *name = sym->name; |
892 | int i; | 893 | int i; |
893 | 894 | ||
894 | /* | 895 | /* |
895 | * ppc64 uses function descriptors and appends a '.' to the | 896 | * ppc64 uses function descriptors and appends a '.' to the |
896 | * start of every instruction address. Remove it. | 897 | * start of every instruction address. Remove it. |
897 | */ | 898 | */ |
898 | if (name[0] == '.') | 899 | if (name[0] == '.') |
899 | name++; | 900 | name++; |
900 | 901 | ||
901 | if (!strcmp(name, "_text") || | 902 | if (!strcmp(name, "_text") || |
902 | !strcmp(name, "_etext") || | 903 | !strcmp(name, "_etext") || |
903 | !strcmp(name, "_sinittext") || | 904 | !strcmp(name, "_sinittext") || |
904 | !strncmp("init_module", name, 11) || | 905 | !strncmp("init_module", name, 11) || |
905 | !strncmp("cleanup_module", name, 14) || | 906 | !strncmp("cleanup_module", name, 14) || |
906 | strstr(name, "_text_start") || | 907 | strstr(name, "_text_start") || |
907 | strstr(name, "_text_end")) | 908 | strstr(name, "_text_end")) |
908 | return 1; | 909 | return 1; |
909 | 910 | ||
910 | syme = symbol__priv(sym); | 911 | syme = symbol__priv(sym); |
911 | syme->map = map; | 912 | syme->map = map; |
912 | syme->src = NULL; | 913 | syme->src = NULL; |
913 | 914 | ||
914 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { | 915 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { |
915 | /* schedule initial sym_filter_entry setup */ | 916 | /* schedule initial sym_filter_entry setup */ |
916 | sym_filter_entry_sched = syme; | 917 | sym_filter_entry_sched = syme; |
917 | sym_filter = NULL; | 918 | sym_filter = NULL; |
918 | } | 919 | } |
919 | 920 | ||
920 | for (i = 0; skip_symbols[i]; i++) { | 921 | for (i = 0; skip_symbols[i]; i++) { |
921 | if (!strcmp(skip_symbols[i], name)) { | 922 | if (!strcmp(skip_symbols[i], name)) { |
922 | syme->skip = 1; | 923 | syme->skip = 1; |
923 | break; | 924 | break; |
924 | } | 925 | } |
925 | } | 926 | } |
926 | 927 | ||
927 | if (!syme->skip) | 928 | if (!syme->skip) |
928 | syme->name_len = strlen(sym->name); | 929 | syme->name_len = strlen(sym->name); |
929 | 930 | ||
930 | return 0; | 931 | return 0; |
931 | } | 932 | } |
932 | 933 | ||
933 | static void event__process_sample(const event_t *self, | 934 | static void event__process_sample(const event_t *self, |
934 | struct perf_session *session, int counter) | 935 | struct perf_session *session, int counter) |
935 | { | 936 | { |
936 | u64 ip = self->ip.ip; | 937 | u64 ip = self->ip.ip; |
937 | struct sym_entry *syme; | 938 | struct sym_entry *syme; |
938 | struct addr_location al; | 939 | struct addr_location al; |
939 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 940 | u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
940 | 941 | ||
941 | ++samples; | 942 | ++samples; |
942 | 943 | ||
943 | switch (origin) { | 944 | switch (origin) { |
944 | case PERF_RECORD_MISC_USER: | 945 | case PERF_RECORD_MISC_USER: |
945 | ++userspace_samples; | 946 | ++userspace_samples; |
946 | if (hide_user_symbols) | 947 | if (hide_user_symbols) |
947 | return; | 948 | return; |
948 | break; | 949 | break; |
949 | case PERF_RECORD_MISC_KERNEL: | 950 | case PERF_RECORD_MISC_KERNEL: |
950 | if (hide_kernel_symbols) | 951 | if (hide_kernel_symbols) |
951 | return; | 952 | return; |
952 | break; | 953 | break; |
953 | default: | 954 | default: |
954 | return; | 955 | return; |
955 | } | 956 | } |
956 | 957 | ||
957 | if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || | 958 | if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || |
958 | al.filtered) | 959 | al.filtered) |
959 | return; | 960 | return; |
960 | 961 | ||
961 | if (al.sym == NULL) { | 962 | if (al.sym == NULL) { |
962 | /* | 963 | /* |
963 | * As we do lazy loading of symtabs we only will know if the | 964 | * As we do lazy loading of symtabs we only will know if the |
964 | * specified vmlinux file is invalid when we actually have a | 965 | * specified vmlinux file is invalid when we actually have a |
965 | * hit in kernel space and then try to load it. So if we get | 966 | * hit in kernel space and then try to load it. So if we get |
966 | * here and there are _no_ symbols in the DSO backing the | 967 | * here and there are _no_ symbols in the DSO backing the |
967 | * kernel map, bail out. | 968 | * kernel map, bail out. |
968 | * | 969 | * |
969 | * We may never get here, for instance, if we use -K/ | 970 | * We may never get here, for instance, if we use -K/ |
970 | * --hide-kernel-symbols, even if the user specifies an | 971 | * --hide-kernel-symbols, even if the user specifies an |
971 | * invalid --vmlinux ;-) | 972 | * invalid --vmlinux ;-) |
972 | */ | 973 | */ |
973 | if (al.map == session->vmlinux_maps[MAP__FUNCTION] && | 974 | if (al.map == session->vmlinux_maps[MAP__FUNCTION] && |
974 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { | 975 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { |
975 | pr_err("The %s file can't be used\n", | 976 | pr_err("The %s file can't be used\n", |
976 | symbol_conf.vmlinux_name); | 977 | symbol_conf.vmlinux_name); |
977 | exit(1); | 978 | exit(1); |
978 | } | 979 | } |
979 | 980 | ||
980 | return; | 981 | return; |
981 | } | 982 | } |
982 | 983 | ||
983 | /* let's see, whether we need to install initial sym_filter_entry */ | 984 | /* let's see, whether we need to install initial sym_filter_entry */ |
984 | if (sym_filter_entry_sched) { | 985 | if (sym_filter_entry_sched) { |
985 | sym_filter_entry = sym_filter_entry_sched; | 986 | sym_filter_entry = sym_filter_entry_sched; |
986 | sym_filter_entry_sched = NULL; | 987 | sym_filter_entry_sched = NULL; |
987 | parse_source(sym_filter_entry); | 988 | parse_source(sym_filter_entry); |
988 | } | 989 | } |
989 | 990 | ||
990 | syme = symbol__priv(al.sym); | 991 | syme = symbol__priv(al.sym); |
991 | if (!syme->skip) { | 992 | if (!syme->skip) { |
992 | syme->count[counter]++; | 993 | syme->count[counter]++; |
993 | syme->origin = origin; | 994 | syme->origin = origin; |
994 | record_precise_ip(syme, counter, ip); | 995 | record_precise_ip(syme, counter, ip); |
995 | pthread_mutex_lock(&active_symbols_lock); | 996 | pthread_mutex_lock(&active_symbols_lock); |
996 | if (list_empty(&syme->node) || !syme->node.next) | 997 | if (list_empty(&syme->node) || !syme->node.next) |
997 | __list_insert_active_sym(syme); | 998 | __list_insert_active_sym(syme); |
998 | pthread_mutex_unlock(&active_symbols_lock); | 999 | pthread_mutex_unlock(&active_symbols_lock); |
999 | } | 1000 | } |
1000 | } | 1001 | } |
1001 | 1002 | ||
1002 | static int event__process(event_t *event, struct perf_session *session) | 1003 | static int event__process(event_t *event, struct perf_session *session) |
1003 | { | 1004 | { |
1004 | switch (event->header.type) { | 1005 | switch (event->header.type) { |
1005 | case PERF_RECORD_COMM: | 1006 | case PERF_RECORD_COMM: |
1006 | event__process_comm(event, session); | 1007 | event__process_comm(event, session); |
1007 | break; | 1008 | break; |
1008 | case PERF_RECORD_MMAP: | 1009 | case PERF_RECORD_MMAP: |
1009 | event__process_mmap(event, session); | 1010 | event__process_mmap(event, session); |
1010 | break; | 1011 | break; |
1011 | case PERF_RECORD_FORK: | 1012 | case PERF_RECORD_FORK: |
1012 | case PERF_RECORD_EXIT: | 1013 | case PERF_RECORD_EXIT: |
1013 | event__process_task(event, session); | 1014 | event__process_task(event, session); |
1014 | break; | 1015 | break; |
1015 | default: | 1016 | default: |
1016 | break; | 1017 | break; |
1017 | } | 1018 | } |
1018 | 1019 | ||
1019 | return 0; | 1020 | return 0; |
1020 | } | 1021 | } |
1021 | 1022 | ||
1022 | struct mmap_data { | 1023 | struct mmap_data { |
1023 | int counter; | 1024 | int counter; |
1024 | void *base; | 1025 | void *base; |
1025 | int mask; | 1026 | int mask; |
1026 | unsigned int prev; | 1027 | unsigned int prev; |
1027 | }; | 1028 | }; |
1028 | 1029 | ||
1029 | static unsigned int mmap_read_head(struct mmap_data *md) | 1030 | static unsigned int mmap_read_head(struct mmap_data *md) |
1030 | { | 1031 | { |
1031 | struct perf_event_mmap_page *pc = md->base; | 1032 | struct perf_event_mmap_page *pc = md->base; |
1032 | int head; | 1033 | int head; |
1033 | 1034 | ||
1034 | head = pc->data_head; | 1035 | head = pc->data_head; |
1035 | rmb(); | 1036 | rmb(); |
1036 | 1037 | ||
1037 | return head; | 1038 | return head; |
1038 | } | 1039 | } |
1039 | 1040 | ||
1040 | static void perf_session__mmap_read_counter(struct perf_session *self, | 1041 | static void perf_session__mmap_read_counter(struct perf_session *self, |
1041 | struct mmap_data *md) | 1042 | struct mmap_data *md) |
1042 | { | 1043 | { |
1043 | unsigned int head = mmap_read_head(md); | 1044 | unsigned int head = mmap_read_head(md); |
1044 | unsigned int old = md->prev; | 1045 | unsigned int old = md->prev; |
1045 | unsigned char *data = md->base + page_size; | 1046 | unsigned char *data = md->base + page_size; |
1046 | int diff; | 1047 | int diff; |
1047 | 1048 | ||
1048 | /* | 1049 | /* |
1049 | * If we're further behind than half the buffer, there's a chance | 1050 | * If we're further behind than half the buffer, there's a chance |
1050 | * the writer will bite our tail and mess up the samples under us. | 1051 | * the writer will bite our tail and mess up the samples under us. |
1051 | * | 1052 | * |
1052 | * If we somehow ended up ahead of the head, we got messed up. | 1053 | * If we somehow ended up ahead of the head, we got messed up. |
1053 | * | 1054 | * |
1054 | * In either case, truncate and restart at head. | 1055 | * In either case, truncate and restart at head. |
1055 | */ | 1056 | */ |
1056 | diff = head - old; | 1057 | diff = head - old; |
1057 | if (diff > md->mask / 2 || diff < 0) { | 1058 | if (diff > md->mask / 2 || diff < 0) { |
1058 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); | 1059 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); |
1059 | 1060 | ||
1060 | /* | 1061 | /* |
1061 | * head points to a known good entry, start there. | 1062 | * head points to a known good entry, start there. |
1062 | */ | 1063 | */ |
1063 | old = head; | 1064 | old = head; |
1064 | } | 1065 | } |
1065 | 1066 | ||
1066 | for (; old != head;) { | 1067 | for (; old != head;) { |
1067 | event_t *event = (event_t *)&data[old & md->mask]; | 1068 | event_t *event = (event_t *)&data[old & md->mask]; |
1068 | 1069 | ||
1069 | event_t event_copy; | 1070 | event_t event_copy; |
1070 | 1071 | ||
1071 | size_t size = event->header.size; | 1072 | size_t size = event->header.size; |
1072 | 1073 | ||
1073 | /* | 1074 | /* |
1074 | * Event straddles the mmap boundary -- header should always | 1075 | * Event straddles the mmap boundary -- header should always |
1075 | * be inside due to u64 alignment of output. | 1076 | * be inside due to u64 alignment of output. |
1076 | */ | 1077 | */ |
1077 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | 1078 | if ((old & md->mask) + size != ((old + size) & md->mask)) { |
1078 | unsigned int offset = old; | 1079 | unsigned int offset = old; |
1079 | unsigned int len = min(sizeof(*event), size), cpy; | 1080 | unsigned int len = min(sizeof(*event), size), cpy; |
1080 | void *dst = &event_copy; | 1081 | void *dst = &event_copy; |
1081 | 1082 | ||
1082 | do { | 1083 | do { |
1083 | cpy = min(md->mask + 1 - (offset & md->mask), len); | 1084 | cpy = min(md->mask + 1 - (offset & md->mask), len); |
1084 | memcpy(dst, &data[offset & md->mask], cpy); | 1085 | memcpy(dst, &data[offset & md->mask], cpy); |
1085 | offset += cpy; | 1086 | offset += cpy; |
1086 | dst += cpy; | 1087 | dst += cpy; |
1087 | len -= cpy; | 1088 | len -= cpy; |
1088 | } while (len); | 1089 | } while (len); |
1089 | 1090 | ||
1090 | event = &event_copy; | 1091 | event = &event_copy; |
1091 | } | 1092 | } |
1092 | 1093 | ||
1093 | if (event->header.type == PERF_RECORD_SAMPLE) | 1094 | if (event->header.type == PERF_RECORD_SAMPLE) |
1094 | event__process_sample(event, self, md->counter); | 1095 | event__process_sample(event, self, md->counter); |
1095 | else | 1096 | else |
1096 | event__process(event, self); | 1097 | event__process(event, self); |
1097 | old += size; | 1098 | old += size; |
1098 | } | 1099 | } |
1099 | 1100 | ||
1100 | md->prev = old; | 1101 | md->prev = old; |
1101 | } | 1102 | } |
1102 | 1103 | ||
1103 | static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; | 1104 | static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; |
1104 | static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; | 1105 | static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; |
1105 | 1106 | ||
1106 | static void perf_session__mmap_read(struct perf_session *self) | 1107 | static void perf_session__mmap_read(struct perf_session *self) |
1107 | { | 1108 | { |
1108 | int i, counter; | 1109 | int i, counter; |
1109 | 1110 | ||
1110 | for (i = 0; i < nr_cpus; i++) { | 1111 | for (i = 0; i < nr_cpus; i++) { |
1111 | for (counter = 0; counter < nr_counters; counter++) | 1112 | for (counter = 0; counter < nr_counters; counter++) |
1112 | perf_session__mmap_read_counter(self, &mmap_array[i][counter]); | 1113 | perf_session__mmap_read_counter(self, &mmap_array[i][counter]); |
1113 | } | 1114 | } |
1114 | } | 1115 | } |
1115 | 1116 | ||
1116 | int nr_poll; | 1117 | int nr_poll; |
1117 | int group_fd; | 1118 | int group_fd; |
1118 | 1119 | ||
1119 | static void start_counter(int i, int counter) | 1120 | static void start_counter(int i, int counter) |
1120 | { | 1121 | { |
1121 | struct perf_event_attr *attr; | 1122 | struct perf_event_attr *attr; |
1122 | int cpu; | 1123 | int cpu; |
1123 | 1124 | ||
1124 | cpu = profile_cpu; | 1125 | cpu = profile_cpu; |
1125 | if (target_pid == -1 && profile_cpu == -1) | 1126 | if (target_pid == -1 && profile_cpu == -1) |
1126 | cpu = i; | 1127 | cpu = cpumap[i]; |
1127 | 1128 | ||
1128 | attr = attrs + counter; | 1129 | attr = attrs + counter; |
1129 | 1130 | ||
1130 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 1131 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
1131 | 1132 | ||
1132 | if (freq) { | 1133 | if (freq) { |
1133 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 1134 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
1134 | attr->freq = 1; | 1135 | attr->freq = 1; |
1135 | attr->sample_freq = freq; | 1136 | attr->sample_freq = freq; |
1136 | } | 1137 | } |
1137 | 1138 | ||
1138 | attr->inherit = (cpu < 0) && inherit; | 1139 | attr->inherit = (cpu < 0) && inherit; |
1139 | attr->mmap = 1; | 1140 | attr->mmap = 1; |
1140 | 1141 | ||
1141 | try_again: | 1142 | try_again: |
1142 | fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); | 1143 | fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); |
1143 | 1144 | ||
1144 | if (fd[i][counter] < 0) { | 1145 | if (fd[i][counter] < 0) { |
1145 | int err = errno; | 1146 | int err = errno; |
1146 | 1147 | ||
1147 | if (err == EPERM || err == EACCES) | 1148 | if (err == EPERM || err == EACCES) |
1148 | die("No permission - are you root?\n"); | 1149 | die("No permission - are you root?\n"); |
1149 | /* | 1150 | /* |
1150 | * If it's cycles then fall back to hrtimer | 1151 | * If it's cycles then fall back to hrtimer |
1151 | * based cpu-clock-tick sw counter, which | 1152 | * based cpu-clock-tick sw counter, which |
1152 | * is always available even if no PMU support: | 1153 | * is always available even if no PMU support: |
1153 | */ | 1154 | */ |
1154 | if (attr->type == PERF_TYPE_HARDWARE | 1155 | if (attr->type == PERF_TYPE_HARDWARE |
1155 | && attr->config == PERF_COUNT_HW_CPU_CYCLES) { | 1156 | && attr->config == PERF_COUNT_HW_CPU_CYCLES) { |
1156 | 1157 | ||
1157 | if (verbose) | 1158 | if (verbose) |
1158 | warning(" ... trying to fall back to cpu-clock-ticks\n"); | 1159 | warning(" ... trying to fall back to cpu-clock-ticks\n"); |
1159 | 1160 | ||
1160 | attr->type = PERF_TYPE_SOFTWARE; | 1161 | attr->type = PERF_TYPE_SOFTWARE; |
1161 | attr->config = PERF_COUNT_SW_CPU_CLOCK; | 1162 | attr->config = PERF_COUNT_SW_CPU_CLOCK; |
1162 | goto try_again; | 1163 | goto try_again; |
1163 | } | 1164 | } |
1164 | printf("\n"); | 1165 | printf("\n"); |
1165 | error("perfcounter syscall returned with %d (%s)\n", | 1166 | error("perfcounter syscall returned with %d (%s)\n", |
1166 | fd[i][counter], strerror(err)); | 1167 | fd[i][counter], strerror(err)); |
1167 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 1168 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
1168 | exit(-1); | 1169 | exit(-1); |
1169 | } | 1170 | } |
1170 | assert(fd[i][counter] >= 0); | 1171 | assert(fd[i][counter] >= 0); |
1171 | fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); | 1172 | fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); |
1172 | 1173 | ||
1173 | /* | 1174 | /* |
1174 | * First counter acts as the group leader: | 1175 | * First counter acts as the group leader: |
1175 | */ | 1176 | */ |
1176 | if (group && group_fd == -1) | 1177 | if (group && group_fd == -1) |
1177 | group_fd = fd[i][counter]; | 1178 | group_fd = fd[i][counter]; |
1178 | 1179 | ||
1179 | event_array[nr_poll].fd = fd[i][counter]; | 1180 | event_array[nr_poll].fd = fd[i][counter]; |
1180 | event_array[nr_poll].events = POLLIN; | 1181 | event_array[nr_poll].events = POLLIN; |
1181 | nr_poll++; | 1182 | nr_poll++; |
1182 | 1183 | ||
1183 | mmap_array[i][counter].counter = counter; | 1184 | mmap_array[i][counter].counter = counter; |
1184 | mmap_array[i][counter].prev = 0; | 1185 | mmap_array[i][counter].prev = 0; |
1185 | mmap_array[i][counter].mask = mmap_pages*page_size - 1; | 1186 | mmap_array[i][counter].mask = mmap_pages*page_size - 1; |
1186 | mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size, | 1187 | mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size, |
1187 | PROT_READ, MAP_SHARED, fd[i][counter], 0); | 1188 | PROT_READ, MAP_SHARED, fd[i][counter], 0); |
1188 | if (mmap_array[i][counter].base == MAP_FAILED) | 1189 | if (mmap_array[i][counter].base == MAP_FAILED) |
1189 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 1190 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
1190 | } | 1191 | } |
1191 | 1192 | ||
1192 | static int __cmd_top(void) | 1193 | static int __cmd_top(void) |
1193 | { | 1194 | { |
1194 | pthread_t thread; | 1195 | pthread_t thread; |
1195 | int i, counter; | 1196 | int i, counter; |
1196 | int ret; | 1197 | int ret; |
1197 | /* | 1198 | /* |
1198 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this | 1199 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this |
1199 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. | 1200 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. |
1200 | */ | 1201 | */ |
1201 | struct perf_session *session = perf_session__new(NULL, O_WRONLY, false); | 1202 | struct perf_session *session = perf_session__new(NULL, O_WRONLY, false); |
1202 | if (session == NULL) | 1203 | if (session == NULL) |
1203 | return -ENOMEM; | 1204 | return -ENOMEM; |
1204 | 1205 | ||
1205 | if (target_pid != -1) | 1206 | if (target_pid != -1) |
1206 | event__synthesize_thread(target_pid, event__process, session); | 1207 | event__synthesize_thread(target_pid, event__process, session); |
1207 | else | 1208 | else |
1208 | event__synthesize_threads(event__process, session); | 1209 | event__synthesize_threads(event__process, session); |
1209 | 1210 | ||
1210 | for (i = 0; i < nr_cpus; i++) { | 1211 | for (i = 0; i < nr_cpus; i++) { |
1211 | group_fd = -1; | 1212 | group_fd = -1; |
1212 | for (counter = 0; counter < nr_counters; counter++) | 1213 | for (counter = 0; counter < nr_counters; counter++) |
1213 | start_counter(i, counter); | 1214 | start_counter(i, counter); |
1214 | } | 1215 | } |
1215 | 1216 | ||
1216 | /* Wait for a minimal set of events before starting the snapshot */ | 1217 | /* Wait for a minimal set of events before starting the snapshot */ |
1217 | poll(event_array, nr_poll, 100); | 1218 | poll(event_array, nr_poll, 100); |
1218 | 1219 | ||
1219 | perf_session__mmap_read(session); | 1220 | perf_session__mmap_read(session); |
1220 | 1221 | ||
1221 | if (pthread_create(&thread, NULL, display_thread, NULL)) { | 1222 | if (pthread_create(&thread, NULL, display_thread, NULL)) { |
1222 | printf("Could not create display thread.\n"); | 1223 | printf("Could not create display thread.\n"); |
1223 | exit(-1); | 1224 | exit(-1); |
1224 | } | 1225 | } |
1225 | 1226 | ||
1226 | if (realtime_prio) { | 1227 | if (realtime_prio) { |
1227 | struct sched_param param; | 1228 | struct sched_param param; |
1228 | 1229 | ||
1229 | param.sched_priority = realtime_prio; | 1230 | param.sched_priority = realtime_prio; |
1230 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 1231 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
1231 | printf("Could not set realtime priority.\n"); | 1232 | printf("Could not set realtime priority.\n"); |
1232 | exit(-1); | 1233 | exit(-1); |
1233 | } | 1234 | } |
1234 | } | 1235 | } |
1235 | 1236 | ||
1236 | while (1) { | 1237 | while (1) { |
1237 | int hits = samples; | 1238 | int hits = samples; |
1238 | 1239 | ||
1239 | perf_session__mmap_read(session); | 1240 | perf_session__mmap_read(session); |
1240 | 1241 | ||
1241 | if (hits == samples) | 1242 | if (hits == samples) |
1242 | ret = poll(event_array, nr_poll, 100); | 1243 | ret = poll(event_array, nr_poll, 100); |
1243 | } | 1244 | } |
1244 | 1245 | ||
1245 | return 0; | 1246 | return 0; |
1246 | } | 1247 | } |
1247 | 1248 | ||
1248 | static const char * const top_usage[] = { | 1249 | static const char * const top_usage[] = { |
1249 | "perf top [<options>]", | 1250 | "perf top [<options>]", |
1250 | NULL | 1251 | NULL |
1251 | }; | 1252 | }; |
1252 | 1253 | ||
1253 | static const struct option options[] = { | 1254 | static const struct option options[] = { |
1254 | OPT_CALLBACK('e', "event", NULL, "event", | 1255 | OPT_CALLBACK('e', "event", NULL, "event", |
1255 | "event selector. use 'perf list' to list available events", | 1256 | "event selector. use 'perf list' to list available events", |
1256 | parse_events), | 1257 | parse_events), |
1257 | OPT_INTEGER('c', "count", &default_interval, | 1258 | OPT_INTEGER('c', "count", &default_interval, |
1258 | "event period to sample"), | 1259 | "event period to sample"), |
1259 | OPT_INTEGER('p', "pid", &target_pid, | 1260 | OPT_INTEGER('p', "pid", &target_pid, |
1260 | "profile events on existing pid"), | 1261 | "profile events on existing pid"), |
1261 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1262 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
1262 | "system-wide collection from all CPUs"), | 1263 | "system-wide collection from all CPUs"), |
1263 | OPT_INTEGER('C', "CPU", &profile_cpu, | 1264 | OPT_INTEGER('C', "CPU", &profile_cpu, |
1264 | "CPU to profile on"), | 1265 | "CPU to profile on"), |
1265 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1266 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1266 | "file", "vmlinux pathname"), | 1267 | "file", "vmlinux pathname"), |
1267 | OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, | 1268 | OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, |
1268 | "hide kernel symbols"), | 1269 | "hide kernel symbols"), |
1269 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, | 1270 | OPT_INTEGER('m', "mmap-pages", &mmap_pages, |
1270 | "number of mmap data pages"), | 1271 | "number of mmap data pages"), |
1271 | OPT_INTEGER('r', "realtime", &realtime_prio, | 1272 | OPT_INTEGER('r', "realtime", &realtime_prio, |
1272 | "collect data with this RT SCHED_FIFO priority"), | 1273 | "collect data with this RT SCHED_FIFO priority"), |
1273 | OPT_INTEGER('d', "delay", &delay_secs, | 1274 | OPT_INTEGER('d', "delay", &delay_secs, |
1274 | "number of seconds to delay between refreshes"), | 1275 | "number of seconds to delay between refreshes"), |
1275 | OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, | 1276 | OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, |
1276 | "dump the symbol table used for profiling"), | 1277 | "dump the symbol table used for profiling"), |
1277 | OPT_INTEGER('f', "count-filter", &count_filter, | 1278 | OPT_INTEGER('f', "count-filter", &count_filter, |
1278 | "only display functions with more events than this"), | 1279 | "only display functions with more events than this"), |
1279 | OPT_BOOLEAN('g', "group", &group, | 1280 | OPT_BOOLEAN('g', "group", &group, |
1280 | "put the counters into a counter group"), | 1281 | "put the counters into a counter group"), |
1281 | OPT_BOOLEAN('i', "inherit", &inherit, | 1282 | OPT_BOOLEAN('i', "inherit", &inherit, |
1282 | "child tasks inherit counters"), | 1283 | "child tasks inherit counters"), |
1283 | OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", | 1284 | OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", |
1284 | "symbol to annotate"), | 1285 | "symbol to annotate"), |
1285 | OPT_BOOLEAN('z', "zero", &zero, | 1286 | OPT_BOOLEAN('z', "zero", &zero, |
1286 | "zero history across updates"), | 1287 | "zero history across updates"), |
1287 | OPT_INTEGER('F', "freq", &freq, | 1288 | OPT_INTEGER('F', "freq", &freq, |
1288 | "profile at this frequency"), | 1289 | "profile at this frequency"), |
1289 | OPT_INTEGER('E', "entries", &print_entries, | 1290 | OPT_INTEGER('E', "entries", &print_entries, |
1290 | "display this many functions"), | 1291 | "display this many functions"), |
1291 | OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, | 1292 | OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, |
1292 | "hide user symbols"), | 1293 | "hide user symbols"), |
1293 | OPT_BOOLEAN('v', "verbose", &verbose, | 1294 | OPT_BOOLEAN('v', "verbose", &verbose, |
1294 | "be more verbose (show counter open errors, etc)"), | 1295 | "be more verbose (show counter open errors, etc)"), |
1295 | OPT_END() | 1296 | OPT_END() |
1296 | }; | 1297 | }; |
1297 | 1298 | ||
1298 | int cmd_top(int argc, const char **argv, const char *prefix __used) | 1299 | int cmd_top(int argc, const char **argv, const char *prefix __used) |
1299 | { | 1300 | { |
1300 | int counter; | 1301 | int counter; |
1301 | 1302 | ||
1302 | page_size = sysconf(_SC_PAGE_SIZE); | 1303 | page_size = sysconf(_SC_PAGE_SIZE); |
1303 | 1304 | ||
1304 | argc = parse_options(argc, argv, options, top_usage, 0); | 1305 | argc = parse_options(argc, argv, options, top_usage, 0); |
1305 | if (argc) | 1306 | if (argc) |
1306 | usage_with_options(top_usage, options); | 1307 | usage_with_options(top_usage, options); |
1307 | 1308 | ||
1308 | /* CPU and PID are mutually exclusive */ | 1309 | /* CPU and PID are mutually exclusive */ |
1309 | if (target_pid != -1 && profile_cpu != -1) { | 1310 | if (target_pid != -1 && profile_cpu != -1) { |
1310 | printf("WARNING: PID switch overriding CPU\n"); | 1311 | printf("WARNING: PID switch overriding CPU\n"); |
1311 | sleep(1); | 1312 | sleep(1); |
1312 | profile_cpu = -1; | 1313 | profile_cpu = -1; |
1313 | } | 1314 | } |
1314 | 1315 | ||
1315 | if (!nr_counters) | 1316 | if (!nr_counters) |
1316 | nr_counters = 1; | 1317 | nr_counters = 1; |
1317 | 1318 | ||
1318 | symbol_conf.priv_size = (sizeof(struct sym_entry) + | 1319 | symbol_conf.priv_size = (sizeof(struct sym_entry) + |
1319 | (nr_counters + 1) * sizeof(unsigned long)); | 1320 | (nr_counters + 1) * sizeof(unsigned long)); |
1320 | 1321 | ||
1321 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | 1322 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1322 | if (symbol__init() < 0) | 1323 | if (symbol__init() < 0) |
1323 | return -1; | 1324 | return -1; |
1324 | 1325 | ||
1325 | if (delay_secs < 1) | 1326 | if (delay_secs < 1) |
1326 | delay_secs = 1; | 1327 | delay_secs = 1; |
1327 | 1328 | ||
1328 | /* | 1329 | /* |
1329 | * User specified count overrides default frequency. | 1330 | * User specified count overrides default frequency. |
1330 | */ | 1331 | */ |
1331 | if (default_interval) | 1332 | if (default_interval) |
1332 | freq = 0; | 1333 | freq = 0; |
1333 | else if (freq) { | 1334 | else if (freq) { |
1334 | default_interval = freq; | 1335 | default_interval = freq; |
1335 | } else { | 1336 | } else { |
1336 | fprintf(stderr, "frequency and count are zero, aborting\n"); | 1337 | fprintf(stderr, "frequency and count are zero, aborting\n"); |
1337 | exit(EXIT_FAILURE); | 1338 | exit(EXIT_FAILURE); |
1338 | } | 1339 | } |
1339 | 1340 | ||
1340 | /* | 1341 | /* |
1341 | * Fill in the ones not specifically initialized via -c: | 1342 | * Fill in the ones not specifically initialized via -c: |
1342 | */ | 1343 | */ |
1343 | for (counter = 0; counter < nr_counters; counter++) { | 1344 | for (counter = 0; counter < nr_counters; counter++) { |
1344 | if (attrs[counter].sample_period) | 1345 | if (attrs[counter].sample_period) |
1345 | continue; | 1346 | continue; |
1346 | 1347 | ||
1347 | attrs[counter].sample_period = default_interval; | 1348 | attrs[counter].sample_period = default_interval; |
1348 | } | 1349 | } |
1349 | 1350 | ||
1350 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
1351 | assert(nr_cpus <= MAX_NR_CPUS); | ||
1352 | assert(nr_cpus >= 0); | ||
1353 | |||
1354 | if (target_pid != -1 || profile_cpu != -1) | 1351 | if (target_pid != -1 || profile_cpu != -1) |
1355 | nr_cpus = 1; | 1352 | nr_cpus = 1; |
1353 | else | ||
1354 | nr_cpus = read_cpu_map(); | ||
1356 | 1355 | ||
1357 | get_term_dimensions(&winsize); | 1356 | get_term_dimensions(&winsize); |
1358 | if (print_entries == 0) { | 1357 | if (print_entries == 0) { |
1359 | update_print_entries(&winsize); | 1358 | update_print_entries(&winsize); |
1360 | signal(SIGWINCH, sig_winch_handler); | 1359 | signal(SIGWINCH, sig_winch_handler); |
1361 | } | 1360 | } |
1362 | 1361 |
tools/perf/util/cpumap.c
File was created | 1 | #include "util.h" | |
2 | #include "../perf.h" | ||
3 | #include "cpumap.h" | ||
4 | #include <assert.h> | ||
5 | #include <stdio.h> | ||
6 | |||
7 | int cpumap[MAX_NR_CPUS]; | ||
8 | |||
9 | static int default_cpu_map(void) | ||
10 | { | ||
11 | int nr_cpus, i; | ||
12 | |||
13 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
14 | assert(nr_cpus <= MAX_NR_CPUS); | ||
15 | assert((int)nr_cpus >= 0); | ||
16 | |||
17 | for (i = 0; i < nr_cpus; ++i) | ||
18 | cpumap[i] = i; | ||
19 | |||
20 | return nr_cpus; | ||
21 | } | ||
22 | |||
23 | int read_cpu_map(void) | ||
24 | { | ||
25 | FILE *onlnf; | ||
26 | int nr_cpus = 0; | ||
27 | int n, cpu, prev; | ||
28 | char sep; | ||
29 | |||
30 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | ||
31 | if (!onlnf) | ||
32 | return default_cpu_map(); | ||
33 | |||
34 | sep = 0; | ||
35 | prev = -1; | ||
36 | for (;;) { | ||
37 | n = fscanf(onlnf, "%u%c", &cpu, &sep); | ||
38 | if (n <= 0) | ||
39 | break; | ||
40 | if (prev >= 0) { | ||
41 | assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS); | ||
42 | while (++prev < cpu) | ||
43 | cpumap[nr_cpus++] = prev; | ||
44 | } | ||
45 | assert (nr_cpus < MAX_NR_CPUS); | ||
46 | cpumap[nr_cpus++] = cpu; | ||
47 | if (n == 2 && sep == '-') | ||
48 | prev = cpu; | ||
49 | else | ||
50 | prev = -1; | ||
51 | if (n == 1 || sep == '\n') | ||
52 | break; | ||
53 | } | ||
54 | fclose(onlnf); | ||
55 | if (nr_cpus > 0) | ||
56 | return nr_cpus; | ||
57 | |||
58 | return default_cpu_map(); | ||
59 | } | ||
60 |
tools/perf/util/cpumap.h
File was created | 1 | #ifndef __PERF_CPUMAP_H | |
2 | #define __PERF_CPUMAP_H | ||
3 | |||
4 | extern int read_cpu_map(void); | ||
5 | extern int cpumap[]; | ||
6 | |||
7 | #endif /* __PERF_CPUMAP_H */ | ||
8 |