diff options
Diffstat (limited to 'tools')
92 files changed, 1661 insertions, 444 deletions
diff --git a/tools/Makefile b/tools/Makefile index d6f307dfb1a3..7dc820a8c1f1 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -32,6 +32,10 @@ help: @echo ' from the kernel command line to build and install one of' @echo ' the tools above' @echo '' + @echo ' $$ make tools/all' + @echo '' + @echo ' builds all tools.' + @echo '' @echo ' $$ make tools/install' @echo '' @echo ' installs all tools.' @@ -77,6 +81,11 @@ tmon: FORCE freefall: FORCE $(call descend,laptop/$@) +all: acpi cgroup cpupower hv firewire lguest \ + perf selftests turbostat usb \ + virtio vm net x86_energy_perf_policy \ + tmon freefall + acpi_install: $(call descend,power/$(@:_install=),install) @@ -101,7 +110,7 @@ freefall_install: install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ perf_install selftests_install turbostat_install usb_install \ virtio_install vm_install net_install x86_energy_perf_policy_install \ - tmon freefall_install + tmon_install freefall_install acpi_clean: $(call descend,power/acpi,clean) diff --git a/tools/include/linux/list.h b/tools/include/linux/list.h index 76b014c96893..a017f1595676 100644 --- a/tools/include/linux/list.h +++ b/tools/include/linux/list.h @@ -1,3 +1,4 @@ +#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/types.h> diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore index 812aeedaea38..f81e549ddfdb 100644 --- a/tools/lib/bpf/.gitignore +++ b/tools/lib/bpf/.gitignore @@ -1,2 +1,2 @@ libbpf_version.h -FEATURE-DUMP +FEATURE-DUMP.libbpf diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index fc9af57b666e..a3caaf3eafbd 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -180,7 +180,7 @@ config-clean: clean: $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ $(RM) LIBBPF-CFLAGS - $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP + $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4252fc22f78f..e176bad19bcb 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -61,6 +61,60 @@ void libbpf_set_print(libbpf_print_fn_t warn, __pr_debug = debug; } +#define STRERR_BUFSIZE 128 + +#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START) +#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c) +#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START) + +static const char *libbpf_strerror_table[NR_ERRNO] = { + [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf", + [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid", + [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost", + [ERRCODE_OFFSET(ENDIAN)] = "Endian missmatch", + [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf", + [ERRCODE_OFFSET(RELOC)] = "Relocation failed", + [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading", + [ERRCODE_OFFSET(PROG2BIG)] = "Program too big", + [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version", +}; + +int libbpf_strerror(int err, char *buf, size_t size) +{ + if (!buf || !size) + return -1; + + err = err > 0 ? err : -err; + + if (err < __LIBBPF_ERRNO__START) { + int ret; + + ret = strerror_r(err, buf, size); + buf[size - 1] = '\0'; + return ret; + } + + if (err < __LIBBPF_ERRNO__END) { + const char *msg; + + msg = libbpf_strerror_table[ERRNO_OFFSET(err)]; + snprintf(buf, size, "%s", msg); + buf[size - 1] = '\0'; + return 0; + } + + snprintf(buf, size, "Unknown libbpf error %d", err); + buf[size - 1] = '\0'; + return -1; +} + +#define CHECK_ERR(action, err, out) do { \ + err = action; \ + if (err) \ + goto out; \ +} while(0) + + /* Copied from tools/perf/util/util.h */ #ifndef zfree # define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) @@ -258,7 +312,7 @@ static struct bpf_object *bpf_object__new(const char *path, obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1); if (!obj) { pr_warning("alloc memory failed for %s\n", path); - return NULL; + return ERR_PTR(-ENOMEM); } strcpy(obj->path, path); @@ -305,7 +359,7 @@ static int bpf_object__elf_init(struct bpf_object *obj) if (obj_elf_valid(obj)) { pr_warning("elf init: internal error\n"); - return -EEXIST; + return -LIBBPF_ERRNO__LIBELF; } if (obj->efile.obj_buf_sz > 0) { @@ -331,14 +385,14 @@ static int bpf_object__elf_init(struct bpf_object *obj) if (!obj->efile.elf) { pr_warning("failed to open %s as ELF file\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__LIBELF; goto errout; } if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) { pr_warning("failed to get EHDR from %s\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto errout; } ep = &obj->efile.ehdr; @@ -346,7 +400,7 @@ static int bpf_object__elf_init(struct bpf_object *obj) if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) { pr_warning("%s is not an eBPF object file\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto errout; } @@ -374,14 +428,14 @@ bpf_object__check_endianness(struct bpf_object *obj) goto mismatch; break; default: - return -EINVAL; + return -LIBBPF_ERRNO__ENDIAN; } return 0; mismatch: pr_warning("Error: endianness mismatch.\n"); - return -EINVAL; + return -LIBBPF_ERRNO__ENDIAN; } static int @@ -402,7 +456,7 @@ bpf_object__init_kversion(struct bpf_object *obj, if (size != sizeof(kver)) { pr_warning("invalid kver section in %s\n", obj->path); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } memcpy(&kver, data, sizeof(kver)); obj->kern_version = kver; @@ -444,7 +498,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { pr_warning("failed to get e_shstrndx from %s\n", obj->path); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } while ((scn = elf_nextscn(elf, scn)) != NULL) { @@ -456,7 +510,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (gelf_getshdr(scn, &sh) != &sh) { pr_warning("failed to get section header from %s\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto out; } @@ -464,7 +518,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (!name) { pr_warning("failed to get section name from %s\n", obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto out; } @@ -472,7 +526,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (!data) { pr_warning("failed to get section data from %s(%s)\n", name, obj->path); - err = -EINVAL; + err = -LIBBPF_ERRNO__FORMAT; goto out; } pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n", @@ -495,7 +549,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj) if (obj->efile.symbols) { pr_warning("bpf: multiple SYMTAB in %s\n", obj->path); - err = -EEXIST; + err = -LIBBPF_ERRNO__FORMAT; } else obj->efile.symbols = data; } else if ((sh.sh_type == SHT_PROGBITS) && @@ -504,7 +558,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj) err = bpf_object__add_program(obj, data->d_buf, data->d_size, name, idx); if (err) { - char errmsg[128]; + char errmsg[STRERR_BUFSIZE]; + strerror_r(-err, errmsg, sizeof(errmsg)); pr_warning("failed to alloc program %s (%s): %s", name, obj->path, errmsg); @@ -576,7 +631,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, if (!gelf_getrel(data, i, &rel)) { pr_warning("relocation: failed to get %d reloc\n", i); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } insn_idx = rel.r_offset / sizeof(struct bpf_insn); @@ -587,20 +642,20 @@ bpf_program__collect_reloc(struct bpf_program *prog, &sym)) { pr_warning("relocation: symbol %"PRIx64" not found\n", GELF_R_SYM(rel.r_info)); - return -EINVAL; + return -LIBBPF_ERRNO__FORMAT; } if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n", insn_idx, insns[insn_idx].code); - return -EINVAL; + return -LIBBPF_ERRNO__RELOC; } map_idx = sym.st_value / sizeof(struct bpf_map_def); if (map_idx >= nr_maps) { pr_warning("bpf relocation: map_idx %d large than %d\n", (int)map_idx, (int)nr_maps - 1); - return -EINVAL; + return -LIBBPF_ERRNO__RELOC; } prog->reloc_desc[i].insn_idx = insn_idx; @@ -683,7 +738,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds) if (insn_idx >= (int)prog->insns_cnt) { pr_warning("relocation out of range: '%s'\n", prog->section_name); - return -ERANGE; + return -LIBBPF_ERRNO__RELOC; } insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; insns[insn_idx].imm = map_fds[map_idx]; @@ -721,7 +776,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) if (!obj_elf_valid(obj)) { pr_warning("Internal error: elf object is closed\n"); - return -EINVAL; + return -LIBBPF_ERRNO__INTERNAL; } for (i = 0; i < obj->efile.nr_reloc; i++) { @@ -734,21 +789,21 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) if (shdr->sh_type != SHT_REL) { pr_warning("internal error at %d\n", __LINE__); - return -EINVAL; + return -LIBBPF_ERRNO__INTERNAL; } prog = bpf_object__find_prog_by_idx(obj, idx); if (!prog) { pr_warning("relocation failed: no %d section\n", idx); - return -ENOENT; + return -LIBBPF_ERRNO__RELOC; } err = bpf_program__collect_reloc(prog, nr_maps, shdr, data, obj->efile.symbols); if (err) - return -EINVAL; + return err; } return 0; } @@ -777,13 +832,23 @@ load_program(struct bpf_insn *insns, int insns_cnt, goto out; } - ret = -EINVAL; + ret = -LIBBPF_ERRNO__LOAD; pr_warning("load bpf program failed: %s\n", strerror(errno)); - if (log_buf) { + if (log_buf && log_buf[0] != '\0') { + ret = -LIBBPF_ERRNO__VERIFY; pr_warning("-- BEGIN DUMP LOG ---\n"); pr_warning("\n%s\n", log_buf); pr_warning("-- END LOG --\n"); + } else { + if (insns_cnt >= BPF_MAXINSNS) { + pr_warning("Program too large (%d insns), at most %d insns\n", + insns_cnt, BPF_MAXINSNS); + ret = -LIBBPF_ERRNO__PROG2BIG; + } else if (log_buf) { + pr_warning("log buffer is empty\n"); + ret = -LIBBPF_ERRNO__KVER; + } } out: @@ -831,7 +896,7 @@ static int bpf_object__validate(struct bpf_object *obj) if (obj->kern_version == 0) { pr_warning("%s doesn't provide kernel version\n", obj->path); - return -EINVAL; + return -LIBBPF_ERRNO__KVERSION; } return 0; } @@ -840,32 +905,28 @@ static struct bpf_object * __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz) { struct bpf_object *obj; + int err; if (elf_version(EV_CURRENT) == EV_NONE) { pr_warning("failed to init libelf for %s\n", path); - return NULL; + return ERR_PTR(-LIBBPF_ERRNO__LIBELF); } obj = bpf_object__new(path, obj_buf, obj_buf_sz); - if (!obj) - return NULL; + if (IS_ERR(obj)) + return obj; - if (bpf_object__elf_init(obj)) - goto out; - if (bpf_object__check_endianness(obj)) - goto out; - if (bpf_object__elf_collect(obj)) - goto out; - if (bpf_object__collect_reloc(obj)) - goto out; - if (bpf_object__validate(obj)) - goto out; + CHECK_ERR(bpf_object__elf_init(obj), err, out); + CHECK_ERR(bpf_object__check_endianness(obj), err, out); + CHECK_ERR(bpf_object__elf_collect(obj), err, out); + CHECK_ERR(bpf_object__collect_reloc(obj), err, out); + CHECK_ERR(bpf_object__validate(obj), err, out); bpf_object__elf_finish(obj); return obj; out: bpf_object__close(obj); - return NULL; + return ERR_PTR(err); } struct bpf_object *bpf_object__open(const char *path) @@ -922,6 +983,8 @@ int bpf_object__unload(struct bpf_object *obj) int bpf_object__load(struct bpf_object *obj) { + int err; + if (!obj) return -EINVAL; @@ -931,18 +994,16 @@ int bpf_object__load(struct bpf_object *obj) } obj->loaded = true; - if (bpf_object__create_maps(obj)) - goto out; - if (bpf_object__relocate(obj)) - goto out; - if (bpf_object__load_progs(obj)) - goto out; + + CHECK_ERR(bpf_object__create_maps(obj), err, out); + CHECK_ERR(bpf_object__relocate(obj), err, out); + CHECK_ERR(bpf_object__load_progs(obj), err, out); return 0; out: bpf_object__unload(obj); pr_warning("failed to load object '%s'\n", obj->path); - return -EINVAL; + return err; } void bpf_object__close(struct bpf_object *obj) @@ -990,10 +1051,18 @@ const char * bpf_object__get_name(struct bpf_object *obj) { if (!obj) - return NULL; + return ERR_PTR(-EINVAL); return obj->path; } +unsigned int +bpf_object__get_kversion(struct bpf_object *obj) +{ + if (!obj) + return 0; + return obj->kern_version; +} + struct bpf_program * bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) { @@ -1034,16 +1103,16 @@ int bpf_program__get_private(struct bpf_program *prog, void **ppriv) return 0; } -const char *bpf_program__title(struct bpf_program *prog, bool dup) +const char *bpf_program__title(struct bpf_program *prog, bool needs_copy) { const char *title; title = prog->section_name; - if (dup) { + if (needs_copy) { title = strdup(title); if (!title) { pr_warning("failed to strdup program title\n"); - return NULL; + return ERR_PTR(-ENOMEM); } } diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index f16170c95ffd..c9a9aef2806c 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -10,6 +10,26 @@ #include <stdio.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 @@ -36,6 +56,7 @@ void bpf_object__close(struct bpf_object *object); int bpf_object__load(struct bpf_object *obj); int bpf_object__unload(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); #define bpf_object__for_each_safe(pos, tmp) \ @@ -63,7 +84,7 @@ int bpf_program__set_private(struct bpf_program *prog, void *priv, int bpf_program__get_private(struct bpf_program *prog, 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); diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c index 8ef602f18a32..9be663340f0a 100644 --- a/tools/lib/lockdep/common.c +++ b/tools/lib/lockdep/common.c @@ -18,7 +18,7 @@ __attribute__((constructor)) static void liblockdep_init(void) __attribute__((destructor)) static void liblockdep_exit(void) { - debug_check_no_locks_held(¤t_obj); + debug_check_no_locks_held(); } struct task_struct *__curr(void) diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h index 0bda630027c3..a60c14b9662a 100644 --- a/tools/lib/lockdep/include/liblockdep/common.h +++ b/tools/lib/lockdep/include/liblockdep/common.h @@ -43,6 +43,8 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass, struct lockdep_map *nest_lock, unsigned long ip); void lock_release(struct lockdep_map *lock, int nested, unsigned long ip); +extern void debug_check_no_locks_freed(const void *from, unsigned long len); +extern void lockdep_init(void); #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ { .name = (_name), .key = (void *)(_key), } diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h index 7ac838a1f196..6386dc3182a0 100644 --- a/tools/lib/lockdep/uinclude/linux/compiler.h +++ b/tools/lib/lockdep/uinclude/linux/compiler.h @@ -3,5 +3,7 @@ #define __used __attribute__((__unused__)) #define unlikely +#define WRITE_ONCE(x, val) x=(val) +#define RCU_INIT_POINTER(p, v) p=(v) #endif diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h index c1552c28507e..c808c7d02d21 100644 --- a/tools/lib/lockdep/uinclude/linux/lockdep.h +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h @@ -6,7 +6,7 @@ #include <string.h> #include <limits.h> #include <linux/utsname.h> - +#include <linux/compiler.h> #define MAX_LOCK_DEPTH 2000UL @@ -54,5 +54,6 @@ static struct new_utsname *init_utsname(void) #define static_obj(x) 1 #define debug_show_all_locks() +extern void debug_check_no_locks_held(void); #endif diff --git a/tools/net/Makefile b/tools/net/Makefile index ee577ea03ba5..ddf888010652 100644 --- a/tools/net/Makefile +++ b/tools/net/Makefile @@ -4,6 +4,9 @@ CC = gcc LEX = flex YACC = bison +CFLAGS += -Wall -O2 +CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include + %.yacc.c: %.y $(YACC) -o $@ -d $< @@ -12,15 +15,13 @@ YACC = bison all : bpf_jit_disasm bpf_dbg bpf_asm -bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm' +bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm' bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl bpf_jit_disasm : bpf_jit_disasm.o -bpf_dbg : CFLAGS = -Wall -O2 bpf_dbg : LDLIBS = -lreadline bpf_dbg : bpf_dbg.o -bpf_asm : CFLAGS = -Wall -O2 -I. bpf_asm : LDLIBS = bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o bpf_exp.lex.o : bpf_exp.yacc.c diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 7ea078658a87..13293de8869f 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -62,7 +62,6 @@ OPTIONS --verbose=:: Verbosity level. --i:: --no-inherit:: Child tasks do not inherit counters. diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 480546d5f13b..dcd9a70c7193 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -78,7 +78,7 @@ clean: # The build-test target is not really parallel, don't print the jobs info: # build-test: - @$(MAKE) -f tests/make --no-print-directory + @$(MAKE) SHUF=1 -f tests/make --no-print-directory # # All other targets get passed through: diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 0a945d2e8ca5..99d127fe9c35 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -675,6 +675,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .fork = perf_event__repipe, .exit = perf_event__repipe, .lost = perf_event__repipe, + .lost_samples = perf_event__repipe, .aux = perf_event__repipe, .itrace_start = perf_event__repipe, .context_switch = perf_event__repipe, diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2853ad2bd435..f256fac1e722 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -44,7 +44,7 @@ struct report { struct perf_tool tool; struct perf_session *session; - bool force, use_tui, use_gtk, use_stdio; + bool use_tui, use_gtk, use_stdio; bool hide_unresolved; bool dont_use_callchains; bool show_full_info; @@ -678,7 +678,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "file", "vmlinux pathname"), OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", "kallsyms pathname"), - OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"), + OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, @@ -832,7 +832,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) } file.path = input_name; - file.force = report.force; + file.force = symbol_conf.force; repeat: session = perf_session__new(&file, false, &report.tool); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0ee6d900e100..e3d3e32c0a93 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -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) { + if (l->thread == r->thread) + return 0; if (l->thread->tid < r->thread->tid) return -1; if (l->thread->tid > r->thread->tid) return 1; - - return 0; + return (int)(l->thread - r->thread); } static int avg_cmp(struct work_atoms *l, struct work_atoms *r) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 2f438f76cceb..e77880b5094d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -122,6 +122,9 @@ static bool forever = false; static struct timespec ref_time; static struct cpu_map *aggr_map; static aggr_get_id_t aggr_get_id; +static bool append_file; +static const char *output_name; +static int output_fd; static volatile int done = 0; @@ -513,15 +516,6 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) if (evsel->cgrp) fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); - - if (csv_output || stat_config.interval) - return; - - if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) - fprintf(output, " # %8.3f CPUs utilized ", - avg / avg_stats(&walltime_nsecs_stats)); - else - fprintf(output, " "); } static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) @@ -529,7 +523,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) FILE *output = stat_config.output; double sc = evsel->scale; const char *fmt; - int cpu = cpu_map__id_to_cpu(id); if (csv_output) { fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; @@ -542,9 +535,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) aggr_printout(evsel, id, nr); - if (stat_config.aggr_mode == AGGR_GLOBAL) - cpu = 0; - fprintf(output, fmt, avg, csv_sep); if (evsel->unit) @@ -556,12 +546,24 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) if (evsel->cgrp) fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); +} - if (csv_output || stat_config.interval) - return; +static void printout(int id, int nr, struct perf_evsel *counter, double uval) +{ + int cpu = cpu_map__id_to_cpu(id); + + if (stat_config.aggr_mode == AGGR_GLOBAL) + cpu = 0; - perf_stat__print_shadow_stats(output, evsel, avg, cpu, - stat_config.aggr_mode); + if (nsec_counter(counter)) + nsec_printout(id, nr, counter, uval); + else + abs_printout(id, nr, counter, uval); + + if (!csv_output && !stat_config.interval) + perf_stat__print_shadow_stats(stat_config.output, counter, + uval, cpu, + stat_config.aggr_mode); } static void print_aggr(char *prefix) @@ -617,12 +619,7 @@ static void print_aggr(char *prefix) continue; } uval = val * counter->scale; - - if (nsec_counter(counter)) - nsec_printout(id, nr, counter, uval); - else - abs_printout(id, nr, counter, uval); - + printout(id, nr, counter, uval); if (!csv_output) print_noise(counter, 1.0); @@ -653,11 +650,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix) fprintf(output, "%s", prefix); uval = val * counter->scale; - - if (nsec_counter(counter)) - nsec_printout(thread, 0, counter, uval); - else - abs_printout(thread, 0, counter, uval); + printout(thread, 0, counter, uval); if (!csv_output) print_noise(counter, 1.0); @@ -707,11 +700,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) } uval = avg * counter->scale; - - if (nsec_counter(counter)) - nsec_printout(-1, 0, counter, uval); - else - abs_printout(-1, 0, counter, uval); + printout(-1, 0, counter, uval); print_noise(counter, avg); @@ -764,12 +753,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix) } uval = val * counter->scale; - - if (nsec_counter(counter)) - nsec_printout(cpu, 0, counter, uval); - else - abs_printout(cpu, 0, counter, uval); - + printout(cpu, 0, counter, uval); if (!csv_output) print_noise(counter, 1.0); print_running(run, ena); @@ -946,6 +930,67 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, return 0; } +static const struct option stat_options[] = { + OPT_BOOLEAN('T', "transaction", &transaction_run, + "hardware transaction statistics"), + OPT_CALLBACK('e', "event", &evsel_list, "event", + "event selector. use 'perf list' to list available events", + parse_events_option), + OPT_CALLBACK(0, "filter", &evsel_list, "filter", + "event filter", parse_filter), + OPT_BOOLEAN('i', "no-inherit", &no_inherit, + "child tasks do not inherit counters"), + OPT_STRING('p', "pid", &target.pid, "pid", + "stat events on existing process id"), + OPT_STRING('t', "tid", &target.tid, "tid", + "stat events on existing thread id"), + OPT_BOOLEAN('a', "all-cpus", &target.system_wide, + "system-wide collection from all CPUs"), + OPT_BOOLEAN('g', "group", &group, + "put the counters into a counter group"), + OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), + OPT_INCR('v', "verbose", &verbose, + "be more verbose (show counter open errors, etc)"), + OPT_INTEGER('r', "repeat", &run_count, + "repeat command and print average + stddev (max: 100, forever: 0)"), + OPT_BOOLEAN('n', "null", &null_run, + "null run - dont start any counters"), + OPT_INCR('d', "detailed", &detailed_run, + "detailed run - start a lot of events"), + OPT_BOOLEAN('S', "sync", &sync_run, + "call sync() before starting a run"), + OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, + "print large numbers with thousands\' separators", + stat__set_big_num), + OPT_STRING('C', "cpu", &target.cpu_list, "cpu", + "list of cpus to monitor in system-wide"), + OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, + "disable CPU count aggregation", AGGR_NONE), + OPT_STRING('x', "field-separator", &csv_sep, "separator", + "print counts with custom separator"), + OPT_CALLBACK('G', "cgroup", &evsel_list, "name", + "monitor event in cgroup name only", parse_cgroups), + OPT_STRING('o', "output", &output_name, "file", "output file name"), + OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), + OPT_INTEGER(0, "log-fd", &output_fd, + "log output to fd, instead of stderr"), + OPT_STRING(0, "pre", &pre_cmd, "command", + "command to run prior to the measured command"), + OPT_STRING(0, "post", &post_cmd, "command", + "command to run after to the measured command"), + OPT_UINTEGER('I', "interval-print", &stat_config.interval, + "print counts at regular interval in ms (>= 10)"), + OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, + "aggregate counts per processor socket", AGGR_SOCKET), + OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, + "aggregate counts per physical processor core", AGGR_CORE), + OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, + "aggregate counts per thread", AGGR_THREAD), + OPT_UINTEGER('D', "delay", &initial_delay, + "ms to wait before starting measurement after program start"), + OPT_END() +}; + static int perf_stat__get_socket(struct cpu_map *map, int cpu) { return cpu_map__get_socket(map, cpu, NULL); @@ -1193,69 +1238,6 @@ static int add_default_attributes(void) int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) { - bool append_file = false; - int output_fd = 0; - const char *output_name = NULL; - const struct option options[] = { - OPT_BOOLEAN('T', "transaction", &transaction_run, - "hardware transaction statistics"), - OPT_CALLBACK('e', "event", &evsel_list, "event", - "event selector. use 'perf list' to list available events", - parse_events_option), - OPT_CALLBACK(0, "filter", &evsel_list, "filter", - "event filter", parse_filter), - OPT_BOOLEAN('i', "no-inherit", &no_inherit, - "child tasks do not inherit counters"), - OPT_STRING('p', "pid", &target.pid, "pid", - "stat events on existing process id"), - OPT_STRING('t', "tid", &target.tid, "tid", - "stat events on existing thread id"), - OPT_BOOLEAN('a', "all-cpus", &target.system_wide, - "system-wide collection from all CPUs"), - OPT_BOOLEAN('g', "group", &group, - "put the counters into a counter group"), - OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"), - OPT_INCR('v', "verbose", &verbose, - "be more verbose (show counter open errors, etc)"), - OPT_INTEGER('r', "repeat", &run_count, - "repeat command and print average + stddev (max: 100, forever: 0)"), - OPT_BOOLEAN('n', "null", &null_run, - "null run - dont start any counters"), - OPT_INCR('d', "detailed", &detailed_run, - "detailed run - start a lot of events"), - OPT_BOOLEAN('S', "sync", &sync_run, - "call sync() before starting a run"), - OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, - "print large numbers with thousands\' separators", - stat__set_big_num), - OPT_STRING('C', "cpu", &target.cpu_list, "cpu", - "list of cpus to monitor in system-wide"), - OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, - "disable CPU count aggregation", AGGR_NONE), - OPT_STRING('x', "field-separator", &csv_sep, "separator", - "print counts with custom separator"), - OPT_CALLBACK('G', "cgroup", &evsel_list, "name", - "monitor event in cgroup name only", parse_cgroups), - OPT_STRING('o', "output", &output_name, "file", "output file name"), - OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), - OPT_INTEGER(0, "log-fd", &output_fd, - "log output to fd, instead of stderr"), - OPT_STRING(0, "pre", &pre_cmd, "command", - "command to run prior to the measured command"), - OPT_STRING(0, "post", &post_cmd, "command", - "command to run after to the measured command"), - OPT_UINTEGER('I', "interval-print", &stat_config.interval, - "print counts at regular interval in ms (>= 10)"), - OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, - "aggregate counts per processor socket", AGGR_SOCKET), - OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, - "aggregate counts per physical processor core", AGGR_CORE), - OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, - "aggregate counts per thread", AGGR_THREAD), - OPT_UINTEGER('D', "delay", &initial_delay, - "ms to wait before starting measurement after program start"), - OPT_END() - }; const char * const stat_usage[] = { "perf stat [<options>] [<command>]", NULL @@ -1271,7 +1253,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) if (evsel_list == NULL) return -ENOMEM; - argc = parse_options(argc, argv, options, stat_usage, + argc = parse_options(argc, argv, stat_options, stat_usage, PARSE_OPT_STOP_AT_NON_OPTION); interval = stat_config.interval; @@ -1281,14 +1263,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) if (output_name && output_fd) { fprintf(stderr, "cannot use both --output and --log-fd\n"); - parse_options_usage(stat_usage, options, "o", 1); - parse_options_usage(NULL, options, "log-fd", 0); + parse_options_usage(stat_usage, stat_options, "o", 1); + parse_options_usage(NULL, stat_options, "log-fd", 0); goto out; } if (output_fd < 0) { fprintf(stderr, "argument to --log-fd must be a > 0\n"); - parse_options_usage(stat_usage, options, "log-fd", 0); + parse_options_usage(stat_usage, stat_options, "log-fd", 0); goto out; } @@ -1328,8 +1310,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) /* User explicitly passed -B? */ if (big_num_opt == 1) { fprintf(stderr, "-B option not supported with -x\n"); - parse_options_usage(stat_usage, options, "B", 1); - parse_options_usage(NULL, options, "x", 1); + parse_options_usage(stat_usage, stat_options, "B", 1); + parse_options_usage(NULL, stat_options, "x", 1); goto out; } else /* Nope, so disable big number formatting */ big_num = false; @@ -1337,11 +1319,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) big_num = false; if (!argc && target__none(&target)) - usage_with_options(stat_usage, options); + usage_with_options(stat_usage, stat_options); if (run_count < 0) { pr_err("Run count must be a positive number\n"); - parse_options_usage(stat_usage, options, "r", 1); + parse_options_usage(stat_usage, stat_options, "r", 1); goto out; } else if (run_count == 0) { forever = true; @@ -1351,8 +1333,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { fprintf(stderr, "The --per-thread option is only available " "when monitoring via -p -t options.\n"); - parse_options_usage(NULL, options, "p", 1); - parse_options_usage(NULL, options, "t", 1); + parse_options_usage(NULL, stat_options, "p", 1); + parse_options_usage(NULL, stat_options, "t", 1); goto out; } @@ -1366,9 +1348,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) fprintf(stderr, "both cgroup and no-aggregation " "modes only available in system-wide mode\n"); - parse_options_usage(stat_usage, options, "G", 1); - parse_options_usage(NULL, options, "A", 1); - parse_options_usage(NULL, options, "a", 1); + parse_options_usage(stat_usage, stat_options, "G", 1); + parse_options_usage(NULL, stat_options, "A", 1); + parse_options_usage(NULL, stat_options, "a", 1); goto out; } @@ -1380,12 +1362,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) if (perf_evlist__create_maps(evsel_list, &target) < 0) { if (target__has_task(&target)) { pr_err("Problems finding threads of monitor\n"); - parse_options_usage(stat_usage, options, "p", 1); - parse_options_usage(NULL, options, "t", 1); + parse_options_usage(stat_usage, stat_options, "p", 1); + parse_options_usage(NULL, stat_options, "t", 1); } else if (target__has_cpu(&target)) { perror("failed to parse CPUs map"); - parse_options_usage(stat_usage, options, "C", 1); - parse_options_usage(NULL, options, "a", 1); + parse_options_usage(stat_usage, stat_options, "C", 1); + parse_options_usage(NULL, stat_options, "a", 1); } goto out; } @@ -1400,7 +1382,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) if (interval && interval < 100) { if (interval < 10) { pr_err("print interval must be >= 10ms\n"); - parse_options_usage(stat_usage, options, "I", 1); + parse_options_usage(stat_usage, stat_options, "I", 1); goto out; } else pr_warning("print interval < 100ms. " diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore new file mode 100644 index 000000000000..489fc9ffbcb0 --- /dev/null +++ b/tools/perf/tests/.gitignore @@ -0,0 +1,2 @@ +llvm-src-base.c +llvm-src-kbuild.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 50de2253cff6..f41ebf8849fe 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -31,9 +31,24 @@ perf-y += sample-parsing.o perf-y += parse-no-sample-id-all.o perf-y += kmod-path.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 +$(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)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o endif diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index 2dfc9ad0e6f2..638875a0960a 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c @@ -171,6 +171,5 @@ int test__attr(void) !lstat(path_perf, &st)) return run_dir(path_dir, path_perf); - fprintf(stderr, " (omitted)"); - return 0; + return TEST_SKIP; } diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c index 410a70b93b93..0ec9c2c03164 100644 --- a/tools/perf/tests/bpf-script-example.c +++ b/tools/perf/tests/bpf-script-example.c @@ -1,3 +1,7 @@ +/* + * bpf-script-example.c + * Test basic LLVM building + */ #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' diff --git a/tools/perf/tests/bpf-script-test-kbuild.c b/tools/perf/tests/bpf-script-test-kbuild.c new file mode 100644 index 000000000000..3626924740d8 --- /dev/null +++ b/tools/perf/tests/bpf-script-test-kbuild.c @@ -0,0 +1,21 @@ +/* + * 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; diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c new file mode 100644 index 000000000000..ec16f7812c8b --- /dev/null +++ b/tools/perf/tests/bpf.c @@ -0,0 +1,209 @@ +#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 diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 66f72d3d6677..80c442eab767 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -166,6 +166,10 @@ static struct test generic_tests[] = { .func = test_session_topology, }, { + .desc = "Test BPF filter", + .func = test__bpf, + }, + { .func = NULL, }, }; @@ -192,7 +196,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char continue; } - if (strstr(test->desc, argv[i])) + if (strcasestr(test->desc, argv[i])) return true; } diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 49b1959dda41..a767a6400c5c 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -613,16 +613,16 @@ int test__code_reading(void) case TEST_CODE_READING_OK: return 0; case TEST_CODE_READING_NO_VMLINUX: - fprintf(stderr, " (no vmlinux)"); + pr_debug("no vmlinux\n"); return 0; case TEST_CODE_READING_NO_KCORE: - fprintf(stderr, " (no kcore)"); + pr_debug("no kcore\n"); return 0; case TEST_CODE_READING_NO_ACCESS: - fprintf(stderr, " (no access)"); + pr_debug("no access\n"); return 0; case TEST_CODE_READING_NO_KERNEL_OBJ: - fprintf(stderr, " (no kernel obj)"); + pr_debug("no kernel obj\n"); return 0; default: return -1; diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 4d4b9837b630..a2e2269aa093 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c @@ -90,8 +90,8 @@ int test__keep_tracking(void) evsel->attr.enable_on_exec = 0; if (perf_evlist__open(evlist) < 0) { - fprintf(stderr, " (not supported)"); - err = 0; + pr_debug("Unable to open dummy and cycles event\n"); + err = TEST_SKIP; goto out_err; } diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index 52d55971f66f..bc4cf507cde5 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c @@ -2,6 +2,7 @@ #include <bpf/libbpf.h> #include <util/llvm-utils.h> #include <util/cache.h> +#include "llvm.h" #include "tests.h" #include "debug.h" @@ -11,42 +12,58 @@ static int perf_config_cb(const char *var, const char *val, 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 static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) { struct bpf_object *obj; obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); - if (!obj) - return -1; + if (IS_ERR(obj)) + return TEST_FAIL; bpf_object__close(obj); - return 0; + return TEST_OK; } #else static int test__bpf_parsing(void *obj_buf __maybe_unused, size_t obj_buf_sz __maybe_unused) { - fprintf(stderr, " (skip bpf parsing)"); - return 0; + pr_debug("Skip bpf parsing\n"); + return TEST_OK; } #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; - void *obj_buf; - size_t obj_buf_sz; - int err, old_verbose; + const char *source; + const char *desc; + const char *tmpl_old, *clang_opt_old; + 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); @@ -54,45 +71,100 @@ int test__llvm(void) * 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 */ - if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) { - fprintf(stderr, " (no clang, try 'perf test -v LLVM')"); + if (!force && (verbose == 0 && + !llvm_param.user_set_param && + llvm__search_clang())) { + pr_debug("No clang and no verbosive, skip this test\n"); return TEST_SKIP; } - old_verbose = verbose; /* * llvm is verbosity when error. Suppress all error output if * not 'perf test -v'. */ + old_verbose = verbose; if (verbose == 0) verbose = -1; + *p_obj_buf = NULL; + *p_obj_buf_sz = 0; + if (!llvm_param.clang_bpf_cmd_template) - return -1; + goto out; if (!llvm_param.clang_opt) llvm_param.clang_opt = strdup(""); - err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog, - llvm_param.clang_bpf_cmd_template); + err = asprintf(&tmpl_new, "echo '%s' | %s%s", source, + llvm_param.clang_bpf_cmd_template, + old_verbose ? "" : " 2>/dev/null"); if (err < 0) - return -1; + goto out; err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); if (err < 0) - return -1; + goto out; + tmpl_old = llvm_param.clang_bpf_cmd_template; llvm_param.clang_bpf_cmd_template = tmpl_new; + clang_opt_old = llvm_param.clang_opt; 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; - if (err) { - if (!verbose) - fprintf(stderr, " (use -v to see error message)"); - return -1; - } + if (err) + goto out; + + 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); - free(obj_buf); - return err; + if (ret == TEST_OK) { + ret = test__bpf_parsing(obj_buf, obj_buf_sz); + 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; } diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h new file mode 100644 index 000000000000..d91d8f44efee --- /dev/null +++ b/tools/perf/tests/llvm.h @@ -0,0 +1,18 @@ +#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 diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 2cbd0c6901e3..8ea3dffc5065 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -221,6 +221,11 @@ test_O = $(if $(test_$1),$(test_$1),$(test_default_O)) all: +ifdef SHUF +run := $(shell shuf -e $(run)) +run_O := $(shell shuf -e $(run_O)) +endif + ifdef DEBUG d := $(info run $(run)) d := $(info run_O $(run_O)) diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index e698742d4fec..a02af503100c 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c @@ -366,7 +366,7 @@ int test__switch_tracking(void) /* Third event */ if (!perf_evlist__can_select_event(evlist, sched_switch)) { - fprintf(stderr, " (no sched_switch)"); + pr_debug("No sched_switch\n"); err = 0; goto out; } @@ -442,7 +442,7 @@ int test__switch_tracking(void) } if (perf_evlist__open(evlist) < 0) { - fprintf(stderr, " (not supported)"); + pr_debug("Not supported\n"); err = 0; goto out; } diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index c80486969f83..3c8734a3abbc 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -66,6 +66,7 @@ int test__fdarray__add(void); int test__kmod_path__parse(void); int test__thread_map(void); int test__llvm(void); +int test__bpf(void); int test_session_topology(void); #if defined(__arm__) || defined(__aarch64__) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e5afb8936040..fa9eb92c9e24 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1430,7 +1430,6 @@ close_file_and_continue: struct popup_action { struct thread *thread; - struct dso *dso; struct map_symbol ms; int socket; @@ -1565,7 +1564,6 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act, return 0; act->ms.map = map; - act->dso = map->dso; act->fn = do_zoom_dso; return 1; } @@ -1827,7 +1825,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, while (1) { struct thread *thread = NULL; - struct dso *dso = NULL; struct map *map = NULL; int choice = 0; int socked_id = -1; @@ -1839,8 +1836,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, if (browser->he_selection != NULL) { thread = hist_browser__selected_thread(browser); map = browser->selection->map; - if (map) - dso = map->dso; socked_id = browser->he_selection->socket; } switch (key) { @@ -1874,7 +1869,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, hist_browser__dump(browser); continue; case 'd': - actions->dso = dso; + actions->ms.map = map; do_zoom_dso(browser, actions); continue; case 'V': diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0fc8d7a2fea5..1dd1949b0e79 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1084,6 +1084,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) struct kcore_extract kce; bool delete_extract = false; int lineno = 0; + int nline; if (filename) symbol__join_symfs(symfs_filename, filename); @@ -1179,6 +1180,9 @@ fallback: 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); close(fd); @@ -1204,13 +1208,25 @@ fallback: pr_debug("Executing: %s\n", command); 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; + } - while (!feof(file)) + nline = 0; + while (!feof(file)) { if (symbol__parse_objdump_line(sym, map, file, privsize, &lineno) < 0) 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. @@ -1604,6 +1620,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, len = symbol__size(sym); if (print_lines) { + srcline_full_filename = full_paths; symbol__get_source_line(sym, map, evsel, &source_line, len); print_summary(&source_line, dso->long_name); } diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index ba6f7526b282..4c50411371db 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -26,18 +26,40 @@ static int libbpf_##name(const char *fmt, ...) \ return ret; \ } -DEFINE_PRINT_FN(warning, 0) -DEFINE_PRINT_FN(info, 0) +DEFINE_PRINT_FN(warning, 1) +DEFINE_PRINT_FN(info, 1) DEFINE_PRINT_FN(debug, 1) struct bpf_prog_priv { 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 *obj; - static bool libbpf_initialized; if (!libbpf_initialized) { libbpf_set_print(libbpf_warning, @@ -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); if (err) - return ERR_PTR(err); + return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE); obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); free(obj_buf); } else obj = bpf_object__open(filename); - if (!obj) { + if (IS_ERR(obj)) { pr_debug("bpf: failed to load %s\n", filename); - return ERR_PTR(-EINVAL); + return obj; } return obj; @@ -96,9 +118,9 @@ config_bpf_program(struct bpf_program *prog) int err; 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"); - return -EINVAL; + return PTR_ERR(config_str); } priv = calloc(sizeof(*priv), 1); @@ -113,14 +135,14 @@ config_bpf_program(struct bpf_program *prog) if (err < 0) { pr_debug("bpf: '%s' is not a valid config string\n", config_str); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__CONFIG; goto errout; } if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { pr_debug("bpf: '%s': group for event is set and not '%s'.\n", config_str, PERF_BPF_PROBE_GROUP); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__GROUP; goto errout; } else if (!pev->group) pev->group = strdup(PERF_BPF_PROBE_GROUP); @@ -132,9 +154,9 @@ config_bpf_program(struct bpf_program *prog) } 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); - err = -EINVAL; + err = -BPF_LOADER_ERRNO__EVENTNAME; goto errout; } pr_debug("bpf: config '%s' is ok\n", config_str); @@ -285,7 +307,7 @@ int bpf__foreach_tev(struct bpf_object *obj, (void **)&priv); if (err || !priv) { pr_debug("bpf: failed to get private field\n"); - return -EINVAL; + return -BPF_LOADER_ERRNO__INTERNAL; } pev = &priv->pev; @@ -308,13 +330,57 @@ int bpf__foreach_tev(struct bpf_object *obj, 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) \ char sbuf[STRERR_BUFSIZE], *emsg;\ if (!size)\ return 0;\ if (err < 0)\ err = -err;\ - emsg = strerror_r(err, sbuf, sizeof(sbuf));\ + bpf_loader_strerror(err, sbuf, sizeof(sbuf));\ + emsg = sbuf;\ switch (err) {\ default:\ scnprintf(buf, size, "%s", emsg);\ @@ -330,23 +396,62 @@ int bpf__foreach_tev(struct bpf_object *obj, }\ 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 err, char *buf, size_t size) { bpf__strerror_head(err, buf, size); 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(ENOENT, "You need to check probing points in BPF file\n"); + bpf__strerror_entry(EACCES, "You need to be root"); + 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); 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) { bpf__strerror_head(err, buf, size); - bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?", - emsg) + case LIBBPF_ERRNO__KVER: { + 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); return 0; } diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index ccd8d7fd79d3..9caf3ae4acf3 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -8,9 +8,21 @@ #include <linux/compiler.h> #include <linux/err.h> #include <string.h> +#include <bpf/libbpf.h> #include "probe-event.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; #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" @@ -19,6 +31,11 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, #ifdef HAVE_LIBBPF_SUPPORT 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); @@ -41,6 +58,13 @@ bpf__prepare_load(const char *filename __maybe_unused, 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 int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} @@ -67,6 +91,15 @@ __bpf_strerror(char *buf, size_t size) 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 bpf__strerror_probe(struct bpf_object *obj __maybe_unused, int err __maybe_unused, diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index d909459fb54c..217b5a60e2ab 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -76,6 +76,7 @@ struct perf_tool build_id__mark_dso_hit_ops = { .exit = perf_event__exit_del_thread, .attr = perf_event__process_attr, .build_id = perf_event__process_build_id, + .ordered_events = true, }; int build_id__sprintf(const u8 *build_id, int len, char *bf) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 7c0c08386a1d..425df5c86c9c 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -933,6 +933,7 @@ static struct dso *__dso__findlink_by_longname(struct rb_root *root, /* Add new node and rebalance tree */ rb_link_node(&dso->rb_node, parent, p); rb_insert_color(&dso->rb_node, root); + dso->root = root; } return NULL; } @@ -945,15 +946,30 @@ static inline struct dso *__dso__find_by_longname(struct rb_root *root, void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) { + struct rb_root *root = dso->root; + if (name == NULL) return; if (dso->long_name_allocated) free((char *)dso->long_name); + if (root) { + rb_erase(&dso->rb_node, root); + /* + * __dso__findlink_by_longname() isn't guaranteed to add it + * back, so a clean removal is required here. + */ + RB_CLEAR_NODE(&dso->rb_node); + dso->root = NULL; + } + dso->long_name = name; dso->long_name_len = strlen(name); dso->long_name_allocated = name_allocated; + + if (root) + __dso__findlink_by_longname(root, dso, NULL); } void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) @@ -1046,6 +1062,7 @@ struct dso *dso__new(const char *name) dso->kernel = DSO_TYPE_USER; dso->needs_swap = DSO_SWAP__UNSET; RB_CLEAR_NODE(&dso->rb_node); + dso->root = NULL; INIT_LIST_HEAD(&dso->node); INIT_LIST_HEAD(&dso->data.open_entry); pthread_mutex_init(&dso->lock, NULL); diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index fc8db9c764ac..45ec4d0a50ed 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -135,6 +135,7 @@ struct dso { pthread_mutex_t lock; struct list_head node; struct rb_node rb_node; /* rbtree node sorted by long name */ + struct rb_root *root; /* root of rbtree that rb_node is in */ struct rb_root symbols[MAP__NR_TYPES]; struct rb_root symbol_names[MAP__NR_TYPES]; struct { diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 4f6a4780bd5f..00724d496d38 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -4,17 +4,18 @@ */ #include <stdio.h> -#include <sys/utsname.h> #include "util.h" #include "debug.h" #include "llvm-utils.h" #include "cache.h" #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ - "$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS " \ - "$KERNEL_INC_OPTIONS -Wno-unused-value " \ - "-Wno-pointer-sign -working-directory " \ - "$WORKING_DIR -c \"$CLANG_SOURCE\" -target bpf -O2 -o -" + "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ + "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \ + "$CLANG_OPTIONS $KERNEL_INC_OPTIONS " \ + "-Wno-unused-value -Wno-pointer-sign " \ + "-working-directory $WORKING_DIR " \ + "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -" struct llvm_param llvm_param = { .clang_path = "clang", @@ -214,18 +215,19 @@ static int detect_kbuild_dir(char **kbuild_dir) const char *suffix_dir = ""; char *autoconf_path; - struct utsname utsname; int err; if (!test_dir) { - err = uname(&utsname); - if (err) { - pr_warning("uname failed: %s\n", strerror(errno)); + /* _UTSNAME_LENGTH is 65 */ + char release[128]; + + err = fetch_kernel_version(NULL, release, + sizeof(release)); + if (err) return -EINVAL; - } - test_dir = utsname.release; + test_dir = release; prefix_dir = "/lib/modules/"; suffix_dir = "/build"; } @@ -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, size_t *p_obj_buf_sz) { - int err; - char clang_path[PATH_MAX]; + size_t obj_buf_sz; + 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 *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; - void *obj_buf = NULL; - size_t obj_buf_sz; + const char *template = llvm_param.clang_bpf_cmd_template; if (!template) template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; @@ -354,6 +358,24 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, */ 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_OPTIONS", clang_opt); force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 5ef90be2a249..8b303ff20289 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -91,6 +91,7 @@ static void dsos__purge(struct dsos *dsos) list_for_each_entry_safe(pos, n, &dsos->head, node) { RB_CLEAR_NODE(&pos->rb_node); + pos->root = NULL; list_del_init(&pos->node); dso__put(pos); } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 4e38c396a897..afc6b56cf749 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -644,6 +644,12 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) 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) { struct rb_root *root; @@ -682,7 +688,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp } before->end = map->start; - __maps__insert(maps, before); + __map_groups__insert(pos->groups, before); if (verbose >= 2) map__fprintf(before, fp); } @@ -696,7 +702,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp } after->start = map->end; - __maps__insert(maps, after); + __map_groups__insert(pos->groups, after); if (verbose >= 2) map__fprintf(after, fp); } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bee60583839a..e48d9da75707 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -632,19 +632,20 @@ int parse_events_load_bpf(struct parse_events_evlist *data, struct bpf_object *obj; obj = bpf__prepare_load(bpf_file_name, source); - if (IS_ERR(obj) || !obj) { + if (IS_ERR(obj)) { char errbuf[BUFSIZ]; int err; - err = obj ? PTR_ERR(obj) : -EINVAL; + err = PTR_ERR(obj); if (err == -ENOTSUP) snprintf(errbuf, sizeof(errbuf), "BPF support is not compiled"); else - snprintf(errbuf, sizeof(errbuf), - "BPF object file '%s' is invalid", - bpf_file_name); + bpf__strerror_prepare_load(bpf_file_name, + source, + -err, errbuf, + sizeof(errbuf)); data->error->help = strdup("(add -v to see detail)"); data->error->str = strdup(errbuf); diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b51a8bfb40f9..03875f9154e7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1895,9 +1895,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, sym = map__find_symbol(map, addr, NULL); } else { if (tp->symbol && !addr) { - ret = kernel_get_symbol_address_by_name(tp->symbol, - &addr, true, false); - if (ret < 0) + if (kernel_get_symbol_address_by_name(tp->symbol, + &addr, true, false) < 0) goto out; } if (addr) { @@ -1905,6 +1904,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, sym = __find_kernel_function(addr, &map); } } + if (!sym) goto out; diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 89dbeb92c68e..e3b3b92e4458 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -138,6 +138,9 @@ struct strlist *probe_file__get_rawlist(int fd) char *p; struct strlist *sl; + if (fd < 0) + return NULL; + sl = strlist__new(NULL, NULL); fp = fdopen(dup(fd), "r"); @@ -271,6 +274,9 @@ int probe_file__get_events(int fd, struct strfilter *filter, const char *p; int ret = -ENOENT; + if (!plist) + return -EINVAL; + namelist = __probe_file__get_namelist(fd, true); if (!namelist) return -ENOENT; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index bd8f03de5e40..05012bb178d7 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1183,7 +1183,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) container_of(pf, struct trace_event_finder, pf); struct perf_probe_point *pp = &pf->pev->point; struct probe_trace_event *tev; - struct perf_probe_arg *args; + struct perf_probe_arg *args = NULL; int ret, i; /* Check number of tevs */ @@ -1198,19 +1198,23 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, pp->retprobe, pp->function, &tev->point); if (ret < 0) - return ret; + goto end; tev->point.realname = strdup(dwarf_diename(sc_die)); - if (!tev->point.realname) - return -ENOMEM; + if (!tev->point.realname) { + ret = -ENOMEM; + goto end; + } pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, tev->point.offset); /* Expand special probe argument if exist */ args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); - if (args == NULL) - return -ENOMEM; + if (args == NULL) { + ret = -ENOMEM; + goto end; + } ret = expand_probe_args(sc_die, pf, args); if (ret < 0) @@ -1234,6 +1238,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) } end: + if (ret) { + clear_probe_trace_event(tev); + tf->ntevs--; + } free(args); return ret; } @@ -1246,7 +1254,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, struct trace_event_finder tf = { .pf = {.pev = pev, .callback = add_probe_trace_event}, .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; - int ret; + int ret, i; /* Allocate result tevs array */ *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); @@ -1258,6 +1266,8 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, ret = debuginfo__find_probes(dbg, &tf.pf); if (ret < 0) { + for (i = 0; i < tf.ntevs; i++) + clear_probe_trace_event(&tf.tevs[i]); zfree(tevs); return ret; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 428149bc64d2..c35ffdd360fe 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -29,7 +29,7 @@ static int perf_session__open(struct perf_session *session) struct perf_data_file *file = session->file; 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; } @@ -37,17 +37,17 @@ static int perf_session__open(struct perf_session *session) return 0; if (!perf_evlist__valid_sample_type(session->evlist)) { - pr_err("non matching sample_type"); + pr_err("non matching sample_type\n"); return -1; } 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; } if (!perf_evlist__valid_read_format(session->evlist)) { - pr_err("non matching read_format"); + pr_err("non matching read_format\n"); return -1; } diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index 2a5d8d7698ae..6ac03146889d 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -413,6 +413,11 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, ratio = total / avg; 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) { char unit = 'M'; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b4cc7662677e..cd08027a6d2c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -654,19 +654,24 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, struct map_groups *kmaps = map__kmaps(map); struct map *curr_map; struct symbol *pos; - int count = 0, moved = 0; + int count = 0; + struct rb_root old_root = dso->symbols[map->type]; struct rb_root *root = &dso->symbols[map->type]; struct rb_node *next = rb_first(root); if (!kmaps) return -1; + *root = RB_ROOT; + while (next) { char *module; pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); + rb_erase_init(&pos->rb_node, &old_root); + module = strchr(pos->name, '\t'); if (module) *module = '\0'; @@ -674,28 +679,21 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, curr_map = map_groups__find(kmaps, map->type, pos->start); if (!curr_map || (filter && filter(curr_map, pos))) { - rb_erase_init(&pos->rb_node, root); symbol__delete(pos); - } else { - pos->start -= curr_map->start - curr_map->pgoff; - if (pos->end) - pos->end -= curr_map->start - curr_map->pgoff; - if (curr_map->dso != map->dso) { - rb_erase_init(&pos->rb_node, root); - symbols__insert( - &curr_map->dso->symbols[curr_map->type], - pos); - ++moved; - } else { - ++count; - } + continue; } + + pos->start -= curr_map->start - curr_map->pgoff; + if (pos->end) + pos->end -= curr_map->start - curr_map->pgoff; + symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); + ++count; } /* Symbols have been adjusted */ dso->adjust_symbols = 1; - return count + moved; + return count; } /* @@ -1438,9 +1436,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) if (lstat(dso->name, &st) < 0) goto out; - if (st.st_uid && (st.st_uid != geteuid())) { + if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) { pr_warning("File %s not owned by current user or root, " - "ignoring it.\n", dso->name); + "ignoring it (use -f to override).\n", dso->name); goto out; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 40073c60b83d..dcd786e364f2 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -84,6 +84,7 @@ struct symbol_conf { unsigned short priv_size; unsigned short nr_events; bool try_vmlinux_path, + force, ignore_vmlinux, ignore_vmlinux_buildid, show_kernel_path, diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index cd12c25e4ea4..47b1e36c7ea0 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -3,6 +3,7 @@ #include "debug.h" #include <api/fs/fs.h> #include <sys/mman.h> +#include <sys/utsname.h> #ifdef HAVE_BACKTRACE_SUPPORT #include <execinfo.h> #endif @@ -665,3 +666,32 @@ bool find_process(const char *name) closedir(dir); 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; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 4cfb913aa9e0..dcc659017976 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -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 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 */ diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c index 8d6a47514253..2c768cf70128 100644 --- a/tools/power/cpupower/debug/i386/dump_psb.c +++ b/tools/power/cpupower/debug/i386/dump_psb.c @@ -134,7 +134,7 @@ next_one: } static struct option info_opts[] = { - {.name = "numpst", .has_arg=no_argument, .flag=NULL, .val='n'}, + {"numpst", no_argument, NULL, 'n'}, }; void print_help(void) diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1 index 3e6799d7a79f..580c4e3ea92a 100644 --- a/tools/power/cpupower/man/cpupower-idle-set.1 +++ b/tools/power/cpupower/man/cpupower-idle-set.1 @@ -20,7 +20,9 @@ Disable a specific processor sleep state. Enable a specific processor sleep state. .TP \fB\-D\fR \fB\-\-disable-by-latency\fR <LATENCY> -Disable all idle states with a equal or higher latency than <LATENCY> +Disable all idle states with a equal or higher latency than <LATENCY>. + +Enable all idle states with a latency lower than <LATENCY>. .TP \fB\-E\fR \fB\-\-enable-all\fR Enable all idle states if not enabled already. diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index b4b90a97662c..0e6764330241 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -536,21 +536,21 @@ static int get_latency(unsigned int cpu, unsigned int human) } static struct option info_opts[] = { - { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'}, - { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'}, - { .name = "freq", .has_arg = no_argument, .flag = NULL, .val = 'f'}, - { .name = "hwfreq", .has_arg = no_argument, .flag = NULL, .val = 'w'}, - { .name = "hwlimits", .has_arg = no_argument, .flag = NULL, .val = 'l'}, - { .name = "driver", .has_arg = no_argument, .flag = NULL, .val = 'd'}, - { .name = "policy", .has_arg = no_argument, .flag = NULL, .val = 'p'}, - { .name = "governors", .has_arg = no_argument, .flag = NULL, .val = 'g'}, - { .name = "related-cpus", .has_arg = no_argument, .flag = NULL, .val = 'r'}, - { .name = "affected-cpus",.has_arg = no_argument, .flag = NULL, .val = 'a'}, - { .name = "stats", .has_arg = no_argument, .flag = NULL, .val = 's'}, - { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'}, - { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, - { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'}, - { .name = "no-rounding", .has_arg = no_argument, .flag = NULL, .val = 'n'}, + {"debug", no_argument, NULL, 'e'}, + {"boost", no_argument, NULL, 'b'}, + {"freq", no_argument, NULL, 'f'}, + {"hwfreq", no_argument, NULL, 'w'}, + {"hwlimits", no_argument, NULL, 'l'}, + {"driver", no_argument, NULL, 'd'}, + {"policy", no_argument, NULL, 'p'}, + {"governors", no_argument, NULL, 'g'}, + {"related-cpus", no_argument, NULL, 'r'}, + {"affected-cpus", no_argument, NULL, 'a'}, + {"stats", no_argument, NULL, 's'}, + {"latency", no_argument, NULL, 'y'}, + {"proc", no_argument, NULL, 'o'}, + {"human", no_argument, NULL, 'm'}, + {"no-rounding", no_argument, NULL, 'n'}, { }, }; diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index 4e213576381e..0fbd1a22c0a9 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c @@ -22,11 +22,11 @@ #define NORM_FREQ_LEN 32 static struct option set_opts[] = { - { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'}, - { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'}, - { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'}, - { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'}, - { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'}, + {"min", required_argument, NULL, 'd'}, + {"max", required_argument, NULL, 'u'}, + {"governor", required_argument, NULL, 'g'}, + {"freq", required_argument, NULL, 'f'}, + {"related", no_argument, NULL, 'r'}, { }, }; diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 75e66de7e7a7..750c1d82c3f7 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c @@ -126,8 +126,8 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) } static struct option info_opts[] = { - { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'}, - { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'}, + {"silent", no_argument, NULL, 's'}, + {"proc", no_argument, NULL, 'o'}, { }, }; diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c index d45d8d775c02..d6b6ae44b8c2 100644 --- a/tools/power/cpupower/utils/cpuidle-set.c +++ b/tools/power/cpupower/utils/cpuidle-set.c @@ -13,15 +13,11 @@ #include "helpers/sysfs.h" static struct option info_opts[] = { - { .name = "disable", - .has_arg = required_argument, .flag = NULL, .val = 'd'}, - { .name = "enable", - .has_arg = required_argument, .flag = NULL, .val = 'e'}, - { .name = "disable-by-latency", - .has_arg = required_argument, .flag = NULL, .val = 'D'}, - { .name = "enable-all", - .has_arg = no_argument, .flag = NULL, .val = 'E'}, - { }, + {"disable", required_argument, NULL, 'd'}, + {"enable", required_argument, NULL, 'e'}, + {"disable-by-latency", required_argument, NULL, 'D'}, + {"enable-all", no_argument, NULL, 'E'}, + { }, }; @@ -148,14 +144,21 @@ int cmd_idle_set(int argc, char **argv) (cpu, idlestate); state_latency = sysfs_get_idlestate_latency (cpu, idlestate); - printf("CPU: %u - idlestate %u - state_latency: %llu - latency: %llu\n", - cpu, idlestate, state_latency, latency); - if (disabled == 1 || latency > state_latency) + if (disabled == 1) { + if (latency > state_latency){ + ret = sysfs_idlestate_disable + (cpu, idlestate, 0); + if (ret == 0) + printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); + } continue; - ret = sysfs_idlestate_disable - (cpu, idlestate, 1); - if (ret == 0) + } + if (latency <= state_latency){ + ret = sysfs_idlestate_disable + (cpu, idlestate, 1); + if (ret == 0) printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); + } } break; case 'E': diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c index 136d979e9586..10299f2e9d2a 100644 --- a/tools/power/cpupower/utils/cpupower-info.c +++ b/tools/power/cpupower/utils/cpupower-info.c @@ -17,8 +17,8 @@ #include "helpers/sysfs.h" static struct option set_opts[] = { - { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'}, - { }, + {"perf-bias", optional_argument, NULL, 'b'}, + { }, }; static void print_wrong_arg_exit(void) diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c index 573c75f8e3f5..3e6f374f8dd7 100644 --- a/tools/power/cpupower/utils/cpupower-set.c +++ b/tools/power/cpupower/utils/cpupower-set.c @@ -18,7 +18,7 @@ #include "helpers/bitmask.h" static struct option set_opts[] = { - { .name = "perf-bias", .has_arg = required_argument, .flag = NULL, .val = 'b'}, + {"perf-bias", required_argument, NULL, 'b'}, { }, }; diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index cea398c176e7..9cbb7fd75171 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -73,18 +73,22 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) for (cpu = 0; cpu < cpus; cpu++) { cpu_top->core_info[cpu].cpu = cpu; cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); - if (!cpu_top->core_info[cpu].is_online) - continue; if(sysfs_topology_read_file( cpu, "physical_package_id", - &(cpu_top->core_info[cpu].pkg)) < 0) - return -1; + &(cpu_top->core_info[cpu].pkg)) < 0) { + cpu_top->core_info[cpu].pkg = -1; + cpu_top->core_info[cpu].core = -1; + continue; + } if(sysfs_topology_read_file( cpu, "core_id", - &(cpu_top->core_info[cpu].core)) < 0) - return -1; + &(cpu_top->core_info[cpu].core)) < 0) { + cpu_top->core_info[cpu].pkg = -1; + cpu_top->core_info[cpu].core = -1; + continue; + } } qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), @@ -95,12 +99,15 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) done by pkg value. */ last_pkg = cpu_top->core_info[0].pkg; for(cpu = 1; cpu < cpus; cpu++) { - if(cpu_top->core_info[cpu].pkg != last_pkg) { + if (cpu_top->core_info[cpu].pkg != last_pkg && + cpu_top->core_info[cpu].pkg != -1) { + last_pkg = cpu_top->core_info[cpu].pkg; cpu_top->pkgs++; } } - cpu_top->pkgs++; + if (!cpu_top->core_info[0].pkg == -1) + cpu_top->pkgs++; /* Intel's cores count is not consecutively numbered, there may * be a core_id of 3, but none of 2. Assume there always is 0 diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index c4bae9203a69..05f953f0f0a0 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c @@ -143,6 +143,9 @@ void print_results(int topology_depth, int cpu) /* Be careful CPUs may got resorted for pkg value do not just use cpu */ if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu)) return; + if (!cpu_top.core_info[cpu].is_online && + cpu_top.core_info[cpu].pkg == -1) + return; if (topology_depth > 2) printf("%4d|", cpu_top.core_info[cpu].pkg); @@ -191,7 +194,8 @@ void print_results(int topology_depth, int cpu) * It's up to the monitor plug-in to check .is_online, this one * is just for additional info. */ - if (!cpu_top.core_info[cpu].is_online) { + if (!cpu_top.core_info[cpu].is_online && + cpu_top.core_info[cpu].pkg != -1) { printf(_(" *is offline\n")); return; } else @@ -388,6 +392,9 @@ int cmd_monitor(int argc, char **argv) return EXIT_FAILURE; } + if (!cpu_top.core_info[0].is_online) + printf("WARNING: at least one cpu is offline\n"); + /* Default is: monitor all CPUs */ if (bitmask_isallclear(cpus_chosen)) bitmask_setall(cpus_chosen); diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index bde0ef1a63df..0dac7e05a6ac 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -75,6 +75,7 @@ unsigned int aperf_mperf_multiplier = 1; int do_smi; double bclk; double base_hz; +unsigned int has_base_hz; double tsc_tweak = 1.0; unsigned int show_pkg; unsigned int show_core; @@ -96,6 +97,7 @@ unsigned int do_ring_perf_limit_reasons; unsigned int crystal_hz; unsigned long long tsc_hz; int base_cpu; +double discover_bclk(unsigned int family, unsigned int model); #define RAPL_PKG (1 << 0) /* 0x610 MSR_PKG_POWER_LIMIT */ @@ -511,9 +513,13 @@ int format_counters(struct thread_data *t, struct core_data *c, } /* Bzy_MHz */ - if (has_aperf) - outp += sprintf(outp, "%8.0f", - 1.0 * t->tsc * tsc_tweak / units * t->aperf / t->mperf / interval_float); + if (has_aperf) { + if (has_base_hz) + outp += sprintf(outp, "%8.0f", base_hz / units * t->aperf / t->mperf); + else + outp += sprintf(outp, "%8.0f", + 1.0 * t->tsc / units * t->aperf / t->mperf / interval_float); + } /* TSC_MHz */ outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float); @@ -1158,12 +1164,6 @@ int phi_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, static void calculate_tsc_tweak() { - unsigned long long msr; - unsigned int base_ratio; - - get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr); - base_ratio = (msr >> 8) & 0xFF; - base_hz = base_ratio * bclk * 1000000; tsc_tweak = base_hz / tsc_hz; } @@ -1173,9 +1173,9 @@ dump_nhm_platform_info(void) unsigned long long msr; unsigned int ratio; - get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr); + get_msr(base_cpu, MSR_PLATFORM_INFO, &msr); - fprintf(stderr, "cpu%d: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr); + fprintf(stderr, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr); ratio = (msr >> 40) & 0xFF; fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency frequency\n", @@ -1440,7 +1440,7 @@ dump_config_tdp(void) get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr); fprintf(stderr, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr); - fprintf(stderr, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0xEF); + fprintf(stderr, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0x7F); fprintf(stderr, " lock=%d", (unsigned int)(msr >> 31) & 1); fprintf(stderr, ")\n"); } @@ -1807,7 +1807,7 @@ void check_permissions() * * MSR_SMI_COUNT 0x00000034 * - * MSR_NHM_PLATFORM_INFO 0x000000ce + * MSR_PLATFORM_INFO 0x000000ce * MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2 * * MSR_PKG_C3_RESIDENCY 0x000003f8 @@ -1821,6 +1821,7 @@ void check_permissions() int probe_nhm_msrs(unsigned int family, unsigned int model) { unsigned long long msr; + unsigned int base_ratio; int *pkg_cstate_limits; if (!genuine_intel) @@ -1829,6 +1830,8 @@ int probe_nhm_msrs(unsigned int family, unsigned int model) if (family != 6) return 0; + bclk = discover_bclk(family, model); + switch (model) { case 0x1A: /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */ case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */ @@ -1871,9 +1874,13 @@ int probe_nhm_msrs(unsigned int family, unsigned int model) return 0; } get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr); - pkg_cstate_limit = pkg_cstate_limits[msr & 0xF]; + get_msr(base_cpu, MSR_PLATFORM_INFO, &msr); + base_ratio = (msr >> 8) & 0xFF; + + base_hz = base_ratio * bclk * 1000000; + has_base_hz = 1; return 1; } int has_nhm_turbo_ratio_limit(unsigned int family, unsigned int model) @@ -2780,7 +2787,6 @@ void process_cpuid() do_skl_residency = has_skl_msrs(family, model); do_slm_cstates = is_slm(family, model); do_knl_cstates = is_knl(family, model); - bclk = discover_bclk(family, model); rapl_probe(family, model); perf_limit_reasons_probe(family, model); diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 021e6f97f33e..40ab4476c80a 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -17,8 +17,10 @@ #include <linux/vmalloc.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/ndctl.h> #include <linux/sizes.h> +#include <linux/list.h> #include <linux/slab.h> #include <nfit.h> #include <nd.h> @@ -44,6 +46,15 @@ * +------+ | blk5.0 | pm1.0 | 3 region5 * +-------------------------+----------+-+-------+ * + * +--+---+ + * | cpu1 | + * +--+---+ (Hotplug DIMM) + * | +----------------------------------------------+ + * +--+---+ | blk6.0/pm7.0 | 4 region6/7 + * | imc0 +--+----------------------------------------------+ + * +------+ + * + * * *) In this layout we have four dimms and two memory controllers in one * socket. Each unique interface (BLK or PMEM) to DPA space * is identified by a region device with a dynamically assigned id. @@ -85,8 +96,8 @@ * reference an NVDIMM. */ enum { - NUM_PM = 2, - NUM_DCR = 4, + NUM_PM = 3, + NUM_DCR = 5, NUM_BDW = NUM_DCR, NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */, @@ -115,6 +126,7 @@ static u32 handle[NUM_DCR] = { [1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1), [2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0), [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), + [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), }; struct nfit_test { @@ -138,6 +150,7 @@ struct nfit_test { dma_addr_t *dcr_dma; int (*alloc)(struct nfit_test *t); void (*setup)(struct nfit_test *t); + int setup_hotplug; }; static struct nfit_test *to_nfit_test(struct device *dev) @@ -428,6 +441,10 @@ static int nfit_test0_alloc(struct nfit_test *t) if (!t->spa_set[1]) return -ENOMEM; + t->spa_set[2] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[2]); + if (!t->spa_set[2]) + return -ENOMEM; + for (i = 0; i < NUM_DCR; i++) { t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]); if (!t->dimm[i]) @@ -950,6 +967,126 @@ static void nfit_test0_setup(struct nfit_test *t) flush->hint_count = 1; flush->hint_address[0] = t->flush_dma[3]; + if (t->setup_hotplug) { + offset = offset + sizeof(struct acpi_nfit_flush_address) * 4; + /* dcr-descriptor4 */ + dcr = nfit_buf + offset; + dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; + dcr->header.length = sizeof(struct acpi_nfit_control_region); + dcr->region_index = 4+1; + dcr->vendor_id = 0xabcd; + dcr->device_id = 0; + dcr->revision_id = 1; + dcr->serial_number = ~handle[4]; + dcr->windows = 1; + dcr->window_size = DCR_SIZE; + dcr->command_offset = 0; + dcr->command_size = 8; + dcr->status_offset = 8; + dcr->status_size = 4; + + offset = offset + sizeof(struct acpi_nfit_control_region); + /* bdw4 (spa/dcr4, dimm4) */ + bdw = nfit_buf + offset; + bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; + bdw->header.length = sizeof(struct acpi_nfit_data_region); + bdw->region_index = 4+1; + bdw->windows = 1; + bdw->offset = 0; + bdw->size = BDW_SIZE; + bdw->capacity = DIMM_SIZE; + bdw->start_address = 0; + + offset = offset + sizeof(struct acpi_nfit_data_region); + /* spa10 (dcr4) dimm4 */ + spa = nfit_buf + offset; + spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; + spa->header.length = sizeof(*spa); + memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); + spa->range_index = 10+1; + spa->address = t->dcr_dma[4]; + spa->length = DCR_SIZE; + + /* + * spa11 (single-dimm interleave for hotplug, note storage + * does not actually alias the related block-data-window + * regions) + */ + spa = nfit_buf + offset + sizeof(*spa); + spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; + spa->header.length = sizeof(*spa); + memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); + spa->range_index = 11+1; + spa->address = t->spa_set_dma[2]; + spa->length = SPA0_SIZE; + + /* spa12 (bdw for dcr4) dimm4 */ + spa = nfit_buf + offset + sizeof(*spa) * 2; + spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; + spa->header.length = sizeof(*spa); + memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); + spa->range_index = 12+1; + spa->address = t->dimm_dma[4]; + spa->length = DIMM_SIZE; + + offset = offset + sizeof(*spa) * 3; + /* mem-region14 (spa/dcr4, dimm4) */ + memdev = nfit_buf + offset; + memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; + memdev->header.length = sizeof(*memdev); + memdev->device_handle = handle[4]; + memdev->physical_id = 4; + memdev->region_id = 0; + memdev->range_index = 10+1; + memdev->region_index = 4+1; + memdev->region_size = 0; + memdev->region_offset = 0; + memdev->address = 0; + memdev->interleave_index = 0; + memdev->interleave_ways = 1; + + /* mem-region15 (spa0, dimm4) */ + memdev = nfit_buf + offset + + sizeof(struct acpi_nfit_memory_map); + memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; + memdev->header.length = sizeof(*memdev); + memdev->device_handle = handle[4]; + memdev->physical_id = 4; + memdev->region_id = 0; + memdev->range_index = 11+1; + memdev->region_index = 4+1; + memdev->region_size = SPA0_SIZE; + memdev->region_offset = t->spa_set_dma[2]; + memdev->address = 0; + memdev->interleave_index = 0; + memdev->interleave_ways = 1; + + /* mem-region16 (spa/dcr4, dimm4) */ + memdev = nfit_buf + offset + + sizeof(struct acpi_nfit_memory_map) * 2; + memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; + memdev->header.length = sizeof(*memdev); + memdev->device_handle = handle[4]; + memdev->physical_id = 4; + memdev->region_id = 0; + memdev->range_index = 12+1; + memdev->region_index = 4+1; + memdev->region_size = 0; + memdev->region_offset = 0; + memdev->address = 0; + memdev->interleave_index = 0; + memdev->interleave_ways = 1; + + offset = offset + sizeof(struct acpi_nfit_memory_map) * 3; + /* flush3 (dimm4) */ + flush = nfit_buf + offset; + flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; + flush->header.length = sizeof(struct acpi_nfit_flush_address); + flush->device_handle = handle[4]; + flush->hint_count = 1; + flush->hint_address[0] = t->flush_dma[4]; + } + acpi_desc = &t->acpi_desc; set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); @@ -998,7 +1135,7 @@ static void nfit_test1_setup(struct nfit_test *t) memdev->interleave_ways = 1; memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED - | ACPI_NFIT_MEM_ARMED; + | ACPI_NFIT_MEM_NOT_ARMED; offset += sizeof(*memdev); /* dcr-descriptor0 */ @@ -1108,6 +1245,29 @@ static int nfit_test_probe(struct platform_device *pdev) if (!acpi_desc->nvdimm_bus) return -ENXIO; + INIT_LIST_HEAD(&acpi_desc->spa_maps); + INIT_LIST_HEAD(&acpi_desc->spas); + INIT_LIST_HEAD(&acpi_desc->dcrs); + INIT_LIST_HEAD(&acpi_desc->bdws); + INIT_LIST_HEAD(&acpi_desc->idts); + INIT_LIST_HEAD(&acpi_desc->flushes); + INIT_LIST_HEAD(&acpi_desc->memdevs); + INIT_LIST_HEAD(&acpi_desc->dimms); + mutex_init(&acpi_desc->spa_map_mutex); + mutex_init(&acpi_desc->init_mutex); + + rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size); + if (rc) { + nvdimm_bus_unregister(acpi_desc->nvdimm_bus); + return rc; + } + + if (nfit_test->setup != nfit_test0_setup) + return 0; + + nfit_test->setup_hotplug = 1; + nfit_test->setup(nfit_test); + rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size); if (rc) { nvdimm_bus_unregister(acpi_desc->nvdimm_bus); diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index cfe121353eec..c8edff6803d1 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -6,6 +6,7 @@ TARGETS += firmware TARGETS += ftrace TARGETS += futex TARGETS += kcmp +TARGETS += lib TARGETS += membarrier TARGETS += memfd TARGETS += memory-hotplug @@ -13,6 +14,7 @@ TARGETS += mount TARGETS += mqueue TARGETS += net TARGETS += powerpc +TARGETS += pstore TARGETS += ptrace TARGETS += seccomp TARGETS += size @@ -65,6 +67,9 @@ clean_hotplug: make -C $$TARGET clean; \ done; +run_pstore_crash: + make -C pstore run_crash + INSTALL_PATH ?= install INSTALL_PATH := $(abspath $(INSTALL_PATH)) ALL_SCRIPT := $(INSTALL_PATH)/run_kselftest.sh diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile index d27108b4f208..c0d957015f52 100644 --- a/tools/testing/selftests/breakpoints/Makefile +++ b/tools/testing/selftests/breakpoints/Makefile @@ -6,7 +6,7 @@ ifeq ($(ARCH),x86) TEST_PROGS := breakpoint_test endif -all: +all: $(TEST_PROGS) include ../lib.mk diff --git a/tools/testing/selftests/efivarfs/.gitignore b/tools/testing/selftests/efivarfs/.gitignore new file mode 100644 index 000000000000..33618493562b --- /dev/null +++ b/tools/testing/selftests/efivarfs/.gitignore @@ -0,0 +1,2 @@ +create-read +open-unlink diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc index a5a426211129..c3843ed49bf6 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc @@ -5,7 +5,7 @@ echo 0 > events/enable echo > kprobe_events -echo p:myevent do_fork > kprobe_events +echo p:myevent _do_fork > kprobe_events grep myevent kprobe_events test -d events/kprobes/myevent echo > kprobe_events diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc index d8c7bb6581fe..74507db8bbc8 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc @@ -5,7 +5,7 @@ echo 0 > events/enable echo > kprobe_events -echo p:myevent do_fork > kprobe_events +echo p:myevent _do_fork > kprobe_events test -d events/kprobes/myevent echo 1 > events/kprobes/myevent/enable echo > kprobe_events && exit 1 # this must fail diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc index c45ee2761354..64949d4eda69 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc @@ -5,7 +5,7 @@ echo 0 > events/enable echo > kprobe_events -echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events +echo 'p:testprobe _do_fork $stack $stack0 +0($stack)' > kprobe_events grep testprobe kprobe_events test -d events/kprobes/testprobe echo 1 > events/kprobes/testprobe/enable diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc index ab41d2b29841..d6f2f4965697 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc @@ -6,31 +6,31 @@ grep function available_tracers || exit_unsupported # this is configurable # prepare echo nop > current_tracer -echo do_fork > set_ftrace_filter +echo _do_fork > set_ftrace_filter echo 0 > events/enable echo > kprobe_events -echo 'p:testprobe do_fork' > kprobe_events +echo 'p:testprobe _do_fork' > kprobe_events # kprobe on / ftrace off echo 1 > events/kprobes/testprobe/enable echo > trace ( echo "forked") grep testprobe trace -! grep 'do_fork <-' trace +! grep '_do_fork <-' trace # kprobe on / ftrace on echo function > current_tracer echo > trace ( echo "forked") grep testprobe trace -grep 'do_fork <-' trace +grep '_do_fork <-' trace # kprobe off / ftrace on echo 0 > events/kprobes/testprobe/enable echo > trace ( echo "forked") ! grep testprobe trace -grep 'do_fork <-' trace +grep '_do_fork <-' trace # kprobe on / ftrace on echo 1 > events/kprobes/testprobe/enable @@ -38,14 +38,14 @@ echo function > current_tracer echo > trace ( echo "forked") grep testprobe trace -grep 'do_fork <-' trace +grep '_do_fork <-' trace # kprobe on / ftrace off echo nop > current_tracer echo > trace ( echo "forked") grep testprobe trace -! grep 'do_fork <-' trace +! grep '_do_fork <-' trace # cleanup echo nop > current_tracer diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc index 31717985acc7..0d09546258fd 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc @@ -5,7 +5,7 @@ echo 0 > events/enable echo > kprobe_events -echo 'r:testprobe2 do_fork $retval' > kprobe_events +echo 'r:testprobe2 _do_fork $retval' > kprobe_events grep testprobe2 kprobe_events test -d events/kprobes/testprobe2 echo 1 > events/kprobes/testprobe2/enable diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README index 3224a049b196..0558bb9ce0a6 100644 --- a/tools/testing/selftests/futex/README +++ b/tools/testing/selftests/futex/README @@ -27,7 +27,7 @@ o The build system shall remain as simple as possible, avoiding any archive or o Where possible, any helper functions or other package-wide code shall be implemented in header files, avoiding the need to compile intermediate object files. -o External dependendencies shall remain as minimal as possible. Currently gcc +o External dependencies shall remain as minimal as possible. Currently gcc and glibc are the only dependencies. o Tests return 0 for success and < 0 for failure. diff --git a/tools/testing/selftests/lib/Makefile b/tools/testing/selftests/lib/Makefile new file mode 100644 index 000000000000..47147b968514 --- /dev/null +++ b/tools/testing/selftests/lib/Makefile @@ -0,0 +1,8 @@ +# Makefile for lib/ function selftests + +# No binaries, but make sure arg-less "make" doesn't trigger "run_tests" +all: + +TEST_PROGS := printf.sh + +include ../lib.mk diff --git a/tools/testing/selftests/lib/printf.sh b/tools/testing/selftests/lib/printf.sh new file mode 100644 index 000000000000..4fdc70fe6980 --- /dev/null +++ b/tools/testing/selftests/lib/printf.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Runs printf infrastructure using test_printf kernel module + +if /sbin/modprobe -q test_printf; then + /sbin/modprobe -q -r test_printf + echo "printf: ok" +else + echo "printf: [FAIL]" + exit 1 +fi diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile index 3e7eb7972511..fd396ac811b6 100644 --- a/tools/testing/selftests/memfd/Makefile +++ b/tools/testing/selftests/memfd/Makefile @@ -4,16 +4,16 @@ CFLAGS += -I../../../../include/uapi/ CFLAGS += -I../../../../include/ CFLAGS += -I../../../../usr/include/ -all: - $(CC) $(CFLAGS) memfd_test.c -o memfd_test - TEST_PROGS := memfd_test +all: $(TEST_PROGS) + include ../lib.mk -build_fuse: - $(CC) $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt - $(CC) $(CFLAGS) fuse_test.c -o fuse_test +build_fuse: fuse_mnt fuse_test + +fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags) +fuse_mnt: LDFLAGS += $(shell pkg-config fuse --libs) run_fuse: build_fuse @./run_fuse_test.sh || echo "fuse_test: [FAIL]" diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c index 0b9eafb7ab7b..26546892cd54 100644 --- a/tools/testing/selftests/memfd/memfd_test.c +++ b/tools/testing/selftests/memfd/memfd_test.c @@ -15,10 +15,11 @@ #include <sys/mman.h> #include <sys/stat.h> #include <sys/syscall.h> +#include <sys/wait.h> #include <unistd.h> #define MFD_DEF_SIZE 8192 -#define STACK_SIZE 65535 +#define STACK_SIZE 65536 static int sys_memfd_create(const char *name, unsigned int flags) diff --git a/tools/testing/selftests/memfd/run_fuse_test.sh b/tools/testing/selftests/memfd/run_fuse_test.sh index 69b930e1e041..69b930e1e041 100644..100755 --- a/tools/testing/selftests/memfd/run_fuse_test.sh +++ b/tools/testing/selftests/memfd/run_fuse_test.sh diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c index 9c1a5d359055..e0a74bd207a5 100644 --- a/tools/testing/selftests/mqueue/mq_open_tests.c +++ b/tools/testing/selftests/mqueue/mq_open_tests.c @@ -31,6 +31,7 @@ #include <sys/resource.h> #include <sys/stat.h> #include <mqueue.h> +#include <error.h> static char *usage = "Usage:\n" diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c index 8519e9ee97e3..8188f72de93c 100644 --- a/tools/testing/selftests/mqueue/mq_perf_tests.c +++ b/tools/testing/selftests/mqueue/mq_perf_tests.c @@ -37,6 +37,7 @@ #include <sys/stat.h> #include <mqueue.h> #include <popt.h> +#include <error.h> static char *usage = "Usage:\n" diff --git a/tools/testing/selftests/pstore/Makefile b/tools/testing/selftests/pstore/Makefile new file mode 100644 index 000000000000..bd7abe24ea08 --- /dev/null +++ b/tools/testing/selftests/pstore/Makefile @@ -0,0 +1,15 @@ +# Makefile for pstore selftests. +# Expects pstore backend is registered. + +all: + +TEST_PROGS := pstore_tests pstore_post_reboot_tests +TEST_FILES := common_tests pstore_crash_test + +include ../lib.mk + +run_crash: + @sh pstore_crash_test || { echo "pstore_crash_test: [FAIL]"; exit 1; } + +clean: + rm -rf logs/* *uuid diff --git a/tools/testing/selftests/pstore/common_tests b/tools/testing/selftests/pstore/common_tests new file mode 100755 index 000000000000..3ea64d7cf1cd --- /dev/null +++ b/tools/testing/selftests/pstore/common_tests @@ -0,0 +1,83 @@ +#!/bin/sh + +# common_tests - Shell script commonly used by pstore test scripts +# +# Copyright (C) Hitachi Ltd., 2015 +# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com> +# +# Released under the terms of the GPL v2. + +# Utilities +errexit() { # message + echo "Error: $1" 1>&2 + exit 1 +} + +absdir() { # file_path + (cd `dirname $1`; pwd) +} + +show_result() { # result_value + if [ $1 -eq 0 ]; then + prlog "ok" + else + prlog "FAIL" + rc=1 + fi +} + +check_files_exist() { # type of pstorefs file + if [ -e ${1}-${backend}-0 ]; then + prlog "ok" + for f in `ls ${1}-${backend}-*`; do + prlog -e "\t${f}" + done + else + prlog "FAIL" + rc=1 + fi +} + +operate_files() { # tested value, files, operation + if [ $1 -eq 0 ]; then + prlog + for f in $2; do + prlog -ne "\t${f} ... " + # execute operation + $3 $f + show_result $? + done + else + prlog " ... FAIL" + rc=1 + fi +} + +# Parameters +TEST_STRING_PATTERN="Testing pstore: uuid=" +UUID=`cat /proc/sys/kernel/random/uuid` +TOP_DIR=`absdir $0` +LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`_${UUID}/ +REBOOT_FLAG=$TOP_DIR/reboot_flag + +# Preparing logs +LOG_FILE=$LOG_DIR/`basename $0`.log +mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR" +date > $LOG_FILE +prlog() { # messages + /bin/echo "$@" | tee -a $LOG_FILE +} + +# Starting tests +rc=0 +prlog "=== Pstore unit tests (`basename $0`) ===" +prlog "UUID="$UUID + +prlog -n "Checking pstore backend is registered ... " +backend=`cat /sys/module/pstore/parameters/backend` +show_result $? +prlog -e "\tbackend=${backend}" +prlog -e "\tcmdline=`cat /proc/cmdline`" +if [ $rc -ne 0 ]; then + exit 1 +fi diff --git a/tools/testing/selftests/pstore/pstore_crash_test b/tools/testing/selftests/pstore/pstore_crash_test new file mode 100755 index 000000000000..1a4afe5c12b6 --- /dev/null +++ b/tools/testing/selftests/pstore/pstore_crash_test @@ -0,0 +1,30 @@ +#!/bin/sh + +# pstore_crash_test - Pstore test shell script which causes crash and reboot +# +# Copyright (C) Hitachi Ltd., 2015 +# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com> +# +# Released under the terms of the GPL v2. + +# exit if pstore backend is not registered +. ./common_tests + +prlog "Causing kernel crash ..." + +# enable all functions triggered by sysrq +echo 1 > /proc/sys/kernel/sysrq +# setting to reboot in 3 seconds after panic +echo 3 > /proc/sys/kernel/panic + +# save uuid file by different name because next test execution will replace it. +mv $TOP_DIR/uuid $TOP_DIR/prev_uuid + +# create a file as reboot flag +touch $REBOOT_FLAG +sync + +# cause crash +# Note: If you use kdump and want to see kmesg-* files after reboot, you should +# specify 'crash_kexec_post_notifiers' in 1st kernel's cmdline. +echo c > /proc/sysrq-trigger diff --git a/tools/testing/selftests/pstore/pstore_post_reboot_tests b/tools/testing/selftests/pstore/pstore_post_reboot_tests new file mode 100755 index 000000000000..6ccb154cb4aa --- /dev/null +++ b/tools/testing/selftests/pstore/pstore_post_reboot_tests @@ -0,0 +1,77 @@ +#!/bin/sh + +# pstore_post_reboot_tests - Check pstore's behavior after crash/reboot +# +# Copyright (C) Hitachi Ltd., 2015 +# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com> +# +# Released under the terms of the GPL v2. + +. ./common_tests + +if [ -e $REBOOT_FLAG ]; then + rm $REBOOT_FLAG +else + prlog "pstore_crash_test has not been executed yet. we skip further tests." + exit 0 +fi + +prlog -n "Mounting pstore filesystem ... " +mount_info=`grep pstore /proc/mounts` +if [ $? -eq 0 ]; then + mount_point=`echo ${mount_info} | cut -d' ' -f2 | head -n1` + prlog "ok" +else + mount none /sys/fs/pstore -t pstore + if [ $? -eq 0 ]; then + mount_point=`grep pstore /proc/mounts | cut -d' ' -f2 | head -n1` + prlog "ok" + else + prlog "FAIL" + exit 1 + fi +fi + +cd ${mount_point} + +prlog -n "Checking dmesg files exist in pstore filesystem ... " +check_files_exist dmesg + +prlog -n "Checking console files exist in pstore filesystem ... " +check_files_exist console + +prlog -n "Checking pmsg files exist in pstore filesystem ... " +check_files_exist pmsg + +prlog -n "Checking dmesg files contain oops end marker" +grep_end_trace() { + grep -q "\---\[ end trace" $1 +} +files=`ls dmesg-${backend}-*` +operate_files $? "$files" grep_end_trace + +prlog -n "Checking console file contains oops end marker ... " +grep -q "\---\[ end trace" console-${backend}-0 +show_result $? + +prlog -n "Checking pmsg file properly keeps the content written before crash ... " +prev_uuid=`cat $TOP_DIR/prev_uuid` +if [ $? -eq 0 ]; then + nr_matched=`grep -c "$TEST_STRING_PATTERN" pmsg-${backend}-0` + if [ $nr_matched -eq 1 ]; then + grep -q "$TEST_STRING_PATTERN"$prev_uuid pmsg-${backend}-0 + show_result $? + else + prlog "FAIL" + rc=1 + fi +else + prlog "FAIL" + rc=1 +fi + +prlog -n "Removing all files in pstore filesystem " +files=`ls *-${backend}-*` +operate_files $? "$files" rm + +exit $rc diff --git a/tools/testing/selftests/pstore/pstore_tests b/tools/testing/selftests/pstore/pstore_tests new file mode 100755 index 000000000000..f25d2a349a60 --- /dev/null +++ b/tools/testing/selftests/pstore/pstore_tests @@ -0,0 +1,30 @@ +#!/bin/sh + +# pstore_tests - Check pstore's behavior before crash/reboot +# +# Copyright (C) Hitachi Ltd., 2015 +# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com> +# +# Released under the terms of the GPL v2. + +. ./common_tests + +prlog -n "Checking pstore console is registered ... " +dmesg | grep -q "console \[pstore" +show_result $? + +prlog -n "Checking /dev/pmsg0 exists ... " +test -e /dev/pmsg0 +show_result $? + +prlog -n "Writing unique string to /dev/pmsg0 ... " +if [ -e "/dev/pmsg0" ]; then + echo "${TEST_STRING_PATTERN}""$UUID" > /dev/pmsg0 + show_result $? + echo "$UUID" > $TOP_DIR/uuid +else + prlog "FAIL" + rc=1 +fi + +exit $rc diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 770f47adf295..882fe83a3554 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -19,15 +19,19 @@ #include <linux/prctl.h> #include <linux/ptrace.h> #include <linux/seccomp.h> -#include <poll.h> #include <pthread.h> #include <semaphore.h> #include <signal.h> #include <stddef.h> #include <stdbool.h> #include <string.h> +#include <time.h> #include <linux/elf.h> #include <sys/uio.h> +#include <sys/utsname.h> +#include <sys/fcntl.h> +#include <sys/mman.h> +#include <sys/times.h> #define _GNU_SOURCE #include <unistd.h> @@ -428,14 +432,16 @@ TEST_SIGNAL(KILL_one, SIGSYS) TEST_SIGNAL(KILL_one_arg_one, SIGSYS) { + void *fatal_address; struct sock_filter filter[] = { BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_times, 1, 0), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), /* Only both with lower 32-bit for now. */ BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(0)), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1), + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, + (unsigned long)&fatal_address, 0, 1), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), }; @@ -445,7 +451,8 @@ TEST_SIGNAL(KILL_one_arg_one, SIGSYS) }; long ret; pid_t parent = getppid(); - pid_t pid = getpid(); + struct tms timebuf; + clock_t clock = times(&timebuf); ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); ASSERT_EQ(0, ret); @@ -454,17 +461,22 @@ TEST_SIGNAL(KILL_one_arg_one, SIGSYS) ASSERT_EQ(0, ret); EXPECT_EQ(parent, syscall(__NR_getppid)); - EXPECT_EQ(pid, syscall(__NR_getpid)); - /* getpid() should never return. */ - EXPECT_EQ(0, syscall(__NR_getpid, 0x0C0FFEE)); + EXPECT_LE(clock, syscall(__NR_times, &timebuf)); + /* times() should never return. */ + EXPECT_EQ(0, syscall(__NR_times, &fatal_address)); } TEST_SIGNAL(KILL_one_arg_six, SIGSYS) { +#ifndef __NR_mmap2 + int sysno = __NR_mmap; +#else + int sysno = __NR_mmap2; +#endif struct sock_filter filter[] = { BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0), + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sysno, 1, 0), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), /* Only both with lower 32-bit for now. */ BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(5)), @@ -478,7 +490,11 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) }; long ret; pid_t parent = getppid(); - pid_t pid = getpid(); + int fd; + void *map1, *map2; + int page_size = sysconf(_SC_PAGESIZE); + + ASSERT_LT(0, page_size); ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); ASSERT_EQ(0, ret); @@ -486,10 +502,22 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); ASSERT_EQ(0, ret); + fd = open("/dev/zero", O_RDONLY); + ASSERT_NE(-1, fd); + EXPECT_EQ(parent, syscall(__NR_getppid)); - EXPECT_EQ(pid, syscall(__NR_getpid)); - /* getpid() should never return. */ - EXPECT_EQ(0, syscall(__NR_getpid, 1, 2, 3, 4, 5, 0x0C0FFEE)); + map1 = (void *)syscall(sysno, + NULL, page_size, PROT_READ, MAP_PRIVATE, fd, page_size); + EXPECT_NE(MAP_FAILED, map1); + /* mmap2() should never return. */ + map2 = (void *)syscall(sysno, + NULL, page_size, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE); + EXPECT_EQ(MAP_FAILED, map2); + + /* The test failed, so clean up the resources. */ + munmap(map1, page_size); + munmap(map2, page_size); + close(fd); } /* TODO(wad) add 64-bit versus 32-bit arg tests. */ @@ -1247,8 +1275,8 @@ void change_syscall(struct __test_metadata *_metadata, ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov); EXPECT_EQ(0, ret); -#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || \ - defined(__powerpc__) || defined(__s390__) +#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \ + defined(__s390__) { regs.SYSCALL_NUM = syscall; } @@ -1262,6 +1290,18 @@ void change_syscall(struct __test_metadata *_metadata, EXPECT_EQ(0, ret); } +#elif defined(__aarch64__) +# ifndef NT_ARM_SYSTEM_CALL +# define NT_ARM_SYSTEM_CALL 0x404 +# endif + { + iov.iov_base = &syscall; + iov.iov_len = sizeof(syscall); + ret = ptrace(PTRACE_SETREGSET, tracee, NT_ARM_SYSTEM_CALL, + &iov); + EXPECT_EQ(0, ret); + } + #else ASSERT_EQ(1, 0) { TH_LOG("How is the syscall changed on this architecture?"); @@ -1272,6 +1312,8 @@ void change_syscall(struct __test_metadata *_metadata, if (syscall == -1) regs.SYSCALL_RET = 1; + iov.iov_base = ®s; + iov.iov_len = sizeof(regs); ret = ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &iov); EXPECT_EQ(0, ret); } @@ -2005,20 +2047,25 @@ TEST(syscall_restart) BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 5, 0), BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_exit, 4, 0), BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_rt_sigreturn, 3, 0), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_poll, 4, 0), + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_nanosleep, 4, 0), BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_restart_syscall, 4, 0), /* Allow __NR_write for easy logging. */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_write, 0, 1), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL), - BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x100), /* poll */ - BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x200), /* restart */ + /* The nanosleep jump target. */ + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x100), + /* The restart_syscall jump target. */ + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x200), }; struct sock_fprog prog = { .len = (unsigned short)ARRAY_SIZE(filter), .filter = filter, }; +#if defined(__arm__) + struct utsname utsbuf; +#endif ASSERT_EQ(0, pipe(pipefd)); @@ -2027,10 +2074,7 @@ TEST(syscall_restart) if (child_pid == 0) { /* Child uses EXPECT not ASSERT to deliver status correctly. */ char buf = ' '; - struct pollfd fds = { - .fd = pipefd[0], - .events = POLLIN, - }; + struct timespec timeout = { }; /* Attach parent as tracer and stop. */ EXPECT_EQ(0, ptrace(PTRACE_TRACEME)); @@ -2054,10 +2098,11 @@ TEST(syscall_restart) TH_LOG("Failed to get sync data from read()"); } - /* Start poll to be interrupted. */ + /* Start nanosleep to be interrupted. */ + timeout.tv_sec = 1; errno = 0; - EXPECT_EQ(1, poll(&fds, 1, -1)) { - TH_LOG("Call to poll() failed (errno %d)", errno); + EXPECT_EQ(0, nanosleep(&timeout, NULL)) { + TH_LOG("Call to nanosleep() failed (errno %d)", errno); } /* Read final sync from parent. */ @@ -2082,14 +2127,14 @@ TEST(syscall_restart) ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); ASSERT_EQ(1, write(pipefd[1], ".", 1)); - /* Wait for poll() to start. */ + /* Wait for nanosleep() to start. */ ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); ASSERT_EQ(true, WIFSTOPPED(status)); ASSERT_EQ(SIGTRAP, WSTOPSIG(status)); ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16)); ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg)); ASSERT_EQ(0x100, msg); - EXPECT_EQ(__NR_poll, get_syscall(_metadata, child_pid)); + EXPECT_EQ(__NR_nanosleep, get_syscall(_metadata, child_pid)); /* Might as well check siginfo for sanity while we're here. */ ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info)); @@ -2100,7 +2145,7 @@ TEST(syscall_restart) /* Verify signal delivery came from child (seccomp-triggered). */ EXPECT_EQ(child_pid, info.si_pid); - /* Interrupt poll with SIGSTOP (which we'll need to handle). */ + /* Interrupt nanosleep with SIGSTOP (which we'll need to handle). */ ASSERT_EQ(0, kill(child_pid, SIGSTOP)); ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); @@ -2110,7 +2155,7 @@ TEST(syscall_restart) ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info)); EXPECT_EQ(getpid(), info.si_pid); - /* Restart poll with SIGCONT, which triggers restart_syscall. */ + /* Restart nanosleep with SIGCONT, which triggers restart_syscall. */ ASSERT_EQ(0, kill(child_pid, SIGCONT)); ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0)); @@ -2124,16 +2169,25 @@ TEST(syscall_restart) ASSERT_EQ(SIGTRAP, WSTOPSIG(status)); ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16)); ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg)); + ASSERT_EQ(0x200, msg); ret = get_syscall(_metadata, child_pid); #if defined(__arm__) - /* FIXME: ARM does not expose true syscall in registers. */ - EXPECT_EQ(__NR_poll, ret); -#else - EXPECT_EQ(__NR_restart_syscall, ret); + /* + * FIXME: + * - native ARM registers do NOT expose true syscall. + * - compat ARM registers on ARM64 DO expose true syscall. + */ + ASSERT_EQ(0, uname(&utsbuf)); + if (strncmp(utsbuf.machine, "arm", 3) == 0) { + EXPECT_EQ(__NR_nanosleep, ret); + } else #endif + { + EXPECT_EQ(__NR_restart_syscall, ret); + } - /* Write again to end poll. */ + /* Write again to end test. */ ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0)); ASSERT_EQ(1, write(pipefd[1], "!", 1)); EXPECT_EQ(0, close(pipefd[1])); diff --git a/tools/testing/selftests/static_keys/test_static_keys.sh b/tools/testing/selftests/static_keys/test_static_keys.sh index 1261e3fa1e3a..1261e3fa1e3a 100644..100755 --- a/tools/testing/selftests/static_keys/test_static_keys.sh +++ b/tools/testing/selftests/static_keys/test_static_keys.sh diff --git a/tools/testing/selftests/timers/nanosleep.c b/tools/testing/selftests/timers/nanosleep.c index 8a3c29de7d49..ff942ff7c9b3 100644 --- a/tools/testing/selftests/timers/nanosleep.c +++ b/tools/testing/selftests/timers/nanosleep.c @@ -19,6 +19,7 @@ * GNU General Public License for more details. */ +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <time.h> diff --git a/tools/testing/selftests/timers/rtctest.c b/tools/testing/selftests/timers/rtctest.c index d80ae852334d..624bce51b27d 100644 --- a/tools/testing/selftests/timers/rtctest.c +++ b/tools/testing/selftests/timers/rtctest.c @@ -61,7 +61,7 @@ int main(int argc, char **argv) /* Turn on update interrupts (one per second) */ retval = ioctl(fd, RTC_UIE_ON, 0); if (retval == -1) { - if (errno == ENOTTY) { + if (errno == EINVAL) { fprintf(stderr, "\n...Update IRQs not supported.\n"); goto test_READ; diff --git a/tools/testing/selftests/vm/mlock2-tests.c b/tools/testing/selftests/vm/mlock2-tests.c index 4431994aade2..02ca5e0177c5 100644 --- a/tools/testing/selftests/vm/mlock2-tests.c +++ b/tools/testing/selftests/vm/mlock2-tests.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include <sys/mman.h> #include <stdint.h> #include <stdio.h> @@ -276,8 +277,8 @@ out: return ret; } -#define PRESENT_BIT 0x8000000000000000 -#define PFN_MASK 0x007FFFFFFFFFFFFF +#define PRESENT_BIT 0x8000000000000000ULL +#define PFN_MASK 0x007FFFFFFFFFFFFFULL #define UNEVICTABLE_BIT (1UL << 18) static int lock_check(char *map) diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index 2df21b3bb26d..e11968b3677e 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -20,13 +20,26 @@ done < /proc/meminfo if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` needpgs=`expr $needmem / $pgsize` - if [ $freepgs -lt $needpgs ]; then + tries=2 + while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do lackpgs=$(( $needpgs - $freepgs )) + echo 3 > /proc/sys/vm/drop_caches echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages if [ $? -ne 0 ]; then echo "Please run this test as root" exit 1 fi + while read name size unit; do + if [ "$name" = "HugePages_Free:" ]; then + freepgs=$size + fi + done < /proc/meminfo + tries=$((tries - 1)) + done + if [ $freepgs -lt $needpgs ]; then + printf "Not enough huge pages available (%d < %d)\n" \ + $freepgs $needpgs + exit 1 fi else echo "no hugetlbfs support in kernel?" diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile index 2e83dd3655a2..3a961e998281 100644 --- a/tools/thermal/tmon/Makefile +++ b/tools/thermal/tmon/Makefile @@ -22,6 +22,9 @@ TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null || pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \ echo -lpanel -lncurses) +CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \ + pkg-config --cflags $(STATIC) panel ncurses 2> /dev/null) + OBJS = tmon.o tui.o sysfs.o pid.o OBJS += diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index bcf5ec760eb9..5a6016224bb9 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -128,6 +128,7 @@ static const char * const page_flag_names[] = { [KPF_THP] = "t:thp", [KPF_BALLOON] = "o:balloon", [KPF_ZERO_PAGE] = "z:zero_page", + [KPF_IDLE] = "i:idle_page", [KPF_RESERVED] = "r:reserved", [KPF_MLOCKED] = "m:mlocked", |