Commit 0ca9b676 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates from Thomas Gleixner:
 "Mostly updates to the perf tool plus two fixes to the kernel core code:

   - Handle tracepoint filters correctly for inherited events (Peter
     Zijlstra)

   - Prevent a deadlock in perf_lock_task_context (Paul McKenney)

   - Add missing newlines to some pr_err() calls (Arnaldo Carvalho de
     Melo)

   - Print full source file paths when using 'perf annotate --print-line
     --full-paths' (Michael Petlan)

   - Fix 'perf probe -d' when just one out of uprobes and kprobes is
     enabled (Wang Nan)

   - Add compiler.h to list.h to fix 'make perf-tar-src-pkg' generated
     tarballs, i.e. out of tree building (Arnaldo Carvalho de Melo)

   - Add the llvm-src-base.c and llvm-src-kbuild.c files, generated by
     the 'perf test' LLVM entries, when running it in-tree, to
     .gitignore (Yunlong Song)

   - libbpf error reporting improvements, using a strerror interface to
     more precisely tell the user about problems with the provided
     scriptlet, be it in C or as a ready made object file (Wang Nan)

   - Do not be case sensitive when searching for matching 'perf test'
     entries (Arnaldo Carvalho de Melo)

   - Inform the user about objdump failures in 'perf annotate' (Andi
     Kleen)

   - Improve the LLVM 'perf test' entry, introduce a new ones for BPF
     and kbuild tests to check the environment used by clang to compile
     .c scriptlets (Wang Nan)"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (32 commits)
  perf/x86/intel/rapl: Remove the unused RAPL_EVENT_DESC() macro
  tools include: Add compiler.h to list.h
  perf probe: Verify parameters in two functions
  perf session: Add missing newlines to some pr_err() calls
  perf annotate: Support full source file paths for srcline fix
  perf test: Add llvm-src-base.c and llvm-src-kbuild.c to .gitignore
  perf: Fix inherited events vs. tracepoint filters
  perf: Disable IRQs across RCU RS CS that acquires scheduler lock
  perf test: Do not be case sensitive when searching for matching tests
  perf test: Add 'perf test BPF'
  perf test: Enhance the LLVM tests: add kbuild test
  perf test: Enhance the LLVM test: update basic BPF test program
  perf bpf: Improve BPF related error messages
  perf tools: Make fetch_kernel_version() publicly available
  bpf tools: Add new API bpf_object__get_kversion()
  bpf tools: Improve libbpf error reporting
  perf probe: Cleanup find_perf_probe_point_from_map to reduce redundancy
  perf annotate: Inform the user about objdump failures in --stdio
  perf stat: Make stat options global
  perf sched latency: Fix thread pid reuse issue
  ...
