aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/llvm-utils.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-08-31 22:49:05 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-08-31 22:49:05 -0400
commit41d859a83c567a9c9f50a34082cc64aab0abb0cd (patch)
treeab911ea521701401413d041e1b92225f3dbdab41 /tools/perf/util/llvm-utils.c
parent4658000955d1864b54890214434e171949c7f1c5 (diff)
parentbac2e4a96d1c0bcce5e9654dcc902f75576b9b03 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Main perf kernel side changes: - uprobes updates/fixes. (Oleg Nesterov) - Add PERF_RECORD_SWITCH to indicate context switches and use it in tooling. (Adrian Hunter) - Support BPF programs attached to uprobes and first steps for BPF tooling support. (Wang Nan) - x86 generic x86 MSR-to-perf PMU driver. (Andy Lutomirski) - x86 Intel PT, LBR and BTS updates. (Alexander Shishkin) - x86 Intel Skylake support. (Andi Kleen) - x86 Intel Knights Landing (KNL) RAPL support. (Dasaratharaman Chandramouli) - x86 Intel Broadwell-DE uncore support. (Kan Liang) - x86 hw breakpoints robustization (Andy Lutomirski) Main perf tooling side changes: - Support Intel PT in several tools, enabling the use of the processor trace feature introduced in Intel Broadwell processors: (Adrian Hunter) # dmesg | grep Performance # [0.188477] Performance Events: PEBS fmt2+, 16-deep LBR, Broadwell events, full-width counters, Intel PMU driver. # perf record -e intel_pt//u -a sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.216 MB perf.data ] # perf script # then navigate in the tool output to some area, like this one: 184 1030 dl_main (/usr/lib64/ld-2.17.so) => 7f21ba661440 dl_main (/usr/lib64/ld-2.17.so) 185 1457 dl_main (/usr/lib64/ld-2.17.so) => 7f21ba669f10 _dl_new_object (/usr/lib64/ld-2.17.so) 186 9f37 _dl_new_object (/usr/lib64/ld-2.17.so) => 7f21ba677b90 strlen (/usr/lib64/ld-2.17.so) 187 7ba3 strlen (/usr/lib64/ld-2.17.so) => 7f21ba677c75 strlen (/usr/lib64/ld-2.17.so) 188 7c78 strlen (/usr/lib64/ld-2.17.so) => 7f21ba669f3c _dl_new_object (/usr/lib64/ld-2.17.so) 189 9f8a _dl_new_object (/usr/lib64/ld-2.17.so) => 7f21ba65fab0 calloc@plt (/usr/lib64/ld-2.17.so) 190 fab0 calloc@plt (/usr/lib64/ld-2.17.so) => 7f21ba675e70 calloc (/usr/lib64/ld-2.17.so) 191 5e87 calloc (/usr/lib64/ld-2.17.so) => 7f21ba65fa90 malloc@plt (/usr/lib64/ld-2.17.so) 192 fa90 malloc@plt (/usr/lib64/ld-2.17.so) => 7f21ba675e60 malloc (/usr/lib64/ld-2.17.so) 193 5e68 malloc (/usr/lib64/ld-2.17.so) => 7f21ba65fa80 __libc_memalign@plt (/usr/lib64/ld-2.17.so) 194 fa80 __libc_memalign@plt (/usr/lib64/ld-2.17.so) => 7f21ba675d50 __libc_memalign (/usr/lib64/ld-2.17.so) 195 5d63 __libc_memalign (/usr/lib64/ld-2.17.so) => 7f21ba675e20 __libc_memalign (/usr/lib64/ld-2.17.so) 196 5e40 __libc_memalign (/usr/lib64/ld-2.17.so) => 7f21ba675d73 __libc_memalign (/usr/lib64/ld-2.17.so) 197 5d97 __libc_memalign (/usr/lib64/ld-2.17.so) => 7f21ba675e18 __libc_memalign (/usr/lib64/ld-2.17.so) 198 5e1e __libc_memalign (/usr/lib64/ld-2.17.so) => 7f21ba675df9 __libc_memalign (/usr/lib64/ld-2.17.so) 199 5e10 __libc_memalign (/usr/lib64/ld-2.17.so) => 7f21ba669f8f _dl_new_object (/usr/lib64/ld-2.17.so) 200 9fc2 _dl_new_object (/usr/lib64/ld-2.17.so) => 7f21ba678e70 memcpy (/usr/lib64/ld-2.17.so) 201 8e8c memcpy (/usr/lib64/ld-2.17.so) => 7f21ba678ea0 memcpy (/usr/lib64/ld-2.17.so) - Add support for using several Intel PT features (CYC, MTC packets), the relevant documentation was updated in: tools/perf/Documentation/intel-pt.txt briefly describing those packets, its purposes, how to configure them in the event config terms and relevant external documentation for further reading. (Adrian Hunter) - Introduce support for probing at an absolute address, for user and kernel 'perf probe's, useful when one have the symbol maps on a developer machine but not on an embedded system. (Wang Nan) - Add Intel BTS support, with a call-graph script to show it and PT in use in a GUI using 'perf script' python scripting with postgresql and Qt. (Adrian Hunter) - Allow selecting the type of callchains per event, including disabling callchains in all but one entry in an event list, to save space, and also to ask for the callchains collected in one event to be used in other events. (Kan Liang) - Beautify more syscall arguments in 'perf trace': (Arnaldo Carvalho de Melo) * A bunch more translate file/pathnames from pointers to strings. * Convert numbers to strings for the 'keyctl' syscall 'option' arg. * Add missing 'clockid' entries. - Introduce 'srcfile' sort key: (Andi Kleen) # perf record -F 10000 usleep 1 # perf report --stdio --dsos '[kernel.vmlinux]' -s srcfile <SNIP> # Overhead Source File 26.49% copy_page_64.S 5.49% signal.c 0.51% msr.h # It can be combined with other fields, for instance, experiment with '-s srcfile,symbol'. There are some oddities in some distros and with some specific DSOs, being investigated, so your mileage may vary. - Support per-event 'freq' term: (Namhyung Kim) $ perf record -e 'cpu/instructions,freq=1234/',cycles -c 1000 sleep 1 $ perf evlist -F cpu/instructions,freq=1234/: sample_freq=1234 cycles: sample_period=1000 $ - Deref sys_enter pointer args with contents from probe:vfs_getname, showing pathnames instead of pointers in many syscalls in 'perf trace'. (Arnaldo Carvalho de Melo) - Stop collecting /proc/kallsyms in perf.data files, saving about 4.5MB on a typical x86-64 system, use the the symbol resolution routines used in all the other tools (report, top, etc) now that we can ask libtraceevent to use perf's symbol resolution code. (Arnaldo Carvalho de Melo) - Allow filtering out of perf's PID via 'perf record --exclude-perf'. (Wang Nan) - 'perf trace' now supports syscall groups, like strace, i.e: $ trace -e file touch file Will expand 'file' into multiple, file related, syscalls. More work needed to add extra groups for other syscall groups, and also to complement what was added for the 'file' group, included as a proof of concept. (Arnaldo Carvalho de Melo) - Add lock_pi stresser to 'perf bench futex', to test the kernel code related to FUTEX_(UN)LOCK_PI. (Davidlohr Bueso) - Let user have timestamps with per-thread recording in 'perf record' (Adrian Hunter) - ... and tons of other changes, see the shortlog and the Git log for details" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (240 commits) perf evlist: Add backpointer for perf_env to evlist perf tools: Rename perf_session_env to perf_env perf tools: Do not change lib/api/fs/debugfs directly perf tools: Add tracing_path and remove unneeded functions perf buildid: Introduce sysfs/filename__sprintf_build_id perf evsel: Add a backpointer to the evlist a evsel is in perf trace: Add header with copyright and background info perf scripts python: Add new compaction-times script perf stat: Get correct cpu id for print_aggr tools lib traceeveent: Allow for negative numbers in print format perf script: Add --[no-]-demangle/--[no-]-demangle-kernel tracing/uprobes: Do not print '0x (null)' when offset is 0 perf probe: Support probing at absolute address perf probe: Fix error reported when offset without function perf probe: Fix list result when address is zero perf probe: Fix list result when symbol can't be found tools build: Allow duplicate objects in the object list perf tools: Remove export.h from MANIFEST perf probe: Prevent segfault when reading probe point with absolute address perf tools: Update Intel PT documentation ...
Diffstat (limited to 'tools/perf/util/llvm-utils.c')
-rw-r--r--tools/perf/util/llvm-utils.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
new file mode 100644
index 000000000000..4f6a4780bd5f
--- /dev/null
+++ b/tools/perf/util/llvm-utils.c
@@ -0,0 +1,408 @@
1/*
2 * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
3 * Copyright (C) 2015, Huawei Inc.
4 */
5
6#include <stdio.h>
7#include <sys/utsname.h>
8#include "util.h"
9#include "debug.h"
10#include "llvm-utils.h"
11#include "cache.h"
12
13#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
14 "$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS " \
15 "$KERNEL_INC_OPTIONS -Wno-unused-value " \
16 "-Wno-pointer-sign -working-directory " \
17 "$WORKING_DIR -c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
18
19struct llvm_param llvm_param = {
20 .clang_path = "clang",
21 .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
22 .clang_opt = NULL,
23 .kbuild_dir = NULL,
24 .kbuild_opts = NULL,
25 .user_set_param = false,
26};
27
28int perf_llvm_config(const char *var, const char *value)
29{
30 if (prefixcmp(var, "llvm."))
31 return 0;
32 var += sizeof("llvm.") - 1;
33
34 if (!strcmp(var, "clang-path"))
35 llvm_param.clang_path = strdup(value);
36 else if (!strcmp(var, "clang-bpf-cmd-template"))
37 llvm_param.clang_bpf_cmd_template = strdup(value);
38 else if (!strcmp(var, "clang-opt"))
39 llvm_param.clang_opt = strdup(value);
40 else if (!strcmp(var, "kbuild-dir"))
41 llvm_param.kbuild_dir = strdup(value);
42 else if (!strcmp(var, "kbuild-opts"))
43 llvm_param.kbuild_opts = strdup(value);
44 else
45 return -1;
46 llvm_param.user_set_param = true;
47 return 0;
48}
49
50static int
51search_program(const char *def, const char *name,
52 char *output)
53{
54 char *env, *path, *tmp = NULL;
55 char buf[PATH_MAX];
56 int ret;
57
58 output[0] = '\0';
59 if (def && def[0] != '\0') {
60 if (def[0] == '/') {
61 if (access(def, F_OK) == 0) {
62 strlcpy(output, def, PATH_MAX);
63 return 0;
64 }
65 } else if (def[0] != '\0')
66 name = def;
67 }
68
69 env = getenv("PATH");
70 if (!env)
71 return -1;
72 env = strdup(env);
73 if (!env)
74 return -1;
75
76 ret = -ENOENT;
77 path = strtok_r(env, ":", &tmp);
78 while (path) {
79 scnprintf(buf, sizeof(buf), "%s/%s", path, name);
80 if (access(buf, F_OK) == 0) {
81 strlcpy(output, buf, PATH_MAX);
82 ret = 0;
83 break;
84 }
85 path = strtok_r(NULL, ":", &tmp);
86 }
87
88 free(env);
89 return ret;
90}
91
92#define READ_SIZE 4096
93static int
94read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
95{
96 int err = 0;
97 void *buf = NULL;
98 FILE *file = NULL;
99 size_t read_sz = 0, buf_sz = 0;
100
101 file = popen(cmd, "r");
102 if (!file) {
103 pr_err("ERROR: unable to popen cmd: %s\n",
104 strerror(errno));
105 return -EINVAL;
106 }
107
108 while (!feof(file) && !ferror(file)) {
109 /*
110 * Make buf_sz always have obe byte extra space so we
111 * can put '\0' there.
112 */
113 if (buf_sz - read_sz < READ_SIZE + 1) {
114 void *new_buf;
115
116 buf_sz = read_sz + READ_SIZE + 1;
117 new_buf = realloc(buf, buf_sz);
118
119 if (!new_buf) {
120 pr_err("ERROR: failed to realloc memory\n");
121 err = -ENOMEM;
122 goto errout;
123 }
124
125 buf = new_buf;
126 }
127 read_sz += fread(buf + read_sz, 1, READ_SIZE, file);
128 }
129
130 if (buf_sz - read_sz < 1) {
131 pr_err("ERROR: internal error\n");
132 err = -EINVAL;
133 goto errout;
134 }
135
136 if (ferror(file)) {
137 pr_err("ERROR: error occurred when reading from pipe: %s\n",
138 strerror(errno));
139 err = -EIO;
140 goto errout;
141 }
142
143 err = WEXITSTATUS(pclose(file));
144 file = NULL;
145 if (err) {
146 err = -EINVAL;
147 goto errout;
148 }
149
150 /*
151 * If buf is string, give it terminal '\0' to make our life
152 * easier. If buf is not string, that '\0' is out of space
153 * indicated by read_sz so caller won't even notice it.
154 */
155 ((char *)buf)[read_sz] = '\0';
156
157 if (!p_buf)
158 free(buf);
159 else
160 *p_buf = buf;
161
162 if (p_read_sz)
163 *p_read_sz = read_sz;
164 return 0;
165
166errout:
167 if (file)
168 pclose(file);
169 free(buf);
170 if (p_buf)
171 *p_buf = NULL;
172 if (p_read_sz)
173 *p_read_sz = 0;
174 return err;
175}
176
177static inline void
178force_set_env(const char *var, const char *value)
179{
180 if (value) {
181 setenv(var, value, 1);
182 pr_debug("set env: %s=%s\n", var, value);
183 } else {
184 unsetenv(var);
185 pr_debug("unset env: %s\n", var);
186 }
187}
188
189static void
190version_notice(void)
191{
192 pr_err(
193" \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n"
194" \tYou may want to try git trunk:\n"
195" \t\tgit clone http://llvm.org/git/llvm.git\n"
196" \t\t and\n"
197" \t\tgit clone http://llvm.org/git/clang.git\n\n"
198" \tOr fetch the latest clang/llvm 3.7 from pre-built llvm packages for\n"
199" \tdebian/ubuntu:\n"
200" \t\thttp://llvm.org/apt\n\n"
201" \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n"
202" \toption in [llvm] section of ~/.perfconfig to:\n\n"
203" \t \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS \\\n"
204" \t -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n"
205" \t -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n"
206" \t(Replace /path/to/llc with path to your llc)\n\n"
207);
208}
209
210static int detect_kbuild_dir(char **kbuild_dir)
211{
212 const char *test_dir = llvm_param.kbuild_dir;
213 const char *prefix_dir = "";
214 const char *suffix_dir = "";
215
216 char *autoconf_path;
217 struct utsname utsname;
218
219 int err;
220
221 if (!test_dir) {
222 err = uname(&utsname);
223 if (err) {
224 pr_warning("uname failed: %s\n", strerror(errno));
225 return -EINVAL;
226 }
227
228 test_dir = utsname.release;
229 prefix_dir = "/lib/modules/";
230 suffix_dir = "/build";
231 }
232
233 err = asprintf(&autoconf_path, "%s%s%s/include/generated/autoconf.h",
234 prefix_dir, test_dir, suffix_dir);
235 if (err < 0)
236 return -ENOMEM;
237
238 if (access(autoconf_path, R_OK) == 0) {
239 free(autoconf_path);
240
241 err = asprintf(kbuild_dir, "%s%s%s", prefix_dir, test_dir,
242 suffix_dir);
243 if (err < 0)
244 return -ENOMEM;
245 return 0;
246 }
247 free(autoconf_path);
248 return -ENOENT;
249}
250
251static const char *kinc_fetch_script =
252"#!/usr/bin/env sh\n"
253"if ! test -d \"$KBUILD_DIR\"\n"
254"then\n"
255" exit -1\n"
256"fi\n"
257"if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n"
258"then\n"
259" exit -1\n"
260"fi\n"
261"TMPDIR=`mktemp -d`\n"
262"if test -z \"$TMPDIR\"\n"
263"then\n"
264" exit -1\n"
265"fi\n"
266"cat << EOF > $TMPDIR/Makefile\n"
267"obj-y := dummy.o\n"
268"\\$(obj)/%.o: \\$(src)/%.c\n"
269"\t@echo -n \"\\$(NOSTDINC_FLAGS) \\$(LINUXINCLUDE) \\$(EXTRA_CFLAGS)\"\n"
270"EOF\n"
271"touch $TMPDIR/dummy.c\n"
272"make -s -C $KBUILD_DIR M=$TMPDIR $KBUILD_OPTS dummy.o 2>/dev/null\n"
273"RET=$?\n"
274"rm -rf $TMPDIR\n"
275"exit $RET\n";
276
277static inline void
278get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
279{
280 int err;
281
282 if (!kbuild_dir || !kbuild_include_opts)
283 return;
284
285 *kbuild_dir = NULL;
286 *kbuild_include_opts = NULL;
287
288 if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) {
289 pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n");
290 pr_debug("Skip kbuild options detection.\n");
291 return;
292 }
293
294 err = detect_kbuild_dir(kbuild_dir);
295 if (err) {
296 pr_warning(
297"WARNING:\tunable to get correct kernel building directory.\n"
298"Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n"
299" \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n"
300" \tdetection.\n\n");
301 return;
302 }
303
304 pr_debug("Kernel build dir is set to %s\n", *kbuild_dir);
305 force_set_env("KBUILD_DIR", *kbuild_dir);
306 force_set_env("KBUILD_OPTS", llvm_param.kbuild_opts);
307 err = read_from_pipe(kinc_fetch_script,
308 (void **)kbuild_include_opts,
309 NULL);
310 if (err) {
311 pr_warning(
312"WARNING:\tunable to get kernel include directories from '%s'\n"
313"Hint:\tTry set clang include options using 'clang-bpf-cmd-template'\n"
314" \toption in [llvm] section of ~/.perfconfig and set 'kbuild-dir'\n"
315" \toption in [llvm] to \"\" to suppress this detection.\n\n",
316 *kbuild_dir);
317
318 free(*kbuild_dir);
319 *kbuild_dir = NULL;
320 return;
321 }
322
323 pr_debug("include option is set to %s\n", *kbuild_include_opts);
324}
325
326int llvm__compile_bpf(const char *path, void **p_obj_buf,
327 size_t *p_obj_buf_sz)
328{
329 int err;
330 char clang_path[PATH_MAX];
331 const char *clang_opt = llvm_param.clang_opt;
332 const char *template = llvm_param.clang_bpf_cmd_template;
333 char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
334 void *obj_buf = NULL;
335 size_t obj_buf_sz;
336
337 if (!template)
338 template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
339
340 err = search_program(llvm_param.clang_path,
341 "clang", clang_path);
342 if (err) {
343 pr_err(
344"ERROR:\tunable to find clang.\n"
345"Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
346" \tand 'clang-path' option in [llvm] section of ~/.perfconfig.\n");
347 version_notice();
348 return -ENOENT;
349 }
350
351 /*
352 * This is an optional work. Even it fail we can continue our
353 * work. Needn't to check error return.
354 */
355 get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
356
357 force_set_env("CLANG_EXEC", clang_path);
358 force_set_env("CLANG_OPTIONS", clang_opt);
359 force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
360 force_set_env("WORKING_DIR", kbuild_dir ? : ".");
361
362 /*
363 * Since we may reset clang's working dir, path of source file
364 * should be transferred into absolute path, except we want
365 * stdin to be source file (testing).
366 */
367 force_set_env("CLANG_SOURCE",
368 (path[0] == '-') ? path :
369 make_nonrelative_path(path));
370
371 pr_debug("llvm compiling command template: %s\n", template);
372 err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
373 if (err) {
374 pr_err("ERROR:\tunable to compile %s\n", path);
375 pr_err("Hint:\tCheck error message shown above.\n");
376 pr_err("Hint:\tYou can also pre-compile it into .o using:\n");
377 pr_err(" \t\tclang -target bpf -O2 -c %s\n", path);
378 pr_err(" \twith proper -I and -D options.\n");
379 goto errout;
380 }
381
382 free(kbuild_dir);
383 free(kbuild_include_opts);
384 if (!p_obj_buf)
385 free(obj_buf);
386 else
387 *p_obj_buf = obj_buf;
388
389 if (p_obj_buf_sz)
390 *p_obj_buf_sz = obj_buf_sz;
391 return 0;
392errout:
393 free(kbuild_dir);
394 free(kbuild_include_opts);
395 free(obj_buf);
396 if (p_obj_buf)
397 *p_obj_buf = NULL;
398 if (p_obj_buf_sz)
399 *p_obj_buf_sz = 0;
400 return err;
401}
402
403int llvm__search_clang(void)
404{
405 char clang_path[PATH_MAX];
406
407 return search_program(llvm_param.clang_path, "clang", clang_path);
408}