parents 051b29f2 41ac18eb
...@@ -107,12 +107,6 @@ static ssize_t __rapl_##_var##_show(struct kobject *kobj, \ ...@@ -107,12 +107,6 @@ static ssize_t __rapl_##_var##_show(struct kobject *kobj, \
static struct kobj_attribute format_attr_##_var = \ static struct kobj_attribute format_attr_##_var = \
__ATTR(_name, 0444, __rapl_##_var##_show, NULL) __ATTR(_name, 0444, __rapl_##_var##_show, NULL)
#define RAPL_EVENT_DESC(_name, _config) \
{ \
.attr = __ATTR(_name, 0444, rapl_event_show, NULL), \
.config = _config, \
}
#define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */ #define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */
#define RAPL_EVENT_ATTR_STR(_name, v, str) \ #define RAPL_EVENT_ATTR_STR(_name, v, str) \
......
...@@ -1050,13 +1050,13 @@ perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags) ...@@ -1050,13 +1050,13 @@ perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags)
/* /*
* One of the few rules of preemptible RCU is that one cannot do * One of the few rules of preemptible RCU is that one cannot do
* rcu_read_unlock() while holding a scheduler (or nested) lock when * rcu_read_unlock() while holding a scheduler (or nested) lock when
* part of the read side critical section was preemptible -- see * part of the read side critical section was irqs-enabled -- see
* rcu_read_unlock_special(). * rcu_read_unlock_special().
* *
* Since ctx->lock nests under rq->lock we must ensure the entire read * Since ctx->lock nests under rq->lock we must ensure the entire read
* side critical section is non-preemptible. * side critical section has interrupts disabled.
*/ */
preempt_disable(); local_irq_save(*flags);
rcu_read_lock(); rcu_read_lock();
ctx = rcu_dereference(task->perf_event_ctxp[ctxn]); ctx = rcu_dereference(task->perf_event_ctxp[ctxn]);
if (ctx) { if (ctx) {
...@@ -1070,21 +1070,22 @@ perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags) ...@@ -1070,21 +1070,22 @@ perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags)
* if so. If we locked the right context, then it * if so. If we locked the right context, then it
* can't get swapped on us any more. * can't get swapped on us any more.
*/ */
raw_spin_lock_irqsave(&ctx->lock, *flags); raw_spin_lock(&ctx->lock);
if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) { if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) {
raw_spin_unlock_irqrestore(&ctx->lock, *flags); raw_spin_unlock(&ctx->lock);
rcu_read_unlock(); rcu_read_unlock();
preempt_enable(); local_irq_restore(*flags);
goto retry; goto retry;
} }
if (!atomic_inc_not_zero(&ctx->refcount)) { if (!atomic_inc_not_zero(&ctx->refcount)) {
raw_spin_unlock_irqrestore(&ctx->lock, *flags); raw_spin_unlock(&ctx->lock);
ctx = NULL; ctx = NULL;
} }
} }
rcu_read_unlock(); rcu_read_unlock();
preempt_enable(); if (!ctx)
local_irq_restore(*flags);
return ctx; return ctx;
} }
...@@ -6913,6 +6914,10 @@ static int perf_tp_filter_match(struct perf_event *event, ...@@ -6913,6 +6914,10 @@ static int perf_tp_filter_match(struct perf_event *event,
{ {
void *record = data->raw->data; void *record = data->raw->data;
/* only top level events have filters set */
if (event->parent)
event = event->parent;
if (likely(!event->filter) || filter_match_preds(event->filter, record)) if (likely(!event->filter) || filter_match_preds(event->filter, record))
return 1; return 1;
return 0; return 0;
......
#include <linux/compiler.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
......
libbpf_version.h libbpf_version.h
FEATURE-DUMP FEATURE-DUMP.libbpf
...@@ -180,7 +180,7 @@ config-clean: ...@@ -180,7 +180,7 @@ config-clean:
clean: clean:
$(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \
$(RM) LIBBPF-CFLAGS $(RM) LIBBPF-CFLAGS
$(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf
......
This diff is collapsed.
...@@ -10,6 +10,26 @@ ...@@ -10,6 +10,26 @@
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <linux/err.h>
enum libbpf_errno {
__LIBBPF_ERRNO__START = 4000,
/* Something wrong in libelf */
LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START,
LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */
LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */
LIBBPF_ERRNO__ENDIAN, /* Endian missmatch */
LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */
LIBBPF_ERRNO__RELOC, /* Relocation failed */
LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */
LIBBPF_ERRNO__VERIFY, /* Kernel verifier blocks program loading */
LIBBPF_ERRNO__PROG2BIG, /* Program too big */
LIBBPF_ERRNO__KVER, /* Incorrect kernel version */
__LIBBPF_ERRNO__END,
};
int libbpf_strerror(int err, char *buf, size_t size);
/* /*
* In include/linux/compiler-gcc.h, __printf is defined. However * In include/linux/compiler-gcc.h, __printf is defined. However
...@@ -36,6 +56,7 @@ void bpf_object__close(struct bpf_object *object); ...@@ -36,6 +56,7 @@ void bpf_object__close(struct bpf_object *object);
int bpf_object__load(struct bpf_object *obj); int bpf_object__load(struct bpf_object *obj);
int bpf_object__unload(struct bpf_object *obj); int bpf_object__unload(struct bpf_object *obj);
const char *bpf_object__get_name(struct bpf_object *obj); const char *bpf_object__get_name(struct bpf_object *obj);
unsigned int bpf_object__get_kversion(struct bpf_object *obj);
struct bpf_object *bpf_object__next(struct bpf_object *prev); struct bpf_object *bpf_object__next(struct bpf_object *prev);
#define bpf_object__for_each_safe(pos, tmp) \ #define bpf_object__for_each_safe(pos, tmp) \
...@@ -63,7 +84,7 @@ int bpf_program__set_private(struct bpf_program *prog, void *priv, ...@@ -63,7 +84,7 @@ int bpf_program__set_private(struct bpf_program *prog, void *priv,
int bpf_program__get_private(struct bpf_program *prog, int bpf_program__get_private(struct bpf_program *prog,
void **ppriv); void **ppriv);
const char *bpf_program__title(struct bpf_program *prog, bool dup); const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
int bpf_program__fd(struct bpf_program *prog); int bpf_program__fd(struct bpf_program *prog);
......
...@@ -62,7 +62,6 @@ OPTIONS ...@@ -62,7 +62,6 @@ OPTIONS
--verbose=:: --verbose=::
Verbosity level. Verbosity level.
-i::
--no-inherit:: --no-inherit::
Child tasks do not inherit counters. Child tasks do not inherit counters.
......
...@@ -78,7 +78,7 @@ clean: ...@@ -78,7 +78,7 @@ clean:
# The build-test target is not really parallel, don't print the jobs info: # The build-test target is not really parallel, don't print the jobs info:
# #
build-test: build-test:
@$(MAKE) -f tests/make --no-print-directory @$(MAKE) SHUF=1 -f tests/make --no-print-directory
# #
# All other targets get passed through: # All other targets get passed through:
......
...@@ -1203,12 +1203,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ ...@@ -1203,12 +1203,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
static int pid_cmp(struct work_atoms *l, struct work_atoms *r) static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
{ {
if (l->thread == r->thread)
return 0;
if (l->thread->tid < r->thread->tid) if (l->thread->tid < r->thread->tid)
return -1; return -1;
if (l->thread->tid > r->thread->tid) if (l->thread->tid > r->thread->tid)
return 1; return 1;
return (int)(l->thread - r->thread);
return 0;
} }
static int avg_cmp(struct work_atoms *l, struct work_atoms *r) static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
......
This diff is collapsed.
llvm-src-base.c
llvm-src-kbuild.c
...@@ -31,9 +31,24 @@ perf-y += sample-parsing.o ...@@ -31,9 +31,24 @@ perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o perf-y += kmod-path.o
perf-y += thread-map.o perf-y += thread-map.o
perf-y += llvm.o perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o
perf-y += bpf.o
perf-y += topology.o perf-y += topology.o
$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
$(call rule_mkdir)
$(Q)echo '#include <tests/llvm.h>' > $@
$(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
$(Q)echo ';' >> $@
$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c
$(call rule_mkdir)
$(Q)echo '#include <tests/llvm.h>' > $@
$(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
$(Q)echo ';' >> $@
ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
endif endif
......
...@@ -171,6 +171,5 @@ int test__attr(void) ...@@ -171,6 +171,5 @@ int test__attr(void)
!lstat(path_perf, &st)) !lstat(path_perf, &st))
return run_dir(path_dir, path_perf); return run_dir(path_dir, path_perf);
fprintf(stderr, " (omitted)"); return TEST_SKIP;
return 0;
} }
/*
* bpf-script-example.c
* Test basic LLVM building
*/
#ifndef LINUX_VERSION_CODE #ifndef LINUX_VERSION_CODE
# error Need LINUX_VERSION_CODE # error Need LINUX_VERSION_CODE
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
......
/*
* bpf-script-test-kbuild.c
* Test include from kernel header
*/
#ifndef LINUX_VERSION_CODE
# error Need LINUX_VERSION_CODE
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
#endif
#define SEC(NAME) __attribute__((section(NAME), used))
#include <uapi/linux/fs.h>
#include <uapi/asm/ptrace.h>
SEC("func=vfs_llseek")
int bpf_func__vfs_llseek(void *ctx)
{
return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
#include <stdio.h>
#include <sys/epoll.h>
#include <util/bpf-loader.h>
#include <util/evlist.h>
#include "tests.h"
#include "llvm.h"
#include "debug.h"
#define NR_ITERS 111
#ifdef HAVE_LIBBPF_SUPPORT
static int epoll_pwait_loop(void)
{
int i;
/* Should fail NR_ITERS times */
for (i = 0; i < NR_ITERS; i++)
epoll_pwait(-(i + 1), NULL, 0, 0, NULL);
return 0;
}
static struct {
enum test_llvm__testcase prog_id;
const char *desc;
const char *name;
const char *msg_compile_fail;
const char *msg_load_fail;
int (*target_func)(void);
int expect_result;
} bpf_testcase_table[] = {
{
LLVM_TESTCASE_BASE,
"Test basic BPF filtering",
"[basic_bpf_test]",
"fix 'perf test LLVM' first",
"load bpf object failed",
&epoll_pwait_loop,
(NR_ITERS + 1) / 2,
},
};
static int do_test(struct bpf_object *obj, int (*func)(void),
int expect)
{
struct record_opts opts = {
.target = {
.uid = UINT_MAX,
.uses_mmap = true,
},
.freq = 0,
.mmap_pages = 256,
.default_interval = 1,
};
char pid[16];
char sbuf[STRERR_BUFSIZE];
struct perf_evlist *evlist;
int i, ret = TEST_FAIL, err = 0, count = 0;
struct parse_events_evlist parse_evlist;
struct parse_events_error parse_error;
bzero(&parse_error, sizeof(parse_error));
bzero(&parse_evlist, sizeof(parse_evlist));
parse_evlist.error = &parse_error;
INIT_LIST_HEAD(&parse_evlist.list);
err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj);
if (err || list_empty(&parse_evlist.list)) {
pr_debug("Failed to add events selected by BPF\n");
if (!err)
return TEST_FAIL;
}
snprintf(pid, sizeof(pid), "%d", getpid());
pid[sizeof(pid) - 1] = '\0';
opts.target.tid = opts.target.pid = pid;
/* Instead of perf_evlist__new_default, don't add default events */
evlist = perf_evlist__new();
if (!evlist) {
pr_debug("No ehough memory to create evlist\n");
return TEST_FAIL;
}
err = perf_evlist__create_maps(evlist, &opts.target);
if (err < 0) {
pr_debug("Not enough memory to create thread/cpu maps\n");
goto out_delete_evlist;
}
perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
evlist->nr_groups = parse_evlist.nr_groups;
perf_evlist__config(evlist, &opts);
err = perf_evlist__open(evlist);
if (err < 0) {
pr_debug("perf_evlist__open: %s\n",
strerror_r(errno, sbuf, sizeof(sbuf)));
goto out_delete_evlist;
}
err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
if (err < 0) {
pr_debug("perf_evlist__mmap: %s\n",
strerror_r(errno, sbuf, sizeof(sbuf)));
goto out_delete_evlist;
}
perf_evlist__enable(evlist);
(*func)();
perf_evlist__disable(evlist);
for (i = 0; i < evlist->nr_mmaps; i++) {
union perf_event *event;
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
const u32 type = event->header.type;
if (type == PERF_RECORD_SAMPLE)
count ++;
}
}
if (count != expect)
pr_debug("BPF filter result incorrect\n");
ret = TEST_OK;
out_delete_evlist:
perf_evlist__delete(evlist);
return ret;
}
static struct bpf_object *
prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
{
struct bpf_object *obj;
obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
if (IS_ERR(obj)) {
pr_debug("Compile BPF program failed.\n");
return NULL;
}
return obj;
}
static int __test__bpf(int index)
{
int ret;
void *obj_buf;
size_t obj_buf_sz;
struct bpf_object *obj;
ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
bpf_testcase_table[index].prog_id,
true);
if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
pr_debug("Unable to get BPF object, %s\n",
bpf_testcase_table[index].msg_compile_fail);
if (index == 0)
return TEST_SKIP;
else
return TEST_FAIL;
}
obj = prepare_bpf(obj_buf, obj_buf_sz,
bpf_testcase_table[index].name);
if (!obj) {
ret = TEST_FAIL;
goto out;
}
ret = do_test(obj,
bpf_testcase_table[index].target_func,
bpf_testcase_table[index].expect_result);
out:
bpf__clear();
return ret;
}
int test__bpf(void)
{
unsigned int i;
int err;
if (geteuid() != 0) {
pr_debug("Only root can run BPF test\n");
return TEST_SKIP;
}
for (i = 0; i < ARRAY_SIZE(bpf_testcase_table); i++) {
err = __test__bpf(i);
if (err != TEST_OK)
return err;
}
return TEST_OK;
}
#else
int test__bpf(void)
{
pr_debug("Skip BPF test because BPF support is not compiled\n");
return TEST_SKIP;
}
#endif
...@@ -165,6 +165,10 @@ static struct test generic_tests[] = { ...@@ -165,6 +165,10 @@ static struct test generic_tests[] = {
.desc = "Test topology in session", .desc = "Test topology in session",
.func = test_session_topology, .func = test_session_topology,
}, },
{
.desc = "Test BPF filter",
.func = test__bpf,
},
{ {
.func = NULL, .func = NULL,
}, },
...@@ -192,7 +196,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char ...@@ -192,7 +196,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
continue; continue;
} }
if (strstr(test->desc, argv[i])) if (strcasestr(test->desc, argv[i]))
return true; return true;
} }
......
...@@ -613,16 +613,16 @@ int test__code_reading(void) ...@@ -613,16 +613,16 @@ int test__code_reading(void)
case TEST_CODE_READING_OK: case TEST_CODE_READING_OK:
return 0; return 0;
case TEST_CODE_READING_NO_VMLINUX: case TEST_CODE_READING_NO_VMLINUX:
fprintf(stderr, " (no vmlinux)"); pr_debug("no vmlinux\n");
return 0; return 0;
case TEST_CODE_READING_NO_KCORE: case TEST_CODE_READING_NO_KCORE:
fprintf(stderr, " (no kcore)"); pr_debug("no kcore\n");
return 0; return 0;
case TEST_CODE_READING_NO_ACCESS: case TEST_CODE_READING_NO_ACCESS:
fprintf(stderr, " (no access)"); pr_debug("no access\n");
return 0; return 0;
case TEST_CODE_READING_NO_KERNEL_OBJ: case TEST_CODE_READING_NO_KERNEL_OBJ:
fprintf(stderr, " (no kernel obj)"); pr_debug("no kernel obj\n");
return 0; return 0;
default: default:
return -1; return -1;
......
...@@ -90,8 +90,8 @@ int test__keep_tracking(void) ...@@ -90,8 +90,8 @@ int test__keep_tracking(void)
evsel->attr.enable_on_exec = 0; evsel->attr.enable_on_exec = 0;
if (perf_evlist__open(evlist) < 0) { if (perf_evlist__open(evlist) < 0) {
fprintf(stderr, " (not supported)"); pr_debug("Unable to open dummy and cycles event\n");
err = 0; err = TEST_SKIP;
goto out_err; goto out_err;
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include <util/llvm-utils.h> #include <util/llvm-utils.h>
#include <util/cache.h> #include <util/cache.h>
#include "llvm.h"
#include "tests.h" #include "tests.h"
#include "debug.h" #include "debug.h"
...@@ -11,42 +12,58 @@ static int perf_config_cb(const char *var, const char *val, ...@@ -11,42 +12,58 @@ static int perf_config_cb(const char *var, const char *val,
return perf_default_config(var, val, arg); return perf_default_config(var, val, arg);
} }
/*
* Randomly give it a "version" section since we don't really load it
* into kernel
*/
static const char test_bpf_prog[] =
"__attribute__((section(\"do_fork\"), used)) "
"int fork(void *ctx) {return 0;} "
"char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";"
"int _version __attribute__((section(\"version\"), used)) = 0x40100;";
#ifdef HAVE_LIBBPF_SUPPORT #ifdef HAVE_LIBBPF_SUPPORT
static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
{ {
struct bpf_object *obj; struct bpf_object *obj;
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
if (!obj) if (IS_ERR(obj))
return -1; return TEST_FAIL;
bpf_object__close(obj); bpf_object__close(obj);
return 0; return TEST_OK;
} }
#else #else
static int test__bpf_parsing(void *obj_buf __maybe_unused, static int test__bpf_parsing(void *obj_buf __maybe_unused,
size_t obj_buf_sz __maybe_unused) size_t obj_buf_sz __maybe_unused)
{ {
fprintf(stderr, " (skip bpf parsing)"); pr_debug("Skip bpf parsing\n");
return 0; return TEST_OK;
} }
#endif #endif
int test__llvm(void) static struct {
const char *source;
const char *desc;
} bpf_source_table[__LLVM_TESTCASE_MAX] = {
[LLVM_TESTCASE_BASE] = {
.source = test_llvm__bpf_base_prog,
.desc = "Basic BPF llvm compiling test",
},
[LLVM_TESTCASE_KBUILD] = {
.source = test_llvm__bpf_test_kbuild_prog,
.desc = "Test kbuild searching",
},
};
int
test_llvm__fetch_bpf_obj(void **p_obj_buf,
size_t *p_obj_buf_sz,
enum test_llvm__testcase index,
bool force)
{ {
char *tmpl_new, *clang_opt_new; const char *source;
void *obj_buf; const char *desc;
size_t obj_buf_sz; const char *tmpl_old, *clang_opt_old;
int err, old_verbose; char *tmpl_new = NULL, *clang_opt_new = NULL;
int err, old_verbose, ret = TEST_FAIL;
if (index >= __LLVM_TESTCASE_MAX)
return TEST_FAIL;
source = bpf_source_table[index].source;
desc = bpf_source_table[index].desc;
perf_config(perf_config_cb, NULL); perf_config(perf_config_cb, NULL);
...@@ -54,45 +71,100 @@ int test__llvm(void) ...@@ -54,45 +71,100 @@ int test__llvm(void)
* Skip this test if user's .perfconfig doesn't set [llvm] section * Skip this test if user's .perfconfig doesn't set [llvm] section
* and clang is not found in $PATH, and this is not perf test -v * and clang is not found in $PATH, and this is not perf test -v
*/ */
if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) { if (!force && (verbose == 0 &&
fprintf(stderr, " (no clang, try 'perf test -v LLVM')"); !llvm_param.user_set_param &&
llvm__search_clang())) {
pr_debug("No clang and no verbosive, skip this test\n");
return TEST_SKIP; return TEST_SKIP;
} }
old_verbose = verbose;
/* /*
* llvm is verbosity when error. Suppress all error output if * llvm is verbosity when error. Suppress all error output if
* not 'perf test -v'. * not 'perf test -v'.
*/ */
old_verbose = verbose;
if (verbose == 0) if (verbose == 0)
verbose = -1; verbose = -1;
*p_obj_buf = NULL;
*p_obj_buf_sz = 0;
if (!llvm_param.clang_bpf_cmd_template) if (!llvm_param.clang_bpf_cmd_template)
return -1; goto out;
if (!llvm_param.clang_opt) if (!llvm_param.clang_opt)
llvm_param.clang_opt = strdup(""); llvm_param.clang_opt = strdup("");
err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog, err = asprintf(&tmpl_new, "echo '%s' | %s%s", source,
llvm_param.clang_bpf_cmd_template); llvm_param.clang_bpf_cmd_template,
old_verbose ? "" : " 2>/dev/null");
if (err < 0) if (err < 0)
return -1; goto out;
err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
if (err < 0) if (err < 0)
return -1; goto out;
tmpl_old = llvm_param.clang_bpf_cmd_template;
llvm_param.clang_bpf_cmd_template = tmpl_new; llvm_param.clang_bpf_cmd_template = tmpl_new;
clang_opt_old = llvm_param.clang_opt;
llvm_param.clang_opt = clang_opt_new; llvm_param.clang_opt = clang_opt_new;
err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz);
err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz);
llvm_param.clang_bpf_cmd_template = tmpl_old;
llvm_param.clang_opt = clang_opt_old;
verbose = old_verbose; verbose = old_verbose;
if (err) { if (err)
if (!verbose) goto out;
fprintf(stderr, " (use -v to see error message)");
return -1; ret = TEST_OK;
} out:
free(tmpl_new);
free(clang_opt_new);
if (ret != TEST_OK)
pr_debug("Failed to compile test case: '%s'\n", desc);
return ret;
}
int test__llvm(void)
{
enum test_llvm__testcase i;
for (i = 0; i < __LLVM_TESTCASE_MAX; i++) {
int ret;
void *obj_buf = NULL;
size_t obj_buf_sz = 0;
ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
i, false);
err = test__bpf_parsing(obj_buf, obj_buf_sz); if (ret == TEST_OK) {
free(obj_buf); ret = test__bpf_parsing(obj_buf, obj_buf_sz);
return err; if (ret != TEST_OK)
pr_debug("Failed to parse test case '%s'\n",
bpf_source_table[i].desc);
}
free(obj_buf);
switch (ret) {
case TEST_SKIP:
return TEST_SKIP;
case TEST_OK:
break;
default:
/*
* Test 0 is the basic LLVM test. If test 0
* fail, the basic LLVM support not functional
* so the whole test should fail. If other test
* case fail, it can be fixed by adjusting
* config so don't report error.
*/
if (i == 0)
return TEST_FAIL;
else
return TEST_SKIP;
}
}
return TEST_OK;
} }
#ifndef PERF_TEST_LLVM_H
#define PERF_TEST_LLVM_H
#include <stddef.h> /* for size_t */
#include <stdbool.h> /* for bool */
extern const char test_llvm__bpf_base_prog[];
extern const char test_llvm__bpf_test_kbuild_prog[];
enum test_llvm__testcase {
LLVM_TESTCASE_BASE,
LLVM_TESTCASE_KBUILD,
__LLVM_TESTCASE_MAX,
};
int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
enum test_llvm__testcase index, bool force);
#endif
...@@ -221,6 +221,11 @@ test_O = $(if $(test_$1),$(test_$1),$(test_default_O)) ...@@ -221,6 +221,11 @@ test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
all: all:
ifdef SHUF
run := $(shell shuf -e $(run))
run_O := $(shell shuf -e $(run_O))
endif
ifdef DEBUG ifdef DEBUG
d := $(info run $(run)) d := $(info run $(run))
d := $(info run_O $(run_O)) d := $(info run_O $(run_O))
......
...@@ -366,7 +366,7 @@ int test__switch_tracking(void) ...@@ -366,7 +366,7 @@ int test__switch_tracking(void)
/* Third event */ /* Third event */
if (!perf_evlist__can_select_event(evlist, sched_switch)) { if (!perf_evlist__can_select_event(evlist, sched_switch)) {
fprintf(stderr, " (no sched_switch)"); pr_debug("No sched_switch\n");
err = 0; err = 0;
goto out; goto out;
} }
...@@ -442,7 +442,7 @@ int test__switch_tracking(void) ...@@ -442,7 +442,7 @@ int test__switch_tracking(void)
} }
if (perf_evlist__open(evlist) < 0) { if (perf_evlist__open(evlist) < 0) {
fprintf(stderr, " (not supported)"); pr_debug("Not supported\n");
err = 0; err = 0;
goto out; goto out;
} }
......
...@@ -66,6 +66,7 @@ int test__fdarray__add(void); ...@@ -66,6 +66,7 @@ int test__fdarray__add(void);
int test__kmod_path__parse(void); int test__kmod_path__parse(void);
int test__thread_map(void); int test__thread_map(void);
int test__llvm(void); int test__llvm(void);
int test__bpf(void);
int test_session_topology(void); int test_session_topology(void);
#if defined(__arm__) || defined(__aarch64__) #if defined(__arm__) || defined(__aarch64__)
......
...@@ -1084,6 +1084,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -1084,6 +1084,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
struct kcore_extract kce; struct kcore_extract kce;
bool delete_extract = false; bool delete_extract = false;
int lineno = 0; int lineno = 0;
int nline;
if (filename) if (filename)
symbol__join_symfs(symfs_filename, filename); symbol__join_symfs(symfs_filename, filename);
...@@ -1179,6 +1180,9 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -1179,6 +1180,9 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
ret = decompress_to_file(m.ext, symfs_filename, fd); ret = decompress_to_file(m.ext, symfs_filename, fd);
if (ret)
pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename);
free(m.ext); free(m.ext);
close(fd); close(fd);
...@@ -1204,13 +1208,25 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -1204,13 +1208,25 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
pr_debug("Executing: %s\n", command); pr_debug("Executing: %s\n", command);
file = popen(command, "r"); file = popen(command, "r");
if (!file) if (!file) {
pr_err("Failure running %s\n", command);
/*
* If we were using debug info should retry with
* original binary.
*/
goto out_remove_tmp; goto out_remove_tmp;
}
while (!feof(file)) nline = 0;
while (!feof(file)) {
if (symbol__parse_objdump_line(sym, map, file, privsize, if (symbol__parse_objdump_line(sym, map, file, privsize,
&lineno) < 0) &lineno) < 0)
break; break;
nline++;
}
if (nline == 0)
pr_err("No output from %s\n", command);
/* /*
* kallsyms does not have symbol sizes so there may a nop at the end. * kallsyms does not have symbol sizes so there may a nop at the end.
...@@ -1604,6 +1620,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, ...@@ -1604,6 +1620,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
len = symbol__size(sym); len = symbol__size(sym);
if (print_lines) { if (print_lines) {
srcline_full_filename = full_paths;
symbol__get_source_line(sym, map, evsel, &source_line, len); symbol__get_source_line(sym, map, evsel, &source_line, len);
print_summary(&source_line, dso->long_name); print_summary(&source_line, dso->long_name);
} }
......
...@@ -26,18 +26,40 @@ static int libbpf_##name(const char *fmt, ...) \ ...@@ -26,18 +26,40 @@ static int libbpf_##name(const char *fmt, ...) \
return ret; \ return ret; \
} }
DEFINE_PRINT_FN(warning, 0) DEFINE_PRINT_FN(warning, 1)
DEFINE_PRINT_FN(info, 0) DEFINE_PRINT_FN(info, 1)
DEFINE_PRINT_FN(debug, 1) DEFINE_PRINT_FN(debug, 1)
struct bpf_prog_priv { struct bpf_prog_priv {
struct perf_probe_event pev; struct perf_probe_event pev;
}; };
static bool libbpf_initialized;
struct bpf_object *
bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
{
struct bpf_object *obj;
if (!libbpf_initialized) {
libbpf_set_print(libbpf_warning,
libbpf_info,
libbpf_debug);
libbpf_initialized = true;
}
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name);
if (IS_ERR(obj)) {
pr_debug("bpf: failed to load buffer\n");
return ERR_PTR(-EINVAL);
}
return obj;
}
struct bpf_object *bpf__prepare_load(const char *filename, bool source) struct bpf_object *bpf__prepare_load(const char *filename, bool source)
{ {
struct bpf_object *obj; struct bpf_object *obj;
static bool libbpf_initialized;
if (!libbpf_initialized) { if (!libbpf_initialized) {
libbpf_set_print(libbpf_warning, libbpf_set_print(libbpf_warning,
...@@ -53,15 +75,15 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) ...@@ -53,15 +75,15 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
free(obj_buf); free(obj_buf);
} else } else
obj = bpf_object__open(filename); obj = bpf_object__open(filename);
if (!obj) { if (IS_ERR(obj)) {
pr_debug("bpf: failed to load %s\n", filename); pr_debug("bpf: failed to load %s\n", filename);
return ERR_PTR(-EINVAL); return obj;
} }
return obj; return obj;
...@@ -96,9 +118,9 @@ config_bpf_program(struct bpf_program *prog) ...@@ -96,9 +118,9 @@ config_bpf_program(struct bpf_program *prog)
int err; int err;
config_str = bpf_program__title(prog, false); config_str = bpf_program__title(prog, false);
if (!config_str) { if (IS_ERR(config_str)) {
pr_debug("bpf: unable to get title for program\n"); pr_debug("bpf: unable to get title for program\n");
return -EINVAL; return PTR_ERR(config_str);
} }
priv = calloc(sizeof(*priv), 1); priv = calloc(sizeof(*priv), 1);
...@@ -113,14 +135,14 @@ config_bpf_program(struct bpf_program *prog) ...@@ -113,14 +135,14 @@ config_bpf_program(struct bpf_program *prog)
if (err < 0) { if (err < 0) {
pr_debug("bpf: '%s' is not a valid config string\n", pr_debug("bpf: '%s' is not a valid config string\n",
config_str); config_str);
err = -EINVAL; err = -BPF_LOADER_ERRNO__CONFIG;
goto errout; goto errout;
} }
if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
pr_debug("bpf: '%s': group for event is set and not '%s'.\n", pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
config_str, PERF_BPF_PROBE_GROUP); config_str, PERF_BPF_PROBE_GROUP);
err = -EINVAL; err = -BPF_LOADER_ERRNO__GROUP;
goto errout; goto errout;
} else if (!pev->group) } else if (!pev->group)
pev->group = strdup(PERF_BPF_PROBE_GROUP); pev->group = strdup(PERF_BPF_PROBE_GROUP);
...@@ -132,9 +154,9 @@ config_bpf_program(struct bpf_program *prog) ...@@ -132,9 +154,9 @@ config_bpf_program(struct bpf_program *prog)
} }
if (!pev->event) { if (!pev->event) {
pr_debug("bpf: '%s': event name is missing\n", pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n",
config_str); config_str);
err = -EINVAL; err = -BPF_LOADER_ERRNO__EVENTNAME;
goto errout; goto errout;
} }
pr_debug("bpf: config '%s' is ok\n", config_str); pr_debug("bpf: config '%s' is ok\n", config_str);
...@@ -285,7 +307,7 @@ int bpf__foreach_tev(struct bpf_object *obj, ...@@ -285,7 +307,7 @@ int bpf__foreach_tev(struct bpf_object *obj,
(void **)&priv); (void **)&priv);
if (err || !priv) { if (err || !priv) {
pr_debug("bpf: failed to get private field\n"); pr_debug("bpf: failed to get private field\n");
return -EINVAL; return -BPF_LOADER_ERRNO__INTERNAL;
} }
pev = &priv->pev; pev = &priv->pev;
...@@ -308,13 +330,57 @@ int bpf__foreach_tev(struct bpf_object *obj, ...@@ -308,13 +330,57 @@ int bpf__foreach_tev(struct bpf_object *obj,
return 0; return 0;
} }
#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
static const char *bpf_loader_strerror_table[NR_ERRNO] = {
[ERRCODE_OFFSET(CONFIG)] = "Invalid config string",
[ERRCODE_OFFSET(GROUP)] = "Invalid group name",
[ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string",
[ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error",
[ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet",
};
static int
bpf_loader_strerror(int err, char *buf, size_t size)
{
char sbuf[STRERR_BUFSIZE];
const char *msg;
if (!buf || !size)
return -1;
err = err > 0 ? err : -err;
if (err >= __LIBBPF_ERRNO__START)
return libbpf_strerror(err, buf, size);
if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) {
msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)];
snprintf(buf, size, "%s", msg);
buf[size - 1] = '\0';
return 0;
}
if (err >= __BPF_LOADER_ERRNO__END)
snprintf(buf, size, "Unknown bpf loader error %d", err);
else
snprintf(buf, size, "%s",
strerror_r(err, sbuf, sizeof(sbuf)));
buf[size - 1] = '\0';
return -1;
}
#define bpf__strerror_head(err, buf, size) \ #define bpf__strerror_head(err, buf, size) \
char sbuf[STRERR_BUFSIZE], *emsg;\ char sbuf[STRERR_BUFSIZE], *emsg;\
if (!size)\ if (!size)\
return 0;\ return 0;\
if (err < 0)\ if (err < 0)\
err = -err;\ err = -err;\
emsg = strerror_r(err, sbuf, sizeof(sbuf));\ bpf_loader_strerror(err, sbuf, sizeof(sbuf));\
emsg = sbuf;\
switch (err) {\ switch (err) {\
default:\ default:\
scnprintf(buf, size, "%s", emsg);\ scnprintf(buf, size, "%s", emsg);\
...@@ -330,23 +396,62 @@ int bpf__foreach_tev(struct bpf_object *obj, ...@@ -330,23 +396,62 @@ int bpf__foreach_tev(struct bpf_object *obj,
}\ }\
buf[size - 1] = '\0'; buf[size - 1] = '\0';
int bpf__strerror_prepare_load(const char *filename, bool source,
int err, char *buf, size_t size)
{
size_t n;
int ret;
n = snprintf(buf, size, "Failed to load %s%s: ",
filename, source ? " from source" : "");
if (n >= size) {
buf[size - 1] = '\0';
return 0;
}
buf += n;
size -= n;
ret = bpf_loader_strerror(err, buf, size);
buf[size - 1] = '\0';
return ret;
}
int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
int err, char *buf, size_t size) int err, char *buf, size_t size)
{ {
bpf__strerror_head(err, buf, size); bpf__strerror_head(err, buf, size);
bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'");
bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n"); bpf__strerror_entry(EACCES, "You need to be root");
bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n"); bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
bpf__strerror_end(buf, size); bpf__strerror_end(buf, size);
return 0; return 0;
} }
int bpf__strerror_load(struct bpf_object *obj __maybe_unused, int bpf__strerror_load(struct bpf_object *obj,
int err, char *buf, size_t size) int err, char *buf, size_t size)
{ {
bpf__strerror_head(err, buf, size); bpf__strerror_head(err, buf, size);
bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?", case LIBBPF_ERRNO__KVER: {
emsg) unsigned int obj_kver = bpf_object__get_kversion(obj);
unsigned int real_kver;
if (fetch_kernel_version(&real_kver, NULL, 0)) {
scnprintf(buf, size, "Unable to fetch kernel version");
break;
}
if (obj_kver != real_kver) {
scnprintf(buf, size,
"'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")",
KVER_PARAM(obj_kver),
KVER_PARAM(real_kver));
break;
}
scnprintf(buf, size, "Failed to load program for unknown reason");
break;
}
bpf__strerror_end(buf, size); bpf__strerror_end(buf, size);
return 0; return 0;
} }
...@@ -8,9 +8,21 @@ ...@@ -8,9 +8,21 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/err.h> #include <linux/err.h>
#include <string.h> #include <string.h>
#include <bpf/libbpf.h>
#include "probe-event.h" #include "probe-event.h"
#include "debug.h" #include "debug.h"
enum bpf_loader_errno {
__BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100,
/* Invalid config string */
BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START,
BPF_LOADER_ERRNO__GROUP, /* Invalid group name */
BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */
BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */
BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */
__BPF_LOADER_ERRNO__END,
};
struct bpf_object; struct bpf_object;
#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" #define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
...@@ -19,6 +31,11 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, ...@@ -19,6 +31,11 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
#ifdef HAVE_LIBBPF_SUPPORT #ifdef HAVE_LIBBPF_SUPPORT
struct bpf_object *bpf__prepare_load(const char *filename, bool source); struct bpf_object *bpf__prepare_load(const char *filename, bool source);
int bpf__strerror_prepare_load(const char *filename, bool source,
int err, char *buf, size_t size);
struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
const char *name);
void bpf__clear(void); void bpf__clear(void);
...@@ -41,6 +58,13 @@ bpf__prepare_load(const char *filename __maybe_unused, ...@@ -41,6 +58,13 @@ bpf__prepare_load(const char *filename __maybe_unused,
return ERR_PTR(-ENOTSUP); return ERR_PTR(-ENOTSUP);
} }
static inline struct bpf_object *
bpf__prepare_load_buffer(void *obj_buf __maybe_unused,
size_t obj_buf_sz __maybe_unused)
{
return ERR_PTR(-ENOTSUP);
}
static inline void bpf__clear(void) { } static inline void bpf__clear(void) { }
static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
...@@ -67,6 +91,15 @@ __bpf_strerror(char *buf, size_t size) ...@@ -67,6 +91,15 @@ __bpf_strerror(char *buf, size_t size)
return 0; return 0;
} }
static inline
int bpf__strerror_prepare_load(const char *filename __maybe_unused,
bool source __maybe_unused,
int err __maybe_unused,
char *buf, size_t size)
{
return __bpf_strerror(buf, size);
}
static inline int static inline int
bpf__strerror_probe(struct bpf_object *obj __maybe_unused, bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
int err __maybe_unused, int err __maybe_unused,
......
...@@ -4,17 +4,18 @@ ...@@ -4,17 +4,18 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <sys/utsname.h>
#include "util.h" #include "util.h"
#include "debug.h" #include "debug.h"
#include "llvm-utils.h" #include "llvm-utils.h"
#include "cache.h" #include "cache.h"
#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
"$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS " \ "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
"$KERNEL_INC_OPTIONS -Wno-unused-value " \ "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \
"-Wno-pointer-sign -working-directory " \ "$CLANG_OPTIONS $KERNEL_INC_OPTIONS " \
"$WORKING_DIR -c \"$CLANG_SOURCE\" -target bpf -O2 -o -" "-Wno-unused-value -Wno-pointer-sign " \
"-working-directory $WORKING_DIR " \
"-c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
struct llvm_param llvm_param = { struct llvm_param llvm_param = {
.clang_path = "clang", .clang_path = "clang",
...@@ -214,18 +215,19 @@ static int detect_kbuild_dir(char **kbuild_dir) ...@@ -214,18 +215,19 @@ static int detect_kbuild_dir(char **kbuild_dir)
const char *suffix_dir = ""; const char *suffix_dir = "";
char *autoconf_path; char *autoconf_path;
struct utsname utsname;
int err; int err;
if (!test_dir) { if (!test_dir) {
err = uname(&utsname); /* _UTSNAME_LENGTH is 65 */
if (err) { char release[128];
pr_warning("uname failed: %s\n", strerror(errno));
err = fetch_kernel_version(NULL, release,
sizeof(release));
if (err)
return -EINVAL; return -EINVAL;
}
test_dir = utsname.release; test_dir = release;
prefix_dir = "/lib/modules/"; prefix_dir = "/lib/modules/";
suffix_dir = "/build"; suffix_dir = "/build";
} }
...@@ -326,13 +328,15 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts) ...@@ -326,13 +328,15 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
int llvm__compile_bpf(const char *path, void **p_obj_buf, int llvm__compile_bpf(const char *path, void **p_obj_buf,
size_t *p_obj_buf_sz) size_t *p_obj_buf_sz)
{ {
int err; size_t obj_buf_sz;
char clang_path[PATH_MAX]; void *obj_buf = NULL;
int err, nr_cpus_avail;
unsigned int kernel_version;
char linux_version_code_str[64];
const char *clang_opt = llvm_param.clang_opt; const char *clang_opt = llvm_param.clang_opt;
const char *template = llvm_param.clang_bpf_cmd_template; char clang_path[PATH_MAX], nr_cpus_avail_str[64];
char *kbuild_dir = NULL, *kbuild_include_opts = NULL; char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
void *obj_buf = NULL; const char *template = llvm_param.clang_bpf_cmd_template;
size_t obj_buf_sz;
if (!template) if (!template)
template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
...@@ -354,6 +358,24 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, ...@@ -354,6 +358,24 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
*/ */
get_kbuild_opts(&kbuild_dir, &kbuild_include_opts); get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
if (nr_cpus_avail <= 0) {
pr_err(
"WARNING:\tunable to get available CPUs in this system: %s\n"
" \tUse 128 instead.\n", strerror(errno));
nr_cpus_avail = 128;
}
snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
nr_cpus_avail);
if (fetch_kernel_version(&kernel_version, NULL, 0))
kernel_version = 0;
snprintf(linux_version_code_str, sizeof(linux_version_code_str),
"0x%x", kernel_version);
force_set_env("NR_CPUS", nr_cpus_avail_str);
force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
force_set_env("CLANG_EXEC", clang_path); force_set_env("CLANG_EXEC", clang_path);
force_set_env("CLANG_OPTIONS", clang_opt); force_set_env("CLANG_OPTIONS", clang_opt);
force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
......
...@@ -644,6 +644,12 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) ...@@ -644,6 +644,12 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
return printed; return printed;
} }
static void __map_groups__insert(struct map_groups *mg, struct map *map)
{
__maps__insert(&mg->maps[map->type], map);
map->groups = mg;
}
static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
{ {
struct rb_root *root; struct rb_root *root;
...@@ -682,7 +688,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp ...@@ -682,7 +688,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
} }
before->end = map->start; before->end = map->start;
__maps__insert(maps, before); __map_groups__insert(pos->groups, before);
if (verbose >= 2) if (verbose >= 2)
map__fprintf(before, fp); map__fprintf(before, fp);
} }
...@@ -696,7 +702,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp ...@@ -696,7 +702,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
} }
after->start = map->end; after->start = map->end;
__maps__insert(maps, after); __map_groups__insert(pos->groups, after);
if (verbose >= 2) if (verbose >= 2)
map__fprintf(after, fp); map__fprintf(after, fp);
} }
......
...@@ -632,19 +632,20 @@ int parse_events_load_bpf(struct parse_events_evlist *data, ...@@ -632,19 +632,20 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
struct bpf_object *obj; struct bpf_object *obj;
obj = bpf__prepare_load(bpf_file_name, source); obj = bpf__prepare_load(bpf_file_name, source);
if (IS_ERR(obj) || !obj) { if (IS_ERR(obj)) {
char errbuf[BUFSIZ]; char errbuf[BUFSIZ];
int err; int err;
err = obj ? PTR_ERR(obj) : -EINVAL; err = PTR_ERR(obj);
if (err == -ENOTSUP) if (err == -ENOTSUP)
snprintf(errbuf, sizeof(errbuf), snprintf(errbuf, sizeof(errbuf),
"BPF support is not compiled"); "BPF support is not compiled");
else else
snprintf(errbuf, sizeof(errbuf), bpf__strerror_prepare_load(bpf_file_name,
"BPF object file '%s' is invalid", source,
bpf_file_name); -err, errbuf,
sizeof(errbuf));
data->error->help = strdup("(add -v to see detail)"); data->error->help = strdup("(add -v to see detail)");
data->error->str = strdup(errbuf); data->error->str = strdup(errbuf);
......
...@@ -1895,9 +1895,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, ...@@ -1895,9 +1895,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
sym = map__find_symbol(map, addr, NULL); sym = map__find_symbol(map, addr, NULL);
} else { } else {
if (tp->symbol && !addr) { if (tp->symbol && !addr) {
ret = kernel_get_symbol_address_by_name(tp->symbol, if (kernel_get_symbol_address_by_name(tp->symbol,
&addr, true, false); &addr, true, false) < 0)
if (ret < 0)
goto out; goto out;
} }
if (addr) { if (addr) {
...@@ -1905,6 +1904,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, ...@@ -1905,6 +1904,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
sym = __find_kernel_function(addr, &map); sym = __find_kernel_function(addr, &map);
} }
} }
if (!sym) if (!sym)
goto out; goto out;
......
...@@ -138,6 +138,9 @@ struct strlist *probe_file__get_rawlist(int fd) ...@@ -138,6 +138,9 @@ struct strlist *probe_file__get_rawlist(int fd)
char *p; char *p;
struct strlist *sl; struct strlist *sl;
if (fd < 0)
return NULL;
sl = strlist__new(NULL, NULL); sl = strlist__new(NULL, NULL);
fp = fdopen(dup(fd), "r"); fp = fdopen(dup(fd), "r");
...@@ -271,6 +274,9 @@ int probe_file__get_events(int fd, struct strfilter *filter, ...@@ -271,6 +274,9 @@ int probe_file__get_events(int fd, struct strfilter *filter,
const char *p; const char *p;
int ret = -ENOENT; int ret = -ENOENT;
if (!plist)
return -EINVAL;
namelist = __probe_file__get_namelist(fd, true); namelist = __probe_file__get_namelist(fd, true);
if (!namelist) if (!namelist)
return -ENOENT; return -ENOENT;
......
...@@ -29,7 +29,7 @@ static int perf_session__open(struct perf_session *session) ...@@ -29,7 +29,7 @@ static int perf_session__open(struct perf_session *session)
struct perf_data_file *file = session->file; struct perf_data_file *file = session->file;
if (perf_session__read_header(session) < 0) { if (perf_session__read_header(session) < 0) {
pr_err("incompatible file format (rerun with -v to learn more)"); pr_err("incompatible file format (rerun with -v to learn more)\n");
return -1; return -1;
} }
...@@ -37,17 +37,17 @@ static int perf_session__open(struct perf_session *session) ...@@ -37,17 +37,17 @@ static int perf_session__open(struct perf_session *session)
return 0; return 0;
if (!perf_evlist__valid_sample_type(session->evlist)) { if (!perf_evlist__valid_sample_type(session->evlist)) {
pr_err("non matching sample_type"); pr_err("non matching sample_type\n");
return -1; return -1;
} }
if (!perf_evlist__valid_sample_id_all(session->evlist)) { if (!perf_evlist__valid_sample_id_all(session->evlist)) {
pr_err("non matching sample_id_all"); pr_err("non matching sample_id_all\n");
return -1; return -1;
} }
if (!perf_evlist__valid_read_format(session->evlist)) { if (!perf_evlist__valid_read_format(session->evlist)) {
pr_err("non matching read_format"); pr_err("non matching read_format\n");
return -1; return -1;
} }
......
...@@ -413,6 +413,11 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, ...@@ -413,6 +413,11 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
ratio = total / avg; ratio = total / avg;
fprintf(out, " # %8.0f cycles / elision ", ratio); fprintf(out, " # %8.0f cycles / elision ", ratio);
} else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) {
if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
fprintf(out, " # %8.3f CPUs utilized ", avg / ratio);
else
fprintf(out, " ");
} else if (runtime_nsecs_stats[cpu].n != 0) { } else if (runtime_nsecs_stats[cpu].n != 0) {
char unit = 'M'; char unit = 'M';
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "debug.h" #include "debug.h"
#include <api/fs/fs.h> #include <api/fs/fs.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/utsname.h>
#ifdef HAVE_BACKTRACE_SUPPORT #ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h> #include <execinfo.h>
#endif #endif
...@@ -665,3 +666,32 @@ bool find_process(const char *name) ...@@ -665,3 +666,32 @@ bool find_process(const char *name)
closedir(dir); closedir(dir);
return ret ? false : true; return ret ? false : true;
} }
int
fetch_kernel_version(unsigned int *puint, char *str,
size_t str_size)
{
struct utsname utsname;
int version, patchlevel, sublevel, err;
if (uname(&utsname))
return -1;
if (str && str_size) {
strncpy(str, utsname.release, str_size);
str[str_size - 1] = '\0';
}
err = sscanf(utsname.release, "%d.%d.%d",
&version, &patchlevel, &sublevel);
if (err != 3) {
pr_debug("Unablt to get kernel version from uname '%s'\n",
utsname.release);
return -1;
}
if (puint)
*puint = (version << 16) + (patchlevel << 8) + sublevel;
return 0;
}
...@@ -350,4 +350,12 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int ...@@ -350,4 +350,12 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
int get_stack_size(const char *str, unsigned long *_size); int get_stack_size(const char *str, unsigned long *_size);
int fetch_kernel_version(unsigned int *puint,
char *str, size_t str_sz);
#define KVER_VERSION(x) (((x) >> 16) & 0xff)
#define KVER_PATCHLEVEL(x) (((x) >> 8) & 0xff)
#define KVER_SUBLEVEL(x) ((x) & 0xff)
#define KVER_FMT "%d.%d.%d"
#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
#endif /* GIT_COMPAT_UTIL_H */ #endif /* GIT_COMPAT_UTIL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment