aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2017-05-22 02:32:40 -0400
committerJames Morris <james.l.morris@oracle.com>2017-05-22 02:32:40 -0400
commitd68c51e0b377838dd31b37707813bb62089f399c (patch)
tree4557d5ced33ea6da60bc84ee288af9924192f046 /tools
parent99c55fb18fc48508ae5bba57146a556aacc4558c (diff)
parent08332893e37af6ae779367e78e444f8f9571511d (diff)
Sync to mainline for security submaintainers to work against
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile5
-rw-r--r--tools/arch/arm/include/uapi/asm/kvm.h13
-rw-r--r--tools/arch/arm64/include/uapi/asm/kvm.h13
-rw-r--r--tools/arch/powerpc/include/uapi/asm/kvm.h22
-rw-r--r--tools/arch/s390/include/uapi/asm/kvm.h3
-rw-r--r--tools/arch/x86/include/asm/atomic.h7
-rw-r--r--tools/arch/x86/include/asm/cmpxchg.h89
-rw-r--r--tools/arch/x86/include/asm/cpufeatures.h9
-rw-r--r--tools/arch/x86/lib/memcpy_64.S2
-rw-r--r--tools/build/Makefile.feature1
-rw-r--r--tools/build/feature/Makefile18
-rw-r--r--tools/build/feature/test-all.c5
-rw-r--r--tools/build/feature/test-bpf.c4
-rw-r--r--tools/build/feature/test-sched_getcpu.c9
-rwxr-xr-xtools/hv/bondvf.sh18
-rw-r--r--tools/include/asm-generic/atomic-gcc.h8
-rw-r--r--tools/include/linux/atomic.h6
-rw-r--r--tools/include/linux/bug.h10
-rw-r--r--tools/include/linux/compiler-gcc.h7
-rw-r--r--tools/include/linux/compiler.h9
-rw-r--r--tools/include/linux/filter.h10
-rw-r--r--tools/include/linux/hashtable.h4
-rw-r--r--tools/include/linux/kernel.h7
-rw-r--r--tools/include/linux/log2.h3
-rw-r--r--tools/include/linux/refcount.h151
-rw-r--r--tools/include/linux/string.h2
-rw-r--r--tools/include/linux/types.h1
-rw-r--r--tools/include/uapi/linux/bpf.h39
-rw-r--r--tools/include/uapi/linux/fcntl.h72
-rw-r--r--tools/include/uapi/linux/perf_event.h49
-rw-r--r--tools/include/uapi/linux/stat.h177
-rwxr-xr-xtools/kvm/kvm_stat/kvm_stat381
-rw-r--r--tools/kvm/kvm_stat/kvm_stat.txt26
-rw-r--r--tools/lguest/lguest.c2
-rw-r--r--tools/lib/api/fs/fs.c29
-rw-r--r--tools/lib/api/fs/fs.h1
-rw-r--r--tools/lib/bpf/bpf.c65
-rw-r--r--tools/lib/bpf/bpf.h10
-rw-r--r--tools/lib/bpf/libbpf.c3
-rw-r--r--tools/lib/bpf/libbpf.h2
-rw-r--r--tools/lib/string.c9
-rw-r--r--tools/lib/subcmd/help.c1
-rw-r--r--tools/lib/subcmd/help.h1
-rw-r--r--tools/lib/subcmd/parse-options.c1
-rw-r--r--tools/lib/subcmd/subcmd-util.h9
-rw-r--r--tools/lib/symbol/kallsyms.c1
-rw-r--r--tools/net/bpf_jit_disasm.c40
-rw-r--r--tools/objtool/builtin-check.c3
-rw-r--r--tools/objtool/objtool.c3
-rw-r--r--tools/pci/pcitest.c186
-rw-r--r--tools/pci/pcitest.sh56
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Build1
-rw-r--r--tools/perf/Documentation/perf-c2c.txt4
-rw-r--r--tools/perf/Documentation/perf-ftrace.txt18
-rw-r--r--tools/perf/Documentation/perf-list.txt8
-rw-r--r--tools/perf/Documentation/perf-record.txt5
-rw-r--r--tools/perf/Documentation/perf-report.txt19
-rw-r--r--tools/perf/Documentation/perf-sched.txt4
-rw-r--r--tools/perf/Documentation/perf-script.txt16
-rw-r--r--tools/perf/Documentation/perf-stat.txt6
-rw-r--r--tools/perf/Documentation/perf-trace.txt3
-rw-r--r--tools/perf/Documentation/perf.data-file-format.txt23
-rw-r--r--tools/perf/Documentation/tips.txt2
-rw-r--r--tools/perf/MANIFEST5
-rw-r--r--tools/perf/Makefile.config39
-rw-r--r--tools/perf/arch/arm/util/cs-etm.c1
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c4
-rw-r--r--tools/perf/arch/arm/util/unwind-libdw.c1
-rw-r--r--tools/perf/arch/arm64/annotate/instructions.c2
-rw-r--r--tools/perf/arch/arm64/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/arm64/util/unwind-libunwind.c2
-rw-r--r--tools/perf/arch/common.c2
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/powerpc/util/kvm-stat.c1
-rw-r--r--tools/perf/arch/powerpc/util/perf_regs.c112
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c26
-rw-r--r--tools/perf/arch/s390/annotate/instructions.c30
-rw-r--r--tools/perf/arch/s390/util/kvm-stat.c1
-rw-r--r--tools/perf/arch/x86/entry/syscalls/syscall_64.tbl1
-rw-r--r--tools/perf/arch/x86/tests/intel-cqm.c3
-rw-r--r--tools/perf/arch/x86/tests/perf-time-to-tsc.c2
-rw-r--r--tools/perf/arch/x86/util/auxtrace.c1
-rw-r--r--tools/perf/arch/x86/util/intel-bts.c1
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c1
-rw-r--r--tools/perf/arch/x86/util/kvm-stat.c1
-rw-r--r--tools/perf/arch/x86/util/perf_regs.c227
-rw-r--r--tools/perf/arch/x86/util/unwind-libdw.c1
-rw-r--r--tools/perf/bench/bench.h20
-rw-r--r--tools/perf/bench/futex-hash.c4
-rw-r--r--tools/perf/bench/futex-lock-pi.c4
-rw-r--r--tools/perf/bench/futex-requeue.c4
-rw-r--r--tools/perf/bench/futex-wake-parallel.c4
-rw-r--r--tools/perf/bench/futex-wake.c4
-rw-r--r--tools/perf/bench/futex.h10
-rw-r--r--tools/perf/bench/mem-functions.c5
-rw-r--r--tools/perf/bench/numa.c7
-rw-r--r--tools/perf/bench/sched-messaging.c3
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c6
-rw-r--r--tools/perf/builtin-bench.c12
-rw-r--r--tools/perf/builtin-buildid-cache.c18
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-c2c.c13
-rw-r--r--tools/perf/builtin-config.c21
-rw-r--r--tools/perf/builtin-data.c9
-rw-r--r--tools/perf/builtin-diff.c5
-rw-r--r--tools/perf/builtin-evlist.c2
-rw-r--r--tools/perf/builtin-ftrace.c157
-rw-r--r--tools/perf/builtin-help.c25
-rw-r--r--tools/perf/builtin-inject.c20
-rw-r--r--tools/perf/builtin-kallsyms.c3
-rw-r--r--tools/perf/builtin-kmem.c10
-rw-r--r--tools/perf/builtin-kvm.c39
-rw-r--r--tools/perf/builtin-list.c16
-rw-r--r--tools/perf/builtin-lock.c32
-rw-r--r--tools/perf/builtin-mem.c12
-rw-r--r--tools/perf/builtin-probe.c14
-rw-r--r--tools/perf/builtin-record.c44
-rw-r--r--tools/perf/builtin-report.c17
-rw-r--r--tools/perf/builtin-sched.c37
-rw-r--r--tools/perf/builtin-script.c326
-rw-r--r--tools/perf/builtin-stat.c224
-rw-r--r--tools/perf/builtin-timechart.c28
-rw-r--r--tools/perf/builtin-top.c8
-rw-r--r--tools/perf/builtin-trace.c96
-rw-r--r--tools/perf/builtin-version.c6
-rw-r--r--tools/perf/builtin.h62
-rwxr-xr-xtools/perf/check-headers.sh2
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c130
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwell/uncore.json278
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwellde/uncore-cache.json28
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwellde/uncore-memory.json29
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwellde/uncore-power.json26
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwellx/uncore-cache.json28
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwellx/uncore-interconnect.json6
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwellx/uncore-memory.json21
-rw-r--r--tools/perf/pmu-events/arch/x86/broadwellx/uncore-power.json26
-rw-r--r--tools/perf/pmu-events/arch/x86/haswell/uncore.json374
-rw-r--r--tools/perf/pmu-events/arch/x86/haswellx/uncore-cache.json28
-rw-r--r--tools/perf/pmu-events/arch/x86/haswellx/uncore-interconnect.json6
-rw-r--r--tools/perf/pmu-events/arch/x86/haswellx/uncore-memory.json21
-rw-r--r--tools/perf/pmu-events/arch/x86/haswellx/uncore-power.json26
-rw-r--r--tools/perf/pmu-events/arch/x86/ivybridge/uncore.json314
-rw-r--r--tools/perf/pmu-events/arch/x86/ivytown/uncore-cache.json22
-rw-r--r--tools/perf/pmu-events/arch/x86/ivytown/uncore-interconnect.json12
-rw-r--r--tools/perf/pmu-events/arch/x86/ivytown/uncore-memory.json19
-rw-r--r--tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json53
-rw-r--r--tools/perf/pmu-events/arch/x86/jaketown/uncore-cache.json13
-rw-r--r--tools/perf/pmu-events/arch/x86/jaketown/uncore-interconnect.json12
-rw-r--r--tools/perf/pmu-events/arch/x86/jaketown/uncore-memory.json21
-rw-r--r--tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json53
-rw-r--r--tools/perf/pmu-events/arch/x86/mapfile.csv1
-rw-r--r--tools/perf/pmu-events/arch/x86/sandybridge/uncore.json314
-rw-r--r--tools/perf/pmu-events/arch/x86/skylake/uncore.json254
-rw-r--r--tools/perf/pmu-events/jevents.c28
-rw-r--r--tools/perf/pmu-events/jevents.h3
-rw-r--r--tools/perf/pmu-events/pmu-events.h2
-rw-r--r--tools/perf/tests/Build1
-rw-r--r--tools/perf/tests/attr.c6
-rw-r--r--tools/perf/tests/backward-ring-buffer.c1
-rw-r--r--tools/perf/tests/bpf.c4
-rw-r--r--tools/perf/tests/builtin-test.c9
-rw-r--r--tools/perf/tests/clang.c1
-rw-r--r--tools/perf/tests/code-reading.c7
-rw-r--r--tools/perf/tests/cpumap.c2
-rw-r--r--tools/perf/tests/dso-data.c2
-rw-r--r--tools/perf/tests/dwarf-unwind.c1
-rw-r--r--tools/perf/tests/event-times.c3
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c2
-rw-r--r--tools/perf/tests/expr.c56
-rw-r--r--tools/perf/tests/hists_common.c2
-rw-r--r--tools/perf/tests/hists_cumulate.c2
-rw-r--r--tools/perf/tests/hists_filter.c2
-rw-r--r--tools/perf/tests/hists_link.c2
-rw-r--r--tools/perf/tests/hists_output.c2
-rw-r--r--tools/perf/tests/is_printable_array.c3
-rw-r--r--tools/perf/tests/kmod-path.c2
-rw-r--r--tools/perf/tests/mmap-basic.c3
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c2
-rw-r--r--tools/perf/tests/openat-syscall-all-cpus.c6
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c1
-rw-r--r--tools/perf/tests/openat-syscall.c5
-rw-r--r--tools/perf/tests/parse-events.c8
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c1
-rw-r--r--tools/perf/tests/perf-record.c2
-rw-r--r--tools/perf/tests/pmu.c2
-rw-r--r--tools/perf/tests/sample-parsing.c2
-rw-r--r--tools/perf/tests/sdt.c4
-rw-r--r--tools/perf/tests/sw-clock.c2
-rw-r--r--tools/perf/tests/switch-tracking.c1
-rw-r--r--tools/perf/tests/task-exit.c1
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/tests/thread-map.c6
-rw-r--r--tools/perf/tests/thread-mg-share.c12
-rw-r--r--tools/perf/tests/unit_number__scnprintf.c3
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c1
-rw-r--r--tools/perf/trace/beauty/Build1
-rw-r--r--tools/perf/trace/beauty/beauty.h24
-rw-r--r--tools/perf/trace/beauty/signum.c1
-rw-r--r--tools/perf/trace/beauty/statx.c72
-rw-r--r--tools/perf/ui/browser.c4
-rw-r--r--tools/perf/ui/browsers/annotate.c3
-rw-r--r--tools/perf/ui/browsers/header.c2
-rw-r--r--tools/perf/ui/browsers/hists.c193
-rw-r--r--tools/perf/ui/browsers/map.c2
-rw-r--r--tools/perf/ui/gtk/annotate.c3
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/ui/hist.c1
-rw-r--r--tools/perf/ui/setup.c4
-rw-r--r--tools/perf/ui/stdio/hist.c91
-rw-r--r--tools/perf/ui/tui/setup.c1
-rw-r--r--tools/perf/util/Build12
-rw-r--r--tools/perf/util/alias.c78
-rw-r--r--tools/perf/util/annotate.c95
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/auxtrace.c10
-rw-r--r--tools/perf/util/auxtrace.h1
-rw-r--r--tools/perf/util/bpf-loader.c3
-rw-r--r--tools/perf/util/bpf-loader.h2
-rw-r--r--tools/perf/util/bpf-prologue.c1
-rw-r--r--tools/perf/util/bpf-prologue.h2
-rw-r--r--tools/perf/util/build-id.c20
-rw-r--r--tools/perf/util/build-id.h8
-rw-r--r--tools/perf/util/c++/clang-c.h1
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c271
-rw-r--r--tools/perf/util/callchain.h3
-rw-r--r--tools/perf/util/cgroup.c11
-rw-r--r--tools/perf/util/cgroup.h4
-rw-r--r--tools/perf/util/cloexec.c1
-rw-r--r--tools/perf/util/cloexec.h6
-rw-r--r--tools/perf/util/color.h2
-rw-r--r--tools/perf/util/comm.c17
-rw-r--r--tools/perf/util/compress.h12
-rw-r--r--tools/perf/util/config.c61
-rw-r--r--tools/perf/util/counts.c2
-rw-r--r--tools/perf/util/cpumap.c65
-rw-r--r--tools/perf/util/cpumap.h5
-rw-r--r--tools/perf/util/ctype.c2
-rw-r--r--tools/perf/util/data-convert-bt.c5
-rw-r--r--tools/perf/util/data.c1
-rw-r--r--tools/perf/util/debug.c37
-rw-r--r--tools/perf/util/debug.h3
-rw-r--r--tools/perf/util/demangle-java.c2
-rw-r--r--tools/perf/util/drv_configs.c1
-rw-r--r--tools/perf/util/dso.c14
-rw-r--r--tools/perf/util/dso.h4
-rw-r--r--tools/perf/util/dump-insn.c14
-rw-r--r--tools/perf/util/dump-insn.h22
-rw-r--r--tools/perf/util/dwarf-aux.c3
-rw-r--r--tools/perf/util/dwarf-regs.c1
-rw-r--r--tools/perf/util/env.c1
-rw-r--r--tools/perf/util/event.c189
-rw-r--r--tools/perf/util/event.h36
-rw-r--r--tools/perf/util/evlist.c36
-rw-r--r--tools/perf/util/evlist.h6
-rw-r--r--tools/perf/util/evsel.c25
-rw-r--r--tools/perf/util/evsel.h5
-rw-r--r--tools/perf/util/evsel_fprintf.c2
-rw-r--r--tools/perf/util/expr.h25
-rw-r--r--tools/perf/util/expr.y173
-rw-r--r--tools/perf/util/header.c21
-rw-r--r--tools/perf/util/help-unknown-cmd.c9
-rw-r--r--tools/perf/util/hist.c18
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/intel-bts.c2
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c26
-rw-r--r--tools/perf/util/intel-pt.c2
-rw-r--r--tools/perf/util/jitdump.c7
-rw-r--r--tools/perf/util/llvm-utils.c1
-rw-r--r--tools/perf/util/lzma.c2
-rw-r--r--tools/perf/util/machine.c75
-rw-r--r--tools/perf/util/machine.h3
-rw-r--r--tools/perf/util/map.c20
-rw-r--r--tools/perf/util/map.h15
-rw-r--r--tools/perf/util/mem-events.c3
-rw-r--r--tools/perf/util/memswap.c24
-rw-r--r--tools/perf/util/memswap.h7
-rw-r--r--tools/perf/util/namespaces.c37
-rw-r--r--tools/perf/util/namespaces.h26
-rw-r--r--tools/perf/util/ordered-events.c5
-rw-r--r--tools/perf/util/parse-events.c92
-rw-r--r--tools/perf/util/parse-events.h30
-rw-r--r--tools/perf/util/parse-events.y73
-rw-r--r--tools/perf/util/path.c28
-rw-r--r--tools/perf/util/path.h9
-rw-r--r--tools/perf/util/perf-hooks.c1
-rw-r--r--tools/perf/util/perf_regs.c6
-rw-r--r--tools/perf/util/perf_regs.h7
-rw-r--r--tools/perf/util/pmu.c38
-rw-r--r--tools/perf/util/pmu.h6
-rw-r--r--tools/perf/util/print_binary.c55
-rw-r--r--tools/perf/util/print_binary.h28
-rw-r--r--tools/perf/util/probe-event.c29
-rw-r--r--tools/perf/util/probe-event.h7
-rw-r--r--tools/perf/util/probe-file.c218
-rw-r--r--tools/perf/util/probe-file.h8
-rw-r--r--tools/perf/util/probe-finder.c3
-rw-r--r--tools/perf/util/probe-finder.h2
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/python.c14
-rw-r--r--tools/perf/util/quote.c1
-rw-r--r--tools/perf/util/record.c1
-rw-r--r--tools/perf/util/sane_ctype.h51
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c5
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/session.c55
-rw-r--r--tools/perf/util/session.h4
-rw-r--r--tools/perf/util/sort.c109
-rw-r--r--tools/perf/util/sort.h16
-rw-r--r--tools/perf/util/srcline.c248
-rw-r--r--tools/perf/util/srcline.h34
-rw-r--r--tools/perf/util/stat-shadow.c197
-rw-r--r--tools/perf/util/stat.c2
-rw-r--r--tools/perf/util/stat.h2
-rw-r--r--tools/perf/util/strbuf.c10
-rw-r--r--tools/perf/util/strfilter.c5
-rw-r--r--tools/perf/util/string.c24
-rw-r--r--tools/perf/util/string2.h42
-rw-r--r--tools/perf/util/strlist.c1
-rw-r--r--tools/perf/util/symbol-elf.c33
-rw-r--r--tools/perf/util/symbol-minimal.c8
-rw-r--r--tools/perf/util/symbol.c75
-rw-r--r--tools/perf/util/symbol.h19
-rw-r--r--tools/perf/util/term.c6
-rw-r--r--tools/perf/util/thread-stack.c1
-rw-r--r--tools/perf/util/thread.c52
-rw-r--r--tools/perf/util/thread.h10
-rw-r--r--tools/perf/util/thread_map.c22
-rw-r--r--tools/perf/util/thread_map.h4
-rw-r--r--tools/perf/util/time-utils.c25
-rw-r--r--tools/perf/util/time-utils.h7
-rw-r--r--tools/perf/util/tool.h2
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/trace-event-parse.c3
-rw-r--r--tools/perf/util/trace-event-read.c4
-rw-r--r--tools/perf/util/units.c68
-rw-r--r--tools/perf/util/units.h17
-rw-r--r--tools/perf/util/unwind-libdw.c1
-rw-r--r--tools/perf/util/unwind-libdw.h6
-rw-r--r--tools/perf/util/unwind-libunwind-local.c2
-rw-r--r--tools/perf/util/unwind.h9
-rw-r--r--tools/perf/util/util.c327
-rw-r--r--tools/perf/util/util.h299
-rw-r--r--tools/perf/util/values.c63
-rw-r--r--tools/perf/util/vdso.c2
-rw-r--r--tools/perf/util/xyarray.c2
-rw-r--r--tools/perf/util/zlib.c1
-rw-r--r--tools/power/cpupower/utils/helpers/cpuid.c1
-rw-r--r--tools/power/pm-graph/Makefile28
-rwxr-xr-xtools/power/pm-graph/analyze_boot.py824
-rwxr-xr-xtools/power/pm-graph/analyze_suspend.py5309
-rw-r--r--tools/power/pm-graph/bootgraph.8132
-rw-r--r--tools/power/pm-graph/sleepgraph.8243
-rwxr-xr-xtools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py17
-rw-r--r--tools/power/x86/turbostat/turbostat.82
-rw-r--r--tools/power/x86/turbostat/turbostat.c26
-rw-r--r--tools/scripts/Makefile.include9
-rw-r--r--tools/spi/spidev_test.c93
-rw-r--r--tools/testing/nvdimm/Kbuild11
-rw-r--r--tools/testing/nvdimm/dax-dev.c49
-rw-r--r--tools/testing/nvdimm/pmem-dax.c21
-rw-r--r--tools/testing/nvdimm/test/nfit.c54
-rw-r--r--tools/testing/selftests/.gitignore4
-rw-r--r--tools/testing/selftests/Makefile4
-rw-r--r--tools/testing/selftests/bpf/Makefile26
-rw-r--r--tools/testing/selftests/bpf/bpf_endian.h23
-rw-r--r--tools/testing/selftests/bpf/bpf_util.h7
-rw-r--r--tools/testing/selftests/bpf/gnu/stubs.h1
-rw-r--r--tools/testing/selftests/bpf/include/uapi/linux/types.h22
-rw-r--r--tools/testing/selftests/bpf/test_align.c453
-rw-r--r--tools/testing/selftests/bpf/test_iptunnel_common.h37
-rw-r--r--tools/testing/selftests/bpf/test_l4lb.c473
-rw-r--r--tools/testing/selftests/bpf/test_lru_map.c104
-rw-r--r--tools/testing/selftests/bpf/test_maps.c66
-rw-r--r--tools/testing/selftests/bpf/test_pkt_access.c65
-rw-r--r--tools/testing/selftests/bpf/test_progs.c299
-rw-r--r--tools/testing/selftests/bpf/test_tcp_estats.c258
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c577
-rw-r--r--tools/testing/selftests/bpf/test_xdp.c235
-rw-r--r--tools/testing/selftests/breakpoints/Makefile2
-rw-r--r--tools/testing/selftests/cpufreq/config15
-rwxr-xr-xtools/testing/selftests/drivers/gpu/i915.sh1
-rw-r--r--tools/testing/selftests/ftrace/config1
-rwxr-xr-xtools/testing/selftests/ftrace/ftracetest25
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic2.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic3.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/event-enable.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/event-pid.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc117
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc114
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc132
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc172
-rw-r--r--tools/testing/selftests/ftrace/test.d/functions21
-rw-r--r--tools/testing/selftests/ftrace/test.d/instances/instance-event.tc8
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_maxactive.tc39
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc1
-rw-r--r--tools/testing/selftests/futex/Makefile9
-rw-r--r--tools/testing/selftests/gpio/Makefile11
-rw-r--r--tools/testing/selftests/gpio/config2
-rw-r--r--tools/testing/selftests/lib.mk6
-rw-r--r--tools/testing/selftests/lib/config3
-rw-r--r--tools/testing/selftests/net/Makefile2
-rwxr-xr-xtools/testing/selftests/net/netdevice.sh200
-rw-r--r--tools/testing/selftests/net/psock_fanout.c115
-rw-r--r--tools/testing/selftests/net/psock_lib.h13
-rw-r--r--tools/testing/selftests/powerpc/Makefile16
-rw-r--r--tools/testing/selftests/powerpc/cache_shape/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/cache_shape/Makefile10
-rw-r--r--tools/testing/selftests/powerpc/cache_shape/cache_shape.c125
-rw-r--r--tools/testing/selftests/powerpc/include/utils.h6
-rw-r--r--tools/testing/selftests/powerpc/tm/.gitignore1
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile4
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-vmx-unavail.c118
-rw-r--r--tools/testing/selftests/powerpc/utils.c53
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh2
-rw-r--r--tools/testing/selftests/splice/Makefile3
-rw-r--r--tools/testing/selftests/sync/Makefile3
-rw-r--r--tools/testing/selftests/timers/Makefile4
-rw-r--r--tools/testing/selftests/timers/clocksource-switch.c2
-rw-r--r--tools/testing/selftests/vm/Makefile12
-rw-r--r--tools/testing/selftests/vm/config1
-rw-r--r--tools/testing/selftests/vm/map_hugetlb.c2
-rw-r--r--tools/testing/selftests/vm/mlock2-tests.c12
-rw-r--r--tools/testing/selftests/vm/on-fault-limit.c2
-rwxr-xr-xtools/testing/selftests/vm/run_vmtests43
-rw-r--r--tools/testing/selftests/vm/thuge-gen.c2
-rw-r--r--tools/testing/selftests/vm/userfaultfd.c207
-rw-r--r--tools/testing/selftests/vm/virtual_address_range.c122
-rw-r--r--tools/testing/selftests/watchdog/watchdog-test.c61
-rw-r--r--tools/testing/selftests/x86/.gitignore13
-rw-r--r--tools/testing/selftests/x86/Makefile3
-rw-r--r--tools/testing/selftests/x86/ldt_gdt.c46
-rw-r--r--tools/testing/selftests/x86/mpx-mini-test.c5
-rw-r--r--tools/usb/.gitignore2
-rw-r--r--tools/usb/usbip/README2
-rw-r--r--tools/usb/usbip/libsrc/usbip_common.c9
-rw-r--r--tools/usb/usbip/libsrc/usbip_host_common.c28
-rw-r--r--tools/usb/usbip/libsrc/vhci_driver.c28
-rw-r--r--tools/usb/usbip/src/usbip.c2
-rw-r--r--tools/virtio/linux/virtio.h1
-rw-r--r--tools/virtio/ringtest/main.c15
-rw-r--r--tools/virtio/ringtest/main.h2
-rw-r--r--tools/virtio/ringtest/ptr_ring.c3
-rw-r--r--tools/virtio/virtio_test.c4
-rw-r--r--tools/virtio/vringh_test.c7
455 files changed, 19491 insertions, 2376 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 00caacd3ed92..c8a90d01dd8e 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -86,10 +86,13 @@ tmon: FORCE
86freefall: FORCE 86freefall: FORCE
87 $(call descend,laptop/$@) 87 $(call descend,laptop/$@)
88 88
89kvm_stat: FORCE
90 $(call descend,kvm/$@)
91
89all: acpi cgroup cpupower gpio hv firewire lguest \ 92all: acpi cgroup cpupower gpio hv firewire lguest \
90 perf selftests turbostat usb \ 93 perf selftests turbostat usb \
91 virtio vm net x86_energy_perf_policy \ 94 virtio vm net x86_energy_perf_policy \
92 tmon freefall objtool 95 tmon freefall objtool kvm_stat
93 96
94acpi_install: 97acpi_install:
95 $(call descend,power/$(@:_install=),install) 98 $(call descend,power/$(@:_install=),install)
diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h
index af05f8e0903e..6ebd3e6a1fd1 100644
--- a/tools/arch/arm/include/uapi/asm/kvm.h
+++ b/tools/arch/arm/include/uapi/asm/kvm.h
@@ -181,10 +181,23 @@ struct kvm_arch_memory_slot {
181#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 181#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
182#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 182#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
183#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) 183#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
184#define KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
185#define KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
186 (0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
184#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 187#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
185#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) 188#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
189#define KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
186#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3 190#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
187#define KVM_DEV_ARM_VGIC_GRP_CTRL 4 191#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
192#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
193#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
194#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
195#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
196#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
197 (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
198#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
199#define VGIC_LEVEL_INFO_LINE_LEVEL 0
200
188#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 201#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
189 202
190/* KVM_IRQ_LINE irq field index values */ 203/* KVM_IRQ_LINE irq field index values */
diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h
index 3051f86a9b5f..c2860358ae3e 100644
--- a/tools/arch/arm64/include/uapi/asm/kvm.h
+++ b/tools/arch/arm64/include/uapi/asm/kvm.h
@@ -201,10 +201,23 @@ struct kvm_arch_memory_slot {
201#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 201#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
202#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 202#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
203#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) 203#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
204#define KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT 32
205#define KVM_DEV_ARM_VGIC_V3_MPIDR_MASK \
206 (0xffffffffULL << KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT)
204#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 207#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
205#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) 208#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
209#define KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK (0xffff)
206#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3 210#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
207#define KVM_DEV_ARM_VGIC_GRP_CTRL 4 211#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
212#define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
213#define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
214#define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO 7
215#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT 10
216#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
217 (0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
218#define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
219#define VGIC_LEVEL_INFO_LINE_LEVEL 0
220
208#define KVM_DEV_ARM_VGIC_CTRL_INIT 0 221#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
209 222
210/* Device Control API on vcpu fd */ 223/* Device Control API on vcpu fd */
diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h
index 3603b6f51b11..4edbe4bb0e8b 100644
--- a/tools/arch/powerpc/include/uapi/asm/kvm.h
+++ b/tools/arch/powerpc/include/uapi/asm/kvm.h
@@ -413,6 +413,26 @@ struct kvm_get_htab_header {
413 __u16 n_invalid; 413 __u16 n_invalid;
414}; 414};
415 415
416/* For KVM_PPC_CONFIGURE_V3_MMU */
417struct kvm_ppc_mmuv3_cfg {
418 __u64 flags;
419 __u64 process_table; /* second doubleword of partition table entry */
420};
421
422/* Flag values for KVM_PPC_CONFIGURE_V3_MMU */
423#define KVM_PPC_MMUV3_RADIX 1 /* 1 = radix mode, 0 = HPT */
424#define KVM_PPC_MMUV3_GTSE 2 /* global translation shootdown enb. */
425
426/* For KVM_PPC_GET_RMMU_INFO */
427struct kvm_ppc_rmmu_info {
428 struct kvm_ppc_radix_geom {
429 __u8 page_shift;
430 __u8 level_bits[4];
431 __u8 pad[3];
432 } geometries[8];
433 __u32 ap_encodings[8];
434};
435
416/* Per-vcpu XICS interrupt controller state */ 436/* Per-vcpu XICS interrupt controller state */
417#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c) 437#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c)
418 438
@@ -613,5 +633,7 @@ struct kvm_get_htab_header {
613#define KVM_XICS_LEVEL_SENSITIVE (1ULL << 40) 633#define KVM_XICS_LEVEL_SENSITIVE (1ULL << 40)
614#define KVM_XICS_MASKED (1ULL << 41) 634#define KVM_XICS_MASKED (1ULL << 41)
615#define KVM_XICS_PENDING (1ULL << 42) 635#define KVM_XICS_PENDING (1ULL << 42)
636#define KVM_XICS_PRESENTED (1ULL << 43)
637#define KVM_XICS_QUEUED (1ULL << 44)
616 638
617#endif /* __LINUX_KVM_POWERPC_H */ 639#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h
index a2ffec4139ad..7f4fd65e9208 100644
--- a/tools/arch/s390/include/uapi/asm/kvm.h
+++ b/tools/arch/s390/include/uapi/asm/kvm.h
@@ -131,7 +131,8 @@ struct kvm_s390_vm_cpu_subfunc {
131 __u8 kmo[16]; /* with MSA4 */ 131 __u8 kmo[16]; /* with MSA4 */
132 __u8 pcc[16]; /* with MSA4 */ 132 __u8 pcc[16]; /* with MSA4 */
133 __u8 ppno[16]; /* with MSA5 */ 133 __u8 ppno[16]; /* with MSA5 */
134 __u8 reserved[1824]; 134 __u8 kma[16]; /* with MSA8 */
135 __u8 reserved[1808];
135}; 136};
136 137
137/* kvm attributes for crypto */ 138/* kvm attributes for crypto */
diff --git a/tools/arch/x86/include/asm/atomic.h b/tools/arch/x86/include/asm/atomic.h
index 059e33e94260..328eeceec709 100644
--- a/tools/arch/x86/include/asm/atomic.h
+++ b/tools/arch/x86/include/asm/atomic.h
@@ -7,6 +7,8 @@
7 7
8#define LOCK_PREFIX "\n\tlock; " 8#define LOCK_PREFIX "\n\tlock; "
9 9
10#include <asm/cmpxchg.h>
11
10/* 12/*
11 * Atomic operations that C can't guarantee us. Useful for 13 * Atomic operations that C can't guarantee us. Useful for
12 * resource counting etc.. 14 * resource counting etc..
@@ -62,4 +64,9 @@ static inline int atomic_dec_and_test(atomic_t *v)
62 GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); 64 GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e");
63} 65}
64 66
67static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new)
68{
69 return cmpxchg(&v->counter, old, new);
70}
71
65#endif /* _TOOLS_LINUX_ASM_X86_ATOMIC_H */ 72#endif /* _TOOLS_LINUX_ASM_X86_ATOMIC_H */
diff --git a/tools/arch/x86/include/asm/cmpxchg.h b/tools/arch/x86/include/asm/cmpxchg.h
new file mode 100644
index 000000000000..f5253260f3cc
--- /dev/null
+++ b/tools/arch/x86/include/asm/cmpxchg.h
@@ -0,0 +1,89 @@
1#ifndef TOOLS_ASM_X86_CMPXCHG_H
2#define TOOLS_ASM_X86_CMPXCHG_H
3
4#include <linux/compiler.h>
5
6/*
7 * Non-existant functions to indicate usage errors at link time
8 * (or compile-time if the compiler implements __compiletime_error().
9 */
10extern void __cmpxchg_wrong_size(void)
11 __compiletime_error("Bad argument size for cmpxchg");
12
13/*
14 * Constants for operation sizes. On 32-bit, the 64-bit size it set to
15 * -1 because sizeof will never return -1, thereby making those switch
16 * case statements guaranteeed dead code which the compiler will
17 * eliminate, and allowing the "missing symbol in the default case" to
18 * indicate a usage error.
19 */
20#define __X86_CASE_B 1
21#define __X86_CASE_W 2
22#define __X86_CASE_L 4
23#ifdef __x86_64__
24#define __X86_CASE_Q 8
25#else
26#define __X86_CASE_Q -1 /* sizeof will never return -1 */
27#endif
28
29/*
30 * Atomic compare and exchange. Compare OLD with MEM, if identical,
31 * store NEW in MEM. Return the initial value in MEM. Success is
32 * indicated by comparing RETURN with OLD.
33 */
34#define __raw_cmpxchg(ptr, old, new, size, lock) \
35({ \
36 __typeof__(*(ptr)) __ret; \
37 __typeof__(*(ptr)) __old = (old); \
38 __typeof__(*(ptr)) __new = (new); \
39 switch (size) { \
40 case __X86_CASE_B: \
41 { \
42 volatile u8 *__ptr = (volatile u8 *)(ptr); \
43 asm volatile(lock "cmpxchgb %2,%1" \
44 : "=a" (__ret), "+m" (*__ptr) \
45 : "q" (__new), "0" (__old) \
46 : "memory"); \
47 break; \
48 } \
49 case __X86_CASE_W: \
50 { \
51 volatile u16 *__ptr = (volatile u16 *)(ptr); \
52 asm volatile(lock "cmpxchgw %2,%1" \
53 : "=a" (__ret), "+m" (*__ptr) \
54 : "r" (__new), "0" (__old) \
55 : "memory"); \
56 break; \
57 } \
58 case __X86_CASE_L: \
59 { \
60 volatile u32 *__ptr = (volatile u32 *)(ptr); \
61 asm volatile(lock "cmpxchgl %2,%1" \
62 : "=a" (__ret), "+m" (*__ptr) \
63 : "r" (__new), "0" (__old) \
64 : "memory"); \
65 break; \
66 } \
67 case __X86_CASE_Q: \
68 { \
69 volatile u64 *__ptr = (volatile u64 *)(ptr); \
70 asm volatile(lock "cmpxchgq %2,%1" \
71 : "=a" (__ret), "+m" (*__ptr) \
72 : "r" (__new), "0" (__old) \
73 : "memory"); \
74 break; \
75 } \
76 default: \
77 __cmpxchg_wrong_size(); \
78 } \
79 __ret; \
80})
81
82#define __cmpxchg(ptr, old, new, size) \
83 __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX)
84
85#define cmpxchg(ptr, old, new) \
86 __cmpxchg(ptr, old, new, sizeof(*(ptr)))
87
88
89#endif /* TOOLS_ASM_X86_CMPXCHG_H */
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
index 293149a1c6a1..0fe00446f9ca 100644
--- a/tools/arch/x86/include/asm/cpufeatures.h
+++ b/tools/arch/x86/include/asm/cpufeatures.h
@@ -100,7 +100,7 @@
100#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */ 100#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */
101#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ 101#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
102#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ 102#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */
103/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */ 103#define X86_FEATURE_CPUID ( 3*32+25) /* CPU has CPUID instruction itself */
104#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ 104#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */
105#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ 105#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */
106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ 106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
@@ -186,7 +186,8 @@
186 * 186 *
187 * Reuse free bits when adding new feature flags! 187 * Reuse free bits when adding new feature flags!
188 */ 188 */
189 189#define X86_FEATURE_RING3MWAIT ( 7*32+ 0) /* Ring 3 MONITOR/MWAIT */
190#define X86_FEATURE_CPUID_FAULT ( 7*32+ 1) /* Intel CPUID faulting */
190#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ 191#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */
191#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ 192#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
192#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */ 193#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */
@@ -289,7 +290,8 @@
289#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */ 290#define X86_FEATURE_PKU (16*32+ 3) /* Protection Keys for Userspace */
290#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */ 291#define X86_FEATURE_OSPKE (16*32+ 4) /* OS Protection Keys Enable */
291#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ 292#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */
292#define X86_FEATURE_RDPID (16*32+ 22) /* RDPID instruction */ 293#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */
294#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */
293 295
294/* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */ 296/* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */
295#define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */ 297#define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */
@@ -321,5 +323,4 @@
321#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ 323#define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */
322#define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ 324#define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */
323#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ 325#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */
324
325#endif /* _ASM_X86_CPUFEATURES_H */ 326#endif /* _ASM_X86_CPUFEATURES_H */
diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S
index 49e6ebac7e73..98dcc112b363 100644
--- a/tools/arch/x86/lib/memcpy_64.S
+++ b/tools/arch/x86/lib/memcpy_64.S
@@ -286,7 +286,7 @@ ENDPROC(memcpy_mcsafe_unrolled)
286 _ASM_EXTABLE_FAULT(.L_copy_leading_bytes, .L_memcpy_mcsafe_fail) 286 _ASM_EXTABLE_FAULT(.L_copy_leading_bytes, .L_memcpy_mcsafe_fail)
287 _ASM_EXTABLE_FAULT(.L_cache_w0, .L_memcpy_mcsafe_fail) 287 _ASM_EXTABLE_FAULT(.L_cache_w0, .L_memcpy_mcsafe_fail)
288 _ASM_EXTABLE_FAULT(.L_cache_w1, .L_memcpy_mcsafe_fail) 288 _ASM_EXTABLE_FAULT(.L_cache_w1, .L_memcpy_mcsafe_fail)
289 _ASM_EXTABLE_FAULT(.L_cache_w3, .L_memcpy_mcsafe_fail) 289 _ASM_EXTABLE_FAULT(.L_cache_w2, .L_memcpy_mcsafe_fail)
290 _ASM_EXTABLE_FAULT(.L_cache_w3, .L_memcpy_mcsafe_fail) 290 _ASM_EXTABLE_FAULT(.L_cache_w3, .L_memcpy_mcsafe_fail)
291 _ASM_EXTABLE_FAULT(.L_cache_w4, .L_memcpy_mcsafe_fail) 291 _ASM_EXTABLE_FAULT(.L_cache_w4, .L_memcpy_mcsafe_fail)
292 _ASM_EXTABLE_FAULT(.L_cache_w5, .L_memcpy_mcsafe_fail) 292 _ASM_EXTABLE_FAULT(.L_cache_w5, .L_memcpy_mcsafe_fail)
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index e3fb5ecbdcb6..523911f316ce 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -63,6 +63,7 @@ FEATURE_TESTS_BASIC := \
63 lzma \ 63 lzma \
64 get_cpuid \ 64 get_cpuid \
65 bpf \ 65 bpf \
66 sched_getcpu \
66 sdt 67 sdt
67 68
68# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list 69# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index b564a2eea039..e35e4e5ad192 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -48,21 +48,22 @@ FILES= \
48 test-get_cpuid.bin \ 48 test-get_cpuid.bin \
49 test-sdt.bin \ 49 test-sdt.bin \
50 test-cxx.bin \ 50 test-cxx.bin \
51 test-jvmti.bin 51 test-jvmti.bin \
52 test-sched_getcpu.bin
52 53
53FILES := $(addprefix $(OUTPUT),$(FILES)) 54FILES := $(addprefix $(OUTPUT),$(FILES))
54 55
55CC := $(CROSS_COMPILE)gcc -MD 56CC ?= $(CROSS_COMPILE)gcc
56CXX := $(CROSS_COMPILE)g++ -MD 57CXX ?= $(CROSS_COMPILE)g++
57PKG_CONFIG := $(CROSS_COMPILE)pkg-config 58PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
58LLVM_CONFIG ?= llvm-config 59LLVM_CONFIG ?= llvm-config
59 60
60all: $(FILES) 61all: $(FILES)
61 62
62__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS) 63__BUILD = $(CC) $(CFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
63 BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1 64 BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
64 65
65__BUILDXX = $(CXX) $(CXXFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS) 66__BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS)
66 BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1 67 BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1
67 68
68############################### 69###############################
@@ -91,6 +92,9 @@ $(OUTPUT)test-libelf.bin:
91$(OUTPUT)test-glibc.bin: 92$(OUTPUT)test-glibc.bin:
92 $(BUILD) 93 $(BUILD)
93 94
95$(OUTPUT)test-sched_getcpu.bin:
96 $(BUILD)
97
94DWARFLIBS := -ldw 98DWARFLIBS := -ldw
95ifeq ($(findstring -static,${LDFLAGS}),-static) 99ifeq ($(findstring -static,${LDFLAGS}),-static)
96DWARFLIBS += -lelf -lebl -lz -llzma -lbz2 100DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
@@ -171,7 +175,7 @@ $(OUTPUT)test-libperl.bin:
171 $(BUILD) $(FLAGS_PERL_EMBED) 175 $(BUILD) $(FLAGS_PERL_EMBED)
172 176
173$(OUTPUT)test-libpython.bin: 177$(OUTPUT)test-libpython.bin:
174 $(BUILD) 178 $(BUILD) $(FLAGS_PYTHON_EMBED)
175 179
176$(OUTPUT)test-libpython-version.bin: 180$(OUTPUT)test-libpython-version.bin:
177 $(BUILD) 181 $(BUILD)
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 699e43627397..cc6c7c01f4ca 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -117,6 +117,10 @@
117# include "test-pthread-attr-setaffinity-np.c" 117# include "test-pthread-attr-setaffinity-np.c"
118#undef main 118#undef main
119 119
120#define main main_test_sched_getcpu
121# include "test-sched_getcpu.c"
122#undef main
123
120# if 0 124# if 0
121/* 125/*
122 * Disable libbabeltrace check for test-all, because the requested 126 * Disable libbabeltrace check for test-all, because the requested
@@ -182,6 +186,7 @@ int main(int argc, char *argv[])
182 main_test_get_cpuid(); 186 main_test_get_cpuid();
183 main_test_bpf(); 187 main_test_bpf();
184 main_test_libcrypto(); 188 main_test_libcrypto();
189 main_test_sched_getcpu();
185 main_test_sdt(); 190 main_test_sdt();
186 191
187 return 0; 192 return 0;
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c
index e04ab89a1013..7598361ef1f1 100644
--- a/tools/build/feature/test-bpf.c
+++ b/tools/build/feature/test-bpf.c
@@ -9,6 +9,9 @@
9# define __NR_bpf 321 9# define __NR_bpf 321
10# elif defined(__aarch64__) 10# elif defined(__aarch64__)
11# define __NR_bpf 280 11# define __NR_bpf 280
12# elif defined(__sparc__)
13# define __NR_bpf 349
14# else
12# error __NR_bpf not defined. libbpf does not support your arch. 15# error __NR_bpf not defined. libbpf does not support your arch.
13# endif 16# endif
14#endif 17#endif
@@ -26,6 +29,7 @@ int main(void)
26 attr.log_size = 0; 29 attr.log_size = 0;
27 attr.log_level = 0; 30 attr.log_level = 0;
28 attr.kern_version = 0; 31 attr.kern_version = 0;
32 attr.prog_flags = 0;
29 33
30 /* 34 /*
31 * Test existence of __NR_bpf and BPF_PROG_LOAD. 35 * Test existence of __NR_bpf and BPF_PROG_LOAD.
diff --git a/tools/build/feature/test-sched_getcpu.c b/tools/build/feature/test-sched_getcpu.c
new file mode 100644
index 000000000000..9c6b4cbffb1c
--- /dev/null
+++ b/tools/build/feature/test-sched_getcpu.c
@@ -0,0 +1,9 @@
1#ifndef _GNU_SOURCE
2#define _GNU_SOURCE
3#endif
4#include <sched.h>
5
6int main(void)
7{
8 return sched_getcpu();
9}
diff --git a/tools/hv/bondvf.sh b/tools/hv/bondvf.sh
index 4aa5369ffa4e..d85968cb1bf2 100755
--- a/tools/hv/bondvf.sh
+++ b/tools/hv/bondvf.sh
@@ -101,9 +101,25 @@ function create_bond_cfg_redhat {
101 echo BONDING_OPTS=\"mode=active-backup miimon=100 primary=$2\" >>$fn 101 echo BONDING_OPTS=\"mode=active-backup miimon=100 primary=$2\" >>$fn
102} 102}
103 103
104function del_eth_cfg_ubuntu {
105 local fn=$cfgdir/interfaces
106 local tmpfl=$(mktemp)
107
108 local nic_start='^[ \t]*(auto|iface|mapping|allow-.*)[ \t]+'$1
109 local nic_end='^[ \t]*(auto|iface|mapping|allow-.*|source)'
110
111 awk "/$nic_end/{x=0} x{next} /$nic_start/{x=1;next} 1" $fn >$tmpfl
112
113 cp $tmpfl $fn
114
115 rm $tmpfl
116}
117
104function create_eth_cfg_ubuntu { 118function create_eth_cfg_ubuntu {
105 local fn=$cfgdir/interfaces 119 local fn=$cfgdir/interfaces
106 120
121 del_eth_cfg_ubuntu $1
122
107 echo $'\n'auto $1 >>$fn 123 echo $'\n'auto $1 >>$fn
108 echo iface $1 inet manual >>$fn 124 echo iface $1 inet manual >>$fn
109 echo bond-master $2 >>$fn 125 echo bond-master $2 >>$fn
@@ -119,6 +135,8 @@ function create_eth_cfg_pri_ubuntu {
119function create_bond_cfg_ubuntu { 135function create_bond_cfg_ubuntu {
120 local fn=$cfgdir/interfaces 136 local fn=$cfgdir/interfaces
121 137
138 del_eth_cfg_ubuntu $1
139
122 echo $'\n'auto $1 >>$fn 140 echo $'\n'auto $1 >>$fn
123 echo iface $1 inet dhcp >>$fn 141 echo iface $1 inet dhcp >>$fn
124 echo bond-mode active-backup >>$fn 142 echo bond-mode active-backup >>$fn
diff --git a/tools/include/asm-generic/atomic-gcc.h b/tools/include/asm-generic/atomic-gcc.h
index 2ba78c9f5701..5e9738f97bf3 100644
--- a/tools/include/asm-generic/atomic-gcc.h
+++ b/tools/include/asm-generic/atomic-gcc.h
@@ -60,4 +60,12 @@ static inline int atomic_dec_and_test(atomic_t *v)
60 return __sync_sub_and_fetch(&v->counter, 1) == 0; 60 return __sync_sub_and_fetch(&v->counter, 1) == 0;
61} 61}
62 62
63#define cmpxchg(ptr, oldval, newval) \
64 __sync_val_compare_and_swap(ptr, oldval, newval)
65
66static inline int atomic_cmpxchg(atomic_t *v, int oldval, int newval)
67{
68 return cmpxchg(&(v)->counter, oldval, newval);
69}
70
63#endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */ 71#endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */
diff --git a/tools/include/linux/atomic.h b/tools/include/linux/atomic.h
index 4e3d3d18ebab..9f21fc2b092b 100644
--- a/tools/include/linux/atomic.h
+++ b/tools/include/linux/atomic.h
@@ -3,4 +3,10 @@
3 3
4#include <asm/atomic.h> 4#include <asm/atomic.h>
5 5
6/* atomic_cmpxchg_relaxed */
7#ifndef atomic_cmpxchg_relaxed
8#define atomic_cmpxchg_relaxed atomic_cmpxchg
9#define atomic_cmpxchg_release atomic_cmpxchg
10#endif /* atomic_cmpxchg_relaxed */
11
6#endif /* __TOOLS_LINUX_ATOMIC_H */ 12#endif /* __TOOLS_LINUX_ATOMIC_H */
diff --git a/tools/include/linux/bug.h b/tools/include/linux/bug.h
new file mode 100644
index 000000000000..8e4a4f49135d
--- /dev/null
+++ b/tools/include/linux/bug.h
@@ -0,0 +1,10 @@
1#ifndef _TOOLS_PERF_LINUX_BUG_H
2#define _TOOLS_PERF_LINUX_BUG_H
3
4/* Force a compilation error if condition is true, but also produce a
5 result (of value 0 and type size_t), so the expression can be used
6 e.g. in a structure initializer (or where-ever else comma expressions
7 aren't permitted). */
8#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
9
10#endif /* _TOOLS_PERF_LINUX_BUG_H */
diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h
index 48af2f10a42d..825d44f89a29 100644
--- a/tools/include/linux/compiler-gcc.h
+++ b/tools/include/linux/compiler-gcc.h
@@ -12,3 +12,10 @@
12#if GCC_VERSION >= 70000 && !defined(__CHECKER__) 12#if GCC_VERSION >= 70000 && !defined(__CHECKER__)
13# define __fallthrough __attribute__ ((fallthrough)) 13# define __fallthrough __attribute__ ((fallthrough))
14#endif 14#endif
15
16#if GCC_VERSION >= 40300
17# define __compiletime_error(message) __attribute__((error(message)))
18#endif /* GCC_VERSION >= 40300 */
19
20/* &a[0] degrades to a pointer: a different type from an array */
21#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h
index 8de163b17c0d..23299d7e7160 100644
--- a/tools/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -5,6 +5,10 @@
5#include <linux/compiler-gcc.h> 5#include <linux/compiler-gcc.h>
6#endif 6#endif
7 7
8#ifndef __compiletime_error
9# define __compiletime_error(message)
10#endif
11
8/* Optimization barrier */ 12/* Optimization barrier */
9/* The "volatile" is due to gcc bugs */ 13/* The "volatile" is due to gcc bugs */
10#define barrier() __asm__ __volatile__("": : :"memory") 14#define barrier() __asm__ __volatile__("": : :"memory")
@@ -13,6 +17,11 @@
13# define __always_inline inline __attribute__((always_inline)) 17# define __always_inline inline __attribute__((always_inline))
14#endif 18#endif
15 19
20/* Are two types/vars the same type (ignoring qualifiers)? */
21#ifndef __same_type
22# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
23#endif
24
16#ifdef __ANDROID__ 25#ifdef __ANDROID__
17/* 26/*
18 * FIXME: Big hammer to get rid of tons of: 27 * FIXME: Big hammer to get rid of tons of:
diff --git a/tools/include/linux/filter.h b/tools/include/linux/filter.h
index 122153b16ea4..390d7c9685fd 100644
--- a/tools/include/linux/filter.h
+++ b/tools/include/linux/filter.h
@@ -168,6 +168,16 @@
168 .off = OFF, \ 168 .off = OFF, \
169 .imm = 0 }) 169 .imm = 0 })
170 170
171/* Atomic memory add, *(uint *)(dst_reg + off16) += src_reg */
172
173#define BPF_STX_XADD(SIZE, DST, SRC, OFF) \
174 ((struct bpf_insn) { \
175 .code = BPF_STX | BPF_SIZE(SIZE) | BPF_XADD, \
176 .dst_reg = DST, \
177 .src_reg = SRC, \
178 .off = OFF, \
179 .imm = 0 })
180
171/* Memory store, *(uint *) (dst_reg + off16) = imm32 */ 181/* Memory store, *(uint *) (dst_reg + off16) = imm32 */
172 182
173#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ 183#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
diff --git a/tools/include/linux/hashtable.h b/tools/include/linux/hashtable.h
index c65cc0aa2659..251eabf2a05e 100644
--- a/tools/include/linux/hashtable.h
+++ b/tools/include/linux/hashtable.h
@@ -13,10 +13,6 @@
13#include <linux/hash.h> 13#include <linux/hash.h>
14#include <linux/log2.h> 14#include <linux/log2.h>
15 15
16#ifndef ARRAY_SIZE
17#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
18#endif
19
20#define DEFINE_HASHTABLE(name, bits) \ 16#define DEFINE_HASHTABLE(name, bits) \
21 struct hlist_head name[1 << (bits)] = \ 17 struct hlist_head name[1 << (bits)] = \
22 { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } 18 { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
diff --git a/tools/include/linux/kernel.h b/tools/include/linux/kernel.h
index 28607db02bd3..73ccc48126bb 100644
--- a/tools/include/linux/kernel.h
+++ b/tools/include/linux/kernel.h
@@ -4,6 +4,11 @@
4#include <stdarg.h> 4#include <stdarg.h>
5#include <stddef.h> 5#include <stddef.h>
6#include <assert.h> 6#include <assert.h>
7#include <linux/compiler.h>
8
9#ifndef UINT_MAX
10#define UINT_MAX (~0U)
11#endif
7 12
8#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) 13#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
9 14
@@ -72,6 +77,8 @@
72int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); 77int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
73int scnprintf(char * buf, size_t size, const char * fmt, ...); 78int scnprintf(char * buf, size_t size, const char * fmt, ...);
74 79
80#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
81
75/* 82/*
76 * This looks more complex than it should be. But we need to 83 * This looks more complex than it should be. But we need to
77 * get the type for the ~ right in round_down (it needs to be 84 * get the type for the ~ right in round_down (it needs to be
diff --git a/tools/include/linux/log2.h b/tools/include/linux/log2.h
index d5677d39c1e4..0325cefc2220 100644
--- a/tools/include/linux/log2.h
+++ b/tools/include/linux/log2.h
@@ -12,6 +12,9 @@
12#ifndef _TOOLS_LINUX_LOG2_H 12#ifndef _TOOLS_LINUX_LOG2_H
13#define _TOOLS_LINUX_LOG2_H 13#define _TOOLS_LINUX_LOG2_H
14 14
15#include <linux/bitops.h>
16#include <linux/types.h>
17
15/* 18/*
16 * non-constant log of base 2 calculators 19 * non-constant log of base 2 calculators
17 * - the arch may override these in asm/bitops.h if they can be implemented 20 * - the arch may override these in asm/bitops.h if they can be implemented
diff --git a/tools/include/linux/refcount.h b/tools/include/linux/refcount.h
new file mode 100644
index 000000000000..a0177c1f55b1
--- /dev/null
+++ b/tools/include/linux/refcount.h
@@ -0,0 +1,151 @@
1#ifndef _TOOLS_LINUX_REFCOUNT_H
2#define _TOOLS_LINUX_REFCOUNT_H
3
4/*
5 * Variant of atomic_t specialized for reference counts.
6 *
7 * The interface matches the atomic_t interface (to aid in porting) but only
8 * provides the few functions one should use for reference counting.
9 *
10 * It differs in that the counter saturates at UINT_MAX and will not move once
11 * there. This avoids wrapping the counter and causing 'spurious'
12 * use-after-free issues.
13 *
14 * Memory ordering rules are slightly relaxed wrt regular atomic_t functions
15 * and provide only what is strictly required for refcounts.
16 *
17 * The increments are fully relaxed; these will not provide ordering. The
18 * rationale is that whatever is used to obtain the object we're increasing the
19 * reference count on will provide the ordering. For locked data structures,
20 * its the lock acquire, for RCU/lockless data structures its the dependent
21 * load.
22 *
23 * Do note that inc_not_zero() provides a control dependency which will order
24 * future stores against the inc, this ensures we'll never modify the object
25 * if we did not in fact acquire a reference.
26 *
27 * The decrements will provide release order, such that all the prior loads and
28 * stores will be issued before, it also provides a control dependency, which
29 * will order us against the subsequent free().
30 *
31 * The control dependency is against the load of the cmpxchg (ll/sc) that
32 * succeeded. This means the stores aren't fully ordered, but this is fine
33 * because the 1->0 transition indicates no concurrency.
34 *
35 * Note that the allocator is responsible for ordering things between free()
36 * and alloc().
37 *
38 */
39
40#include <linux/atomic.h>
41#include <linux/kernel.h>
42
43#ifdef NDEBUG
44#define REFCOUNT_WARN(cond, str) (void)(cond)
45#define __refcount_check
46#else
47#define REFCOUNT_WARN(cond, str) BUG_ON(cond)
48#define __refcount_check __must_check
49#endif
50
51typedef struct refcount_struct {
52 atomic_t refs;
53} refcount_t;
54
55#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), }
56
57static inline void refcount_set(refcount_t *r, unsigned int n)
58{
59 atomic_set(&r->refs, n);
60}
61
62static inline unsigned int refcount_read(const refcount_t *r)
63{
64 return atomic_read(&r->refs);
65}
66
67/*
68 * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN.
69 *
70 * Provides no memory ordering, it is assumed the caller has guaranteed the
71 * object memory to be stable (RCU, etc.). It does provide a control dependency
72 * and thereby orders future stores. See the comment on top.
73 */
74static inline __refcount_check
75bool refcount_inc_not_zero(refcount_t *r)
76{
77 unsigned int old, new, val = atomic_read(&r->refs);
78
79 for (;;) {
80 new = val + 1;
81
82 if (!val)
83 return false;
84
85 if (unlikely(!new))
86 return true;
87
88 old = atomic_cmpxchg_relaxed(&r->refs, val, new);
89 if (old == val)
90 break;
91
92 val = old;
93 }
94
95 REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n");
96
97 return true;
98}
99
100/*
101 * Similar to atomic_inc(), will saturate at UINT_MAX and WARN.
102 *
103 * Provides no memory ordering, it is assumed the caller already has a
104 * reference on the object, will WARN when this is not so.
105 */
106static inline void refcount_inc(refcount_t *r)
107{
108 REFCOUNT_WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n");
109}
110
111/*
112 * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
113 * decrement when saturated at UINT_MAX.
114 *
115 * Provides release memory ordering, such that prior loads and stores are done
116 * before, and provides a control dependency such that free() must come after.
117 * See the comment on top.
118 */
119static inline __refcount_check
120bool refcount_sub_and_test(unsigned int i, refcount_t *r)
121{
122 unsigned int old, new, val = atomic_read(&r->refs);
123
124 for (;;) {
125 if (unlikely(val == UINT_MAX))
126 return false;
127
128 new = val - i;
129 if (new > val) {
130 REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n");
131 return false;
132 }
133
134 old = atomic_cmpxchg_release(&r->refs, val, new);
135 if (old == val)
136 break;
137
138 val = old;
139 }
140
141 return !new;
142}
143
144static inline __refcount_check
145bool refcount_dec_and_test(refcount_t *r)
146{
147 return refcount_sub_and_test(1, r);
148}
149
150
151#endif /* _ATOMIC_LINUX_REFCOUNT_H */
diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h
index f436d2420a18..d62b56cf8c12 100644
--- a/tools/include/linux/string.h
+++ b/tools/include/linux/string.h
@@ -18,4 +18,6 @@ extern size_t strlcpy(char *dest, const char *src, size_t size);
18 18
19char *str_error_r(int errnum, char *buf, size_t buflen); 19char *str_error_r(int errnum, char *buf, size_t buflen);
20 20
21int prefixcmp(const char *str, const char *prefix);
22
21#endif /* _LINUX_STRING_H_ */ 23#endif /* _LINUX_STRING_H_ */
diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h
index c24b3e3ae296..77a28a26a670 100644
--- a/tools/include/linux/types.h
+++ b/tools/include/linux/types.h
@@ -7,6 +7,7 @@
7 7
8#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ 8#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
9#include <asm/types.h> 9#include <asm/types.h>
10#include <asm/posix_types.h>
10 11
11struct page; 12struct page;
12struct kmem_cache; 13struct kmem_cache;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 0539a0ceef38..94dfa9def355 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -81,6 +81,7 @@ enum bpf_cmd {
81 BPF_OBJ_GET, 81 BPF_OBJ_GET,
82 BPF_PROG_ATTACH, 82 BPF_PROG_ATTACH,
83 BPF_PROG_DETACH, 83 BPF_PROG_DETACH,
84 BPF_PROG_TEST_RUN,
84}; 85};
85 86
86enum bpf_map_type { 87enum bpf_map_type {
@@ -96,6 +97,8 @@ enum bpf_map_type {
96 BPF_MAP_TYPE_LRU_HASH, 97 BPF_MAP_TYPE_LRU_HASH,
97 BPF_MAP_TYPE_LRU_PERCPU_HASH, 98 BPF_MAP_TYPE_LRU_PERCPU_HASH,
98 BPF_MAP_TYPE_LPM_TRIE, 99 BPF_MAP_TYPE_LPM_TRIE,
100 BPF_MAP_TYPE_ARRAY_OF_MAPS,
101 BPF_MAP_TYPE_HASH_OF_MAPS,
99}; 102};
100 103
101enum bpf_prog_type { 104enum bpf_prog_type {
@@ -129,6 +132,13 @@ enum bpf_attach_type {
129 */ 132 */
130#define BPF_F_ALLOW_OVERRIDE (1U << 0) 133#define BPF_F_ALLOW_OVERRIDE (1U << 0)
131 134
135/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
136 * verifier will perform strict alignment checking as if the kernel
137 * has been built with CONFIG_EFFICIENT_UNALIGNED_ACCESS not set,
138 * and NET_IP_ALIGN defined to 2.
139 */
140#define BPF_F_STRICT_ALIGNMENT (1U << 0)
141
132#define BPF_PSEUDO_MAP_FD 1 142#define BPF_PSEUDO_MAP_FD 1
133 143
134/* flags for BPF_MAP_UPDATE_ELEM command */ 144/* flags for BPF_MAP_UPDATE_ELEM command */
@@ -152,6 +162,7 @@ union bpf_attr {
152 __u32 value_size; /* size of value in bytes */ 162 __u32 value_size; /* size of value in bytes */
153 __u32 max_entries; /* max number of entries in a map */ 163 __u32 max_entries; /* max number of entries in a map */
154 __u32 map_flags; /* prealloc or not */ 164 __u32 map_flags; /* prealloc or not */
165 __u32 inner_map_fd; /* fd pointing to the inner map */
155 }; 166 };
156 167
157 struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ 168 struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
@@ -173,6 +184,7 @@ union bpf_attr {
173 __u32 log_size; /* size of user buffer */ 184 __u32 log_size; /* size of user buffer */
174 __aligned_u64 log_buf; /* user supplied buffer */ 185 __aligned_u64 log_buf; /* user supplied buffer */
175 __u32 kern_version; /* checked when prog_type=kprobe */ 186 __u32 kern_version; /* checked when prog_type=kprobe */
187 __u32 prog_flags;
176 }; 188 };
177 189
178 struct { /* anonymous struct used by BPF_OBJ_* commands */ 190 struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -186,6 +198,17 @@ union bpf_attr {
186 __u32 attach_type; 198 __u32 attach_type;
187 __u32 attach_flags; 199 __u32 attach_flags;
188 }; 200 };
201
202 struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
203 __u32 prog_fd;
204 __u32 retval;
205 __u32 data_size_in;
206 __u32 data_size_out;
207 __aligned_u64 data_in;
208 __aligned_u64 data_out;
209 __u32 repeat;
210 __u32 duration;
211 } test;
189} __attribute__((aligned(8))); 212} __attribute__((aligned(8)));
190 213
191/* BPF helper function descriptions: 214/* BPF helper function descriptions:
@@ -456,6 +479,17 @@ union bpf_attr {
456 * Return: 479 * Return:
457 * > 0 length of the string including the trailing NUL on success 480 * > 0 length of the string including the trailing NUL on success
458 * < 0 error 481 * < 0 error
482 *
483 * u64 bpf_get_socket_cookie(skb)
484 * Get the cookie for the socket stored inside sk_buff.
485 * @skb: pointer to skb
486 * Return: 8 Bytes non-decreasing number on success or 0 if the socket
487 * field is missing inside sk_buff
488 *
489 * u32 bpf_get_socket_uid(skb)
490 * Get the owner uid of the socket stored inside sk_buff.
491 * @skb: pointer to skb
492 * Return: uid of the socket owner on success or overflowuid if failed.
459 */ 493 */
460#define __BPF_FUNC_MAPPER(FN) \ 494#define __BPF_FUNC_MAPPER(FN) \
461 FN(unspec), \ 495 FN(unspec), \
@@ -503,7 +537,9 @@ union bpf_attr {
503 FN(get_numa_node_id), \ 537 FN(get_numa_node_id), \
504 FN(skb_change_head), \ 538 FN(skb_change_head), \
505 FN(xdp_adjust_head), \ 539 FN(xdp_adjust_head), \
506 FN(probe_read_str), 540 FN(probe_read_str), \
541 FN(get_socket_cookie), \
542 FN(get_socket_uid),
507 543
508/* integer value in 'imm' field of BPF_CALL instruction selects which helper 544/* integer value in 'imm' field of BPF_CALL instruction selects which helper
509 * function eBPF program intends to call 545 * function eBPF program intends to call
@@ -574,6 +610,7 @@ struct __sk_buff {
574 __u32 tc_classid; 610 __u32 tc_classid;
575 __u32 data; 611 __u32 data;
576 __u32 data_end; 612 __u32 data_end;
613 __u32 napi_id;
577}; 614};
578 615
579struct bpf_tunnel_key { 616struct bpf_tunnel_key {
diff --git a/tools/include/uapi/linux/fcntl.h b/tools/include/uapi/linux/fcntl.h
new file mode 100644
index 000000000000..813afd6eee71
--- /dev/null
+++ b/tools/include/uapi/linux/fcntl.h
@@ -0,0 +1,72 @@
1#ifndef _UAPI_LINUX_FCNTL_H
2#define _UAPI_LINUX_FCNTL_H
3
4#include <asm/fcntl.h>
5
6#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0)
7#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1)
8
9/*
10 * Cancel a blocking posix lock; internal use only until we expose an
11 * asynchronous lock api to userspace:
12 */
13#define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5)
14
15/* Create a file descriptor with FD_CLOEXEC set. */
16#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
17
18/*
19 * Request nofications on a directory.
20 * See below for events that may be notified.
21 */
22#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2)
23
24/*
25 * Set and get of pipe page size array
26 */
27#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
28#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
29
30/*
31 * Set/Get seals
32 */
33#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
34#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
35
36/*
37 * Types of seals
38 */
39#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
40#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
41#define F_SEAL_GROW 0x0004 /* prevent file from growing */
42#define F_SEAL_WRITE 0x0008 /* prevent writes */
43/* (1U << 31) is reserved for signed error codes */
44
45/*
46 * Types of directory notifications that may be requested.
47 */
48#define DN_ACCESS 0x00000001 /* File accessed */
49#define DN_MODIFY 0x00000002 /* File modified */
50#define DN_CREATE 0x00000004 /* File created */
51#define DN_DELETE 0x00000008 /* File removed */
52#define DN_RENAME 0x00000010 /* File renamed */
53#define DN_ATTRIB 0x00000020 /* File changed attibutes */
54#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
55
56#define AT_FDCWD -100 /* Special value used to indicate
57 openat should use the current
58 working directory. */
59#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
60#define AT_REMOVEDIR 0x200 /* Remove directory instead of
61 unlinking file. */
62#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
63#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
64#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
65
66#define AT_STATX_SYNC_TYPE 0x6000 /* Type of synchronisation required from statx() */
67#define AT_STATX_SYNC_AS_STAT 0x0000 /* - Do whatever stat() does */
68#define AT_STATX_FORCE_SYNC 0x2000 /* - Force the attributes to be sync'd with the server */
69#define AT_STATX_DONT_SYNC 0x4000 /* - Don't sync attributes with the server */
70
71
72#endif /* _UAPI_LINUX_FCNTL_H */
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index c66a485a24ac..b1c0b187acfe 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -344,7 +344,8 @@ struct perf_event_attr {
344 use_clockid : 1, /* use @clockid for time fields */ 344 use_clockid : 1, /* use @clockid for time fields */
345 context_switch : 1, /* context switch data */ 345 context_switch : 1, /* context switch data */
346 write_backward : 1, /* Write ring buffer from end to beginning */ 346 write_backward : 1, /* Write ring buffer from end to beginning */
347 __reserved_1 : 36; 347 namespaces : 1, /* include namespaces data */
348 __reserved_1 : 35;
348 349
349 union { 350 union {
350 __u32 wakeup_events; /* wakeup every n events */ 351 __u32 wakeup_events; /* wakeup every n events */
@@ -610,6 +611,23 @@ struct perf_event_header {
610 __u16 size; 611 __u16 size;
611}; 612};
612 613
614struct perf_ns_link_info {
615 __u64 dev;
616 __u64 ino;
617};
618
619enum {
620 NET_NS_INDEX = 0,
621 UTS_NS_INDEX = 1,
622 IPC_NS_INDEX = 2,
623 PID_NS_INDEX = 3,
624 USER_NS_INDEX = 4,
625 MNT_NS_INDEX = 5,
626 CGROUP_NS_INDEX = 6,
627
628 NR_NAMESPACES, /* number of available namespaces */
629};
630
613enum perf_event_type { 631enum perf_event_type {
614 632
615 /* 633 /*
@@ -862,6 +880,18 @@ enum perf_event_type {
862 */ 880 */
863 PERF_RECORD_SWITCH_CPU_WIDE = 15, 881 PERF_RECORD_SWITCH_CPU_WIDE = 15,
864 882
883 /*
884 * struct {
885 * struct perf_event_header header;
886 * u32 pid;
887 * u32 tid;
888 * u64 nr_namespaces;
889 * { u64 dev, inode; } [nr_namespaces];
890 * struct sample_id sample_id;
891 * };
892 */
893 PERF_RECORD_NAMESPACES = 16,
894
865 PERF_RECORD_MAX, /* non-ABI */ 895 PERF_RECORD_MAX, /* non-ABI */
866}; 896};
867 897
@@ -885,12 +915,14 @@ enum perf_callchain_context {
885 */ 915 */
886#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */ 916#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */
887#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */ 917#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */
918#define PERF_AUX_FLAG_PARTIAL 0x04 /* record contains gaps */
888 919
889#define PERF_FLAG_FD_NO_GROUP (1UL << 0) 920#define PERF_FLAG_FD_NO_GROUP (1UL << 0)
890#define PERF_FLAG_FD_OUTPUT (1UL << 1) 921#define PERF_FLAG_FD_OUTPUT (1UL << 1)
891#define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ 922#define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
892#define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ 923#define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
893 924
925#if defined(__LITTLE_ENDIAN_BITFIELD)
894union perf_mem_data_src { 926union perf_mem_data_src {
895 __u64 val; 927 __u64 val;
896 struct { 928 struct {
@@ -902,6 +934,21 @@ union perf_mem_data_src {
902 mem_rsvd:31; 934 mem_rsvd:31;
903 }; 935 };
904}; 936};
937#elif defined(__BIG_ENDIAN_BITFIELD)
938union perf_mem_data_src {
939 __u64 val;
940 struct {
941 __u64 mem_rsvd:31,
942 mem_dtlb:7, /* tlb access */
943 mem_lock:2, /* lock instr */
944 mem_snoop:5, /* snoop mode */
945 mem_lvl:14, /* memory hierarchy level */
946 mem_op:5; /* type of opcode */
947 };
948};
949#else
950#error "Unknown endianness"
951#endif
905 952
906/* type of opcode (load/store/prefetch,code) */ 953/* type of opcode (load/store/prefetch,code) */
907#define PERF_MEM_OP_NA 0x01 /* not available */ 954#define PERF_MEM_OP_NA 0x01 /* not available */
diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h
new file mode 100644
index 000000000000..d538897b8e08
--- /dev/null
+++ b/tools/include/uapi/linux/stat.h
@@ -0,0 +1,177 @@
1#ifndef _UAPI_LINUX_STAT_H
2#define _UAPI_LINUX_STAT_H
3
4#include <linux/types.h>
5
6#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
7
8#define S_IFMT 00170000
9#define S_IFSOCK 0140000
10#define S_IFLNK 0120000
11#define S_IFREG 0100000
12#define S_IFBLK 0060000
13#define S_IFDIR 0040000
14#define S_IFCHR 0020000
15#define S_IFIFO 0010000
16#define S_ISUID 0004000
17#define S_ISGID 0002000
18#define S_ISVTX 0001000
19
20#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
21#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
22#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
23#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
24#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
25#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
26#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
27
28#define S_IRWXU 00700
29#define S_IRUSR 00400
30#define S_IWUSR 00200
31#define S_IXUSR 00100
32
33#define S_IRWXG 00070
34#define S_IRGRP 00040
35#define S_IWGRP 00020
36#define S_IXGRP 00010
37
38#define S_IRWXO 00007
39#define S_IROTH 00004
40#define S_IWOTH 00002
41#define S_IXOTH 00001
42
43#endif
44
45/*
46 * Timestamp structure for the timestamps in struct statx.
47 *
48 * tv_sec holds the number of seconds before (negative) or after (positive)
49 * 00:00:00 1st January 1970 UTC.
50 *
51 * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is
52 * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time.
53 *
54 * Note that if both tv_sec and tv_nsec are non-zero, then the two values must
55 * either be both positive or both negative.
56 *
57 * __reserved is held in case we need a yet finer resolution.
58 */
59struct statx_timestamp {
60 __s64 tv_sec;
61 __s32 tv_nsec;
62 __s32 __reserved;
63};
64
65/*
66 * Structures for the extended file attribute retrieval system call
67 * (statx()).
68 *
69 * The caller passes a mask of what they're specifically interested in as a
70 * parameter to statx(). What statx() actually got will be indicated in
71 * st_mask upon return.
72 *
73 * For each bit in the mask argument:
74 *
75 * - if the datum is not supported:
76 *
77 * - the bit will be cleared, and
78 *
79 * - the datum will be set to an appropriate fabricated value if one is
80 * available (eg. CIFS can take a default uid and gid), otherwise
81 *
82 * - the field will be cleared;
83 *
84 * - otherwise, if explicitly requested:
85 *
86 * - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is
87 * set or if the datum is considered out of date, and
88 *
89 * - the field will be filled in and the bit will be set;
90 *
91 * - otherwise, if not requested, but available in approximate form without any
92 * effort, it will be filled in anyway, and the bit will be set upon return
93 * (it might not be up to date, however, and no attempt will be made to
94 * synchronise the internal state first);
95 *
96 * - otherwise the field and the bit will be cleared before returning.
97 *
98 * Items in STATX_BASIC_STATS may be marked unavailable on return, but they
99 * will have values installed for compatibility purposes so that stat() and
100 * co. can be emulated in userspace.
101 */
102struct statx {
103 /* 0x00 */
104 __u32 stx_mask; /* What results were written [uncond] */
105 __u32 stx_blksize; /* Preferred general I/O size [uncond] */
106 __u64 stx_attributes; /* Flags conveying information about the file [uncond] */
107 /* 0x10 */
108 __u32 stx_nlink; /* Number of hard links */
109 __u32 stx_uid; /* User ID of owner */
110 __u32 stx_gid; /* Group ID of owner */
111 __u16 stx_mode; /* File mode */
112 __u16 __spare0[1];
113 /* 0x20 */
114 __u64 stx_ino; /* Inode number */
115 __u64 stx_size; /* File size */
116 __u64 stx_blocks; /* Number of 512-byte blocks allocated */
117 __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */
118 /* 0x40 */
119 struct statx_timestamp stx_atime; /* Last access time */
120 struct statx_timestamp stx_btime; /* File creation time */
121 struct statx_timestamp stx_ctime; /* Last attribute change time */
122 struct statx_timestamp stx_mtime; /* Last data modification time */
123 /* 0x80 */
124 __u32 stx_rdev_major; /* Device ID of special file [if bdev/cdev] */
125 __u32 stx_rdev_minor;
126 __u32 stx_dev_major; /* ID of device containing file [uncond] */
127 __u32 stx_dev_minor;
128 /* 0x90 */
129 __u64 __spare2[14]; /* Spare space for future expansion */
130 /* 0x100 */
131};
132
133/*
134 * Flags to be stx_mask
135 *
136 * Query request/result mask for statx() and struct statx::stx_mask.
137 *
138 * These bits should be set in the mask argument of statx() to request
139 * particular items when calling statx().
140 */
141#define STATX_TYPE 0x00000001U /* Want/got stx_mode & S_IFMT */
142#define STATX_MODE 0x00000002U /* Want/got stx_mode & ~S_IFMT */
143#define STATX_NLINK 0x00000004U /* Want/got stx_nlink */
144#define STATX_UID 0x00000008U /* Want/got stx_uid */
145#define STATX_GID 0x00000010U /* Want/got stx_gid */
146#define STATX_ATIME 0x00000020U /* Want/got stx_atime */
147#define STATX_MTIME 0x00000040U /* Want/got stx_mtime */
148#define STATX_CTIME 0x00000080U /* Want/got stx_ctime */
149#define STATX_INO 0x00000100U /* Want/got stx_ino */
150#define STATX_SIZE 0x00000200U /* Want/got stx_size */
151#define STATX_BLOCKS 0x00000400U /* Want/got stx_blocks */
152#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */
153#define STATX_BTIME 0x00000800U /* Want/got stx_btime */
154#define STATX_ALL 0x00000fffU /* All currently supported flags */
155#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */
156
157/*
158 * Attributes to be found in stx_attributes and masked in stx_attributes_mask.
159 *
160 * These give information about the features or the state of a file that might
161 * be of use to ordinary userspace programs such as GUIs or ls rather than
162 * specialised tools.
163 *
164 * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS
165 * semantically. Where possible, the numerical value is picked to correspond
166 * also.
167 */
168#define STATX_ATTR_COMPRESSED 0x00000004 /* [I] File is compressed by the fs */
169#define STATX_ATTR_IMMUTABLE 0x00000010 /* [I] File is marked immutable */
170#define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */
171#define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */
172#define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */
173
174#define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */
175
176
177#endif /* _UAPI_LINUX_STAT_H */
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat
index 581278c58488..8f74ed8e7237 100755
--- a/tools/kvm/kvm_stat/kvm_stat
+++ b/tools/kvm/kvm_stat/kvm_stat
@@ -30,8 +30,8 @@ import fcntl
30import resource 30import resource
31import struct 31import struct
32import re 32import re
33import subprocess
33from collections import defaultdict 34from collections import defaultdict
34from time import sleep
35 35
36VMX_EXIT_REASONS = { 36VMX_EXIT_REASONS = {
37 'EXCEPTION_NMI': 0, 37 'EXCEPTION_NMI': 0,
@@ -225,6 +225,7 @@ IOCTL_NUMBERS = {
225 'RESET': 0x00002403, 225 'RESET': 0x00002403,
226} 226}
227 227
228
228class Arch(object): 229class Arch(object):
229 """Encapsulates global architecture specific data. 230 """Encapsulates global architecture specific data.
230 231
@@ -255,12 +256,14 @@ class Arch(object):
255 return ArchX86(SVM_EXIT_REASONS) 256 return ArchX86(SVM_EXIT_REASONS)
256 return 257 return
257 258
259
258class ArchX86(Arch): 260class ArchX86(Arch):
259 def __init__(self, exit_reasons): 261 def __init__(self, exit_reasons):
260 self.sc_perf_evt_open = 298 262 self.sc_perf_evt_open = 298
261 self.ioctl_numbers = IOCTL_NUMBERS 263 self.ioctl_numbers = IOCTL_NUMBERS
262 self.exit_reasons = exit_reasons 264 self.exit_reasons = exit_reasons
263 265
266
264class ArchPPC(Arch): 267class ArchPPC(Arch):
265 def __init__(self): 268 def __init__(self):
266 self.sc_perf_evt_open = 319 269 self.sc_perf_evt_open = 319
@@ -275,12 +278,14 @@ class ArchPPC(Arch):
275 self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 278 self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16
276 self.exit_reasons = {} 279 self.exit_reasons = {}
277 280
281
278class ArchA64(Arch): 282class ArchA64(Arch):
279 def __init__(self): 283 def __init__(self):
280 self.sc_perf_evt_open = 241 284 self.sc_perf_evt_open = 241
281 self.ioctl_numbers = IOCTL_NUMBERS 285 self.ioctl_numbers = IOCTL_NUMBERS
282 self.exit_reasons = AARCH64_EXIT_REASONS 286 self.exit_reasons = AARCH64_EXIT_REASONS
283 287
288
284class ArchS390(Arch): 289class ArchS390(Arch):
285 def __init__(self): 290 def __init__(self):
286 self.sc_perf_evt_open = 331 291 self.sc_perf_evt_open = 331
@@ -316,6 +321,61 @@ def parse_int_list(list_string):
316 return integers 321 return integers
317 322
318 323
324def get_pid_from_gname(gname):
325 """Fuzzy function to convert guest name to QEMU process pid.
326
327 Returns a list of potential pids, can be empty if no match found.
328 Throws an exception on processing errors.
329
330 """
331 pids = []
332 try:
333 child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'],
334 stdout=subprocess.PIPE)
335 except:
336 raise Exception
337 for line in child.stdout:
338 line = line.lstrip().split(' ', 1)
339 # perform a sanity check before calling the more expensive
340 # function to possibly extract the guest name
341 if ' -name ' in line[1] and gname == get_gname_from_pid(line[0]):
342 pids.append(int(line[0]))
343 child.stdout.close()
344
345 return pids
346
347
348def get_gname_from_pid(pid):
349 """Returns the guest name for a QEMU process pid.
350
351 Extracts the guest name from the QEMU comma line by processing the '-name'
352 option. Will also handle names specified out of sequence.
353
354 """
355 name = ''
356 try:
357 line = open('/proc/{}/cmdline'.format(pid), 'rb').read().split('\0')
358 parms = line[line.index('-name') + 1].split(',')
359 while '' in parms:
360 # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results in
361 # ['foo', '', 'bar'], which we revert here
362 idx = parms.index('')
363 parms[idx - 1] += ',' + parms[idx + 1]
364 del parms[idx:idx+2]
365 # the '-name' switch allows for two ways to specify the guest name,
366 # where the plain name overrides the name specified via 'guest='
367 for arg in parms:
368 if '=' not in arg:
369 name = arg
370 break
371 if arg[:6] == 'guest=':
372 name = arg[6:]
373 except (ValueError, IOError, IndexError):
374 pass
375
376 return name
377
378
319def get_online_cpus(): 379def get_online_cpus():
320 """Returns a list of cpu id integers.""" 380 """Returns a list of cpu id integers."""
321 with open('/sys/devices/system/cpu/online') as cpu_list: 381 with open('/sys/devices/system/cpu/online') as cpu_list:
@@ -342,6 +402,7 @@ def get_filters():
342libc = ctypes.CDLL('libc.so.6', use_errno=True) 402libc = ctypes.CDLL('libc.so.6', use_errno=True)
343syscall = libc.syscall 403syscall = libc.syscall
344 404
405
345class perf_event_attr(ctypes.Structure): 406class perf_event_attr(ctypes.Structure):
346 """Struct that holds the necessary data to set up a trace event. 407 """Struct that holds the necessary data to set up a trace event.
347 408
@@ -370,6 +431,7 @@ class perf_event_attr(ctypes.Structure):
370 self.size = ctypes.sizeof(self) 431 self.size = ctypes.sizeof(self)
371 self.read_format = PERF_FORMAT_GROUP 432 self.read_format = PERF_FORMAT_GROUP
372 433
434
373def perf_event_open(attr, pid, cpu, group_fd, flags): 435def perf_event_open(attr, pid, cpu, group_fd, flags):
374 """Wrapper for the sys_perf_evt_open() syscall. 436 """Wrapper for the sys_perf_evt_open() syscall.
375 437
@@ -395,6 +457,7 @@ PERF_FORMAT_GROUP = 1 << 3
395PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' 457PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing'
396PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' 458PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm'
397 459
460
398class Group(object): 461class Group(object):
399 """Represents a perf event group.""" 462 """Represents a perf event group."""
400 463
@@ -427,6 +490,7 @@ class Group(object):
427 struct.unpack(read_format, 490 struct.unpack(read_format,
428 os.read(self.events[0].fd, length)))) 491 os.read(self.events[0].fd, length))))
429 492
493
430class Event(object): 494class Event(object):
431 """Represents a performance event and manages its life cycle.""" 495 """Represents a performance event and manages its life cycle."""
432 def __init__(self, name, group, trace_cpu, trace_pid, trace_point, 496 def __init__(self, name, group, trace_cpu, trace_pid, trace_point,
@@ -510,6 +574,7 @@ class Event(object):
510 """Resets the count of the trace event in the kernel.""" 574 """Resets the count of the trace event in the kernel."""
511 fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) 575 fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0)
512 576
577
513class TracepointProvider(object): 578class TracepointProvider(object):
514 """Data provider for the stats class. 579 """Data provider for the stats class.
515 580
@@ -551,6 +616,7 @@ class TracepointProvider(object):
551 def setup_traces(self): 616 def setup_traces(self):
552 """Creates all event and group objects needed to be able to retrieve 617 """Creates all event and group objects needed to be able to retrieve
553 data.""" 618 data."""
619 fields = self.get_available_fields()
554 if self._pid > 0: 620 if self._pid > 0:
555 # Fetch list of all threads of the monitored pid, as qemu 621 # Fetch list of all threads of the monitored pid, as qemu
556 # starts a thread for each vcpu. 622 # starts a thread for each vcpu.
@@ -561,7 +627,7 @@ class TracepointProvider(object):
561 627
562 # The constant is needed as a buffer for python libs, std 628 # The constant is needed as a buffer for python libs, std
563 # streams and other files that the script opens. 629 # streams and other files that the script opens.
564 newlim = len(groupids) * len(self._fields) + 50 630 newlim = len(groupids) * len(fields) + 50
565 try: 631 try:
566 softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) 632 softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE)
567 633
@@ -577,7 +643,7 @@ class TracepointProvider(object):
577 643
578 for groupid in groupids: 644 for groupid in groupids:
579 group = Group() 645 group = Group()
580 for name in self._fields: 646 for name in fields:
581 tracepoint = name 647 tracepoint = name
582 tracefilter = None 648 tracefilter = None
583 match = re.match(r'(.*)\((.*)\)', name) 649 match = re.match(r'(.*)\((.*)\)', name)
@@ -650,13 +716,23 @@ class TracepointProvider(object):
650 ret[name] += val 716 ret[name] += val
651 return ret 717 return ret
652 718
719 def reset(self):
720 """Reset all field counters"""
721 for group in self.group_leaders:
722 for event in group.events:
723 event.reset()
724
725
653class DebugfsProvider(object): 726class DebugfsProvider(object):
654 """Provides data from the files that KVM creates in the kvm debugfs 727 """Provides data from the files that KVM creates in the kvm debugfs
655 folder.""" 728 folder."""
656 def __init__(self): 729 def __init__(self):
657 self._fields = self.get_available_fields() 730 self._fields = self.get_available_fields()
731 self._baseline = {}
658 self._pid = 0 732 self._pid = 0
659 self.do_read = True 733 self.do_read = True
734 self.paths = []
735 self.reset()
660 736
661 def get_available_fields(self): 737 def get_available_fields(self):
662 """"Returns a list of available fields. 738 """"Returns a list of available fields.
@@ -673,6 +749,7 @@ class DebugfsProvider(object):
673 @fields.setter 749 @fields.setter
674 def fields(self, fields): 750 def fields(self, fields):
675 self._fields = fields 751 self._fields = fields
752 self.reset()
676 753
677 @property 754 @property
678 def pid(self): 755 def pid(self):
@@ -690,10 +767,11 @@ class DebugfsProvider(object):
690 self.paths = filter(lambda x: "{}-".format(pid) in x, vms) 767 self.paths = filter(lambda x: "{}-".format(pid) in x, vms)
691 768
692 else: 769 else:
693 self.paths = [''] 770 self.paths = []
694 self.do_read = True 771 self.do_read = True
772 self.reset()
695 773
696 def read(self): 774 def read(self, reset=0):
697 """Returns a dict with format:'file name / field -> current value'.""" 775 """Returns a dict with format:'file name / field -> current value'."""
698 results = {} 776 results = {}
699 777
@@ -701,10 +779,22 @@ class DebugfsProvider(object):
701 if not self.do_read: 779 if not self.do_read:
702 return results 780 return results
703 781
704 for path in self.paths: 782 paths = self.paths
783 if self._pid == 0:
784 paths = []
785 for entry in os.walk(PATH_DEBUGFS_KVM):
786 for dir in entry[1]:
787 paths.append(dir)
788 for path in paths:
705 for field in self._fields: 789 for field in self._fields:
706 results[field] = results.get(field, 0) \ 790 value = self.read_field(field, path)
707 + self.read_field(field, path) 791 key = path + field
792 if reset:
793 self._baseline[key] = value
794 if self._baseline.get(key, -1) == -1:
795 self._baseline[key] = value
796 results[field] = (results.get(field, 0) + value -
797 self._baseline.get(key, 0))
708 798
709 return results 799 return results
710 800
@@ -718,6 +808,12 @@ class DebugfsProvider(object):
718 except IOError: 808 except IOError:
719 return 0 809 return 0
720 810
811 def reset(self):
812 """Reset field counters"""
813 self._baseline = {}
814 self.read(1)
815
816
721class Stats(object): 817class Stats(object):
722 """Manages the data providers and the data they provide. 818 """Manages the data providers and the data they provide.
723 819
@@ -753,14 +849,20 @@ class Stats(object):
753 for provider in self.providers: 849 for provider in self.providers:
754 provider.pid = self._pid_filter 850 provider.pid = self._pid_filter
755 851
852 def reset(self):
853 self.values = {}
854 for provider in self.providers:
855 provider.reset()
856
756 @property 857 @property
757 def fields_filter(self): 858 def fields_filter(self):
758 return self._fields_filter 859 return self._fields_filter
759 860
760 @fields_filter.setter 861 @fields_filter.setter
761 def fields_filter(self, fields_filter): 862 def fields_filter(self, fields_filter):
762 self._fields_filter = fields_filter 863 if fields_filter != self._fields_filter:
763 self.update_provider_filters() 864 self._fields_filter = fields_filter
865 self.update_provider_filters()
764 866
765 @property 867 @property
766 def pid_filter(self): 868 def pid_filter(self):
@@ -768,9 +870,10 @@ class Stats(object):
768 870
769 @pid_filter.setter 871 @pid_filter.setter
770 def pid_filter(self, pid): 872 def pid_filter(self, pid):
771 self._pid_filter = pid 873 if pid != self._pid_filter:
772 self.values = {} 874 self._pid_filter = pid
773 self.update_provider_pid() 875 self.values = {}
876 self.update_provider_pid()
774 877
775 def get(self): 878 def get(self):
776 """Returns a dict with field -> (value, delta to last value) of all 879 """Returns a dict with field -> (value, delta to last value) of all
@@ -778,23 +881,26 @@ class Stats(object):
778 for provider in self.providers: 881 for provider in self.providers:
779 new = provider.read() 882 new = provider.read()
780 for key in provider.fields: 883 for key in provider.fields:
781 oldval = self.values.get(key, (0, 0)) 884 oldval = self.values.get(key, (0, 0))[0]
782 newval = new.get(key, 0) 885 newval = new.get(key, 0)
783 newdelta = None 886 newdelta = newval - oldval
784 if oldval is not None:
785 newdelta = newval - oldval[0]
786 self.values[key] = (newval, newdelta) 887 self.values[key] = (newval, newdelta)
787 return self.values 888 return self.values
788 889
789LABEL_WIDTH = 40 890LABEL_WIDTH = 40
790NUMBER_WIDTH = 10 891NUMBER_WIDTH = 10
892DELAY_INITIAL = 0.25
893DELAY_REGULAR = 3.0
894MAX_GUEST_NAME_LEN = 48
895MAX_REGEX_LEN = 44
896DEFAULT_REGEX = r'^[^\(]*$'
897
791 898
792class Tui(object): 899class Tui(object):
793 """Instruments curses to draw a nice text ui.""" 900 """Instruments curses to draw a nice text ui."""
794 def __init__(self, stats): 901 def __init__(self, stats):
795 self.stats = stats 902 self.stats = stats
796 self.screen = None 903 self.screen = None
797 self.drilldown = False
798 self.update_drilldown() 904 self.update_drilldown()
799 905
800 def __enter__(self): 906 def __enter__(self):
@@ -809,7 +915,14 @@ class Tui(object):
809 # return from C start_color() is ignorable. 915 # return from C start_color() is ignorable.
810 try: 916 try:
811 curses.start_color() 917 curses.start_color()
812 except: 918 except curses.error:
919 pass
920
921 # Hide cursor in extra statement as some monochrome terminals
922 # might support hiding but not colors.
923 try:
924 curses.curs_set(0)
925 except curses.error:
813 pass 926 pass
814 927
815 curses.use_default_colors() 928 curses.use_default_colors()
@@ -827,36 +940,60 @@ class Tui(object):
827 def update_drilldown(self): 940 def update_drilldown(self):
828 """Sets or removes a filter that only allows fields without braces.""" 941 """Sets or removes a filter that only allows fields without braces."""
829 if not self.stats.fields_filter: 942 if not self.stats.fields_filter:
830 self.stats.fields_filter = r'^[^\(]*$' 943 self.stats.fields_filter = DEFAULT_REGEX
831 944
832 elif self.stats.fields_filter == r'^[^\(]*$': 945 elif self.stats.fields_filter == DEFAULT_REGEX:
833 self.stats.fields_filter = None 946 self.stats.fields_filter = None
834 947
835 def update_pid(self, pid): 948 def update_pid(self, pid):
836 """Propagates pid selection to stats object.""" 949 """Propagates pid selection to stats object."""
837 self.stats.pid_filter = pid 950 self.stats.pid_filter = pid
838 951
839 def refresh(self, sleeptime): 952 def refresh_header(self, pid=None):
840 """Refreshes on-screen data.""" 953 """Refreshes the header."""
954 if pid is None:
955 pid = self.stats.pid_filter
841 self.screen.erase() 956 self.screen.erase()
842 if self.stats.pid_filter > 0: 957 gname = get_gname_from_pid(pid)
843 self.screen.addstr(0, 0, 'kvm statistics - pid {0}' 958 if gname:
844 .format(self.stats.pid_filter), 959 gname = ('({})'.format(gname[:MAX_GUEST_NAME_LEN] + '...'
845 curses.A_BOLD) 960 if len(gname) > MAX_GUEST_NAME_LEN
961 else gname))
962 if pid > 0:
963 self.screen.addstr(0, 0, 'kvm statistics - pid {0} {1}'
964 .format(pid, gname), curses.A_BOLD)
846 else: 965 else:
847 self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) 966 self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD)
967 if self.stats.fields_filter and self.stats.fields_filter \
968 != DEFAULT_REGEX:
969 regex = self.stats.fields_filter
970 if len(regex) > MAX_REGEX_LEN:
971 regex = regex[:MAX_REGEX_LEN] + '...'
972 self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex))
848 self.screen.addstr(2, 1, 'Event') 973 self.screen.addstr(2, 1, 'Event')
849 self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - 974 self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH -
850 len('Total'), 'Total') 975 len('Total'), 'Total')
851 self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - 976 self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 -
977 len('%Total'), '%Total')
978 self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 + 8 -
852 len('Current'), 'Current') 979 len('Current'), 'Current')
980 self.screen.addstr(4, 1, 'Collecting data...')
981 self.screen.refresh()
982
983 def refresh_body(self, sleeptime):
853 row = 3 984 row = 3
985 self.screen.move(row, 0)
986 self.screen.clrtobot()
854 stats = self.stats.get() 987 stats = self.stats.get()
988
855 def sortkey(x): 989 def sortkey(x):
856 if stats[x][1]: 990 if stats[x][1]:
857 return (-stats[x][1], -stats[x][0]) 991 return (-stats[x][1], -stats[x][0])
858 else: 992 else:
859 return (0, -stats[x][0]) 993 return (0, -stats[x][0])
994 total = 0.
995 for val in stats.values():
996 total += val[0]
860 for key in sorted(stats.keys(), key=sortkey): 997 for key in sorted(stats.keys(), key=sortkey):
861 998
862 if row >= self.screen.getmaxyx()[0]: 999 if row >= self.screen.getmaxyx()[0]:
@@ -869,6 +1006,8 @@ class Tui(object):
869 col += LABEL_WIDTH 1006 col += LABEL_WIDTH
870 self.screen.addstr(row, col, '%10d' % (values[0],)) 1007 self.screen.addstr(row, col, '%10d' % (values[0],))
871 col += NUMBER_WIDTH 1008 col += NUMBER_WIDTH
1009 self.screen.addstr(row, col, '%7.1f' % (values[0] * 100 / total,))
1010 col += 7
872 if values[1] is not None: 1011 if values[1] is not None:
873 self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) 1012 self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
874 row += 1 1013 row += 1
@@ -893,20 +1032,24 @@ class Tui(object):
893 regex = self.screen.getstr() 1032 regex = self.screen.getstr()
894 curses.noecho() 1033 curses.noecho()
895 if len(regex) == 0: 1034 if len(regex) == 0:
1035 self.stats.fields_filter = DEFAULT_REGEX
1036 self.refresh_header()
896 return 1037 return
897 try: 1038 try:
898 re.compile(regex) 1039 re.compile(regex)
899 self.stats.fields_filter = regex 1040 self.stats.fields_filter = regex
1041 self.refresh_header()
900 return 1042 return
901 except re.error: 1043 except re.error:
902 continue 1044 continue
903 1045
904 def show_vm_selection(self): 1046 def show_vm_selection_by_pid(self):
905 """Draws PID selection mask. 1047 """Draws PID selection mask.
906 1048
907 Asks for a pid until a valid pid or 0 has been entered. 1049 Asks for a pid until a valid pid or 0 has been entered.
908 1050
909 """ 1051 """
1052 msg = ''
910 while True: 1053 while True:
911 self.screen.erase() 1054 self.screen.erase()
912 self.screen.addstr(0, 0, 1055 self.screen.addstr(0, 0,
@@ -915,6 +1058,7 @@ class Tui(object):
915 self.screen.addstr(1, 0, 1058 self.screen.addstr(1, 0,
916 'This might limit the shown data to the trace ' 1059 'This might limit the shown data to the trace '
917 'statistics.') 1060 'statistics.')
1061 self.screen.addstr(5, 0, msg)
918 1062
919 curses.echo() 1063 curses.echo()
920 self.screen.addstr(3, 0, "Pid [0 or pid]: ") 1064 self.screen.addstr(3, 0, "Pid [0 or pid]: ")
@@ -922,60 +1066,128 @@ class Tui(object):
922 curses.noecho() 1066 curses.noecho()
923 1067
924 try: 1068 try:
925 pid = int(pid) 1069 if len(pid) > 0:
926 1070 pid = int(pid)
927 if pid == 0: 1071 if pid != 0 and not os.path.isdir(os.path.join('/proc/',
928 self.update_pid(pid) 1072 str(pid))):
929 break 1073 msg = '"' + str(pid) + '": Not a running process'
930 else:
931 if not os.path.isdir(os.path.join('/proc/', str(pid))):
932 continue 1074 continue
933 else: 1075 else:
934 self.update_pid(pid) 1076 pid = 0
935 break 1077 self.refresh_header(pid)
1078 self.update_pid(pid)
1079 break
936 1080
937 except ValueError: 1081 except ValueError:
1082 msg = '"' + str(pid) + '": Not a valid pid'
938 continue 1083 continue
939 1084
1085 def show_vm_selection_by_guest_name(self):
1086 """Draws guest selection mask.
1087
1088 Asks for a guest name until a valid guest name or '' is entered.
1089
1090 """
1091 msg = ''
1092 while True:
1093 self.screen.erase()
1094 self.screen.addstr(0, 0,
1095 'Show statistics for specific guest.',
1096 curses.A_BOLD)
1097 self.screen.addstr(1, 0,
1098 'This might limit the shown data to the trace '
1099 'statistics.')
1100 self.screen.addstr(5, 0, msg)
1101 curses.echo()
1102 self.screen.addstr(3, 0, "Guest [ENTER or guest]: ")
1103 gname = self.screen.getstr()
1104 curses.noecho()
1105
1106 if not gname:
1107 self.refresh_header(0)
1108 self.update_pid(0)
1109 break
1110 else:
1111 pids = []
1112 try:
1113 pids = get_pid_from_gname(gname)
1114 except:
1115 msg = '"' + gname + '": Internal error while searching, ' \
1116 'use pid filter instead'
1117 continue
1118 if len(pids) == 0:
1119 msg = '"' + gname + '": Not an active guest'
1120 continue
1121 if len(pids) > 1:
1122 msg = '"' + gname + '": Multiple matches found, use pid ' \
1123 'filter instead'
1124 continue
1125 self.refresh_header(pids[0])
1126 self.update_pid(pids[0])
1127 break
1128
940 def show_stats(self): 1129 def show_stats(self):
941 """Refreshes the screen and processes user input.""" 1130 """Refreshes the screen and processes user input."""
942 sleeptime = 0.25 1131 sleeptime = DELAY_INITIAL
1132 self.refresh_header()
943 while True: 1133 while True:
944 self.refresh(sleeptime) 1134 self.refresh_body(sleeptime)
945 curses.halfdelay(int(sleeptime * 10)) 1135 curses.halfdelay(int(sleeptime * 10))
946 sleeptime = 3 1136 sleeptime = DELAY_REGULAR
947 try: 1137 try:
948 char = self.screen.getkey() 1138 char = self.screen.getkey()
949 if char == 'x': 1139 if char == 'x':
950 self.drilldown = not self.drilldown 1140 self.refresh_header()
951 self.update_drilldown() 1141 self.update_drilldown()
1142 sleeptime = DELAY_INITIAL
952 if char == 'q': 1143 if char == 'q':
953 break 1144 break
1145 if char == 'c':
1146 self.stats.fields_filter = DEFAULT_REGEX
1147 self.refresh_header(0)
1148 self.update_pid(0)
1149 sleeptime = DELAY_INITIAL
954 if char == 'f': 1150 if char == 'f':
955 self.show_filter_selection() 1151 self.show_filter_selection()
1152 sleeptime = DELAY_INITIAL
1153 if char == 'g':
1154 self.show_vm_selection_by_guest_name()
1155 sleeptime = DELAY_INITIAL
956 if char == 'p': 1156 if char == 'p':
957 self.show_vm_selection() 1157 self.show_vm_selection_by_pid()
1158 sleeptime = DELAY_INITIAL
1159 if char == 'r':
1160 self.refresh_header()
1161 self.stats.reset()
1162 sleeptime = DELAY_INITIAL
958 except KeyboardInterrupt: 1163 except KeyboardInterrupt:
959 break 1164 break
960 except curses.error: 1165 except curses.error:
961 continue 1166 continue
962 1167
1168
963def batch(stats): 1169def batch(stats):
964 """Prints statistics in a key, value format.""" 1170 """Prints statistics in a key, value format."""
965 s = stats.get() 1171 try:
966 time.sleep(1) 1172 s = stats.get()
967 s = stats.get() 1173 time.sleep(1)
968 for key in sorted(s.keys()): 1174 s = stats.get()
969 values = s[key] 1175 for key in sorted(s.keys()):
970 print '%-42s%10d%10d' % (key, values[0], values[1]) 1176 values = s[key]
1177 print '%-42s%10d%10d' % (key, values[0], values[1])
1178 except KeyboardInterrupt:
1179 pass
1180
971 1181
972def log(stats): 1182def log(stats):
973 """Prints statistics as reiterating key block, multiple value blocks.""" 1183 """Prints statistics as reiterating key block, multiple value blocks."""
974 keys = sorted(stats.get().iterkeys()) 1184 keys = sorted(stats.get().iterkeys())
1185
975 def banner(): 1186 def banner():
976 for k in keys: 1187 for k in keys:
977 print '%s' % k, 1188 print '%s' % k,
978 print 1189 print
1190
979 def statline(): 1191 def statline():
980 s = stats.get() 1192 s = stats.get()
981 for k in keys: 1193 for k in keys:
@@ -984,11 +1196,15 @@ def log(stats):
984 line = 0 1196 line = 0
985 banner_repeat = 20 1197 banner_repeat = 20
986 while True: 1198 while True:
987 time.sleep(1) 1199 try:
988 if line % banner_repeat == 0: 1200 time.sleep(1)
989 banner() 1201 if line % banner_repeat == 0:
990 statline() 1202 banner()
991 line += 1 1203 statline()
1204 line += 1
1205 except KeyboardInterrupt:
1206 break
1207
992 1208
993def get_options(): 1209def get_options():
994 """Returns processed program arguments.""" 1210 """Returns processed program arguments."""
@@ -1009,6 +1225,16 @@ Requirements:
1009 CAP_SYS_ADMIN and perf events are used. 1225 CAP_SYS_ADMIN and perf events are used.
1010- CAP_SYS_RESOURCE if the hard limit is not high enough to allow 1226- CAP_SYS_RESOURCE if the hard limit is not high enough to allow
1011 the large number of files that are possibly opened. 1227 the large number of files that are possibly opened.
1228
1229Interactive Commands:
1230 c clear filter
1231 f filter by regular expression
1232 g filter by guest name
1233 p filter by PID
1234 q quit
1235 x toggle reporting of stats for individual child trace events
1236 r reset stats
1237Press any other key to refresh statistics immediately.
1012""" 1238"""
1013 1239
1014 class PlainHelpFormatter(optparse.IndentedHelpFormatter): 1240 class PlainHelpFormatter(optparse.IndentedHelpFormatter):
@@ -1018,6 +1244,22 @@ Requirements:
1018 else: 1244 else:
1019 return "" 1245 return ""
1020 1246
1247 def cb_guest_to_pid(option, opt, val, parser):
1248 try:
1249 pids = get_pid_from_gname(val)
1250 except:
1251 raise optparse.OptionValueError('Error while searching for guest '
1252 '"{}", use "-p" to specify a pid '
1253 'instead'.format(val))
1254 if len(pids) == 0:
1255 raise optparse.OptionValueError('No guest by the name "{}" '
1256 'found'.format(val))
1257 if len(pids) > 1:
1258 raise optparse.OptionValueError('Multiple processes found (pids: '
1259 '{}) - use "-p" to specify a pid '
1260 'instead'.format(" ".join(pids)))
1261 parser.values.pid = pids[0]
1262
1021 optparser = optparse.OptionParser(description=description_text, 1263 optparser = optparse.OptionParser(description=description_text,
1022 formatter=PlainHelpFormatter()) 1264 formatter=PlainHelpFormatter())
1023 optparser.add_option('-1', '--once', '--batch', 1265 optparser.add_option('-1', '--once', '--batch',
@@ -1051,15 +1293,24 @@ Requirements:
1051 help='fields to display (regex)', 1293 help='fields to display (regex)',
1052 ) 1294 )
1053 optparser.add_option('-p', '--pid', 1295 optparser.add_option('-p', '--pid',
1054 action='store', 1296 action='store',
1055 default=0, 1297 default=0,
1056 type=int, 1298 type='int',
1057 dest='pid', 1299 dest='pid',
1058 help='restrict statistics to pid', 1300 help='restrict statistics to pid',
1059 ) 1301 )
1302 optparser.add_option('-g', '--guest',
1303 action='callback',
1304 type='string',
1305 dest='pid',
1306 metavar='GUEST',
1307 help='restrict statistics to guest by name',
1308 callback=cb_guest_to_pid,
1309 )
1060 (options, _) = optparser.parse_args(sys.argv) 1310 (options, _) = optparser.parse_args(sys.argv)
1061 return options 1311 return options
1062 1312
1313
1063def get_providers(options): 1314def get_providers(options):
1064 """Returns a list of data providers depending on the passed options.""" 1315 """Returns a list of data providers depending on the passed options."""
1065 providers = [] 1316 providers = []
@@ -1073,6 +1324,7 @@ def get_providers(options):
1073 1324
1074 return providers 1325 return providers
1075 1326
1327
1076def check_access(options): 1328def check_access(options):
1077 """Exits if the current user can't access all needed directories.""" 1329 """Exits if the current user can't access all needed directories."""
1078 if not os.path.exists('/sys/kernel/debug'): 1330 if not os.path.exists('/sys/kernel/debug'):
@@ -1086,8 +1338,8 @@ def check_access(options):
1086 "Also ensure, that the kvm modules are loaded.\n") 1338 "Also ensure, that the kvm modules are loaded.\n")
1087 sys.exit(1) 1339 sys.exit(1)
1088 1340
1089 if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints 1341 if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints or
1090 or not options.debugfs): 1342 not options.debugfs):
1091 sys.stderr.write("Please enable CONFIG_TRACING in your kernel " 1343 sys.stderr.write("Please enable CONFIG_TRACING in your kernel "
1092 "when using the option -t (default).\n" 1344 "when using the option -t (default).\n"
1093 "If it is enabled, make {0} readable by the " 1345 "If it is enabled, make {0} readable by the "
@@ -1098,10 +1350,11 @@ def check_access(options):
1098 1350
1099 sys.stderr.write("Falling back to debugfs statistics!\n") 1351 sys.stderr.write("Falling back to debugfs statistics!\n")
1100 options.debugfs = True 1352 options.debugfs = True
1101 sleep(5) 1353 time.sleep(5)
1102 1354
1103 return options 1355 return options
1104 1356
1357
1105def main(): 1358def main():
1106 options = get_options() 1359 options = get_options()
1107 options = check_access(options) 1360 options = check_access(options)
diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt
index b92a153d7115..109431bdc63c 100644
--- a/tools/kvm/kvm_stat/kvm_stat.txt
+++ b/tools/kvm/kvm_stat/kvm_stat.txt
@@ -18,11 +18,33 @@ state transitions such as guest mode entry and exit.
18This tool is useful for observing guest behavior from the host perspective. 18This tool is useful for observing guest behavior from the host perspective.
19Often conclusions about performance or buggy behavior can be drawn from the 19Often conclusions about performance or buggy behavior can be drawn from the
20output. 20output.
21While running in regular mode, use any of the keys listed in section
22'Interactive Commands' below.
23Use batch and logging modes for scripting purposes.
21 24
22The set of KVM kernel module trace events may be specific to the kernel version 25The set of KVM kernel module trace events may be specific to the kernel version
23or architecture. It is best to check the KVM kernel module source code for the 26or architecture. It is best to check the KVM kernel module source code for the
24meaning of events. 27meaning of events.
25 28
29INTERACTIVE COMMANDS
30--------------------
31[horizontal]
32*c*:: clear filter
33
34*f*:: filter by regular expression
35
36*g*:: filter by guest name
37
38*p*:: filter by PID
39
40*q*:: quit
41
42*r*:: reset stats
43
44*x*:: toggle reporting of stats for child trace events
45
46Press any other key to refresh statistics immediately.
47
26OPTIONS 48OPTIONS
27------- 49-------
28-1:: 50-1::
@@ -46,6 +68,10 @@ OPTIONS
46--pid=<pid>:: 68--pid=<pid>::
47 limit statistics to one virtual machine (pid) 69 limit statistics to one virtual machine (pid)
48 70
71-g<guest>::
72--guest=<guest_name>::
73 limit statistics to one virtual machine (guest name)
74
49-f<fields>:: 75-f<fields>::
50--fields=<fields>:: 76--fields=<fields>::
51 fields to display (regex) 77 fields to display (regex)
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
index 5d19fdf80292..897cd6f3f687 100644
--- a/tools/lguest/lguest.c
+++ b/tools/lguest/lguest.c
@@ -3339,7 +3339,7 @@ int main(int argc, char *argv[])
3339 * simple, single region. 3339 * simple, single region.
3340 */ 3340 */
3341 boot->e820_entries = 1; 3341 boot->e820_entries = 1;
3342 boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM }); 3342 boot->e820_table[0] = ((struct e820_entry) { 0, mem, E820_TYPE_RAM });
3343 /* 3343 /*
3344 * The boot header contains a command line pointer: we put the command 3344 * The boot header contains a command line pointer: we put the command
3345 * line after the boot header. 3345 * line after the boot header.
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c
index 4b6bfc43cccf..809c7721cd24 100644
--- a/tools/lib/api/fs/fs.c
+++ b/tools/lib/api/fs/fs.c
@@ -439,6 +439,35 @@ int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
439 return filename__read_str(path, buf, sizep); 439 return filename__read_str(path, buf, sizep);
440} 440}
441 441
442int sysfs__read_bool(const char *entry, bool *value)
443{
444 char *buf;
445 size_t size;
446 int ret;
447
448 ret = sysfs__read_str(entry, &buf, &size);
449 if (ret < 0)
450 return ret;
451
452 switch (buf[0]) {
453 case '1':
454 case 'y':
455 case 'Y':
456 *value = true;
457 break;
458 case '0':
459 case 'n':
460 case 'N':
461 *value = false;
462 break;
463 default:
464 ret = -1;
465 }
466
467 free(buf);
468
469 return ret;
470}
442int sysctl__read_int(const char *sysctl, int *value) 471int sysctl__read_int(const char *sysctl, int *value)
443{ 472{
444 char path[PATH_MAX]; 473 char path[PATH_MAX];
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h
index 6b332dc74498..956c21127d1e 100644
--- a/tools/lib/api/fs/fs.h
+++ b/tools/lib/api/fs/fs.h
@@ -37,4 +37,5 @@ int sysctl__read_int(const char *sysctl, int *value);
37int sysfs__read_int(const char *entry, int *value); 37int sysfs__read_int(const char *entry, int *value);
38int sysfs__read_ull(const char *entry, unsigned long long *value); 38int sysfs__read_ull(const char *entry, unsigned long long *value);
39int sysfs__read_str(const char *entry, char **buf, size_t *sizep); 39int sysfs__read_str(const char *entry, char **buf, size_t *sizep);
40int sysfs__read_bool(const char *entry, bool *value);
40#endif /* __API_FS__ */ 41#endif /* __API_FS__ */
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 207c2eeddab0..6e178987af8e 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -37,6 +37,8 @@
37# define __NR_bpf 321 37# define __NR_bpf 321
38# elif defined(__aarch64__) 38# elif defined(__aarch64__)
39# define __NR_bpf 280 39# define __NR_bpf 280
40# elif defined(__sparc__)
41# define __NR_bpf 349
40# else 42# else
41# error __NR_bpf not defined. libbpf does not support your arch. 43# error __NR_bpf not defined. libbpf does not support your arch.
42# endif 44# endif
@@ -69,6 +71,23 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size,
69 return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); 71 return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
70} 72}
71 73
74int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size,
75 int inner_map_fd, int max_entries, __u32 map_flags)
76{
77 union bpf_attr attr;
78
79 memset(&attr, '\0', sizeof(attr));
80
81 attr.map_type = map_type;
82 attr.key_size = key_size;
83 attr.value_size = 4;
84 attr.inner_map_fd = inner_map_fd;
85 attr.max_entries = max_entries;
86 attr.map_flags = map_flags;
87
88 return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
89}
90
72int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 91int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
73 size_t insns_cnt, const char *license, 92 size_t insns_cnt, const char *license,
74 __u32 kern_version, char *log_buf, size_t log_buf_sz) 93 __u32 kern_version, char *log_buf, size_t log_buf_sz)
@@ -98,6 +117,28 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
98 return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 117 return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
99} 118}
100 119
120int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
121 size_t insns_cnt, int strict_alignment,
122 const char *license, __u32 kern_version,
123 char *log_buf, size_t log_buf_sz)
124{
125 union bpf_attr attr;
126
127 bzero(&attr, sizeof(attr));
128 attr.prog_type = type;
129 attr.insn_cnt = (__u32)insns_cnt;
130 attr.insns = ptr_to_u64(insns);
131 attr.license = ptr_to_u64(license);
132 attr.log_buf = ptr_to_u64(log_buf);
133 attr.log_size = log_buf_sz;
134 attr.log_level = 2;
135 log_buf[0] = 0;
136 attr.kern_version = kern_version;
137 attr.prog_flags = strict_alignment ? BPF_F_STRICT_ALIGNMENT : 0;
138
139 return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
140}
141
101int bpf_map_update_elem(int fd, const void *key, const void *value, 142int bpf_map_update_elem(int fd, const void *key, const void *value,
102 __u64 flags) 143 __u64 flags)
103{ 144{
@@ -192,3 +233,27 @@ int bpf_prog_detach(int target_fd, enum bpf_attach_type type)
192 233
193 return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); 234 return sys_bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
194} 235}
236
237int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
238 void *data_out, __u32 *size_out, __u32 *retval,
239 __u32 *duration)
240{
241 union bpf_attr attr;
242 int ret;
243
244 bzero(&attr, sizeof(attr));
245 attr.test.prog_fd = prog_fd;
246 attr.test.data_in = ptr_to_u64(data);
247 attr.test.data_out = ptr_to_u64(data_out);
248 attr.test.data_size_in = size;
249 attr.test.repeat = repeat;
250
251 ret = sys_bpf(BPF_PROG_TEST_RUN, &attr, sizeof(attr));
252 if (size_out)
253 *size_out = attr.test.data_size_out;
254 if (retval)
255 *retval = attr.test.retval;
256 if (duration)
257 *duration = attr.test.duration;
258 return ret;
259}
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 09c3dcac0496..972bd8333eb7 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -26,6 +26,8 @@
26 26
27int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, 27int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
28 int max_entries, __u32 map_flags); 28 int max_entries, __u32 map_flags);
29int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size,
30 int inner_map_fd, int max_entries, __u32 map_flags);
29 31
30/* Recommend log buffer size */ 32/* Recommend log buffer size */
31#define BPF_LOG_BUF_SIZE 65536 33#define BPF_LOG_BUF_SIZE 65536
@@ -33,6 +35,10 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
33 size_t insns_cnt, const char *license, 35 size_t insns_cnt, const char *license,
34 __u32 kern_version, char *log_buf, 36 __u32 kern_version, char *log_buf,
35 size_t log_buf_sz); 37 size_t log_buf_sz);
38int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
39 size_t insns_cnt, int strict_alignment,
40 const char *license, __u32 kern_version,
41 char *log_buf, size_t log_buf_sz);
36 42
37int bpf_map_update_elem(int fd, const void *key, const void *value, 43int bpf_map_update_elem(int fd, const void *key, const void *value,
38 __u64 flags); 44 __u64 flags);
@@ -45,6 +51,8 @@ int bpf_obj_get(const char *pathname);
45int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type, 51int bpf_prog_attach(int prog_fd, int attachable_fd, enum bpf_attach_type type,
46 unsigned int flags); 52 unsigned int flags);
47int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type); 53int bpf_prog_detach(int attachable_fd, enum bpf_attach_type type);
48 54int bpf_prog_test_run(int prog_fd, int repeat, void *data, __u32 size,
55 void *data_out, __u32 *size_out, __u32 *retval,
56 __u32 *duration);
49 57
50#endif 58#endif
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index ac6eb863b2a4..1a2c07eb7795 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1618,8 +1618,7 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n)
1618 return fd; 1618 return fd;
1619} 1619}
1620 1620
1621static void bpf_program__set_type(struct bpf_program *prog, 1621void bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type)
1622 enum bpf_prog_type type)
1623{ 1622{
1624 prog->type = type; 1623 prog->type = type;
1625} 1624}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index b30394f9947a..32c7252f734e 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -25,6 +25,7 @@
25#include <stdint.h> 25#include <stdint.h>
26#include <stdbool.h> 26#include <stdbool.h>
27#include <sys/types.h> // for size_t 27#include <sys/types.h> // for size_t
28#include <linux/bpf.h>
28 29
29enum libbpf_errno { 30enum libbpf_errno {
30 __LIBBPF_ERRNO__START = 4000, 31 __LIBBPF_ERRNO__START = 4000,
@@ -185,6 +186,7 @@ int bpf_program__set_sched_cls(struct bpf_program *prog);
185int bpf_program__set_sched_act(struct bpf_program *prog); 186int bpf_program__set_sched_act(struct bpf_program *prog);
186int bpf_program__set_xdp(struct bpf_program *prog); 187int bpf_program__set_xdp(struct bpf_program *prog);
187int bpf_program__set_perf_event(struct bpf_program *prog); 188int bpf_program__set_perf_event(struct bpf_program *prog);
189void bpf_program__set_type(struct bpf_program *prog, enum bpf_prog_type type);
188 190
189bool bpf_program__is_socket_filter(struct bpf_program *prog); 191bool bpf_program__is_socket_filter(struct bpf_program *prog);
190bool bpf_program__is_tracepoint(struct bpf_program *prog); 192bool bpf_program__is_tracepoint(struct bpf_program *prog);
diff --git a/tools/lib/string.c b/tools/lib/string.c
index bd239bc1d557..8e678af1c6ee 100644
--- a/tools/lib/string.c
+++ b/tools/lib/string.c
@@ -87,3 +87,12 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size)
87 } 87 }
88 return ret; 88 return ret;
89} 89}
90
91int prefixcmp(const char *str, const char *prefix)
92{
93 for (; ; str++, prefix++)
94 if (!*prefix)
95 return 0;
96 else if (*str != *prefix)
97 return (unsigned char)*prefix - (unsigned char)*str;
98}
diff --git a/tools/lib/subcmd/help.c b/tools/lib/subcmd/help.c
index e228c3cb3716..ba970a73d053 100644
--- a/tools/lib/subcmd/help.c
+++ b/tools/lib/subcmd/help.c
@@ -1,6 +1,7 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include <string.h> 3#include <string.h>
4#include <linux/string.h>
4#include <termios.h> 5#include <termios.h>
5#include <sys/ioctl.h> 6#include <sys/ioctl.h>
6#include <sys/types.h> 7#include <sys/types.h>
diff --git a/tools/lib/subcmd/help.h b/tools/lib/subcmd/help.h
index e145a020780c..9bd4223dc722 100644
--- a/tools/lib/subcmd/help.h
+++ b/tools/lib/subcmd/help.h
@@ -2,6 +2,7 @@
2#define __SUBCMD_HELP_H 2#define __SUBCMD_HELP_H
3 3
4#include <sys/types.h> 4#include <sys/types.h>
5#include <stdio.h>
5 6
6struct cmdnames { 7struct cmdnames {
7 size_t alloc; 8 size_t alloc;
diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c
index 6bc24025d054..359bfa77f39c 100644
--- a/tools/lib/subcmd/parse-options.c
+++ b/tools/lib/subcmd/parse-options.c
@@ -1,4 +1,5 @@
1#include <linux/compiler.h> 1#include <linux/compiler.h>
2#include <linux/string.h>
2#include <linux/types.h> 3#include <linux/types.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <stdlib.h> 5#include <stdlib.h>
diff --git a/tools/lib/subcmd/subcmd-util.h b/tools/lib/subcmd/subcmd-util.h
index fc2e45d8aaf1..8fa5f036eff0 100644
--- a/tools/lib/subcmd/subcmd-util.h
+++ b/tools/lib/subcmd/subcmd-util.h
@@ -79,13 +79,4 @@ static inline void astrcat(char **out, const char *add)
79 free(tmp); 79 free(tmp);
80} 80}
81 81
82static inline int prefixcmp(const char *str, const char *prefix)
83{
84 for (; ; str++, prefix++)
85 if (!*prefix)
86 return 0;
87 else if (*str != *prefix)
88 return (unsigned char)*prefix - (unsigned char)*str;
89}
90
91#endif /* __SUBCMD_UTIL_H */ 82#endif /* __SUBCMD_UTIL_H */
diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c
index 5e431077fcd6..d270ac00613d 100644
--- a/tools/lib/symbol/kallsyms.c
+++ b/tools/lib/symbol/kallsyms.c
@@ -1,3 +1,4 @@
1#include <ctype.h>
1#include "symbol/kallsyms.h" 2#include "symbol/kallsyms.h"
2#include <stdio.h> 3#include <stdio.h>
3#include <stdlib.h> 4#include <stdlib.h>
diff --git a/tools/net/bpf_jit_disasm.c b/tools/net/bpf_jit_disasm.c
index 544b05a53b70..ad572e6cdbd0 100644
--- a/tools/net/bpf_jit_disasm.c
+++ b/tools/net/bpf_jit_disasm.c
@@ -229,6 +229,7 @@ static void usage(void)
229{ 229{
230 printf("Usage: bpf_jit_disasm [...]\n"); 230 printf("Usage: bpf_jit_disasm [...]\n");
231 printf(" -o Also display related opcodes (default: off).\n"); 231 printf(" -o Also display related opcodes (default: off).\n");
232 printf(" -O <file> Write binary image of code to file, don't disassemble to stdout.\n");
232 printf(" -f <file> Read last image dump from file or stdin (default: klog).\n"); 233 printf(" -f <file> Read last image dump from file or stdin (default: klog).\n");
233 printf(" -h Display this help.\n"); 234 printf(" -h Display this help.\n");
234} 235}
@@ -238,12 +239,19 @@ int main(int argc, char **argv)
238 unsigned int len, klen, opt, opcodes = 0; 239 unsigned int len, klen, opt, opcodes = 0;
239 static uint8_t image[32768]; 240 static uint8_t image[32768];
240 char *kbuff, *file = NULL; 241 char *kbuff, *file = NULL;
242 char *ofile = NULL;
243 int ofd;
244 ssize_t nr;
245 uint8_t *pos;
241 246
242 while ((opt = getopt(argc, argv, "of:")) != -1) { 247 while ((opt = getopt(argc, argv, "of:O:")) != -1) {
243 switch (opt) { 248 switch (opt) {
244 case 'o': 249 case 'o':
245 opcodes = 1; 250 opcodes = 1;
246 break; 251 break;
252 case 'O':
253 ofile = optarg;
254 break;
247 case 'f': 255 case 'f':
248 file = optarg; 256 file = optarg;
249 break; 257 break;
@@ -263,11 +271,35 @@ int main(int argc, char **argv)
263 } 271 }
264 272
265 len = get_last_jit_image(kbuff, klen, image, sizeof(image)); 273 len = get_last_jit_image(kbuff, klen, image, sizeof(image));
266 if (len > 0) 274 if (len <= 0) {
267 get_asm_insns(image, len, opcodes);
268 else
269 fprintf(stderr, "No JIT image found!\n"); 275 fprintf(stderr, "No JIT image found!\n");
276 goto done;
277 }
278 if (!ofile) {
279 get_asm_insns(image, len, opcodes);
280 goto done;
281 }
282
283 ofd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
284 if (ofd < 0) {
285 fprintf(stderr, "Could not open file %s for writing: ", ofile);
286 perror(NULL);
287 goto done;
288 }
289 pos = image;
290 do {
291 nr = write(ofd, pos, len);
292 if (nr < 0) {
293 fprintf(stderr, "Could not write data to %s: ", ofile);
294 perror(NULL);
295 goto done;
296 }
297 len -= nr;
298 pos += nr;
299 } while (len);
300 close(ofd);
270 301
302done:
271 put_log_buff(kbuff); 303 put_log_buff(kbuff);
272 return 0; 304 return 0;
273} 305}
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
index 066086dd59a8..282a60368b14 100644
--- a/tools/objtool/builtin-check.c
+++ b/tools/objtool/builtin-check.c
@@ -36,8 +36,7 @@
36#include "warn.h" 36#include "warn.h"
37 37
38#include <linux/hashtable.h> 38#include <linux/hashtable.h>
39 39#include <linux/kernel.h>
40#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
41 40
42#define STATE_FP_SAVED 0x1 41#define STATE_FP_SAVED 0x1
43#define STATE_FP_SETUP 0x2 42#define STATE_FP_SETUP 0x2
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index 46c326db4f46..ecc5b1b5d15d 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -31,11 +31,10 @@
31#include <stdlib.h> 31#include <stdlib.h>
32#include <subcmd/exec-cmd.h> 32#include <subcmd/exec-cmd.h>
33#include <subcmd/pager.h> 33#include <subcmd/pager.h>
34#include <linux/kernel.h>
34 35
35#include "builtin.h" 36#include "builtin.h"
36 37
37#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
38
39struct cmd_struct { 38struct cmd_struct {
40 const char *name; 39 const char *name;
41 int (*fn)(int, const char **); 40 int (*fn)(int, const char **);
diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c
new file mode 100644
index 000000000000..ad54a58d7dda
--- /dev/null
+++ b/tools/pci/pcitest.c
@@ -0,0 +1,186 @@
1/**
2 * Userspace PCI Endpoint Test Module
3 *
4 * Copyright (C) 2017 Texas Instruments
5 * Author: Kishon Vijay Abraham I <kishon@ti.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 of
9 * the License as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <errno.h>
21#include <fcntl.h>
22#include <stdbool.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/ioctl.h>
26#include <time.h>
27#include <unistd.h>
28
29#include <linux/pcitest.h>
30
31#define BILLION 1E9
32
33static char *result[] = { "NOT OKAY", "OKAY" };
34
35struct pci_test {
36 char *device;
37 char barnum;
38 bool legacyirq;
39 unsigned int msinum;
40 bool read;
41 bool write;
42 bool copy;
43 unsigned long size;
44};
45
46static int run_test(struct pci_test *test)
47{
48 long ret;
49 int fd;
50 struct timespec start, end;
51 double time;
52
53 fd = open(test->device, O_RDWR);
54 if (fd < 0) {
55 perror("can't open PCI Endpoint Test device");
56 return fd;
57 }
58
59 if (test->barnum >= 0 && test->barnum <= 5) {
60 ret = ioctl(fd, PCITEST_BAR, test->barnum);
61 fprintf(stdout, "BAR%d:\t\t", test->barnum);
62 if (ret < 0)
63 fprintf(stdout, "TEST FAILED\n");
64 else
65 fprintf(stdout, "%s\n", result[ret]);
66 }
67
68 if (test->legacyirq) {
69 ret = ioctl(fd, PCITEST_LEGACY_IRQ, 0);
70 fprintf(stdout, "LEGACY IRQ:\t");
71 if (ret < 0)
72 fprintf(stdout, "TEST FAILED\n");
73 else
74 fprintf(stdout, "%s\n", result[ret]);
75 }
76
77 if (test->msinum > 0 && test->msinum <= 32) {
78 ret = ioctl(fd, PCITEST_MSI, test->msinum);
79 fprintf(stdout, "MSI%d:\t\t", test->msinum);
80 if (ret < 0)
81 fprintf(stdout, "TEST FAILED\n");
82 else
83 fprintf(stdout, "%s\n", result[ret]);
84 }
85
86 if (test->write) {
87 ret = ioctl(fd, PCITEST_WRITE, test->size);
88 fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size);
89 if (ret < 0)
90 fprintf(stdout, "TEST FAILED\n");
91 else
92 fprintf(stdout, "%s\n", result[ret]);
93 }
94
95 if (test->read) {
96 ret = ioctl(fd, PCITEST_READ, test->size);
97 fprintf(stdout, "READ (%7ld bytes):\t\t", test->size);
98 if (ret < 0)
99 fprintf(stdout, "TEST FAILED\n");
100 else
101 fprintf(stdout, "%s\n", result[ret]);
102 }
103
104 if (test->copy) {
105 ret = ioctl(fd, PCITEST_COPY, test->size);
106 fprintf(stdout, "COPY (%7ld bytes):\t\t", test->size);
107 if (ret < 0)
108 fprintf(stdout, "TEST FAILED\n");
109 else
110 fprintf(stdout, "%s\n", result[ret]);
111 }
112
113 fflush(stdout);
114}
115
116int main(int argc, char **argv)
117{
118 int c;
119 struct pci_test *test;
120
121 test = calloc(1, sizeof(*test));
122 if (!test) {
123 perror("Fail to allocate memory for pci_test\n");
124 return -ENOMEM;
125 }
126
127 /* since '0' is a valid BAR number, initialize it to -1 */
128 test->barnum = -1;
129
130 /* set default size as 100KB */
131 test->size = 0x19000;
132
133 /* set default endpoint device */
134 test->device = "/dev/pci-endpoint-test.0";
135
136 while ((c = getopt(argc, argv, "D:b:m:lrwcs:")) != EOF)
137 switch (c) {
138 case 'D':
139 test->device = optarg;
140 continue;
141 case 'b':
142 test->barnum = atoi(optarg);
143 if (test->barnum < 0 || test->barnum > 5)
144 goto usage;
145 continue;
146 case 'l':
147 test->legacyirq = true;
148 continue;
149 case 'm':
150 test->msinum = atoi(optarg);
151 if (test->msinum < 1 || test->msinum > 32)
152 goto usage;
153 continue;
154 case 'r':
155 test->read = true;
156 continue;
157 case 'w':
158 test->write = true;
159 continue;
160 case 'c':
161 test->copy = true;
162 continue;
163 case 's':
164 test->size = strtoul(optarg, NULL, 0);
165 continue;
166 case '?':
167 case 'h':
168 default:
169usage:
170 fprintf(stderr,
171 "usage: %s [options]\n"
172 "Options:\n"
173 "\t-D <dev> PCI endpoint test device {default: /dev/pci-endpoint-test.0}\n"
174 "\t-b <bar num> BAR test (bar number between 0..5)\n"
175 "\t-m <msi num> MSI test (msi number between 1..32)\n"
176 "\t-r Read buffer test\n"
177 "\t-w Write buffer test\n"
178 "\t-c Copy buffer test\n"
179 "\t-s <size> Size of buffer {default: 100KB}\n",
180 argv[0]);
181 return -EINVAL;
182 }
183
184 run_test(test);
185 return 0;
186}
diff --git a/tools/pci/pcitest.sh b/tools/pci/pcitest.sh
new file mode 100644
index 000000000000..5442bbea4c22
--- /dev/null
+++ b/tools/pci/pcitest.sh
@@ -0,0 +1,56 @@
1#!/bin/sh
2
3echo "BAR tests"
4echo
5
6bar=0
7
8while [ $bar -lt 6 ]
9do
10 pcitest -b $bar
11 bar=`expr $bar + 1`
12done
13echo
14
15echo "Interrupt tests"
16echo
17
18pcitest -l
19msi=1
20
21while [ $msi -lt 33 ]
22do
23 pcitest -m $msi
24 msi=`expr $msi + 1`
25done
26echo
27
28echo "Read Tests"
29echo
30
31pcitest -r -s 1
32pcitest -r -s 1024
33pcitest -r -s 1025
34pcitest -r -s 1024000
35pcitest -r -s 1024001
36echo
37
38echo "Write Tests"
39echo
40
41pcitest -w -s 1
42pcitest -w -s 1024
43pcitest -w -s 1025
44pcitest -w -s 1024000
45pcitest -w -s 1024001
46echo
47
48echo "Copy Tests"
49echo
50
51pcitest -c -s 1
52pcitest -c -s 1024
53pcitest -c -s 1025
54pcitest -c -s 1024000
55pcitest -c -s 1024001
56echo
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 3db3db9278be..643cc4ba6872 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -31,3 +31,5 @@ config.mak.autogen
31.config-detected 31.config-detected
32util/intel-pt-decoder/inat-tables.c 32util/intel-pt-decoder/inat-tables.c
33arch/*/include/generated/ 33arch/*/include/generated/
34pmu-events/pmu-events.c
35pmu-events/jevents
diff --git a/tools/perf/Build b/tools/perf/Build
index 9b79f8d7db50..bd8eeb60533c 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -50,5 +50,6 @@ libperf-y += util/
50libperf-y += arch/ 50libperf-y += arch/
51libperf-y += ui/ 51libperf-y += ui/
52libperf-y += scripts/ 52libperf-y += scripts/
53libperf-y += trace/beauty/
53 54
54gtk-y += ui/gtk/ 55gtk-y += ui/gtk/
diff --git a/tools/perf/Documentation/perf-c2c.txt b/tools/perf/Documentation/perf-c2c.txt
index 2da07e51e119..822414235170 100644
--- a/tools/perf/Documentation/perf-c2c.txt
+++ b/tools/perf/Documentation/perf-c2c.txt
@@ -76,7 +76,7 @@ REPORT OPTIONS
76 76
77-c:: 77-c::
78--coalesce:: 78--coalesce::
79 Specify sorintg fields for single cacheline display. 79 Specify sorting fields for single cacheline display.
80 Following fields are available: tid,pid,iaddr,dso 80 Following fields are available: tid,pid,iaddr,dso
81 (see COALESCE) 81 (see COALESCE)
82 82
@@ -106,7 +106,7 @@ REPORT OPTIONS
106 106
107-d:: 107-d::
108--display:: 108--display::
109 Siwtch to HITM type (rmt, lcl) to display and sort on. Total HITMs as default. 109 Switch to HITM type (rmt, lcl) to display and sort on. Total HITMs as default.
110 110
111C2C RECORD 111C2C RECORD
112---------- 112----------
diff --git a/tools/perf/Documentation/perf-ftrace.txt b/tools/perf/Documentation/perf-ftrace.txt
index 2d96de6132a9..6e6a8b22c859 100644
--- a/tools/perf/Documentation/perf-ftrace.txt
+++ b/tools/perf/Documentation/perf-ftrace.txt
@@ -30,6 +30,24 @@ OPTIONS
30--verbose=:: 30--verbose=::
31 Verbosity level. 31 Verbosity level.
32 32
33-p::
34--pid=::
35 Trace on existing process id (comma separated list).
36
37-a::
38--all-cpus::
39 Force system-wide collection. Scripts run without a <command>
40 normally use -a by default, while scripts run with a <command>
41 normally don't - this option allows the latter to be run in
42 system-wide mode.
43
44-C::
45--cpu=::
46 Only trace for the list of CPUs provided. Multiple CPUs can
47 be provided as a comma separated list with no space like: 0,1.
48 Ranges of CPUs are specified with -: 0-2.
49 Default is to trace on all online CPUs.
50
33 51
34SEE ALSO 52SEE ALSO
35-------- 53--------
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 41857cce5e86..f709de54707b 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|event_glob] 11'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -24,6 +24,10 @@ Don't print descriptions.
24--long-desc:: 24--long-desc::
25Print longer event descriptions. 25Print longer event descriptions.
26 26
27--details::
28Print how named events are resolved internally into perf events, and also
29any extra expressions computed by perf stat.
30
27 31
28[[EVENT_MODIFIERS]] 32[[EVENT_MODIFIERS]]
29EVENT MODIFIERS 33EVENT MODIFIERS
@@ -240,6 +244,8 @@ To limit the list use:
240 244
241. 'pmu' to print the kernel supplied PMU events. 245. 'pmu' to print the kernel supplied PMU events.
242 246
247. 'sdt' to list all Statically Defined Tracepoint events.
248
243. If none of the above is matched, it will apply the supplied glob to all 249. If none of the above is matched, it will apply the supplied glob to all
244 events, printing the ones that match. 250 events, printing the ones that match.
245 251
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index b16003ec14a7..b0e9e921d534 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -225,7 +225,7 @@ OPTIONS
225 the libunwind or libdw library) should be used instead. 225 the libunwind or libdw library) should be used instead.
226 Using the "lbr" method doesn't require any compiler options. It 226 Using the "lbr" method doesn't require any compiler options. It
227 will produce call graphs from the hardware LBR registers. The 227 will produce call graphs from the hardware LBR registers. The
228 main limition is that it is only available on new Intel 228 main limitation is that it is only available on new Intel
229 platforms, such as Haswell. It can only get user call chain. It 229 platforms, such as Haswell. It can only get user call chain. It
230 doesn't work with branch stack sampling at the same time. 230 doesn't work with branch stack sampling at the same time.
231 231
@@ -347,6 +347,9 @@ Enable weightened sampling. An additional weight is recorded per sample and can
347displayed with the weight and local_weight sort keys. This currently works for TSX 347displayed with the weight and local_weight sort keys. This currently works for TSX
348abort events and some memory events in precise mode on modern Intel CPUs. 348abort events and some memory events in precise mode on modern Intel CPUs.
349 349
350--namespaces::
351Record events of type PERF_RECORD_NAMESPACES.
352
350--transaction:: 353--transaction::
351Record transaction flags for transaction related events. 354Record transaction flags for transaction related events.
352 355
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index c04cc0647c16..9fa84617181e 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -72,7 +72,8 @@ OPTIONS
72--sort=:: 72--sort=::
73 Sort histogram entries by given key(s) - multiple keys can be specified 73 Sort histogram entries by given key(s) - multiple keys can be specified
74 in CSV format. Following sort keys are available: 74 in CSV format. Following sort keys are available:
75 pid, comm, dso, symbol, parent, cpu, socket, srcline, weight, local_weight. 75 pid, comm, dso, symbol, parent, cpu, socket, srcline, weight,
76 local_weight, cgroup_id.
76 77
77 Each key has following meaning: 78 Each key has following meaning:
78 79
@@ -80,6 +81,7 @@ OPTIONS
80 - pid: command and tid of the task 81 - pid: command and tid of the task
81 - dso: name of library or module executed at the time of sample 82 - dso: name of library or module executed at the time of sample
82 - symbol: name of function executed at the time of sample 83 - symbol: name of function executed at the time of sample
84 - symbol_size: size of function executed at the time of sample
83 - parent: name of function matched to the parent regex filter. Unmatched 85 - parent: name of function matched to the parent regex filter. Unmatched
84 entries are displayed as "[other]". 86 entries are displayed as "[other]".
85 - cpu: cpu number the task ran at the time of sample 87 - cpu: cpu number the task ran at the time of sample
@@ -91,6 +93,7 @@ OPTIONS
91 - weight: Event specific weight, e.g. memory latency or transaction 93 - weight: Event specific weight, e.g. memory latency or transaction
92 abort cost. This is the global weight. 94 abort cost. This is the global weight.
93 - local_weight: Local weight version of the weight above. 95 - local_weight: Local weight version of the weight above.
96 - cgroup_id: ID derived from cgroup namespace device and inode numbers.
94 - transaction: Transaction abort flags. 97 - transaction: Transaction abort flags.
95 - overhead: Overhead percentage of sample 98 - overhead: Overhead percentage of sample
96 - overhead_sys: Overhead percentage of sample running in system mode 99 - overhead_sys: Overhead percentage of sample running in system mode
@@ -172,11 +175,14 @@ OPTIONS
172 By default, every sort keys not specified in -F will be appended 175 By default, every sort keys not specified in -F will be appended
173 automatically. 176 automatically.
174 177
178 If the keys starts with a prefix '+', then it will append the specified
179 field(s) to the default field order. For example: perf report -F +period,sample.
180
175-p:: 181-p::
176--parent=<regex>:: 182--parent=<regex>::
177 A regex filter to identify parent. The parent is a caller of this 183 A regex filter to identify parent. The parent is a caller of this
178 function and searched through the callchain, thus it requires callchain 184 function and searched through the callchain, thus it requires callchain
179 information recorded. The pattern is in the exteneded regex format and 185 information recorded. The pattern is in the extended regex format and
180 defaults to "\^sys_|^do_page_fault", see '--sort parent'. 186 defaults to "\^sys_|^do_page_fault", see '--sort parent'.
181 187
182-x:: 188-x::
@@ -201,8 +207,8 @@ OPTIONS
201-g:: 207-g::
202--call-graph=<print_type,threshold[,print_limit],order,sort_key[,branch],value>:: 208--call-graph=<print_type,threshold[,print_limit],order,sort_key[,branch],value>::
203 Display call chains using type, min percent threshold, print limit, 209 Display call chains using type, min percent threshold, print limit,
204 call order, sort key, optional branch and value. Note that ordering of 210 call order, sort key, optional branch and value. Note that ordering
205 parameters is not fixed so any parement can be given in an arbitraty order. 211 is not fixed so any parameter can be given in an arbitrary order.
206 One exception is the print_limit which should be preceded by threshold. 212 One exception is the print_limit which should be preceded by threshold.
207 213
208 print_type can be either: 214 print_type can be either:
@@ -229,6 +235,7 @@ OPTIONS
229 sort_key can be: 235 sort_key can be:
230 - function: compare on functions (default) 236 - function: compare on functions (default)
231 - address: compare on individual code addresses 237 - address: compare on individual code addresses
238 - srcline: compare on source filename and line number
232 239
233 branch can be: 240 branch can be:
234 - branch: include last branch information in callgraph when available. 241 - branch: include last branch information in callgraph when available.
@@ -424,6 +431,10 @@ include::itrace.txt[]
424--hierarchy:: 431--hierarchy::
425 Enable hierarchical output. 432 Enable hierarchical output.
426 433
434--inline::
435 If a callgraph address belongs to an inlined function, the inline stack
436 will be printed. Each entry is function name or file/line.
437
427include::callchain-overhead-calculation.txt[] 438include::callchain-overhead-calculation.txt[]
428 439
429SEE ALSO 440SEE ALSO
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index d33deddb0146..a092a2499e8f 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -132,6 +132,10 @@ OPTIONS for 'perf sched timehist'
132--migrations:: 132--migrations::
133 Show migration events. 133 Show migration events.
134 134
135-n::
136--next::
137 Show next task.
138
135-I:: 139-I::
136--idle-hist:: 140--idle-hist::
137 Show idle-related events only. 141 Show idle-related events only.
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 4ed5f239ba7d..cb0eda3925e6 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -116,7 +116,7 @@ OPTIONS
116--fields:: 116--fields::
117 Comma separated list of fields to print. Options are: 117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, 118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff,
119 srcline, period, iregs, brstack, brstacksym, flags, bpf-output, 119 srcline, period, iregs, brstack, brstacksym, flags, bpf-output, brstackinsn,
120 callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw, 120 callindent, insn, insnlen. Field list can be prepended with the type, trace, sw or hw,
121 to indicate to which event type the field list applies. 121 to indicate to which event type the field list applies.
122 e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace 122 e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace
@@ -189,15 +189,20 @@ OPTIONS
189 i.e., -F "" is not allowed. 189 i.e., -F "" is not allowed.
190 190
191 The brstack output includes branch related information with raw addresses using the 191 The brstack output includes branch related information with raw addresses using the
192 /v/v/v/v/ syntax in the following order: 192 /v/v/v/v/cycles syntax in the following order:
193 FROM: branch source instruction 193 FROM: branch source instruction
194 TO : branch target instruction 194 TO : branch target instruction
195 M/P/-: M=branch target mispredicted or branch direction was mispredicted, P=target predicted or direction predicted, -=not supported 195 M/P/-: M=branch target mispredicted or branch direction was mispredicted, P=target predicted or direction predicted, -=not supported
196 X/- : X=branch inside a transactional region, -=not in transaction region or not supported 196 X/- : X=branch inside a transactional region, -=not in transaction region or not supported
197 A/- : A=TSX abort entry, -=not aborted region or not supported 197 A/- : A=TSX abort entry, -=not aborted region or not supported
198 cycles
198 199
199 The brstacksym is identical to brstack, except that the FROM and TO addresses are printed in a symbolic form if possible. 200 The brstacksym is identical to brstack, except that the FROM and TO addresses are printed in a symbolic form if possible.
200 201
202 When brstackinsn is specified the full assembler sequences of branch sequences for each sample
203 is printed. This is the full execution path leading to the sample. This is only supported when the
204 sample was recorded with perf record -b or -j any.
205
201-k:: 206-k::
202--vmlinux=<file>:: 207--vmlinux=<file>::
203 vmlinux pathname 208 vmlinux pathname
@@ -248,6 +253,9 @@ OPTIONS
248--show-mmap-events 253--show-mmap-events
249 Display mmap related events (e.g. MMAP, MMAP2). 254 Display mmap related events (e.g. MMAP, MMAP2).
250 255
256--show-namespace-events
257 Display namespace events i.e. events of type PERF_RECORD_NAMESPACES.
258
251--show-switch-events 259--show-switch-events
252 Display context switch events i.e. events of type PERF_RECORD_SWITCH or 260 Display context switch events i.e. events of type PERF_RECORD_SWITCH or
253 PERF_RECORD_SWITCH_CPU_WIDE. 261 PERF_RECORD_SWITCH_CPU_WIDE.
@@ -299,6 +307,10 @@ include::itrace.txt[]
299 stop time is not given (i.e, time string is 'x.y,') then analysis goes 307 stop time is not given (i.e, time string is 'x.y,') then analysis goes
300 to end of file. 308 to end of file.
301 309
310--max-blocks::
311 Set the maximum number of program blocks to print with brstackasm for
312 each sample.
313
302SEE ALSO 314SEE ALSO
303-------- 315--------
304linkperf:perf-record[1], linkperf:perf-script-perl[1], 316linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index aecf2a87e7d6..bd0e4417f2be 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -94,8 +94,7 @@ to activate system-wide monitoring. Default is to count on all CPUs.
94 94
95-A:: 95-A::
96--no-aggr:: 96--no-aggr::
97Do not aggregate counts across all monitored CPUs in system-wide mode (-a). 97Do not aggregate counts across all monitored CPUs.
98This option is only valid in system-wide mode.
99 98
100-n:: 99-n::
101--null:: 100--null::
@@ -237,6 +236,9 @@ To interpret the results it is usually needed to know on which
237CPUs the workload runs on. If needed the CPUs can be forced using 236CPUs the workload runs on. If needed the CPUs can be forced using
238taskset. 237taskset.
239 238
239--no-merge::
240Do not merge results from same PMUs.
241
240EXAMPLES 242EXAMPLES
241-------- 243--------
242 244
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index afd728672b6f..c1e3288a2dfb 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -123,7 +123,8 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
123 major or all pagefaults. Default value is maj. 123 major or all pagefaults. Default value is maj.
124 124
125--syscalls:: 125--syscalls::
126 Trace system calls. This options is enabled by default. 126 Trace system calls. This options is enabled by default, disable with
127 --no-syscalls.
127 128
128--call-graph [mode,type,min[,limit],order[,key][,branch]]:: 129--call-graph [mode,type,min[,limit],order[,key][,branch]]::
129 Setup and enable call-graph (stack chain/backtrace) recording. 130 Setup and enable call-graph (stack chain/backtrace) recording.
diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
index b664b18d3991..de8b39dda7b8 100644
--- a/tools/perf/Documentation/perf.data-file-format.txt
+++ b/tools/perf/Documentation/perf.data-file-format.txt
@@ -11,8 +11,8 @@ All fields are in native-endian of the machine that generated the perf.data.
11 11
12When perf is writing to a pipe it uses a special version of the file 12When perf is writing to a pipe it uses a special version of the file
13format that does not rely on seeking to adjust data offsets. This 13format that does not rely on seeking to adjust data offsets. This
14format is not described here. The pipe version can be converted to 14format is described in "Pipe-mode data" section. The pipe data version can be
15normal perf.data with perf inject. 15augmented with additional events using perf inject.
16 16
17The file starts with a perf_header: 17The file starts with a perf_header:
18 18
@@ -270,7 +270,7 @@ When the event stream contains multiple events each event is identified
270by an ID. This can be either through the PERF_SAMPLE_ID or the 270by an ID. This can be either through the PERF_SAMPLE_ID or the
271PERF_SAMPLE_IDENTIFIER header. The PERF_SAMPLE_IDENTIFIER header is 271PERF_SAMPLE_IDENTIFIER header. The PERF_SAMPLE_IDENTIFIER header is
272at a fixed offset from the event header, which allows reliable 272at a fixed offset from the event header, which allows reliable
273parsing of the header. Relying on ID may be ambigious. 273parsing of the header. Relying on ID may be ambiguous.
274IDENTIFIER is only supported by newer Linux kernels. 274IDENTIFIER is only supported by newer Linux kernels.
275 275
276Perf record specific events: 276Perf record specific events:
@@ -288,7 +288,7 @@ struct attr_event {
288 uint64_t id[]; 288 uint64_t id[];
289}; 289};
290 290
291 PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */ 291 PERF_RECORD_HEADER_EVENT_TYPE = 65, /* deprecated */
292 292
293#define MAX_EVENT_NAME 64 293#define MAX_EVENT_NAME 64
294 294
@@ -411,6 +411,21 @@ An array bound by the perf_file_section size.
411 411
412ids points to a array of uint64_t defining the ids for event attr attr. 412ids points to a array of uint64_t defining the ids for event attr attr.
413 413
414Pipe-mode data
415
416Pipe-mode avoid seeks in the file by removing the perf_file_section and flags
417from the struct perf_header. The trimmed header is:
418
419struct perf_pipe_file_header {
420 u64 magic;
421 u64 size;
422};
423
424The information about attrs, data, and event_types is instead in the
425synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA and
426PERF_RECORD_HEADER_EVENT_TYPE that are generated by perf record in pipe-mode.
427
428
414References: 429References:
415 430
416include/uapi/linux/perf_event.h 431include/uapi/linux/perf_event.h
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
index 170b0289a7bc..db0ca3063eae 100644
--- a/tools/perf/Documentation/tips.txt
+++ b/tools/perf/Documentation/tips.txt
@@ -23,7 +23,7 @@ For memory address profiling, try: perf mem record / perf mem report
23For tracepoint events, try: perf report -s trace_fields 23For tracepoint events, try: perf report -s trace_fields
24To record callchains for each sample: perf record -g 24To record callchains for each sample: perf record -g
25To record every process run by a user: perf record -u <user> 25To record every process run by a user: perf record -u <user>
26Skip collecing build-id when recording: perf record -B 26Skip collecting build-id when recording: perf record -B
27To change sampling frequency to 100 Hz: perf record -F 100 27To change sampling frequency to 100 Hz: perf record -F 100
28See assembly instructions with percentage: perf annotate <symbol> 28See assembly instructions with percentage: perf annotate <symbol>
29If you prefer Intel style assembly, try: perf annotate -M intel 29If you prefer Intel style assembly, try: perf annotate -M intel
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 8672f835ae4e..a29da46d180f 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -12,6 +12,7 @@ tools/arch/sparc/include/asm/barrier_32.h
12tools/arch/sparc/include/asm/barrier_64.h 12tools/arch/sparc/include/asm/barrier_64.h
13tools/arch/tile/include/asm/barrier.h 13tools/arch/tile/include/asm/barrier.h
14tools/arch/x86/include/asm/barrier.h 14tools/arch/x86/include/asm/barrier.h
15tools/arch/x86/include/asm/cmpxchg.h
15tools/arch/x86/include/asm/cpufeatures.h 16tools/arch/x86/include/asm/cpufeatures.h
16tools/arch/x86/include/asm/disabled-features.h 17tools/arch/x86/include/asm/disabled-features.h
17tools/arch/x86/include/asm/required-features.h 18tools/arch/x86/include/asm/required-features.h
@@ -63,6 +64,7 @@ tools/include/linux/bitops.h
63tools/include/linux/compiler.h 64tools/include/linux/compiler.h
64tools/include/linux/compiler-gcc.h 65tools/include/linux/compiler-gcc.h
65tools/include/linux/coresight-pmu.h 66tools/include/linux/coresight-pmu.h
67tools/include/linux/bug.h
66tools/include/linux/filter.h 68tools/include/linux/filter.h
67tools/include/linux/hash.h 69tools/include/linux/hash.h
68tools/include/linux/kernel.h 70tools/include/linux/kernel.h
@@ -72,12 +74,15 @@ tools/include/uapi/asm-generic/mman-common.h
72tools/include/uapi/asm-generic/mman.h 74tools/include/uapi/asm-generic/mman.h
73tools/include/uapi/linux/bpf.h 75tools/include/uapi/linux/bpf.h
74tools/include/uapi/linux/bpf_common.h 76tools/include/uapi/linux/bpf_common.h
77tools/include/uapi/linux/fcntl.h
75tools/include/uapi/linux/hw_breakpoint.h 78tools/include/uapi/linux/hw_breakpoint.h
76tools/include/uapi/linux/mman.h 79tools/include/uapi/linux/mman.h
77tools/include/uapi/linux/perf_event.h 80tools/include/uapi/linux/perf_event.h
81tools/include/uapi/linux/stat.h
78tools/include/linux/poison.h 82tools/include/linux/poison.h
79tools/include/linux/rbtree.h 83tools/include/linux/rbtree.h
80tools/include/linux/rbtree_augmented.h 84tools/include/linux/rbtree_augmented.h
85tools/include/linux/refcount.h
81tools/include/linux/string.h 86tools/include/linux/string.h
82tools/include/linux/stringify.h 87tools/include/linux/stringify.h
83tools/include/linux/types.h 88tools/include/linux/types.h
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 27c9fbca7bd9..8354d04b392f 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -170,13 +170,20 @@ PYTHON2_CONFIG := \
170override PYTHON_CONFIG := \ 170override PYTHON_CONFIG := \
171 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG)) 171 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
172 172
173PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) 173grep-libs = $(filter -l%,$(1))
174strip-libs = $(filter-out -l%,$(1))
174 175
175PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) 176PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
176PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
177 177
178ifeq ($(CC), clang) 178ifdef PYTHON_CONFIG
179 PYTHON_EMBED_CCOPTS := $(filter-out -specs=%,$(PYTHON_EMBED_CCOPTS)) 179 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
180 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
181 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil
182 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
183 ifeq ($(CC), clang)
184 PYTHON_EMBED_CCOPTS := $(filter-out -specs=%,$(PYTHON_EMBED_CCOPTS))
185 endif
186 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
180endif 187endif
181 188
182FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) 189FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
@@ -267,6 +274,7 @@ ifdef NO_LIBELF
267 NO_LIBUNWIND := 1 274 NO_LIBUNWIND := 1
268 NO_LIBDW_DWARF_UNWIND := 1 275 NO_LIBDW_DWARF_UNWIND := 1
269 NO_LIBBPF := 1 276 NO_LIBBPF := 1
277 NO_JVMTI := 1
270else 278else
271 ifeq ($(feature-libelf), 0) 279 ifeq ($(feature-libelf), 0)
272 ifeq ($(feature-glibc), 1) 280 ifeq ($(feature-glibc), 1)
@@ -276,7 +284,7 @@ else
276 LIBC_SUPPORT := 1 284 LIBC_SUPPORT := 1
277 endif 285 endif
278 ifeq ($(LIBC_SUPPORT),1) 286 ifeq ($(LIBC_SUPPORT),1)
279 msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install libelf-dev, libelf-devel or elfutils-libelf-devel); 287 msg := $(warning No libelf found. Disables 'probe' tool, jvmti and BPF support in 'perf record'. Please install libelf-dev, libelf-devel or elfutils-libelf-devel);
280 288
281 NO_LIBELF := 1 289 NO_LIBELF := 1
282 NO_DWARF := 1 290 NO_DWARF := 1
@@ -284,6 +292,7 @@ else
284 NO_LIBUNWIND := 1 292 NO_LIBUNWIND := 1
285 NO_LIBDW_DWARF_UNWIND := 1 293 NO_LIBDW_DWARF_UNWIND := 1
286 NO_LIBBPF := 1 294 NO_LIBBPF := 1
295 NO_JVMTI := 1
287 else 296 else
288 ifneq ($(filter s% -static%,$(LDFLAGS),),) 297 ifneq ($(filter s% -static%,$(LDFLAGS),),)
289 msg := $(error No static glibc found, please install glibc-static); 298 msg := $(error No static glibc found, please install glibc-static);
@@ -317,6 +326,10 @@ ifdef NO_DWARF
317 NO_LIBDW_DWARF_UNWIND := 1 326 NO_LIBDW_DWARF_UNWIND := 1
318endif 327endif
319 328
329ifeq ($(feature-sched_getcpu), 1)
330 CFLAGS += -DHAVE_SCHED_GETCPU_SUPPORT
331endif
332
320ifndef NO_LIBELF 333ifndef NO_LIBELF
321 CFLAGS += -DHAVE_LIBELF_SUPPORT 334 CFLAGS += -DHAVE_LIBELF_SUPPORT
322 EXTLIBS += -lelf 335 EXTLIBS += -lelf
@@ -550,8 +563,6 @@ ifndef NO_GTK2
550 endif 563 endif
551endif 564endif
552 565
553grep-libs = $(filter -l%,$(1))
554strip-libs = $(filter-out -l%,$(1))
555 566
556ifdef NO_LIBPERL 567ifdef NO_LIBPERL
557 CFLAGS += -DNO_LIBPERL 568 CFLAGS += -DNO_LIBPERL
@@ -599,21 +610,9 @@ else
599 $(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev) 610 $(call disable-python,No 'python-config' tool was found: disables Python support - please install python-devel/python-dev)
600 else 611 else
601 612
602 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
603
604 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
605 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
606 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil
607 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
608 ifeq ($(CC), clang)
609 PYTHON_EMBED_CCOPTS := $(filter-out -specs=%,$(PYTHON_EMBED_CCOPTS))
610 endif
611 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
612
613 ifneq ($(feature-libpython), 1) 613 ifneq ($(feature-libpython), 1)
614 $(call disable-python,No 'Python.h' (for Python 2.x support) was found: disables Python support - please install python-devel/python-dev) 614 $(call disable-python,No 'Python.h' (for Python 2.x support) was found: disables Python support - please install python-devel/python-dev)
615 else 615 else
616
617 ifneq ($(feature-libpython-version), 1) 616 ifneq ($(feature-libpython-version), 1)
618 $(warning Python 3 is not yet supported; please set) 617 $(warning Python 3 is not yet supported; please set)
619 $(warning PYTHON and/or PYTHON_CONFIG appropriately.) 618 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index dfea6b635525..29361d9b635a 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -33,6 +33,7 @@
33#include "../../util/cs-etm.h" 33#include "../../util/cs-etm.h"
34 34
35#include <stdlib.h> 35#include <stdlib.h>
36#include <sys/stat.h>
36 37
37#define ENABLE_SINK_MAX 128 38#define ENABLE_SINK_MAX 128
38#define CS_BUS_DEVICE_PATH "/bus/coresight/devices/" 39#define CS_BUS_DEVICE_PATH "/bus/coresight/devices/"
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index 33ec5b339da8..8bb176a37990 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -9,6 +9,7 @@
9 */ 9 */
10 10
11#include <stddef.h> 11#include <stddef.h>
12#include <linux/stringify.h>
12#include <dwarf-regs.h> 13#include <dwarf-regs.h>
13 14
14struct pt_regs_dwarfnum { 15struct pt_regs_dwarfnum {
@@ -16,10 +17,9 @@ struct pt_regs_dwarfnum {
16 unsigned int dwarfnum; 17 unsigned int dwarfnum;
17}; 18};
18 19
19#define STR(s) #s
20#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} 20#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
21#define GPR_DWARFNUM_NAME(num) \ 21#define GPR_DWARFNUM_NAME(num) \
22 {.name = STR(%r##num), .dwarfnum = num} 22 {.name = __stringify(%r##num), .dwarfnum = num}
23#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} 23#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
24 24
25/* 25/*
diff --git a/tools/perf/arch/arm/util/unwind-libdw.c b/tools/perf/arch/arm/util/unwind-libdw.c
index b4176c60117a..bacfa00fca39 100644
--- a/tools/perf/arch/arm/util/unwind-libdw.c
+++ b/tools/perf/arch/arm/util/unwind-libdw.c
@@ -1,6 +1,7 @@
1#include <elfutils/libdwfl.h> 1#include <elfutils/libdwfl.h>
2#include "../../util/unwind-libdw.h" 2#include "../../util/unwind-libdw.h"
3#include "../../util/perf_regs.h" 3#include "../../util/perf_regs.h"
4#include "../../util/event.h"
4 5
5bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) 6bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
6{ 7{
diff --git a/tools/perf/arch/arm64/annotate/instructions.c b/tools/perf/arch/arm64/annotate/instructions.c
index 44eafd6f2d50..8f1908756cb6 100644
--- a/tools/perf/arch/arm64/annotate/instructions.c
+++ b/tools/perf/arch/arm64/annotate/instructions.c
@@ -50,7 +50,7 @@ static int arm64__annotate_init(struct arch *arch)
50 arch->initialized = true; 50 arch->initialized = true;
51 arch->priv = arm; 51 arch->priv = arm;
52 arch->associate_instruction_ops = arm64__associate_instruction_ops; 52 arch->associate_instruction_ops = arm64__associate_instruction_ops;
53 arch->objdump.comment_char = ';'; 53 arch->objdump.comment_char = '/';
54 arch->objdump.skip_functions_char = '+'; 54 arch->objdump.skip_functions_char = '+';
55 return 0; 55 return 0;
56 56
diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c
index 068b6189157b..cd764a9fd098 100644
--- a/tools/perf/arch/arm64/util/dwarf-regs.c
+++ b/tools/perf/arch/arm64/util/dwarf-regs.c
@@ -8,9 +8,12 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11#include <errno.h>
11#include <stddef.h> 12#include <stddef.h>
13#include <string.h>
12#include <dwarf-regs.h> 14#include <dwarf-regs.h>
13#include <linux/ptrace.h> /* for struct user_pt_regs */ 15#include <linux/ptrace.h> /* for struct user_pt_regs */
16#include <linux/stringify.h>
14#include "util.h" 17#include "util.h"
15 18
16struct pt_regs_dwarfnum { 19struct pt_regs_dwarfnum {
@@ -20,7 +23,7 @@ struct pt_regs_dwarfnum {
20 23
21#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} 24#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
22#define GPR_DWARFNUM_NAME(num) \ 25#define GPR_DWARFNUM_NAME(num) \
23 {.name = STR(%x##num), .dwarfnum = num} 26 {.name = __stringify(%x##num), .dwarfnum = num}
24#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} 27#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
25#define DWARFNUM2OFFSET(index) \ 28#define DWARFNUM2OFFSET(index) \
26 (index * sizeof((struct user_pt_regs *)0)->regs[0]) 29 (index * sizeof((struct user_pt_regs *)0)->regs[0])
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c
index c116b713f7f7..b415dfdbccca 100644
--- a/tools/perf/arch/arm64/util/unwind-libunwind.c
+++ b/tools/perf/arch/arm64/util/unwind-libunwind.c
@@ -1,6 +1,6 @@
1#include <errno.h>
1 2
2#ifndef REMOTE_UNWIND_LIBUNWIND 3#ifndef REMOTE_UNWIND_LIBUNWIND
3#include <errno.h>
4#include <libunwind.h> 4#include <libunwind.h>
5#include "perf_regs.h" 5#include "perf_regs.h"
6#include "../../util/unwind.h" 6#include "../../util/unwind.h"
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
index 886dd2aaff0d..837067f48a4c 100644
--- a/tools/perf/arch/common.c
+++ b/tools/perf/arch/common.c
@@ -4,6 +4,8 @@
4#include "../util/util.h" 4#include "../util/util.h"
5#include "../util/debug.h" 5#include "../util/debug.h"
6 6
7#include "sane_ctype.h"
8
7const char *const arm_triplets[] = { 9const char *const arm_triplets[] = {
8 "arm-eabi-", 10 "arm-eabi-",
9 "arm-linux-androideabi-", 11 "arm-linux-androideabi-",
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
index 41bdf9530d82..98ac87052a74 100644
--- a/tools/perf/arch/powerpc/util/dwarf-regs.c
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -15,6 +15,7 @@
15#include <dwarf-regs.h> 15#include <dwarf-regs.h>
16#include <linux/ptrace.h> 16#include <linux/ptrace.h>
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/stringify.h>
18#include "util.h" 19#include "util.h"
19 20
20struct pt_regs_dwarfnum { 21struct pt_regs_dwarfnum {
@@ -24,10 +25,10 @@ struct pt_regs_dwarfnum {
24}; 25};
25 26
26#define REG_DWARFNUM_NAME(r, num) \ 27#define REG_DWARFNUM_NAME(r, num) \
27 {.name = STR(%)STR(r), .dwarfnum = num, \ 28 {.name = __stringify(%)__stringify(r), .dwarfnum = num, \
28 .ptregs_offset = offsetof(struct pt_regs, r)} 29 .ptregs_offset = offsetof(struct pt_regs, r)}
29#define GPR_DWARFNUM_NAME(num) \ 30#define GPR_DWARFNUM_NAME(num) \
30 {.name = STR(%gpr##num), .dwarfnum = num, \ 31 {.name = __stringify(%gpr##num), .dwarfnum = num, \
31 .ptregs_offset = offsetof(struct pt_regs, gpr[num])} 32 .ptregs_offset = offsetof(struct pt_regs, gpr[num])}
32#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0, .ptregs_offset = 0} 33#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0, .ptregs_offset = 0}
33 34
diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c
index 74eee30398f8..249723f0e6a9 100644
--- a/tools/perf/arch/powerpc/util/kvm-stat.c
+++ b/tools/perf/arch/powerpc/util/kvm-stat.c
@@ -1,3 +1,4 @@
1#include <errno.h>
1#include "util/kvm-stat.h" 2#include "util/kvm-stat.h"
2#include "util/parse-events.h" 3#include "util/parse-events.h"
3#include "util/debug.h" 4#include "util/debug.h"
diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c
index a3c3e1ce6807..f860dc411f69 100644
--- a/tools/perf/arch/powerpc/util/perf_regs.c
+++ b/tools/perf/arch/powerpc/util/perf_regs.c
@@ -1,5 +1,11 @@
1#include <errno.h>
2#include <string.h>
3#include <regex.h>
4
1#include "../../perf.h" 5#include "../../perf.h"
6#include "../../util/util.h"
2#include "../../util/perf_regs.h" 7#include "../../util/perf_regs.h"
8#include "../../util/debug.h"
3 9
4const struct sample_reg sample_reg_masks[] = { 10const struct sample_reg sample_reg_masks[] = {
5 SMPL_REG(r0, PERF_REG_POWERPC_R0), 11 SMPL_REG(r0, PERF_REG_POWERPC_R0),
@@ -47,3 +53,109 @@ const struct sample_reg sample_reg_masks[] = {
47 SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR), 53 SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR),
48 SMPL_REG_END 54 SMPL_REG_END
49}; 55};
56
57/* REG or %rREG */
58#define SDT_OP_REGEX1 "^(%r)?([1-2]?[0-9]|3[0-1])$"
59
60/* -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) */
61#define SDT_OP_REGEX2 "^(\\-)?([0-9]+)\\((%r)?([1-2]?[0-9]|3[0-1])\\)$"
62
63static regex_t sdt_op_regex1, sdt_op_regex2;
64
65static int sdt_init_op_regex(void)
66{
67 static int initialized;
68 int ret = 0;
69
70 if (initialized)
71 return 0;
72
73 ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED);
74 if (ret)
75 goto error;
76
77 ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED);
78 if (ret)
79 goto free_regex1;
80
81 initialized = 1;
82 return 0;
83
84free_regex1:
85 regfree(&sdt_op_regex1);
86error:
87 pr_debug4("Regex compilation error.\n");
88 return ret;
89}
90
91/*
92 * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG).
93 * Possible variants of OP are:
94 * Format Example
95 * -------------------------
96 * NUM(REG) 48(18)
97 * -NUM(REG) -48(18)
98 * NUM(%rREG) 48(%r18)
99 * -NUM(%rREG) -48(%r18)
100 * REG 18
101 * %rREG %r18
102 * iNUM i0
103 * i-NUM i-1
104 *
105 * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag
106 * and REG form with -mno-regnames. Here REG is general purpose register,
107 * which is in 0 to 31 range.
108 */
109int arch_sdt_arg_parse_op(char *old_op, char **new_op)
110{
111 int ret, new_len;
112 regmatch_t rm[5];
113 char prefix;
114
115 /* Constant argument. Uprobe does not support it */
116 if (old_op[0] == 'i') {
117 pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
118 return SDT_ARG_SKIP;
119 }
120
121 ret = sdt_init_op_regex();
122 if (ret < 0)
123 return ret;
124
125 if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) {
126 /* REG or %rREG --> %gprREG */
127
128 new_len = 5; /* % g p r NULL */
129 new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
130
131 *new_op = zalloc(new_len);
132 if (!*new_op)
133 return -ENOMEM;
134
135 scnprintf(*new_op, new_len, "%%gpr%.*s",
136 (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so);
137 } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) {
138 /*
139 * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) -->
140 * +/-NUM(%gprREG)
141 */
142 prefix = (rm[1].rm_so == -1) ? '+' : '-';
143
144 new_len = 8; /* +/- ( % g p r ) NULL */
145 new_len += (int)(rm[2].rm_eo - rm[2].rm_so);
146 new_len += (int)(rm[4].rm_eo - rm[4].rm_so);
147
148 *new_op = zalloc(new_len);
149 if (!*new_op)
150 return -ENOMEM;
151
152 scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix,
153 (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
154 (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so);
155 } else {
156 pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
157 return SDT_ARG_SKIP;
158 }
159
160 return SDT_ARG_VALID;
161}
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index 1030a6e504bb..bf9a2594572c 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -10,6 +10,7 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "map.h" 11#include "map.h"
12#include "probe-event.h" 12#include "probe-event.h"
13#include "probe-file.h"
13 14
14#ifdef HAVE_LIBELF_SUPPORT 15#ifdef HAVE_LIBELF_SUPPORT
15bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) 16bool elf__needs_adjust_symbols(GElf_Ehdr ehdr)
@@ -51,6 +52,18 @@ int arch__compare_symbol_names(const char *namea, const char *nameb)
51 52
52 return strcmp(namea, nameb); 53 return strcmp(namea, nameb);
53} 54}
55
56int arch__compare_symbol_names_n(const char *namea, const char *nameb,
57 unsigned int n)
58{
59 /* Skip over initial dot */
60 if (*namea == '.')
61 namea++;
62 if (*nameb == '.')
63 nameb++;
64
65 return strncmp(namea, nameb, n);
66}
54#endif 67#endif
55 68
56#if defined(_CALL_ELF) && _CALL_ELF == 2 69#if defined(_CALL_ELF) && _CALL_ELF == 2
@@ -79,13 +92,18 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
79 * However, if the user specifies an offset, we fall back to using the 92 * However, if the user specifies an offset, we fall back to using the
80 * GEP since all userspace applications (objdump/readelf) show function 93 * GEP since all userspace applications (objdump/readelf) show function
81 * disassembly with offsets from the GEP. 94 * disassembly with offsets from the GEP.
82 *
83 * In addition, we shouldn't specify an offset for kretprobes.
84 */ 95 */
85 if (pev->point.offset || (!pev->uprobes && pev->point.retprobe) || 96 if (pev->point.offset || !map || !sym)
86 !map || !sym)
87 return; 97 return;
88 98
99 /* For kretprobes, add an offset only if the kernel supports it */
100 if (!pev->uprobes && pev->point.retprobe) {
101#ifdef HAVE_LIBELF_SUPPORT
102 if (!kretprobe_offset_is_supported())
103#endif
104 return;
105 }
106
89 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); 107 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
90 108
91 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) 109 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS)
diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c
new file mode 100644
index 000000000000..745b4b1b8b21
--- /dev/null
+++ b/tools/perf/arch/s390/annotate/instructions.c
@@ -0,0 +1,30 @@
1static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name)
2{
3 struct ins_ops *ops = NULL;
4
5 /* catch all kind of jumps */
6 if (strchr(name, 'j') ||
7 !strncmp(name, "bct", 3) ||
8 !strncmp(name, "br", 2))
9 ops = &jump_ops;
10 /* override call/returns */
11 if (!strcmp(name, "bras") ||
12 !strcmp(name, "brasl") ||
13 !strcmp(name, "basr"))
14 ops = &call_ops;
15 if (!strcmp(name, "br"))
16 ops = &ret_ops;
17
18 arch__associate_ins_ops(arch, name, ops);
19 return ops;
20}
21
22static int s390__annotate_init(struct arch *arch)
23{
24 if (!arch->initialized) {
25 arch->initialized = true;
26 arch->associate_instruction_ops = s390__associate_ins_ops;
27 }
28
29 return 0;
30}
diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c
index ed57df2e6d68..d233e2eb9592 100644
--- a/tools/perf/arch/s390/util/kvm-stat.c
+++ b/tools/perf/arch/s390/util/kvm-stat.c
@@ -9,6 +9,7 @@
9 * as published by the Free Software Foundation. 9 * as published by the Free Software Foundation.
10 */ 10 */
11 11
12#include <errno.h>
12#include "../../util/kvm-stat.h" 13#include "../../util/kvm-stat.h"
13#include <asm/sie.h> 14#include <asm/sie.h>
14 15
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
index e93ef0b38db8..5aef183e2f85 100644
--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
@@ -338,6 +338,7 @@
338329 common pkey_mprotect sys_pkey_mprotect 338329 common pkey_mprotect sys_pkey_mprotect
339330 common pkey_alloc sys_pkey_alloc 339330 common pkey_alloc sys_pkey_alloc
340331 common pkey_free sys_pkey_free 340331 common pkey_free sys_pkey_free
341332 common statx sys_statx
341 342
342# 343#
343# x32-specific system call numbers start at 512 to avoid cache impact 344# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c
index 7f064eb37158..f9713a71d77e 100644
--- a/tools/perf/arch/x86/tests/intel-cqm.c
+++ b/tools/perf/arch/x86/tests/intel-cqm.c
@@ -6,7 +6,10 @@
6#include "evsel.h" 6#include "evsel.h"
7#include "arch-tests.h" 7#include "arch-tests.h"
8 8
9#include <signal.h>
9#include <sys/mman.h> 10#include <sys/mman.h>
11#include <sys/wait.h>
12#include <errno.h>
10#include <string.h> 13#include <string.h>
11 14
12static pid_t spawn(void) 15static pid_t spawn(void)
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
index 5c76cc83186a..e3ae9cff2b67 100644
--- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c
+++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
@@ -1,3 +1,5 @@
1#include <errno.h>
2#include <inttypes.h>
1#include <stdio.h> 3#include <stdio.h>
2#include <unistd.h> 4#include <unistd.h>
3#include <linux/types.h> 5#include <linux/types.h>
diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c
index cc1d865e31f1..6aa3f2a38321 100644
--- a/tools/perf/arch/x86/util/auxtrace.c
+++ b/tools/perf/arch/x86/util/auxtrace.c
@@ -13,6 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16#include <errno.h>
16#include <stdbool.h> 17#include <stdbool.h>
17 18
18#include "../../util/header.h" 19#include "../../util/header.h"
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 5132775a044f..af2bce7a2cd6 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -13,6 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16#include <errno.h>
16#include <linux/kernel.h> 17#include <linux/kernel.h>
17#include <linux/types.h> 18#include <linux/types.h>
18#include <linux/bitops.h> 19#include <linux/bitops.h>
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 90fa2286edcf..f630de0206a1 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -13,6 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16#include <errno.h>
16#include <stdbool.h> 17#include <stdbool.h>
17#include <linux/kernel.h> 18#include <linux/kernel.h>
18#include <linux/types.h> 19#include <linux/types.h>
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c
index b63d4be655a2..bf817beca0a8 100644
--- a/tools/perf/arch/x86/util/kvm-stat.c
+++ b/tools/perf/arch/x86/util/kvm-stat.c
@@ -1,3 +1,4 @@
1#include <errno.h>
1#include "../../util/kvm-stat.h" 2#include "../../util/kvm-stat.h"
2#include <asm/svm.h> 3#include <asm/svm.h>
3#include <asm/vmx.h> 4#include <asm/vmx.h>
diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c
index c5db14f36cc7..f95edebfb716 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -1,5 +1,11 @@
1#include <errno.h>
2#include <string.h>
3#include <regex.h>
4
1#include "../../perf.h" 5#include "../../perf.h"
6#include "../../util/util.h"
2#include "../../util/perf_regs.h" 7#include "../../util/perf_regs.h"
8#include "../../util/debug.h"
3 9
4const struct sample_reg sample_reg_masks[] = { 10const struct sample_reg sample_reg_masks[] = {
5 SMPL_REG(AX, PERF_REG_X86_AX), 11 SMPL_REG(AX, PERF_REG_X86_AX),
@@ -26,3 +32,224 @@ const struct sample_reg sample_reg_masks[] = {
26#endif 32#endif
27 SMPL_REG_END 33 SMPL_REG_END
28}; 34};
35
36struct sdt_name_reg {
37 const char *sdt_name;
38 const char *uprobe_name;
39};
40#define SDT_NAME_REG(n, m) {.sdt_name = "%" #n, .uprobe_name = "%" #m}
41#define SDT_NAME_REG_END {.sdt_name = NULL, .uprobe_name = NULL}
42
43static const struct sdt_name_reg sdt_reg_tbl[] = {
44 SDT_NAME_REG(eax, ax),
45 SDT_NAME_REG(rax, ax),
46 SDT_NAME_REG(al, ax),
47 SDT_NAME_REG(ah, ax),
48 SDT_NAME_REG(ebx, bx),
49 SDT_NAME_REG(rbx, bx),
50 SDT_NAME_REG(bl, bx),
51 SDT_NAME_REG(bh, bx),
52 SDT_NAME_REG(ecx, cx),
53 SDT_NAME_REG(rcx, cx),
54 SDT_NAME_REG(cl, cx),
55 SDT_NAME_REG(ch, cx),
56 SDT_NAME_REG(edx, dx),
57 SDT_NAME_REG(rdx, dx),
58 SDT_NAME_REG(dl, dx),
59 SDT_NAME_REG(dh, dx),
60 SDT_NAME_REG(esi, si),
61 SDT_NAME_REG(rsi, si),
62 SDT_NAME_REG(sil, si),
63 SDT_NAME_REG(edi, di),
64 SDT_NAME_REG(rdi, di),
65 SDT_NAME_REG(dil, di),
66 SDT_NAME_REG(ebp, bp),
67 SDT_NAME_REG(rbp, bp),
68 SDT_NAME_REG(bpl, bp),
69 SDT_NAME_REG(rsp, sp),
70 SDT_NAME_REG(esp, sp),
71 SDT_NAME_REG(spl, sp),
72
73 /* rNN registers */
74 SDT_NAME_REG(r8b, r8),
75 SDT_NAME_REG(r8w, r8),
76 SDT_NAME_REG(r8d, r8),
77 SDT_NAME_REG(r9b, r9),
78 SDT_NAME_REG(r9w, r9),
79 SDT_NAME_REG(r9d, r9),
80 SDT_NAME_REG(r10b, r10),
81 SDT_NAME_REG(r10w, r10),
82 SDT_NAME_REG(r10d, r10),
83 SDT_NAME_REG(r11b, r11),
84 SDT_NAME_REG(r11w, r11),
85 SDT_NAME_REG(r11d, r11),
86 SDT_NAME_REG(r12b, r12),
87 SDT_NAME_REG(r12w, r12),
88 SDT_NAME_REG(r12d, r12),
89 SDT_NAME_REG(r13b, r13),
90 SDT_NAME_REG(r13w, r13),
91 SDT_NAME_REG(r13d, r13),
92 SDT_NAME_REG(r14b, r14),
93 SDT_NAME_REG(r14w, r14),
94 SDT_NAME_REG(r14d, r14),
95 SDT_NAME_REG(r15b, r15),
96 SDT_NAME_REG(r15w, r15),
97 SDT_NAME_REG(r15d, r15),
98 SDT_NAME_REG_END,
99};
100
101/*
102 * Perf only supports OP which is in +/-NUM(REG) form.
103 * Here plus-minus sign, NUM and parenthesis are optional,
104 * only REG is mandatory.
105 *
106 * SDT events also supports indirect addressing mode with a
107 * symbol as offset, scaled mode and constants in OP. But
108 * perf does not support them yet. Below are few examples.
109 *
110 * OP with scaled mode:
111 * (%rax,%rsi,8)
112 * 10(%ras,%rsi,8)
113 *
114 * OP with indirect addressing mode:
115 * check_action(%rip)
116 * mp_+52(%rip)
117 * 44+mp_(%rip)
118 *
119 * OP with constant values:
120 * $0
121 * $123
122 * $-1
123 */
124#define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
125
126static regex_t sdt_op_regex;
127
128static int sdt_init_op_regex(void)
129{
130 static int initialized;
131 int ret = 0;
132
133 if (initialized)
134 return 0;
135
136 ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED);
137 if (ret < 0) {
138 pr_debug4("Regex compilation error.\n");
139 return ret;
140 }
141
142 initialized = 1;
143 return 0;
144}
145
146/*
147 * Max x86 register name length is 5(ex: %r15d). So, 6th char
148 * should always contain NULL. This helps to find register name
149 * length using strlen, insted of maintaing one more variable.
150 */
151#define SDT_REG_NAME_SIZE 6
152
153/*
154 * The uprobe parser does not support all gas register names;
155 * so, we have to replace them (ex. for x86_64: %rax -> %ax).
156 * Note: If register does not require renaming, just copy
157 * paste as it is, but don't leave it empty.
158 */
159static void sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
160{
161 int i = 0;
162
163 for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) {
164 if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
165 strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name);
166 return;
167 }
168 }
169
170 strncpy(uprobe_reg, sdt_reg, sdt_len);
171}
172
173int arch_sdt_arg_parse_op(char *old_op, char **new_op)
174{
175 char new_reg[SDT_REG_NAME_SIZE] = {0};
176 int new_len = 0, ret;
177 /*
178 * rm[0]: +/-NUM(REG)
179 * rm[1]: +/-
180 * rm[2]: NUM
181 * rm[3]: (
182 * rm[4]: REG
183 * rm[5]: )
184 */
185 regmatch_t rm[6];
186 /*
187 * Max prefix length is 2 as it may contains sign(+/-)
188 * and displacement 0 (Both sign and displacement 0 are
189 * optional so it may be empty). Use one more character
190 * to hold last NULL so that strlen can be used to find
191 * prefix length, instead of maintaing one more variable.
192 */
193 char prefix[3] = {0};
194
195 ret = sdt_init_op_regex();
196 if (ret < 0)
197 return ret;
198
199 /*
200 * If unsupported OR does not match with regex OR
201 * register name too long, skip it.
202 */
203 if (strchr(old_op, ',') || strchr(old_op, '$') ||
204 regexec(&sdt_op_regex, old_op, 6, rm, 0) ||
205 rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) {
206 pr_debug4("Skipping unsupported SDT argument: %s\n", old_op);
207 return SDT_ARG_SKIP;
208 }
209
210 /*
211 * Prepare prefix.
212 * If SDT OP has parenthesis but does not provide
213 * displacement, add 0 for displacement.
214 * SDT Uprobe Prefix
215 * -----------------------------
216 * +24(%rdi) +24(%di) +
217 * 24(%rdi) +24(%di) +
218 * %rdi %di
219 * (%rdi) +0(%di) +0
220 * -80(%rbx) -80(%bx) -
221 */
222 if (rm[3].rm_so != rm[3].rm_eo) {
223 if (rm[1].rm_so != rm[1].rm_eo)
224 prefix[0] = *(old_op + rm[1].rm_so);
225 else if (rm[2].rm_so != rm[2].rm_eo)
226 prefix[0] = '+';
227 else
228 strncpy(prefix, "+0", 2);
229 }
230
231 /* Rename register */
232 sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so,
233 new_reg);
234
235 /* Prepare final OP which should be valid for uprobe_events */
236 new_len = strlen(prefix) +
237 (rm[2].rm_eo - rm[2].rm_so) +
238 (rm[3].rm_eo - rm[3].rm_so) +
239 strlen(new_reg) +
240 (rm[5].rm_eo - rm[5].rm_so) +
241 1; /* NULL */
242
243 *new_op = zalloc(new_len);
244 if (!*new_op)
245 return -ENOMEM;
246
247 scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s",
248 strlen(prefix), prefix,
249 (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so,
250 (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so,
251 strlen(new_reg), new_reg,
252 (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so);
253
254 return SDT_ARG_VALID;
255}
diff --git a/tools/perf/arch/x86/util/unwind-libdw.c b/tools/perf/arch/x86/util/unwind-libdw.c
index c4b72176ca83..38dc9bb2a7c9 100644
--- a/tools/perf/arch/x86/util/unwind-libdw.c
+++ b/tools/perf/arch/x86/util/unwind-libdw.c
@@ -1,6 +1,7 @@
1#include <elfutils/libdwfl.h> 1#include <elfutils/libdwfl.h>
2#include "../../util/unwind-libdw.h" 2#include "../../util/unwind-libdw.h"
3#include "../../util/perf_regs.h" 3#include "../../util/perf_regs.h"
4#include "../../util/event.h"
4 5
5bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) 6bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
6{ 7{
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index 579a592990dd..842ab2781cdc 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -25,17 +25,17 @@
25# endif 25# endif
26#endif 26#endif
27 27
28int bench_numa(int argc, const char **argv, const char *prefix); 28int bench_numa(int argc, const char **argv);
29int bench_sched_messaging(int argc, const char **argv, const char *prefix); 29int bench_sched_messaging(int argc, const char **argv);
30int bench_sched_pipe(int argc, const char **argv, const char *prefix); 30int bench_sched_pipe(int argc, const char **argv);
31int bench_mem_memcpy(int argc, const char **argv, const char *prefix); 31int bench_mem_memcpy(int argc, const char **argv);
32int bench_mem_memset(int argc, const char **argv, const char *prefix); 32int bench_mem_memset(int argc, const char **argv);
33int bench_futex_hash(int argc, const char **argv, const char *prefix); 33int bench_futex_hash(int argc, const char **argv);
34int bench_futex_wake(int argc, const char **argv, const char *prefix); 34int bench_futex_wake(int argc, const char **argv);
35int bench_futex_wake_parallel(int argc, const char **argv, const char *prefix); 35int bench_futex_wake_parallel(int argc, const char **argv);
36int bench_futex_requeue(int argc, const char **argv, const char *prefix); 36int bench_futex_requeue(int argc, const char **argv);
37/* pi futexes */ 37/* pi futexes */
38int bench_futex_lock_pi(int argc, const char **argv, const char *prefix); 38int bench_futex_lock_pi(int argc, const char **argv);
39 39
40#define BENCH_FORMAT_DEFAULT_STR "default" 40#define BENCH_FORMAT_DEFAULT_STR "default"
41#define BENCH_FORMAT_DEFAULT 0 41#define BENCH_FORMAT_DEFAULT 0
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
index da04b8c5568a..fe16b310097f 100644
--- a/tools/perf/bench/futex-hash.c
+++ b/tools/perf/bench/futex-hash.c
@@ -9,6 +9,7 @@
9 */ 9 */
10 10
11/* For the CLR_() macros */ 11/* For the CLR_() macros */
12#include <string.h>
12#include <pthread.h> 13#include <pthread.h>
13 14
14#include <errno.h> 15#include <errno.h>
@@ -113,8 +114,7 @@ static void print_summary(void)
113 (int) runtime.tv_sec); 114 (int) runtime.tv_sec);
114} 115}
115 116
116int bench_futex_hash(int argc, const char **argv, 117int bench_futex_hash(int argc, const char **argv)
117 const char *prefix __maybe_unused)
118{ 118{
119 int ret = 0; 119 int ret = 0;
120 cpu_set_t cpu; 120 cpu_set_t cpu;
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c
index 91877777ec6e..73a1c44ea63c 100644
--- a/tools/perf/bench/futex-lock-pi.c
+++ b/tools/perf/bench/futex-lock-pi.c
@@ -3,6 +3,7 @@
3 */ 3 */
4 4
5/* For the CLR_() macros */ 5/* For the CLR_() macros */
6#include <string.h>
6#include <pthread.h> 7#include <pthread.h>
7 8
8#include <signal.h> 9#include <signal.h>
@@ -139,8 +140,7 @@ static void create_threads(struct worker *w, pthread_attr_t thread_attr)
139 } 140 }
140} 141}
141 142
142int bench_futex_lock_pi(int argc, const char **argv, 143int bench_futex_lock_pi(int argc, const char **argv)
143 const char *prefix __maybe_unused)
144{ 144{
145 int ret = 0; 145 int ret = 0;
146 unsigned int i; 146 unsigned int i;
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
index 2b9705a8734c..41786cbea24c 100644
--- a/tools/perf/bench/futex-requeue.c
+++ b/tools/perf/bench/futex-requeue.c
@@ -9,6 +9,7 @@
9 */ 9 */
10 10
11/* For the CLR_() macros */ 11/* For the CLR_() macros */
12#include <string.h>
12#include <pthread.h> 13#include <pthread.h>
13 14
14#include <signal.h> 15#include <signal.h>
@@ -108,8 +109,7 @@ static void toggle_done(int sig __maybe_unused,
108 done = true; 109 done = true;
109} 110}
110 111
111int bench_futex_requeue(int argc, const char **argv, 112int bench_futex_requeue(int argc, const char **argv)
112 const char *prefix __maybe_unused)
113{ 113{
114 int ret = 0; 114 int ret = 0;
115 unsigned int i, j; 115 unsigned int i, j;
diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c
index 2c8fa67ad537..4ab12c8e016a 100644
--- a/tools/perf/bench/futex-wake-parallel.c
+++ b/tools/perf/bench/futex-wake-parallel.c
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10/* For the CLR_() macros */ 10/* For the CLR_() macros */
11#include <string.h>
11#include <pthread.h> 12#include <pthread.h>
12 13
13#include <signal.h> 14#include <signal.h>
@@ -196,8 +197,7 @@ static void toggle_done(int sig __maybe_unused,
196 done = true; 197 done = true;
197} 198}
198 199
199int bench_futex_wake_parallel(int argc, const char **argv, 200int bench_futex_wake_parallel(int argc, const char **argv)
200 const char *prefix __maybe_unused)
201{ 201{
202 int ret = 0; 202 int ret = 0;
203 unsigned int i, j; 203 unsigned int i, j;
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
index e246b1b8388a..2fa49222ef8d 100644
--- a/tools/perf/bench/futex-wake.c
+++ b/tools/perf/bench/futex-wake.c
@@ -9,6 +9,7 @@
9 */ 9 */
10 10
11/* For the CLR_() macros */ 11/* For the CLR_() macros */
12#include <string.h>
12#include <pthread.h> 13#include <pthread.h>
13 14
14#include <signal.h> 15#include <signal.h>
@@ -114,8 +115,7 @@ static void toggle_done(int sig __maybe_unused,
114 done = true; 115 done = true;
115} 116}
116 117
117int bench_futex_wake(int argc, const char **argv, 118int bench_futex_wake(int argc, const char **argv)
118 const char *prefix __maybe_unused)
119{ 119{
120 int ret = 0; 120 int ret = 0;
121 unsigned int i, j; 121 unsigned int i, j;
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h
index b2e06d1190d0..e44fd3239530 100644
--- a/tools/perf/bench/futex.h
+++ b/tools/perf/bench/futex.h
@@ -88,13 +88,11 @@ futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wak
88 88
89#ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP 89#ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP
90#include <pthread.h> 90#include <pthread.h>
91static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr, 91#include <linux/compiler.h>
92 size_t cpusetsize, 92static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr __maybe_unused,
93 cpu_set_t *cpuset) 93 size_t cpusetsize __maybe_unused,
94 cpu_set_t *cpuset __maybe_unused)
94{ 95{
95 attr = attr;
96 cpusetsize = cpusetsize;
97 cpuset = cpuset;
98 return 0; 96 return 0;
99} 97}
100#endif 98#endif
diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c
index 52504a83b5a1..fbd732b54047 100644
--- a/tools/perf/bench/mem-functions.c
+++ b/tools/perf/bench/mem-functions.c
@@ -12,6 +12,7 @@
12#include <subcmd/parse-options.h> 12#include <subcmd/parse-options.h>
13#include "../util/header.h" 13#include "../util/header.h"
14#include "../util/cloexec.h" 14#include "../util/cloexec.h"
15#include "../util/string2.h"
15#include "bench.h" 16#include "bench.h"
16#include "mem-memcpy-arch.h" 17#include "mem-memcpy-arch.h"
17#include "mem-memset-arch.h" 18#include "mem-memset-arch.h"
@@ -284,7 +285,7 @@ static const char * const bench_mem_memcpy_usage[] = {
284 NULL 285 NULL
285}; 286};
286 287
287int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused) 288int bench_mem_memcpy(int argc, const char **argv)
288{ 289{
289 struct bench_mem_info info = { 290 struct bench_mem_info info = {
290 .functions = memcpy_functions, 291 .functions = memcpy_functions,
@@ -358,7 +359,7 @@ static const struct function memset_functions[] = {
358 { .name = NULL, } 359 { .name = NULL, }
359}; 360};
360 361
361int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unused) 362int bench_mem_memset(int argc, const char **argv)
362{ 363{
363 struct bench_mem_info info = { 364 struct bench_mem_info info = {
364 .functions = memset_functions, 365 .functions = memset_functions,
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 3083fc36282b..27de0c8c5c19 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -4,6 +4,7 @@
4 * numa: Simulate NUMA-sensitive workload and measure their NUMA performance 4 * numa: Simulate NUMA-sensitive workload and measure their NUMA performance
5 */ 5 */
6 6
7#include <inttypes.h>
7/* For the CLR_() macros */ 8/* For the CLR_() macros */
8#include <pthread.h> 9#include <pthread.h>
9 10
@@ -30,6 +31,7 @@
30#include <sys/wait.h> 31#include <sys/wait.h>
31#include <sys/prctl.h> 32#include <sys/prctl.h>
32#include <sys/types.h> 33#include <sys/types.h>
34#include <linux/kernel.h>
33#include <linux/time64.h> 35#include <linux/time64.h>
34 36
35#include <numa.h> 37#include <numa.h>
@@ -187,7 +189,8 @@ static const struct option options[] = {
187 OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"), 189 OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"),
188 OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"), 190 OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"),
189 OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"), 191 OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
190 OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"), 192 OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details, "
193 "convergence is reached when each process (all its threads) is running on a single NUMA node."),
191 OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"), 194 OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
192 OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "quiet mode"), 195 OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "quiet mode"),
193 OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"), 196 OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
@@ -1766,7 +1769,7 @@ static int bench_all(void)
1766 return 0; 1769 return 0;
1767} 1770}
1768 1771
1769int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused) 1772int bench_numa(int argc, const char **argv)
1770{ 1773{
1771 init_params(&p0, "main,", argc, argv); 1774 init_params(&p0, "main,", argc, argv);
1772 argc = parse_options(argc, argv, options, bench_numa_usage, 0); 1775 argc = parse_options(argc, argv, options, bench_numa_usage, 0);
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index 6a111e775210..4f961e74535b 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -260,8 +260,7 @@ static const char * const bench_sched_message_usage[] = {
260 NULL 260 NULL
261}; 261};
262 262
263int bench_sched_messaging(int argc, const char **argv, 263int bench_sched_messaging(int argc, const char **argv)
264 const char *prefix __maybe_unused)
265{ 264{
266 unsigned int i, total_children; 265 unsigned int i, total_children;
267 struct timeval start, stop, diff; 266 struct timeval start, stop, diff;
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 2243f0150d76..a152737370c5 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -76,7 +76,7 @@ static void *worker_thread(void *__tdata)
76 return NULL; 76 return NULL;
77} 77}
78 78
79int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused) 79int bench_sched_pipe(int argc, const char **argv)
80{ 80{
81 struct thread_data threads[2], *td; 81 struct thread_data threads[2], *td;
82 int pipe_1[2], pipe_2[2]; 82 int pipe_1[2], pipe_2[2];
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 4f52d85f5ebc..7a5dc7e5c577 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -33,6 +33,7 @@
33#include "util/block-range.h" 33#include "util/block-range.h"
34 34
35#include <dlfcn.h> 35#include <dlfcn.h>
36#include <errno.h>
36#include <linux/bitmap.h> 37#include <linux/bitmap.h>
37 38
38struct perf_annotate { 39struct perf_annotate {
@@ -383,7 +384,7 @@ static const char * const annotate_usage[] = {
383 NULL 384 NULL
384}; 385};
385 386
386int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) 387int cmd_annotate(int argc, const char **argv)
387{ 388{
388 struct perf_annotate annotate = { 389 struct perf_annotate annotate = {
389 .tool = { 390 .tool = {
@@ -393,6 +394,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
393 .comm = perf_event__process_comm, 394 .comm = perf_event__process_comm,
394 .exit = perf_event__process_exit, 395 .exit = perf_event__process_exit,
395 .fork = perf_event__process_fork, 396 .fork = perf_event__process_fork,
397 .namespaces = perf_event__process_namespaces,
398 .attr = perf_event__process_attr,
399 .build_id = perf_event__process_build_id,
396 .ordered_events = true, 400 .ordered_events = true,
397 .ordering_requires_timestamps = true, 401 .ordering_requires_timestamps = true,
398 }, 402 },
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index a1cddc6bbf0f..445e62881254 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -25,7 +25,7 @@
25#include <string.h> 25#include <string.h>
26#include <sys/prctl.h> 26#include <sys/prctl.h>
27 27
28typedef int (*bench_fn_t)(int argc, const char **argv, const char *prefix); 28typedef int (*bench_fn_t)(int argc, const char **argv);
29 29
30struct bench { 30struct bench {
31 const char *name; 31 const char *name;
@@ -155,7 +155,7 @@ static int bench_str2int(const char *str)
155 * to something meaningful: 155 * to something meaningful:
156 */ 156 */
157static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn, 157static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
158 int argc, const char **argv, const char *prefix) 158 int argc, const char **argv)
159{ 159{
160 int size; 160 int size;
161 char *name; 161 char *name;
@@ -171,7 +171,7 @@ static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t f
171 prctl(PR_SET_NAME, name); 171 prctl(PR_SET_NAME, name);
172 argv[0] = name; 172 argv[0] = name;
173 173
174 ret = fn(argc, argv, prefix); 174 ret = fn(argc, argv);
175 175
176 free(name); 176 free(name);
177 177
@@ -198,7 +198,7 @@ static void run_collection(struct collection *coll)
198 fflush(stdout); 198 fflush(stdout);
199 199
200 argv[1] = bench->name; 200 argv[1] = bench->name;
201 run_bench(coll->name, bench->name, bench->fn, 1, argv, NULL); 201 run_bench(coll->name, bench->name, bench->fn, 1, argv);
202 printf("\n"); 202 printf("\n");
203 } 203 }
204} 204}
@@ -211,7 +211,7 @@ static void run_all_collections(void)
211 run_collection(coll); 211 run_collection(coll);
212} 212}
213 213
214int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) 214int cmd_bench(int argc, const char **argv)
215{ 215{
216 struct collection *coll; 216 struct collection *coll;
217 int ret = 0; 217 int ret = 0;
@@ -270,7 +270,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
270 if (bench_format == BENCH_FORMAT_DEFAULT) 270 if (bench_format == BENCH_FORMAT_DEFAULT)
271 printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name); 271 printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
272 fflush(stdout); 272 fflush(stdout);
273 ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1, prefix); 273 ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
274 goto end; 274 goto end;
275 } 275 }
276 276
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 30e2b2cb2421..9eba7f1add1f 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -10,6 +10,7 @@
10#include <sys/time.h> 10#include <sys/time.h>
11#include <time.h> 11#include <time.h>
12#include <dirent.h> 12#include <dirent.h>
13#include <errno.h>
13#include <unistd.h> 14#include <unistd.h>
14#include "builtin.h" 15#include "builtin.h"
15#include "perf.h" 16#include "perf.h"
@@ -21,6 +22,7 @@
21#include "util/build-id.h" 22#include "util/build-id.h"
22#include "util/session.h" 23#include "util/session.h"
23#include "util/symbol.h" 24#include "util/symbol.h"
25#include "util/time-utils.h"
24 26
25static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid) 27static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
26{ 28{
@@ -47,19 +49,22 @@ static bool same_kallsyms_reloc(const char *from_dir, char *to_dir)
47 char to[PATH_MAX]; 49 char to[PATH_MAX];
48 const char *name; 50 const char *name;
49 u64 addr1 = 0, addr2 = 0; 51 u64 addr1 = 0, addr2 = 0;
50 int i; 52 int i, err = -1;
51 53
52 scnprintf(from, sizeof(from), "%s/kallsyms", from_dir); 54 scnprintf(from, sizeof(from), "%s/kallsyms", from_dir);
53 scnprintf(to, sizeof(to), "%s/kallsyms", to_dir); 55 scnprintf(to, sizeof(to), "%s/kallsyms", to_dir);
54 56
55 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { 57 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
56 addr1 = kallsyms__get_function_start(from, name); 58 err = kallsyms__get_function_start(from, name, &addr1);
57 if (addr1) 59 if (!err)
58 break; 60 break;
59 } 61 }
60 62
61 if (name) 63 if (err)
62 addr2 = kallsyms__get_function_start(to, name); 64 return false;
65
66 if (kallsyms__get_function_start(to, name, &addr2))
67 return false;
63 68
64 return addr1 == addr2; 69 return addr1 == addr2;
65} 70}
@@ -276,8 +281,7 @@ static int build_id_cache__update_file(const char *filename)
276 return err; 281 return err;
277} 282}
278 283
279int cmd_buildid_cache(int argc, const char **argv, 284int cmd_buildid_cache(int argc, const char **argv)
280 const char *prefix __maybe_unused)
281{ 285{
282 struct strlist *list; 286 struct strlist *list;
283 struct str_node *pos; 287 struct str_node *pos;
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 5e914ee79eb3..fdaca16e0c74 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -16,6 +16,7 @@
16#include "util/session.h" 16#include "util/session.h"
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/data.h" 18#include "util/data.h"
19#include <errno.h>
19 20
20static int sysfs__fprintf_build_id(FILE *fp) 21static int sysfs__fprintf_build_id(FILE *fp)
21{ 22{
@@ -87,8 +88,7 @@ out:
87 return 0; 88 return 0;
88} 89}
89 90
90int cmd_buildid_list(int argc, const char **argv, 91int cmd_buildid_list(int argc, const char **argv)
91 const char *prefix __maybe_unused)
92{ 92{
93 bool show_kernel = false; 93 bool show_kernel = false;
94 bool with_hits = false; 94 bool with_hits = false;
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index e2b21723bbf8..620a467ee304 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -9,10 +9,13 @@
9 * Dick Fowles <fowles@inreach.com> 9 * Dick Fowles <fowles@inreach.com>
10 * Joe Mario <jmario@redhat.com> 10 * Joe Mario <jmario@redhat.com>
11 */ 11 */
12#include <errno.h>
13#include <inttypes.h>
12#include <linux/compiler.h> 14#include <linux/compiler.h>
13#include <linux/kernel.h> 15#include <linux/kernel.h>
14#include <linux/stringify.h> 16#include <linux/stringify.h>
15#include <asm/bug.h> 17#include <asm/bug.h>
18#include <sys/param.h>
16#include "util.h" 19#include "util.h"
17#include "debug.h" 20#include "debug.h"
18#include "builtin.h" 21#include "builtin.h"
@@ -24,11 +27,13 @@
24#include "tool.h" 27#include "tool.h"
25#include "data.h" 28#include "data.h"
26#include "sort.h" 29#include "sort.h"
30#include "event.h"
27#include "evlist.h" 31#include "evlist.h"
28#include "evsel.h" 32#include "evsel.h"
29#include <asm/bug.h> 33#include <asm/bug.h>
30#include "ui/browsers/hists.h" 34#include "ui/browsers/hists.h"
31#include "evlist.h" 35#include "evlist.h"
36#include "thread.h"
32 37
33struct c2c_hists { 38struct c2c_hists {
34 struct hists hists; 39 struct hists hists;
@@ -2334,7 +2339,7 @@ out:
2334 2339
2335static void perf_c2c_display(struct perf_session *session) 2340static void perf_c2c_display(struct perf_session *session)
2336{ 2341{
2337 if (c2c.use_stdio) 2342 if (use_browser == 0)
2338 perf_c2c__hists_fprintf(stdout, session); 2343 perf_c2c__hists_fprintf(stdout, session);
2339 else 2344 else
2340 perf_c2c__hists_browse(&c2c.hists.hists); 2345 perf_c2c__hists_browse(&c2c.hists.hists);
@@ -2536,7 +2541,7 @@ static int perf_c2c__report(int argc, const char **argv)
2536 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"), 2541 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2537#endif 2542#endif
2538 OPT_BOOLEAN(0, "stats", &c2c.stats_only, 2543 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
2539 "Use the stdio interface"), 2544 "Display only statistic tables (implies --stdio)"),
2540 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full, 2545 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
2541 "Display full length of symbols"), 2546 "Display full length of symbols"),
2542 OPT_BOOLEAN(0, "no-source", &no_source, 2547 OPT_BOOLEAN(0, "no-source", &no_source,
@@ -2755,12 +2760,12 @@ static int perf_c2c__record(int argc, const char **argv)
2755 pr_debug("\n"); 2760 pr_debug("\n");
2756 } 2761 }
2757 2762
2758 ret = cmd_record(i, rec_argv, NULL); 2763 ret = cmd_record(i, rec_argv);
2759 free(rec_argv); 2764 free(rec_argv);
2760 return ret; 2765 return ret;
2761} 2766}
2762 2767
2763int cmd_c2c(int argc, const char **argv, const char *prefix __maybe_unused) 2768int cmd_c2c(int argc, const char **argv)
2764{ 2769{
2765 argc = parse_options(argc, argv, c2c_options, c2c_usage, 2770 argc = parse_options(argc, argv, c2c_options, c2c_usage,
2766 PARSE_OPT_STOP_AT_NON_OPTION); 2771 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 8c0d93b7c2f0..80668fa7556e 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -154,11 +154,12 @@ static int parse_config_arg(char *arg, char **var, char **value)
154 return 0; 154 return 0;
155} 155}
156 156
157int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) 157int cmd_config(int argc, const char **argv)
158{ 158{
159 int i, ret = 0; 159 int i, ret = 0;
160 struct perf_config_set *set; 160 struct perf_config_set *set;
161 char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); 161 char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
162 const char *config_filename;
162 163
163 argc = parse_options(argc, argv, config_options, config_usage, 164 argc = parse_options(argc, argv, config_options, config_usage,
164 PARSE_OPT_STOP_AT_NON_OPTION); 165 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -175,6 +176,11 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
175 else if (use_user_config) 176 else if (use_user_config)
176 config_exclusive_filename = user_config; 177 config_exclusive_filename = user_config;
177 178
179 if (!config_exclusive_filename)
180 config_filename = user_config;
181 else
182 config_filename = config_exclusive_filename;
183
178 /* 184 /*
179 * At only 'config' sub-command, individually use the config set 185 * At only 'config' sub-command, individually use the config set
180 * because of reinitializing with options config file location. 186 * because of reinitializing with options config file location.
@@ -192,13 +198,9 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
192 parse_options_usage(config_usage, config_options, "l", 1); 198 parse_options_usage(config_usage, config_options, "l", 1);
193 } else { 199 } else {
194 ret = show_config(set); 200 ret = show_config(set);
195 if (ret < 0) { 201 if (ret < 0)
196 const char * config_filename = config_exclusive_filename;
197 if (!config_exclusive_filename)
198 config_filename = user_config;
199 pr_err("Nothing configured, " 202 pr_err("Nothing configured, "
200 "please check your %s \n", config_filename); 203 "please check your %s \n", config_filename);
201 }
202 } 204 }
203 break; 205 break;
204 default: 206 default:
@@ -221,13 +223,8 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
221 223
222 if (value == NULL) 224 if (value == NULL)
223 ret = show_spec_config(set, var); 225 ret = show_spec_config(set, var);
224 else { 226 else
225 const char *config_filename = config_exclusive_filename;
226
227 if (!config_exclusive_filename)
228 config_filename = user_config;
229 ret = set_config(set, config_filename, var, value); 227 ret = set_config(set, config_filename, var, value);
230 }
231 free(arg); 228 free(arg);
232 } 229 }
233 } else 230 } else
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c
index 7ad6e17ac6b3..0adb5f82335a 100644
--- a/tools/perf/builtin-data.c
+++ b/tools/perf/builtin-data.c
@@ -6,7 +6,7 @@
6#include "data-convert.h" 6#include "data-convert.h"
7#include "data-convert-bt.h" 7#include "data-convert-bt.h"
8 8
9typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); 9typedef int (*data_cmd_fn_t)(int argc, const char **argv);
10 10
11struct data_cmd { 11struct data_cmd {
12 const char *name; 12 const char *name;
@@ -50,8 +50,7 @@ static const char * const data_convert_usage[] = {
50 NULL 50 NULL
51}; 51};
52 52
53static int cmd_data_convert(int argc, const char **argv, 53static int cmd_data_convert(int argc, const char **argv)
54 const char *prefix __maybe_unused)
55{ 54{
56 const char *to_ctf = NULL; 55 const char *to_ctf = NULL;
57 struct perf_data_convert_opts opts = { 56 struct perf_data_convert_opts opts = {
@@ -98,7 +97,7 @@ static struct data_cmd data_cmds[] = {
98 { .name = NULL, }, 97 { .name = NULL, },
99}; 98};
100 99
101int cmd_data(int argc, const char **argv, const char *prefix) 100int cmd_data(int argc, const char **argv)
102{ 101{
103 struct data_cmd *cmd; 102 struct data_cmd *cmd;
104 const char *cmdstr; 103 const char *cmdstr;
@@ -118,7 +117,7 @@ int cmd_data(int argc, const char **argv, const char *prefix)
118 if (strcmp(cmd->name, cmdstr)) 117 if (strcmp(cmd->name, cmdstr))
119 continue; 118 continue;
120 119
121 return cmd->fn(argc, argv, prefix); 120 return cmd->fn(argc, argv);
122 } 121 }
123 122
124 pr_err("Unknown command: %s\n", cmdstr); 123 pr_err("Unknown command: %s\n", cmdstr);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 1b96a3122228..eec5df80f5a3 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -19,6 +19,8 @@
19#include "util/data.h" 19#include "util/data.h"
20#include "util/config.h" 20#include "util/config.h"
21 21
22#include <errno.h>
23#include <inttypes.h>
22#include <stdlib.h> 24#include <stdlib.h>
23#include <math.h> 25#include <math.h>
24 26
@@ -364,6 +366,7 @@ static struct perf_tool tool = {
364 .exit = perf_event__process_exit, 366 .exit = perf_event__process_exit,
365 .fork = perf_event__process_fork, 367 .fork = perf_event__process_fork,
366 .lost = perf_event__process_lost, 368 .lost = perf_event__process_lost,
369 .namespaces = perf_event__process_namespaces,
367 .ordered_events = true, 370 .ordered_events = true,
368 .ordering_requires_timestamps = true, 371 .ordering_requires_timestamps = true,
369}; 372};
@@ -1320,7 +1323,7 @@ static int diff__config(const char *var, const char *value,
1320 return 0; 1323 return 0;
1321} 1324}
1322 1325
1323int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 1326int cmd_diff(int argc, const char **argv)
1324{ 1327{
1325 int ret = hists__init(); 1328 int ret = hists__init();
1326 1329
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index e09c4287fe87..6d210e40d611 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -46,7 +46,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
46 return 0; 46 return 0;
47} 47}
48 48
49int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) 49int cmd_evlist(int argc, const char **argv)
50{ 50{
51 struct perf_attr_details details = { .verbose = false, }; 51 struct perf_attr_details details = { .verbose = false, };
52 const struct option options[] = { 52 const struct option options[] = {
diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c
index c3e643666c72..9e0b35cd0eea 100644
--- a/tools/perf/builtin-ftrace.c
+++ b/tools/perf/builtin-ftrace.c
@@ -9,13 +9,18 @@
9#include "builtin.h" 9#include "builtin.h"
10#include "perf.h" 10#include "perf.h"
11 11
12#include <errno.h>
12#include <unistd.h> 13#include <unistd.h>
13#include <signal.h> 14#include <signal.h>
15#include <fcntl.h>
16#include <poll.h>
14 17
15#include "debug.h" 18#include "debug.h"
16#include <subcmd/parse-options.h> 19#include <subcmd/parse-options.h>
20#include <api/fs/tracing_path.h>
17#include "evlist.h" 21#include "evlist.h"
18#include "target.h" 22#include "target.h"
23#include "cpumap.h"
19#include "thread_map.h" 24#include "thread_map.h"
20#include "util/config.h" 25#include "util/config.h"
21 26
@@ -50,11 +55,12 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
50 done = true; 55 done = true;
51} 56}
52 57
53static int write_tracing_file(const char *name, const char *val) 58static int __write_tracing_file(const char *name, const char *val, bool append)
54{ 59{
55 char *file; 60 char *file;
56 int fd, ret = -1; 61 int fd, ret = -1;
57 ssize_t size = strlen(val); 62 ssize_t size = strlen(val);
63 int flags = O_WRONLY;
58 64
59 file = get_tracing_file(name); 65 file = get_tracing_file(name);
60 if (!file) { 66 if (!file) {
@@ -62,7 +68,12 @@ static int write_tracing_file(const char *name, const char *val)
62 return -1; 68 return -1;
63 } 69 }
64 70
65 fd = open(file, O_WRONLY); 71 if (append)
72 flags |= O_APPEND;
73 else
74 flags |= O_TRUNC;
75
76 fd = open(file, flags);
66 if (fd < 0) { 77 if (fd < 0) {
67 pr_debug("cannot open tracing file: %s\n", name); 78 pr_debug("cannot open tracing file: %s\n", name);
68 goto out; 79 goto out;
@@ -79,6 +90,18 @@ out:
79 return ret; 90 return ret;
80} 91}
81 92
93static int write_tracing_file(const char *name, const char *val)
94{
95 return __write_tracing_file(name, val, false);
96}
97
98static int append_tracing_file(const char *name, const char *val)
99{
100 return __write_tracing_file(name, val, true);
101}
102
103static int reset_tracing_cpu(void);
104
82static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused) 105static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
83{ 106{
84 if (write_tracing_file("tracing_on", "0") < 0) 107 if (write_tracing_file("tracing_on", "0") < 0)
@@ -90,14 +113,78 @@ static int reset_tracing_files(struct perf_ftrace *ftrace __maybe_unused)
90 if (write_tracing_file("set_ftrace_pid", " ") < 0) 113 if (write_tracing_file("set_ftrace_pid", " ") < 0)
91 return -1; 114 return -1;
92 115
116 if (reset_tracing_cpu() < 0)
117 return -1;
118
119 return 0;
120}
121
122static int set_tracing_pid(struct perf_ftrace *ftrace)
123{
124 int i;
125 char buf[16];
126
127 if (target__has_cpu(&ftrace->target))
128 return 0;
129
130 for (i = 0; i < thread_map__nr(ftrace->evlist->threads); i++) {
131 scnprintf(buf, sizeof(buf), "%d",
132 ftrace->evlist->threads->map[i]);
133 if (append_tracing_file("set_ftrace_pid", buf) < 0)
134 return -1;
135 }
93 return 0; 136 return 0;
94} 137}
95 138
139static int set_tracing_cpumask(struct cpu_map *cpumap)
140{
141 char *cpumask;
142 size_t mask_size;
143 int ret;
144 int last_cpu;
145
146 last_cpu = cpu_map__cpu(cpumap, cpumap->nr - 1);
147 mask_size = (last_cpu + 3) / 4 + 1;
148 mask_size += last_cpu / 32; /* ',' is needed for every 32th cpus */
149
150 cpumask = malloc(mask_size);
151 if (cpumask == NULL) {
152 pr_debug("failed to allocate cpu mask\n");
153 return -1;
154 }
155
156 cpu_map__snprint_mask(cpumap, cpumask, mask_size);
157
158 ret = write_tracing_file("tracing_cpumask", cpumask);
159
160 free(cpumask);
161 return ret;
162}
163
164static int set_tracing_cpu(struct perf_ftrace *ftrace)
165{
166 struct cpu_map *cpumap = ftrace->evlist->cpus;
167
168 if (!target__has_cpu(&ftrace->target))
169 return 0;
170
171 return set_tracing_cpumask(cpumap);
172}
173
174static int reset_tracing_cpu(void)
175{
176 struct cpu_map *cpumap = cpu_map__new(NULL);
177 int ret;
178
179 ret = set_tracing_cpumask(cpumap);
180 cpu_map__put(cpumap);
181 return ret;
182}
183
96static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv) 184static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
97{ 185{
98 char *trace_file; 186 char *trace_file;
99 int trace_fd; 187 int trace_fd;
100 char *trace_pid;
101 char buf[4096]; 188 char buf[4096];
102 struct pollfd pollfd = { 189 struct pollfd pollfd = {
103 .events = POLLIN, 190 .events = POLLIN,
@@ -108,42 +195,43 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
108 return -1; 195 return -1;
109 } 196 }
110 197
111 if (argc < 1)
112 return -1;
113
114 signal(SIGINT, sig_handler); 198 signal(SIGINT, sig_handler);
115 signal(SIGUSR1, sig_handler); 199 signal(SIGUSR1, sig_handler);
116 signal(SIGCHLD, sig_handler); 200 signal(SIGCHLD, sig_handler);
201 signal(SIGPIPE, sig_handler);
117 202
118 reset_tracing_files(ftrace); 203 if (reset_tracing_files(ftrace) < 0)
204 goto out;
119 205
120 /* reset ftrace buffer */ 206 /* reset ftrace buffer */
121 if (write_tracing_file("trace", "0") < 0) 207 if (write_tracing_file("trace", "0") < 0)
122 goto out; 208 goto out;
123 209
124 if (perf_evlist__prepare_workload(ftrace->evlist, &ftrace->target, 210 if (argc && perf_evlist__prepare_workload(ftrace->evlist,
125 argv, false, ftrace__workload_exec_failed_signal) < 0) 211 &ftrace->target, argv, false,
212 ftrace__workload_exec_failed_signal) < 0) {
126 goto out; 213 goto out;
214 }
127 215
128 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) { 216 if (set_tracing_pid(ftrace) < 0) {
129 pr_err("failed to set current_tracer to %s\n", ftrace->tracer); 217 pr_err("failed to set ftrace pid\n");
130 goto out; 218 goto out_reset;
131 } 219 }
132 220
133 if (asprintf(&trace_pid, "%d", thread_map__pid(ftrace->evlist->threads, 0)) < 0) { 221 if (set_tracing_cpu(ftrace) < 0) {
134 pr_err("failed to allocate pid string\n"); 222 pr_err("failed to set tracing cpumask\n");
135 goto out; 223 goto out_reset;
136 } 224 }
137 225
138 if (write_tracing_file("set_ftrace_pid", trace_pid) < 0) { 226 if (write_tracing_file("current_tracer", ftrace->tracer) < 0) {
139 pr_err("failed to set pid: %s\n", trace_pid); 227 pr_err("failed to set current_tracer to %s\n", ftrace->tracer);
140 goto out_free_pid; 228 goto out_reset;
141 } 229 }
142 230
143 trace_file = get_tracing_file("trace_pipe"); 231 trace_file = get_tracing_file("trace_pipe");
144 if (!trace_file) { 232 if (!trace_file) {
145 pr_err("failed to open trace_pipe\n"); 233 pr_err("failed to open trace_pipe\n");
146 goto out_free_pid; 234 goto out_reset;
147 } 235 }
148 236
149 trace_fd = open(trace_file, O_RDONLY); 237 trace_fd = open(trace_file, O_RDONLY);
@@ -152,7 +240,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
152 240
153 if (trace_fd < 0) { 241 if (trace_fd < 0) {
154 pr_err("failed to open trace_pipe\n"); 242 pr_err("failed to open trace_pipe\n");
155 goto out_free_pid; 243 goto out_reset;
156 } 244 }
157 245
158 fcntl(trace_fd, F_SETFL, O_NONBLOCK); 246 fcntl(trace_fd, F_SETFL, O_NONBLOCK);
@@ -163,6 +251,8 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
163 goto out_close_fd; 251 goto out_close_fd;
164 } 252 }
165 253
254 setup_pager();
255
166 perf_evlist__start_workload(ftrace->evlist); 256 perf_evlist__start_workload(ftrace->evlist);
167 257
168 while (!done) { 258 while (!done) {
@@ -191,11 +281,9 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
191 281
192out_close_fd: 282out_close_fd:
193 close(trace_fd); 283 close(trace_fd);
194out_free_pid: 284out_reset:
195 free(trace_pid);
196out:
197 reset_tracing_files(ftrace); 285 reset_tracing_files(ftrace);
198 286out:
199 return done ? 0 : -1; 287 return done ? 0 : -1;
200} 288}
201 289
@@ -219,7 +307,7 @@ static int perf_ftrace_config(const char *var, const char *value, void *cb)
219 return -1; 307 return -1;
220} 308}
221 309
222int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused) 310int cmd_ftrace(int argc, const char **argv)
223{ 311{
224 int ret; 312 int ret;
225 struct perf_ftrace ftrace = { 313 struct perf_ftrace ftrace = {
@@ -227,15 +315,21 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
227 .target = { .uid = UINT_MAX, }, 315 .target = { .uid = UINT_MAX, },
228 }; 316 };
229 const char * const ftrace_usage[] = { 317 const char * const ftrace_usage[] = {
230 "perf ftrace [<options>] <command>", 318 "perf ftrace [<options>] [<command>]",
231 "perf ftrace [<options>] -- <command> [<options>]", 319 "perf ftrace [<options>] -- <command> [<options>]",
232 NULL 320 NULL
233 }; 321 };
234 const struct option ftrace_options[] = { 322 const struct option ftrace_options[] = {
235 OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", 323 OPT_STRING('t', "tracer", &ftrace.tracer, "tracer",
236 "tracer to use: function_graph(default) or function"), 324 "tracer to use: function_graph(default) or function"),
325 OPT_STRING('p', "pid", &ftrace.target.pid, "pid",
326 "trace on existing process id"),
237 OPT_INCR('v', "verbose", &verbose, 327 OPT_INCR('v', "verbose", &verbose,
238 "be more verbose"), 328 "be more verbose"),
329 OPT_BOOLEAN('a', "all-cpus", &ftrace.target.system_wide,
330 "system-wide collection from all CPUs"),
331 OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu",
332 "list of cpus to monitor"),
239 OPT_END() 333 OPT_END()
240 }; 334 };
241 335
@@ -245,9 +339,18 @@ int cmd_ftrace(int argc, const char **argv, const char *prefix __maybe_unused)
245 339
246 argc = parse_options(argc, argv, ftrace_options, ftrace_usage, 340 argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
247 PARSE_OPT_STOP_AT_NON_OPTION); 341 PARSE_OPT_STOP_AT_NON_OPTION);
248 if (!argc) 342 if (!argc && target__none(&ftrace.target))
249 usage_with_options(ftrace_usage, ftrace_options); 343 usage_with_options(ftrace_usage, ftrace_options);
250 344
345 ret = target__validate(&ftrace.target);
346 if (ret) {
347 char errbuf[512];
348
349 target__strerror(&ftrace.target, ret, errbuf, 512);
350 pr_err("%s\n", errbuf);
351 return -EINVAL;
352 }
353
251 ftrace.evlist = perf_evlist__new(); 354 ftrace.evlist = perf_evlist__new();
252 if (ftrace.evlist == NULL) 355 if (ftrace.evlist == NULL)
253 return -ENOMEM; 356 return -ENOMEM;
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index aed0d844e8c2..492f8e14ab09 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -12,16 +12,22 @@
12#include <subcmd/run-command.h> 12#include <subcmd/run-command.h>
13#include <subcmd/help.h> 13#include <subcmd/help.h>
14#include "util/debug.h" 14#include "util/debug.h"
15#include <linux/kernel.h>
16#include <errno.h>
17#include <stdio.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <unistd.h>
15 21
16static struct man_viewer_list { 22static struct man_viewer_list {
17 struct man_viewer_list *next; 23 struct man_viewer_list *next;
18 char name[FLEX_ARRAY]; 24 char name[0];
19} *man_viewer_list; 25} *man_viewer_list;
20 26
21static struct man_viewer_info_list { 27static struct man_viewer_info_list {
22 struct man_viewer_info_list *next; 28 struct man_viewer_info_list *next;
23 const char *info; 29 const char *info;
24 char name[FLEX_ARRAY]; 30 char name[0];
25} *man_viewer_info_list; 31} *man_viewer_info_list;
26 32
27enum help_format { 33enum help_format {
@@ -301,12 +307,6 @@ void list_common_cmds_help(void)
301 } 307 }
302} 308}
303 309
304static int is_perf_command(const char *s)
305{
306 return is_in_cmdlist(&main_cmds, s) ||
307 is_in_cmdlist(&other_cmds, s);
308}
309
310static const char *cmd_to_page(const char *perf_cmd) 310static const char *cmd_to_page(const char *perf_cmd)
311{ 311{
312 char *s; 312 char *s;
@@ -418,7 +418,7 @@ static int show_html_page(const char *perf_cmd)
418 return 0; 418 return 0;
419} 419}
420 420
421int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) 421int cmd_help(int argc, const char **argv)
422{ 422{
423 bool show_all = false; 423 bool show_all = false;
424 enum help_format help_format = HELP_FORMAT_MAN; 424 enum help_format help_format = HELP_FORMAT_MAN;
@@ -446,7 +446,6 @@ int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused)
446 "perf help [--all] [--man|--web|--info] [command]", 446 "perf help [--all] [--man|--web|--info] [command]",
447 NULL 447 NULL
448 }; 448 };
449 const char *alias;
450 int rc; 449 int rc;
451 450
452 load_command_list("perf-", &main_cmds, &other_cmds); 451 load_command_list("perf-", &main_cmds, &other_cmds);
@@ -472,12 +471,6 @@ int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused)
472 return 0; 471 return 0;
473 } 472 }
474 473
475 alias = alias_lookup(argv[0]);
476 if (alias && !is_perf_command(argv[0])) {
477 printf("`perf %s' is aliased to `%s'\n", argv[0], alias);
478 return 0;
479 }
480
481 switch (help_format) { 474 switch (help_format) {
482 case HELP_FORMAT_MAN: 475 case HELP_FORMAT_MAN:
483 rc = show_man_page(argv[0]); 476 rc = show_man_page(argv[0]);
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index b9bc7e39833a..ea8db38eedd1 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -18,10 +18,13 @@
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h" 19#include "util/auxtrace.h"
20#include "util/jit.h" 20#include "util/jit.h"
21#include "util/thread.h"
21 22
22#include <subcmd/parse-options.h> 23#include <subcmd/parse-options.h>
23 24
24#include <linux/list.h> 25#include <linux/list.h>
26#include <errno.h>
27#include <signal.h>
25 28
26struct perf_inject { 29struct perf_inject {
27 struct perf_tool tool; 30 struct perf_tool tool;
@@ -333,6 +336,18 @@ static int perf_event__repipe_comm(struct perf_tool *tool,
333 return err; 336 return err;
334} 337}
335 338
339static int perf_event__repipe_namespaces(struct perf_tool *tool,
340 union perf_event *event,
341 struct perf_sample *sample,
342 struct machine *machine)
343{
344 int err = perf_event__process_namespaces(tool, event, sample, machine);
345
346 perf_event__repipe(tool, event, sample, machine);
347
348 return err;
349}
350
336static int perf_event__repipe_exit(struct perf_tool *tool, 351static int perf_event__repipe_exit(struct perf_tool *tool,
337 union perf_event *event, 352 union perf_event *event,
338 struct perf_sample *sample, 353 struct perf_sample *sample,
@@ -660,6 +675,7 @@ static int __cmd_inject(struct perf_inject *inject)
660 session->itrace_synth_opts = &inject->itrace_synth_opts; 675 session->itrace_synth_opts = &inject->itrace_synth_opts;
661 inject->itrace_synth_opts.inject = true; 676 inject->itrace_synth_opts.inject = true;
662 inject->tool.comm = perf_event__repipe_comm; 677 inject->tool.comm = perf_event__repipe_comm;
678 inject->tool.namespaces = perf_event__repipe_namespaces;
663 inject->tool.exit = perf_event__repipe_exit; 679 inject->tool.exit = perf_event__repipe_exit;
664 inject->tool.id_index = perf_event__repipe_id_index; 680 inject->tool.id_index = perf_event__repipe_id_index;
665 inject->tool.auxtrace_info = perf_event__process_auxtrace_info; 681 inject->tool.auxtrace_info = perf_event__process_auxtrace_info;
@@ -681,6 +697,8 @@ static int __cmd_inject(struct perf_inject *inject)
681 lseek(fd, output_data_offset, SEEK_SET); 697 lseek(fd, output_data_offset, SEEK_SET);
682 698
683 ret = perf_session__process_events(session); 699 ret = perf_session__process_events(session);
700 if (ret)
701 return ret;
684 702
685 if (!file_out->is_pipe) { 703 if (!file_out->is_pipe) {
686 if (inject->build_ids) 704 if (inject->build_ids)
@@ -725,7 +743,7 @@ static int __cmd_inject(struct perf_inject *inject)
725 return ret; 743 return ret;
726} 744}
727 745
728int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) 746int cmd_inject(int argc, const char **argv)
729{ 747{
730 struct perf_inject inject = { 748 struct perf_inject inject = {
731 .tool = { 749 .tool = {
diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c
index 224bfc454b4a..bcfb363112d3 100644
--- a/tools/perf/builtin-kallsyms.c
+++ b/tools/perf/builtin-kallsyms.c
@@ -7,6 +7,7 @@
7 * 7 *
8 * Released under the GPL v2. (and only v2, not any later version) 8 * Released under the GPL v2. (and only v2, not any later version)
9 */ 9 */
10#include <inttypes.h>
10#include "builtin.h" 11#include "builtin.h"
11#include <linux/compiler.h> 12#include <linux/compiler.h>
12#include <subcmd/parse-options.h> 13#include <subcmd/parse-options.h>
@@ -43,7 +44,7 @@ static int __cmd_kallsyms(int argc, const char **argv)
43 return 0; 44 return 0;
44} 45}
45 46
46int cmd_kallsyms(int argc, const char **argv, const char *prefix __maybe_unused) 47int cmd_kallsyms(int argc, const char **argv)
47{ 48{
48 const struct option options[] = { 49 const struct option options[] = {
49 OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), 50 OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"),
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 6da8d083e4e5..9409c9464667 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -20,11 +20,16 @@
20 20
21#include "util/debug.h" 21#include "util/debug.h"
22 22
23#include <linux/kernel.h>
23#include <linux/rbtree.h> 24#include <linux/rbtree.h>
24#include <linux/string.h> 25#include <linux/string.h>
26#include <errno.h>
27#include <inttypes.h>
25#include <locale.h> 28#include <locale.h>
26#include <regex.h> 29#include <regex.h>
27 30
31#include "sane_ctype.h"
32
28static int kmem_slab; 33static int kmem_slab;
29static int kmem_page; 34static int kmem_page;
30 35
@@ -964,6 +969,7 @@ static struct perf_tool perf_kmem = {
964 .comm = perf_event__process_comm, 969 .comm = perf_event__process_comm,
965 .mmap = perf_event__process_mmap, 970 .mmap = perf_event__process_mmap,
966 .mmap2 = perf_event__process_mmap2, 971 .mmap2 = perf_event__process_mmap2,
972 .namespaces = perf_event__process_namespaces,
967 .ordered_events = true, 973 .ordered_events = true,
968}; 974};
969 975
@@ -1865,7 +1871,7 @@ static int __cmd_record(int argc, const char **argv)
1865 for (j = 1; j < (unsigned int)argc; j++, i++) 1871 for (j = 1; j < (unsigned int)argc; j++, i++)
1866 rec_argv[i] = argv[j]; 1872 rec_argv[i] = argv[j];
1867 1873
1868 return cmd_record(i, rec_argv, NULL); 1874 return cmd_record(i, rec_argv);
1869} 1875}
1870 1876
1871static int kmem_config(const char *var, const char *value, void *cb __maybe_unused) 1877static int kmem_config(const char *var, const char *value, void *cb __maybe_unused)
@@ -1884,7 +1890,7 @@ static int kmem_config(const char *var, const char *value, void *cb __maybe_unus
1884 return 0; 1890 return 0;
1885} 1891}
1886 1892
1887int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) 1893int cmd_kmem(int argc, const char **argv)
1888{ 1894{
1889 const char * const default_slab_sort = "frag,hit,bytes"; 1895 const char * const default_slab_sort = "frag,hit,bytes";
1890 const char * const default_page_sort = "bytes,hit"; 1896 const char * const default_page_sort = "bytes,hit";
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 08fa88f62a24..f309c3773522 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -3,6 +3,7 @@
3 3
4#include "util/evsel.h" 4#include "util/evsel.h"
5#include "util/evlist.h" 5#include "util/evlist.h"
6#include "util/term.h"
6#include "util/util.h" 7#include "util/util.h"
7#include "util/cache.h" 8#include "util/cache.h"
8#include "util/symbol.h" 9#include "util/symbol.h"
@@ -23,13 +24,33 @@
23#ifdef HAVE_TIMERFD_SUPPORT 24#ifdef HAVE_TIMERFD_SUPPORT
24#include <sys/timerfd.h> 25#include <sys/timerfd.h>
25#endif 26#endif
27#include <sys/time.h>
26 28
29#include <linux/kernel.h>
27#include <linux/time64.h> 30#include <linux/time64.h>
31#include <errno.h>
32#include <inttypes.h>
33#include <poll.h>
28#include <termios.h> 34#include <termios.h>
29#include <semaphore.h> 35#include <semaphore.h>
36#include <signal.h>
30#include <pthread.h> 37#include <pthread.h>
31#include <math.h> 38#include <math.h>
32 39
40static const char *get_filename_for_perf_kvm(void)
41{
42 const char *filename;
43
44 if (perf_host && !perf_guest)
45 filename = strdup("perf.data.host");
46 else if (!perf_host && perf_guest)
47 filename = strdup("perf.data.guest");
48 else
49 filename = strdup("perf.data.kvm");
50
51 return filename;
52}
53
33#ifdef HAVE_KVM_STAT_SUPPORT 54#ifdef HAVE_KVM_STAT_SUPPORT
34#include "util/kvm-stat.h" 55#include "util/kvm-stat.h"
35 56
@@ -1044,6 +1065,7 @@ static int read_events(struct perf_kvm_stat *kvm)
1044 struct perf_tool eops = { 1065 struct perf_tool eops = {
1045 .sample = process_sample_event, 1066 .sample = process_sample_event,
1046 .comm = perf_event__process_comm, 1067 .comm = perf_event__process_comm,
1068 .namespaces = perf_event__process_namespaces,
1047 .ordered_events = true, 1069 .ordered_events = true,
1048 }; 1070 };
1049 struct perf_data_file file = { 1071 struct perf_data_file file = {
@@ -1208,7 +1230,7 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1208 set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED); 1230 set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED);
1209 1231
1210 record_usage = kvm_stat_record_usage; 1232 record_usage = kvm_stat_record_usage;
1211 return cmd_record(i, rec_argv, NULL); 1233 return cmd_record(i, rec_argv);
1212} 1234}
1213 1235
1214static int 1236static int
@@ -1348,6 +1370,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1348 kvm->tool.exit = perf_event__process_exit; 1370 kvm->tool.exit = perf_event__process_exit;
1349 kvm->tool.fork = perf_event__process_fork; 1371 kvm->tool.fork = perf_event__process_fork;
1350 kvm->tool.lost = process_lost_event; 1372 kvm->tool.lost = process_lost_event;
1373 kvm->tool.namespaces = perf_event__process_namespaces;
1351 kvm->tool.ordered_events = true; 1374 kvm->tool.ordered_events = true;
1352 perf_tool__fill_defaults(&kvm->tool); 1375 perf_tool__fill_defaults(&kvm->tool);
1353 1376
@@ -1475,7 +1498,7 @@ static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
1475#endif 1498#endif
1476 1499
1477perf_stat: 1500perf_stat:
1478 return cmd_stat(argc, argv, NULL); 1501 return cmd_stat(argc, argv);
1479} 1502}
1480#endif /* HAVE_KVM_STAT_SUPPORT */ 1503#endif /* HAVE_KVM_STAT_SUPPORT */
1481 1504
@@ -1494,7 +1517,7 @@ static int __cmd_record(const char *file_name, int argc, const char **argv)
1494 1517
1495 BUG_ON(i != rec_argc); 1518 BUG_ON(i != rec_argc);
1496 1519
1497 return cmd_record(i, rec_argv, NULL); 1520 return cmd_record(i, rec_argv);
1498} 1521}
1499 1522
1500static int __cmd_report(const char *file_name, int argc, const char **argv) 1523static int __cmd_report(const char *file_name, int argc, const char **argv)
@@ -1512,7 +1535,7 @@ static int __cmd_report(const char *file_name, int argc, const char **argv)
1512 1535
1513 BUG_ON(i != rec_argc); 1536 BUG_ON(i != rec_argc);
1514 1537
1515 return cmd_report(i, rec_argv, NULL); 1538 return cmd_report(i, rec_argv);
1516} 1539}
1517 1540
1518static int 1541static int
@@ -1531,10 +1554,10 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)
1531 1554
1532 BUG_ON(i != rec_argc); 1555 BUG_ON(i != rec_argc);
1533 1556
1534 return cmd_buildid_list(i, rec_argv, NULL); 1557 return cmd_buildid_list(i, rec_argv);
1535} 1558}
1536 1559
1537int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) 1560int cmd_kvm(int argc, const char **argv)
1538{ 1561{
1539 const char *file_name = NULL; 1562 const char *file_name = NULL;
1540 const struct option kvm_options[] = { 1563 const struct option kvm_options[] = {
@@ -1589,9 +1612,9 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1589 else if (!strncmp(argv[0], "rep", 3)) 1612 else if (!strncmp(argv[0], "rep", 3))
1590 return __cmd_report(file_name, argc, argv); 1613 return __cmd_report(file_name, argc, argv);
1591 else if (!strncmp(argv[0], "diff", 4)) 1614 else if (!strncmp(argv[0], "diff", 4))
1592 return cmd_diff(argc, argv, NULL); 1615 return cmd_diff(argc, argv);
1593 else if (!strncmp(argv[0], "top", 3)) 1616 else if (!strncmp(argv[0], "top", 3))
1594 return cmd_top(argc, argv, NULL); 1617 return cmd_top(argc, argv);
1595 else if (!strncmp(argv[0], "buildid-list", 12)) 1618 else if (!strncmp(argv[0], "buildid-list", 12))
1596 return __cmd_buildid_list(file_name, argc, argv); 1619 return __cmd_buildid_list(file_name, argc, argv);
1597#ifdef HAVE_KVM_STAT_SUPPORT 1620#ifdef HAVE_KVM_STAT_SUPPORT
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 3b9d98b5feef..4bf2cb4d25aa 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -18,8 +18,9 @@
18#include <subcmd/parse-options.h> 18#include <subcmd/parse-options.h>
19 19
20static bool desc_flag = true; 20static bool desc_flag = true;
21static bool details_flag;
21 22
22int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 23int cmd_list(int argc, const char **argv)
23{ 24{
24 int i; 25 int i;
25 bool raw_dump = false; 26 bool raw_dump = false;
@@ -30,6 +31,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
30 "Print extra event descriptions. --no-desc to not print."), 31 "Print extra event descriptions. --no-desc to not print."),
31 OPT_BOOLEAN('v', "long-desc", &long_desc_flag, 32 OPT_BOOLEAN('v', "long-desc", &long_desc_flag,
32 "Print longer event descriptions."), 33 "Print longer event descriptions."),
34 OPT_BOOLEAN(0, "details", &details_flag,
35 "Print information on the perf event names and expressions used internally by events."),
33 OPT_INCR(0, "debug", &verbose, 36 OPT_INCR(0, "debug", &verbose,
34 "Enable debugging output"), 37 "Enable debugging output"),
35 OPT_END() 38 OPT_END()
@@ -50,7 +53,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
50 printf("\nList of pre-defined events (to be used in -e):\n\n"); 53 printf("\nList of pre-defined events (to be used in -e):\n\n");
51 54
52 if (argc == 0) { 55 if (argc == 0) {
53 print_events(NULL, raw_dump, !desc_flag, long_desc_flag); 56 print_events(NULL, raw_dump, !desc_flag, long_desc_flag,
57 details_flag);
54 return 0; 58 return 0;
55 } 59 }
56 60
@@ -72,7 +76,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
72 print_hwcache_events(NULL, raw_dump); 76 print_hwcache_events(NULL, raw_dump);
73 else if (strcmp(argv[i], "pmu") == 0) 77 else if (strcmp(argv[i], "pmu") == 0)
74 print_pmu_events(NULL, raw_dump, !desc_flag, 78 print_pmu_events(NULL, raw_dump, !desc_flag,
75 long_desc_flag); 79 long_desc_flag, details_flag);
76 else if (strcmp(argv[i], "sdt") == 0) 80 else if (strcmp(argv[i], "sdt") == 0)
77 print_sdt_events(NULL, NULL, raw_dump); 81 print_sdt_events(NULL, NULL, raw_dump);
78 else if ((sep = strchr(argv[i], ':')) != NULL) { 82 else if ((sep = strchr(argv[i], ':')) != NULL) {
@@ -80,7 +84,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
80 84
81 if (sep == NULL) { 85 if (sep == NULL) {
82 print_events(argv[i], raw_dump, !desc_flag, 86 print_events(argv[i], raw_dump, !desc_flag,
83 long_desc_flag); 87 long_desc_flag,
88 details_flag);
84 continue; 89 continue;
85 } 90 }
86 sep_idx = sep - argv[i]; 91 sep_idx = sep - argv[i];
@@ -103,7 +108,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
103 event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); 108 event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump);
104 print_hwcache_events(s, raw_dump); 109 print_hwcache_events(s, raw_dump);
105 print_pmu_events(s, raw_dump, !desc_flag, 110 print_pmu_events(s, raw_dump, !desc_flag,
106 long_desc_flag); 111 long_desc_flag,
112 details_flag);
107 print_tracepoint_events(NULL, s, raw_dump); 113 print_tracepoint_events(NULL, s, raw_dump);
108 print_sdt_events(NULL, s, raw_dump); 114 print_sdt_events(NULL, s, raw_dump);
109 free(s); 115 free(s);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index ce3bfb48b26f..ff98652484a7 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1,3 +1,5 @@
1#include <errno.h>
2#include <inttypes.h>
1#include "builtin.h" 3#include "builtin.h"
2#include "perf.h" 4#include "perf.h"
3 5
@@ -26,6 +28,7 @@
26 28
27#include <linux/list.h> 29#include <linux/list.h>
28#include <linux/hash.h> 30#include <linux/hash.h>
31#include <linux/kernel.h>
29 32
30static struct perf_session *session; 33static struct perf_session *session;
31 34
@@ -858,6 +861,7 @@ static int __cmd_report(bool display_info)
858 struct perf_tool eops = { 861 struct perf_tool eops = {
859 .sample = process_sample_event, 862 .sample = process_sample_event,
860 .comm = perf_event__process_comm, 863 .comm = perf_event__process_comm,
864 .namespaces = perf_event__process_namespaces,
861 .ordered_events = true, 865 .ordered_events = true,
862 }; 866 };
863 struct perf_data_file file = { 867 struct perf_data_file file = {
@@ -940,34 +944,36 @@ static int __cmd_record(int argc, const char **argv)
940 944
941 BUG_ON(i != rec_argc); 945 BUG_ON(i != rec_argc);
942 946
943 ret = cmd_record(i, rec_argv, NULL); 947 ret = cmd_record(i, rec_argv);
944 free(rec_argv); 948 free(rec_argv);
945 return ret; 949 return ret;
946} 950}
947 951
948int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) 952int cmd_lock(int argc, const char **argv)
949{ 953{
950 const struct option info_options[] = {
951 OPT_BOOLEAN('t', "threads", &info_threads,
952 "dump thread list in perf.data"),
953 OPT_BOOLEAN('m', "map", &info_map,
954 "map of lock instances (address:name table)"),
955 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
956 OPT_END()
957 };
958 const struct option lock_options[] = { 954 const struct option lock_options[] = {
959 OPT_STRING('i', "input", &input_name, "file", "input file name"), 955 OPT_STRING('i', "input", &input_name, "file", "input file name"),
960 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), 956 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
961 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), 957 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
958 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
962 OPT_END() 959 OPT_END()
963 }; 960 };
961
962 const struct option info_options[] = {
963 OPT_BOOLEAN('t', "threads", &info_threads,
964 "dump thread list in perf.data"),
965 OPT_BOOLEAN('m', "map", &info_map,
966 "map of lock instances (address:name table)"),
967 OPT_PARENT(lock_options)
968 };
969
964 const struct option report_options[] = { 970 const struct option report_options[] = {
965 OPT_STRING('k', "key", &sort_key, "acquired", 971 OPT_STRING('k', "key", &sort_key, "acquired",
966 "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"), 972 "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
967 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
968 /* TODO: type */ 973 /* TODO: type */
969 OPT_END() 974 OPT_PARENT(lock_options)
970 }; 975 };
976
971 const char * const info_usage[] = { 977 const char * const info_usage[] = {
972 "perf lock info [<options>]", 978 "perf lock info [<options>]",
973 NULL 979 NULL
@@ -1006,7 +1012,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
1006 rc = __cmd_report(false); 1012 rc = __cmd_report(false);
1007 } else if (!strcmp(argv[0], "script")) { 1013 } else if (!strcmp(argv[0], "script")) {
1008 /* Aliased to 'perf script' */ 1014 /* Aliased to 'perf script' */
1009 return cmd_script(argc, argv, prefix); 1015 return cmd_script(argc, argv);
1010 } else if (!strcmp(argv[0], "info")) { 1016 } else if (!strcmp(argv[0], "info")) {
1011 if (argc) { 1017 if (argc) {
1012 argc = parse_options(argc, argv, 1018 argc = parse_options(argc, argv,
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 6114e07ca613..e001c0290793 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -1,3 +1,7 @@
1#include <inttypes.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <unistd.h>
1#include "builtin.h" 5#include "builtin.h"
2#include "perf.h" 6#include "perf.h"
3 7
@@ -8,6 +12,7 @@
8#include "util/data.h" 12#include "util/data.h"
9#include "util/mem-events.h" 13#include "util/mem-events.h"
10#include "util/debug.h" 14#include "util/debug.h"
15#include "util/symbol.h"
11 16
12#define MEM_OPERATION_LOAD 0x1 17#define MEM_OPERATION_LOAD 0x1
13#define MEM_OPERATION_STORE 0x2 18#define MEM_OPERATION_STORE 0x2
@@ -129,7 +134,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
129 pr_debug("\n"); 134 pr_debug("\n");
130 } 135 }
131 136
132 ret = cmd_record(i, rec_argv, NULL); 137 ret = cmd_record(i, rec_argv);
133 free(rec_argv); 138 free(rec_argv);
134 return ret; 139 return ret;
135} 140}
@@ -256,7 +261,7 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem)
256 for (j = 1; j < argc; j++, i++) 261 for (j = 1; j < argc; j++, i++)
257 rep_argv[i] = argv[j]; 262 rep_argv[i] = argv[j];
258 263
259 ret = cmd_report(i, rep_argv, NULL); 264 ret = cmd_report(i, rep_argv);
260 free(rep_argv); 265 free(rep_argv);
261 return ret; 266 return ret;
262} 267}
@@ -330,7 +335,7 @@ error:
330 return ret; 335 return ret;
331} 336}
332 337
333int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) 338int cmd_mem(int argc, const char **argv)
334{ 339{
335 struct stat st; 340 struct stat st;
336 struct perf_mem mem = { 341 struct perf_mem mem = {
@@ -342,6 +347,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
342 .lost = perf_event__process_lost, 347 .lost = perf_event__process_lost,
343 .fork = perf_event__process_fork, 348 .fork = perf_event__process_fork,
344 .build_id = perf_event__process_build_id, 349 .build_id = perf_event__process_build_id,
350 .namespaces = perf_event__process_namespaces,
345 .ordered_events = true, 351 .ordered_events = true,
346 }, 352 },
347 .input_name = "perf.data", 353 .input_name = "perf.data",
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 1fcebc31a508..cf9f9e9c2fc0 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -442,9 +442,9 @@ static int perf_del_probe_events(struct strfilter *filter)
442 } 442 }
443 443
444 if (ret == -ENOENT && ret2 == -ENOENT) 444 if (ret == -ENOENT && ret2 == -ENOENT)
445 pr_debug("\"%s\" does not hit any event.\n", str); 445 pr_warning("\"%s\" does not hit any event.\n", str);
446 /* Note that this is silently ignored */ 446 else
447 ret = 0; 447 ret = 0;
448 448
449error: 449error:
450 if (kfd >= 0) 450 if (kfd >= 0)
@@ -468,7 +468,7 @@ out:
468 468
469 469
470static int 470static int
471__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 471__cmd_probe(int argc, const char **argv)
472{ 472{
473 const char * const probe_usage[] = { 473 const char * const probe_usage[] = {
474 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 474 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
@@ -486,7 +486,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
486 OPT_INCR('v', "verbose", &verbose, 486 OPT_INCR('v', "verbose", &verbose,
487 "be more verbose (show parsed arguments, etc)"), 487 "be more verbose (show parsed arguments, etc)"),
488 OPT_BOOLEAN('q', "quiet", &params.quiet, 488 OPT_BOOLEAN('q', "quiet", &params.quiet,
489 "be quiet (do not show any mesages)"), 489 "be quiet (do not show any messages)"),
490 OPT_CALLBACK_DEFAULT('l', "list", NULL, "[GROUP:]EVENT", 490 OPT_CALLBACK_DEFAULT('l', "list", NULL, "[GROUP:]EVENT",
491 "list up probe events", 491 "list up probe events",
492 opt_set_filter_with_command, DEFAULT_LIST_FILTER), 492 opt_set_filter_with_command, DEFAULT_LIST_FILTER),
@@ -687,13 +687,13 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
687 return 0; 687 return 0;
688} 688}
689 689
690int cmd_probe(int argc, const char **argv, const char *prefix) 690int cmd_probe(int argc, const char **argv)
691{ 691{
692 int ret; 692 int ret;
693 693
694 ret = init_params(); 694 ret = init_params();
695 if (!ret) { 695 if (!ret) {
696 ret = __cmd_probe(argc, argv, prefix); 696 ret = __cmd_probe(argc, argv);
697 cleanup_params(); 697 cleanup_params();
698 } 698 }
699 699
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index bc84a375295d..ee7d0a82ccd0 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -38,11 +38,18 @@
38#include "util/bpf-loader.h" 38#include "util/bpf-loader.h"
39#include "util/trigger.h" 39#include "util/trigger.h"
40#include "util/perf-hooks.h" 40#include "util/perf-hooks.h"
41#include "util/time-utils.h"
42#include "util/units.h"
41#include "asm/bug.h" 43#include "asm/bug.h"
42 44
45#include <errno.h>
46#include <inttypes.h>
47#include <poll.h>
43#include <unistd.h> 48#include <unistd.h>
44#include <sched.h> 49#include <sched.h>
50#include <signal.h>
45#include <sys/mman.h> 51#include <sys/mman.h>
52#include <sys/wait.h>
46#include <asm/bug.h> 53#include <asm/bug.h>
47#include <linux/time64.h> 54#include <linux/time64.h>
48 55
@@ -876,6 +883,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
876 signal(SIGTERM, sig_handler); 883 signal(SIGTERM, sig_handler);
877 signal(SIGSEGV, sigsegv_handler); 884 signal(SIGSEGV, sigsegv_handler);
878 885
886 if (rec->opts.record_namespaces)
887 tool->namespace_events = true;
888
879 if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) { 889 if (rec->opts.auxtrace_snapshot_mode || rec->switch_output.enabled) {
880 signal(SIGUSR2, snapshot_sig_handler); 890 signal(SIGUSR2, snapshot_sig_handler);
881 if (rec->opts.auxtrace_snapshot_mode) 891 if (rec->opts.auxtrace_snapshot_mode)
@@ -983,6 +993,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
983 */ 993 */
984 if (forks) { 994 if (forks) {
985 union perf_event *event; 995 union perf_event *event;
996 pid_t tgid;
986 997
987 event = malloc(sizeof(event->comm) + machine->id_hdr_size); 998 event = malloc(sizeof(event->comm) + machine->id_hdr_size);
988 if (event == NULL) { 999 if (event == NULL) {
@@ -996,10 +1007,30 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
996 * cannot see a correct process name for those events. 1007 * cannot see a correct process name for those events.
997 * Synthesize COMM event to prevent it. 1008 * Synthesize COMM event to prevent it.
998 */ 1009 */
999 perf_event__synthesize_comm(tool, event, 1010 tgid = perf_event__synthesize_comm(tool, event,
1000 rec->evlist->workload.pid, 1011 rec->evlist->workload.pid,
1001 process_synthesized_event, 1012 process_synthesized_event,
1002 machine); 1013 machine);
1014 free(event);
1015
1016 if (tgid == -1)
1017 goto out_child;
1018
1019 event = malloc(sizeof(event->namespaces) +
1020 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
1021 machine->id_hdr_size);
1022 if (event == NULL) {
1023 err = -ENOMEM;
1024 goto out_child;
1025 }
1026
1027 /*
1028 * Synthesize NAMESPACES event for the command specified.
1029 */
1030 perf_event__synthesize_namespaces(tool, event,
1031 rec->evlist->workload.pid,
1032 tgid, process_synthesized_event,
1033 machine);
1003 free(event); 1034 free(event);
1004 1035
1005 perf_evlist__start_workload(rec->evlist); 1036 perf_evlist__start_workload(rec->evlist);
@@ -1497,6 +1528,7 @@ static struct record record = {
1497 .fork = perf_event__process_fork, 1528 .fork = perf_event__process_fork,
1498 .exit = perf_event__process_exit, 1529 .exit = perf_event__process_exit,
1499 .comm = perf_event__process_comm, 1530 .comm = perf_event__process_comm,
1531 .namespaces = perf_event__process_namespaces,
1500 .mmap = perf_event__process_mmap, 1532 .mmap = perf_event__process_mmap,
1501 .mmap2 = perf_event__process_mmap2, 1533 .mmap2 = perf_event__process_mmap2,
1502 .ordered_events = true, 1534 .ordered_events = true,
@@ -1611,6 +1643,8 @@ static struct option __record_options[] = {
1611 "opts", "AUX area tracing Snapshot Mode", ""), 1643 "opts", "AUX area tracing Snapshot Mode", ""),
1612 OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout, 1644 OPT_UINTEGER(0, "proc-map-timeout", &record.opts.proc_map_timeout,
1613 "per thread proc mmap processing timeout in ms"), 1645 "per thread proc mmap processing timeout in ms"),
1646 OPT_BOOLEAN(0, "namespaces", &record.opts.record_namespaces,
1647 "Record namespaces events"),
1614 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1648 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1615 "Record context switch events"), 1649 "Record context switch events"),
1616 OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel, 1650 OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
@@ -1640,7 +1674,7 @@ static struct option __record_options[] = {
1640 1674
1641struct option *record_options = __record_options; 1675struct option *record_options = __record_options;
1642 1676
1643int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 1677int cmd_record(int argc, const char **argv)
1644{ 1678{
1645 int err; 1679 int err;
1646 struct record *rec = &record; 1680 struct record *rec = &record;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0a88670e56f3..22478ff2b706 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -16,7 +16,6 @@
16#include <linux/rbtree.h> 16#include <linux/rbtree.h>
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/callchain.h" 18#include "util/callchain.h"
19#include "util/strlist.h"
20#include "util/values.h" 19#include "util/values.h"
21 20
22#include "perf.h" 21#include "perf.h"
@@ -38,10 +37,18 @@
38#include "arch/common.h" 37#include "arch/common.h"
39#include "util/time-utils.h" 38#include "util/time-utils.h"
40#include "util/auxtrace.h" 39#include "util/auxtrace.h"
40#include "util/units.h"
41 41
42#include <dlfcn.h> 42#include <dlfcn.h>
43#include <errno.h>
44#include <inttypes.h>
45#include <regex.h>
46#include <signal.h>
43#include <linux/bitmap.h> 47#include <linux/bitmap.h>
44#include <linux/stringify.h> 48#include <linux/stringify.h>
49#include <sys/types.h>
50#include <sys/stat.h>
51#include <unistd.h>
45 52
46struct report { 53struct report {
47 struct perf_tool tool; 54 struct perf_tool tool;
@@ -394,8 +401,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
394 fprintf(stdout, "\n\n"); 401 fprintf(stdout, "\n\n");
395 } 402 }
396 403
397 if (sort_order == NULL && 404 if (!quiet)
398 parent_pattern == default_parent_pattern)
399 fprintf(stdout, "#\n# (%s)\n#\n", help); 405 fprintf(stdout, "#\n# (%s)\n#\n", help);
400 406
401 if (rep->show_threads) { 407 if (rep->show_threads) {
@@ -682,7 +688,7 @@ const char report_callchain_help[] = "Display call graph (stack chain/backtrace)
682 CALLCHAIN_REPORT_HELP 688 CALLCHAIN_REPORT_HELP
683 "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; 689 "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
684 690
685int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) 691int cmd_report(int argc, const char **argv)
686{ 692{
687 struct perf_session *session; 693 struct perf_session *session;
688 struct itrace_synth_opts itrace_synth_opts = { .set = 0, }; 694 struct itrace_synth_opts itrace_synth_opts = { .set = 0, };
@@ -701,6 +707,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
701 .mmap = perf_event__process_mmap, 707 .mmap = perf_event__process_mmap,
702 .mmap2 = perf_event__process_mmap2, 708 .mmap2 = perf_event__process_mmap2,
703 .comm = perf_event__process_comm, 709 .comm = perf_event__process_comm,
710 .namespaces = perf_event__process_namespaces,
704 .exit = perf_event__process_exit, 711 .exit = perf_event__process_exit,
705 .fork = perf_event__process_fork, 712 .fork = perf_event__process_fork,
706 .lost = perf_event__process_lost, 713 .lost = perf_event__process_lost,
@@ -845,6 +852,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
845 stdio__config_color, "always"), 852 stdio__config_color, "always"),
846 OPT_STRING(0, "time", &report.time_str, "str", 853 OPT_STRING(0, "time", &report.time_str, "str",
847 "Time span of interest (start,stop)"), 854 "Time span of interest (start,stop)"),
855 OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,
856 "Show inline function"),
848 OPT_END() 857 OPT_END()
849 }; 858 };
850 struct perf_data_file file = { 859 struct perf_data_file file = {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index b94cf0de715a..39996c53995a 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -22,16 +22,21 @@
22 22
23#include "util/debug.h" 23#include "util/debug.h"
24 24
25#include <linux/kernel.h>
25#include <linux/log2.h> 26#include <linux/log2.h>
26#include <sys/prctl.h> 27#include <sys/prctl.h>
27#include <sys/resource.h> 28#include <sys/resource.h>
29#include <inttypes.h>
28 30
31#include <errno.h>
29#include <semaphore.h> 32#include <semaphore.h>
30#include <pthread.h> 33#include <pthread.h>
31#include <math.h> 34#include <math.h>
32#include <api/fs/fs.h> 35#include <api/fs/fs.h>
33#include <linux/time64.h> 36#include <linux/time64.h>
34 37
38#include "sane_ctype.h"
39
35#define PR_SET_NAME 15 /* Set process name */ 40#define PR_SET_NAME 15 /* Set process name */
36#define MAX_CPUS 4096 41#define MAX_CPUS 4096
37#define COMM_LEN 20 42#define COMM_LEN 20
@@ -221,6 +226,7 @@ struct perf_sched {
221 unsigned int max_stack; 226 unsigned int max_stack;
222 bool show_cpu_visual; 227 bool show_cpu_visual;
223 bool show_wakeups; 228 bool show_wakeups;
229 bool show_next;
224 bool show_migrations; 230 bool show_migrations;
225 bool show_state; 231 bool show_state;
226 u64 skipped_samples; 232 u64 skipped_samples;
@@ -1897,14 +1903,18 @@ static char task_state_char(struct thread *thread, int state)
1897} 1903}
1898 1904
1899static void timehist_print_sample(struct perf_sched *sched, 1905static void timehist_print_sample(struct perf_sched *sched,
1906 struct perf_evsel *evsel,
1900 struct perf_sample *sample, 1907 struct perf_sample *sample,
1901 struct addr_location *al, 1908 struct addr_location *al,
1902 struct thread *thread, 1909 struct thread *thread,
1903 u64 t, int state) 1910 u64 t, int state)
1904{ 1911{
1905 struct thread_runtime *tr = thread__priv(thread); 1912 struct thread_runtime *tr = thread__priv(thread);
1913 const char *next_comm = perf_evsel__strval(evsel, sample, "next_comm");
1914 const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1906 u32 max_cpus = sched->max_cpu + 1; 1915 u32 max_cpus = sched->max_cpu + 1;
1907 char tstr[64]; 1916 char tstr[64];
1917 char nstr[30];
1908 u64 wait_time; 1918 u64 wait_time;
1909 1919
1910 timestamp__scnprintf_usec(t, tstr, sizeof(tstr)); 1920 timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
@@ -1937,7 +1947,12 @@ static void timehist_print_sample(struct perf_sched *sched,
1937 if (sched->show_state) 1947 if (sched->show_state)
1938 printf(" %5c ", task_state_char(thread, state)); 1948 printf(" %5c ", task_state_char(thread, state));
1939 1949
1940 if (sched->show_wakeups) 1950 if (sched->show_next) {
1951 snprintf(nstr, sizeof(nstr), "next: %s[%d]", next_comm, next_pid);
1952 printf(" %-*s", comm_width, nstr);
1953 }
1954
1955 if (sched->show_wakeups && !sched->show_next)
1941 printf(" %-*s", comm_width, ""); 1956 printf(" %-*s", comm_width, "");
1942 1957
1943 if (thread->tid == 0) 1958 if (thread->tid == 0)
@@ -2531,7 +2546,7 @@ static int timehist_sched_change_event(struct perf_tool *tool,
2531 } 2546 }
2532 2547
2533 if (!sched->summary_only) 2548 if (!sched->summary_only)
2534 timehist_print_sample(sched, sample, &al, thread, t, state); 2549 timehist_print_sample(sched, evsel, sample, &al, thread, t, state);
2535 2550
2536out: 2551out:
2537 if (sched->hist_time.start == 0 && t >= ptime->start) 2552 if (sched->hist_time.start == 0 && t >= ptime->start)
@@ -3262,16 +3277,17 @@ static int __cmd_record(int argc, const char **argv)
3262 3277
3263 BUG_ON(i != rec_argc); 3278 BUG_ON(i != rec_argc);
3264 3279
3265 return cmd_record(i, rec_argv, NULL); 3280 return cmd_record(i, rec_argv);
3266} 3281}
3267 3282
3268int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) 3283int cmd_sched(int argc, const char **argv)
3269{ 3284{
3270 const char default_sort_order[] = "avg, max, switch, runtime"; 3285 const char default_sort_order[] = "avg, max, switch, runtime";
3271 struct perf_sched sched = { 3286 struct perf_sched sched = {
3272 .tool = { 3287 .tool = {
3273 .sample = perf_sched__process_tracepoint_sample, 3288 .sample = perf_sched__process_tracepoint_sample,
3274 .comm = perf_event__process_comm, 3289 .comm = perf_event__process_comm,
3290 .namespaces = perf_event__process_namespaces,
3275 .lost = perf_event__process_lost, 3291 .lost = perf_event__process_lost,
3276 .fork = perf_sched__process_fork_event, 3292 .fork = perf_sched__process_fork_event,
3277 .ordered_events = true, 3293 .ordered_events = true,
@@ -3340,6 +3356,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3340 OPT_BOOLEAN('S', "with-summary", &sched.summary, 3356 OPT_BOOLEAN('S', "with-summary", &sched.summary,
3341 "Show all syscalls and summary with statistics"), 3357 "Show all syscalls and summary with statistics"),
3342 OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"), 3358 OPT_BOOLEAN('w', "wakeups", &sched.show_wakeups, "Show wakeup events"),
3359 OPT_BOOLEAN('n', "next", &sched.show_next, "Show next task"),
3343 OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"), 3360 OPT_BOOLEAN('M', "migrations", &sched.show_migrations, "Show migration events"),
3344 OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"), 3361 OPT_BOOLEAN('V', "cpu-visual", &sched.show_cpu_visual, "Add CPU visual"),
3345 OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"), 3362 OPT_BOOLEAN('I', "idle-hist", &sched.idle_hist, "Show idle events only"),
@@ -3400,7 +3417,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3400 * Aliased to 'perf script' for now: 3417 * Aliased to 'perf script' for now:
3401 */ 3418 */
3402 if (!strcmp(argv[0], "script")) 3419 if (!strcmp(argv[0], "script"))
3403 return cmd_script(argc, argv, prefix); 3420 return cmd_script(argc, argv);
3404 3421
3405 if (!strncmp(argv[0], "rec", 3)) { 3422 if (!strncmp(argv[0], "rec", 3)) {
3406 return __cmd_record(argc, argv); 3423 return __cmd_record(argc, argv);
@@ -3437,10 +3454,14 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
3437 if (argc) 3454 if (argc)
3438 usage_with_options(timehist_usage, timehist_options); 3455 usage_with_options(timehist_usage, timehist_options);
3439 } 3456 }
3440 if (sched.show_wakeups && sched.summary_only) { 3457 if ((sched.show_wakeups || sched.show_next) &&
3441 pr_err(" Error: -s and -w are mutually exclusive.\n"); 3458 sched.summary_only) {
3459 pr_err(" Error: -s and -[n|w] are mutually exclusive.\n");
3442 parse_options_usage(timehist_usage, timehist_options, "s", true); 3460 parse_options_usage(timehist_usage, timehist_options, "s", true);
3443 parse_options_usage(NULL, timehist_options, "w", true); 3461 if (sched.show_wakeups)
3462 parse_options_usage(NULL, timehist_options, "w", true);
3463 if (sched.show_next)
3464 parse_options_usage(NULL, timehist_options, "n", true);
3444 return -EINVAL; 3465 return -EINVAL;
3445 } 3466 }
3446 3467
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c0783b4f7b6c..d05aec491cff 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -21,13 +21,27 @@
21#include "util/cpumap.h" 21#include "util/cpumap.h"
22#include "util/thread_map.h" 22#include "util/thread_map.h"
23#include "util/stat.h" 23#include "util/stat.h"
24#include "util/string2.h"
24#include "util/thread-stack.h" 25#include "util/thread-stack.h"
25#include "util/time-utils.h" 26#include "util/time-utils.h"
27#include "print_binary.h"
26#include <linux/bitmap.h> 28#include <linux/bitmap.h>
29#include <linux/kernel.h>
27#include <linux/stringify.h> 30#include <linux/stringify.h>
28#include <linux/time64.h> 31#include <linux/time64.h>
29#include "asm/bug.h" 32#include "asm/bug.h"
30#include "util/mem-events.h" 33#include "util/mem-events.h"
34#include "util/dump-insn.h"
35#include <dirent.h>
36#include <errno.h>
37#include <inttypes.h>
38#include <signal.h>
39#include <sys/param.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <unistd.h>
43
44#include "sane_ctype.h"
31 45
32static char const *script_name; 46static char const *script_name;
33static char const *generate_script_lang; 47static char const *generate_script_lang;
@@ -42,6 +56,7 @@ static bool nanosecs;
42static const char *cpu_list; 56static const char *cpu_list;
43static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 57static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
44static struct perf_stat_config stat_config; 58static struct perf_stat_config stat_config;
59static int max_blocks;
45 60
46unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; 61unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
47 62
@@ -69,6 +84,7 @@ enum perf_output_field {
69 PERF_OUTPUT_CALLINDENT = 1U << 20, 84 PERF_OUTPUT_CALLINDENT = 1U << 20,
70 PERF_OUTPUT_INSN = 1U << 21, 85 PERF_OUTPUT_INSN = 1U << 21,
71 PERF_OUTPUT_INSNLEN = 1U << 22, 86 PERF_OUTPUT_INSNLEN = 1U << 22,
87 PERF_OUTPUT_BRSTACKINSN = 1U << 23,
72}; 88};
73 89
74struct output_option { 90struct output_option {
@@ -98,6 +114,7 @@ struct output_option {
98 {.str = "callindent", .field = PERF_OUTPUT_CALLINDENT}, 114 {.str = "callindent", .field = PERF_OUTPUT_CALLINDENT},
99 {.str = "insn", .field = PERF_OUTPUT_INSN}, 115 {.str = "insn", .field = PERF_OUTPUT_INSN},
100 {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN}, 116 {.str = "insnlen", .field = PERF_OUTPUT_INSNLEN},
117 {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN},
101}; 118};
102 119
103/* default set to maintain compatibility with current format */ 120/* default set to maintain compatibility with current format */
@@ -292,7 +309,13 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
292 "selected. Hence, no address to lookup the source line number.\n"); 309 "selected. Hence, no address to lookup the source line number.\n");
293 return -EINVAL; 310 return -EINVAL;
294 } 311 }
295 312 if (PRINT_FIELD(BRSTACKINSN) &&
313 !(perf_evlist__combined_branch_type(session->evlist) &
314 PERF_SAMPLE_BRANCH_ANY)) {
315 pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"
316 "Hint: run 'perf record -b ...'\n");
317 return -EINVAL;
318 }
296 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 319 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
297 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", 320 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
298 PERF_OUTPUT_TID|PERF_OUTPUT_PID)) 321 PERF_OUTPUT_TID|PERF_OUTPUT_PID))
@@ -546,6 +569,233 @@ static void print_sample_brstacksym(struct perf_sample *sample,
546 } 569 }
547} 570}
548 571
572#define MAXBB 16384UL
573
574static int grab_bb(u8 *buffer, u64 start, u64 end,
575 struct machine *machine, struct thread *thread,
576 bool *is64bit, u8 *cpumode, bool last)
577{
578 long offset, len;
579 struct addr_location al;
580 bool kernel;
581
582 if (!start || !end)
583 return 0;
584
585 kernel = machine__kernel_ip(machine, start);
586 if (kernel)
587 *cpumode = PERF_RECORD_MISC_KERNEL;
588 else
589 *cpumode = PERF_RECORD_MISC_USER;
590
591 /*
592 * Block overlaps between kernel and user.
593 * This can happen due to ring filtering
594 * On Intel CPUs the entry into the kernel is filtered,
595 * but the exit is not. Let the caller patch it up.
596 */
597 if (kernel != machine__kernel_ip(machine, end)) {
598 printf("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n",
599 start, end);
600 return -ENXIO;
601 }
602
603 memset(&al, 0, sizeof(al));
604 if (end - start > MAXBB - MAXINSN) {
605 if (last)
606 printf("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end);
607 else
608 printf("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start);
609 return 0;
610 }
611
612 thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al);
613 if (!al.map || !al.map->dso) {
614 printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
615 return 0;
616 }
617 if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) {
618 printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
619 return 0;
620 }
621
622 /* Load maps to ensure dso->is_64_bit has been updated */
623 map__load(al.map);
624
625 offset = al.map->map_ip(al.map, start);
626 len = dso__data_read_offset(al.map->dso, machine, offset, (u8 *)buffer,
627 end - start + MAXINSN);
628
629 *is64bit = al.map->dso->is_64_bit;
630 if (len <= 0)
631 printf("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n",
632 start, end);
633 return len;
634}
635
636static void print_jump(uint64_t ip, struct branch_entry *en,
637 struct perf_insn *x, u8 *inbuf, int len,
638 int insn)
639{
640 printf("\t%016" PRIx64 "\t%-30s\t#%s%s%s%s",
641 ip,
642 dump_insn(x, ip, inbuf, len, NULL),
643 en->flags.predicted ? " PRED" : "",
644 en->flags.mispred ? " MISPRED" : "",
645 en->flags.in_tx ? " INTX" : "",
646 en->flags.abort ? " ABORT" : "");
647 if (en->flags.cycles) {
648 printf(" %d cycles", en->flags.cycles);
649 if (insn)
650 printf(" %.2f IPC", (float)insn / en->flags.cycles);
651 }
652 putchar('\n');
653}
654
655static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu,
656 uint64_t addr, struct symbol **lastsym,
657 struct perf_event_attr *attr)
658{
659 struct addr_location al;
660 int off;
661
662 memset(&al, 0, sizeof(al));
663
664 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, addr, &al);
665 if (!al.map)
666 thread__find_addr_map(thread, cpumode, MAP__VARIABLE,
667 addr, &al);
668 if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
669 return;
670
671 al.cpu = cpu;
672 al.sym = NULL;
673 if (al.map)
674 al.sym = map__find_symbol(al.map, al.addr);
675
676 if (!al.sym)
677 return;
678
679 if (al.addr < al.sym->end)
680 off = al.addr - al.sym->start;
681 else
682 off = al.addr - al.map->start - al.sym->start;
683 printf("\t%s", al.sym->name);
684 if (off)
685 printf("%+d", off);
686 putchar(':');
687 if (PRINT_FIELD(SRCLINE))
688 map__fprintf_srcline(al.map, al.addr, "\t", stdout);
689 putchar('\n');
690 *lastsym = al.sym;
691}
692
693static void print_sample_brstackinsn(struct perf_sample *sample,
694 struct thread *thread,
695 struct perf_event_attr *attr,
696 struct machine *machine)
697{
698 struct branch_stack *br = sample->branch_stack;
699 u64 start, end;
700 int i, insn, len, nr, ilen;
701 struct perf_insn x;
702 u8 buffer[MAXBB];
703 unsigned off;
704 struct symbol *lastsym = NULL;
705
706 if (!(br && br->nr))
707 return;
708 nr = br->nr;
709 if (max_blocks && nr > max_blocks + 1)
710 nr = max_blocks + 1;
711
712 x.thread = thread;
713 x.cpu = sample->cpu;
714
715 putchar('\n');
716
717 /* Handle first from jump, of which we don't know the entry. */
718 len = grab_bb(buffer, br->entries[nr-1].from,
719 br->entries[nr-1].from,
720 machine, thread, &x.is64bit, &x.cpumode, false);
721 if (len > 0) {
722 print_ip_sym(thread, x.cpumode, x.cpu,
723 br->entries[nr - 1].from, &lastsym, attr);
724 print_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
725 &x, buffer, len, 0);
726 }
727
728 /* Print all blocks */
729 for (i = nr - 2; i >= 0; i--) {
730 if (br->entries[i].from || br->entries[i].to)
731 pr_debug("%d: %" PRIx64 "-%" PRIx64 "\n", i,
732 br->entries[i].from,
733 br->entries[i].to);
734 start = br->entries[i + 1].to;
735 end = br->entries[i].from;
736
737 len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false);
738 /* Patch up missing kernel transfers due to ring filters */
739 if (len == -ENXIO && i > 0) {
740 end = br->entries[--i].from;
741 pr_debug("\tpatching up to %" PRIx64 "-%" PRIx64 "\n", start, end);
742 len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false);
743 }
744 if (len <= 0)
745 continue;
746
747 insn = 0;
748 for (off = 0;; off += ilen) {
749 uint64_t ip = start + off;
750
751 print_ip_sym(thread, x.cpumode, x.cpu, ip, &lastsym, attr);
752 if (ip == end) {
753 print_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn);
754 break;
755 } else {
756 printf("\t%016" PRIx64 "\t%s\n", ip,
757 dump_insn(&x, ip, buffer + off, len - off, &ilen));
758 if (ilen == 0)
759 break;
760 insn++;
761 }
762 }
763 }
764
765 /*
766 * Hit the branch? In this case we are already done, and the target
767 * has not been executed yet.
768 */
769 if (br->entries[0].from == sample->ip)
770 return;
771 if (br->entries[0].flags.abort)
772 return;
773
774 /*
775 * Print final block upto sample
776 */
777 start = br->entries[0].to;
778 end = sample->ip;
779 len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true);
780 print_ip_sym(thread, x.cpumode, x.cpu, start, &lastsym, attr);
781 if (len <= 0) {
782 /* Print at least last IP if basic block did not work */
783 len = grab_bb(buffer, sample->ip, sample->ip,
784 machine, thread, &x.is64bit, &x.cpumode, false);
785 if (len <= 0)
786 return;
787
788 printf("\t%016" PRIx64 "\t%s\n", sample->ip,
789 dump_insn(&x, sample->ip, buffer, len, NULL));
790 return;
791 }
792 for (off = 0; off <= end - start; off += ilen) {
793 printf("\t%016" PRIx64 "\t%s\n", start + off,
794 dump_insn(&x, start + off, buffer + off, len - off, &ilen));
795 if (ilen == 0)
796 break;
797 }
798}
549 799
550static void print_sample_addr(struct perf_sample *sample, 800static void print_sample_addr(struct perf_sample *sample,
551 struct thread *thread, 801 struct thread *thread,
@@ -632,7 +882,9 @@ static void print_sample_callindent(struct perf_sample *sample,
632} 882}
633 883
634static void print_insn(struct perf_sample *sample, 884static void print_insn(struct perf_sample *sample,
635 struct perf_event_attr *attr) 885 struct perf_event_attr *attr,
886 struct thread *thread,
887 struct machine *machine)
636{ 888{
637 if (PRINT_FIELD(INSNLEN)) 889 if (PRINT_FIELD(INSNLEN))
638 printf(" ilen: %d", sample->insn_len); 890 printf(" ilen: %d", sample->insn_len);
@@ -643,12 +895,15 @@ static void print_insn(struct perf_sample *sample,
643 for (i = 0; i < sample->insn_len; i++) 895 for (i = 0; i < sample->insn_len; i++)
644 printf(" %02x", (unsigned char)sample->insn[i]); 896 printf(" %02x", (unsigned char)sample->insn[i]);
645 } 897 }
898 if (PRINT_FIELD(BRSTACKINSN))
899 print_sample_brstackinsn(sample, thread, attr, machine);
646} 900}
647 901
648static void print_sample_bts(struct perf_sample *sample, 902static void print_sample_bts(struct perf_sample *sample,
649 struct perf_evsel *evsel, 903 struct perf_evsel *evsel,
650 struct thread *thread, 904 struct thread *thread,
651 struct addr_location *al) 905 struct addr_location *al,
906 struct machine *machine)
652{ 907{
653 struct perf_event_attr *attr = &evsel->attr; 908 struct perf_event_attr *attr = &evsel->attr;
654 bool print_srcline_last = false; 909 bool print_srcline_last = false;
@@ -689,7 +944,7 @@ static void print_sample_bts(struct perf_sample *sample,
689 if (print_srcline_last) 944 if (print_srcline_last)
690 map__fprintf_srcline(al->map, al->addr, "\n ", stdout); 945 map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
691 946
692 print_insn(sample, attr); 947 print_insn(sample, attr, thread, machine);
693 948
694 printf("\n"); 949 printf("\n");
695} 950}
@@ -830,6 +1085,7 @@ struct perf_script {
830 bool show_task_events; 1085 bool show_task_events;
831 bool show_mmap_events; 1086 bool show_mmap_events;
832 bool show_switch_events; 1087 bool show_switch_events;
1088 bool show_namespace_events;
833 bool allocated; 1089 bool allocated;
834 struct cpu_map *cpus; 1090 struct cpu_map *cpus;
835 struct thread_map *threads; 1091 struct thread_map *threads;
@@ -871,7 +1127,8 @@ static size_t data_src__printf(u64 data_src)
871 1127
872static void process_event(struct perf_script *script, 1128static void process_event(struct perf_script *script,
873 struct perf_sample *sample, struct perf_evsel *evsel, 1129 struct perf_sample *sample, struct perf_evsel *evsel,
874 struct addr_location *al) 1130 struct addr_location *al,
1131 struct machine *machine)
875{ 1132{
876 struct thread *thread = al->thread; 1133 struct thread *thread = al->thread;
877 struct perf_event_attr *attr = &evsel->attr; 1134 struct perf_event_attr *attr = &evsel->attr;
@@ -898,7 +1155,7 @@ static void process_event(struct perf_script *script,
898 print_sample_flags(sample->flags); 1155 print_sample_flags(sample->flags);
899 1156
900 if (is_bts_event(attr)) { 1157 if (is_bts_event(attr)) {
901 print_sample_bts(sample, evsel, thread, al); 1158 print_sample_bts(sample, evsel, thread, al, machine);
902 return; 1159 return;
903 } 1160 }
904 1161
@@ -936,7 +1193,7 @@ static void process_event(struct perf_script *script,
936 1193
937 if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) 1194 if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
938 print_sample_bpf_output(sample); 1195 print_sample_bpf_output(sample);
939 print_insn(sample, attr); 1196 print_insn(sample, attr, thread, machine);
940 printf("\n"); 1197 printf("\n");
941} 1198}
942 1199
@@ -1046,7 +1303,7 @@ static int process_sample_event(struct perf_tool *tool,
1046 if (scripting_ops) 1303 if (scripting_ops)
1047 scripting_ops->process_event(event, sample, evsel, &al); 1304 scripting_ops->process_event(event, sample, evsel, &al);
1048 else 1305 else
1049 process_event(scr, sample, evsel, &al); 1306 process_event(scr, sample, evsel, &al, machine);
1050 1307
1051out_put: 1308out_put:
1052 addr_location__put(&al); 1309 addr_location__put(&al);
@@ -1118,6 +1375,41 @@ out:
1118 return ret; 1375 return ret;
1119} 1376}
1120 1377
1378static int process_namespaces_event(struct perf_tool *tool,
1379 union perf_event *event,
1380 struct perf_sample *sample,
1381 struct machine *machine)
1382{
1383 struct thread *thread;
1384 struct perf_script *script = container_of(tool, struct perf_script, tool);
1385 struct perf_session *session = script->session;
1386 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);
1387 int ret = -1;
1388
1389 thread = machine__findnew_thread(machine, event->namespaces.pid,
1390 event->namespaces.tid);
1391 if (thread == NULL) {
1392 pr_debug("problem processing NAMESPACES event, skipping it.\n");
1393 return -1;
1394 }
1395
1396 if (perf_event__process_namespaces(tool, event, sample, machine) < 0)
1397 goto out;
1398
1399 if (!evsel->attr.sample_id_all) {
1400 sample->cpu = 0;
1401 sample->time = 0;
1402 sample->tid = event->namespaces.tid;
1403 sample->pid = event->namespaces.pid;
1404 }
1405 print_sample_start(sample, thread, evsel);
1406 perf_event__fprintf(event, stdout);
1407 ret = 0;
1408out:
1409 thread__put(thread);
1410 return ret;
1411}
1412
1121static int process_fork_event(struct perf_tool *tool, 1413static int process_fork_event(struct perf_tool *tool,
1122 union perf_event *event, 1414 union perf_event *event,
1123 struct perf_sample *sample, 1415 struct perf_sample *sample,
@@ -1293,6 +1585,8 @@ static int __cmd_script(struct perf_script *script)
1293 } 1585 }
1294 if (script->show_switch_events) 1586 if (script->show_switch_events)
1295 script->tool.context_switch = process_switch_event; 1587 script->tool.context_switch = process_switch_event;
1588 if (script->show_namespace_events)
1589 script->tool.namespaces = process_namespaces_event;
1296 1590
1297 ret = perf_session__process_events(script->session); 1591 ret = perf_session__process_events(script->session);
1298 1592
@@ -1427,7 +1721,7 @@ static int parse_scriptname(const struct option *opt __maybe_unused,
1427static int parse_output_fields(const struct option *opt __maybe_unused, 1721static int parse_output_fields(const struct option *opt __maybe_unused,
1428 const char *arg, int unset __maybe_unused) 1722 const char *arg, int unset __maybe_unused)
1429{ 1723{
1430 char *tok; 1724 char *tok, *strtok_saveptr = NULL;
1431 int i, imax = ARRAY_SIZE(all_output_options); 1725 int i, imax = ARRAY_SIZE(all_output_options);
1432 int j; 1726 int j;
1433 int rc = 0; 1727 int rc = 0;
@@ -1488,7 +1782,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
1488 } 1782 }
1489 } 1783 }
1490 1784
1491 for (tok = strtok(tok, ","); tok; tok = strtok(NULL, ",")) { 1785 for (tok = strtok_r(tok, ",", &strtok_saveptr); tok; tok = strtok_r(NULL, ",", &strtok_saveptr)) {
1492 for (i = 0; i < imax; ++i) { 1786 for (i = 0; i < imax; ++i) {
1493 if (strcmp(tok, all_output_options[i].str) == 0) 1787 if (strcmp(tok, all_output_options[i].str) == 0)
1494 break; 1788 break;
@@ -2078,7 +2372,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
2078 return set_maps(script); 2372 return set_maps(script);
2079} 2373}
2080 2374
2081int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 2375int cmd_script(int argc, const char **argv)
2082{ 2376{
2083 bool show_full_info = false; 2377 bool show_full_info = false;
2084 bool header = false; 2378 bool header = false;
@@ -2097,6 +2391,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2097 .mmap = perf_event__process_mmap, 2391 .mmap = perf_event__process_mmap,
2098 .mmap2 = perf_event__process_mmap2, 2392 .mmap2 = perf_event__process_mmap2,
2099 .comm = perf_event__process_comm, 2393 .comm = perf_event__process_comm,
2394 .namespaces = perf_event__process_namespaces,
2100 .exit = perf_event__process_exit, 2395 .exit = perf_event__process_exit,
2101 .fork = perf_event__process_fork, 2396 .fork = perf_event__process_fork,
2102 .attr = process_attr, 2397 .attr = process_attr,
@@ -2152,7 +2447,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2152 "Valid types: hw,sw,trace,raw. " 2447 "Valid types: hw,sw,trace,raw. "
2153 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," 2448 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
2154 "addr,symoff,period,iregs,brstack,brstacksym,flags," 2449 "addr,symoff,period,iregs,brstack,brstacksym,flags,"
2155 "bpf-output,callindent,insn,insnlen", parse_output_fields), 2450 "bpf-output,callindent,insn,insnlen,brstackinsn",
2451 parse_output_fields),
2156 OPT_BOOLEAN('a', "all-cpus", &system_wide, 2452 OPT_BOOLEAN('a', "all-cpus", &system_wide,
2157 "system-wide collection from all CPUs"), 2453 "system-wide collection from all CPUs"),
2158 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 2454 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
@@ -2180,7 +2476,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2180 "Show the mmap events"), 2476 "Show the mmap events"),
2181 OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events, 2477 OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events,
2182 "Show context switch events (if recorded)"), 2478 "Show context switch events (if recorded)"),
2479 OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events,
2480 "Show namespace events (if recorded)"),
2183 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), 2481 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
2482 OPT_INTEGER(0, "max-blocks", &max_blocks,
2483 "Maximum number of code blocks to dump with brstackinsn"),
2184 OPT_BOOLEAN(0, "ns", &nanosecs, 2484 OPT_BOOLEAN(0, "ns", &nanosecs,
2185 "Use 9 decimal places when displaying time"), 2485 "Use 9 decimal places when displaying time"),
2186 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", 2486 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
@@ -2217,7 +2517,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2217 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { 2517 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
2218 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); 2518 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
2219 if (!rec_script_path) 2519 if (!rec_script_path)
2220 return cmd_record(argc, argv, NULL); 2520 return cmd_record(argc, argv);
2221 } 2521 }
2222 2522
2223 if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) { 2523 if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 13b54999ad79..a935b5023732 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -64,14 +64,24 @@
64#include "util/session.h" 64#include "util/session.h"
65#include "util/tool.h" 65#include "util/tool.h"
66#include "util/group.h" 66#include "util/group.h"
67#include "util/string2.h"
67#include "asm/bug.h" 68#include "asm/bug.h"
68 69
69#include <linux/time64.h> 70#include <linux/time64.h>
70#include <api/fs/fs.h> 71#include <api/fs/fs.h>
72#include <errno.h>
73#include <signal.h>
71#include <stdlib.h> 74#include <stdlib.h>
72#include <sys/prctl.h> 75#include <sys/prctl.h>
76#include <inttypes.h>
73#include <locale.h> 77#include <locale.h>
74#include <math.h> 78#include <math.h>
79#include <sys/types.h>
80#include <sys/stat.h>
81#include <sys/wait.h>
82#include <unistd.h>
83
84#include "sane_ctype.h"
75 85
76#define DEFAULT_SEPARATOR " " 86#define DEFAULT_SEPARATOR " "
77#define CNTR_NOT_SUPPORTED "<not supported>" 87#define CNTR_NOT_SUPPORTED "<not supported>"
@@ -140,12 +150,14 @@ static unsigned int unit_width = 4; /* strlen("unit") */
140static bool forever = false; 150static bool forever = false;
141static bool metric_only = false; 151static bool metric_only = false;
142static bool force_metric_only = false; 152static bool force_metric_only = false;
153static bool no_merge = false;
143static struct timespec ref_time; 154static struct timespec ref_time;
144static struct cpu_map *aggr_map; 155static struct cpu_map *aggr_map;
145static aggr_get_id_t aggr_get_id; 156static aggr_get_id_t aggr_get_id;
146static bool append_file; 157static bool append_file;
147static const char *output_name; 158static const char *output_name;
148static int output_fd; 159static int output_fd;
160static int print_free_counters_hint;
149 161
150struct perf_stat { 162struct perf_stat {
151 bool record; 163 bool record;
@@ -310,8 +322,12 @@ static int read_counter(struct perf_evsel *counter)
310 struct perf_counts_values *count; 322 struct perf_counts_values *count;
311 323
312 count = perf_counts(counter->counts, cpu, thread); 324 count = perf_counts(counter->counts, cpu, thread);
313 if (perf_evsel__read(counter, cpu, thread, count)) 325 if (perf_evsel__read(counter, cpu, thread, count)) {
326 counter->counts->scaled = -1;
327 perf_counts(counter->counts, cpu, thread)->ena = 0;
328 perf_counts(counter->counts, cpu, thread)->run = 0;
314 return -1; 329 return -1;
330 }
315 331
316 if (STAT_RECORD) { 332 if (STAT_RECORD) {
317 if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { 333 if (perf_evsel__write_stat_event(counter, cpu, thread, count)) {
@@ -336,12 +352,14 @@ static int read_counter(struct perf_evsel *counter)
336static void read_counters(void) 352static void read_counters(void)
337{ 353{
338 struct perf_evsel *counter; 354 struct perf_evsel *counter;
355 int ret;
339 356
340 evlist__for_each_entry(evsel_list, counter) { 357 evlist__for_each_entry(evsel_list, counter) {
341 if (read_counter(counter)) 358 ret = read_counter(counter);
359 if (ret)
342 pr_debug("failed to read counter %s\n", counter->name); 360 pr_debug("failed to read counter %s\n", counter->name);
343 361
344 if (perf_stat_process_counter(&stat_config, counter)) 362 if (ret == 0 && perf_stat_process_counter(&stat_config, counter))
345 pr_warning("failed to process counter %s\n", counter->name); 363 pr_warning("failed to process counter %s\n", counter->name);
346 } 364 }
347} 365}
@@ -873,10 +891,7 @@ static void print_metric_csv(void *ctx,
873 return; 891 return;
874 } 892 }
875 snprintf(buf, sizeof(buf), fmt, val); 893 snprintf(buf, sizeof(buf), fmt, val);
876 vals = buf; 894 ends = vals = ltrim(buf);
877 while (isspace(*vals))
878 vals++;
879 ends = vals;
880 while (isdigit(*ends) || *ends == '.') 895 while (isdigit(*ends) || *ends == '.')
881 ends++; 896 ends++;
882 *ends = 0; 897 *ends = 0;
@@ -948,10 +963,7 @@ static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
948 return; 963 return;
949 unit = fixunit(tbuf, os->evsel, unit); 964 unit = fixunit(tbuf, os->evsel, unit);
950 snprintf(buf, sizeof buf, fmt, val); 965 snprintf(buf, sizeof buf, fmt, val);
951 vals = buf; 966 ends = vals = ltrim(buf);
952 while (isspace(*vals))
953 vals++;
954 ends = vals;
955 while (isdigit(*ends) || *ends == '.') 967 while (isdigit(*ends) || *ends == '.')
956 ends++; 968 ends++;
957 *ends = 0; 969 *ends = 0;
@@ -1109,6 +1121,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1109 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1121 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1110 csv_sep); 1122 csv_sep);
1111 1123
1124 if (counter->supported)
1125 print_free_counters_hint = 1;
1126
1112 fprintf(stat_config.output, "%-*s%s", 1127 fprintf(stat_config.output, "%-*s%s",
1113 csv_output ? 0 : unit_width, 1128 csv_output ? 0 : unit_width,
1114 counter->unit, csv_sep); 1129 counter->unit, csv_sep);
@@ -1140,6 +1155,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1140 out.print_metric = pm; 1155 out.print_metric = pm;
1141 out.new_line = nl; 1156 out.new_line = nl;
1142 out.ctx = &os; 1157 out.ctx = &os;
1158 out.force_header = false;
1143 1159
1144 if (csv_output && !metric_only) { 1160 if (csv_output && !metric_only) {
1145 print_noise(counter, noise); 1161 print_noise(counter, noise);
@@ -1178,11 +1194,81 @@ static void aggr_update_shadow(void)
1178 } 1194 }
1179} 1195}
1180 1196
1197static void collect_all_aliases(struct perf_evsel *counter,
1198 void (*cb)(struct perf_evsel *counter, void *data,
1199 bool first),
1200 void *data)
1201{
1202 struct perf_evsel *alias;
1203
1204 alias = list_prepare_entry(counter, &(evsel_list->entries), node);
1205 list_for_each_entry_continue (alias, &evsel_list->entries, node) {
1206 if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
1207 alias->scale != counter->scale ||
1208 alias->cgrp != counter->cgrp ||
1209 strcmp(alias->unit, counter->unit) ||
1210 nsec_counter(alias) != nsec_counter(counter))
1211 break;
1212 alias->merged_stat = true;
1213 cb(alias, data, false);
1214 }
1215}
1216
1217static bool collect_data(struct perf_evsel *counter,
1218 void (*cb)(struct perf_evsel *counter, void *data,
1219 bool first),
1220 void *data)
1221{
1222 if (counter->merged_stat)
1223 return false;
1224 cb(counter, data, true);
1225 if (!no_merge)
1226 collect_all_aliases(counter, cb, data);
1227 return true;
1228}
1229
1230struct aggr_data {
1231 u64 ena, run, val;
1232 int id;
1233 int nr;
1234 int cpu;
1235};
1236
1237static void aggr_cb(struct perf_evsel *counter, void *data, bool first)
1238{
1239 struct aggr_data *ad = data;
1240 int cpu, s2;
1241
1242 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1243 struct perf_counts_values *counts;
1244
1245 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu);
1246 if (s2 != ad->id)
1247 continue;
1248 if (first)
1249 ad->nr++;
1250 counts = perf_counts(counter->counts, cpu, 0);
1251 /*
1252 * When any result is bad, make them all to give
1253 * consistent output in interval mode.
1254 */
1255 if (counts->ena == 0 || counts->run == 0 ||
1256 counter->counts->scaled == -1) {
1257 ad->ena = 0;
1258 ad->run = 0;
1259 break;
1260 }
1261 ad->val += counts->val;
1262 ad->ena += counts->ena;
1263 ad->run += counts->run;
1264 }
1265}
1266
1181static void print_aggr(char *prefix) 1267static void print_aggr(char *prefix)
1182{ 1268{
1183 FILE *output = stat_config.output; 1269 FILE *output = stat_config.output;
1184 struct perf_evsel *counter; 1270 struct perf_evsel *counter;
1185 int cpu, s, s2, id, nr; 1271 int s, id, nr;
1186 double uval; 1272 double uval;
1187 u64 ena, run, val; 1273 u64 ena, run, val;
1188 bool first; 1274 bool first;
@@ -1197,23 +1283,21 @@ static void print_aggr(char *prefix)
1197 * Without each counter has its own line. 1283 * Without each counter has its own line.
1198 */ 1284 */
1199 for (s = 0; s < aggr_map->nr; s++) { 1285 for (s = 0; s < aggr_map->nr; s++) {
1286 struct aggr_data ad;
1200 if (prefix && metric_only) 1287 if (prefix && metric_only)
1201 fprintf(output, "%s", prefix); 1288 fprintf(output, "%s", prefix);
1202 1289
1203 id = aggr_map->map[s]; 1290 ad.id = id = aggr_map->map[s];
1204 first = true; 1291 first = true;
1205 evlist__for_each_entry(evsel_list, counter) { 1292 evlist__for_each_entry(evsel_list, counter) {
1206 val = ena = run = 0; 1293 ad.val = ad.ena = ad.run = 0;
1207 nr = 0; 1294 ad.nr = 0;
1208 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1295 if (!collect_data(counter, aggr_cb, &ad))
1209 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu); 1296 continue;
1210 if (s2 != id) 1297 nr = ad.nr;
1211 continue; 1298 ena = ad.ena;
1212 val += perf_counts(counter->counts, cpu, 0)->val; 1299 run = ad.run;
1213 ena += perf_counts(counter->counts, cpu, 0)->ena; 1300 val = ad.val;
1214 run += perf_counts(counter->counts, cpu, 0)->run;
1215 nr++;
1216 }
1217 if (first && metric_only) { 1301 if (first && metric_only) {
1218 first = false; 1302 first = false;
1219 aggr_printout(counter, id, nr); 1303 aggr_printout(counter, id, nr);
@@ -1257,6 +1341,21 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1257 } 1341 }
1258} 1342}
1259 1343
1344struct caggr_data {
1345 double avg, avg_enabled, avg_running;
1346};
1347
1348static void counter_aggr_cb(struct perf_evsel *counter, void *data,
1349 bool first __maybe_unused)
1350{
1351 struct caggr_data *cd = data;
1352 struct perf_stat_evsel *ps = counter->priv;
1353
1354 cd->avg += avg_stats(&ps->res_stats[0]);
1355 cd->avg_enabled += avg_stats(&ps->res_stats[1]);
1356 cd->avg_running += avg_stats(&ps->res_stats[2]);
1357}
1358
1260/* 1359/*
1261 * Print out the results of a single counter: 1360 * Print out the results of a single counter:
1262 * aggregated counts in system-wide mode 1361 * aggregated counts in system-wide mode
@@ -1264,23 +1363,31 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1264static void print_counter_aggr(struct perf_evsel *counter, char *prefix) 1363static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1265{ 1364{
1266 FILE *output = stat_config.output; 1365 FILE *output = stat_config.output;
1267 struct perf_stat_evsel *ps = counter->priv;
1268 double avg = avg_stats(&ps->res_stats[0]);
1269 double uval; 1366 double uval;
1270 double avg_enabled, avg_running; 1367 struct caggr_data cd = { .avg = 0.0 };
1271 1368
1272 avg_enabled = avg_stats(&ps->res_stats[1]); 1369 if (!collect_data(counter, counter_aggr_cb, &cd))
1273 avg_running = avg_stats(&ps->res_stats[2]); 1370 return;
1274 1371
1275 if (prefix && !metric_only) 1372 if (prefix && !metric_only)
1276 fprintf(output, "%s", prefix); 1373 fprintf(output, "%s", prefix);
1277 1374
1278 uval = avg * counter->scale; 1375 uval = cd.avg * counter->scale;
1279 printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg); 1376 printout(-1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled, cd.avg);
1280 if (!metric_only) 1377 if (!metric_only)
1281 fprintf(output, "\n"); 1378 fprintf(output, "\n");
1282} 1379}
1283 1380
1381static void counter_cb(struct perf_evsel *counter, void *data,
1382 bool first __maybe_unused)
1383{
1384 struct aggr_data *ad = data;
1385
1386 ad->val += perf_counts(counter->counts, ad->cpu, 0)->val;
1387 ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena;
1388 ad->run += perf_counts(counter->counts, ad->cpu, 0)->run;
1389}
1390
1284/* 1391/*
1285 * Print out the results of a single counter: 1392 * Print out the results of a single counter:
1286 * does not use aggregated count in system-wide 1393 * does not use aggregated count in system-wide
@@ -1293,9 +1400,13 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1293 int cpu; 1400 int cpu;
1294 1401
1295 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1402 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1296 val = perf_counts(counter->counts, cpu, 0)->val; 1403 struct aggr_data ad = { .cpu = cpu };
1297 ena = perf_counts(counter->counts, cpu, 0)->ena; 1404
1298 run = perf_counts(counter->counts, cpu, 0)->run; 1405 if (!collect_data(counter, counter_cb, &ad))
1406 return;
1407 val = ad.val;
1408 ena = ad.ena;
1409 run = ad.run;
1299 1410
1300 if (prefix) 1411 if (prefix)
1301 fprintf(output, "%s", prefix); 1412 fprintf(output, "%s", prefix);
@@ -1380,6 +1491,7 @@ static void print_metric_headers(const char *prefix, bool no_indent)
1380 out.ctx = &os; 1491 out.ctx = &os;
1381 out.print_metric = print_metric_header; 1492 out.print_metric = print_metric_header;
1382 out.new_line = new_line_metric; 1493 out.new_line = new_line_metric;
1494 out.force_header = true;
1383 os.evsel = counter; 1495 os.evsel = counter;
1384 perf_stat__print_shadow_stats(counter, 0, 1496 perf_stat__print_shadow_stats(counter, 0,
1385 0, 1497 0,
@@ -1477,6 +1589,13 @@ static void print_footer(void)
1477 avg_stats(&walltime_nsecs_stats)); 1589 avg_stats(&walltime_nsecs_stats));
1478 } 1590 }
1479 fprintf(output, "\n\n"); 1591 fprintf(output, "\n\n");
1592
1593 if (print_free_counters_hint)
1594 fprintf(output,
1595"Some events weren't counted. Try disabling the NMI watchdog:\n"
1596" echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1597" perf stat ...\n"
1598" echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1480} 1599}
1481 1600
1482static void print_counters(struct timespec *ts, int argc, const char **argv) 1601static void print_counters(struct timespec *ts, int argc, const char **argv)
@@ -1633,6 +1752,7 @@ static const struct option stat_options[] = {
1633 "list of cpus to monitor in system-wide"), 1752 "list of cpus to monitor in system-wide"),
1634 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, 1753 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
1635 "disable CPU count aggregation", AGGR_NONE), 1754 "disable CPU count aggregation", AGGR_NONE),
1755 OPT_BOOLEAN(0, "no-merge", &no_merge, "Do not merge identical named events"),
1636 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1756 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1637 "print counts with custom separator"), 1757 "print counts with custom separator"),
1638 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1758 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
@@ -2339,7 +2459,36 @@ static int __cmd_report(int argc, const char **argv)
2339 return 0; 2459 return 0;
2340} 2460}
2341 2461
2342int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 2462static void setup_system_wide(int forks)
2463{
2464 /*
2465 * Make system wide (-a) the default target if
2466 * no target was specified and one of following
2467 * conditions is met:
2468 *
2469 * - there's no workload specified
2470 * - there is workload specified but all requested
2471 * events are system wide events
2472 */
2473 if (!target__none(&target))
2474 return;
2475
2476 if (!forks)
2477 target.system_wide = true;
2478 else {
2479 struct perf_evsel *counter;
2480
2481 evlist__for_each_entry(evsel_list, counter) {
2482 if (!counter->system_wide)
2483 return;
2484 }
2485
2486 if (evsel_list->nr_entries)
2487 target.system_wide = true;
2488 }
2489}
2490
2491int cmd_stat(int argc, const char **argv)
2343{ 2492{
2344 const char * const stat_usage[] = { 2493 const char * const stat_usage[] = {
2345 "perf stat [<options>] [<command>]", 2494 "perf stat [<options>] [<command>]",
@@ -2361,6 +2510,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
2361 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2510 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
2362 (const char **) stat_usage, 2511 (const char **) stat_usage,
2363 PARSE_OPT_STOP_AT_NON_OPTION); 2512 PARSE_OPT_STOP_AT_NON_OPTION);
2513 perf_stat__collect_metric_expr(evsel_list);
2364 perf_stat__init_shadow_stats(); 2514 perf_stat__init_shadow_stats();
2365 2515
2366 if (csv_sep) { 2516 if (csv_sep) {
@@ -2445,9 +2595,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
2445 } else if (big_num_opt == 0) /* User passed --no-big-num */ 2595 } else if (big_num_opt == 0) /* User passed --no-big-num */
2446 big_num = false; 2596 big_num = false;
2447 2597
2448 /* Make system wide (-a) the default target. */ 2598 setup_system_wide(argc);
2449 if (!argc && target__none(&target))
2450 target.system_wide = true;
2451 2599
2452 if (run_count < 0) { 2600 if (run_count < 0) {
2453 pr_err("Run count must be a positive number\n"); 2601 pr_err("Run count must be a positive number\n");
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index e7eaa298d34a..4e2e61695986 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -12,6 +12,8 @@
12 * of the License. 12 * of the License.
13 */ 13 */
14 14
15#include <errno.h>
16#include <inttypes.h>
15#include <traceevent/event-parse.h> 17#include <traceevent/event-parse.h>
16 18
17#include "builtin.h" 19#include "builtin.h"
@@ -23,11 +25,12 @@
23#include "util/cache.h" 25#include "util/cache.h"
24#include "util/evlist.h" 26#include "util/evlist.h"
25#include "util/evsel.h" 27#include "util/evsel.h"
28#include <linux/kernel.h>
26#include <linux/rbtree.h> 29#include <linux/rbtree.h>
27#include <linux/time64.h> 30#include <linux/time64.h>
28#include "util/symbol.h" 31#include "util/symbol.h"
32#include "util/thread.h"
29#include "util/callchain.h" 33#include "util/callchain.h"
30#include "util/strlist.h"
31 34
32#include "perf.h" 35#include "perf.h"
33#include "util/header.h" 36#include "util/header.h"
@@ -1773,7 +1776,7 @@ static int timechart__io_record(int argc, const char **argv)
1773 for (i = 0; i < (unsigned int)argc; i++) 1776 for (i = 0; i < (unsigned int)argc; i++)
1774 *p++ = argv[i]; 1777 *p++ = argv[i];
1775 1778
1776 return cmd_record(rec_argc, rec_argv, NULL); 1779 return cmd_record(rec_argc, rec_argv);
1777} 1780}
1778 1781
1779 1782
@@ -1864,7 +1867,7 @@ static int timechart__record(struct timechart *tchart, int argc, const char **ar
1864 for (j = 0; j < (unsigned int)argc; j++) 1867 for (j = 0; j < (unsigned int)argc; j++)
1865 *p++ = argv[j]; 1868 *p++ = argv[j];
1866 1869
1867 return cmd_record(rec_argc, rec_argv, NULL); 1870 return cmd_record(rec_argc, rec_argv);
1868} 1871}
1869 1872
1870static int 1873static int
@@ -1917,8 +1920,7 @@ parse_time(const struct option *opt, const char *arg, int __maybe_unused unset)
1917 return 0; 1920 return 0;
1918} 1921}
1919 1922
1920int cmd_timechart(int argc, const char **argv, 1923int cmd_timechart(int argc, const char **argv)
1921 const char *prefix __maybe_unused)
1922{ 1924{
1923 struct timechart tchart = { 1925 struct timechart tchart = {
1924 .tool = { 1926 .tool = {
@@ -1933,6 +1935,11 @@ int cmd_timechart(int argc, const char **argv,
1933 .merge_dist = 1000, 1935 .merge_dist = 1000,
1934 }; 1936 };
1935 const char *output_name = "output.svg"; 1937 const char *output_name = "output.svg";
1938 const struct option timechart_common_options[] = {
1939 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1940 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, "output processes data only"),
1941 OPT_END()
1942 };
1936 const struct option timechart_options[] = { 1943 const struct option timechart_options[] = {
1937 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1944 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1938 OPT_STRING('o', "output", &output_name, "file", "output file name"), 1945 OPT_STRING('o', "output", &output_name, "file", "output file name"),
@@ -1940,9 +1947,6 @@ int cmd_timechart(int argc, const char **argv,
1940 OPT_CALLBACK(0, "highlight", NULL, "duration or task name", 1947 OPT_CALLBACK(0, "highlight", NULL, "duration or task name",
1941 "highlight tasks. Pass duration in ns or process name.", 1948 "highlight tasks. Pass duration in ns or process name.",
1942 parse_highlight), 1949 parse_highlight),
1943 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1944 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1945 "output processes data only"),
1946 OPT_CALLBACK('p', "process", NULL, "process", 1950 OPT_CALLBACK('p', "process", NULL, "process",
1947 "process selector. Pass a pid or process name.", 1951 "process selector. Pass a pid or process name.",
1948 parse_process), 1952 parse_process),
@@ -1962,22 +1966,18 @@ int cmd_timechart(int argc, const char **argv,
1962 "merge events that are merge-dist us apart", 1966 "merge events that are merge-dist us apart",
1963 parse_time), 1967 parse_time),
1964 OPT_BOOLEAN('f', "force", &tchart.force, "don't complain, do it"), 1968 OPT_BOOLEAN('f', "force", &tchart.force, "don't complain, do it"),
1965 OPT_END() 1969 OPT_PARENT(timechart_common_options),
1966 }; 1970 };
1967 const char * const timechart_subcommands[] = { "record", NULL }; 1971 const char * const timechart_subcommands[] = { "record", NULL };
1968 const char *timechart_usage[] = { 1972 const char *timechart_usage[] = {
1969 "perf timechart [<options>] {record}", 1973 "perf timechart [<options>] {record}",
1970 NULL 1974 NULL
1971 }; 1975 };
1972
1973 const struct option timechart_record_options[] = { 1976 const struct option timechart_record_options[] = {
1974 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1975 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1976 "output processes data only"),
1977 OPT_BOOLEAN('I', "io-only", &tchart.io_only, 1977 OPT_BOOLEAN('I', "io-only", &tchart.io_only,
1978 "record only IO data"), 1978 "record only IO data"),
1979 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), 1979 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1980 OPT_END() 1980 OPT_PARENT(timechart_common_options),
1981 }; 1981 };
1982 const char * const timechart_record_usage[] = { 1982 const char * const timechart_record_usage[] = {
1983 "perf timechart record [<options>]", 1983 "perf timechart record [<options>]",
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ab9077915763..10b6362ca0bf 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -27,19 +27,20 @@
27#include "util/drv_configs.h" 27#include "util/drv_configs.h"
28#include "util/evlist.h" 28#include "util/evlist.h"
29#include "util/evsel.h" 29#include "util/evsel.h"
30#include "util/event.h"
30#include "util/machine.h" 31#include "util/machine.h"
31#include "util/session.h" 32#include "util/session.h"
32#include "util/symbol.h" 33#include "util/symbol.h"
33#include "util/thread.h" 34#include "util/thread.h"
34#include "util/thread_map.h" 35#include "util/thread_map.h"
35#include "util/top.h" 36#include "util/top.h"
36#include "util/util.h"
37#include <linux/rbtree.h> 37#include <linux/rbtree.h>
38#include <subcmd/parse-options.h> 38#include <subcmd/parse-options.h>
39#include "util/parse-events.h" 39#include "util/parse-events.h"
40#include "util/cpumap.h" 40#include "util/cpumap.h"
41#include "util/xyarray.h" 41#include "util/xyarray.h"
42#include "util/sort.h" 42#include "util/sort.h"
43#include "util/term.h"
43#include "util/intlist.h" 44#include "util/intlist.h"
44#include "util/parse-branch-options.h" 45#include "util/parse-branch-options.h"
45#include "arch/common.h" 46#include "arch/common.h"
@@ -58,6 +59,7 @@
58#include <errno.h> 59#include <errno.h>
59#include <time.h> 60#include <time.h>
60#include <sched.h> 61#include <sched.h>
62#include <signal.h>
61 63
62#include <sys/syscall.h> 64#include <sys/syscall.h>
63#include <sys/ioctl.h> 65#include <sys/ioctl.h>
@@ -72,6 +74,8 @@
72#include <linux/time64.h> 74#include <linux/time64.h>
73#include <linux/types.h> 75#include <linux/types.h>
74 76
77#include "sane_ctype.h"
78
75static volatile int done; 79static volatile int done;
76 80
77#define HEADER_LINE_NR 5 81#define HEADER_LINE_NR 5
@@ -1075,7 +1079,7 @@ parse_percent_limit(const struct option *opt, const char *arg,
1075const char top_callchain_help[] = CALLCHAIN_RECORD_HELP CALLCHAIN_REPORT_HELP 1079const char top_callchain_help[] = CALLCHAIN_RECORD_HELP CALLCHAIN_REPORT_HELP
1076 "\n\t\t\t\tDefault: fp,graph,0.5,caller,function"; 1080 "\n\t\t\t\tDefault: fp,graph,0.5,caller,function";
1077 1081
1078int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1082int cmd_top(int argc, const char **argv)
1079{ 1083{
1080 char errbuf[BUFSIZ]; 1084 char errbuf[BUFSIZ];
1081 struct perf_top top = { 1085 struct perf_top top = {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 256f1fac6f7e..d014350adc52 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -21,9 +21,11 @@
21#include "builtin.h" 21#include "builtin.h"
22#include "util/color.h" 22#include "util/color.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/event.h"
24#include "util/evlist.h" 25#include "util/evlist.h"
25#include <subcmd/exec-cmd.h> 26#include <subcmd/exec-cmd.h>
26#include "util/machine.h" 27#include "util/machine.h"
28#include "util/path.h"
27#include "util/session.h" 29#include "util/session.h"
28#include "util/thread.h" 30#include "util/thread.h"
29#include <subcmd/parse-options.h> 31#include <subcmd/parse-options.h>
@@ -31,23 +33,33 @@
31#include "util/intlist.h" 33#include "util/intlist.h"
32#include "util/thread_map.h" 34#include "util/thread_map.h"
33#include "util/stat.h" 35#include "util/stat.h"
36#include "trace/beauty/beauty.h"
34#include "trace-event.h" 37#include "trace-event.h"
35#include "util/parse-events.h" 38#include "util/parse-events.h"
36#include "util/bpf-loader.h" 39#include "util/bpf-loader.h"
37#include "callchain.h" 40#include "callchain.h"
41#include "print_binary.h"
42#include "string2.h"
38#include "syscalltbl.h" 43#include "syscalltbl.h"
39#include "rb_resort.h" 44#include "rb_resort.h"
40 45
46#include <errno.h>
47#include <inttypes.h>
41#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ 48#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
49#include <poll.h>
50#include <signal.h>
42#include <stdlib.h> 51#include <stdlib.h>
43#include <string.h> 52#include <string.h>
44#include <linux/err.h> 53#include <linux/err.h>
45#include <linux/filter.h> 54#include <linux/filter.h>
46#include <linux/audit.h> 55#include <linux/audit.h>
56#include <linux/kernel.h>
47#include <linux/random.h> 57#include <linux/random.h>
48#include <linux/stringify.h> 58#include <linux/stringify.h>
49#include <linux/time64.h> 59#include <linux/time64.h>
50 60
61#include "sane_ctype.h"
62
51#ifndef O_CLOEXEC 63#ifndef O_CLOEXEC
52# define O_CLOEXEC 02000000 64# define O_CLOEXEC 02000000
53#endif 65#endif
@@ -267,15 +279,6 @@ out_delete:
267 ({ struct syscall_tp *fields = evsel->priv; \ 279 ({ struct syscall_tp *fields = evsel->priv; \
268 fields->name.pointer(&fields->name, sample); }) 280 fields->name.pointer(&fields->name, sample); })
269 281
270struct syscall_arg {
271 unsigned long val;
272 struct thread *thread;
273 struct trace *trace;
274 void *parm;
275 u8 idx;
276 u8 mask;
277};
278
279struct strarray { 282struct strarray {
280 int offset; 283 int offset;
281 int nr_entries; 284 int nr_entries;
@@ -771,6 +774,10 @@ static struct syscall_fmt {
771 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, 774 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
772 { .name = "stat", .errmsg = true, .alias = "newstat", }, 775 { .name = "stat", .errmsg = true, .alias = "newstat", },
773 { .name = "statfs", .errmsg = true, }, 776 { .name = "statfs", .errmsg = true, },
777 { .name = "statx", .errmsg = true,
778 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
779 [2] = SCA_STATX_FLAGS, /* flags */
780 [3] = SCA_STATX_MASK, /* mask */ }, },
774 { .name = "swapoff", .errmsg = true, 781 { .name = "swapoff", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, }, 782 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
776 { .name = "swapon", .errmsg = true, 783 { .name = "swapon", .errmsg = true,
@@ -821,12 +828,21 @@ struct syscall {
821 void **arg_parm; 828 void **arg_parm;
822}; 829};
823 830
824static size_t fprintf_duration(unsigned long t, FILE *fp) 831/*
832 * We need to have this 'calculated' boolean because in some cases we really
833 * don't know what is the duration of a syscall, for instance, when we start
834 * a session and some threads are waiting for a syscall to finish, say 'poll',
835 * in which case all we can do is to print "( ? ) for duration and for the
836 * start timestamp.
837 */
838static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
825{ 839{
826 double duration = (double)t / NSEC_PER_MSEC; 840 double duration = (double)t / NSEC_PER_MSEC;
827 size_t printed = fprintf(fp, "("); 841 size_t printed = fprintf(fp, "(");
828 842
829 if (duration >= 1.0) 843 if (!calculated)
844 printed += fprintf(fp, " ? ");
845 else if (duration >= 1.0)
830 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration); 846 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
831 else if (duration >= 0.01) 847 else if (duration >= 0.01)
832 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration); 848 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
@@ -1028,13 +1044,27 @@ static bool trace__filter_duration(struct trace *trace, double t)
1028 return t < (trace->duration_filter * NSEC_PER_MSEC); 1044 return t < (trace->duration_filter * NSEC_PER_MSEC);
1029} 1045}
1030 1046
1031static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) 1047static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1032{ 1048{
1033 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC; 1049 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1034 1050
1035 return fprintf(fp, "%10.3f ", ts); 1051 return fprintf(fp, "%10.3f ", ts);
1036} 1052}
1037 1053
1054/*
1055 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1056 * using ttrace->entry_time for a thread that receives a sys_exit without
1057 * first having received a sys_enter ("poll" issued before tracing session
1058 * starts, lost sys_enter exit due to ring buffer overflow).
1059 */
1060static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1061{
1062 if (tstamp > 0)
1063 return __trace__fprintf_tstamp(trace, tstamp, fp);
1064
1065 return fprintf(fp, " ? ");
1066}
1067
1038static bool done = false; 1068static bool done = false;
1039static bool interrupted = false; 1069static bool interrupted = false;
1040 1070
@@ -1045,10 +1075,10 @@ static void sig_handler(int sig)
1045} 1075}
1046 1076
1047static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, 1077static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
1048 u64 duration, u64 tstamp, FILE *fp) 1078 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
1049{ 1079{
1050 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); 1080 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
1051 printed += fprintf_duration(duration, fp); 1081 printed += fprintf_duration(duration, duration_calculated, fp);
1052 1082
1053 if (trace->multiple_threads) { 1083 if (trace->multiple_threads) {
1054 if (trace->show_comm) 1084 if (trace->show_comm)
@@ -1450,7 +1480,7 @@ static int trace__printf_interrupted_entry(struct trace *trace, struct perf_samp
1450 1480
1451 duration = sample->time - ttrace->entry_time; 1481 duration = sample->time - ttrace->entry_time;
1452 1482
1453 printed = trace__fprintf_entry_head(trace, trace->current, duration, ttrace->entry_time, trace->output); 1483 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
1454 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str); 1484 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1455 ttrace->entry_pending = false; 1485 ttrace->entry_pending = false;
1456 1486
@@ -1497,7 +1527,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1497 1527
1498 if (sc->is_exit) { 1528 if (sc->is_exit) {
1499 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { 1529 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
1500 trace__fprintf_entry_head(trace, thread, 1, ttrace->entry_time, trace->output); 1530 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
1501 fprintf(trace->output, "%-70s)\n", ttrace->entry_str); 1531 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
1502 } 1532 }
1503 } else { 1533 } else {
@@ -1545,6 +1575,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1545{ 1575{
1546 long ret; 1576 long ret;
1547 u64 duration = 0; 1577 u64 duration = 0;
1578 bool duration_calculated = false;
1548 struct thread *thread; 1579 struct thread *thread;
1549 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0; 1580 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
1550 struct syscall *sc = trace__syscall_info(trace, evsel, id); 1581 struct syscall *sc = trace__syscall_info(trace, evsel, id);
@@ -1573,6 +1604,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1573 duration = sample->time - ttrace->entry_time; 1604 duration = sample->time - ttrace->entry_time;
1574 if (trace__filter_duration(trace, duration)) 1605 if (trace__filter_duration(trace, duration))
1575 goto out; 1606 goto out;
1607 duration_calculated = true;
1576 } else if (trace->duration_filter) 1608 } else if (trace->duration_filter)
1577 goto out; 1609 goto out;
1578 1610
@@ -1588,7 +1620,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1588 if (trace->summary_only) 1620 if (trace->summary_only)
1589 goto out; 1621 goto out;
1590 1622
1591 trace__fprintf_entry_head(trace, thread, duration, ttrace->entry_time, trace->output); 1623 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
1592 1624
1593 if (ttrace->entry_pending) { 1625 if (ttrace->entry_pending) {
1594 fprintf(trace->output, "%-70s", ttrace->entry_str); 1626 fprintf(trace->output, "%-70s", ttrace->entry_str);
@@ -1653,15 +1685,17 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1653 1685
1654 ttrace = thread__priv(thread); 1686 ttrace = thread__priv(thread);
1655 if (!ttrace) 1687 if (!ttrace)
1656 goto out; 1688 goto out_put;
1657 1689
1658 filename_len = strlen(filename); 1690 filename_len = strlen(filename);
1691 if (filename_len == 0)
1692 goto out_put;
1659 1693
1660 if (ttrace->filename.namelen < filename_len) { 1694 if (ttrace->filename.namelen < filename_len) {
1661 char *f = realloc(ttrace->filename.name, filename_len + 1); 1695 char *f = realloc(ttrace->filename.name, filename_len + 1);
1662 1696
1663 if (f == NULL) 1697 if (f == NULL)
1664 goto out; 1698 goto out_put;
1665 1699
1666 ttrace->filename.namelen = filename_len; 1700 ttrace->filename.namelen = filename_len;
1667 ttrace->filename.name = f; 1701 ttrace->filename.name = f;
@@ -1671,12 +1705,12 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1671 ttrace->filename.pending_open = true; 1705 ttrace->filename.pending_open = true;
1672 1706
1673 if (!ttrace->filename.ptr) 1707 if (!ttrace->filename.ptr)
1674 goto out; 1708 goto out_put;
1675 1709
1676 entry_str_len = strlen(ttrace->entry_str); 1710 entry_str_len = strlen(ttrace->entry_str);
1677 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */ 1711 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1678 if (remaining_space <= 0) 1712 if (remaining_space <= 0)
1679 goto out; 1713 goto out_put;
1680 1714
1681 if (filename_len > (size_t)remaining_space) { 1715 if (filename_len > (size_t)remaining_space) {
1682 filename += filename_len - remaining_space; 1716 filename += filename_len - remaining_space;
@@ -1690,6 +1724,8 @@ static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1690 1724
1691 ttrace->filename.ptr = 0; 1725 ttrace->filename.ptr = 0;
1692 ttrace->filename.entry_str_pos = 0; 1726 ttrace->filename.entry_str_pos = 0;
1727out_put:
1728 thread__put(thread);
1693out: 1729out:
1694 return 0; 1730 return 0;
1695} 1731}
@@ -1710,6 +1746,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
1710 1746
1711 ttrace->runtime_ms += runtime_ms; 1747 ttrace->runtime_ms += runtime_ms;
1712 trace->runtime_ms += runtime_ms; 1748 trace->runtime_ms += runtime_ms;
1749out_put:
1713 thread__put(thread); 1750 thread__put(thread);
1714 return 0; 1751 return 0;
1715 1752
@@ -1720,8 +1757,7 @@ out_dump:
1720 (pid_t)perf_evsel__intval(evsel, sample, "pid"), 1757 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1721 runtime, 1758 runtime,
1722 perf_evsel__intval(evsel, sample, "vruntime")); 1759 perf_evsel__intval(evsel, sample, "vruntime"));
1723 thread__put(thread); 1760 goto out_put;
1724 return 0;
1725} 1761}
1726 1762
1727static void bpf_output__printer(enum binary_printer_ops op, 1763static void bpf_output__printer(enum binary_printer_ops op,
@@ -1851,7 +1887,7 @@ static int trace__pgfault(struct trace *trace,
1851 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION, 1887 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
1852 sample->ip, &al); 1888 sample->ip, &al);
1853 1889
1854 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output); 1890 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
1855 1891
1856 fprintf(trace->output, "%sfault [", 1892 fprintf(trace->output, "%sfault [",
1857 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ? 1893 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
@@ -1920,7 +1956,7 @@ static int trace__process_sample(struct perf_tool *tool,
1920 1956
1921 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); 1957 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1922 if (thread && thread__is_filtered(thread)) 1958 if (thread && thread__is_filtered(thread))
1923 return 0; 1959 goto out;
1924 1960
1925 trace__set_base_time(trace, evsel, sample); 1961 trace__set_base_time(trace, evsel, sample);
1926 1962
@@ -1928,7 +1964,8 @@ static int trace__process_sample(struct perf_tool *tool,
1928 ++trace->nr_events; 1964 ++trace->nr_events;
1929 handler(trace, evsel, event, sample); 1965 handler(trace, evsel, event, sample);
1930 } 1966 }
1931 1967out:
1968 thread__put(thread);
1932 return err; 1969 return err;
1933} 1970}
1934 1971
@@ -1988,7 +2025,7 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
1988 for (i = 0; i < (unsigned int)argc; i++) 2025 for (i = 0; i < (unsigned int)argc; i++)
1989 rec_argv[j++] = argv[i]; 2026 rec_argv[j++] = argv[i];
1990 2027
1991 return cmd_record(j, rec_argv, NULL); 2028 return cmd_record(j, rec_argv);
1992} 2029}
1993 2030
1994static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); 2031static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
@@ -2415,8 +2452,9 @@ static int trace__replay(struct trace *trace)
2415 trace->tool.exit = perf_event__process_exit; 2452 trace->tool.exit = perf_event__process_exit;
2416 trace->tool.fork = perf_event__process_fork; 2453 trace->tool.fork = perf_event__process_fork;
2417 trace->tool.attr = perf_event__process_attr; 2454 trace->tool.attr = perf_event__process_attr;
2418 trace->tool.tracing_data = perf_event__process_tracing_data; 2455 trace->tool.tracing_data = perf_event__process_tracing_data;
2419 trace->tool.build_id = perf_event__process_build_id; 2456 trace->tool.build_id = perf_event__process_build_id;
2457 trace->tool.namespaces = perf_event__process_namespaces;
2420 2458
2421 trace->tool.ordered_events = true; 2459 trace->tool.ordered_events = true;
2422 trace->tool.ordering_requires_timestamps = true; 2460 trace->tool.ordering_requires_timestamps = true;
@@ -2785,7 +2823,7 @@ out:
2785 return err; 2823 return err;
2786} 2824}
2787 2825
2788int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 2826int cmd_trace(int argc, const char **argv)
2789{ 2827{
2790 const char *trace_usage[] = { 2828 const char *trace_usage[] = {
2791 "perf trace [<options>] [<command>]", 2829 "perf trace [<options>] [<command>]",
diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c
index 9b10cda6b6dc..d25149456a2f 100644
--- a/tools/perf/builtin-version.c
+++ b/tools/perf/builtin-version.c
@@ -1,9 +1,9 @@
1#include "util/util.h"
2#include "builtin.h" 1#include "builtin.h"
3#include "perf.h" 2#include "perf.h"
3#include <linux/compiler.h>
4#include <stdio.h>
4 5
5int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused, 6int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused)
6 const char *prefix __maybe_unused)
7{ 7{
8 printf("perf version %s\n", perf_version_string); 8 printf("perf version %s\n", perf_version_string);
9 return 0; 9 return 0;
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 036e1e35b1a8..d4d19fe3d050 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -2,46 +2,42 @@
2#define BUILTIN_H 2#define BUILTIN_H
3 3
4#include "util/util.h" 4#include "util/util.h"
5#include "util/strbuf.h"
6 5
7extern const char perf_usage_string[]; 6extern const char perf_usage_string[];
8extern const char perf_more_info_string[]; 7extern const char perf_more_info_string[];
9 8
10void list_common_cmds_help(void); 9void list_common_cmds_help(void);
11const char *help_unknown_cmd(const char *cmd); 10const char *help_unknown_cmd(const char *cmd);
12void prune_packed_objects(int);
13int read_line_with_nul(char *buf, int size, FILE *file);
14int check_pager_config(const char *cmd);
15 11
16int cmd_annotate(int argc, const char **argv, const char *prefix); 12int cmd_annotate(int argc, const char **argv);
17int cmd_bench(int argc, const char **argv, const char *prefix); 13int cmd_bench(int argc, const char **argv);
18int cmd_buildid_cache(int argc, const char **argv, const char *prefix); 14int cmd_buildid_cache(int argc, const char **argv);
19int cmd_buildid_list(int argc, const char **argv, const char *prefix); 15int cmd_buildid_list(int argc, const char **argv);
20int cmd_config(int argc, const char **argv, const char *prefix); 16int cmd_config(int argc, const char **argv);
21int cmd_c2c(int argc, const char **argv, const char *prefix); 17int cmd_c2c(int argc, const char **argv);
22int cmd_diff(int argc, const char **argv, const char *prefix); 18int cmd_diff(int argc, const char **argv);
23int cmd_evlist(int argc, const char **argv, const char *prefix); 19int cmd_evlist(int argc, const char **argv);
24int cmd_help(int argc, const char **argv, const char *prefix); 20int cmd_help(int argc, const char **argv);
25int cmd_sched(int argc, const char **argv, const char *prefix); 21int cmd_sched(int argc, const char **argv);
26int cmd_kallsyms(int argc, const char **argv, const char *prefix); 22int cmd_kallsyms(int argc, const char **argv);
27int cmd_list(int argc, const char **argv, const char *prefix); 23int cmd_list(int argc, const char **argv);
28int cmd_record(int argc, const char **argv, const char *prefix); 24int cmd_record(int argc, const char **argv);
29int cmd_report(int argc, const char **argv, const char *prefix); 25int cmd_report(int argc, const char **argv);
30int cmd_stat(int argc, const char **argv, const char *prefix); 26int cmd_stat(int argc, const char **argv);
31int cmd_timechart(int argc, const char **argv, const char *prefix); 27int cmd_timechart(int argc, const char **argv);
32int cmd_top(int argc, const char **argv, const char *prefix); 28int cmd_top(int argc, const char **argv);
33int cmd_script(int argc, const char **argv, const char *prefix); 29int cmd_script(int argc, const char **argv);
34int cmd_version(int argc, const char **argv, const char *prefix); 30int cmd_version(int argc, const char **argv);
35int cmd_probe(int argc, const char **argv, const char *prefix); 31int cmd_probe(int argc, const char **argv);
36int cmd_kmem(int argc, const char **argv, const char *prefix); 32int cmd_kmem(int argc, const char **argv);
37int cmd_lock(int argc, const char **argv, const char *prefix); 33int cmd_lock(int argc, const char **argv);
38int cmd_kvm(int argc, const char **argv, const char *prefix); 34int cmd_kvm(int argc, const char **argv);
39int cmd_test(int argc, const char **argv, const char *prefix); 35int cmd_test(int argc, const char **argv);
40int cmd_trace(int argc, const char **argv, const char *prefix); 36int cmd_trace(int argc, const char **argv);
41int cmd_inject(int argc, const char **argv, const char *prefix); 37int cmd_inject(int argc, const char **argv);
42int cmd_mem(int argc, const char **argv, const char *prefix); 38int cmd_mem(int argc, const char **argv);
43int cmd_data(int argc, const char **argv, const char *prefix); 39int cmd_data(int argc, const char **argv);
44int cmd_ftrace(int argc, const char **argv, const char *prefix); 40int cmd_ftrace(int argc, const char **argv);
45 41
46int find_scripts(char **scripts_array, char **scripts_path_array); 42int find_scripts(char **scripts_array, char **scripts_path_array);
47#endif 43#endif
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
index c747bfd7f14d..83fe2202382e 100755
--- a/tools/perf/check-headers.sh
+++ b/tools/perf/check-headers.sh
@@ -1,7 +1,9 @@
1#!/bin/sh 1#!/bin/sh
2 2
3HEADERS=' 3HEADERS='
4include/uapi/linux/fcntl.h
4include/uapi/linux/perf_event.h 5include/uapi/linux/perf_event.h
6include/uapi/linux/stat.h
5include/linux/hash.h 7include/linux/hash.h
6include/uapi/linux/hw_breakpoint.h 8include/uapi/linux/hw_breakpoint.h
7arch/x86/include/asm/disabled-features.h 9arch/x86/include/asm/disabled-features.h
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index ac3efd396a72..2d0caf20ff3a 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-data mainporcelain common 10perf-data mainporcelain common
11perf-diff mainporcelain common 11perf-diff mainporcelain common
12perf-c2c mainporcelain common
12perf-config mainporcelain common 13perf-config mainporcelain common
13perf-evlist mainporcelain common 14perf-evlist mainporcelain common
14perf-ftrace mainporcelain common 15perf-ftrace mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 6d5479e03e0d..628a5e412cb1 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -17,11 +17,18 @@
17#include <subcmd/parse-options.h> 17#include <subcmd/parse-options.h>
18#include "util/bpf-loader.h" 18#include "util/bpf-loader.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include "util/event.h"
20#include <api/fs/fs.h> 21#include <api/fs/fs.h>
21#include <api/fs/tracing_path.h> 22#include <api/fs/tracing_path.h>
23#include <errno.h>
22#include <pthread.h> 24#include <pthread.h>
25#include <signal.h>
23#include <stdlib.h> 26#include <stdlib.h>
24#include <time.h> 27#include <time.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <unistd.h>
31#include <linux/kernel.h>
25 32
26const char perf_usage_string[] = 33const char perf_usage_string[] =
27 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]"; 34 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
@@ -34,7 +41,7 @@ const char *input_name;
34 41
35struct cmd_struct { 42struct cmd_struct {
36 const char *cmd; 43 const char *cmd;
37 int (*fn)(int, const char **, const char *); 44 int (*fn)(int, const char **);
38 int option; 45 int option;
39}; 46};
40 47
@@ -88,7 +95,7 @@ static int pager_command_config(const char *var, const char *value, void *data)
88} 95}
89 96
90/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ 97/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
91int check_pager_config(const char *cmd) 98static int check_pager_config(const char *cmd)
92{ 99{
93 int err; 100 int err;
94 struct pager_config c; 101 struct pager_config c;
@@ -267,71 +274,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
267 return handled; 274 return handled;
268} 275}
269 276
270static int handle_alias(int *argcp, const char ***argv)
271{
272 int envchanged = 0, ret = 0, saved_errno = errno;
273 int count, option_count;
274 const char **new_argv;
275 const char *alias_command;
276 char *alias_string;
277
278 alias_command = (*argv)[0];
279 alias_string = alias_lookup(alias_command);
280 if (alias_string) {
281 if (alias_string[0] == '!') {
282 if (*argcp > 1) {
283 struct strbuf buf;
284
285 if (strbuf_init(&buf, PATH_MAX) < 0 ||
286 strbuf_addstr(&buf, alias_string) < 0 ||
287 sq_quote_argv(&buf, (*argv) + 1,
288 PATH_MAX) < 0)
289 die("Failed to allocate memory.");
290 free(alias_string);
291 alias_string = buf.buf;
292 }
293 ret = system(alias_string + 1);
294 if (ret >= 0 && WIFEXITED(ret) &&
295 WEXITSTATUS(ret) != 127)
296 exit(WEXITSTATUS(ret));
297 die("Failed to run '%s' when expanding alias '%s'",
298 alias_string + 1, alias_command);
299 }
300 count = split_cmdline(alias_string, &new_argv);
301 if (count < 0)
302 die("Bad alias.%s string", alias_command);
303 option_count = handle_options(&new_argv, &count, &envchanged);
304 if (envchanged)
305 die("alias '%s' changes environment variables\n"
306 "You can use '!perf' in the alias to do this.",
307 alias_command);
308 memmove(new_argv - option_count, new_argv,
309 count * sizeof(char *));
310 new_argv -= option_count;
311
312 if (count < 1)
313 die("empty alias for %s", alias_command);
314
315 if (!strcmp(alias_command, new_argv[0]))
316 die("recursive alias: %s", alias_command);
317
318 new_argv = realloc(new_argv, sizeof(char *) *
319 (count + *argcp + 1));
320 /* insert after command name */
321 memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
322 new_argv[count + *argcp] = NULL;
323
324 *argv = new_argv;
325 *argcp += count - 1;
326
327 ret = 1;
328 }
329
330 errno = saved_errno;
331
332 return ret;
333}
334
335#define RUN_SETUP (1<<0) 277#define RUN_SETUP (1<<0)
336#define USE_PAGER (1<<1) 278#define USE_PAGER (1<<1)
337 279
@@ -339,13 +281,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
339{ 281{
340 int status; 282 int status;
341 struct stat st; 283 struct stat st;
342 const char *prefix;
343 char sbuf[STRERR_BUFSIZE]; 284 char sbuf[STRERR_BUFSIZE];
344 285
345 prefix = NULL;
346 if (p->option & RUN_SETUP)
347 prefix = NULL; /* setup_perf_directory(); */
348
349 if (use_browser == -1) 286 if (use_browser == -1)
350 use_browser = check_browser_config(p->cmd); 287 use_browser = check_browser_config(p->cmd);
351 288
@@ -356,7 +293,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
356 commit_pager_choice(); 293 commit_pager_choice();
357 294
358 perf_env__set_cmdline(&perf_env, argc, argv); 295 perf_env__set_cmdline(&perf_env, argc, argv);
359 status = p->fn(argc, argv, prefix); 296 status = p->fn(argc, argv);
360 perf_config__exit(); 297 perf_config__exit();
361 exit_browser(status); 298 exit_browser(status);
362 perf_env__exit(&perf_env); 299 perf_env__exit(&perf_env);
@@ -397,16 +334,6 @@ static void handle_internal_command(int argc, const char **argv)
397{ 334{
398 const char *cmd = argv[0]; 335 const char *cmd = argv[0];
399 unsigned int i; 336 unsigned int i;
400 static const char ext[] = STRIP_EXTENSION;
401
402 if (sizeof(ext) > 1) {
403 i = strlen(argv[0]) - strlen(ext);
404 if (i > 0 && !strcmp(argv[0] + i, ext)) {
405 char *argv0 = strdup(argv[0]);
406 argv[0] = cmd = argv0;
407 argv0[i] = '\0';
408 }
409 }
410 337
411 /* Turn "perf cmd --help" into "perf help cmd" */ 338 /* Turn "perf cmd --help" into "perf help cmd" */
412 if (argc > 1 && !strcmp(argv[1], "--help")) { 339 if (argc > 1 && !strcmp(argv[1], "--help")) {
@@ -448,7 +375,8 @@ static void execv_dashed_external(const char **argv)
448 if (status != -ERR_RUN_COMMAND_EXEC) { 375 if (status != -ERR_RUN_COMMAND_EXEC) {
449 if (IS_RUN_COMMAND_ERR(status)) { 376 if (IS_RUN_COMMAND_ERR(status)) {
450do_die: 377do_die:
451 die("unable to run '%s'", argv[0]); 378 pr_err("FATAL: unable to run '%s'", argv[0]);
379 status = -128;
452 } 380 }
453 exit(-status); 381 exit(-status);
454 } 382 }
@@ -460,25 +388,12 @@ do_die:
460 388
461static int run_argv(int *argcp, const char ***argv) 389static int run_argv(int *argcp, const char ***argv)
462{ 390{
463 int done_alias = 0; 391 /* See if it's an internal command */
392 handle_internal_command(*argcp, *argv);
464 393
465 while (1) { 394 /* .. then try the external ones */
466 /* See if it's an internal command */ 395 execv_dashed_external(*argv);
467 handle_internal_command(*argcp, *argv); 396 return 0;
468
469 /* .. then try the external ones */
470 execv_dashed_external(*argv);
471
472 /* It could be an alias -- this works around the insanity
473 * of overriding "perf log" with "perf show" by having
474 * alias.log = show
475 */
476 if (done_alias || !handle_alias(argcp, argv))
477 break;
478 done_alias = 1;
479 }
480
481 return done_alias;
482} 397}
483 398
484static void pthread__block_sigwinch(void) 399static void pthread__block_sigwinch(void)
@@ -566,7 +481,7 @@ int main(int argc, const char **argv)
566#ifdef HAVE_LIBAUDIT_SUPPORT 481#ifdef HAVE_LIBAUDIT_SUPPORT
567 setup_path(); 482 setup_path();
568 argv[0] = "trace"; 483 argv[0] = "trace";
569 return cmd_trace(argc, argv, NULL); 484 return cmd_trace(argc, argv);
570#else 485#else
571 fprintf(stderr, 486 fprintf(stderr,
572 "trace command not available: missing audit-libs devel package at build time.\n"); 487 "trace command not available: missing audit-libs devel package at build time.\n");
@@ -611,17 +526,12 @@ int main(int argc, const char **argv)
611 526
612 while (1) { 527 while (1) {
613 static int done_help; 528 static int done_help;
614 int was_alias = run_argv(&argc, &argv); 529
530 run_argv(&argc, &argv);
615 531
616 if (errno != ENOENT) 532 if (errno != ENOENT)
617 break; 533 break;
618 534
619 if (was_alias) {
620 fprintf(stderr, "Expansion of alias '%s' failed; "
621 "'%s' is not a perf-command\n",
622 cmd, argv[0]);
623 goto out;
624 }
625 if (!done_help) { 535 if (!done_help) {
626 cmd = argv[0] = help_unknown_cmd(cmd); 536 cmd = argv[0] = help_unknown_cmd(cmd);
627 done_help = 1; 537 done_help = 1;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 1c27d947c2fe..806c216a1078 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -50,6 +50,7 @@ struct record_opts {
50 bool running_time; 50 bool running_time;
51 bool full_auxtrace; 51 bool full_auxtrace;
52 bool auxtrace_snapshot_mode; 52 bool auxtrace_snapshot_mode;
53 bool record_namespaces;
53 bool record_switch_events; 54 bool record_switch_events;
54 bool all_kernel; 55 bool all_kernel;
55 bool all_user; 56 bool all_user;
diff --git a/tools/perf/pmu-events/arch/x86/broadwell/uncore.json b/tools/perf/pmu-events/arch/x86/broadwell/uncore.json
new file mode 100644
index 000000000000..28e1e159a3cb
--- /dev/null
+++ b/tools/perf/pmu-events/arch/x86/broadwell/uncore.json
@@ -0,0 +1,278 @@
1[
2 {
3 "Unit": "CBO",
4 "EventCode": "0x22",
5 "UMask": "0x41",
6 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_XCORE",
7 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which misses in some processor core.",
8 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which misses in some processor core.",
9 "Counter": "0,1",
10 "CounterMask": "0",
11 "Invert": "0",
12 "EdgeDetect": "0"
13 },
14 {
15 "Unit": "CBO",
16 "EventCode": "0x22",
17 "UMask": "0x81",
18 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_EVICTION",
19 "BriefDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.",
20 "PublicDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.",
21 "Counter": "0,1",
22 "CounterMask": "0",
23 "Invert": "0",
24 "EdgeDetect": "0"
25 },
26 {
27 "Unit": "CBO",
28 "EventCode": "0x22",
29 "UMask": "0x44",
30 "EventName": "UNC_CBO_XSNP_RESPONSE.HIT_XCORE",
31 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a non-modified line in some processor core.",
32 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a non-modified line in some processor core.",
33 "Counter": "0,1",
34 "CounterMask": "0",
35 "Invert": "0",
36 "EdgeDetect": "0"
37 },
38 {
39 "Unit": "CBO",
40 "EventCode": "0x22",
41 "UMask": "0x48",
42 "EventName": "UNC_CBO_XSNP_RESPONSE.HITM_XCORE",
43 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a modified line in some processor core.",
44 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a modified line in some processor core.",
45 "Counter": "0,1",
46 "CounterMask": "0",
47 "Invert": "0",
48 "EdgeDetect": "0"
49 },
50 {
51 "Unit": "CBO",
52 "EventCode": "0x34",
53 "UMask": "0x11",
54 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_M",
55 "BriefDescription": "L3 Lookup read request that access cache and found line in M-state",
56 "PublicDescription": "L3 Lookup read request that access cache and found line in M-state.",
57 "Counter": "0,1",
58 "CounterMask": "0",
59 "Invert": "0",
60 "EdgeDetect": "0"
61 },
62 {
63 "Unit": "CBO",
64 "EventCode": "0x34",
65 "UMask": "0x21",
66 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_M",
67 "BriefDescription": "L3 Lookup write request that access cache and found line in M-state",
68 "PublicDescription": "L3 Lookup write request that access cache and found line in M-state.",
69 "Counter": "0,1",
70 "CounterMask": "0",
71 "Invert": "0",
72 "EdgeDetect": "0"
73 },
74 {
75 "Unit": "CBO",
76 "EventCode": "0x34",
77 "UMask": "0x81",
78 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_M",
79 "BriefDescription": "L3 Lookup any request that access cache and found line in M-state",
80 "PublicDescription": "L3 Lookup any request that access cache and found line in M-state.",
81 "Counter": "0,1",
82 "CounterMask": "0",
83 "Invert": "0",
84 "EdgeDetect": "0"
85 },
86 {
87 "Unit": "CBO",
88 "EventCode": "0x34",
89 "UMask": "0x18",
90 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_I",
91 "BriefDescription": "L3 Lookup read request that access cache and found line in I-state",
92 "PublicDescription": "L3 Lookup read request that access cache and found line in I-state.",
93 "Counter": "0,1",
94 "CounterMask": "0",
95 "Invert": "0",
96 "EdgeDetect": "0"
97 },
98 {
99 "Unit": "CBO",
100 "EventCode": "0x34",
101 "UMask": "0x88",
102 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_I",
103 "BriefDescription": "L3 Lookup any request that access cache and found line in I-state",
104 "PublicDescription": "L3 Lookup any request that access cache and found line in I-state.",
105 "Counter": "0,1",
106 "CounterMask": "0",
107 "Invert": "0",
108 "EdgeDetect": "0"
109 },
110 {
111 "Unit": "CBO",
112 "EventCode": "0x34",
113 "UMask": "0x1f",
114 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_MESI",
115 "BriefDescription": "L3 Lookup read request that access cache and found line in any MESI-state",
116 "PublicDescription": "L3 Lookup read request that access cache and found line in any MESI-state.",
117 "Counter": "0,1",
118 "CounterMask": "0",
119 "Invert": "0",
120 "EdgeDetect": "0"
121 },
122 {
123 "Unit": "CBO",
124 "EventCode": "0x34",
125 "UMask": "0x2f",
126 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_MESI",
127 "BriefDescription": "L3 Lookup write request that access cache and found line in MESI-state",
128 "PublicDescription": "L3 Lookup write request that access cache and found line in MESI-state.",
129 "Counter": "0,1",
130 "CounterMask": "0",
131 "Invert": "0",
132 "EdgeDetect": "0"
133 },
134 {
135 "Unit": "CBO",
136 "EventCode": "0x34",
137 "UMask": "0x8f",
138 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_MESI",
139 "BriefDescription": "L3 Lookup any request that access cache and found line in MESI-state",
140 "PublicDescription": "L3 Lookup any request that access cache and found line in MESI-state.",
141 "Counter": "0,1",
142 "CounterMask": "0",
143 "Invert": "0",
144 "EdgeDetect": "0"
145 },
146 {
147 "Unit": "CBO",
148 "EventCode": "0x34",
149 "UMask": "0x86",
150 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_ES",
151 "BriefDescription": "L3 Lookup any request that access cache and found line in E or S-state",
152 "PublicDescription": "L3 Lookup any request that access cache and found line in E or S-state.",
153 "Counter": "0,1",
154 "CounterMask": "0",
155 "Invert": "0",
156 "EdgeDetect": "0"
157 },
158 {
159 "Unit": "CBO",
160 "EventCode": "0x34",
161 "UMask": "0x16",
162 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_ES",
163 "BriefDescription": "L3 Lookup read request that access cache and found line in E or S-state",
164 "PublicDescription": "L3 Lookup read request that access cache and found line in E or S-state.",
165 "Counter": "0,1",
166 "CounterMask": "0",
167 "Invert": "0",
168 "EdgeDetect": "0"
169 },
170 {
171 "Unit": "CBO",
172 "EventCode": "0x34",
173 "UMask": "0x26",
174 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_ES",
175 "BriefDescription": "L3 Lookup write request that access cache and found line in E or S-state",
176 "PublicDescription": "L3 Lookup write request that access cache and found line in E or S-state.",
177 "Counter": "0,1",
178 "CounterMask": "0",
179 "Invert": "0",
180 "EdgeDetect": "0"
181 },
182 {
183 "Unit": "iMPH-U",
184 "EventCode": "0x80",
185 "UMask": "0x01",
186 "EventName": "UNC_ARB_TRK_OCCUPANCY.ALL",
187 "BriefDescription": "Each cycle count number of all Core outgoing valid entries. Such entry is defined as valid from it's allocation till first of IDI0 or DRS0 messages is sent out. Accounts for Coherent and non-coherent traffic.",
188 "PublicDescription": "Each cycle count number of all Core outgoing valid entries. Such entry is defined as valid from it's allocation till first of IDI0 or DRS0 messages is sent out. Accounts for Coherent and non-coherent traffic.",
189 "Counter": "0,",
190 "CounterMask": "0",
191 "Invert": "0",
192 "EdgeDetect": "0"
193 },
194 {
195 "Unit": "iMPH-U",
196 "EventCode": "0x80",
197 "UMask": "0x02",
198 "EventName": "UNC_ARB_TRK_OCCUPANCY.DRD_DIRECT",
199 "BriefDescription": "Each cycle count number of 'valid' coherent Data Read entries that are in DirectData mode. Such entry is defined as valid when it is allocated till data sent to Core (first chunk, IDI0). Applicable for IA Cores' requests in normal case.",
200 "PublicDescription": "Each cycle count number of 'valid' coherent Data Read entries that are in DirectData mode. Such entry is defined as valid when it is allocated till data sent to Core (first chunk, IDI0). Applicable for IA Cores' requests in normal case.",
201 "Counter": "0,",
202 "CounterMask": "0",
203 "Invert": "0",
204 "EdgeDetect": "0"
205 },
206 {
207 "Unit": "iMPH-U",
208 "EventCode": "0x81",
209 "UMask": "0x01",
210 "EventName": "UNC_ARB_TRK_REQUESTS.ALL",
211 "BriefDescription": "Total number of Core outgoing entries allocated. Accounts for Coherent and non-coherent traffic.",
212 "PublicDescription": "Total number of Core outgoing entries allocated. Accounts for Coherent and non-coherent traffic.",
213 "Counter": "0,1",
214 "CounterMask": "0",
215 "Invert": "0",
216 "EdgeDetect": "0"
217 },
218 {
219 "Unit": "iMPH-U",
220 "EventCode": "0x81",
221 "UMask": "0x02",
222 "EventName": "UNC_ARB_TRK_REQUESTS.DRD_DIRECT",
223 "BriefDescription": "Number of Core coherent Data Read entries allocated in DirectData mode",
224 "PublicDescription": "Number of Core coherent Data Read entries allocated in DirectData mode.",
225 "Counter": "0,1",
226 "CounterMask": "0",
227 "Invert": "0",
228 "EdgeDetect": "0"
229 },
230 {
231 "Unit": "iMPH-U",
232 "EventCode": "0x81",
233 "UMask": "0x20",
234 "EventName": "UNC_ARB_TRK_REQUESTS.WRITES",
235 "BriefDescription": "Number of Writes allocated - any write transactions: full/partials writes and evictions.",
236 "PublicDescription": "Number of Writes allocated - any write transactions: full/partials writes and evictions.",
237 "Counter": "0,1",
238 "CounterMask": "0",
239 "Invert": "0",
240 "EdgeDetect": "0"
241 },
242 {
243 "Unit": "iMPH-U",
244 "EventCode": "0x84",
245 "UMask": "0x01",
246 "EventName": "UNC_ARB_COH_TRK_REQUESTS.ALL",
247 "BriefDescription": "Number of entries allocated. Account for Any type: e.g. Snoop, Core aperture, etc.",
248 "PublicDescription": "Number of entries allocated. Account for Any type: e.g. Snoop, Core aperture, etc.",
249 "Counter": "0,1",
250 "CounterMask": "0",
251 "Invert": "0",
252 "EdgeDetect": "0"
253 },
254 {
255 "Unit": "iMPH-U",
256 "EventCode": "0x80",
257 "UMask": "0x01",
258 "EventName": "UNC_ARB_TRK_OCCUPANCY.CYCLES_WITH_ANY_REQUEST",
259 "BriefDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.;",
260 "PublicDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
261 "Counter": "0,",
262 "CounterMask": "1",
263 "Invert": "0",
264 "EdgeDetect": "0"
265 },
266 {
267 "Unit": "NCU",
268 "EventCode": "0x0",
269 "UMask": "0x01",
270 "EventName": "UNC_CLOCK.SOCKET",
271 "BriefDescription": "This 48-bit fixed counter counts the UCLK cycles",
272 "PublicDescription": "This 48-bit fixed counter counts the UCLK cycles.",
273 "Counter": "FIXED",
274 "CounterMask": "0",
275 "Invert": "0",
276 "EdgeDetect": "0"
277 }
278] \ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/broadwellde/uncore-cache.json b/tools/perf/pmu-events/arch/x86/broadwellde/uncore-cache.json
index 076459c51d4e..58ed6d33d1f4 100644
--- a/tools/perf/pmu-events/arch/x86/broadwellde/uncore-cache.json
+++ b/tools/perf/pmu-events/arch/x86/broadwellde/uncore-cache.json
@@ -1,13 +1,13 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "Uncore cache clock ticks. Derived from unc_c_clockticks", 3 "BriefDescription": "Uncore cache clock ticks",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_C_CLOCKTICKS", 5 "EventName": "UNC_C_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "CBO" 7 "Unit": "CBO"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch). Derived from unc_c_llc_lookup.any", 10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch)",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0x34", 12 "EventCode": "0x34",
13 "EventName": "UNC_C_LLC_LOOKUP.ANY", 13 "EventName": "UNC_C_LLC_LOOKUP.ANY",
@@ -18,7 +18,7 @@
18 "Unit": "CBO" 18 "Unit": "CBO"
19 }, 19 },
20 { 20 {
21 "BriefDescription": "M line evictions from LLC (writebacks to memory). Derived from unc_c_llc_victims.m_state", 21 "BriefDescription": "M line evictions from LLC (writebacks to memory)",
22 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
23 "EventCode": "0x37", 23 "EventCode": "0x37",
24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE", 24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE",
@@ -212,7 +212,7 @@
212 "Unit": "CBO" 212 "Unit": "CBO"
213 }, 213 },
214 { 214 {
215 "BriefDescription": "read requests to home agent. Derived from unc_h_requests.reads", 215 "BriefDescription": "read requests to home agent",
216 "Counter": "0,1,2,3", 216 "Counter": "0,1,2,3",
217 "EventCode": "0x1", 217 "EventCode": "0x1",
218 "EventName": "UNC_H_REQUESTS.READS", 218 "EventName": "UNC_H_REQUESTS.READS",
@@ -221,7 +221,7 @@
221 "Unit": "HA" 221 "Unit": "HA"
222 }, 222 },
223 { 223 {
224 "BriefDescription": "read requests to local home agent. Derived from unc_h_requests.reads_local", 224 "BriefDescription": "read requests to local home agent",
225 "Counter": "0,1,2,3", 225 "Counter": "0,1,2,3",
226 "EventCode": "0x1", 226 "EventCode": "0x1",
227 "EventName": "UNC_H_REQUESTS.READS_LOCAL", 227 "EventName": "UNC_H_REQUESTS.READS_LOCAL",
@@ -230,7 +230,7 @@
230 "Unit": "HA" 230 "Unit": "HA"
231 }, 231 },
232 { 232 {
233 "BriefDescription": "read requests to remote home agent. Derived from unc_h_requests.reads_remote", 233 "BriefDescription": "read requests to remote home agent",
234 "Counter": "0,1,2,3", 234 "Counter": "0,1,2,3",
235 "EventCode": "0x1", 235 "EventCode": "0x1",
236 "EventName": "UNC_H_REQUESTS.READS_REMOTE", 236 "EventName": "UNC_H_REQUESTS.READS_REMOTE",
@@ -239,7 +239,7 @@
239 "Unit": "HA" 239 "Unit": "HA"
240 }, 240 },
241 { 241 {
242 "BriefDescription": "write requests to home agent. Derived from unc_h_requests.writes", 242 "BriefDescription": "write requests to home agent",
243 "Counter": "0,1,2,3", 243 "Counter": "0,1,2,3",
244 "EventCode": "0x1", 244 "EventCode": "0x1",
245 "EventName": "UNC_H_REQUESTS.WRITES", 245 "EventName": "UNC_H_REQUESTS.WRITES",
@@ -248,7 +248,7 @@
248 "Unit": "HA" 248 "Unit": "HA"
249 }, 249 },
250 { 250 {
251 "BriefDescription": "write requests to local home agent. Derived from unc_h_requests.writes_local", 251 "BriefDescription": "write requests to local home agent",
252 "Counter": "0,1,2,3", 252 "Counter": "0,1,2,3",
253 "EventCode": "0x1", 253 "EventCode": "0x1",
254 "EventName": "UNC_H_REQUESTS.WRITES_LOCAL", 254 "EventName": "UNC_H_REQUESTS.WRITES_LOCAL",
@@ -257,7 +257,7 @@
257 "Unit": "HA" 257 "Unit": "HA"
258 }, 258 },
259 { 259 {
260 "BriefDescription": "write requests to remote home agent. Derived from unc_h_requests.writes_remote", 260 "BriefDescription": "write requests to remote home agent",
261 "Counter": "0,1,2,3", 261 "Counter": "0,1,2,3",
262 "EventCode": "0x1", 262 "EventCode": "0x1",
263 "EventName": "UNC_H_REQUESTS.WRITES_REMOTE", 263 "EventName": "UNC_H_REQUESTS.WRITES_REMOTE",
@@ -266,7 +266,7 @@
266 "Unit": "HA" 266 "Unit": "HA"
267 }, 267 },
268 { 268 {
269 "BriefDescription": "Conflict requests (requests for same address from multiple agents simultaneously). Derived from unc_h_snoop_resp.rspcnflct", 269 "BriefDescription": "Conflict requests (requests for same address from multiple agents simultaneously)",
270 "Counter": "0,1,2,3", 270 "Counter": "0,1,2,3",
271 "EventCode": "0x21", 271 "EventCode": "0x21",
272 "EventName": "UNC_H_SNOOP_RESP.RSPCNFLCT", 272 "EventName": "UNC_H_SNOOP_RESP.RSPCNFLCT",
@@ -275,7 +275,7 @@
275 "Unit": "HA" 275 "Unit": "HA"
276 }, 276 },
277 { 277 {
278 "BriefDescription": "M line forwarded from remote cache along with writeback to memory. Derived from unc_h_snoop_resp.rsp_fwd_wb", 278 "BriefDescription": "M line forwarded from remote cache along with writeback to memory",
279 "Counter": "0,1,2,3", 279 "Counter": "0,1,2,3",
280 "EventCode": "0x21", 280 "EventCode": "0x21",
281 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB", 281 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB",
@@ -285,7 +285,7 @@
285 "Unit": "HA" 285 "Unit": "HA"
286 }, 286 },
287 { 287 {
288 "BriefDescription": "M line forwarded from remote cache with no writeback to memory. Derived from unc_h_snoop_resp.rspifwd", 288 "BriefDescription": "M line forwarded from remote cache with no writeback to memory",
289 "Counter": "0,1,2,3", 289 "Counter": "0,1,2,3",
290 "EventCode": "0x21", 290 "EventCode": "0x21",
291 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD", 291 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD",
@@ -295,7 +295,7 @@
295 "Unit": "HA" 295 "Unit": "HA"
296 }, 296 },
297 { 297 {
298 "BriefDescription": "Shared line response from remote cache. Derived from unc_h_snoop_resp.rsps", 298 "BriefDescription": "Shared line response from remote cache",
299 "Counter": "0,1,2,3", 299 "Counter": "0,1,2,3",
300 "EventCode": "0x21", 300 "EventCode": "0x21",
301 "EventName": "UNC_H_SNOOP_RESP.RSPS", 301 "EventName": "UNC_H_SNOOP_RESP.RSPS",
@@ -305,7 +305,7 @@
305 "Unit": "HA" 305 "Unit": "HA"
306 }, 306 },
307 { 307 {
308 "BriefDescription": "Shared line forwarded from remote cache. Derived from unc_h_snoop_resp.rspsfwd", 308 "BriefDescription": "Shared line forwarded from remote cache",
309 "Counter": "0,1,2,3", 309 "Counter": "0,1,2,3",
310 "EventCode": "0x21", 310 "EventCode": "0x21",
311 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD", 311 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD",
diff --git a/tools/perf/pmu-events/arch/x86/broadwellde/uncore-memory.json b/tools/perf/pmu-events/arch/x86/broadwellde/uncore-memory.json
index d17dc235f734..f4b0745cdbbf 100644
--- a/tools/perf/pmu-events/arch/x86/broadwellde/uncore-memory.json
+++ b/tools/perf/pmu-events/arch/x86/broadwellde/uncore-memory.json
@@ -3,7 +3,7 @@
3 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd", 3 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x4", 5 "EventCode": "0x4",
6 "EventName": "UNC_M_CAS_COUNT.RD", 6 "EventName": "LLC_MISSES.MEM_READ",
7 "PerPkg": "1", 7 "PerPkg": "1",
8 "ScaleUnit": "64Bytes", 8 "ScaleUnit": "64Bytes",
9 "UMask": "0x3", 9 "UMask": "0x3",
@@ -13,48 +13,51 @@
13 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr", 13 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr",
14 "Counter": "0,1,2,3", 14 "Counter": "0,1,2,3",
15 "EventCode": "0x4", 15 "EventCode": "0x4",
16 "EventName": "UNC_M_CAS_COUNT.WR", 16 "EventName": "LLC_MISSES.MEM_WRITE",
17 "PerPkg": "1", 17 "PerPkg": "1",
18 "ScaleUnit": "64Bytes", 18 "ScaleUnit": "64Bytes",
19 "UMask": "0xC", 19 "UMask": "0xC",
20 "Unit": "iMC" 20 "Unit": "iMC"
21 }, 21 },
22 { 22 {
23 "BriefDescription": "Memory controller clock ticks. Derived from unc_m_clockticks", 23 "BriefDescription": "Memory controller clock ticks",
24 "Counter": "0,1,2,3", 24 "Counter": "0,1,2,3",
25 "EventName": "UNC_M_CLOCKTICKS", 25 "EventName": "UNC_M_DCLOCKTICKS",
26 "PerPkg": "1", 26 "PerPkg": "1",
27 "Unit": "iMC" 27 "Unit": "iMC"
28 }, 28 },
29 { 29 {
30 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode. Derived from unc_m_power_channel_ppd", 30 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode",
31 "Counter": "0,1,2,3", 31 "Counter": "0,1,2,3",
32 "EventCode": "0x85", 32 "EventCode": "0x85",
33 "EventName": "UNC_M_POWER_CHANNEL_PPD", 33 "EventName": "UNC_M_POWER_CHANNEL_PPD",
34 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.", 34 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_DCLOCKTICKS) * 100.",
35 "MetricName": "power_channel_ppd %",
35 "PerPkg": "1", 36 "PerPkg": "1",
36 "Unit": "iMC" 37 "Unit": "iMC"
37 }, 38 },
38 { 39 {
39 "BriefDescription": "Cycles all ranks are in critical thermal throttle. Derived from unc_m_power_critical_throttle_cycles", 40 "BriefDescription": "Cycles all ranks are in critical thermal throttle",
40 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
41 "EventCode": "0x86", 42 "EventCode": "0x86",
42 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES", 43 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES",
43 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.", 44 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_DCLOCKTICKS) * 100.",
45 "MetricName": "power_critical_throttle_cycles %",
44 "PerPkg": "1", 46 "PerPkg": "1",
45 "Unit": "iMC" 47 "Unit": "iMC"
46 }, 48 },
47 { 49 {
48 "BriefDescription": "Cycles Memory is in self refresh power mode. Derived from unc_m_power_self_refresh", 50 "BriefDescription": "Cycles Memory is in self refresh power mode",
49 "Counter": "0,1,2,3", 51 "Counter": "0,1,2,3",
50 "EventCode": "0x43", 52 "EventCode": "0x43",
51 "EventName": "UNC_M_POWER_SELF_REFRESH", 53 "EventName": "UNC_M_POWER_SELF_REFRESH",
52 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.", 54 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_DCLOCKTICKS) * 100.",
55 "MetricName": "power_self_refresh %",
53 "PerPkg": "1", 56 "PerPkg": "1",
54 "Unit": "iMC" 57 "Unit": "iMC"
55 }, 58 },
56 { 59 {
57 "BriefDescription": "Pre-charges due to page misses. Derived from unc_m_pre_count.page_miss", 60 "BriefDescription": "Pre-charges due to page misses",
58 "Counter": "0,1,2,3", 61 "Counter": "0,1,2,3",
59 "EventCode": "0x2", 62 "EventCode": "0x2",
60 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS", 63 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS",
@@ -63,7 +66,7 @@
63 "Unit": "iMC" 66 "Unit": "iMC"
64 }, 67 },
65 { 68 {
66 "BriefDescription": "Pre-charge for reads. Derived from unc_m_pre_count.rd", 69 "BriefDescription": "Pre-charge for reads",
67 "Counter": "0,1,2,3", 70 "Counter": "0,1,2,3",
68 "EventCode": "0x2", 71 "EventCode": "0x2",
69 "EventName": "UNC_M_PRE_COUNT.RD", 72 "EventName": "UNC_M_PRE_COUNT.RD",
@@ -72,7 +75,7 @@
72 "Unit": "iMC" 75 "Unit": "iMC"
73 }, 76 },
74 { 77 {
75 "BriefDescription": "Pre-charge for writes. Derived from unc_m_pre_count.wr", 78 "BriefDescription": "Pre-charge for writes",
76 "Counter": "0,1,2,3", 79 "Counter": "0,1,2,3",
77 "EventCode": "0x2", 80 "EventCode": "0x2",
78 "EventName": "UNC_M_PRE_COUNT.WR", 81 "EventName": "UNC_M_PRE_COUNT.WR",
diff --git a/tools/perf/pmu-events/arch/x86/broadwellde/uncore-power.json b/tools/perf/pmu-events/arch/x86/broadwellde/uncore-power.json
index b44d43088bbb..dd1b95655d1d 100644
--- a/tools/perf/pmu-events/arch/x86/broadwellde/uncore-power.json
+++ b/tools/perf/pmu-events/arch/x86/broadwellde/uncore-power.json
@@ -1,83 +1,91 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events. Derived from unc_p_clockticks", 3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_P_CLOCKTICKS", 5 "EventName": "UNC_P_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "PCU" 7 "Unit": "PCU"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "C0 and C1. Derived from unc_p_power_state_occupancy.cores_c0", 10 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C0. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0x80", 12 "EventCode": "0x80",
13 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0", 13 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0",
14 "Filter": "occ_sel=1", 14 "Filter": "occ_sel=1",
15 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.", 15 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.",
16 "MetricName": "power_state_occupancy.cores_c0 %",
16 "PerPkg": "1", 17 "PerPkg": "1",
17 "Unit": "PCU" 18 "Unit": "PCU"
18 }, 19 },
19 { 20 {
20 "BriefDescription": "C3. Derived from unc_p_power_state_occupancy.cores_c3", 21 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C3. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
21 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
22 "EventCode": "0x80", 23 "EventCode": "0x80",
23 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3", 24 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3",
24 "Filter": "occ_sel=2", 25 "Filter": "occ_sel=2",
25 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.", 26 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.",
27 "MetricName": "power_state_occupancy.cores_c3 %",
26 "PerPkg": "1", 28 "PerPkg": "1",
27 "Unit": "PCU" 29 "Unit": "PCU"
28 }, 30 },
29 { 31 {
30 "BriefDescription": "C6 and C7. Derived from unc_p_power_state_occupancy.cores_c6", 32 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C6. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events ",
31 "Counter": "0,1,2,3", 33 "Counter": "0,1,2,3",
32 "EventCode": "0x80", 34 "EventCode": "0x80",
33 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6", 35 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6",
34 "Filter": "occ_sel=3", 36 "Filter": "occ_sel=3",
35 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.", 37 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.",
38 "MetricName": "power_state_occupancy.cores_c6 %",
36 "PerPkg": "1", 39 "PerPkg": "1",
37 "Unit": "PCU" 40 "Unit": "PCU"
38 }, 41 },
39 { 42 {
40 "BriefDescription": "External Prochot. Derived from unc_p_prochot_external_cycles", 43 "BriefDescription": "Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip",
41 "Counter": "0,1,2,3", 44 "Counter": "0,1,2,3",
42 "EventCode": "0xA", 45 "EventCode": "0xA",
43 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES", 46 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES",
44 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 47 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
48 "MetricName": "prochot_external_cycles %",
45 "PerPkg": "1", 49 "PerPkg": "1",
46 "Unit": "PCU" 50 "Unit": "PCU"
47 }, 51 },
48 { 52 {
49 "BriefDescription": "Thermal Strongest Upper Limit Cycles. Derived from unc_p_freq_max_limit_thermal_cycles", 53 "BriefDescription": "Counts the number of cycles when temperature is the upper limit on frequency",
50 "Counter": "0,1,2,3", 54 "Counter": "0,1,2,3",
51 "EventCode": "0x4", 55 "EventCode": "0x4",
52 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES", 56 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES",
53 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 57 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
58 "MetricName": "freq_max_limit_thermal_cycles %",
54 "PerPkg": "1", 59 "PerPkg": "1",
55 "Unit": "PCU" 60 "Unit": "PCU"
56 }, 61 },
57 { 62 {
58 "BriefDescription": "OS Strongest Upper Limit Cycles. Derived from unc_p_freq_max_os_cycles", 63 "BriefDescription": "Counts the number of cycles when the OS is the upper limit on frequency",
59 "Counter": "0,1,2,3", 64 "Counter": "0,1,2,3",
60 "EventCode": "0x6", 65 "EventCode": "0x6",
61 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES", 66 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES",
62 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 67 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
68 "MetricName": "freq_max_os_cycles %",
63 "PerPkg": "1", 69 "PerPkg": "1",
64 "Unit": "PCU" 70 "Unit": "PCU"
65 }, 71 },
66 { 72 {
67 "BriefDescription": "Power Strongest Upper Limit Cycles. Derived from unc_p_freq_max_power_cycles", 73 "BriefDescription": "Counts the number of cycles when power is the upper limit on frequency",
68 "Counter": "0,1,2,3", 74 "Counter": "0,1,2,3",
69 "EventCode": "0x5", 75 "EventCode": "0x5",
70 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES", 76 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES",
71 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.", 77 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.",
78 "MetricName": "freq_max_power_cycles %",
72 "PerPkg": "1", 79 "PerPkg": "1",
73 "Unit": "PCU" 80 "Unit": "PCU"
74 }, 81 },
75 { 82 {
76 "BriefDescription": "Cycles spent changing Frequency. Derived from unc_p_freq_trans_cycles", 83 "BriefDescription": "Counts the number of cycles when current is the upper limit on frequency",
77 "Counter": "0,1,2,3", 84 "Counter": "0,1,2,3",
78 "EventCode": "0x74", 85 "EventCode": "0x74",
79 "EventName": "UNC_P_FREQ_TRANS_CYCLES", 86 "EventName": "UNC_P_FREQ_TRANS_CYCLES",
80 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 87 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
88 "MetricName": "freq_trans_cycles %",
81 "PerPkg": "1", 89 "PerPkg": "1",
82 "Unit": "PCU" 90 "Unit": "PCU"
83 } 91 }
diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-cache.json b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-cache.json
index 076459c51d4e..58ed6d33d1f4 100644
--- a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-cache.json
+++ b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-cache.json
@@ -1,13 +1,13 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "Uncore cache clock ticks. Derived from unc_c_clockticks", 3 "BriefDescription": "Uncore cache clock ticks",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_C_CLOCKTICKS", 5 "EventName": "UNC_C_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "CBO" 7 "Unit": "CBO"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch). Derived from unc_c_llc_lookup.any", 10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch)",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0x34", 12 "EventCode": "0x34",
13 "EventName": "UNC_C_LLC_LOOKUP.ANY", 13 "EventName": "UNC_C_LLC_LOOKUP.ANY",
@@ -18,7 +18,7 @@
18 "Unit": "CBO" 18 "Unit": "CBO"
19 }, 19 },
20 { 20 {
21 "BriefDescription": "M line evictions from LLC (writebacks to memory). Derived from unc_c_llc_victims.m_state", 21 "BriefDescription": "M line evictions from LLC (writebacks to memory)",
22 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
23 "EventCode": "0x37", 23 "EventCode": "0x37",
24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE", 24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE",
@@ -212,7 +212,7 @@
212 "Unit": "CBO" 212 "Unit": "CBO"
213 }, 213 },
214 { 214 {
215 "BriefDescription": "read requests to home agent. Derived from unc_h_requests.reads", 215 "BriefDescription": "read requests to home agent",
216 "Counter": "0,1,2,3", 216 "Counter": "0,1,2,3",
217 "EventCode": "0x1", 217 "EventCode": "0x1",
218 "EventName": "UNC_H_REQUESTS.READS", 218 "EventName": "UNC_H_REQUESTS.READS",
@@ -221,7 +221,7 @@
221 "Unit": "HA" 221 "Unit": "HA"
222 }, 222 },
223 { 223 {
224 "BriefDescription": "read requests to local home agent. Derived from unc_h_requests.reads_local", 224 "BriefDescription": "read requests to local home agent",
225 "Counter": "0,1,2,3", 225 "Counter": "0,1,2,3",
226 "EventCode": "0x1", 226 "EventCode": "0x1",
227 "EventName": "UNC_H_REQUESTS.READS_LOCAL", 227 "EventName": "UNC_H_REQUESTS.READS_LOCAL",
@@ -230,7 +230,7 @@
230 "Unit": "HA" 230 "Unit": "HA"
231 }, 231 },
232 { 232 {
233 "BriefDescription": "read requests to remote home agent. Derived from unc_h_requests.reads_remote", 233 "BriefDescription": "read requests to remote home agent",
234 "Counter": "0,1,2,3", 234 "Counter": "0,1,2,3",
235 "EventCode": "0x1", 235 "EventCode": "0x1",
236 "EventName": "UNC_H_REQUESTS.READS_REMOTE", 236 "EventName": "UNC_H_REQUESTS.READS_REMOTE",
@@ -239,7 +239,7 @@
239 "Unit": "HA" 239 "Unit": "HA"
240 }, 240 },
241 { 241 {
242 "BriefDescription": "write requests to home agent. Derived from unc_h_requests.writes", 242 "BriefDescription": "write requests to home agent",
243 "Counter": "0,1,2,3", 243 "Counter": "0,1,2,3",
244 "EventCode": "0x1", 244 "EventCode": "0x1",
245 "EventName": "UNC_H_REQUESTS.WRITES", 245 "EventName": "UNC_H_REQUESTS.WRITES",
@@ -248,7 +248,7 @@
248 "Unit": "HA" 248 "Unit": "HA"
249 }, 249 },
250 { 250 {
251 "BriefDescription": "write requests to local home agent. Derived from unc_h_requests.writes_local", 251 "BriefDescription": "write requests to local home agent",
252 "Counter": "0,1,2,3", 252 "Counter": "0,1,2,3",
253 "EventCode": "0x1", 253 "EventCode": "0x1",
254 "EventName": "UNC_H_REQUESTS.WRITES_LOCAL", 254 "EventName": "UNC_H_REQUESTS.WRITES_LOCAL",
@@ -257,7 +257,7 @@
257 "Unit": "HA" 257 "Unit": "HA"
258 }, 258 },
259 { 259 {
260 "BriefDescription": "write requests to remote home agent. Derived from unc_h_requests.writes_remote", 260 "BriefDescription": "write requests to remote home agent",
261 "Counter": "0,1,2,3", 261 "Counter": "0,1,2,3",
262 "EventCode": "0x1", 262 "EventCode": "0x1",
263 "EventName": "UNC_H_REQUESTS.WRITES_REMOTE", 263 "EventName": "UNC_H_REQUESTS.WRITES_REMOTE",
@@ -266,7 +266,7 @@
266 "Unit": "HA" 266 "Unit": "HA"
267 }, 267 },
268 { 268 {
269 "BriefDescription": "Conflict requests (requests for same address from multiple agents simultaneously). Derived from unc_h_snoop_resp.rspcnflct", 269 "BriefDescription": "Conflict requests (requests for same address from multiple agents simultaneously)",
270 "Counter": "0,1,2,3", 270 "Counter": "0,1,2,3",
271 "EventCode": "0x21", 271 "EventCode": "0x21",
272 "EventName": "UNC_H_SNOOP_RESP.RSPCNFLCT", 272 "EventName": "UNC_H_SNOOP_RESP.RSPCNFLCT",
@@ -275,7 +275,7 @@
275 "Unit": "HA" 275 "Unit": "HA"
276 }, 276 },
277 { 277 {
278 "BriefDescription": "M line forwarded from remote cache along with writeback to memory. Derived from unc_h_snoop_resp.rsp_fwd_wb", 278 "BriefDescription": "M line forwarded from remote cache along with writeback to memory",
279 "Counter": "0,1,2,3", 279 "Counter": "0,1,2,3",
280 "EventCode": "0x21", 280 "EventCode": "0x21",
281 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB", 281 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB",
@@ -285,7 +285,7 @@
285 "Unit": "HA" 285 "Unit": "HA"
286 }, 286 },
287 { 287 {
288 "BriefDescription": "M line forwarded from remote cache with no writeback to memory. Derived from unc_h_snoop_resp.rspifwd", 288 "BriefDescription": "M line forwarded from remote cache with no writeback to memory",
289 "Counter": "0,1,2,3", 289 "Counter": "0,1,2,3",
290 "EventCode": "0x21", 290 "EventCode": "0x21",
291 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD", 291 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD",
@@ -295,7 +295,7 @@
295 "Unit": "HA" 295 "Unit": "HA"
296 }, 296 },
297 { 297 {
298 "BriefDescription": "Shared line response from remote cache. Derived from unc_h_snoop_resp.rsps", 298 "BriefDescription": "Shared line response from remote cache",
299 "Counter": "0,1,2,3", 299 "Counter": "0,1,2,3",
300 "EventCode": "0x21", 300 "EventCode": "0x21",
301 "EventName": "UNC_H_SNOOP_RESP.RSPS", 301 "EventName": "UNC_H_SNOOP_RESP.RSPS",
@@ -305,7 +305,7 @@
305 "Unit": "HA" 305 "Unit": "HA"
306 }, 306 },
307 { 307 {
308 "BriefDescription": "Shared line forwarded from remote cache. Derived from unc_h_snoop_resp.rspsfwd", 308 "BriefDescription": "Shared line forwarded from remote cache",
309 "Counter": "0,1,2,3", 309 "Counter": "0,1,2,3",
310 "EventCode": "0x21", 310 "EventCode": "0x21",
311 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD", 311 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD",
diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-interconnect.json
index 39387f7909b2..824961318c1e 100644
--- a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-interconnect.json
+++ b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-interconnect.json
@@ -1,6 +1,6 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "QPI clock ticks. Derived from unc_q_clockticks", 3 "BriefDescription": "QPI clock ticks",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x14", 5 "EventCode": "0x14",
6 "EventName": "UNC_Q_CLOCKTICKS", 6 "EventName": "UNC_Q_CLOCKTICKS",
@@ -10,7 +10,7 @@
10 { 10 {
11 "BriefDescription": "Number of data flits transmitted . Derived from unc_q_txl_flits_g0.data", 11 "BriefDescription": "Number of data flits transmitted . Derived from unc_q_txl_flits_g0.data",
12 "Counter": "0,1,2,3", 12 "Counter": "0,1,2,3",
13 "EventName": "UNC_Q_TxL_FLITS_G0.DATA", 13 "EventName": "QPI_DATA_BANDWIDTH_TX",
14 "PerPkg": "1", 14 "PerPkg": "1",
15 "ScaleUnit": "8Bytes", 15 "ScaleUnit": "8Bytes",
16 "UMask": "0x2", 16 "UMask": "0x2",
@@ -19,7 +19,7 @@
19 { 19 {
20 "BriefDescription": "Number of non data (control) flits transmitted . Derived from unc_q_txl_flits_g0.non_data", 20 "BriefDescription": "Number of non data (control) flits transmitted . Derived from unc_q_txl_flits_g0.non_data",
21 "Counter": "0,1,2,3", 21 "Counter": "0,1,2,3",
22 "EventName": "UNC_Q_TxL_FLITS_G0.NON_DATA", 22 "EventName": "QPI_CTL_BANDWIDTH_TX",
23 "PerPkg": "1", 23 "PerPkg": "1",
24 "ScaleUnit": "8Bytes", 24 "ScaleUnit": "8Bytes",
25 "UMask": "0x4", 25 "UMask": "0x4",
diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-memory.json b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-memory.json
index d17dc235f734..66eed399724c 100644
--- a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-memory.json
+++ b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-memory.json
@@ -3,7 +3,7 @@
3 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd", 3 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x4", 5 "EventCode": "0x4",
6 "EventName": "UNC_M_CAS_COUNT.RD", 6 "EventName": "LLC_MISSES.MEM_READ",
7 "PerPkg": "1", 7 "PerPkg": "1",
8 "ScaleUnit": "64Bytes", 8 "ScaleUnit": "64Bytes",
9 "UMask": "0x3", 9 "UMask": "0x3",
@@ -13,48 +13,51 @@
13 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr", 13 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr",
14 "Counter": "0,1,2,3", 14 "Counter": "0,1,2,3",
15 "EventCode": "0x4", 15 "EventCode": "0x4",
16 "EventName": "UNC_M_CAS_COUNT.WR", 16 "EventName": "LLC_MISSES.MEM_WRITE",
17 "PerPkg": "1", 17 "PerPkg": "1",
18 "ScaleUnit": "64Bytes", 18 "ScaleUnit": "64Bytes",
19 "UMask": "0xC", 19 "UMask": "0xC",
20 "Unit": "iMC" 20 "Unit": "iMC"
21 }, 21 },
22 { 22 {
23 "BriefDescription": "Memory controller clock ticks. Derived from unc_m_clockticks", 23 "BriefDescription": "Memory controller clock ticks",
24 "Counter": "0,1,2,3", 24 "Counter": "0,1,2,3",
25 "EventName": "UNC_M_CLOCKTICKS", 25 "EventName": "UNC_M_CLOCKTICKS",
26 "PerPkg": "1", 26 "PerPkg": "1",
27 "Unit": "iMC" 27 "Unit": "iMC"
28 }, 28 },
29 { 29 {
30 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode. Derived from unc_m_power_channel_ppd", 30 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode",
31 "Counter": "0,1,2,3", 31 "Counter": "0,1,2,3",
32 "EventCode": "0x85", 32 "EventCode": "0x85",
33 "EventName": "UNC_M_POWER_CHANNEL_PPD", 33 "EventName": "UNC_M_POWER_CHANNEL_PPD",
34 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.", 34 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.",
35 "MetricName": "power_channel_ppd %",
35 "PerPkg": "1", 36 "PerPkg": "1",
36 "Unit": "iMC" 37 "Unit": "iMC"
37 }, 38 },
38 { 39 {
39 "BriefDescription": "Cycles all ranks are in critical thermal throttle. Derived from unc_m_power_critical_throttle_cycles", 40 "BriefDescription": "Cycles all ranks are in critical thermal throttle",
40 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
41 "EventCode": "0x86", 42 "EventCode": "0x86",
42 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES", 43 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES",
43 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.", 44 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.",
45 "MetricName": "power_critical_throttle_cycles %",
44 "PerPkg": "1", 46 "PerPkg": "1",
45 "Unit": "iMC" 47 "Unit": "iMC"
46 }, 48 },
47 { 49 {
48 "BriefDescription": "Cycles Memory is in self refresh power mode. Derived from unc_m_power_self_refresh", 50 "BriefDescription": "Cycles Memory is in self refresh power mode",
49 "Counter": "0,1,2,3", 51 "Counter": "0,1,2,3",
50 "EventCode": "0x43", 52 "EventCode": "0x43",
51 "EventName": "UNC_M_POWER_SELF_REFRESH", 53 "EventName": "UNC_M_POWER_SELF_REFRESH",
52 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.", 54 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.",
55 "MetricName": "power_self_refresh %",
53 "PerPkg": "1", 56 "PerPkg": "1",
54 "Unit": "iMC" 57 "Unit": "iMC"
55 }, 58 },
56 { 59 {
57 "BriefDescription": "Pre-charges due to page misses. Derived from unc_m_pre_count.page_miss", 60 "BriefDescription": "Pre-charges due to page misses",
58 "Counter": "0,1,2,3", 61 "Counter": "0,1,2,3",
59 "EventCode": "0x2", 62 "EventCode": "0x2",
60 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS", 63 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS",
@@ -63,7 +66,7 @@
63 "Unit": "iMC" 66 "Unit": "iMC"
64 }, 67 },
65 { 68 {
66 "BriefDescription": "Pre-charge for reads. Derived from unc_m_pre_count.rd", 69 "BriefDescription": "Pre-charge for reads",
67 "Counter": "0,1,2,3", 70 "Counter": "0,1,2,3",
68 "EventCode": "0x2", 71 "EventCode": "0x2",
69 "EventName": "UNC_M_PRE_COUNT.RD", 72 "EventName": "UNC_M_PRE_COUNT.RD",
@@ -72,7 +75,7 @@
72 "Unit": "iMC" 75 "Unit": "iMC"
73 }, 76 },
74 { 77 {
75 "BriefDescription": "Pre-charge for writes. Derived from unc_m_pre_count.wr", 78 "BriefDescription": "Pre-charge for writes",
76 "Counter": "0,1,2,3", 79 "Counter": "0,1,2,3",
77 "EventCode": "0x2", 80 "EventCode": "0x2",
78 "EventName": "UNC_M_PRE_COUNT.WR", 81 "EventName": "UNC_M_PRE_COUNT.WR",
diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-power.json b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-power.json
index b44d43088bbb..dd1b95655d1d 100644
--- a/tools/perf/pmu-events/arch/x86/broadwellx/uncore-power.json
+++ b/tools/perf/pmu-events/arch/x86/broadwellx/uncore-power.json
@@ -1,83 +1,91 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events. Derived from unc_p_clockticks", 3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_P_CLOCKTICKS", 5 "EventName": "UNC_P_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "PCU" 7 "Unit": "PCU"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "C0 and C1. Derived from unc_p_power_state_occupancy.cores_c0", 10 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C0. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0x80", 12 "EventCode": "0x80",
13 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0", 13 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0",
14 "Filter": "occ_sel=1", 14 "Filter": "occ_sel=1",
15 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.", 15 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.",
16 "MetricName": "power_state_occupancy.cores_c0 %",
16 "PerPkg": "1", 17 "PerPkg": "1",
17 "Unit": "PCU" 18 "Unit": "PCU"
18 }, 19 },
19 { 20 {
20 "BriefDescription": "C3. Derived from unc_p_power_state_occupancy.cores_c3", 21 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C3. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
21 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
22 "EventCode": "0x80", 23 "EventCode": "0x80",
23 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3", 24 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3",
24 "Filter": "occ_sel=2", 25 "Filter": "occ_sel=2",
25 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.", 26 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.",
27 "MetricName": "power_state_occupancy.cores_c3 %",
26 "PerPkg": "1", 28 "PerPkg": "1",
27 "Unit": "PCU" 29 "Unit": "PCU"
28 }, 30 },
29 { 31 {
30 "BriefDescription": "C6 and C7. Derived from unc_p_power_state_occupancy.cores_c6", 32 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C6. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events ",
31 "Counter": "0,1,2,3", 33 "Counter": "0,1,2,3",
32 "EventCode": "0x80", 34 "EventCode": "0x80",
33 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6", 35 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6",
34 "Filter": "occ_sel=3", 36 "Filter": "occ_sel=3",
35 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.", 37 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.",
38 "MetricName": "power_state_occupancy.cores_c6 %",
36 "PerPkg": "1", 39 "PerPkg": "1",
37 "Unit": "PCU" 40 "Unit": "PCU"
38 }, 41 },
39 { 42 {
40 "BriefDescription": "External Prochot. Derived from unc_p_prochot_external_cycles", 43 "BriefDescription": "Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip",
41 "Counter": "0,1,2,3", 44 "Counter": "0,1,2,3",
42 "EventCode": "0xA", 45 "EventCode": "0xA",
43 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES", 46 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES",
44 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 47 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
48 "MetricName": "prochot_external_cycles %",
45 "PerPkg": "1", 49 "PerPkg": "1",
46 "Unit": "PCU" 50 "Unit": "PCU"
47 }, 51 },
48 { 52 {
49 "BriefDescription": "Thermal Strongest Upper Limit Cycles. Derived from unc_p_freq_max_limit_thermal_cycles", 53 "BriefDescription": "Counts the number of cycles when temperature is the upper limit on frequency",
50 "Counter": "0,1,2,3", 54 "Counter": "0,1,2,3",
51 "EventCode": "0x4", 55 "EventCode": "0x4",
52 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES", 56 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES",
53 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 57 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
58 "MetricName": "freq_max_limit_thermal_cycles %",
54 "PerPkg": "1", 59 "PerPkg": "1",
55 "Unit": "PCU" 60 "Unit": "PCU"
56 }, 61 },
57 { 62 {
58 "BriefDescription": "OS Strongest Upper Limit Cycles. Derived from unc_p_freq_max_os_cycles", 63 "BriefDescription": "Counts the number of cycles when the OS is the upper limit on frequency",
59 "Counter": "0,1,2,3", 64 "Counter": "0,1,2,3",
60 "EventCode": "0x6", 65 "EventCode": "0x6",
61 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES", 66 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES",
62 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 67 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
68 "MetricName": "freq_max_os_cycles %",
63 "PerPkg": "1", 69 "PerPkg": "1",
64 "Unit": "PCU" 70 "Unit": "PCU"
65 }, 71 },
66 { 72 {
67 "BriefDescription": "Power Strongest Upper Limit Cycles. Derived from unc_p_freq_max_power_cycles", 73 "BriefDescription": "Counts the number of cycles when power is the upper limit on frequency",
68 "Counter": "0,1,2,3", 74 "Counter": "0,1,2,3",
69 "EventCode": "0x5", 75 "EventCode": "0x5",
70 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES", 76 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES",
71 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.", 77 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.",
78 "MetricName": "freq_max_power_cycles %",
72 "PerPkg": "1", 79 "PerPkg": "1",
73 "Unit": "PCU" 80 "Unit": "PCU"
74 }, 81 },
75 { 82 {
76 "BriefDescription": "Cycles spent changing Frequency. Derived from unc_p_freq_trans_cycles", 83 "BriefDescription": "Counts the number of cycles when current is the upper limit on frequency",
77 "Counter": "0,1,2,3", 84 "Counter": "0,1,2,3",
78 "EventCode": "0x74", 85 "EventCode": "0x74",
79 "EventName": "UNC_P_FREQ_TRANS_CYCLES", 86 "EventName": "UNC_P_FREQ_TRANS_CYCLES",
80 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 87 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
88 "MetricName": "freq_trans_cycles %",
81 "PerPkg": "1", 89 "PerPkg": "1",
82 "Unit": "PCU" 90 "Unit": "PCU"
83 } 91 }
diff --git a/tools/perf/pmu-events/arch/x86/haswell/uncore.json b/tools/perf/pmu-events/arch/x86/haswell/uncore.json
new file mode 100644
index 000000000000..3ef5c21fef56
--- /dev/null
+++ b/tools/perf/pmu-events/arch/x86/haswell/uncore.json
@@ -0,0 +1,374 @@
1[
2 {
3 "Unit": "CBO",
4 "EventCode": "0x22",
5 "UMask": "0x21",
6 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_EXTERNAL",
7 "BriefDescription": "An external snoop misses in some processor core.",
8 "PublicDescription": "An external snoop misses in some processor core.",
9 "Counter": "0,1",
10 "CounterMask": "0",
11 "Invert": "0",
12 "EdgeDetect": "0"
13 },
14 {
15 "Unit": "CBO",
16 "EventCode": "0x22",
17 "UMask": "0x41",
18 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_XCORE",
19 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which misses in some processor core.",
20 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which misses in some processor core.",
21 "Counter": "0,1",
22 "CounterMask": "0",
23 "Invert": "0",
24 "EdgeDetect": "0"
25 },
26 {
27 "Unit": "CBO",
28 "EventCode": "0x22",
29 "UMask": "0x81",
30 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_EVICTION",
31 "BriefDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.",
32 "PublicDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.",
33 "Counter": "0,1",
34 "CounterMask": "0",
35 "Invert": "0",
36 "EdgeDetect": "0"
37 },
38 {
39 "Unit": "CBO",
40 "EventCode": "0x22",
41 "UMask": "0x24",
42 "EventName": "UNC_CBO_XSNP_RESPONSE.HIT_EXTERNAL",
43 "BriefDescription": "An external snoop hits a non-modified line in some processor core.",
44 "PublicDescription": "An external snoop hits a non-modified line in some processor core.",
45 "Counter": "0,1",
46 "CounterMask": "0",
47 "Invert": "0",
48 "EdgeDetect": "0"
49 },
50 {
51 "Unit": "CBO",
52 "EventCode": "0x22",
53 "UMask": "0x44",
54 "EventName": "UNC_CBO_XSNP_RESPONSE.HIT_XCORE",
55 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a non-modified line in some processor core.",
56 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a non-modified line in some processor core.",
57 "Counter": "0,1",
58 "CounterMask": "0",
59 "Invert": "0",
60 "EdgeDetect": "0"
61 },
62 {
63 "Unit": "CBO",
64 "EventCode": "0x22",
65 "UMask": "0x84",
66 "EventName": "UNC_CBO_XSNP_RESPONSE.HIT_EVICTION",
67 "BriefDescription": "A cross-core snoop resulted from L3 Eviction which hits a non-modified line in some processor core.",
68 "PublicDescription": "A cross-core snoop resulted from L3 Eviction which hits a non-modified line in some processor core.",
69 "Counter": "0,1",
70 "CounterMask": "0",
71 "Invert": "0",
72 "EdgeDetect": "0"
73 },
74 {
75 "Unit": "CBO",
76 "EventCode": "0x22",
77 "UMask": "0x28",
78 "EventName": "UNC_CBO_XSNP_RESPONSE.HITM_EXTERNAL",
79 "BriefDescription": "An external snoop hits a modified line in some processor core.",
80 "PublicDescription": "An external snoop hits a modified line in some processor core.",
81 "Counter": "0,1",
82 "CounterMask": "0",
83 "Invert": "0",
84 "EdgeDetect": "0"
85 },
86 {
87 "Unit": "CBO",
88 "EventCode": "0x22",
89 "UMask": "0x48",
90 "EventName": "UNC_CBO_XSNP_RESPONSE.HITM_XCORE",
91 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a modified line in some processor core.",
92 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a modified line in some processor core.",
93 "Counter": "0,1",
94 "CounterMask": "0",
95 "Invert": "0",
96 "EdgeDetect": "0"
97 },
98 {
99 "Unit": "CBO",
100 "EventCode": "0x22",
101 "UMask": "0x88",
102 "EventName": "UNC_CBO_XSNP_RESPONSE.HITM_EVICTION",
103 "BriefDescription": "A cross-core snoop resulted from L3 Eviction which hits a modified line in some processor core.",
104 "PublicDescription": "A cross-core snoop resulted from L3 Eviction which hits a modified line in some processor core.",
105 "Counter": "0,1",
106 "CounterMask": "0",
107 "Invert": "0",
108 "EdgeDetect": "0"
109 },
110 {
111 "Unit": "CBO",
112 "EventCode": "0x34",
113 "UMask": "0x11",
114 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_M",
115 "BriefDescription": "L3 Lookup read request that access cache and found line in M-state.",
116 "PublicDescription": "L3 Lookup read request that access cache and found line in M-state.",
117 "Counter": "0,1",
118 "CounterMask": "0",
119 "Invert": "0",
120 "EdgeDetect": "0"
121 },
122 {
123 "Unit": "CBO",
124 "EventCode": "0x34",
125 "UMask": "0x21",
126 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_M",
127 "BriefDescription": "L3 Lookup write request that access cache and found line in M-state.",
128 "PublicDescription": "L3 Lookup write request that access cache and found line in M-state.",
129 "Counter": "0,1",
130 "CounterMask": "0",
131 "Invert": "0",
132 "EdgeDetect": "0"
133 },
134 {
135 "Unit": "CBO",
136 "EventCode": "0x34",
137 "UMask": "0x41",
138 "EventName": "UNC_CBO_CACHE_LOOKUP.EXTSNP_M",
139 "BriefDescription": "L3 Lookup external snoop request that access cache and found line in M-state.",
140 "PublicDescription": "L3 Lookup external snoop request that access cache and found line in M-state.",
141 "Counter": "0,1",
142 "CounterMask": "0",
143 "Invert": "0",
144 "EdgeDetect": "0"
145 },
146 {
147 "Unit": "CBO",
148 "EventCode": "0x34",
149 "UMask": "0x81",
150 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_M",
151 "BriefDescription": "L3 Lookup any request that access cache and found line in M-state.",
152 "PublicDescription": "L3 Lookup any request that access cache and found line in M-state.",
153 "Counter": "0,1",
154 "CounterMask": "0",
155 "Invert": "0",
156 "EdgeDetect": "0"
157 },
158 {
159 "Unit": "CBO",
160 "EventCode": "0x34",
161 "UMask": "0x18",
162 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_I",
163 "BriefDescription": "L3 Lookup read request that access cache and found line in I-state.",
164 "PublicDescription": "L3 Lookup read request that access cache and found line in I-state.",
165 "Counter": "0,1",
166 "CounterMask": "0",
167 "Invert": "0",
168 "EdgeDetect": "0"
169 },
170 {
171 "Unit": "CBO",
172 "EventCode": "0x34",
173 "UMask": "0x28",
174 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_I",
175 "BriefDescription": "L3 Lookup write request that access cache and found line in I-state.",
176 "PublicDescription": "L3 Lookup write request that access cache and found line in I-state.",
177 "Counter": "0,1",
178 "CounterMask": "0",
179 "Invert": "0",
180 "EdgeDetect": "0"
181 },
182 {
183 "Unit": "CBO",
184 "EventCode": "0x34",
185 "UMask": "0x48",
186 "EventName": "UNC_CBO_CACHE_LOOKUP.EXTSNP_I",
187 "BriefDescription": "L3 Lookup external snoop request that access cache and found line in I-state.",
188 "PublicDescription": "L3 Lookup external snoop request that access cache and found line in I-state.",
189 "Counter": "0,1",
190 "CounterMask": "0",
191 "Invert": "0",
192 "EdgeDetect": "0"
193 },
194 {
195 "Unit": "CBO",
196 "EventCode": "0x34",
197 "UMask": "0x88",
198 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_I",
199 "BriefDescription": "L3 Lookup any request that access cache and found line in I-state.",
200 "PublicDescription": "L3 Lookup any request that access cache and found line in I-state.",
201 "Counter": "0,1",
202 "CounterMask": "0",
203 "Invert": "0",
204 "EdgeDetect": "0"
205 },
206 {
207 "Unit": "CBO",
208 "EventCode": "0x34",
209 "UMask": "0x1f",
210 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_MESI",
211 "BriefDescription": "L3 Lookup read request that access cache and found line in any MESI-state.",
212 "PublicDescription": "L3 Lookup read request that access cache and found line in any MESI-state.",
213 "Counter": "0,1",
214 "CounterMask": "0",
215 "Invert": "0",
216 "EdgeDetect": "0"
217 },
218 {
219 "Unit": "CBO",
220 "EventCode": "0x34",
221 "UMask": "0x2f",
222 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_MESI",
223 "BriefDescription": "L3 Lookup write request that access cache and found line in MESI-state.",
224 "PublicDescription": "L3 Lookup write request that access cache and found line in MESI-state.",
225 "Counter": "0,1",
226 "CounterMask": "0",
227 "Invert": "0",
228 "EdgeDetect": "0"
229 },
230 {
231 "Unit": "CBO",
232 "EventCode": "0x34",
233 "UMask": "0x4f",
234 "EventName": "UNC_CBO_CACHE_LOOKUP.EXTSNP_MESI",
235 "BriefDescription": "L3 Lookup external snoop request that access cache and found line in MESI-state.",
236 "PublicDescription": "L3 Lookup external snoop request that access cache and found line in MESI-state.",
237 "Counter": "0,1",
238 "CounterMask": "0",
239 "Invert": "0",
240 "EdgeDetect": "0"
241 },
242 {
243 "Unit": "CBO",
244 "EventCode": "0x34",
245 "UMask": "0x8f",
246 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_MESI",
247 "BriefDescription": "L3 Lookup any request that access cache and found line in MESI-state.",
248 "PublicDescription": "L3 Lookup any request that access cache and found line in MESI-state.",
249 "Counter": "0,1",
250 "CounterMask": "0",
251 "Invert": "0",
252 "EdgeDetect": "0"
253 },
254 {
255 "Unit": "CBO",
256 "EventCode": "0x34",
257 "UMask": "0x86",
258 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_ES",
259 "BriefDescription": "L3 Lookup any request that access cache and found line in E or S-state.",
260 "PublicDescription": "L3 Lookup any request that access cache and found line in E or S-state.",
261 "Counter": "0,1",
262 "CounterMask": "0",
263 "Invert": "0",
264 "EdgeDetect": "0"
265 },
266 {
267 "Unit": "CBO",
268 "EventCode": "0x34",
269 "UMask": "0x46",
270 "EventName": "UNC_CBO_CACHE_LOOKUP.EXTSNP_ES",
271 "BriefDescription": "L3 Lookup external snoop request that access cache and found line in E or S-state.",
272 "PublicDescription": "L3 Lookup external snoop request that access cache and found line in E or S-state.",
273 "Counter": "0,1",
274 "CounterMask": "0",
275 "Invert": "0",
276 "EdgeDetect": "0"
277 },
278 {
279 "Unit": "CBO",
280 "EventCode": "0x34",
281 "UMask": "0x16",
282 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_ES",
283 "BriefDescription": "L3 Lookup read request that access cache and found line in E or S-state.",
284 "PublicDescription": "L3 Lookup read request that access cache and found line in E or S-state.",
285 "Counter": "0,1",
286 "CounterMask": "0",
287 "Invert": "0",
288 "EdgeDetect": "0"
289 },
290 {
291 "Unit": "CBO",
292 "EventCode": "0x34",
293 "UMask": "0x26",
294 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_ES",
295 "BriefDescription": "L3 Lookup write request that access cache and found line in E or S-state.",
296 "PublicDescription": "L3 Lookup write request that access cache and found line in E or S-state.",
297 "Counter": "0,1",
298 "CounterMask": "0",
299 "Invert": "0",
300 "EdgeDetect": "0"
301 },
302 {
303 "Unit": "iMPH-U",
304 "EventCode": "0x80",
305 "UMask": "0x01",
306 "EventName": "UNC_ARB_TRK_OCCUPANCY.ALL",
307 "BriefDescription": "Each cycle count number of all Core outgoing valid entries. Such entry is defined as valid from it's allocation till first of IDI0 or DRS0 messages is sent out. Accounts for Coherent and non-coherent traffic.",
308 "PublicDescription": "Each cycle count number of all Core outgoing valid entries. Such entry is defined as valid from it's allocation till first of IDI0 or DRS0 messages is sent out. Accounts for Coherent and non-coherent traffic.",
309 "Counter": "0",
310 "CounterMask": "0",
311 "Invert": "0",
312 "EdgeDetect": "0"
313 },
314 {
315 "Unit": "iMPH-U",
316 "EventCode": "0x81",
317 "UMask": "0x01",
318 "EventName": "UNC_ARB_TRK_REQUESTS.ALL",
319 "BriefDescription": "Total number of Core outgoing entries allocated. Accounts for Coherent and non-coherent traffic.",
320 "PublicDescription": "Total number of Core outgoing entries allocated. Accounts for Coherent and non-coherent traffic.",
321 "Counter": "0,1",
322 "CounterMask": "0",
323 "Invert": "0",
324 "EdgeDetect": "0"
325 },
326 {
327 "Unit": "iMPH-U",
328 "EventCode": "0x81",
329 "UMask": "0x20",
330 "EventName": "UNC_ARB_TRK_REQUESTS.WRITES",
331 "BriefDescription": "Number of Writes allocated - any write transactions: full/partials writes and evictions.",
332 "PublicDescription": "Number of Writes allocated - any write transactions: full/partials writes and evictions.",
333 "Counter": "0,1",
334 "CounterMask": "0",
335 "Invert": "0",
336 "EdgeDetect": "0"
337 },
338 {
339 "Unit": "iMPH-U",
340 "EventCode": "0x83",
341 "UMask": "0x01",
342 "EventName": "UNC_ARB_COH_TRK_OCCUPANCY.All",
343 "BriefDescription": "Each cycle count number of valid entries in Coherency Tracker queue from allocation till deallocation. Aperture requests (snoops) appear as NC decoded internally and become coherent (snoop L3, access memory)",
344 "PublicDescription": "Each cycle count number of valid entries in Coherency Tracker queue from allocation till deallocation. Aperture requests (snoops) appear as NC decoded internally and become coherent (snoop L3, access memory).",
345 "Counter": "0",
346 "CounterMask": "0",
347 "Invert": "0",
348 "EdgeDetect": "0"
349 },
350 {
351 "Unit": "iMPH-U",
352 "EventCode": "0x84",
353 "UMask": "0x01",
354 "EventName": "UNC_ARB_COH_TRK_REQUESTS.ALL",
355 "BriefDescription": "Number of entries allocated. Account for Any type: e.g. Snoop, Core aperture, etc.",
356 "PublicDescription": "Number of entries allocated. Account for Any type: e.g. Snoop, Core aperture, etc.",
357 "Counter": "0,1",
358 "CounterMask": "0",
359 "Invert": "0",
360 "EdgeDetect": "0"
361 },
362 {
363 "Unit": "NCU",
364 "EventCode": "0x0",
365 "UMask": "0x01",
366 "EventName": "UNC_CLOCK.SOCKET",
367 "BriefDescription": "This 48-bit fixed counter counts the UCLK cycles.",
368 "PublicDescription": "This 48-bit fixed counter counts the UCLK cycles.",
369 "Counter": "FIXED",
370 "CounterMask": "0",
371 "Invert": "0",
372 "EdgeDetect": "0"
373 }
374] \ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/haswellx/uncore-cache.json b/tools/perf/pmu-events/arch/x86/haswellx/uncore-cache.json
index 076459c51d4e..58ed6d33d1f4 100644
--- a/tools/perf/pmu-events/arch/x86/haswellx/uncore-cache.json
+++ b/tools/perf/pmu-events/arch/x86/haswellx/uncore-cache.json
@@ -1,13 +1,13 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "Uncore cache clock ticks. Derived from unc_c_clockticks", 3 "BriefDescription": "Uncore cache clock ticks",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_C_CLOCKTICKS", 5 "EventName": "UNC_C_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "CBO" 7 "Unit": "CBO"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch). Derived from unc_c_llc_lookup.any", 10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch)",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0x34", 12 "EventCode": "0x34",
13 "EventName": "UNC_C_LLC_LOOKUP.ANY", 13 "EventName": "UNC_C_LLC_LOOKUP.ANY",
@@ -18,7 +18,7 @@
18 "Unit": "CBO" 18 "Unit": "CBO"
19 }, 19 },
20 { 20 {
21 "BriefDescription": "M line evictions from LLC (writebacks to memory). Derived from unc_c_llc_victims.m_state", 21 "BriefDescription": "M line evictions from LLC (writebacks to memory)",
22 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
23 "EventCode": "0x37", 23 "EventCode": "0x37",
24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE", 24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE",
@@ -212,7 +212,7 @@
212 "Unit": "CBO" 212 "Unit": "CBO"
213 }, 213 },
214 { 214 {
215 "BriefDescription": "read requests to home agent. Derived from unc_h_requests.reads", 215 "BriefDescription": "read requests to home agent",
216 "Counter": "0,1,2,3", 216 "Counter": "0,1,2,3",
217 "EventCode": "0x1", 217 "EventCode": "0x1",
218 "EventName": "UNC_H_REQUESTS.READS", 218 "EventName": "UNC_H_REQUESTS.READS",
@@ -221,7 +221,7 @@
221 "Unit": "HA" 221 "Unit": "HA"
222 }, 222 },
223 { 223 {
224 "BriefDescription": "read requests to local home agent. Derived from unc_h_requests.reads_local", 224 "BriefDescription": "read requests to local home agent",
225 "Counter": "0,1,2,3", 225 "Counter": "0,1,2,3",
226 "EventCode": "0x1", 226 "EventCode": "0x1",
227 "EventName": "UNC_H_REQUESTS.READS_LOCAL", 227 "EventName": "UNC_H_REQUESTS.READS_LOCAL",
@@ -230,7 +230,7 @@
230 "Unit": "HA" 230 "Unit": "HA"
231 }, 231 },
232 { 232 {
233 "BriefDescription": "read requests to remote home agent. Derived from unc_h_requests.reads_remote", 233 "BriefDescription": "read requests to remote home agent",
234 "Counter": "0,1,2,3", 234 "Counter": "0,1,2,3",
235 "EventCode": "0x1", 235 "EventCode": "0x1",
236 "EventName": "UNC_H_REQUESTS.READS_REMOTE", 236 "EventName": "UNC_H_REQUESTS.READS_REMOTE",
@@ -239,7 +239,7 @@
239 "Unit": "HA" 239 "Unit": "HA"
240 }, 240 },
241 { 241 {
242 "BriefDescription": "write requests to home agent. Derived from unc_h_requests.writes", 242 "BriefDescription": "write requests to home agent",
243 "Counter": "0,1,2,3", 243 "Counter": "0,1,2,3",
244 "EventCode": "0x1", 244 "EventCode": "0x1",
245 "EventName": "UNC_H_REQUESTS.WRITES", 245 "EventName": "UNC_H_REQUESTS.WRITES",
@@ -248,7 +248,7 @@
248 "Unit": "HA" 248 "Unit": "HA"
249 }, 249 },
250 { 250 {
251 "BriefDescription": "write requests to local home agent. Derived from unc_h_requests.writes_local", 251 "BriefDescription": "write requests to local home agent",
252 "Counter": "0,1,2,3", 252 "Counter": "0,1,2,3",
253 "EventCode": "0x1", 253 "EventCode": "0x1",
254 "EventName": "UNC_H_REQUESTS.WRITES_LOCAL", 254 "EventName": "UNC_H_REQUESTS.WRITES_LOCAL",
@@ -257,7 +257,7 @@
257 "Unit": "HA" 257 "Unit": "HA"
258 }, 258 },
259 { 259 {
260 "BriefDescription": "write requests to remote home agent. Derived from unc_h_requests.writes_remote", 260 "BriefDescription": "write requests to remote home agent",
261 "Counter": "0,1,2,3", 261 "Counter": "0,1,2,3",
262 "EventCode": "0x1", 262 "EventCode": "0x1",
263 "EventName": "UNC_H_REQUESTS.WRITES_REMOTE", 263 "EventName": "UNC_H_REQUESTS.WRITES_REMOTE",
@@ -266,7 +266,7 @@
266 "Unit": "HA" 266 "Unit": "HA"
267 }, 267 },
268 { 268 {
269 "BriefDescription": "Conflict requests (requests for same address from multiple agents simultaneously). Derived from unc_h_snoop_resp.rspcnflct", 269 "BriefDescription": "Conflict requests (requests for same address from multiple agents simultaneously)",
270 "Counter": "0,1,2,3", 270 "Counter": "0,1,2,3",
271 "EventCode": "0x21", 271 "EventCode": "0x21",
272 "EventName": "UNC_H_SNOOP_RESP.RSPCNFLCT", 272 "EventName": "UNC_H_SNOOP_RESP.RSPCNFLCT",
@@ -275,7 +275,7 @@
275 "Unit": "HA" 275 "Unit": "HA"
276 }, 276 },
277 { 277 {
278 "BriefDescription": "M line forwarded from remote cache along with writeback to memory. Derived from unc_h_snoop_resp.rsp_fwd_wb", 278 "BriefDescription": "M line forwarded from remote cache along with writeback to memory",
279 "Counter": "0,1,2,3", 279 "Counter": "0,1,2,3",
280 "EventCode": "0x21", 280 "EventCode": "0x21",
281 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB", 281 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB",
@@ -285,7 +285,7 @@
285 "Unit": "HA" 285 "Unit": "HA"
286 }, 286 },
287 { 287 {
288 "BriefDescription": "M line forwarded from remote cache with no writeback to memory. Derived from unc_h_snoop_resp.rspifwd", 288 "BriefDescription": "M line forwarded from remote cache with no writeback to memory",
289 "Counter": "0,1,2,3", 289 "Counter": "0,1,2,3",
290 "EventCode": "0x21", 290 "EventCode": "0x21",
291 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD", 291 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD",
@@ -295,7 +295,7 @@
295 "Unit": "HA" 295 "Unit": "HA"
296 }, 296 },
297 { 297 {
298 "BriefDescription": "Shared line response from remote cache. Derived from unc_h_snoop_resp.rsps", 298 "BriefDescription": "Shared line response from remote cache",
299 "Counter": "0,1,2,3", 299 "Counter": "0,1,2,3",
300 "EventCode": "0x21", 300 "EventCode": "0x21",
301 "EventName": "UNC_H_SNOOP_RESP.RSPS", 301 "EventName": "UNC_H_SNOOP_RESP.RSPS",
@@ -305,7 +305,7 @@
305 "Unit": "HA" 305 "Unit": "HA"
306 }, 306 },
307 { 307 {
308 "BriefDescription": "Shared line forwarded from remote cache. Derived from unc_h_snoop_resp.rspsfwd", 308 "BriefDescription": "Shared line forwarded from remote cache",
309 "Counter": "0,1,2,3", 309 "Counter": "0,1,2,3",
310 "EventCode": "0x21", 310 "EventCode": "0x21",
311 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD", 311 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD",
diff --git a/tools/perf/pmu-events/arch/x86/haswellx/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/haswellx/uncore-interconnect.json
index 39387f7909b2..824961318c1e 100644
--- a/tools/perf/pmu-events/arch/x86/haswellx/uncore-interconnect.json
+++ b/tools/perf/pmu-events/arch/x86/haswellx/uncore-interconnect.json
@@ -1,6 +1,6 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "QPI clock ticks. Derived from unc_q_clockticks", 3 "BriefDescription": "QPI clock ticks",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x14", 5 "EventCode": "0x14",
6 "EventName": "UNC_Q_CLOCKTICKS", 6 "EventName": "UNC_Q_CLOCKTICKS",
@@ -10,7 +10,7 @@
10 { 10 {
11 "BriefDescription": "Number of data flits transmitted . Derived from unc_q_txl_flits_g0.data", 11 "BriefDescription": "Number of data flits transmitted . Derived from unc_q_txl_flits_g0.data",
12 "Counter": "0,1,2,3", 12 "Counter": "0,1,2,3",
13 "EventName": "UNC_Q_TxL_FLITS_G0.DATA", 13 "EventName": "QPI_DATA_BANDWIDTH_TX",
14 "PerPkg": "1", 14 "PerPkg": "1",
15 "ScaleUnit": "8Bytes", 15 "ScaleUnit": "8Bytes",
16 "UMask": "0x2", 16 "UMask": "0x2",
@@ -19,7 +19,7 @@
19 { 19 {
20 "BriefDescription": "Number of non data (control) flits transmitted . Derived from unc_q_txl_flits_g0.non_data", 20 "BriefDescription": "Number of non data (control) flits transmitted . Derived from unc_q_txl_flits_g0.non_data",
21 "Counter": "0,1,2,3", 21 "Counter": "0,1,2,3",
22 "EventName": "UNC_Q_TxL_FLITS_G0.NON_DATA", 22 "EventName": "QPI_CTL_BANDWIDTH_TX",
23 "PerPkg": "1", 23 "PerPkg": "1",
24 "ScaleUnit": "8Bytes", 24 "ScaleUnit": "8Bytes",
25 "UMask": "0x4", 25 "UMask": "0x4",
diff --git a/tools/perf/pmu-events/arch/x86/haswellx/uncore-memory.json b/tools/perf/pmu-events/arch/x86/haswellx/uncore-memory.json
index d17dc235f734..66eed399724c 100644
--- a/tools/perf/pmu-events/arch/x86/haswellx/uncore-memory.json
+++ b/tools/perf/pmu-events/arch/x86/haswellx/uncore-memory.json
@@ -3,7 +3,7 @@
3 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd", 3 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x4", 5 "EventCode": "0x4",
6 "EventName": "UNC_M_CAS_COUNT.RD", 6 "EventName": "LLC_MISSES.MEM_READ",
7 "PerPkg": "1", 7 "PerPkg": "1",
8 "ScaleUnit": "64Bytes", 8 "ScaleUnit": "64Bytes",
9 "UMask": "0x3", 9 "UMask": "0x3",
@@ -13,48 +13,51 @@
13 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr", 13 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr",
14 "Counter": "0,1,2,3", 14 "Counter": "0,1,2,3",
15 "EventCode": "0x4", 15 "EventCode": "0x4",
16 "EventName": "UNC_M_CAS_COUNT.WR", 16 "EventName": "LLC_MISSES.MEM_WRITE",
17 "PerPkg": "1", 17 "PerPkg": "1",
18 "ScaleUnit": "64Bytes", 18 "ScaleUnit": "64Bytes",
19 "UMask": "0xC", 19 "UMask": "0xC",
20 "Unit": "iMC" 20 "Unit": "iMC"
21 }, 21 },
22 { 22 {
23 "BriefDescription": "Memory controller clock ticks. Derived from unc_m_clockticks", 23 "BriefDescription": "Memory controller clock ticks",
24 "Counter": "0,1,2,3", 24 "Counter": "0,1,2,3",
25 "EventName": "UNC_M_CLOCKTICKS", 25 "EventName": "UNC_M_CLOCKTICKS",
26 "PerPkg": "1", 26 "PerPkg": "1",
27 "Unit": "iMC" 27 "Unit": "iMC"
28 }, 28 },
29 { 29 {
30 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode. Derived from unc_m_power_channel_ppd", 30 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode",
31 "Counter": "0,1,2,3", 31 "Counter": "0,1,2,3",
32 "EventCode": "0x85", 32 "EventCode": "0x85",
33 "EventName": "UNC_M_POWER_CHANNEL_PPD", 33 "EventName": "UNC_M_POWER_CHANNEL_PPD",
34 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.", 34 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.",
35 "MetricName": "power_channel_ppd %",
35 "PerPkg": "1", 36 "PerPkg": "1",
36 "Unit": "iMC" 37 "Unit": "iMC"
37 }, 38 },
38 { 39 {
39 "BriefDescription": "Cycles all ranks are in critical thermal throttle. Derived from unc_m_power_critical_throttle_cycles", 40 "BriefDescription": "Cycles all ranks are in critical thermal throttle",
40 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
41 "EventCode": "0x86", 42 "EventCode": "0x86",
42 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES", 43 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES",
43 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.", 44 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.",
45 "MetricName": "power_critical_throttle_cycles %",
44 "PerPkg": "1", 46 "PerPkg": "1",
45 "Unit": "iMC" 47 "Unit": "iMC"
46 }, 48 },
47 { 49 {
48 "BriefDescription": "Cycles Memory is in self refresh power mode. Derived from unc_m_power_self_refresh", 50 "BriefDescription": "Cycles Memory is in self refresh power mode",
49 "Counter": "0,1,2,3", 51 "Counter": "0,1,2,3",
50 "EventCode": "0x43", 52 "EventCode": "0x43",
51 "EventName": "UNC_M_POWER_SELF_REFRESH", 53 "EventName": "UNC_M_POWER_SELF_REFRESH",
52 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.", 54 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.",
55 "MetricName": "power_self_refresh %",
53 "PerPkg": "1", 56 "PerPkg": "1",
54 "Unit": "iMC" 57 "Unit": "iMC"
55 }, 58 },
56 { 59 {
57 "BriefDescription": "Pre-charges due to page misses. Derived from unc_m_pre_count.page_miss", 60 "BriefDescription": "Pre-charges due to page misses",
58 "Counter": "0,1,2,3", 61 "Counter": "0,1,2,3",
59 "EventCode": "0x2", 62 "EventCode": "0x2",
60 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS", 63 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS",
@@ -63,7 +66,7 @@
63 "Unit": "iMC" 66 "Unit": "iMC"
64 }, 67 },
65 { 68 {
66 "BriefDescription": "Pre-charge for reads. Derived from unc_m_pre_count.rd", 69 "BriefDescription": "Pre-charge for reads",
67 "Counter": "0,1,2,3", 70 "Counter": "0,1,2,3",
68 "EventCode": "0x2", 71 "EventCode": "0x2",
69 "EventName": "UNC_M_PRE_COUNT.RD", 72 "EventName": "UNC_M_PRE_COUNT.RD",
@@ -72,7 +75,7 @@
72 "Unit": "iMC" 75 "Unit": "iMC"
73 }, 76 },
74 { 77 {
75 "BriefDescription": "Pre-charge for writes. Derived from unc_m_pre_count.wr", 78 "BriefDescription": "Pre-charge for writes",
76 "Counter": "0,1,2,3", 79 "Counter": "0,1,2,3",
77 "EventCode": "0x2", 80 "EventCode": "0x2",
78 "EventName": "UNC_M_PRE_COUNT.WR", 81 "EventName": "UNC_M_PRE_COUNT.WR",
diff --git a/tools/perf/pmu-events/arch/x86/haswellx/uncore-power.json b/tools/perf/pmu-events/arch/x86/haswellx/uncore-power.json
index b44d43088bbb..dd1b95655d1d 100644
--- a/tools/perf/pmu-events/arch/x86/haswellx/uncore-power.json
+++ b/tools/perf/pmu-events/arch/x86/haswellx/uncore-power.json
@@ -1,83 +1,91 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events. Derived from unc_p_clockticks", 3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_P_CLOCKTICKS", 5 "EventName": "UNC_P_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "PCU" 7 "Unit": "PCU"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "C0 and C1. Derived from unc_p_power_state_occupancy.cores_c0", 10 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C0. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0x80", 12 "EventCode": "0x80",
13 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0", 13 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0",
14 "Filter": "occ_sel=1", 14 "Filter": "occ_sel=1",
15 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.", 15 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.",
16 "MetricName": "power_state_occupancy.cores_c0 %",
16 "PerPkg": "1", 17 "PerPkg": "1",
17 "Unit": "PCU" 18 "Unit": "PCU"
18 }, 19 },
19 { 20 {
20 "BriefDescription": "C3. Derived from unc_p_power_state_occupancy.cores_c3", 21 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C3. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
21 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
22 "EventCode": "0x80", 23 "EventCode": "0x80",
23 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3", 24 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3",
24 "Filter": "occ_sel=2", 25 "Filter": "occ_sel=2",
25 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.", 26 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.",
27 "MetricName": "power_state_occupancy.cores_c3 %",
26 "PerPkg": "1", 28 "PerPkg": "1",
27 "Unit": "PCU" 29 "Unit": "PCU"
28 }, 30 },
29 { 31 {
30 "BriefDescription": "C6 and C7. Derived from unc_p_power_state_occupancy.cores_c6", 32 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C6. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events ",
31 "Counter": "0,1,2,3", 33 "Counter": "0,1,2,3",
32 "EventCode": "0x80", 34 "EventCode": "0x80",
33 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6", 35 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6",
34 "Filter": "occ_sel=3", 36 "Filter": "occ_sel=3",
35 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.", 37 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.",
38 "MetricName": "power_state_occupancy.cores_c6 %",
36 "PerPkg": "1", 39 "PerPkg": "1",
37 "Unit": "PCU" 40 "Unit": "PCU"
38 }, 41 },
39 { 42 {
40 "BriefDescription": "External Prochot. Derived from unc_p_prochot_external_cycles", 43 "BriefDescription": "Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip",
41 "Counter": "0,1,2,3", 44 "Counter": "0,1,2,3",
42 "EventCode": "0xA", 45 "EventCode": "0xA",
43 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES", 46 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES",
44 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 47 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
48 "MetricName": "prochot_external_cycles %",
45 "PerPkg": "1", 49 "PerPkg": "1",
46 "Unit": "PCU" 50 "Unit": "PCU"
47 }, 51 },
48 { 52 {
49 "BriefDescription": "Thermal Strongest Upper Limit Cycles. Derived from unc_p_freq_max_limit_thermal_cycles", 53 "BriefDescription": "Counts the number of cycles when temperature is the upper limit on frequency",
50 "Counter": "0,1,2,3", 54 "Counter": "0,1,2,3",
51 "EventCode": "0x4", 55 "EventCode": "0x4",
52 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES", 56 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES",
53 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 57 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
58 "MetricName": "freq_max_limit_thermal_cycles %",
54 "PerPkg": "1", 59 "PerPkg": "1",
55 "Unit": "PCU" 60 "Unit": "PCU"
56 }, 61 },
57 { 62 {
58 "BriefDescription": "OS Strongest Upper Limit Cycles. Derived from unc_p_freq_max_os_cycles", 63 "BriefDescription": "Counts the number of cycles when the OS is the upper limit on frequency",
59 "Counter": "0,1,2,3", 64 "Counter": "0,1,2,3",
60 "EventCode": "0x6", 65 "EventCode": "0x6",
61 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES", 66 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES",
62 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 67 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
68 "MetricName": "freq_max_os_cycles %",
63 "PerPkg": "1", 69 "PerPkg": "1",
64 "Unit": "PCU" 70 "Unit": "PCU"
65 }, 71 },
66 { 72 {
67 "BriefDescription": "Power Strongest Upper Limit Cycles. Derived from unc_p_freq_max_power_cycles", 73 "BriefDescription": "Counts the number of cycles when power is the upper limit on frequency",
68 "Counter": "0,1,2,3", 74 "Counter": "0,1,2,3",
69 "EventCode": "0x5", 75 "EventCode": "0x5",
70 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES", 76 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES",
71 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.", 77 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.",
78 "MetricName": "freq_max_power_cycles %",
72 "PerPkg": "1", 79 "PerPkg": "1",
73 "Unit": "PCU" 80 "Unit": "PCU"
74 }, 81 },
75 { 82 {
76 "BriefDescription": "Cycles spent changing Frequency. Derived from unc_p_freq_trans_cycles", 83 "BriefDescription": "Counts the number of cycles when current is the upper limit on frequency",
77 "Counter": "0,1,2,3", 84 "Counter": "0,1,2,3",
78 "EventCode": "0x74", 85 "EventCode": "0x74",
79 "EventName": "UNC_P_FREQ_TRANS_CYCLES", 86 "EventName": "UNC_P_FREQ_TRANS_CYCLES",
80 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 87 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
88 "MetricName": "freq_trans_cycles %",
81 "PerPkg": "1", 89 "PerPkg": "1",
82 "Unit": "PCU" 90 "Unit": "PCU"
83 } 91 }
diff --git a/tools/perf/pmu-events/arch/x86/ivybridge/uncore.json b/tools/perf/pmu-events/arch/x86/ivybridge/uncore.json
new file mode 100644
index 000000000000..42c70eed05a2
--- /dev/null
+++ b/tools/perf/pmu-events/arch/x86/ivybridge/uncore.json
@@ -0,0 +1,314 @@
1[
2 {
3 "Unit": "CBO",
4 "EventCode": "0x22",
5 "UMask": "0x01",
6 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS",
7 "BriefDescription": "A snoop misses in some processor core.",
8 "PublicDescription": "A snoop misses in some processor core.",
9 "Counter": "0,1",
10 "CounterMask": "0",
11 "Invert": "0",
12 "EdgeDetect": "0"
13 },
14 {
15 "Unit": "CBO",
16 "EventCode": "0x22",
17 "UMask": "0x02",
18 "EventName": "UNC_CBO_XSNP_RESPONSE.INVAL",
19 "BriefDescription": "A snoop invalidates a non-modified line in some processor core.",
20 "PublicDescription": "A snoop invalidates a non-modified line in some processor core.",
21 "Counter": "0,1",
22 "CounterMask": "0",
23 "Invert": "0",
24 "EdgeDetect": "0"
25 },
26 {
27 "Unit": "CBO",
28 "EventCode": "0x22",
29 "UMask": "0x04",
30 "EventName": "UNC_CBO_XSNP_RESPONSE.HIT",
31 "BriefDescription": "A snoop hits a non-modified line in some processor core.",
32 "PublicDescription": "A snoop hits a non-modified line in some processor core.",
33 "Counter": "0,1",
34 "CounterMask": "0",
35 "Invert": "0",
36 "EdgeDetect": "0"
37 },
38 {
39 "Unit": "CBO",
40 "EventCode": "0x22",
41 "UMask": "0x08",
42 "EventName": "UNC_CBO_XSNP_RESPONSE.HITM",
43 "BriefDescription": "A snoop hits a modified line in some processor core.",
44 "PublicDescription": "A snoop hits a modified line in some processor core.",
45 "Counter": "0,1",
46 "CounterMask": "0",
47 "Invert": "0",
48 "EdgeDetect": "0"
49 },
50 {
51 "Unit": "CBO",
52 "EventCode": "0x22",
53 "UMask": "0x10",
54 "EventName": "UNC_CBO_XSNP_RESPONSE.INVAL_M",
55 "BriefDescription": "A snoop invalidates a modified line in some processor core.",
56 "PublicDescription": "A snoop invalidates a modified line in some processor core.",
57 "Counter": "0,1",
58 "CounterMask": "0",
59 "Invert": "0",
60 "EdgeDetect": "0"
61 },
62 {
63 "Unit": "CBO",
64 "EventCode": "0x22",
65 "UMask": "0x20",
66 "EventName": "UNC_CBO_XSNP_RESPONSE.EXTERNAL_FILTER",
67 "BriefDescription": "Filter on cross-core snoops initiated by this Cbox due to external snoop request.",
68 "PublicDescription": "Filter on cross-core snoops initiated by this Cbox due to external snoop request.",
69 "Counter": "0,1",
70 "CounterMask": "0",
71 "Invert": "0",
72 "EdgeDetect": "0"
73 },
74 {
75 "Unit": "CBO",
76 "EventCode": "0x22",
77 "UMask": "0x40",
78 "EventName": "UNC_CBO_XSNP_RESPONSE.XCORE_FILTER",
79 "BriefDescription": "Filter on cross-core snoops initiated by this Cbox due to processor core memory request.",
80 "PublicDescription": "Filter on cross-core snoops initiated by this Cbox due to processor core memory request.",
81 "Counter": "0,1",
82 "CounterMask": "0",
83 "Invert": "0",
84 "EdgeDetect": "0"
85 },
86 {
87 "Unit": "CBO",
88 "EventCode": "0x22",
89 "UMask": "0x80",
90 "EventName": "UNC_CBO_XSNP_RESPONSE.EVICTION_FILTER",
91 "BriefDescription": "Filter on cross-core snoops initiated by this Cbox due to LLC eviction.",
92 "PublicDescription": "Filter on cross-core snoops initiated by this Cbox due to LLC eviction.",
93 "Counter": "0,1",
94 "CounterMask": "0",
95 "Invert": "0",
96 "EdgeDetect": "0"
97 },
98 {
99 "Unit": "CBO",
100 "EventCode": "0x34",
101 "UMask": "0x01",
102 "EventName": "UNC_CBO_CACHE_LOOKUP.M",
103 "BriefDescription": "LLC lookup request that access cache and found line in M-state.",
104 "PublicDescription": "LLC lookup request that access cache and found line in M-state.",
105 "Counter": "0,1",
106 "CounterMask": "0",
107 "Invert": "0",
108 "EdgeDetect": "0"
109 },
110 {
111 "Unit": "CBO",
112 "EventCode": "0x34",
113 "UMask": "0x02",
114 "EventName": "UNC_CBO_CACHE_LOOKUP.E",
115 "BriefDescription": "LLC lookup request that access cache and found line in E-state.",
116 "PublicDescription": "LLC lookup request that access cache and found line in E-state.",
117 "Counter": "0,1",
118 "CounterMask": "0",
119 "Invert": "0",
120 "EdgeDetect": "0"
121 },
122 {
123 "Unit": "CBO",
124 "EventCode": "0x34",
125 "UMask": "0x04",
126 "EventName": "UNC_CBO_CACHE_LOOKUP.S",
127 "BriefDescription": "LLC lookup request that access cache and found line in S-state.",
128 "PublicDescription": "LLC lookup request that access cache and found line in S-state.",
129 "Counter": "0,1",
130 "CounterMask": "0",
131 "Invert": "0",
132 "EdgeDetect": "0"
133 },
134 {
135 "Unit": "CBO",
136 "EventCode": "0x34",
137 "UMask": "0x08",
138 "EventName": "UNC_CBO_CACHE_LOOKUP.I",
139 "BriefDescription": "LLC lookup request that access cache and found line in I-state.",
140 "PublicDescription": "LLC lookup request that access cache and found line in I-state.",
141 "Counter": "0,1",
142 "CounterMask": "0",
143 "Invert": "0",
144 "EdgeDetect": "0"
145 },
146 {
147 "Unit": "CBO",
148 "EventCode": "0x34",
149 "UMask": "0x10",
150 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_FILTER",
151 "BriefDescription": "Filter on processor core initiated cacheable read requests.",
152 "PublicDescription": "Filter on processor core initiated cacheable read requests.",
153 "Counter": "0,1",
154 "CounterMask": "0",
155 "Invert": "0",
156 "EdgeDetect": "0"
157 },
158 {
159 "Unit": "CBO",
160 "EventCode": "0x34",
161 "UMask": "0x20",
162 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_FILTER",
163 "BriefDescription": "Filter on processor core initiated cacheable write requests.",
164 "PublicDescription": "Filter on processor core initiated cacheable write requests.",
165 "Counter": "0,1",
166 "CounterMask": "0",
167 "Invert": "0",
168 "EdgeDetect": "0"
169 },
170 {
171 "Unit": "CBO",
172 "EventCode": "0x34",
173 "UMask": "0x40",
174 "EventName": "UNC_CBO_CACHE_LOOKUP.EXTSNP_FILTER",
175 "BriefDescription": "Filter on external snoop requests.",
176 "PublicDescription": "Filter on external snoop requests.",
177 "Counter": "0,1",
178 "CounterMask": "0",
179 "Invert": "0",
180 "EdgeDetect": "0"
181 },
182 {
183 "Unit": "CBO",
184 "EventCode": "0x34",
185 "UMask": "0x80",
186 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_REQUEST_FILTER",
187 "BriefDescription": "Filter on any IRQ or IPQ initiated requests including uncacheable, non-coherent requests.",
188 "PublicDescription": "Filter on any IRQ or IPQ initiated requests including uncacheable, non-coherent requests.",
189 "Counter": "0,1",
190 "CounterMask": "0",
191 "Invert": "0",
192 "EdgeDetect": "0"
193 },
194 {
195 "Unit": "ARB",
196 "EventCode": "0x80",
197 "UMask": "0x01",
198 "EventName": "UNC_ARB_TRK_OCCUPANCY.ALL",
199 "BriefDescription": "Counts cycles weighted by the number of requests waiting for data returning from the memory controller. Accounts for coherent and non-coherent requests initiated by IA cores, processor graphic units, or LLC.",
200 "PublicDescription": "Counts cycles weighted by the number of requests waiting for data returning from the memory controller. Accounts for coherent and non-coherent requests initiated by IA cores, processor graphic units, or LLC.",
201 "Counter": "0",
202 "CounterMask": "0",
203 "Invert": "0",
204 "EdgeDetect": "0"
205 },
206 {
207 "Unit": "ARB",
208 "EventCode": "0x81",
209 "UMask": "0x01",
210 "EventName": "UNC_ARB_TRK_REQUESTS.ALL",
211 "BriefDescription": "Counts the number of coherent and in-coherent requests initiated by IA cores, processor graphic units, or LLC.",
212 "PublicDescription": "Counts the number of coherent and in-coherent requests initiated by IA cores, processor graphic units, or LLC.",
213 "Counter": "0,1",
214 "CounterMask": "0",
215 "Invert": "0",
216 "EdgeDetect": "0"
217 },
218 {
219 "Unit": "ARB",
220 "EventCode": "0x81",
221 "UMask": "0x20",
222 "EventName": "UNC_ARB_TRK_REQUESTS.WRITES",
223 "BriefDescription": "Counts the number of allocated write entries, include full, partial, and LLC evictions.",
224 "PublicDescription": "Counts the number of allocated write entries, include full, partial, and LLC evictions.",
225 "Counter": "0,1",
226 "CounterMask": "0",
227 "Invert": "0",
228 "EdgeDetect": "0"
229 },
230 {
231 "Unit": "ARB",
232 "EventCode": "0x81",
233 "UMask": "0x80",
234 "EventName": "UNC_ARB_TRK_REQUESTS.EVICTIONS",
235 "BriefDescription": "Counts the number of LLC evictions allocated.",
236 "PublicDescription": "Counts the number of LLC evictions allocated.",
237 "Counter": "0,1",
238 "CounterMask": "0",
239 "Invert": "0",
240 "EdgeDetect": "0"
241 },
242 {
243 "Unit": "ARB",
244 "EventCode": "0x83",
245 "UMask": "0x01",
246 "EventName": "UNC_ARB_COH_TRK_OCCUPANCY.ALL",
247 "BriefDescription": "Cycles weighted by number of requests pending in Coherency Tracker.",
248 "PublicDescription": "Cycles weighted by number of requests pending in Coherency Tracker.",
249 "Counter": "0",
250 "CounterMask": "0",
251 "Invert": "0",
252 "EdgeDetect": "0"
253 },
254 {
255 "Unit": "ARB",
256 "EventCode": "0x84",
257 "UMask": "0x01",
258 "EventName": "UNC_ARB_COH_TRK_REQUESTS.ALL",
259 "BriefDescription": "Number of requests allocated in Coherency Tracker.",
260 "PublicDescription": "Number of requests allocated in Coherency Tracker.",
261 "Counter": "0,1",
262 "CounterMask": "0",
263 "Invert": "0",
264 "EdgeDetect": "0"
265 },
266 {
267 "Unit": "ARB",
268 "EventCode": "0x80",
269 "UMask": "0x01",
270 "EventName": "UNC_ARB_TRK_OCCUPANCY.CYCLES_WITH_ANY_REQUEST",
271 "BriefDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
272 "PublicDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
273 "Counter": "0,1",
274 "CounterMask": "1",
275 "Invert": "0",
276 "EdgeDetect": "0"
277 },
278 {
279 "Unit": "ARB",
280 "EventCode": "0x80",
281 "UMask": "0x01",
282 "EventName": "UNC_ARB_TRK_OCCUPANCY.CYCLES_OVER_HALF_FULL",
283 "BriefDescription": "Cycles with at least half of the requests outstanding are waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
284 "PublicDescription": "Cycles with at least half of the requests outstanding are waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
285 "Counter": "0,1",
286 "CounterMask": "10",
287 "Invert": "0",
288 "EdgeDetect": "0"
289 },
290 {
291 "Unit": "ARB",
292 "EventCode": "0x0",
293 "UMask": "0x01",
294 "EventName": "UNC_CLOCK.SOCKET",
295 "BriefDescription": "This 48-bit fixed counter counts the UCLK cycles.",
296 "PublicDescription": "This 48-bit fixed counter counts the UCLK cycles.",
297 "Counter": "Fixed",
298 "CounterMask": "0",
299 "Invert": "0",
300 "EdgeDetect": "0"
301 },
302 {
303 "Unit": "CBO",
304 "EventCode": "0x34",
305 "UMask": "0x06",
306 "EventName": "UNC_CBO_CACHE_LOOKUP.ES",
307 "BriefDescription": "LLC lookup request that access cache and found line in E-state or S-state.",
308 "PublicDescription": "LLC lookup request that access cache and found line in E-state or S-state.",
309 "Counter": "0,1",
310 "CounterMask": "0",
311 "Invert": "0",
312 "EdgeDetect": "0"
313 }
314] \ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/ivytown/uncore-cache.json b/tools/perf/pmu-events/arch/x86/ivytown/uncore-cache.json
index 2efdc6772e0b..267410594833 100644
--- a/tools/perf/pmu-events/arch/x86/ivytown/uncore-cache.json
+++ b/tools/perf/pmu-events/arch/x86/ivytown/uncore-cache.json
@@ -1,13 +1,13 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "Uncore cache clock ticks. Derived from unc_c_clockticks", 3 "BriefDescription": "Uncore cache clock ticks",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_C_CLOCKTICKS", 5 "EventName": "UNC_C_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "CBO" 7 "Unit": "CBO"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch). Derived from unc_c_llc_lookup.any", 10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch)",
11 "Counter": "0,1", 11 "Counter": "0,1",
12 "EventCode": "0x34", 12 "EventCode": "0x34",
13 "EventName": "UNC_C_LLC_LOOKUP.ANY", 13 "EventName": "UNC_C_LLC_LOOKUP.ANY",
@@ -18,7 +18,7 @@
18 "Unit": "CBO" 18 "Unit": "CBO"
19 }, 19 },
20 { 20 {
21 "BriefDescription": "M line evictions from LLC (writebacks to memory). Derived from unc_c_llc_victims.m_state", 21 "BriefDescription": "M line evictions from LLC (writebacks to memory)",
22 "Counter": "0,1", 22 "Counter": "0,1",
23 "EventCode": "0x37", 23 "EventCode": "0x37",
24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE", 24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE",
@@ -237,7 +237,7 @@
237 "Unit": "CBO" 237 "Unit": "CBO"
238 }, 238 },
239 { 239 {
240 "BriefDescription": "Occupancy for all LLC misses that are addressed to local memory. Derived from unc_c_tor_occupancy.miss_local", 240 "BriefDescription": "Occupancy for all LLC misses that are addressed to local memory",
241 "EventCode": "0x36", 241 "EventCode": "0x36",
242 "EventName": "UNC_C_TOR_OCCUPANCY.MISS_LOCAL", 242 "EventName": "UNC_C_TOR_OCCUPANCY.MISS_LOCAL",
243 "PerPkg": "1", 243 "PerPkg": "1",
@@ -254,7 +254,7 @@
254 "Unit": "CBO" 254 "Unit": "CBO"
255 }, 255 },
256 { 256 {
257 "BriefDescription": "Occupancy for all LLC misses that are addressed to remote memory. Derived from unc_c_tor_occupancy.miss_remote", 257 "BriefDescription": "Occupancy for all LLC misses that are addressed to remote memory",
258 "EventCode": "0x36", 258 "EventCode": "0x36",
259 "EventName": "UNC_C_TOR_OCCUPANCY.MISS_REMOTE", 259 "EventName": "UNC_C_TOR_OCCUPANCY.MISS_REMOTE",
260 "PerPkg": "1", 260 "PerPkg": "1",
@@ -262,7 +262,7 @@
262 "Unit": "CBO" 262 "Unit": "CBO"
263 }, 263 },
264 { 264 {
265 "BriefDescription": "Read requests to home agent. Derived from unc_h_requests.reads", 265 "BriefDescription": "Read requests to home agent",
266 "Counter": "0,1,2,3", 266 "Counter": "0,1,2,3",
267 "EventCode": "0x1", 267 "EventCode": "0x1",
268 "EventName": "UNC_H_REQUESTS.READS", 268 "EventName": "UNC_H_REQUESTS.READS",
@@ -271,7 +271,7 @@
271 "Unit": "HA" 271 "Unit": "HA"
272 }, 272 },
273 { 273 {
274 "BriefDescription": "Write requests to home agent. Derived from unc_h_requests.writes", 274 "BriefDescription": "Write requests to home agent",
275 "Counter": "0,1,2,3", 275 "Counter": "0,1,2,3",
276 "EventCode": "0x1", 276 "EventCode": "0x1",
277 "EventName": "UNC_H_REQUESTS.WRITES", 277 "EventName": "UNC_H_REQUESTS.WRITES",
@@ -280,7 +280,7 @@
280 "Unit": "HA" 280 "Unit": "HA"
281 }, 281 },
282 { 282 {
283 "BriefDescription": "M line forwarded from remote cache along with writeback to memory. Derived from unc_h_snoop_resp.rsp_fwd_wb", 283 "BriefDescription": "M line forwarded from remote cache along with writeback to memory",
284 "Counter": "0,1,2,3", 284 "Counter": "0,1,2,3",
285 "EventCode": "0x21", 285 "EventCode": "0x21",
286 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB", 286 "EventName": "UNC_H_SNOOP_RESP.RSP_FWD_WB",
@@ -290,7 +290,7 @@
290 "Unit": "HA" 290 "Unit": "HA"
291 }, 291 },
292 { 292 {
293 "BriefDescription": "M line forwarded from remote cache with no writeback to memory. Derived from unc_h_snoop_resp.rspifwd", 293 "BriefDescription": "M line forwarded from remote cache with no writeback to memory",
294 "Counter": "0,1,2,3", 294 "Counter": "0,1,2,3",
295 "EventCode": "0x21", 295 "EventCode": "0x21",
296 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD", 296 "EventName": "UNC_H_SNOOP_RESP.RSPIFWD",
@@ -300,7 +300,7 @@
300 "Unit": "HA" 300 "Unit": "HA"
301 }, 301 },
302 { 302 {
303 "BriefDescription": "Shared line response from remote cache. Derived from unc_h_snoop_resp.rsps", 303 "BriefDescription": "Shared line response from remote cache",
304 "Counter": "0,1,2,3", 304 "Counter": "0,1,2,3",
305 "EventCode": "0x21", 305 "EventCode": "0x21",
306 "EventName": "UNC_H_SNOOP_RESP.RSPS", 306 "EventName": "UNC_H_SNOOP_RESP.RSPS",
@@ -310,7 +310,7 @@
310 "Unit": "HA" 310 "Unit": "HA"
311 }, 311 },
312 { 312 {
313 "BriefDescription": "Shared line forwarded from remote cache. Derived from unc_h_snoop_resp.rspsfwd", 313 "BriefDescription": "Shared line forwarded from remote cache",
314 "Counter": "0,1,2,3", 314 "Counter": "0,1,2,3",
315 "EventCode": "0x21", 315 "EventCode": "0x21",
316 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD", 316 "EventName": "UNC_H_SNOOP_RESP.RSPSFWD",
diff --git a/tools/perf/pmu-events/arch/x86/ivytown/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/ivytown/uncore-interconnect.json
index d7e2fda1d695..b798a860bc81 100644
--- a/tools/perf/pmu-events/arch/x86/ivytown/uncore-interconnect.json
+++ b/tools/perf/pmu-events/arch/x86/ivytown/uncore-interconnect.json
@@ -1,6 +1,6 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "QPI clock ticks. Use to get percentages for QPI cycles events. Derived from unc_q_clockticks", 3 "BriefDescription": "QPI clock ticks. Use to get percentages for QPI cycles events",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x14", 5 "EventCode": "0x14",
6 "EventName": "UNC_Q_CLOCKTICKS", 6 "EventName": "UNC_Q_CLOCKTICKS",
@@ -8,25 +8,27 @@
8 "Unit": "QPI LL" 8 "Unit": "QPI LL"
9 }, 9 },
10 { 10 {
11 "BriefDescription": "Cycles where receiving QPI link is in half-width mode. Derived from unc_q_rxl0p_power_cycles", 11 "BriefDescription": "Cycles where receiving QPI link is in half-width mode",
12 "Counter": "0,1,2,3", 12 "Counter": "0,1,2,3",
13 "EventCode": "0x10", 13 "EventCode": "0x10",
14 "EventName": "UNC_Q_RxL0P_POWER_CYCLES", 14 "EventName": "UNC_Q_RxL0P_POWER_CYCLES",
15 "MetricExpr": "(UNC_Q_RxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.", 15 "MetricExpr": "(UNC_Q_RxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.",
16 "MetricName": "rxl0p_power_cycles %",
16 "PerPkg": "1", 17 "PerPkg": "1",
17 "Unit": "QPI LL" 18 "Unit": "QPI LL"
18 }, 19 },
19 { 20 {
20 "BriefDescription": "Cycles where transmitting QPI link is in half-width mode. Derived from unc_q_txl0p_power_cycles", 21 "BriefDescription": "Cycles where transmitting QPI link is in half-width mode",
21 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
22 "EventCode": "0xd", 23 "EventCode": "0xd",
23 "EventName": "UNC_Q_TxL0P_POWER_CYCLES", 24 "EventName": "UNC_Q_TxL0P_POWER_CYCLES",
24 "MetricExpr": "(UNC_Q_TxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.", 25 "MetricExpr": "(UNC_Q_TxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.",
26 "MetricName": "txl0p_power_cycles %",
25 "PerPkg": "1", 27 "PerPkg": "1",
26 "Unit": "QPI LL" 28 "Unit": "QPI LL"
27 }, 29 },
28 { 30 {
29 "BriefDescription": "Number of data flits transmitted . Derived from unc_q_txl_flits_g0.data", 31 "BriefDescription": "Number of data flits transmitted ",
30 "Counter": "0,1,2,3", 32 "Counter": "0,1,2,3",
31 "EventName": "UNC_Q_TxL_FLITS_G0.DATA", 33 "EventName": "UNC_Q_TxL_FLITS_G0.DATA",
32 "PerPkg": "1", 34 "PerPkg": "1",
@@ -35,7 +37,7 @@
35 "Unit": "QPI LL" 37 "Unit": "QPI LL"
36 }, 38 },
37 { 39 {
38 "BriefDescription": "Number of non data (control) flits transmitted . Derived from unc_q_txl_flits_g0.non_data", 40 "BriefDescription": "Number of non data (control) flits transmitted ",
39 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
40 "EventName": "UNC_Q_TxL_FLITS_G0.NON_DATA", 42 "EventName": "UNC_Q_TxL_FLITS_G0.NON_DATA",
41 "PerPkg": "1", 43 "PerPkg": "1",
diff --git a/tools/perf/pmu-events/arch/x86/ivytown/uncore-memory.json b/tools/perf/pmu-events/arch/x86/ivytown/uncore-memory.json
index ac4ad4d6357b..df4b43294fa0 100644
--- a/tools/perf/pmu-events/arch/x86/ivytown/uncore-memory.json
+++ b/tools/perf/pmu-events/arch/x86/ivytown/uncore-memory.json
@@ -1,6 +1,6 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "Memory page activates for reads and writes. Derived from unc_m_act_count.rd", 3 "BriefDescription": "Memory page activates for reads and writes",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x1", 5 "EventCode": "0x1",
6 "EventName": "UNC_M_ACT_COUNT.RD", 6 "EventName": "UNC_M_ACT_COUNT.RD",
@@ -13,7 +13,7 @@
13 "BriefDescription": "Read requests to memory controller. Derived from unc_m_cas_count.rd", 13 "BriefDescription": "Read requests to memory controller. Derived from unc_m_cas_count.rd",
14 "Counter": "0,1,2,3", 14 "Counter": "0,1,2,3",
15 "EventCode": "0x4", 15 "EventCode": "0x4",
16 "EventName": "UNC_M_CAS_COUNT.RD", 16 "EventName": "LLC_MISSES.MEM_READ",
17 "PerPkg": "1", 17 "PerPkg": "1",
18 "ScaleUnit": "64Bytes", 18 "ScaleUnit": "64Bytes",
19 "UMask": "0x3", 19 "UMask": "0x3",
@@ -23,48 +23,51 @@
23 "BriefDescription": "Write requests to memory controller. Derived from unc_m_cas_count.wr", 23 "BriefDescription": "Write requests to memory controller. Derived from unc_m_cas_count.wr",
24 "Counter": "0,1,2,3", 24 "Counter": "0,1,2,3",
25 "EventCode": "0x4", 25 "EventCode": "0x4",
26 "EventName": "UNC_M_CAS_COUNT.WR", 26 "EventName": "LLC_MISSES.MEM_WRITE",
27 "PerPkg": "1", 27 "PerPkg": "1",
28 "ScaleUnit": "64Bytes", 28 "ScaleUnit": "64Bytes",
29 "UMask": "0xC", 29 "UMask": "0xC",
30 "Unit": "iMC" 30 "Unit": "iMC"
31 }, 31 },
32 { 32 {
33 "BriefDescription": "Memory controller clock ticks. Use to generate percentages for memory controller CYCLES events. Derived from unc_m_clockticks", 33 "BriefDescription": "Memory controller clock ticks. Use to generate percentages for memory controller CYCLES events",
34 "Counter": "0,1,2,3", 34 "Counter": "0,1,2,3",
35 "EventName": "UNC_M_CLOCKTICKS", 35 "EventName": "UNC_M_CLOCKTICKS",
36 "PerPkg": "1", 36 "PerPkg": "1",
37 "Unit": "iMC" 37 "Unit": "iMC"
38 }, 38 },
39 { 39 {
40 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode. Derived from unc_m_power_channel_ppd", 40 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode",
41 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
42 "EventCode": "0x85", 42 "EventCode": "0x85",
43 "EventName": "UNC_M_POWER_CHANNEL_PPD", 43 "EventName": "UNC_M_POWER_CHANNEL_PPD",
44 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.", 44 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.",
45 "MetricName": "power_channel_ppd %",
45 "PerPkg": "1", 46 "PerPkg": "1",
46 "Unit": "iMC" 47 "Unit": "iMC"
47 }, 48 },
48 { 49 {
49 "BriefDescription": "Cycles all ranks are in critical thermal throttle. Derived from unc_m_power_critical_throttle_cycles", 50 "BriefDescription": "Cycles all ranks are in critical thermal throttle",
50 "Counter": "0,1,2,3", 51 "Counter": "0,1,2,3",
51 "EventCode": "0x86", 52 "EventCode": "0x86",
52 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES", 53 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES",
53 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.", 54 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.",
55 "MetricName": "power_critical_throttle_cycles %",
54 "PerPkg": "1", 56 "PerPkg": "1",
55 "Unit": "iMC" 57 "Unit": "iMC"
56 }, 58 },
57 { 59 {
58 "BriefDescription": "Cycles Memory is in self refresh power mode. Derived from unc_m_power_self_refresh", 60 "BriefDescription": "Cycles Memory is in self refresh power mode",
59 "Counter": "0,1,2,3", 61 "Counter": "0,1,2,3",
60 "EventCode": "0x43", 62 "EventCode": "0x43",
61 "EventName": "UNC_M_POWER_SELF_REFRESH", 63 "EventName": "UNC_M_POWER_SELF_REFRESH",
62 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.", 64 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.",
65 "MetricName": "power_self_refresh %",
63 "PerPkg": "1", 66 "PerPkg": "1",
64 "Unit": "iMC" 67 "Unit": "iMC"
65 }, 68 },
66 { 69 {
67 "BriefDescription": "Memory page conflicts. Derived from unc_m_pre_count.page_miss", 70 "BriefDescription": "Memory page conflicts",
68 "Counter": "0,1,2,3", 71 "Counter": "0,1,2,3",
69 "EventCode": "0x2", 72 "EventCode": "0x2",
70 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS", 73 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS",
diff --git a/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json b/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json
index dc2586db0dfc..d40498f2cb1e 100644
--- a/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json
+++ b/tools/perf/pmu-events/arch/x86/ivytown/uncore-power.json
@@ -1,44 +1,48 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events. Derived from unc_p_clockticks", 3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_P_CLOCKTICKS", 5 "EventName": "UNC_P_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "PCU" 7 "Unit": "PCU"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band0=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band0_cycles", 10 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band0=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0xb", 12 "EventCode": "0xb",
13 "EventName": "UNC_P_FREQ_BAND0_CYCLES", 13 "EventName": "UNC_P_FREQ_BAND0_CYCLES",
14 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.", 14 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.",
15 "MetricName": "freq_band0_cycles %",
15 "PerPkg": "1", 16 "PerPkg": "1",
16 "Unit": "PCU" 17 "Unit": "PCU"
17 }, 18 },
18 { 19 {
19 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band1=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band1_cycles", 20 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band1=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
20 "Counter": "0,1,2,3", 21 "Counter": "0,1,2,3",
21 "EventCode": "0xc", 22 "EventCode": "0xc",
22 "EventName": "UNC_P_FREQ_BAND1_CYCLES", 23 "EventName": "UNC_P_FREQ_BAND1_CYCLES",
23 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.", 24 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.",
25 "MetricName": "freq_band1_cycles %",
24 "PerPkg": "1", 26 "PerPkg": "1",
25 "Unit": "PCU" 27 "Unit": "PCU"
26 }, 28 },
27 { 29 {
28 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band2=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band2_cycles", 30 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band2=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
29 "Counter": "0,1,2,3", 31 "Counter": "0,1,2,3",
30 "EventCode": "0xd", 32 "EventCode": "0xd",
31 "EventName": "UNC_P_FREQ_BAND2_CYCLES", 33 "EventName": "UNC_P_FREQ_BAND2_CYCLES",
32 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.", 34 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.",
35 "MetricName": "freq_band2_cycles %",
33 "PerPkg": "1", 36 "PerPkg": "1",
34 "Unit": "PCU" 37 "Unit": "PCU"
35 }, 38 },
36 { 39 {
37 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band3=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band3_cycles", 40 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band3=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
38 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
39 "EventCode": "0xe", 42 "EventCode": "0xe",
40 "EventName": "UNC_P_FREQ_BAND3_CYCLES", 43 "EventName": "UNC_P_FREQ_BAND3_CYCLES",
41 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.", 44 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.",
45 "MetricName": "freq_band3_cycles %",
42 "PerPkg": "1", 46 "PerPkg": "1",
43 "Unit": "PCU" 47 "Unit": "PCU"
44 }, 48 },
@@ -49,6 +53,7 @@
49 "EventName": "UNC_P_FREQ_BAND0_TRANSITIONS", 53 "EventName": "UNC_P_FREQ_BAND0_TRANSITIONS",
50 "Filter": "edge=1", 54 "Filter": "edge=1",
51 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.", 55 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.",
56 "MetricName": "freq_band0_cycles %",
52 "PerPkg": "1", 57 "PerPkg": "1",
53 "Unit": "PCU" 58 "Unit": "PCU"
54 }, 59 },
@@ -59,6 +64,7 @@
59 "EventName": "UNC_P_FREQ_BAND1_TRANSITIONS", 64 "EventName": "UNC_P_FREQ_BAND1_TRANSITIONS",
60 "Filter": "edge=1", 65 "Filter": "edge=1",
61 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.", 66 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.",
67 "MetricName": "freq_band1_cycles %",
62 "PerPkg": "1", 68 "PerPkg": "1",
63 "Unit": "PCU" 69 "Unit": "PCU"
64 }, 70 },
@@ -69,6 +75,7 @@
69 "EventName": "UNC_P_FREQ_BAND2_TRANSITIONS", 75 "EventName": "UNC_P_FREQ_BAND2_TRANSITIONS",
70 "Filter": "edge=1", 76 "Filter": "edge=1",
71 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.", 77 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.",
78 "MetricName": "freq_band2_cycles %",
72 "PerPkg": "1", 79 "PerPkg": "1",
73 "Unit": "PCU" 80 "Unit": "PCU"
74 }, 81 },
@@ -79,90 +86,100 @@
79 "EventName": "UNC_P_FREQ_BAND3_TRANSITIONS", 86 "EventName": "UNC_P_FREQ_BAND3_TRANSITIONS",
80 "Filter": "edge=1", 87 "Filter": "edge=1",
81 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.", 88 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.",
89 "MetricName": "freq_band3_cycles %",
82 "PerPkg": "1", 90 "PerPkg": "1",
83 "Unit": "PCU" 91 "Unit": "PCU"
84 }, 92 },
85 { 93 {
86 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details. Derived from unc_p_power_state_occupancy.cores_c0", 94 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C0. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
87 "Counter": "0,1,2,3", 95 "Counter": "0,1,2,3",
88 "EventCode": "0x80", 96 "EventCode": "0x80",
89 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0", 97 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0",
90 "Filter": "occ_sel=1", 98 "Filter": "occ_sel=1",
91 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.", 99 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.",
100 "MetricName": "power_state_occupancy.cores_c0 %",
92 "PerPkg": "1", 101 "PerPkg": "1",
93 "Unit": "PCU" 102 "Unit": "PCU"
94 }, 103 },
95 { 104 {
96 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details. Derived from unc_p_power_state_occupancy.cores_c3", 105 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C3. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
97 "Counter": "0,1,2,3", 106 "Counter": "0,1,2,3",
98 "EventCode": "0x80", 107 "EventCode": "0x80",
99 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3", 108 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3",
100 "Filter": "occ_sel=2", 109 "Filter": "occ_sel=2",
101 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.", 110 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.",
111 "MetricName": "power_state_occupancy.cores_c3 %",
102 "PerPkg": "1", 112 "PerPkg": "1",
103 "Unit": "PCU" 113 "Unit": "PCU"
104 }, 114 },
105 { 115 {
106 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in the chosen C-State. It can be used by itself to get the average number of cores in that C-state with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details. Derived from unc_p_power_state_occupancy.cores_c6", 116 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C6. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events ",
107 "Counter": "0,1,2,3", 117 "Counter": "0,1,2,3",
108 "EventCode": "0x80", 118 "EventCode": "0x80",
109 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6", 119 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6",
110 "Filter": "occ_sel=3", 120 "Filter": "occ_sel=3",
111 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.", 121 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.",
122 "MetricName": "power_state_occupancy.cores_c6 %",
112 "PerPkg": "1", 123 "PerPkg": "1",
113 "Unit": "PCU" 124 "Unit": "PCU"
114 }, 125 },
115 { 126 {
116 "BriefDescription": "Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip. Derived from unc_p_prochot_external_cycles", 127 "BriefDescription": "Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip",
117 "Counter": "0,1,2,3", 128 "Counter": "0,1,2,3",
118 "EventCode": "0xa", 129 "EventCode": "0xa",
119 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES", 130 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES",
120 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 131 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
132 "MetricName": "prochot_external_cycles %",
121 "PerPkg": "1", 133 "PerPkg": "1",
122 "Unit": "PCU" 134 "Unit": "PCU"
123 }, 135 },
124 { 136 {
125 "BriefDescription": "Counts the number of cycles when thermal conditions are the upper limit on frequency. This is related to the THERMAL_THROTTLE CYCLES_ABOVE_TEMP event, which always counts cycles when we are above the thermal temperature. This event (STRONGEST_UPPER_LIMIT) is sampled at the output of the algorithm that determines the actual frequency, while THERMAL_THROTTLE looks at the input. Derived from unc_p_freq_max_limit_thermal_cycles", 137 "BriefDescription": "Counts the number of cycles when temperature is the upper limit on frequency",
126 "Counter": "0,1,2,3", 138 "Counter": "0,1,2,3",
127 "EventCode": "0x4", 139 "EventCode": "0x4",
128 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES", 140 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES",
129 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 141 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
142 "MetricName": "freq_max_limit_thermal_cycles %",
130 "PerPkg": "1", 143 "PerPkg": "1",
131 "Unit": "PCU" 144 "Unit": "PCU"
132 }, 145 },
133 { 146 {
134 "BriefDescription": "Counts the number of cycles when the OS is the upper limit on frequency. Derived from unc_p_freq_max_os_cycles", 147 "BriefDescription": "Counts the number of cycles when the OS is the upper limit on frequency",
135 "Counter": "0,1,2,3", 148 "Counter": "0,1,2,3",
136 "EventCode": "0x6", 149 "EventCode": "0x6",
137 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES", 150 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES",
138 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 151 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
152 "MetricName": "freq_max_os_cycles %",
139 "PerPkg": "1", 153 "PerPkg": "1",
140 "Unit": "PCU" 154 "Unit": "PCU"
141 }, 155 },
142 { 156 {
143 "BriefDescription": "Counts the number of cycles when power is the upper limit on frequency. Derived from unc_p_freq_max_power_cycles", 157 "BriefDescription": "Counts the number of cycles when power is the upper limit on frequency",
144 "Counter": "0,1,2,3", 158 "Counter": "0,1,2,3",
145 "EventCode": "0x5", 159 "EventCode": "0x5",
146 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES", 160 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES",
147 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.", 161 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.",
162 "MetricName": "freq_max_power_cycles %",
148 "PerPkg": "1", 163 "PerPkg": "1",
149 "Unit": "PCU" 164 "Unit": "PCU"
150 }, 165 },
151 { 166 {
152 "BriefDescription": "Counts the number of cycles when current is the upper limit on frequency. Derived from unc_p_freq_max_current_cycles", 167 "BriefDescription": "Counts the number of cycles when current is the upper limit on frequency",
153 "Counter": "0,1,2,3", 168 "Counter": "0,1,2,3",
154 "EventCode": "0x7", 169 "EventCode": "0x7",
155 "EventName": "UNC_P_FREQ_MAX_CURRENT_CYCLES", 170 "EventName": "UNC_P_FREQ_MAX_CURRENT_CYCLES",
156 "MetricExpr": "(UNC_P_FREQ_MAX_CURRENT_CYCLES / UNC_P_CLOCKTICKS) * 100.", 171 "MetricExpr": "(UNC_P_FREQ_MAX_CURRENT_CYCLES / UNC_P_CLOCKTICKS) * 100.",
172 "MetricName": "freq_max_current_cycles %",
157 "PerPkg": "1", 173 "PerPkg": "1",
158 "Unit": "PCU" 174 "Unit": "PCU"
159 }, 175 },
160 { 176 {
161 "BriefDescription": "Counts the number of cycles when the system is changing frequency. This can not be filtered by thread ID. One can also use it with the occupancy counter that monitors number of threads in C0 to estimate the performance impact that frequency transitions had on the system. Derived from unc_p_freq_trans_cycles", 177 "BriefDescription": "Cycles spent changing Frequency",
162 "Counter": "0,1,2,3", 178 "Counter": "0,1,2,3",
163 "EventCode": "0x60", 179 "EventCode": "0x60",
164 "EventName": "UNC_P_FREQ_TRANS_CYCLES", 180 "EventName": "UNC_P_FREQ_TRANS_CYCLES",
165 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 181 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
182 "MetricName": "freq_trans_cycles %",
166 "PerPkg": "1", 183 "PerPkg": "1",
167 "Unit": "PCU" 184 "Unit": "PCU"
168 }, 185 },
@@ -173,6 +190,7 @@
173 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES", 190 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES",
174 "Filter": "filter_band0=1200", 191 "Filter": "filter_band0=1200",
175 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 192 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
193 "MetricName": "freq_ge_1200mhz_cycles %",
176 "PerPkg": "1", 194 "PerPkg": "1",
177 "Unit": "PCU" 195 "Unit": "PCU"
178 }, 196 },
@@ -183,6 +201,7 @@
183 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES", 201 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES",
184 "Filter": "filter_band1=2000", 202 "Filter": "filter_band1=2000",
185 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 203 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
204 "MetricName": "freq_ge_2000mhz_cycles %",
186 "PerPkg": "1", 205 "PerPkg": "1",
187 "Unit": "PCU" 206 "Unit": "PCU"
188 }, 207 },
@@ -193,6 +212,7 @@
193 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES", 212 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES",
194 "Filter": "filter_band2=3000", 213 "Filter": "filter_band2=3000",
195 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 214 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
215 "MetricName": "freq_ge_3000mhz_cycles %",
196 "PerPkg": "1", 216 "PerPkg": "1",
197 "Unit": "PCU" 217 "Unit": "PCU"
198 }, 218 },
@@ -203,6 +223,7 @@
203 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES", 223 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES",
204 "Filter": "filter_band3=4000", 224 "Filter": "filter_band3=4000",
205 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 225 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
226 "MetricName": "freq_ge_4000mhz_cycles %",
206 "PerPkg": "1", 227 "PerPkg": "1",
207 "Unit": "PCU" 228 "Unit": "PCU"
208 }, 229 },
@@ -213,6 +234,7 @@
213 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS", 234 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS",
214 "Filter": "edge=1,filter_band0=1200", 235 "Filter": "edge=1,filter_band0=1200",
215 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 236 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
237 "MetricName": "freq_ge_1200mhz_cycles %",
216 "PerPkg": "1", 238 "PerPkg": "1",
217 "Unit": "PCU" 239 "Unit": "PCU"
218 }, 240 },
@@ -223,6 +245,7 @@
223 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS", 245 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS",
224 "Filter": "edge=1,filter_band1=2000", 246 "Filter": "edge=1,filter_band1=2000",
225 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 247 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
248 "MetricName": "freq_ge_2000mhz_cycles %",
226 "PerPkg": "1", 249 "PerPkg": "1",
227 "Unit": "PCU" 250 "Unit": "PCU"
228 }, 251 },
@@ -233,6 +256,7 @@
233 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS", 256 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS",
234 "Filter": "edge=1,filter_band2=4000", 257 "Filter": "edge=1,filter_band2=4000",
235 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 258 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
259 "MetricName": "freq_ge_3000mhz_cycles %",
236 "PerPkg": "1", 260 "PerPkg": "1",
237 "Unit": "PCU" 261 "Unit": "PCU"
238 }, 262 },
@@ -243,6 +267,7 @@
243 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS", 267 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS",
244 "Filter": "edge=1,filter_band3=4000", 268 "Filter": "edge=1,filter_band3=4000",
245 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 269 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
270 "MetricName": "freq_ge_4000mhz_cycles %",
246 "PerPkg": "1", 271 "PerPkg": "1",
247 "Unit": "PCU" 272 "Unit": "PCU"
248 } 273 }
diff --git a/tools/perf/pmu-events/arch/x86/jaketown/uncore-cache.json b/tools/perf/pmu-events/arch/x86/jaketown/uncore-cache.json
index 2f23cf0129e7..3fa61d962607 100644
--- a/tools/perf/pmu-events/arch/x86/jaketown/uncore-cache.json
+++ b/tools/perf/pmu-events/arch/x86/jaketown/uncore-cache.json
@@ -1,13 +1,13 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "Uncore cache clock ticks. Derived from unc_c_clockticks", 3 "BriefDescription": "Uncore cache clock ticks",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_C_CLOCKTICKS", 5 "EventName": "UNC_C_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "CBO" 7 "Unit": "CBO"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch). Derived from unc_c_llc_lookup.any", 10 "BriefDescription": "All LLC Misses (code+ data rd + data wr - including demand and prefetch)",
11 "Counter": "0,1", 11 "Counter": "0,1",
12 "EventCode": "0x34", 12 "EventCode": "0x34",
13 "EventName": "UNC_C_LLC_LOOKUP.ANY", 13 "EventName": "UNC_C_LLC_LOOKUP.ANY",
@@ -18,7 +18,7 @@
18 "Unit": "CBO" 18 "Unit": "CBO"
19 }, 19 },
20 { 20 {
21 "BriefDescription": "M line evictions from LLC (writebacks to memory). Derived from unc_c_llc_victims.m_state", 21 "BriefDescription": "M line evictions from LLC (writebacks to memory)",
22 "Counter": "0,1", 22 "Counter": "0,1",
23 "EventCode": "0x37", 23 "EventCode": "0x37",
24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE", 24 "EventName": "UNC_C_LLC_VICTIMS.M_STATE",
@@ -171,11 +171,12 @@
171 "Unit": "CBO" 171 "Unit": "CBO"
172 }, 172 },
173 { 173 {
174 "BriefDescription": "Occupancy counter for all LLC misses; we divide this by UNC_C_CLOCKTICKS to get average Q depth. Derived from unc_c_tor_occupancy.miss_all", 174 "BriefDescription": "Occupancy counter for all LLC misses; we divide this by UNC_C_CLOCKTICKS to get average Q depth",
175 "EventCode": "0x36", 175 "EventCode": "0x36",
176 "EventName": "UNC_C_TOR_OCCUPANCY.MISS_ALL", 176 "EventName": "UNC_C_TOR_OCCUPANCY.MISS_ALL",
177 "Filter": "filter_opc=0x182", 177 "Filter": "filter_opc=0x182",
178 "MetricExpr": "(UNC_C_TOR_OCCUPANCY.MISS_ALL / UNC_C_CLOCKTICKS) * 100.", 178 "MetricExpr": "(UNC_C_TOR_OCCUPANCY.MISS_ALL / UNC_C_CLOCKTICKS) * 100.",
179 "MetricName": "tor_occupancy.miss_all %",
179 "PerPkg": "1", 180 "PerPkg": "1",
180 "UMask": "0xa", 181 "UMask": "0xa",
181 "Unit": "CBO" 182 "Unit": "CBO"
@@ -189,7 +190,7 @@
189 "Unit": "CBO" 190 "Unit": "CBO"
190 }, 191 },
191 { 192 {
192 "BriefDescription": "read requests to home agent. Derived from unc_h_requests.reads", 193 "BriefDescription": "read requests to home agent",
193 "Counter": "0,1,2,3", 194 "Counter": "0,1,2,3",
194 "EventCode": "0x1", 195 "EventCode": "0x1",
195 "EventName": "UNC_H_REQUESTS.READS", 196 "EventName": "UNC_H_REQUESTS.READS",
@@ -198,7 +199,7 @@
198 "Unit": "HA" 199 "Unit": "HA"
199 }, 200 },
200 { 201 {
201 "BriefDescription": "write requests to home agent. Derived from unc_h_requests.writes", 202 "BriefDescription": "write requests to home agent",
202 "Counter": "0,1,2,3", 203 "Counter": "0,1,2,3",
203 "EventCode": "0x1", 204 "EventCode": "0x1",
204 "EventName": "UNC_H_REQUESTS.WRITES", 205 "EventName": "UNC_H_REQUESTS.WRITES",
diff --git a/tools/perf/pmu-events/arch/x86/jaketown/uncore-interconnect.json b/tools/perf/pmu-events/arch/x86/jaketown/uncore-interconnect.json
index 63351876eb57..1b53c0e609e3 100644
--- a/tools/perf/pmu-events/arch/x86/jaketown/uncore-interconnect.json
+++ b/tools/perf/pmu-events/arch/x86/jaketown/uncore-interconnect.json
@@ -1,6 +1,6 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "QPI clock ticks. Used to get percentages of QPI cycles events. Derived from unc_q_clockticks", 3 "BriefDescription": "QPI clock ticks. Used to get percentages of QPI cycles events",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x14", 5 "EventCode": "0x14",
6 "EventName": "UNC_Q_CLOCKTICKS", 6 "EventName": "UNC_Q_CLOCKTICKS",
@@ -8,25 +8,27 @@
8 "Unit": "QPI LL" 8 "Unit": "QPI LL"
9 }, 9 },
10 { 10 {
11 "BriefDescription": "Cycles where receiving QPI link is in half-width mode. Derived from unc_q_rxl0p_power_cycles", 11 "BriefDescription": "Cycles where receiving QPI link is in half-width mode",
12 "Counter": "0,1,2,3", 12 "Counter": "0,1,2,3",
13 "EventCode": "0x10", 13 "EventCode": "0x10",
14 "EventName": "UNC_Q_RxL0P_POWER_CYCLES", 14 "EventName": "UNC_Q_RxL0P_POWER_CYCLES",
15 "MetricExpr": "(UNC_Q_RxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.", 15 "MetricExpr": "(UNC_Q_RxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.",
16 "MetricName": "rxl0p_power_cycles %",
16 "PerPkg": "1", 17 "PerPkg": "1",
17 "Unit": "QPI LL" 18 "Unit": "QPI LL"
18 }, 19 },
19 { 20 {
20 "BriefDescription": "Cycles where transmitting QPI link is in half-width mode. Derived from unc_q_txl0p_power_cycles", 21 "BriefDescription": "Cycles where transmitting QPI link is in half-width mode",
21 "Counter": "0,1,2,3", 22 "Counter": "0,1,2,3",
22 "EventCode": "0xd", 23 "EventCode": "0xd",
23 "EventName": "UNC_Q_TxL0P_POWER_CYCLES", 24 "EventName": "UNC_Q_TxL0P_POWER_CYCLES",
24 "MetricExpr": "(UNC_Q_TxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.", 25 "MetricExpr": "(UNC_Q_TxL0P_POWER_CYCLES / UNC_Q_CLOCKTICKS) * 100.",
26 "MetricName": "txl0p_power_cycles %",
25 "PerPkg": "1", 27 "PerPkg": "1",
26 "Unit": "QPI LL" 28 "Unit": "QPI LL"
27 }, 29 },
28 { 30 {
29 "BriefDescription": "Number of data flits transmitted . Derived from unc_q_txl_flits_g0.data", 31 "BriefDescription": "Number of data flits transmitted ",
30 "Counter": "0,1,2,3", 32 "Counter": "0,1,2,3",
31 "EventName": "UNC_Q_TxL_FLITS_G0.DATA", 33 "EventName": "UNC_Q_TxL_FLITS_G0.DATA",
32 "PerPkg": "1", 34 "PerPkg": "1",
@@ -35,7 +37,7 @@
35 "Unit": "QPI LL" 37 "Unit": "QPI LL"
36 }, 38 },
37 { 39 {
38 "BriefDescription": "Number of non data (control) flits transmitted . Derived from unc_q_txl_flits_g0.non_data", 40 "BriefDescription": "Number of non data (control) flits transmitted ",
39 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
40 "EventName": "UNC_Q_TxL_FLITS_G0.NON_DATA", 42 "EventName": "UNC_Q_TxL_FLITS_G0.NON_DATA",
41 "PerPkg": "1", 43 "PerPkg": "1",
diff --git a/tools/perf/pmu-events/arch/x86/jaketown/uncore-memory.json b/tools/perf/pmu-events/arch/x86/jaketown/uncore-memory.json
index e2cf6daa7b37..8551cebeba23 100644
--- a/tools/perf/pmu-events/arch/x86/jaketown/uncore-memory.json
+++ b/tools/perf/pmu-events/arch/x86/jaketown/uncore-memory.json
@@ -1,6 +1,6 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "Memory page activates. Derived from unc_m_act_count", 3 "BriefDescription": "Memory page activates",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventCode": "0x1", 5 "EventCode": "0x1",
6 "EventName": "UNC_M_ACT_COUNT", 6 "EventName": "UNC_M_ACT_COUNT",
@@ -11,7 +11,7 @@
11 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd", 11 "BriefDescription": "read requests to memory controller. Derived from unc_m_cas_count.rd",
12 "Counter": "0,1,2,3", 12 "Counter": "0,1,2,3",
13 "EventCode": "0x4", 13 "EventCode": "0x4",
14 "EventName": "UNC_M_CAS_COUNT.RD", 14 "EventName": "LLC_MISSES.MEM_READ",
15 "PerPkg": "1", 15 "PerPkg": "1",
16 "UMask": "0x3", 16 "UMask": "0x3",
17 "Unit": "iMC" 17 "Unit": "iMC"
@@ -20,47 +20,50 @@
20 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr", 20 "BriefDescription": "write requests to memory controller. Derived from unc_m_cas_count.wr",
21 "Counter": "0,1,2,3", 21 "Counter": "0,1,2,3",
22 "EventCode": "0x4", 22 "EventCode": "0x4",
23 "EventName": "UNC_M_CAS_COUNT.WR", 23 "EventName": "LLC_MISSES.MEM_WRITE",
24 "PerPkg": "1", 24 "PerPkg": "1",
25 "UMask": "0xc", 25 "UMask": "0xc",
26 "Unit": "iMC" 26 "Unit": "iMC"
27 }, 27 },
28 { 28 {
29 "BriefDescription": "Memory controller clock ticks. Used to get percentages of memory controller cycles events. Derived from unc_m_clockticks", 29 "BriefDescription": "Memory controller clock ticks. Used to get percentages of memory controller cycles events",
30 "Counter": "0,1,2,3", 30 "Counter": "0,1,2,3",
31 "EventName": "UNC_M_CLOCKTICKS", 31 "EventName": "UNC_M_CLOCKTICKS",
32 "PerPkg": "1", 32 "PerPkg": "1",
33 "Unit": "iMC" 33 "Unit": "iMC"
34 }, 34 },
35 { 35 {
36 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode. Derived from unc_m_power_channel_ppd", 36 "BriefDescription": "Cycles where DRAM ranks are in power down (CKE) mode",
37 "Counter": "0,1,2,3", 37 "Counter": "0,1,2,3",
38 "EventCode": "0x85", 38 "EventCode": "0x85",
39 "EventName": "UNC_M_POWER_CHANNEL_PPD", 39 "EventName": "UNC_M_POWER_CHANNEL_PPD",
40 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.", 40 "MetricExpr": "(UNC_M_POWER_CHANNEL_PPD / UNC_M_CLOCKTICKS) * 100.",
41 "MetricName": "power_channel_ppd %",
41 "PerPkg": "1", 42 "PerPkg": "1",
42 "Unit": "iMC" 43 "Unit": "iMC"
43 }, 44 },
44 { 45 {
45 "BriefDescription": "Cycles all ranks are in critical thermal throttle. Derived from unc_m_power_critical_throttle_cycles", 46 "BriefDescription": "Cycles all ranks are in critical thermal throttle",
46 "Counter": "0,1,2,3", 47 "Counter": "0,1,2,3",
47 "EventCode": "0x86", 48 "EventCode": "0x86",
48 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES", 49 "EventName": "UNC_M_POWER_CRITICAL_THROTTLE_CYCLES",
49 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.", 50 "MetricExpr": "(UNC_M_POWER_CRITICAL_THROTTLE_CYCLES / UNC_M_CLOCKTICKS) * 100.",
51 "MetricName": "power_critical_throttle_cycles %",
50 "PerPkg": "1", 52 "PerPkg": "1",
51 "Unit": "iMC" 53 "Unit": "iMC"
52 }, 54 },
53 { 55 {
54 "BriefDescription": "Cycles Memory is in self refresh power mode. Derived from unc_m_power_self_refresh", 56 "BriefDescription": "Cycles Memory is in self refresh power mode",
55 "Counter": "0,1,2,3", 57 "Counter": "0,1,2,3",
56 "EventCode": "0x43", 58 "EventCode": "0x43",
57 "EventName": "UNC_M_POWER_SELF_REFRESH", 59 "EventName": "UNC_M_POWER_SELF_REFRESH",
58 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.", 60 "MetricExpr": "(UNC_M_POWER_SELF_REFRESH / UNC_M_CLOCKTICKS) * 100.",
61 "MetricName": "power_self_refresh %",
59 "PerPkg": "1", 62 "PerPkg": "1",
60 "Unit": "iMC" 63 "Unit": "iMC"
61 }, 64 },
62 { 65 {
63 "BriefDescription": "Memory page conflicts. Derived from unc_m_pre_count.page_miss", 66 "BriefDescription": "Memory page conflicts",
64 "Counter": "0,1,2,3", 67 "Counter": "0,1,2,3",
65 "EventCode": "0x2", 68 "EventCode": "0x2",
66 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS", 69 "EventName": "UNC_M_PRE_COUNT.PAGE_MISS",
@@ -69,7 +72,7 @@
69 "Unit": "iMC" 72 "Unit": "iMC"
70 }, 73 },
71 { 74 {
72 "BriefDescription": "Occupancy counter for memory read queue. Derived from unc_m_rpq_occupancy", 75 "BriefDescription": "Occupancy counter for memory read queue",
73 "Counter": "0,1,2,3", 76 "Counter": "0,1,2,3",
74 "EventCode": "0x80", 77 "EventCode": "0x80",
75 "EventName": "UNC_M_RPQ_OCCUPANCY", 78 "EventName": "UNC_M_RPQ_OCCUPANCY",
diff --git a/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json b/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json
index bbe36d547386..16034bfd06dd 100644
--- a/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json
+++ b/tools/perf/pmu-events/arch/x86/jaketown/uncore-power.json
@@ -1,44 +1,48 @@
1[ 1[
2 { 2 {
3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events. Derived from unc_p_clockticks", 3 "BriefDescription": "PCU clock ticks. Use to get percentages of PCU cycles events",
4 "Counter": "0,1,2,3", 4 "Counter": "0,1,2,3",
5 "EventName": "UNC_P_CLOCKTICKS", 5 "EventName": "UNC_P_CLOCKTICKS",
6 "PerPkg": "1", 6 "PerPkg": "1",
7 "Unit": "PCU" 7 "Unit": "PCU"
8 }, 8 },
9 { 9 {
10 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band0=XXX with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band0_cycles", 10 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band0=XXX with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
11 "Counter": "0,1,2,3", 11 "Counter": "0,1,2,3",
12 "EventCode": "0xb", 12 "EventCode": "0xb",
13 "EventName": "UNC_P_FREQ_BAND0_CYCLES", 13 "EventName": "UNC_P_FREQ_BAND0_CYCLES",
14 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.", 14 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.",
15 "MetricName": "freq_band0_cycles %",
15 "PerPkg": "1", 16 "PerPkg": "1",
16 "Unit": "PCU" 17 "Unit": "PCU"
17 }, 18 },
18 { 19 {
19 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band1=XXX with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band1_cycles", 20 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band1=XXX with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
20 "Counter": "0,1,2,3", 21 "Counter": "0,1,2,3",
21 "EventCode": "0xc", 22 "EventCode": "0xc",
22 "EventName": "UNC_P_FREQ_BAND1_CYCLES", 23 "EventName": "UNC_P_FREQ_BAND1_CYCLES",
23 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.", 24 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.",
25 "MetricName": "freq_band1_cycles %",
24 "PerPkg": "1", 26 "PerPkg": "1",
25 "Unit": "PCU" 27 "Unit": "PCU"
26 }, 28 },
27 { 29 {
28 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band2=XXX with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band2_cycles", 30 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band2=XXX with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
29 "Counter": "0,1,2,3", 31 "Counter": "0,1,2,3",
30 "EventCode": "0xd", 32 "EventCode": "0xd",
31 "EventName": "UNC_P_FREQ_BAND2_CYCLES", 33 "EventName": "UNC_P_FREQ_BAND2_CYCLES",
32 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.", 34 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.",
35 "MetricName": "freq_band2_cycles %",
33 "PerPkg": "1", 36 "PerPkg": "1",
34 "Unit": "PCU" 37 "Unit": "PCU"
35 }, 38 },
36 { 39 {
37 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band3=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency. Derived from unc_p_freq_band3_cycles", 40 "BriefDescription": "Counts the number of cycles that the uncore was running at a frequency greater than or equal to the frequency that is configured in the filter. (filter_band3=XXX, with XXX in 100Mhz units). One can also use inversion (filter_inv=1) to track cycles when we were less than the configured frequency",
38 "Counter": "0,1,2,3", 41 "Counter": "0,1,2,3",
39 "EventCode": "0xe", 42 "EventCode": "0xe",
40 "EventName": "UNC_P_FREQ_BAND3_CYCLES", 43 "EventName": "UNC_P_FREQ_BAND3_CYCLES",
41 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.", 44 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.",
45 "MetricName": "freq_band3_cycles %",
42 "PerPkg": "1", 46 "PerPkg": "1",
43 "Unit": "PCU" 47 "Unit": "PCU"
44 }, 48 },
@@ -49,6 +53,7 @@
49 "EventName": "UNC_P_FREQ_BAND0_TRANSITIONS", 53 "EventName": "UNC_P_FREQ_BAND0_TRANSITIONS",
50 "Filter": "edge=1", 54 "Filter": "edge=1",
51 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.", 55 "MetricExpr": "(UNC_P_FREQ_BAND0_CYCLES / UNC_P_CLOCKTICKS) * 100.",
56 "MetricName": "freq_band0_cycles %",
52 "PerPkg": "1", 57 "PerPkg": "1",
53 "Unit": "PCU" 58 "Unit": "PCU"
54 }, 59 },
@@ -59,6 +64,7 @@
59 "EventName": "UNC_P_FREQ_BAND1_TRANSITIONS", 64 "EventName": "UNC_P_FREQ_BAND1_TRANSITIONS",
60 "Filter": "edge=1", 65 "Filter": "edge=1",
61 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.", 66 "MetricExpr": "(UNC_P_FREQ_BAND1_CYCLES / UNC_P_CLOCKTICKS) * 100.",
67 "MetricName": "freq_band1_cycles %",
62 "PerPkg": "1", 68 "PerPkg": "1",
63 "Unit": "PCU" 69 "Unit": "PCU"
64 }, 70 },
@@ -69,6 +75,7 @@
69 "EventName": "UNC_P_FREQ_BAND2_TRANSITIONS", 75 "EventName": "UNC_P_FREQ_BAND2_TRANSITIONS",
70 "Filter": "edge=1", 76 "Filter": "edge=1",
71 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.", 77 "MetricExpr": "(UNC_P_FREQ_BAND2_CYCLES / UNC_P_CLOCKTICKS) * 100.",
78 "MetricName": "freq_band2_cycles %",
72 "PerPkg": "1", 79 "PerPkg": "1",
73 "Unit": "PCU" 80 "Unit": "PCU"
74 }, 81 },
@@ -79,89 +86,99 @@
79 "EventName": "UNC_P_FREQ_BAND3_TRANSITIONS", 86 "EventName": "UNC_P_FREQ_BAND3_TRANSITIONS",
80 "Filter": "edge=1", 87 "Filter": "edge=1",
81 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.", 88 "MetricExpr": "(UNC_P_FREQ_BAND3_CYCLES / UNC_P_CLOCKTICKS) * 100.",
89 "MetricName": "freq_band3_cycles %",
82 "PerPkg": "1", 90 "PerPkg": "1",
83 "Unit": "PCU" 91 "Unit": "PCU"
84 }, 92 },
85 { 93 {
86 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C0. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details. Derived from unc_p_power_state_occupancy.cores_c0", 94 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C0. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
87 "Counter": "0,1,2,3", 95 "Counter": "0,1,2,3",
88 "EventCode": "0x80", 96 "EventCode": "0x80",
89 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0", 97 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C0",
90 "Filter": "occ_sel=1", 98 "Filter": "occ_sel=1",
91 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.", 99 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C0 / UNC_P_CLOCKTICKS) * 100.",
100 "MetricName": "power_state_occupancy.cores_c0 %",
92 "PerPkg": "1", 101 "PerPkg": "1",
93 "Unit": "PCU" 102 "Unit": "PCU"
94 }, 103 },
95 { 104 {
96 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C3. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details. Derived from unc_p_power_state_occupancy.cores_c3", 105 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C3. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events and occupancy triggering to capture other details",
97 "Counter": "0,1,2,3", 106 "Counter": "0,1,2,3",
98 "EventCode": "0x80", 107 "EventCode": "0x80",
99 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3", 108 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C3",
100 "Filter": "occ_sel=2", 109 "Filter": "occ_sel=2",
101 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.", 110 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C3 / UNC_P_CLOCKTICKS) * 100.",
111 "MetricName": "power_state_occupancy.cores_c3 %",
102 "PerPkg": "1", 112 "PerPkg": "1",
103 "Unit": "PCU" 113 "Unit": "PCU"
104 }, 114 },
105 { 115 {
106 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C6. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events . Derived from unc_p_power_state_occupancy.cores_c6", 116 "BriefDescription": "This is an occupancy event that tracks the number of cores that are in C6. It can be used by itself to get the average number of cores in C0, with threshholding to generate histograms, or with other PCU events ",
107 "Counter": "0,1,2,3", 117 "Counter": "0,1,2,3",
108 "EventCode": "0x80", 118 "EventCode": "0x80",
109 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6", 119 "EventName": "UNC_P_POWER_STATE_OCCUPANCY.CORES_C6",
110 "Filter": "occ_sel=3", 120 "Filter": "occ_sel=3",
111 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.", 121 "MetricExpr": "(UNC_P_POWER_STATE_OCCUPANCY.CORES_C6 / UNC_P_CLOCKTICKS) * 100.",
122 "MetricName": "power_state_occupancy.cores_c6 %",
112 "PerPkg": "1", 123 "PerPkg": "1",
113 "Unit": "PCU" 124 "Unit": "PCU"
114 }, 125 },
115 { 126 {
116 "BriefDescription": "Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip. Derived from unc_p_prochot_external_cycles", 127 "BriefDescription": "Counts the number of cycles that we are in external PROCHOT mode. This mode is triggered when a sensor off the die determines that something off-die (like DRAM) is too hot and must throttle to avoid damaging the chip",
117 "Counter": "0,1,2,3", 128 "Counter": "0,1,2,3",
118 "EventCode": "0xa", 129 "EventCode": "0xa",
119 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES", 130 "EventName": "UNC_P_PROCHOT_EXTERNAL_CYCLES",
120 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 131 "MetricExpr": "(UNC_P_PROCHOT_EXTERNAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
132 "MetricName": "prochot_external_cycles %",
121 "PerPkg": "1", 133 "PerPkg": "1",
122 "Unit": "PCU" 134 "Unit": "PCU"
123 }, 135 },
124 { 136 {
125 "BriefDescription": "Counts the number of cycles when temperature is the upper limit on frequency. Derived from unc_p_freq_max_limit_thermal_cycles", 137 "BriefDescription": "Counts the number of cycles when temperature is the upper limit on frequency",
126 "Counter": "0,1,2,3", 138 "Counter": "0,1,2,3",
127 "EventCode": "0x4", 139 "EventCode": "0x4",
128 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES", 140 "EventName": "UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES",
129 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.", 141 "MetricExpr": "(UNC_P_FREQ_MAX_LIMIT_THERMAL_CYCLES / UNC_P_CLOCKTICKS) * 100.",
142 "MetricName": "freq_max_limit_thermal_cycles %",
130 "PerPkg": "1", 143 "PerPkg": "1",
131 "Unit": "PCU" 144 "Unit": "PCU"
132 }, 145 },
133 { 146 {
134 "BriefDescription": "Counts the number of cycles when the OS is the upper limit on frequency. Derived from unc_p_freq_max_os_cycles", 147 "BriefDescription": "Counts the number of cycles when the OS is the upper limit on frequency",
135 "Counter": "0,1,2,3", 148 "Counter": "0,1,2,3",
136 "EventCode": "0x6", 149 "EventCode": "0x6",
137 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES", 150 "EventName": "UNC_P_FREQ_MAX_OS_CYCLES",
138 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 151 "MetricExpr": "(UNC_P_FREQ_MAX_OS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
152 "MetricName": "freq_max_os_cycles %",
139 "PerPkg": "1", 153 "PerPkg": "1",
140 "Unit": "PCU" 154 "Unit": "PCU"
141 }, 155 },
142 { 156 {
143 "BriefDescription": "Counts the number of cycles when power is the upper limit on frequency. Derived from unc_p_freq_max_power_cycles", 157 "BriefDescription": "Counts the number of cycles when power is the upper limit on frequency",
144 "Counter": "0,1,2,3", 158 "Counter": "0,1,2,3",
145 "EventCode": "0x5", 159 "EventCode": "0x5",
146 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES", 160 "EventName": "UNC_P_FREQ_MAX_POWER_CYCLES",
147 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.", 161 "MetricExpr": "(UNC_P_FREQ_MAX_POWER_CYCLES / UNC_P_CLOCKTICKS) * 100.",
162 "MetricName": "freq_max_power_cycles %",
148 "PerPkg": "1", 163 "PerPkg": "1",
149 "Unit": "PCU" 164 "Unit": "PCU"
150 }, 165 },
151 { 166 {
152 "BriefDescription": "Counts the number of cycles when current is the upper limit on frequency. Derived from unc_p_freq_max_current_cycles", 167 "BriefDescription": "Counts the number of cycles when current is the upper limit on frequency",
153 "Counter": "0,1,2,3", 168 "Counter": "0,1,2,3",
154 "EventCode": "0x7", 169 "EventCode": "0x7",
155 "EventName": "UNC_P_FREQ_MAX_CURRENT_CYCLES", 170 "EventName": "UNC_P_FREQ_MAX_CURRENT_CYCLES",
156 "MetricExpr": "(UNC_P_FREQ_MAX_CURRENT_CYCLES / UNC_P_CLOCKTICKS) * 100.", 171 "MetricExpr": "(UNC_P_FREQ_MAX_CURRENT_CYCLES / UNC_P_CLOCKTICKS) * 100.",
172 "MetricName": "freq_max_current_cycles %",
157 "PerPkg": "1", 173 "PerPkg": "1",
158 "Unit": "PCU" 174 "Unit": "PCU"
159 }, 175 },
160 { 176 {
161 "BriefDescription": "Cycles spent changing Frequency. Derived from unc_p_freq_trans_cycles", 177 "BriefDescription": "Cycles spent changing Frequency",
162 "Counter": "0,1,2,3", 178 "Counter": "0,1,2,3",
163 "EventName": "UNC_P_FREQ_TRANS_CYCLES", 179 "EventName": "UNC_P_FREQ_TRANS_CYCLES",
164 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.", 180 "MetricExpr": "(UNC_P_FREQ_TRANS_CYCLES / UNC_P_CLOCKTICKS) * 100.",
181 "MetricName": "freq_trans_cycles %",
165 "PerPkg": "1", 182 "PerPkg": "1",
166 "Unit": "PCU" 183 "Unit": "PCU"
167 }, 184 },
@@ -172,6 +189,7 @@
172 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES", 189 "EventName": "UNC_P_FREQ_GE_1200MHZ_CYCLES",
173 "Filter": "filter_band0=1200", 190 "Filter": "filter_band0=1200",
174 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 191 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
192 "MetricName": "freq_ge_1200mhz_cycles %",
175 "PerPkg": "1", 193 "PerPkg": "1",
176 "Unit": "PCU" 194 "Unit": "PCU"
177 }, 195 },
@@ -182,6 +200,7 @@
182 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES", 200 "EventName": "UNC_P_FREQ_GE_2000MHZ_CYCLES",
183 "Filter": "filter_band1=2000", 201 "Filter": "filter_band1=2000",
184 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 202 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
203 "MetricName": "freq_ge_2000mhz_cycles %",
185 "PerPkg": "1", 204 "PerPkg": "1",
186 "Unit": "PCU" 205 "Unit": "PCU"
187 }, 206 },
@@ -192,6 +211,7 @@
192 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES", 211 "EventName": "UNC_P_FREQ_GE_3000MHZ_CYCLES",
193 "Filter": "filter_band2=3000", 212 "Filter": "filter_band2=3000",
194 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 213 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
214 "MetricName": "freq_ge_3000mhz_cycles %",
195 "PerPkg": "1", 215 "PerPkg": "1",
196 "Unit": "PCU" 216 "Unit": "PCU"
197 }, 217 },
@@ -202,6 +222,7 @@
202 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES", 222 "EventName": "UNC_P_FREQ_GE_4000MHZ_CYCLES",
203 "Filter": "filter_band3=4000", 223 "Filter": "filter_band3=4000",
204 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 224 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
225 "MetricName": "freq_ge_4000mhz_cycles %",
205 "PerPkg": "1", 226 "PerPkg": "1",
206 "Unit": "PCU" 227 "Unit": "PCU"
207 }, 228 },
@@ -212,6 +233,7 @@
212 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS", 233 "EventName": "UNC_P_FREQ_GE_1200MHZ_TRANSITIONS",
213 "Filter": "edge=1,filter_band0=1200", 234 "Filter": "edge=1,filter_band0=1200",
214 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 235 "MetricExpr": "(UNC_P_FREQ_GE_1200MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
236 "MetricName": "freq_ge_1200mhz_cycles %",
215 "PerPkg": "1", 237 "PerPkg": "1",
216 "Unit": "PCU" 238 "Unit": "PCU"
217 }, 239 },
@@ -222,6 +244,7 @@
222 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS", 244 "EventName": "UNC_P_FREQ_GE_2000MHZ_TRANSITIONS",
223 "Filter": "edge=1,filter_band1=2000", 245 "Filter": "edge=1,filter_band1=2000",
224 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 246 "MetricExpr": "(UNC_P_FREQ_GE_2000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
247 "MetricName": "freq_ge_2000mhz_cycles %",
225 "PerPkg": "1", 248 "PerPkg": "1",
226 "Unit": "PCU" 249 "Unit": "PCU"
227 }, 250 },
@@ -232,6 +255,7 @@
232 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS", 255 "EventName": "UNC_P_FREQ_GE_3000MHZ_TRANSITIONS",
233 "Filter": "edge=1,filter_band2=4000", 256 "Filter": "edge=1,filter_band2=4000",
234 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 257 "MetricExpr": "(UNC_P_FREQ_GE_3000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
258 "MetricName": "freq_ge_3000mhz_cycles %",
235 "PerPkg": "1", 259 "PerPkg": "1",
236 "Unit": "PCU" 260 "Unit": "PCU"
237 }, 261 },
@@ -242,6 +266,7 @@
242 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS", 266 "EventName": "UNC_P_FREQ_GE_4000MHZ_TRANSITIONS",
243 "Filter": "edge=1,filter_band3=4000", 267 "Filter": "edge=1,filter_band3=4000",
244 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.", 268 "MetricExpr": "(UNC_P_FREQ_GE_4000MHZ_CYCLES / UNC_P_CLOCKTICKS) * 100.",
269 "MetricName": "freq_ge_4000mhz_cycles %",
245 "PerPkg": "1", 270 "PerPkg": "1",
246 "Unit": "PCU" 271 "Unit": "PCU"
247 } 272 }
diff --git a/tools/perf/pmu-events/arch/x86/mapfile.csv b/tools/perf/pmu-events/arch/x86/mapfile.csv
index 12181bb1da2a..d1a12e584c1b 100644
--- a/tools/perf/pmu-events/arch/x86/mapfile.csv
+++ b/tools/perf/pmu-events/arch/x86/mapfile.csv
@@ -17,6 +17,7 @@ GenuineIntel-6-3A,v18,ivybridge,core
17GenuineIntel-6-3E,v19,ivytown,core 17GenuineIntel-6-3E,v19,ivytown,core
18GenuineIntel-6-2D,v20,jaketown,core 18GenuineIntel-6-2D,v20,jaketown,core
19GenuineIntel-6-57,v9,knightslanding,core 19GenuineIntel-6-57,v9,knightslanding,core
20GenuineIntel-6-85,v9,knightslanding,core
20GenuineIntel-6-1E,v2,nehalemep,core 21GenuineIntel-6-1E,v2,nehalemep,core
21GenuineIntel-6-1F,v2,nehalemep,core 22GenuineIntel-6-1F,v2,nehalemep,core
22GenuineIntel-6-1A,v2,nehalemep,core 23GenuineIntel-6-1A,v2,nehalemep,core
diff --git a/tools/perf/pmu-events/arch/x86/sandybridge/uncore.json b/tools/perf/pmu-events/arch/x86/sandybridge/uncore.json
new file mode 100644
index 000000000000..42c70eed05a2
--- /dev/null
+++ b/tools/perf/pmu-events/arch/x86/sandybridge/uncore.json
@@ -0,0 +1,314 @@
1[
2 {
3 "Unit": "CBO",
4 "EventCode": "0x22",
5 "UMask": "0x01",
6 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS",
7 "BriefDescription": "A snoop misses in some processor core.",
8 "PublicDescription": "A snoop misses in some processor core.",
9 "Counter": "0,1",
10 "CounterMask": "0",
11 "Invert": "0",
12 "EdgeDetect": "0"
13 },
14 {
15 "Unit": "CBO",
16 "EventCode": "0x22",
17 "UMask": "0x02",
18 "EventName": "UNC_CBO_XSNP_RESPONSE.INVAL",
19 "BriefDescription": "A snoop invalidates a non-modified line in some processor core.",
20 "PublicDescription": "A snoop invalidates a non-modified line in some processor core.",
21 "Counter": "0,1",
22 "CounterMask": "0",
23 "Invert": "0",
24 "EdgeDetect": "0"
25 },
26 {
27 "Unit": "CBO",
28 "EventCode": "0x22",
29 "UMask": "0x04",
30 "EventName": "UNC_CBO_XSNP_RESPONSE.HIT",
31 "BriefDescription": "A snoop hits a non-modified line in some processor core.",
32 "PublicDescription": "A snoop hits a non-modified line in some processor core.",
33 "Counter": "0,1",
34 "CounterMask": "0",
35 "Invert": "0",
36 "EdgeDetect": "0"
37 },
38 {
39 "Unit": "CBO",
40 "EventCode": "0x22",
41 "UMask": "0x08",
42 "EventName": "UNC_CBO_XSNP_RESPONSE.HITM",
43 "BriefDescription": "A snoop hits a modified line in some processor core.",
44 "PublicDescription": "A snoop hits a modified line in some processor core.",
45 "Counter": "0,1",
46 "CounterMask": "0",
47 "Invert": "0",
48 "EdgeDetect": "0"
49 },
50 {
51 "Unit": "CBO",
52 "EventCode": "0x22",
53 "UMask": "0x10",
54 "EventName": "UNC_CBO_XSNP_RESPONSE.INVAL_M",
55 "BriefDescription": "A snoop invalidates a modified line in some processor core.",
56 "PublicDescription": "A snoop invalidates a modified line in some processor core.",
57 "Counter": "0,1",
58 "CounterMask": "0",
59 "Invert": "0",
60 "EdgeDetect": "0"
61 },
62 {
63 "Unit": "CBO",
64 "EventCode": "0x22",
65 "UMask": "0x20",
66 "EventName": "UNC_CBO_XSNP_RESPONSE.EXTERNAL_FILTER",
67 "BriefDescription": "Filter on cross-core snoops initiated by this Cbox due to external snoop request.",
68 "PublicDescription": "Filter on cross-core snoops initiated by this Cbox due to external snoop request.",
69 "Counter": "0,1",
70 "CounterMask": "0",
71 "Invert": "0",
72 "EdgeDetect": "0"
73 },
74 {
75 "Unit": "CBO",
76 "EventCode": "0x22",
77 "UMask": "0x40",
78 "EventName": "UNC_CBO_XSNP_RESPONSE.XCORE_FILTER",
79 "BriefDescription": "Filter on cross-core snoops initiated by this Cbox due to processor core memory request.",
80 "PublicDescription": "Filter on cross-core snoops initiated by this Cbox due to processor core memory request.",
81 "Counter": "0,1",
82 "CounterMask": "0",
83 "Invert": "0",
84 "EdgeDetect": "0"
85 },
86 {
87 "Unit": "CBO",
88 "EventCode": "0x22",
89 "UMask": "0x80",
90 "EventName": "UNC_CBO_XSNP_RESPONSE.EVICTION_FILTER",
91 "BriefDescription": "Filter on cross-core snoops initiated by this Cbox due to LLC eviction.",
92 "PublicDescription": "Filter on cross-core snoops initiated by this Cbox due to LLC eviction.",
93 "Counter": "0,1",
94 "CounterMask": "0",
95 "Invert": "0",
96 "EdgeDetect": "0"
97 },
98 {
99 "Unit": "CBO",
100 "EventCode": "0x34",
101 "UMask": "0x01",
102 "EventName": "UNC_CBO_CACHE_LOOKUP.M",
103 "BriefDescription": "LLC lookup request that access cache and found line in M-state.",
104 "PublicDescription": "LLC lookup request that access cache and found line in M-state.",
105 "Counter": "0,1",
106 "CounterMask": "0",
107 "Invert": "0",
108 "EdgeDetect": "0"
109 },
110 {
111 "Unit": "CBO",
112 "EventCode": "0x34",
113 "UMask": "0x02",
114 "EventName": "UNC_CBO_CACHE_LOOKUP.E",
115 "BriefDescription": "LLC lookup request that access cache and found line in E-state.",
116 "PublicDescription": "LLC lookup request that access cache and found line in E-state.",
117 "Counter": "0,1",
118 "CounterMask": "0",
119 "Invert": "0",
120 "EdgeDetect": "0"
121 },
122 {
123 "Unit": "CBO",
124 "EventCode": "0x34",
125 "UMask": "0x04",
126 "EventName": "UNC_CBO_CACHE_LOOKUP.S",
127 "BriefDescription": "LLC lookup request that access cache and found line in S-state.",
128 "PublicDescription": "LLC lookup request that access cache and found line in S-state.",
129 "Counter": "0,1",
130 "CounterMask": "0",
131 "Invert": "0",
132 "EdgeDetect": "0"
133 },
134 {
135 "Unit": "CBO",
136 "EventCode": "0x34",
137 "UMask": "0x08",
138 "EventName": "UNC_CBO_CACHE_LOOKUP.I",
139 "BriefDescription": "LLC lookup request that access cache and found line in I-state.",
140 "PublicDescription": "LLC lookup request that access cache and found line in I-state.",
141 "Counter": "0,1",
142 "CounterMask": "0",
143 "Invert": "0",
144 "EdgeDetect": "0"
145 },
146 {
147 "Unit": "CBO",
148 "EventCode": "0x34",
149 "UMask": "0x10",
150 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_FILTER",
151 "BriefDescription": "Filter on processor core initiated cacheable read requests.",
152 "PublicDescription": "Filter on processor core initiated cacheable read requests.",
153 "Counter": "0,1",
154 "CounterMask": "0",
155 "Invert": "0",
156 "EdgeDetect": "0"
157 },
158 {
159 "Unit": "CBO",
160 "EventCode": "0x34",
161 "UMask": "0x20",
162 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_FILTER",
163 "BriefDescription": "Filter on processor core initiated cacheable write requests.",
164 "PublicDescription": "Filter on processor core initiated cacheable write requests.",
165 "Counter": "0,1",
166 "CounterMask": "0",
167 "Invert": "0",
168 "EdgeDetect": "0"
169 },
170 {
171 "Unit": "CBO",
172 "EventCode": "0x34",
173 "UMask": "0x40",
174 "EventName": "UNC_CBO_CACHE_LOOKUP.EXTSNP_FILTER",
175 "BriefDescription": "Filter on external snoop requests.",
176 "PublicDescription": "Filter on external snoop requests.",
177 "Counter": "0,1",
178 "CounterMask": "0",
179 "Invert": "0",
180 "EdgeDetect": "0"
181 },
182 {
183 "Unit": "CBO",
184 "EventCode": "0x34",
185 "UMask": "0x80",
186 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_REQUEST_FILTER",
187 "BriefDescription": "Filter on any IRQ or IPQ initiated requests including uncacheable, non-coherent requests.",
188 "PublicDescription": "Filter on any IRQ or IPQ initiated requests including uncacheable, non-coherent requests.",
189 "Counter": "0,1",
190 "CounterMask": "0",
191 "Invert": "0",
192 "EdgeDetect": "0"
193 },
194 {
195 "Unit": "ARB",
196 "EventCode": "0x80",
197 "UMask": "0x01",
198 "EventName": "UNC_ARB_TRK_OCCUPANCY.ALL",
199 "BriefDescription": "Counts cycles weighted by the number of requests waiting for data returning from the memory controller. Accounts for coherent and non-coherent requests initiated by IA cores, processor graphic units, or LLC.",
200 "PublicDescription": "Counts cycles weighted by the number of requests waiting for data returning from the memory controller. Accounts for coherent and non-coherent requests initiated by IA cores, processor graphic units, or LLC.",
201 "Counter": "0",
202 "CounterMask": "0",
203 "Invert": "0",
204 "EdgeDetect": "0"
205 },
206 {
207 "Unit": "ARB",
208 "EventCode": "0x81",
209 "UMask": "0x01",
210 "EventName": "UNC_ARB_TRK_REQUESTS.ALL",
211 "BriefDescription": "Counts the number of coherent and in-coherent requests initiated by IA cores, processor graphic units, or LLC.",
212 "PublicDescription": "Counts the number of coherent and in-coherent requests initiated by IA cores, processor graphic units, or LLC.",
213 "Counter": "0,1",
214 "CounterMask": "0",
215 "Invert": "0",
216 "EdgeDetect": "0"
217 },
218 {
219 "Unit": "ARB",
220 "EventCode": "0x81",
221 "UMask": "0x20",
222 "EventName": "UNC_ARB_TRK_REQUESTS.WRITES",
223 "BriefDescription": "Counts the number of allocated write entries, include full, partial, and LLC evictions.",
224 "PublicDescription": "Counts the number of allocated write entries, include full, partial, and LLC evictions.",
225 "Counter": "0,1",
226 "CounterMask": "0",
227 "Invert": "0",
228 "EdgeDetect": "0"
229 },
230 {
231 "Unit": "ARB",
232 "EventCode": "0x81",
233 "UMask": "0x80",
234 "EventName": "UNC_ARB_TRK_REQUESTS.EVICTIONS",
235 "BriefDescription": "Counts the number of LLC evictions allocated.",
236 "PublicDescription": "Counts the number of LLC evictions allocated.",
237 "Counter": "0,1",
238 "CounterMask": "0",
239 "Invert": "0",
240 "EdgeDetect": "0"
241 },
242 {
243 "Unit": "ARB",
244 "EventCode": "0x83",
245 "UMask": "0x01",
246 "EventName": "UNC_ARB_COH_TRK_OCCUPANCY.ALL",
247 "BriefDescription": "Cycles weighted by number of requests pending in Coherency Tracker.",
248 "PublicDescription": "Cycles weighted by number of requests pending in Coherency Tracker.",
249 "Counter": "0",
250 "CounterMask": "0",
251 "Invert": "0",
252 "EdgeDetect": "0"
253 },
254 {
255 "Unit": "ARB",
256 "EventCode": "0x84",
257 "UMask": "0x01",
258 "EventName": "UNC_ARB_COH_TRK_REQUESTS.ALL",
259 "BriefDescription": "Number of requests allocated in Coherency Tracker.",
260 "PublicDescription": "Number of requests allocated in Coherency Tracker.",
261 "Counter": "0,1",
262 "CounterMask": "0",
263 "Invert": "0",
264 "EdgeDetect": "0"
265 },
266 {
267 "Unit": "ARB",
268 "EventCode": "0x80",
269 "UMask": "0x01",
270 "EventName": "UNC_ARB_TRK_OCCUPANCY.CYCLES_WITH_ANY_REQUEST",
271 "BriefDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
272 "PublicDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
273 "Counter": "0,1",
274 "CounterMask": "1",
275 "Invert": "0",
276 "EdgeDetect": "0"
277 },
278 {
279 "Unit": "ARB",
280 "EventCode": "0x80",
281 "UMask": "0x01",
282 "EventName": "UNC_ARB_TRK_OCCUPANCY.CYCLES_OVER_HALF_FULL",
283 "BriefDescription": "Cycles with at least half of the requests outstanding are waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
284 "PublicDescription": "Cycles with at least half of the requests outstanding are waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
285 "Counter": "0,1",
286 "CounterMask": "10",
287 "Invert": "0",
288 "EdgeDetect": "0"
289 },
290 {
291 "Unit": "ARB",
292 "EventCode": "0x0",
293 "UMask": "0x01",
294 "EventName": "UNC_CLOCK.SOCKET",
295 "BriefDescription": "This 48-bit fixed counter counts the UCLK cycles.",
296 "PublicDescription": "This 48-bit fixed counter counts the UCLK cycles.",
297 "Counter": "Fixed",
298 "CounterMask": "0",
299 "Invert": "0",
300 "EdgeDetect": "0"
301 },
302 {
303 "Unit": "CBO",
304 "EventCode": "0x34",
305 "UMask": "0x06",
306 "EventName": "UNC_CBO_CACHE_LOOKUP.ES",
307 "BriefDescription": "LLC lookup request that access cache and found line in E-state or S-state.",
308 "PublicDescription": "LLC lookup request that access cache and found line in E-state or S-state.",
309 "Counter": "0,1",
310 "CounterMask": "0",
311 "Invert": "0",
312 "EdgeDetect": "0"
313 }
314] \ No newline at end of file
diff --git a/tools/perf/pmu-events/arch/x86/skylake/uncore.json b/tools/perf/pmu-events/arch/x86/skylake/uncore.json
new file mode 100644
index 000000000000..dbc193252fb3
--- /dev/null
+++ b/tools/perf/pmu-events/arch/x86/skylake/uncore.json
@@ -0,0 +1,254 @@
1[
2 {
3 "Unit": "CBO",
4 "EventCode": "0x22",
5 "UMask": "0x41",
6 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_XCORE",
7 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which misses in some processor core.",
8 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which misses in some processor core.",
9 "Counter": "0,1",
10 "CounterMask": "0",
11 "Invert": "0",
12 "EdgeDetect": "0"
13 },
14 {
15 "Unit": "CBO",
16 "EventCode": "0x22",
17 "UMask": "0x81",
18 "EventName": "UNC_CBO_XSNP_RESPONSE.MISS_EVICTION",
19 "BriefDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.",
20 "PublicDescription": "A cross-core snoop resulted from L3 Eviction which misses in some processor core.",
21 "Counter": "0,1",
22 "CounterMask": "0",
23 "Invert": "0",
24 "EdgeDetect": "0"
25 },
26 {
27 "Unit": "CBO",
28 "EventCode": "0x22",
29 "UMask": "0x44",
30 "EventName": "UNC_CBO_XSNP_RESPONSE.HIT_XCORE",
31 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a non-modified line in some processor core.",
32 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a non-modified line in some processor core.",
33 "Counter": "0,1",
34 "CounterMask": "0",
35 "Invert": "0",
36 "EdgeDetect": "0"
37 },
38 {
39 "Unit": "CBO",
40 "EventCode": "0x22",
41 "UMask": "0x48",
42 "EventName": "UNC_CBO_XSNP_RESPONSE.HITM_XCORE",
43 "BriefDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a modified line in some processor core.",
44 "PublicDescription": "A cross-core snoop initiated by this Cbox due to processor core memory request which hits a modified line in some processor core.",
45 "Counter": "0,1",
46 "CounterMask": "0",
47 "Invert": "0",
48 "EdgeDetect": "0"
49 },
50 {
51 "Unit": "CBO",
52 "EventCode": "0x34",
53 "UMask": "0x21",
54 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_M",
55 "BriefDescription": "L3 Lookup write request that access cache and found line in M-state",
56 "PublicDescription": "L3 Lookup write request that access cache and found line in M-state.",
57 "Counter": "0,1",
58 "CounterMask": "0",
59 "Invert": "0",
60 "EdgeDetect": "0"
61 },
62 {
63 "Unit": "CBO",
64 "EventCode": "0x34",
65 "UMask": "0x81",
66 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_M",
67 "BriefDescription": "L3 Lookup any request that access cache and found line in M-state",
68 "PublicDescription": "L3 Lookup any request that access cache and found line in M-state.",
69 "Counter": "0,1",
70 "CounterMask": "0",
71 "Invert": "0",
72 "EdgeDetect": "0"
73 },
74 {
75 "Unit": "CBO",
76 "EventCode": "0x34",
77 "UMask": "0x18",
78 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_I",
79 "BriefDescription": "L3 Lookup read request that access cache and found line in I-state",
80 "PublicDescription": "L3 Lookup read request that access cache and found line in I-state.",
81 "Counter": "0,1",
82 "CounterMask": "0",
83 "Invert": "0",
84 "EdgeDetect": "0"
85 },
86 {
87 "Unit": "CBO",
88 "EventCode": "0x34",
89 "UMask": "0x88",
90 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_I",
91 "BriefDescription": "L3 Lookup any request that access cache and found line in I-state",
92 "PublicDescription": "L3 Lookup any request that access cache and found line in I-state.",
93 "Counter": "0,1",
94 "CounterMask": "0",
95 "Invert": "0",
96 "EdgeDetect": "0"
97 },
98 {
99 "Unit": "CBO",
100 "EventCode": "0x34",
101 "UMask": "0x1f",
102 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_MESI",
103 "BriefDescription": "L3 Lookup read request that access cache and found line in any MESI-state",
104 "PublicDescription": "L3 Lookup read request that access cache and found line in any MESI-state.",
105 "Counter": "0,1",
106 "CounterMask": "0",
107 "Invert": "0",
108 "EdgeDetect": "0"
109 },
110 {
111 "Unit": "CBO",
112 "EventCode": "0x34",
113 "UMask": "0x2f",
114 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_MESI",
115 "BriefDescription": "L3 Lookup write request that access cache and found line in MESI-state",
116 "PublicDescription": "L3 Lookup write request that access cache and found line in MESI-state.",
117 "Counter": "0,1",
118 "CounterMask": "0",
119 "Invert": "0",
120 "EdgeDetect": "0"
121 },
122 {
123 "Unit": "CBO",
124 "EventCode": "0x34",
125 "UMask": "0x8f",
126 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_MESI",
127 "BriefDescription": "L3 Lookup any request that access cache and found line in MESI-state",
128 "PublicDescription": "L3 Lookup any request that access cache and found line in MESI-state.",
129 "Counter": "0,1",
130 "CounterMask": "0",
131 "Invert": "0",
132 "EdgeDetect": "0"
133 },
134 {
135 "Unit": "CBO",
136 "EventCode": "0x34",
137 "UMask": "0x86",
138 "EventName": "UNC_CBO_CACHE_LOOKUP.ANY_ES",
139 "BriefDescription": "L3 Lookup any request that access cache and found line in E or S-state",
140 "PublicDescription": "L3 Lookup any request that access cache and found line in E or S-state.",
141 "Counter": "0,1",
142 "CounterMask": "0",
143 "Invert": "0",
144 "EdgeDetect": "0"
145 },
146 {
147 "Unit": "CBO",
148 "EventCode": "0x34",
149 "UMask": "0x16",
150 "EventName": "UNC_CBO_CACHE_LOOKUP.READ_ES",
151 "BriefDescription": "L3 Lookup read request that access cache and found line in E or S-state",
152 "PublicDescription": "L3 Lookup read request that access cache and found line in E or S-state.",
153 "Counter": "0,1",
154 "CounterMask": "0",
155 "Invert": "0",
156 "EdgeDetect": "0"
157 },
158 {
159 "Unit": "CBO",
160 "EventCode": "0x34",
161 "UMask": "0x26",
162 "EventName": "UNC_CBO_CACHE_LOOKUP.WRITE_ES",
163 "BriefDescription": "L3 Lookup write request that access cache and found line in E or S-state",
164 "PublicDescription": "L3 Lookup write request that access cache and found line in E or S-state.",
165 "Counter": "0,1",
166 "CounterMask": "0",
167 "Invert": "0",
168 "EdgeDetect": "0"
169 },
170 {
171 "Unit": "iMPH-U",
172 "EventCode": "0x80",
173 "UMask": "0x01",
174 "EventName": "UNC_ARB_TRK_OCCUPANCY.ALL",
175 "BriefDescription": "Each cycle count number of all Core outgoing valid entries. Such entry is defined as valid from its allocation till first of IDI0 or DRS0 messages is sent out. Accounts for Coherent and non-coherent traffic.",
176 "PublicDescription": "Each cycle count number of all Core outgoing valid entries. Such entry is defined as valid from its allocation till first of IDI0 or DRS0 messages is sent out. Accounts for Coherent and non-coherent traffic.",
177 "Counter": "0",
178 "CounterMask": "0",
179 "Invert": "0",
180 "EdgeDetect": "0"
181 },
182 {
183 "Unit": "iMPH-U",
184 "EventCode": "0x81",
185 "UMask": "0x01",
186 "EventName": "UNC_ARB_TRK_REQUESTS.ALL",
187 "BriefDescription": "Total number of Core outgoing entries allocated. Accounts for Coherent and non-coherent traffic.",
188 "PublicDescription": "Total number of Core outgoing entries allocated. Accounts for Coherent and non-coherent traffic.",
189 "Counter": "0,1",
190 "CounterMask": "0",
191 "Invert": "0",
192 "EdgeDetect": "0"
193 },
194 {
195 "Unit": "iMPH-U",
196 "EventCode": "0x81",
197 "UMask": "0x02",
198 "EventName": "UNC_ARB_TRK_REQUESTS.DRD_DIRECT",
199 "BriefDescription": "Number of Core coherent Data Read entries allocated in DirectData mode",
200 "PublicDescription": "Number of Core coherent Data Read entries allocated in DirectData mode.",
201 "Counter": "0,1",
202 "CounterMask": "0",
203 "Invert": "0",
204 "EdgeDetect": "0"
205 },
206 {
207 "Unit": "iMPH-U",
208 "EventCode": "0x81",
209 "UMask": "0x20",
210 "EventName": "UNC_ARB_TRK_REQUESTS.WRITES",
211 "BriefDescription": "Number of Writes allocated - any write transactions: full/partials writes and evictions.",
212 "PublicDescription": "Number of Writes allocated - any write transactions: full/partials writes and evictions.",
213 "Counter": "0,1",
214 "CounterMask": "0",
215 "Invert": "0",
216 "EdgeDetect": "0"
217 },
218 {
219 "Unit": "iMPH-U",
220 "EventCode": "0x84",
221 "UMask": "0x01",
222 "EventName": "UNC_ARB_COH_TRK_REQUESTS.ALL",
223 "BriefDescription": "Number of entries allocated. Account for Any type: e.g. Snoop, Core aperture, etc.",
224 "PublicDescription": "Number of entries allocated. Account for Any type: e.g. Snoop, Core aperture, etc.",
225 "Counter": "0,1",
226 "CounterMask": "0",
227 "Invert": "0",
228 "EdgeDetect": "0"
229 },
230 {
231 "Unit": "iMPH-U",
232 "EventCode": "0x80",
233 "UMask": "0x01",
234 "EventName": "UNC_ARB_TRK_OCCUPANCY.CYCLES_WITH_ANY_REQUEST",
235 "BriefDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.;",
236 "PublicDescription": "Cycles with at least one request outstanding is waiting for data return from memory controller. Account for coherent and non-coherent requests initiated by IA Cores, Processor Graphics Unit, or LLC.",
237 "Counter": "0",
238 "CounterMask": "1",
239 "Invert": "0",
240 "EdgeDetect": "0"
241 },
242 {
243 "Unit": "NCU",
244 "EventCode": "0x0",
245 "UMask": "0x01",
246 "EventName": "UNC_CLOCK.SOCKET",
247 "BriefDescription": "This 48-bit fixed counter counts the UCLK cycles",
248 "PublicDescription": "This 48-bit fixed counter counts the UCLK cycles.",
249 "Counter": "FIXED",
250 "CounterMask": "0",
251 "Invert": "0",
252 "EdgeDetect": "0"
253 }
254] \ No newline at end of file
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
index eed09346a72a..baa073f38334 100644
--- a/tools/perf/pmu-events/jevents.c
+++ b/tools/perf/pmu-events/jevents.c
@@ -195,6 +195,7 @@ static struct map {
195 { "CBO", "uncore_cbox" }, 195 { "CBO", "uncore_cbox" },
196 { "QPI LL", "uncore_qpi" }, 196 { "QPI LL", "uncore_qpi" },
197 { "SBO", "uncore_sbox" }, 197 { "SBO", "uncore_sbox" },
198 { "iMPH-U", "uncore_arb" },
198 {} 199 {}
199}; 200};
200 201
@@ -291,7 +292,9 @@ static void print_events_table_prefix(FILE *fp, const char *tblname)
291 292
292static int print_events_table_entry(void *data, char *name, char *event, 293static int print_events_table_entry(void *data, char *name, char *event,
293 char *desc, char *long_desc, 294 char *desc, char *long_desc,
294 char *pmu, char *unit, char *perpkg) 295 char *pmu, char *unit, char *perpkg,
296 char *metric_expr,
297 char *metric_name)
295{ 298{
296 struct perf_entry_data *pd = data; 299 struct perf_entry_data *pd = data;
297 FILE *outfp = pd->outfp; 300 FILE *outfp = pd->outfp;
@@ -315,6 +318,10 @@ static int print_events_table_entry(void *data, char *name, char *event,
315 fprintf(outfp, "\t.unit = \"%s\",\n", unit); 318 fprintf(outfp, "\t.unit = \"%s\",\n", unit);
316 if (perpkg) 319 if (perpkg)
317 fprintf(outfp, "\t.perpkg = \"%s\",\n", perpkg); 320 fprintf(outfp, "\t.perpkg = \"%s\",\n", perpkg);
321 if (metric_expr)
322 fprintf(outfp, "\t.metric_expr = \"%s\",\n", metric_expr);
323 if (metric_name)
324 fprintf(outfp, "\t.metric_name = \"%s\",\n", metric_name);
318 fprintf(outfp, "},\n"); 325 fprintf(outfp, "},\n");
319 326
320 return 0; 327 return 0;
@@ -362,7 +369,9 @@ static char *real_event(const char *name, char *event)
362int json_events(const char *fn, 369int json_events(const char *fn,
363 int (*func)(void *data, char *name, char *event, char *desc, 370 int (*func)(void *data, char *name, char *event, char *desc,
364 char *long_desc, 371 char *long_desc,
365 char *pmu, char *unit, char *perpkg), 372 char *pmu, char *unit, char *perpkg,
373 char *metric_expr,
374 char *metric_name),
366 void *data) 375 void *data)
367{ 376{
368 int err = -EIO; 377 int err = -EIO;
@@ -388,6 +397,8 @@ int json_events(const char *fn,
388 char *filter = NULL; 397 char *filter = NULL;
389 char *perpkg = NULL; 398 char *perpkg = NULL;
390 char *unit = NULL; 399 char *unit = NULL;
400 char *metric_expr = NULL;
401 char *metric_name = NULL;
391 unsigned long long eventcode = 0; 402 unsigned long long eventcode = 0;
392 struct msrmap *msr = NULL; 403 struct msrmap *msr = NULL;
393 jsmntok_t *msrval = NULL; 404 jsmntok_t *msrval = NULL;
@@ -398,6 +409,7 @@ int json_events(const char *fn,
398 for (j = 0; j < obj->size; j += 2) { 409 for (j = 0; j < obj->size; j += 2) {
399 jsmntok_t *field, *val; 410 jsmntok_t *field, *val;
400 int nz; 411 int nz;
412 char *s;
401 413
402 field = tok + j; 414 field = tok + j;
403 EXPECT(field->type == JSMN_STRING, tok + j, 415 EXPECT(field->type == JSMN_STRING, tok + j,
@@ -444,7 +456,6 @@ int json_events(const char *fn,
444 NULL); 456 NULL);
445 } else if (json_streq(map, field, "Unit")) { 457 } else if (json_streq(map, field, "Unit")) {
446 const char *ppmu; 458 const char *ppmu;
447 char *s;
448 459
449 ppmu = field_to_perf(unit_to_pmu, map, val); 460 ppmu = field_to_perf(unit_to_pmu, map, val);
450 if (ppmu) { 461 if (ppmu) {
@@ -458,12 +469,19 @@ int json_events(const char *fn,
458 } 469 }
459 addfield(map, &desc, ". ", "Unit: ", NULL); 470 addfield(map, &desc, ". ", "Unit: ", NULL);
460 addfield(map, &desc, "", pmu, NULL); 471 addfield(map, &desc, "", pmu, NULL);
472 addfield(map, &desc, "", " ", NULL);
461 } else if (json_streq(map, field, "Filter")) { 473 } else if (json_streq(map, field, "Filter")) {
462 addfield(map, &filter, "", "", val); 474 addfield(map, &filter, "", "", val);
463 } else if (json_streq(map, field, "ScaleUnit")) { 475 } else if (json_streq(map, field, "ScaleUnit")) {
464 addfield(map, &unit, "", "", val); 476 addfield(map, &unit, "", "", val);
465 } else if (json_streq(map, field, "PerPkg")) { 477 } else if (json_streq(map, field, "PerPkg")) {
466 addfield(map, &perpkg, "", "", val); 478 addfield(map, &perpkg, "", "", val);
479 } else if (json_streq(map, field, "MetricName")) {
480 addfield(map, &metric_name, "", "", val);
481 } else if (json_streq(map, field, "MetricExpr")) {
482 addfield(map, &metric_expr, "", "", val);
483 for (s = metric_expr; *s; s++)
484 *s = tolower(*s);
467 } 485 }
468 /* ignore unknown fields */ 486 /* ignore unknown fields */
469 } 487 }
@@ -488,7 +506,7 @@ int json_events(const char *fn,
488 fixname(name); 506 fixname(name);
489 507
490 err = func(data, name, real_event(name, event), desc, long_desc, 508 err = func(data, name, real_event(name, event), desc, long_desc,
491 pmu, unit, perpkg); 509 pmu, unit, perpkg, metric_expr, metric_name);
492 free(event); 510 free(event);
493 free(desc); 511 free(desc);
494 free(name); 512 free(name);
@@ -498,6 +516,8 @@ int json_events(const char *fn,
498 free(filter); 516 free(filter);
499 free(perpkg); 517 free(perpkg);
500 free(unit); 518 free(unit);
519 free(metric_expr);
520 free(metric_name);
501 if (err) 521 if (err)
502 break; 522 break;
503 tok += j; 523 tok += j;
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
index 71e13de31092..611fac01913d 100644
--- a/tools/perf/pmu-events/jevents.h
+++ b/tools/perf/pmu-events/jevents.h
@@ -5,7 +5,8 @@ int json_events(const char *fn,
5 int (*func)(void *data, char *name, char *event, char *desc, 5 int (*func)(void *data, char *name, char *event, char *desc,
6 char *long_desc, 6 char *long_desc,
7 char *pmu, 7 char *pmu,
8 char *unit, char *perpkg), 8 char *unit, char *perpkg, char *metric_expr,
9 char *metric_name),
9 void *data); 10 void *data);
10char *get_cpu_str(void); 11char *get_cpu_str(void);
11 12
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
index c669a3cdb9f0..569eab3688dd 100644
--- a/tools/perf/pmu-events/pmu-events.h
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -13,6 +13,8 @@ struct pmu_event {
13 const char *pmu; 13 const char *pmu;
14 const char *unit; 14 const char *unit;
15 const char *perpkg; 15 const char *perpkg;
16 const char *metric_expr;
17 const char *metric_name;
16}; 18};
17 19
18/* 20/*
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 1cb3d9b540e9..af58ebc243ef 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -38,6 +38,7 @@ perf-y += cpumap.o
38perf-y += stat.o 38perf-y += stat.o
39perf-y += event_update.o 39perf-y += event_update.o
40perf-y += event-times.o 40perf-y += event-times.o
41perf-y += expr.o
41perf-y += backward-ring-buffer.o 42perf-y += backward-ring-buffer.o
42perf-y += sdt.o 43perf-y += sdt.o
43perf-y += is_printable_array.o 44perf-y += is_printable_array.o
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 88dc51f4c27b..0dd77494bb58 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -18,10 +18,16 @@
18 * permissions. All the event text files are stored there. 18 * permissions. All the event text files are stored there.
19 */ 19 */
20 20
21#include <errno.h>
22#include <inttypes.h>
21#include <stdlib.h> 23#include <stdlib.h>
22#include <stdio.h> 24#include <stdio.h>
23#include <linux/types.h> 25#include <linux/types.h>
24#include <linux/kernel.h> 26#include <linux/kernel.h>
27#include <sys/param.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <unistd.h>
25#include "../perf.h" 31#include "../perf.h"
26#include "util.h" 32#include "util.h"
27#include <subcmd/exec-cmd.h> 33#include <subcmd/exec-cmd.h>
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
index 42e892b1e979..50f6d7afee58 100644
--- a/tools/perf/tests/backward-ring-buffer.c
+++ b/tools/perf/tests/backward-ring-buffer.c
@@ -8,6 +8,7 @@
8#include <sys/prctl.h> 8#include <sys/prctl.h>
9#include "tests.h" 9#include "tests.h"
10#include "debug.h" 10#include "debug.h"
11#include <errno.h>
11 12
12#define NR_ITERS 111 13#define NR_ITERS 111
13 14
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index 1a04fe77487d..5876da126b58 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -1,10 +1,14 @@
1#include <errno.h>
1#include <stdio.h> 2#include <stdio.h>
2#include <sys/epoll.h> 3#include <sys/epoll.h>
4#include <sys/types.h>
5#include <sys/stat.h>
3#include <util/util.h> 6#include <util/util.h>
4#include <util/bpf-loader.h> 7#include <util/bpf-loader.h>
5#include <util/evlist.h> 8#include <util/evlist.h>
6#include <linux/bpf.h> 9#include <linux/bpf.h>
7#include <linux/filter.h> 10#include <linux/filter.h>
11#include <linux/kernel.h>
8#include <api/fs/fs.h> 12#include <api/fs/fs.h>
9#include <bpf/bpf.h> 13#include <bpf/bpf.h>
10#include "tests.h" 14#include "tests.h"
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 83c4669cbc5b..9e08d297f1a9 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -3,8 +3,10 @@
3 * 3 *
4 * Builtin regression testing command: ever growing number of sanity tests 4 * Builtin regression testing command: ever growing number of sanity tests
5 */ 5 */
6#include <errno.h>
6#include <unistd.h> 7#include <unistd.h>
7#include <string.h> 8#include <string.h>
9#include <sys/wait.h>
8#include "builtin.h" 10#include "builtin.h"
9#include "hist.h" 11#include "hist.h"
10#include "intlist.h" 12#include "intlist.h"
@@ -13,6 +15,7 @@
13#include "color.h" 15#include "color.h"
14#include <subcmd/parse-options.h> 16#include <subcmd/parse-options.h>
15#include "symbol.h" 17#include "symbol.h"
18#include <linux/kernel.h>
16 19
17static bool dont_fork; 20static bool dont_fork;
18 21
@@ -44,6 +47,10 @@ static struct test generic_tests[] = {
44 .func = test__parse_events, 47 .func = test__parse_events,
45 }, 48 },
46 { 49 {
50 .desc = "Simple expression parser",
51 .func = test__expr,
52 },
53 {
47 .desc = "PERF_RECORD_* events & perf_sample fields", 54 .desc = "PERF_RECORD_* events & perf_sample fields",
48 .func = test__PERF_RECORD, 55 .func = test__PERF_RECORD,
49 }, 56 },
@@ -460,7 +467,7 @@ static int perf_test__list(int argc, const char **argv)
460 return 0; 467 return 0;
461} 468}
462 469
463int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) 470int cmd_test(int argc, const char **argv)
464{ 471{
465 const char *test_usage[] = { 472 const char *test_usage[] = {
466 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", 473 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
diff --git a/tools/perf/tests/clang.c b/tools/perf/tests/clang.c
index f853e242a86c..c5bb2203f5a9 100644
--- a/tools/perf/tests/clang.c
+++ b/tools/perf/tests/clang.c
@@ -2,6 +2,7 @@
2#include "debug.h" 2#include "debug.h"
3#include "util.h" 3#include "util.h"
4#include "c++/clang-c.h" 4#include "c++/clang-c.h"
5#include <linux/kernel.h>
5 6
6static struct { 7static struct {
7 int (*func)(void); 8 int (*func)(void);
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index d1f693041324..1f14e7612cbb 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -1,9 +1,12 @@
1#include <errno.h>
2#include <linux/kernel.h>
1#include <linux/types.h> 3#include <linux/types.h>
4#include <inttypes.h>
2#include <stdlib.h> 5#include <stdlib.h>
3#include <unistd.h> 6#include <unistd.h>
4#include <stdio.h> 7#include <stdio.h>
5#include <ctype.h>
6#include <string.h> 8#include <string.h>
9#include <sys/param.h>
7 10
8#include "parse-events.h" 11#include "parse-events.h"
9#include "evlist.h" 12#include "evlist.h"
@@ -16,6 +19,8 @@
16 19
17#include "tests.h" 20#include "tests.h"
18 21
22#include "sane_ctype.h"
23
19#define BUFSZ 1024 24#define BUFSZ 1024
20#define READLEN 128 25#define READLEN 128
21 26
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
index f168a85992d0..4478773cdb97 100644
--- a/tools/perf/tests/cpumap.c
+++ b/tools/perf/tests/cpumap.c
@@ -66,7 +66,7 @@ static int process_event_cpus(struct perf_tool *tool __maybe_unused,
66 TEST_ASSERT_VAL("wrong nr", map->nr == 2); 66 TEST_ASSERT_VAL("wrong nr", map->nr == 2);
67 TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1); 67 TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
68 TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256); 68 TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
69 TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1); 69 TEST_ASSERT_VAL("wrong refcnt", refcount_read(&map->refcnt) == 1);
70 cpu_map__put(map); 70 cpu_map__put(map);
71 return 0; 71 return 0;
72} 72}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 13725e09ba22..8f08df5861cb 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -1,4 +1,6 @@
1#include <dirent.h>
1#include <stdlib.h> 2#include <stdlib.h>
3#include <linux/kernel.h>
2#include <linux/types.h> 4#include <linux/types.h>
3#include <sys/stat.h> 5#include <sys/stat.h>
4#include <fcntl.h> 6#include <fcntl.h>
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 1046491de4b2..dfe5c89e2049 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -1,5 +1,6 @@
1#include <linux/compiler.h> 1#include <linux/compiler.h>
2#include <linux/types.h> 2#include <linux/types.h>
3#include <inttypes.h>
3#include <unistd.h> 4#include <unistd.h>
4#include "tests.h" 5#include "tests.h"
5#include "debug.h" 6#include "debug.h"
diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c
index 19ef77bd6eb4..634f20c631d8 100644
--- a/tools/perf/tests/event-times.c
+++ b/tools/perf/tests/event-times.c
@@ -1,5 +1,8 @@
1#include <linux/compiler.h> 1#include <linux/compiler.h>
2#include <errno.h>
3#include <inttypes.h>
2#include <string.h> 4#include <string.h>
5#include <sys/wait.h>
3#include "tests.h" 6#include "tests.h"
4#include "evlist.h" 7#include "evlist.h"
5#include "evsel.h" 8#include "evsel.h"
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 60926a1f6fd7..d2bea6f780f8 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -3,6 +3,8 @@
3#include "parse-events.h" 3#include "parse-events.h"
4#include "tests.h" 4#include "tests.h"
5#include "debug.h" 5#include "debug.h"
6#include <errno.h>
7#include <linux/kernel.h>
6 8
7static int perf_evsel__roundtrip_cache_name_test(void) 9static int perf_evsel__roundtrip_cache_name_test(void)
8{ 10{
diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c
new file mode 100644
index 000000000000..6c6a3749aaf6
--- /dev/null
+++ b/tools/perf/tests/expr.c
@@ -0,0 +1,56 @@
1#include "util/debug.h"
2#include "util/expr.h"
3#include "tests.h"
4#include <stdlib.h>
5
6static int test(struct parse_ctx *ctx, const char *e, double val2)
7{
8 double val;
9
10 if (expr__parse(&val, ctx, &e))
11 TEST_ASSERT_VAL("parse test failed", 0);
12 TEST_ASSERT_VAL("unexpected value", val == val2);
13 return 0;
14}
15
16int test__expr(int subtest __maybe_unused)
17{
18 const char *p;
19 const char **other;
20 double val;
21 int ret;
22 struct parse_ctx ctx;
23 int num_other;
24
25 expr__ctx_init(&ctx);
26 expr__add_id(&ctx, "FOO", 1);
27 expr__add_id(&ctx, "BAR", 2);
28
29 ret = test(&ctx, "1+1", 2);
30 ret |= test(&ctx, "FOO+BAR", 3);
31 ret |= test(&ctx, "(BAR/2)%2", 1);
32 ret |= test(&ctx, "1 - -4", 5);
33 ret |= test(&ctx, "(FOO-1)*2 + (BAR/2)%2 - -4", 5);
34
35 if (ret)
36 return ret;
37
38 p = "FOO/0";
39 ret = expr__parse(&val, &ctx, &p);
40 TEST_ASSERT_VAL("division by zero", ret == 1);
41
42 p = "BAR/";
43 ret = expr__parse(&val, &ctx, &p);
44 TEST_ASSERT_VAL("missing operand", ret == 1);
45
46 TEST_ASSERT_VAL("find other",
47 expr__find_other("FOO + BAR + BAZ + BOZO", "FOO", &other, &num_other) == 0);
48 TEST_ASSERT_VAL("find other", num_other == 3);
49 TEST_ASSERT_VAL("find other", !strcmp(other[0], "BAR"));
50 TEST_ASSERT_VAL("find other", !strcmp(other[1], "BAZ"));
51 TEST_ASSERT_VAL("find other", !strcmp(other[2], "BOZO"));
52 TEST_ASSERT_VAL("find other", other[3] == NULL);
53 free((void *)other);
54
55 return 0;
56}
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index 6b21746d6eec..00b8dc50f3db 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -1,3 +1,4 @@
1#include <inttypes.h>
1#include "perf.h" 2#include "perf.h"
2#include "util/debug.h" 3#include "util/debug.h"
3#include "util/symbol.h" 4#include "util/symbol.h"
@@ -7,6 +8,7 @@
7#include "util/machine.h" 8#include "util/machine.h"
8#include "util/thread.h" 9#include "util/thread.h"
9#include "tests/hists_common.h" 10#include "tests/hists_common.h"
11#include <linux/kernel.h>
10 12
11static struct { 13static struct {
12 u32 pid; 14 u32 pid;
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 9fd54b79a788..d549a9f2c41b 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -1,5 +1,6 @@
1#include "perf.h" 1#include "perf.h"
2#include "util/debug.h" 2#include "util/debug.h"
3#include "util/event.h"
3#include "util/symbol.h" 4#include "util/symbol.h"
4#include "util/sort.h" 5#include "util/sort.h"
5#include "util/evsel.h" 6#include "util/evsel.h"
@@ -9,6 +10,7 @@
9#include "util/parse-events.h" 10#include "util/parse-events.h"
10#include "tests/tests.h" 11#include "tests/tests.h"
11#include "tests/hists_common.h" 12#include "tests/hists_common.h"
13#include <linux/kernel.h>
12 14
13struct sample { 15struct sample {
14 u32 pid; 16 u32 pid;
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 62efb14f3a5a..df9c91f49af1 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -3,12 +3,14 @@
3#include "util/symbol.h" 3#include "util/symbol.h"
4#include "util/sort.h" 4#include "util/sort.h"
5#include "util/evsel.h" 5#include "util/evsel.h"
6#include "util/event.h"
6#include "util/evlist.h" 7#include "util/evlist.h"
7#include "util/machine.h" 8#include "util/machine.h"
8#include "util/thread.h" 9#include "util/thread.h"
9#include "util/parse-events.h" 10#include "util/parse-events.h"
10#include "tests/tests.h" 11#include "tests/tests.h"
11#include "tests/hists_common.h" 12#include "tests/hists_common.h"
13#include <linux/kernel.h>
12 14
13struct sample { 15struct sample {
14 u32 pid; 16 u32 pid;
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index eddc7407ff8a..a26cbb79e988 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -9,6 +9,8 @@
9#include "thread.h" 9#include "thread.h"
10#include "parse-events.h" 10#include "parse-events.h"
11#include "hists_common.h" 11#include "hists_common.h"
12#include <errno.h>
13#include <linux/kernel.h>
12 14
13struct sample { 15struct sample {
14 u32 pid; 16 u32 pid;
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index 63c5efaba1b5..06e5080182d3 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -1,5 +1,6 @@
1#include "perf.h" 1#include "perf.h"
2#include "util/debug.h" 2#include "util/debug.h"
3#include "util/event.h"
3#include "util/symbol.h" 4#include "util/symbol.h"
4#include "util/sort.h" 5#include "util/sort.h"
5#include "util/evsel.h" 6#include "util/evsel.h"
@@ -9,6 +10,7 @@
9#include "util/parse-events.h" 10#include "util/parse-events.h"
10#include "tests/tests.h" 11#include "tests/tests.h"
11#include "tests/hists_common.h" 12#include "tests/hists_common.h"
13#include <linux/kernel.h>
12 14
13struct sample { 15struct sample {
14 u32 cpu; 16 u32 cpu;
diff --git a/tools/perf/tests/is_printable_array.c b/tools/perf/tests/is_printable_array.c
index 42e13393e502..a5192f6a20d7 100644
--- a/tools/perf/tests/is_printable_array.c
+++ b/tools/perf/tests/is_printable_array.c
@@ -1,7 +1,8 @@
1#include <linux/compiler.h> 1#include <linux/compiler.h>
2#include <linux/kernel.h>
2#include "tests.h" 3#include "tests.h"
3#include "debug.h" 4#include "debug.h"
4#include "util.h" 5#include "print_binary.h"
5 6
6int test__is_printable_array(int subtest __maybe_unused) 7int test__is_printable_array(int subtest __maybe_unused)
7{ 8{
diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c
index 76f41f249944..6cd9e5107f77 100644
--- a/tools/perf/tests/kmod-path.c
+++ b/tools/perf/tests/kmod-path.c
@@ -61,6 +61,7 @@ int test__kmod_path__parse(int subtest __maybe_unused)
61 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true); 61 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true);
62 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false); 62 M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false);
63 63
64#ifdef HAVE_ZLIB_SUPPORT
64 /* path alloc_name alloc_ext kmod comp name ext */ 65 /* path alloc_name alloc_ext kmod comp name ext */
65 T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz"); 66 T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz");
66 T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz"); 67 T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz");
@@ -96,6 +97,7 @@ int test__kmod_path__parse(int subtest __maybe_unused)
96 M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); 97 M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true);
97 M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true); 98 M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true);
98 M("x.ko.gz", PERF_RECORD_MISC_USER, false); 99 M("x.ko.gz", PERF_RECORD_MISC_USER, false);
100#endif
99 101
100 /* path alloc_name alloc_ext kmod comp name ext */ 102 /* path alloc_name alloc_ext kmod comp name ext */
101 T("[test_module]", true , true , true, false, "[test_module]", NULL); 103 T("[test_module]", true , true , true, false, "[test_module]", NULL);
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 634bce9caebd..15c770856aac 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -1,3 +1,5 @@
1#include <errno.h>
2#include <inttypes.h>
1/* For the CLR_() macros */ 3/* For the CLR_() macros */
2#include <pthread.h> 4#include <pthread.h>
3 5
@@ -7,6 +9,7 @@
7#include "cpumap.h" 9#include "cpumap.h"
8#include "tests.h" 10#include "tests.h"
9#include <linux/err.h> 11#include <linux/err.h>
12#include <linux/kernel.h>
10 13
11/* 14/*
12 * This test will generate random numbers of calls to some getpid syscalls, 15 * This test will generate random numbers of calls to some getpid syscalls,
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index 0c5ce44f723f..6ea4d8a5d26b 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -1,3 +1,4 @@
1#include <inttypes.h>
1#include <unistd.h> 2#include <unistd.h>
2#include <sys/syscall.h> 3#include <sys/syscall.h>
3#include <sys/types.h> 4#include <sys/types.h>
@@ -11,6 +12,7 @@
11#include "thread_map.h" 12#include "thread_map.h"
12#include "symbol.h" 13#include "symbol.h"
13#include "thread.h" 14#include "thread.h"
15#include "util.h"
14 16
15#define THREADS 4 17#define THREADS 4
16 18
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c
index c8d9592eb142..1a74dd9fd067 100644
--- a/tools/perf/tests/openat-syscall-all-cpus.c
+++ b/tools/perf/tests/openat-syscall-all-cpus.c
@@ -1,8 +1,14 @@
1#include <errno.h>
2#include <inttypes.h>
1/* For the CPU_* macros */ 3/* For the CPU_* macros */
2#include <pthread.h> 4#include <pthread.h>
3 5
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
4#include <api/fs/fs.h> 9#include <api/fs/fs.h>
5#include <linux/err.h> 10#include <linux/err.h>
11#include <api/fs/tracing_path.h>
6#include "evsel.h" 12#include "evsel.h"
7#include "tests.h" 13#include "tests.h"
8#include "thread_map.h" 14#include "thread_map.h"
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index f52239fed361..9788fac91095 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -5,6 +5,7 @@
5#include "thread_map.h" 5#include "thread_map.h"
6#include "tests.h" 6#include "tests.h"
7#include "debug.h" 7#include "debug.h"
8#include <errno.h>
8 9
9#ifndef O_DIRECTORY 10#ifndef O_DIRECTORY
10#define O_DIRECTORY 00200000 11#define O_DIRECTORY 00200000
diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c
index d7414128d7fe..e44506e21ee7 100644
--- a/tools/perf/tests/openat-syscall.c
+++ b/tools/perf/tests/openat-syscall.c
@@ -1,5 +1,10 @@
1#include <errno.h>
2#include <inttypes.h>
1#include <api/fs/tracing_path.h> 3#include <api/fs/tracing_path.h>
2#include <linux/err.h> 4#include <linux/err.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
3#include "thread_map.h" 8#include "thread_map.h"
4#include "evsel.h" 9#include "evsel.h"
5#include "debug.h" 10#include "debug.h"
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 1dc838014422..7fad885491c5 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1,4 +1,3 @@
1
2#include "parse-events.h" 1#include "parse-events.h"
3#include "evsel.h" 2#include "evsel.h"
4#include "evlist.h" 3#include "evlist.h"
@@ -6,8 +5,15 @@
6#include "tests.h" 5#include "tests.h"
7#include "debug.h" 6#include "debug.h"
8#include "util.h" 7#include "util.h"
8#include <dirent.h>
9#include <errno.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <unistd.h>
13#include <linux/kernel.h>
9#include <linux/hw_breakpoint.h> 14#include <linux/hw_breakpoint.h>
10#include <api/fs/fs.h> 15#include <api/fs/fs.h>
16#include <api/fs/tracing_path.h>
11 17
12#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ 18#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
13 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) 19 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 65dcf48a92fb..c6207db09f12 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -1,3 +1,4 @@
1#include <linux/kernel.h>
1#include <linux/types.h> 2#include <linux/types.h>
2#include <stddef.h> 3#include <stddef.h>
3 4
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 87893f3ba5f1..d37cd9588cc0 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -1,3 +1,5 @@
1#include <errno.h>
2#include <inttypes.h>
1/* For the CLR_() macros */ 3/* For the CLR_() macros */
2#include <pthread.h> 4#include <pthread.h>
3 5
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index 1e2ba2602930..a6d7aef30030 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -2,6 +2,8 @@
2#include "pmu.h" 2#include "pmu.h"
3#include "util.h" 3#include "util.h"
4#include "tests.h" 4#include "tests.h"
5#include <errno.h>
6#include <linux/kernel.h>
5 7
6/* Simulated format definitions. */ 8/* Simulated format definitions. */
7static struct test_format { 9static struct test_format {
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 5f23710b9fee..bac5c3885b3b 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -1,4 +1,6 @@
1#include <stdbool.h> 1#include <stdbool.h>
2#include <inttypes.h>
3#include <linux/kernel.h>
2#include <linux/types.h> 4#include <linux/types.h>
3 5
4#include "util.h" 6#include "util.h"
diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c
index f59d210e1baf..06eda675ae2c 100644
--- a/tools/perf/tests/sdt.c
+++ b/tools/perf/tests/sdt.c
@@ -1,6 +1,6 @@
1#include <errno.h>
1#include <stdio.h> 2#include <stdio.h>
2#include <sys/epoll.h> 3#include <sys/epoll.h>
3#include <util/util.h>
4#include <util/evlist.h> 4#include <util/evlist.h>
5#include <linux/filter.h> 5#include <linux/filter.h>
6#include "tests.h" 6#include "tests.h"
@@ -43,7 +43,7 @@ static char *get_self_path(void)
43{ 43{
44 char *buf = calloc(PATH_MAX, sizeof(char)); 44 char *buf = calloc(PATH_MAX, sizeof(char));
45 45
46 if (buf && readlink("/proc/self/exe", buf, PATH_MAX) < 0) { 46 if (buf && readlink("/proc/self/exe", buf, PATH_MAX - 1) < 0) {
47 pr_debug("Failed to get correct path of perf\n"); 47 pr_debug("Failed to get correct path of perf\n");
48 free(buf); 48 free(buf);
49 return NULL; 49 return NULL;
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 4c9fd046d57b..828494db4a19 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -1,3 +1,5 @@
1#include <errno.h>
2#include <inttypes.h>
1#include <unistd.h> 3#include <unistd.h>
2#include <stdlib.h> 4#include <stdlib.h>
3#include <signal.h> 5#include <signal.h>
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index 7ddbe267d0ac..65474fd80da7 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -1,5 +1,6 @@
1#include <sys/time.h> 1#include <sys/time.h>
2#include <sys/prctl.h> 2#include <sys/prctl.h>
3#include <errno.h>
3#include <time.h> 4#include <time.h>
4#include <stdlib.h> 5#include <stdlib.h>
5 6
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index 01a5ba2788c6..32873ec91a4e 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -4,6 +4,7 @@
4#include "cpumap.h" 4#include "cpumap.h"
5#include "tests.h" 5#include "tests.h"
6 6
7#include <errno.h>
7#include <signal.h> 8#include <signal.h>
8 9
9static int exited; 10static int exited;
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 1fa9b9d83aa5..631859629403 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -62,6 +62,7 @@ int test__sample_parsing(int subtest);
62int test__keep_tracking(int subtest); 62int test__keep_tracking(int subtest);
63int test__parse_no_sample_id_all(int subtest); 63int test__parse_no_sample_id_all(int subtest);
64int test__dwarf_unwind(int subtest); 64int test__dwarf_unwind(int subtest);
65int test__expr(int subtest);
65int test__hists_filter(int subtest); 66int test__hists_filter(int subtest);
66int test__mmap_thread_lookup(int subtest); 67int test__mmap_thread_lookup(int subtest);
67int test__thread_mg_share(int subtest); 68int test__thread_mg_share(int subtest);
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index f2d2e542d0ee..a63d6945807b 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -29,7 +29,7 @@ int test__thread_map(int subtest __maybe_unused)
29 thread_map__comm(map, 0) && 29 thread_map__comm(map, 0) &&
30 !strcmp(thread_map__comm(map, 0), NAME)); 30 !strcmp(thread_map__comm(map, 0), NAME));
31 TEST_ASSERT_VAL("wrong refcnt", 31 TEST_ASSERT_VAL("wrong refcnt",
32 atomic_read(&map->refcnt) == 1); 32 refcount_read(&map->refcnt) == 1);
33 thread_map__put(map); 33 thread_map__put(map);
34 34
35 /* test dummy pid */ 35 /* test dummy pid */
@@ -44,7 +44,7 @@ int test__thread_map(int subtest __maybe_unused)
44 thread_map__comm(map, 0) && 44 thread_map__comm(map, 0) &&
45 !strcmp(thread_map__comm(map, 0), "dummy")); 45 !strcmp(thread_map__comm(map, 0), "dummy"));
46 TEST_ASSERT_VAL("wrong refcnt", 46 TEST_ASSERT_VAL("wrong refcnt",
47 atomic_read(&map->refcnt) == 1); 47 refcount_read(&map->refcnt) == 1);
48 thread_map__put(map); 48 thread_map__put(map);
49 return 0; 49 return 0;
50} 50}
@@ -71,7 +71,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
71 thread_map__comm(threads, 0) && 71 thread_map__comm(threads, 0) &&
72 !strcmp(thread_map__comm(threads, 0), NAME)); 72 !strcmp(thread_map__comm(threads, 0), NAME));
73 TEST_ASSERT_VAL("wrong refcnt", 73 TEST_ASSERT_VAL("wrong refcnt",
74 atomic_read(&threads->refcnt) == 1); 74 refcount_read(&threads->refcnt) == 1);
75 thread_map__put(threads); 75 thread_map__put(threads);
76 return 0; 76 return 0;
77} 77}
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
index 188b63140fc8..76686dd6f5ec 100644
--- a/tools/perf/tests/thread-mg-share.c
+++ b/tools/perf/tests/thread-mg-share.c
@@ -43,7 +43,7 @@ int test__thread_mg_share(int subtest __maybe_unused)
43 leader && t1 && t2 && t3 && other); 43 leader && t1 && t2 && t3 && other);
44 44
45 mg = leader->mg; 45 mg = leader->mg;
46 TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 4); 46 TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 4);
47 47
48 /* test the map groups pointer is shared */ 48 /* test the map groups pointer is shared */
49 TEST_ASSERT_VAL("map groups don't match", mg == t1->mg); 49 TEST_ASSERT_VAL("map groups don't match", mg == t1->mg);
@@ -71,25 +71,25 @@ int test__thread_mg_share(int subtest __maybe_unused)
71 machine__remove_thread(machine, other_leader); 71 machine__remove_thread(machine, other_leader);
72 72
73 other_mg = other->mg; 73 other_mg = other->mg;
74 TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&other_mg->refcnt), 2); 74 TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 2);
75 75
76 TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg); 76 TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg);
77 77
78 /* release thread group */ 78 /* release thread group */
79 thread__put(leader); 79 thread__put(leader);
80 TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 3); 80 TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 3);
81 81
82 thread__put(t1); 82 thread__put(t1);
83 TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 2); 83 TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 2);
84 84
85 thread__put(t2); 85 thread__put(t2);
86 TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&mg->refcnt), 1); 86 TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&mg->refcnt), 1);
87 87
88 thread__put(t3); 88 thread__put(t3);
89 89
90 /* release other group */ 90 /* release other group */
91 thread__put(other_leader); 91 thread__put(other_leader);
92 TEST_ASSERT_EQUAL("wrong refcnt", atomic_read(&other_mg->refcnt), 1); 92 TEST_ASSERT_EQUAL("wrong refcnt", refcount_read(&other_mg->refcnt), 1);
93 93
94 thread__put(other); 94 thread__put(other);
95 95
diff --git a/tools/perf/tests/unit_number__scnprintf.c b/tools/perf/tests/unit_number__scnprintf.c
index 623c2aa53c4a..44589de084b8 100644
--- a/tools/perf/tests/unit_number__scnprintf.c
+++ b/tools/perf/tests/unit_number__scnprintf.c
@@ -1,7 +1,8 @@
1#include <inttypes.h>
1#include <linux/compiler.h> 2#include <linux/compiler.h>
2#include <linux/types.h> 3#include <linux/types.h>
3#include "tests.h" 4#include "tests.h"
4#include "util.h" 5#include "units.h"
5#include "debug.h" 6#include "debug.h"
6 7
7int test__unit_number__scnprint(int subtest __maybe_unused) 8int test__unit_number__scnprint(int subtest __maybe_unused)
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 862b043e5924..8456175fc234 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -1,5 +1,6 @@
1#include <linux/compiler.h> 1#include <linux/compiler.h>
2#include <linux/rbtree.h> 2#include <linux/rbtree.h>
3#include <inttypes.h>
3#include <string.h> 4#include <string.h>
4#include "map.h" 5#include "map.h"
5#include "symbol.h" 6#include "symbol.h"
diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build
new file mode 100644
index 000000000000..be95ac6ce845
--- /dev/null
+++ b/tools/perf/trace/beauty/Build
@@ -0,0 +1 @@
libperf-y += statx.o
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h
new file mode 100644
index 000000000000..cf50be3f17a4
--- /dev/null
+++ b/tools/perf/trace/beauty/beauty.h
@@ -0,0 +1,24 @@
1#ifndef _PERF_TRACE_BEAUTY_H
2#define _PERF_TRACE_BEAUTY_H
3
4#include <linux/types.h>
5
6struct trace;
7struct thread;
8
9struct syscall_arg {
10 unsigned long val;
11 struct thread *thread;
12 struct trace *trace;
13 void *parm;
14 u8 idx;
15 u8 mask;
16};
17
18size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg);
19#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
20
21size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg);
22#define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask
23
24#endif /* _PERF_TRACE_BEAUTY_H */
diff --git a/tools/perf/trace/beauty/signum.c b/tools/perf/trace/beauty/signum.c
index d3b0b1fab077..fde8f2fc6558 100644
--- a/tools/perf/trace/beauty/signum.c
+++ b/tools/perf/trace/beauty/signum.c
@@ -1,3 +1,4 @@
1#include <signal.h>
1 2
2static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) 3static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
3{ 4{
diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c
new file mode 100644
index 000000000000..5643b692af4c
--- /dev/null
+++ b/tools/perf/trace/beauty/statx.c
@@ -0,0 +1,72 @@
1/*
2 * trace/beauty/statx.c
3 *
4 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
5 *
6 * Released under the GPL v2. (and only v2, not any later version)
7 */
8
9#include "trace/beauty/beauty.h"
10#include <linux/kernel.h>
11#include <sys/types.h>
12#include <uapi/linux/fcntl.h>
13#include <uapi/linux/stat.h>
14
15size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg)
16{
17 int printed = 0, flags = arg->val;
18
19 if (flags == 0)
20 return scnprintf(bf, size, "SYNC_AS_STAT");
21#define P_FLAG(n) \
22 if (flags & AT_##n) { \
23 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
24 flags &= ~AT_##n; \
25 }
26
27 P_FLAG(SYMLINK_NOFOLLOW);
28 P_FLAG(REMOVEDIR);
29 P_FLAG(SYMLINK_FOLLOW);
30 P_FLAG(NO_AUTOMOUNT);
31 P_FLAG(EMPTY_PATH);
32 P_FLAG(STATX_FORCE_SYNC);
33 P_FLAG(STATX_DONT_SYNC);
34
35#undef P_FLAG
36
37 if (flags)
38 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
39
40 return printed;
41}
42
43size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg)
44{
45 int printed = 0, flags = arg->val;
46
47#define P_FLAG(n) \
48 if (flags & STATX_##n) { \
49 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
50 flags &= ~STATX_##n; \
51 }
52
53 P_FLAG(TYPE);
54 P_FLAG(MODE);
55 P_FLAG(NLINK);
56 P_FLAG(UID);
57 P_FLAG(GID);
58 P_FLAG(ATIME);
59 P_FLAG(MTIME);
60 P_FLAG(CTIME);
61 P_FLAG(INO);
62 P_FLAG(SIZE);
63 P_FLAG(BLOCKS);
64 P_FLAG(BTIME);
65
66#undef P_FLAG
67
68 if (flags)
69 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
70
71 return printed;
72}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 3eb3edb307a4..a4d3762cd825 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -1,4 +1,5 @@
1#include "../util.h" 1#include "../util.h"
2#include "../string2.h"
2#include "../config.h" 3#include "../config.h"
3#include "../../perf.h" 4#include "../../perf.h"
4#include "libslang.h" 5#include "libslang.h"
@@ -13,6 +14,7 @@
13#include "helpline.h" 14#include "helpline.h"
14#include "keysyms.h" 15#include "keysyms.h"
15#include "../color.h" 16#include "../color.h"
17#include "sane_ctype.h"
16 18
17static int ui_browser__percent_color(struct ui_browser *browser, 19static int ui_browser__percent_color(struct ui_browser *browser,
18 double percent, bool current) 20 double percent, bool current)
@@ -579,7 +581,7 @@ static int ui_browser__color_config(const char *var, const char *value,
579 break; 581 break;
580 582
581 *bg = '\0'; 583 *bg = '\0';
582 while (isspace(*++bg)); 584 bg = ltrim(++bg);
583 ui_browser__colorsets[i].bg = bg; 585 ui_browser__colorsets[i].bg = bg;
584 ui_browser__colorsets[i].fg = fg; 586 ui_browser__colorsets[i].fg = fg;
585 return 0; 587 return 0;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index ba36aac340bc..d990ad08a3c6 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -9,7 +9,10 @@
9#include "../../util/symbol.h" 9#include "../../util/symbol.h"
10#include "../../util/evsel.h" 10#include "../../util/evsel.h"
11#include "../../util/config.h" 11#include "../../util/config.h"
12#include <inttypes.h>
12#include <pthread.h> 13#include <pthread.h>
14#include <linux/kernel.h>
15#include <sys/ttydefaults.h>
13 16
14struct disasm_line_samples { 17struct disasm_line_samples {
15 double percent; 18 double percent;
diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c
index edbeaaf31ace..e2c9390ff4c5 100644
--- a/tools/perf/ui/browsers/header.c
+++ b/tools/perf/ui/browsers/header.c
@@ -8,6 +8,8 @@
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h" 9#include "util/session.h"
10 10
11#include <sys/ttydefaults.h>
12
11static void ui_browser__argv_write(struct ui_browser *browser, 13static void ui_browser__argv_write(struct ui_browser *browser,
12 void *entry, int row) 14 void *entry, int row)
13{ 15{
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index fc4fb669ceee..69f4570bd4f9 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1,7 +1,11 @@
1#include <dirent.h>
2#include <errno.h>
3#include <inttypes.h>
1#include <stdio.h> 4#include <stdio.h>
2#include <stdlib.h> 5#include <stdlib.h>
3#include <string.h> 6#include <string.h>
4#include <linux/rbtree.h> 7#include <linux/rbtree.h>
8#include <sys/ttydefaults.h>
5 9
6#include "../../util/evsel.h" 10#include "../../util/evsel.h"
7#include "../../util/evlist.h" 11#include "../../util/evlist.h"
@@ -10,6 +14,7 @@
10#include "../../util/sort.h" 14#include "../../util/sort.h"
11#include "../../util/util.h" 15#include "../../util/util.h"
12#include "../../util/top.h" 16#include "../../util/top.h"
17#include "../../util/thread.h"
13#include "../../arch/common.h" 18#include "../../arch/common.h"
14 19
15#include "../browsers/hists.h" 20#include "../browsers/hists.h"
@@ -18,6 +23,11 @@
18#include "../ui.h" 23#include "../ui.h"
19#include "map.h" 24#include "map.h"
20#include "annotate.h" 25#include "annotate.h"
26#include "srcline.h"
27#include "string2.h"
28#include "units.h"
29
30#include "sane_ctype.h"
21 31
22extern void hist_browser__init_hpp(void); 32extern void hist_browser__init_hpp(void);
23 33
@@ -144,9 +154,60 @@ static void callchain_list__set_folding(struct callchain_list *cl, bool unfold)
144 cl->unfolded = unfold ? cl->has_children : false; 154 cl->unfolded = unfold ? cl->has_children : false;
145} 155}
146 156
157static struct inline_node *inline_node__create(struct map *map, u64 ip)
158{
159 struct dso *dso;
160 struct inline_node *node;
161
162 if (map == NULL)
163 return NULL;
164
165 dso = map->dso;
166 if (dso == NULL)
167 return NULL;
168
169 if (dso->kernel != DSO_TYPE_USER)
170 return NULL;
171
172 node = dso__parse_addr_inlines(dso,
173 map__rip_2objdump(map, ip));
174
175 return node;
176}
177
178static int inline__count_rows(struct inline_node *node)
179{
180 struct inline_list *ilist;
181 int i = 0;
182
183 if (node == NULL)
184 return 0;
185
186 list_for_each_entry(ilist, &node->val, list) {
187 if ((ilist->filename != NULL) || (ilist->funcname != NULL))
188 i++;
189 }
190
191 return i;
192}
193
194static int callchain_list__inline_rows(struct callchain_list *chain)
195{
196 struct inline_node *node;
197 int rows;
198
199 node = inline_node__create(chain->ms.map, chain->ip);
200 if (node == NULL)
201 return 0;
202
203 rows = inline__count_rows(node);
204 inline_node__delete(node);
205 return rows;
206}
207
147static int callchain_node__count_rows_rb_tree(struct callchain_node *node) 208static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
148{ 209{
149 int n = 0; 210 int n = 0, inline_rows;
150 struct rb_node *nd; 211 struct rb_node *nd;
151 212
152 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) { 213 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
@@ -156,6 +217,13 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
156 217
157 list_for_each_entry(chain, &child->val, list) { 218 list_for_each_entry(chain, &child->val, list) {
158 ++n; 219 ++n;
220
221 if (symbol_conf.inline_name) {
222 inline_rows =
223 callchain_list__inline_rows(chain);
224 n += inline_rows;
225 }
226
159 /* We need this because we may not have children */ 227 /* We need this because we may not have children */
160 folded_sign = callchain_list__folded(chain); 228 folded_sign = callchain_list__folded(chain);
161 if (folded_sign == '+') 229 if (folded_sign == '+')
@@ -207,7 +275,7 @@ static int callchain_node__count_rows(struct callchain_node *node)
207{ 275{
208 struct callchain_list *chain; 276 struct callchain_list *chain;
209 bool unfolded = false; 277 bool unfolded = false;
210 int n = 0; 278 int n = 0, inline_rows;
211 279
212 if (callchain_param.mode == CHAIN_FLAT) 280 if (callchain_param.mode == CHAIN_FLAT)
213 return callchain_node__count_flat_rows(node); 281 return callchain_node__count_flat_rows(node);
@@ -216,6 +284,11 @@ static int callchain_node__count_rows(struct callchain_node *node)
216 284
217 list_for_each_entry(chain, &node->val, list) { 285 list_for_each_entry(chain, &node->val, list) {
218 ++n; 286 ++n;
287 if (symbol_conf.inline_name) {
288 inline_rows = callchain_list__inline_rows(chain);
289 n += inline_rows;
290 }
291
219 unfolded = chain->unfolded; 292 unfolded = chain->unfolded;
220 } 293 }
221 294
@@ -362,6 +435,19 @@ static void hist_entry__init_have_children(struct hist_entry *he)
362 he->init_have_children = true; 435 he->init_have_children = true;
363} 436}
364 437
438static void hist_entry_init_inline_node(struct hist_entry *he)
439{
440 if (he->inline_node)
441 return;
442
443 he->inline_node = inline_node__create(he->ms.map, he->ip);
444
445 if (he->inline_node == NULL)
446 return;
447
448 he->has_children = true;
449}
450
365static bool hist_browser__toggle_fold(struct hist_browser *browser) 451static bool hist_browser__toggle_fold(struct hist_browser *browser)
366{ 452{
367 struct hist_entry *he = browser->he_selection; 453 struct hist_entry *he = browser->he_selection;
@@ -393,7 +479,12 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
393 479
394 if (he->unfolded) { 480 if (he->unfolded) {
395 if (he->leaf) 481 if (he->leaf)
396 he->nr_rows = callchain__count_rows(&he->sorted_chain); 482 if (he->inline_node)
483 he->nr_rows = inline__count_rows(
484 he->inline_node);
485 else
486 he->nr_rows = callchain__count_rows(
487 &he->sorted_chain);
397 else 488 else
398 he->nr_rows = hierarchy_count_rows(browser, he, false); 489 he->nr_rows = hierarchy_count_rows(browser, he, false);
399 490
@@ -753,6 +844,71 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
753 844
754#define LEVEL_OFFSET_STEP 3 845#define LEVEL_OFFSET_STEP 3
755 846
847static int hist_browser__show_inline(struct hist_browser *browser,
848 struct inline_node *node,
849 unsigned short row,
850 int offset)
851{
852 struct inline_list *ilist;
853 char buf[1024];
854 int color, width, first_row;
855
856 first_row = row;
857 width = browser->b.width - (LEVEL_OFFSET_STEP + 2);
858 list_for_each_entry(ilist, &node->val, list) {
859 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
860 color = HE_COLORSET_NORMAL;
861 if (ui_browser__is_current_entry(&browser->b, row))
862 color = HE_COLORSET_SELECTED;
863
864 if (callchain_param.key == CCKEY_ADDRESS ||
865 callchain_param.key == CCKEY_SRCLINE) {
866 if (ilist->filename != NULL)
867 scnprintf(buf, sizeof(buf),
868 "%s:%d (inline)",
869 ilist->filename,
870 ilist->line_nr);
871 else
872 scnprintf(buf, sizeof(buf), "??");
873 } else if (ilist->funcname != NULL)
874 scnprintf(buf, sizeof(buf), "%s (inline)",
875 ilist->funcname);
876 else if (ilist->filename != NULL)
877 scnprintf(buf, sizeof(buf),
878 "%s:%d (inline)",
879 ilist->filename,
880 ilist->line_nr);
881 else
882 scnprintf(buf, sizeof(buf), "??");
883
884 ui_browser__set_color(&browser->b, color);
885 hist_browser__gotorc(browser, row, 0);
886 ui_browser__write_nstring(&browser->b, " ",
887 LEVEL_OFFSET_STEP + offset);
888 ui_browser__write_nstring(&browser->b, buf, width);
889 row++;
890 }
891 }
892
893 return row - first_row;
894}
895
896static size_t show_inline_list(struct hist_browser *browser, struct map *map,
897 u64 ip, int row, int offset)
898{
899 struct inline_node *node;
900 int ret;
901
902 node = inline_node__create(map, ip);
903 if (node == NULL)
904 return 0;
905
906 ret = hist_browser__show_inline(browser, node, row, offset);
907
908 inline_node__delete(node);
909 return ret;
910}
911
756static int hist_browser__show_callchain_list(struct hist_browser *browser, 912static int hist_browser__show_callchain_list(struct hist_browser *browser,
757 struct callchain_node *node, 913 struct callchain_node *node,
758 struct callchain_list *chain, 914 struct callchain_list *chain,
@@ -764,6 +920,7 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
764 char bf[1024], *alloc_str; 920 char bf[1024], *alloc_str;
765 char buf[64], *alloc_str2; 921 char buf[64], *alloc_str2;
766 const char *str; 922 const char *str;
923 int inline_rows = 0, ret = 1;
767 924
768 if (arg->row_offset != 0) { 925 if (arg->row_offset != 0) {
769 arg->row_offset--; 926 arg->row_offset--;
@@ -801,10 +958,15 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
801 } 958 }
802 959
803 print(browser, chain, str, offset, row, arg); 960 print(browser, chain, str, offset, row, arg);
804
805 free(alloc_str); 961 free(alloc_str);
806 free(alloc_str2); 962 free(alloc_str2);
807 return 1; 963
964 if (symbol_conf.inline_name) {
965 inline_rows = show_inline_list(browser, chain->ms.map,
966 chain->ip, row + 1, offset);
967 }
968
969 return ret + inline_rows;
808} 970}
809 971
810static bool check_percent_display(struct rb_node *node, u64 parent_total) 972static bool check_percent_display(struct rb_node *node, u64 parent_total)
@@ -1228,6 +1390,12 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1228 folded_sign = hist_entry__folded(entry); 1390 folded_sign = hist_entry__folded(entry);
1229 } 1391 }
1230 1392
1393 if (symbol_conf.inline_name &&
1394 (!entry->has_children)) {
1395 hist_entry_init_inline_node(entry);
1396 folded_sign = hist_entry__folded(entry);
1397 }
1398
1231 if (row_offset == 0) { 1399 if (row_offset == 0) {
1232 struct hpp_arg arg = { 1400 struct hpp_arg arg = {
1233 .b = &browser->b, 1401 .b = &browser->b,
@@ -1259,7 +1427,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1259 } 1427 }
1260 1428
1261 if (first) { 1429 if (first) {
1262 if (symbol_conf.use_callchain) { 1430 if (symbol_conf.use_callchain ||
1431 symbol_conf.inline_name) {
1263 ui_browser__printf(&browser->b, "%c ", folded_sign); 1432 ui_browser__printf(&browser->b, "%c ", folded_sign);
1264 width -= 2; 1433 width -= 2;
1265 } 1434 }
@@ -1301,8 +1470,14 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1301 .is_current_entry = current_entry, 1470 .is_current_entry = current_entry,
1302 }; 1471 };
1303 1472
1304 printed += hist_browser__show_callchain(browser, entry, 1, row, 1473 if (entry->inline_node)
1305 hist_browser__show_callchain_entry, &arg, 1474 printed += hist_browser__show_inline(browser,
1475 entry->inline_node, row, 0);
1476 else
1477 printed += hist_browser__show_callchain(browser,
1478 entry, 1, row,
1479 hist_browser__show_callchain_entry,
1480 &arg,
1306 hist_browser__check_output_full); 1481 hist_browser__check_output_full);
1307 } 1482 }
1308 1483
@@ -2308,7 +2483,7 @@ static int switch_data_file(void)
2308 return ret; 2483 return ret;
2309 2484
2310 memset(options, 0, sizeof(options)); 2485 memset(options, 0, sizeof(options));
2311 memset(options, 0, sizeof(abs_path)); 2486 memset(abs_path, 0, sizeof(abs_path));
2312 2487
2313 while ((dent = readdir(pwd_dir))) { 2488 while ((dent = readdir(pwd_dir))) {
2314 char path[PATH_MAX]; 2489 char path[PATH_MAX];
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 9ce142de536d..ffa5addf631d 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -11,6 +11,8 @@
11#include "../keysyms.h" 11#include "../keysyms.h"
12#include "map.h" 12#include "map.h"
13 13
14#include "sane_ctype.h"
15
14struct map_browser { 16struct map_browser {
15 struct ui_browser b; 17 struct ui_browser b;
16 struct map *map; 18 struct map *map;
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
index 8c9308ac30b7..e99ba86158d2 100644
--- a/tools/perf/ui/gtk/annotate.c
+++ b/tools/perf/ui/gtk/annotate.c
@@ -3,7 +3,8 @@
3#include "util/annotate.h" 3#include "util/annotate.h"
4#include "util/evsel.h" 4#include "util/evsel.h"
5#include "ui/helpline.h" 5#include "ui/helpline.h"
6 6#include <inttypes.h>
7#include <signal.h>
7 8
8enum { 9enum {
9 ANN_COL__PERCENT, 10 ANN_COL__PERCENT,
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index a4f02de7c1b5..e24f83957705 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -4,7 +4,9 @@
4#include "../sort.h" 4#include "../sort.h"
5#include "../hist.h" 5#include "../hist.h"
6#include "../helpline.h" 6#include "../helpline.h"
7#include "../string2.h"
7#include "gtk.h" 8#include "gtk.h"
9#include <signal.h>
8 10
9#define MAX_COLUMNS 32 11#define MAX_COLUMNS 32
10 12
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 5d632dca672a..59addd52d9cd 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -1,3 +1,4 @@
1#include <inttypes.h>
1#include <math.h> 2#include <math.h>
2#include <linux/compiler.h> 3#include <linux/compiler.h>
3 4
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index 50d13e58210f..caf1ce6f5152 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -4,12 +4,16 @@
4#include "../util/cache.h" 4#include "../util/cache.h"
5#include "../util/debug.h" 5#include "../util/debug.h"
6#include "../util/hist.h" 6#include "../util/hist.h"
7#include "../util/util.h"
7 8
8pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; 9pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
9void *perf_gtk_handle; 10void *perf_gtk_handle;
10int use_browser = -1; 11int use_browser = -1;
11 12
13#define PERF_GTK_DSO "libperf-gtk.so"
14
12#ifdef HAVE_GTK2_SUPPORT 15#ifdef HAVE_GTK2_SUPPORT
16
13static int setup_gtk_browser(void) 17static int setup_gtk_browser(void)
14{ 18{
15 int (*perf_ui_init)(void); 19 int (*perf_ui_init)(void);
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 668f4aecf2e6..42e432bd2eb4 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -4,7 +4,10 @@
4#include "../../util/hist.h" 4#include "../../util/hist.h"
5#include "../../util/sort.h" 5#include "../../util/sort.h"
6#include "../../util/evsel.h" 6#include "../../util/evsel.h"
7 7#include "../../util/srcline.h"
8#include "../../util/string2.h"
9#include "../../util/thread.h"
10#include "../../util/sane_ctype.h"
8 11
9static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 12static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
10{ 13{
@@ -17,6 +20,67 @@ static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
17 return ret; 20 return ret;
18} 21}
19 22
23static size_t inline__fprintf(struct map *map, u64 ip, int left_margin,
24 int depth, int depth_mask, FILE *fp)
25{
26 struct dso *dso;
27 struct inline_node *node;
28 struct inline_list *ilist;
29 int ret = 0, i;
30
31 if (map == NULL)
32 return 0;
33
34 dso = map->dso;
35 if (dso == NULL)
36 return 0;
37
38 if (dso->kernel != DSO_TYPE_USER)
39 return 0;
40
41 node = dso__parse_addr_inlines(dso,
42 map__rip_2objdump(map, ip));
43 if (node == NULL)
44 return 0;
45
46 list_for_each_entry(ilist, &node->val, list) {
47 if ((ilist->filename != NULL) || (ilist->funcname != NULL)) {
48 ret += callchain__fprintf_left_margin(fp, left_margin);
49
50 for (i = 0; i < depth; i++) {
51 if (depth_mask & (1 << i))
52 ret += fprintf(fp, "|");
53 else
54 ret += fprintf(fp, " ");
55 ret += fprintf(fp, " ");
56 }
57
58 if (callchain_param.key == CCKEY_ADDRESS ||
59 callchain_param.key == CCKEY_SRCLINE) {
60 if (ilist->filename != NULL)
61 ret += fprintf(fp, "%s:%d (inline)",
62 ilist->filename,
63 ilist->line_nr);
64 else
65 ret += fprintf(fp, "??");
66 } else if (ilist->funcname != NULL)
67 ret += fprintf(fp, "%s (inline)",
68 ilist->funcname);
69 else if (ilist->filename != NULL)
70 ret += fprintf(fp, "%s:%d (inline)",
71 ilist->filename,
72 ilist->line_nr);
73 else
74 ret += fprintf(fp, "??");
75
76 ret += fprintf(fp, "\n");
77 }
78 }
79
80 inline_node__delete(node);
81 return ret;
82}
83
20static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, 84static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
21 int left_margin) 85 int left_margin)
22{ 86{
@@ -78,6 +142,10 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
78 fputs(str, fp); 142 fputs(str, fp);
79 fputc('\n', fp); 143 fputc('\n', fp);
80 free(alloc_str); 144 free(alloc_str);
145
146 if (symbol_conf.inline_name)
147 ret += inline__fprintf(chain->ms.map, chain->ip,
148 left_margin, depth, depth_mask, fp);
81 return ret; 149 return ret;
82} 150}
83 151
@@ -229,6 +297,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
229 if (!i++ && field_order == NULL && 297 if (!i++ && field_order == NULL &&
230 sort_order && !prefixcmp(sort_order, "sym")) 298 sort_order && !prefixcmp(sort_order, "sym"))
231 continue; 299 continue;
300
232 if (!printed) { 301 if (!printed) {
233 ret += callchain__fprintf_left_margin(fp, left_margin); 302 ret += callchain__fprintf_left_margin(fp, left_margin);
234 ret += fprintf(fp, "|\n"); 303 ret += fprintf(fp, "|\n");
@@ -251,6 +320,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
251 320
252 if (++entries_printed == callchain_param.print_limit) 321 if (++entries_printed == callchain_param.print_limit)
253 break; 322 break;
323
324 if (symbol_conf.inline_name)
325 ret += inline__fprintf(chain->ms.map,
326 chain->ip,
327 left_margin,
328 0, 0,
329 fp);
254 } 330 }
255 root = &cnode->rb_root; 331 root = &cnode->rb_root;
256 } 332 }
@@ -529,6 +605,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
529 bool use_callchain) 605 bool use_callchain)
530{ 606{
531 int ret; 607 int ret;
608 int callchain_ret = 0;
609 int inline_ret = 0;
532 struct perf_hpp hpp = { 610 struct perf_hpp hpp = {
533 .buf = bf, 611 .buf = bf,
534 .size = size, 612 .size = size,
@@ -547,7 +625,16 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
547 ret = fprintf(fp, "%s\n", bf); 625 ret = fprintf(fp, "%s\n", bf);
548 626
549 if (use_callchain) 627 if (use_callchain)
550 ret += hist_entry_callchain__fprintf(he, total_period, 0, fp); 628 callchain_ret = hist_entry_callchain__fprintf(he, total_period,
629 0, fp);
630
631 if (callchain_ret == 0 && symbol_conf.inline_name) {
632 inline_ret = inline__fprintf(he->ms.map, he->ip, 0, 0, 0, fp);
633 ret += inline_ret;
634 if (inline_ret > 0)
635 ret += fprintf(fp, "\n");
636 } else
637 ret += callchain_ret;
551 638
552 return ret; 639 return ret;
553} 640}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 4ea2ba861fc2..d9350a1da48b 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -1,6 +1,7 @@
1#include <errno.h> 1#include <errno.h>
2#include <signal.h> 2#include <signal.h>
3#include <stdbool.h> 3#include <stdbool.h>
4#include <linux/kernel.h>
4#ifdef HAVE_BACKTRACE_SUPPORT 5#ifdef HAVE_BACKTRACE_SUPPORT
5#include <execinfo.h> 6#include <execinfo.h>
6#endif 7#endif
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5da376bc1afc..79dea95a7f68 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -1,4 +1,3 @@
1libperf-y += alias.o
2libperf-y += annotate.o 1libperf-y += annotate.o
3libperf-y += block-range.o 2libperf-y += block-range.o
4libperf-y += build-id.o 3libperf-y += build-id.o
@@ -14,9 +13,11 @@ libperf-y += find_bit.o
14libperf-y += kallsyms.o 13libperf-y += kallsyms.o
15libperf-y += levenshtein.o 14libperf-y += levenshtein.o
16libperf-y += llvm-utils.o 15libperf-y += llvm-utils.o
16libperf-y += memswap.o
17libperf-y += parse-events.o 17libperf-y += parse-events.o
18libperf-y += perf_regs.o 18libperf-y += perf_regs.o
19libperf-y += path.o 19libperf-y += path.o
20libperf-y += print_binary.o
20libperf-y += rbtree.o 21libperf-y += rbtree.o
21libperf-y += libstring.o 22libperf-y += libstring.o
22libperf-y += bitmap.o 23libperf-y += bitmap.o
@@ -42,6 +43,7 @@ libperf-y += pstack.o
42libperf-y += session.o 43libperf-y += session.o
43libperf-$(CONFIG_AUDIT) += syscalltbl.o 44libperf-$(CONFIG_AUDIT) += syscalltbl.o
44libperf-y += ordered-events.o 45libperf-y += ordered-events.o
46libperf-y += namespaces.o
45libperf-y += comm.o 47libperf-y += comm.o
46libperf-y += thread.o 48libperf-y += thread.o
47libperf-y += thread_map.o 49libperf-y += thread_map.o
@@ -81,13 +83,16 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
81libperf-$(CONFIG_AUXTRACE) += intel-pt.o 83libperf-$(CONFIG_AUXTRACE) += intel-pt.o
82libperf-$(CONFIG_AUXTRACE) += intel-bts.o 84libperf-$(CONFIG_AUXTRACE) += intel-bts.o
83libperf-y += parse-branch-options.o 85libperf-y += parse-branch-options.o
86libperf-y += dump-insn.o
84libperf-y += parse-regs-options.o 87libperf-y += parse-regs-options.o
85libperf-y += term.o 88libperf-y += term.o
86libperf-y += help-unknown-cmd.o 89libperf-y += help-unknown-cmd.o
87libperf-y += mem-events.o 90libperf-y += mem-events.o
88libperf-y += vsprintf.o 91libperf-y += vsprintf.o
89libperf-y += drv_configs.o 92libperf-y += drv_configs.o
93libperf-y += units.o
90libperf-y += time-utils.o 94libperf-y += time-utils.o
95libperf-y += expr-bison.o
91 96
92libperf-$(CONFIG_LIBBPF) += bpf-loader.o 97libperf-$(CONFIG_LIBBPF) += bpf-loader.o
93libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o 98libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
@@ -140,6 +145,10 @@ $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
140 $(call rule_mkdir) 145 $(call rule_mkdir)
141 $(Q)$(call echo-cmd,bison)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $@ -p parse_events_ 146 $(Q)$(call echo-cmd,bison)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $@ -p parse_events_
142 147
148$(OUTPUT)util/expr-bison.c: util/expr.y
149 $(call rule_mkdir)
150 $(Q)$(call echo-cmd,bison)$(BISON) -v util/expr.y -d $(PARSER_DEBUG_BISON) -o $@ -p expr__
151
143$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c 152$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
144 $(call rule_mkdir) 153 $(call rule_mkdir)
145 $(Q)$(call echo-cmd,flex)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l 154 $(Q)$(call echo-cmd,flex)$(FLEX) -o $@ --header-file=$(OUTPUT)util/pmu-flex.h util/pmu.l
@@ -152,6 +161,7 @@ CFLAGS_parse-events-flex.o += -w
152CFLAGS_pmu-flex.o += -w 161CFLAGS_pmu-flex.o += -w
153CFLAGS_parse-events-bison.o += -DYYENABLE_NLS=0 -w 162CFLAGS_parse-events-bison.o += -DYYENABLE_NLS=0 -w
154CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w 163CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
164CFLAGS_expr-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
155 165
156$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c 166$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
157$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c 167$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
deleted file mode 100644
index 6455471d9cd1..000000000000
--- a/tools/perf/util/alias.c
+++ /dev/null
@@ -1,78 +0,0 @@
1#include "cache.h"
2#include "util.h"
3#include "config.h"
4
5static const char *alias_key;
6static char *alias_val;
7
8static int alias_lookup_cb(const char *k, const char *v,
9 void *cb __maybe_unused)
10{
11 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
12 if (!v)
13 return config_error_nonbool(k);
14 alias_val = strdup(v);
15 return 0;
16 }
17 return 0;
18}
19
20char *alias_lookup(const char *alias)
21{
22 alias_key = alias;
23 alias_val = NULL;
24 perf_config(alias_lookup_cb, NULL);
25 return alias_val;
26}
27
28int split_cmdline(char *cmdline, const char ***argv)
29{
30 int src, dst, count = 0, size = 16;
31 char quoted = 0;
32
33 *argv = malloc(sizeof(char*) * size);
34
35 /* split alias_string */
36 (*argv)[count++] = cmdline;
37 for (src = dst = 0; cmdline[src];) {
38 char c = cmdline[src];
39 if (!quoted && isspace(c)) {
40 cmdline[dst++] = 0;
41 while (cmdline[++src]
42 && isspace(cmdline[src]))
43 ; /* skip */
44 if (count >= size) {
45 size += 16;
46 *argv = realloc(*argv, sizeof(char*) * size);
47 }
48 (*argv)[count++] = cmdline + dst;
49 } else if (!quoted && (c == '\'' || c == '"')) {
50 quoted = c;
51 src++;
52 } else if (c == quoted) {
53 quoted = 0;
54 src++;
55 } else {
56 if (c == '\\' && quoted != '\'') {
57 src++;
58 c = cmdline[src];
59 if (!c) {
60 zfree(argv);
61 return error("cmdline ends with \\");
62 }
63 }
64 cmdline[dst++] = c;
65 src++;
66 }
67 }
68
69 cmdline[dst] = 0;
70
71 if (quoted) {
72 zfree(argv);
73 return error("unclosed quote");
74 }
75
76 return count;
77}
78
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 273f21fa32b5..683f8340460c 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -7,6 +7,8 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9 9
10#include <errno.h>
11#include <inttypes.h>
10#include "util.h" 12#include "util.h"
11#include "ui/ui.h" 13#include "ui/ui.h"
12#include "sort.h" 14#include "sort.h"
@@ -18,12 +20,16 @@
18#include "annotate.h" 20#include "annotate.h"
19#include "evsel.h" 21#include "evsel.h"
20#include "block-range.h" 22#include "block-range.h"
23#include "string2.h"
21#include "arch/common.h" 24#include "arch/common.h"
22#include <regex.h> 25#include <regex.h>
23#include <pthread.h> 26#include <pthread.h>
24#include <linux/bitops.h> 27#include <linux/bitops.h>
28#include <linux/kernel.h>
25#include <sys/utsname.h> 29#include <sys/utsname.h>
26 30
31#include "sane_ctype.h"
32
27const char *disassembler_style; 33const char *disassembler_style;
28const char *objdump_path; 34const char *objdump_path;
29static regex_t file_lineno; 35static regex_t file_lineno;
@@ -108,6 +114,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i
108#include "arch/arm64/annotate/instructions.c" 114#include "arch/arm64/annotate/instructions.c"
109#include "arch/x86/annotate/instructions.c" 115#include "arch/x86/annotate/instructions.c"
110#include "arch/powerpc/annotate/instructions.c" 116#include "arch/powerpc/annotate/instructions.c"
117#include "arch/s390/annotate/instructions.c"
111 118
112static struct arch architectures[] = { 119static struct arch architectures[] = {
113 { 120 {
@@ -130,6 +137,13 @@ static struct arch architectures[] = {
130 .name = "powerpc", 137 .name = "powerpc",
131 .init = powerpc__annotate_init, 138 .init = powerpc__annotate_init,
132 }, 139 },
140 {
141 .name = "s390",
142 .init = s390__annotate_init,
143 .objdump = {
144 .comment_char = '#',
145 },
146 },
133}; 147};
134 148
135static void ins__delete(struct ins_operands *ops) 149static void ins__delete(struct ins_operands *ops)
@@ -379,9 +393,7 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *m
379 if (comment == NULL) 393 if (comment == NULL)
380 return 0; 394 return 0;
381 395
382 while (comment[0] != '\0' && isspace(comment[0])) 396 comment = ltrim(comment);
383 ++comment;
384
385 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); 397 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
386 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); 398 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
387 399
@@ -426,9 +438,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops
426 if (comment == NULL) 438 if (comment == NULL)
427 return 0; 439 return 0;
428 440
429 while (comment[0] != '\0' && isspace(comment[0])) 441 comment = ltrim(comment);
430 ++comment;
431
432 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); 442 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
433 443
434 return 0; 444 return 0;
@@ -777,10 +787,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, str
777 787
778static int disasm_line__parse(char *line, const char **namep, char **rawp) 788static int disasm_line__parse(char *line, const char **namep, char **rawp)
779{ 789{
780 char *name = line, tmp; 790 char tmp, *name = ltrim(line);
781
782 while (isspace(name[0]))
783 ++name;
784 791
785 if (name[0] == '\0') 792 if (name[0] == '\0')
786 return -1; 793 return -1;
@@ -798,12 +805,7 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)
798 goto out_free_name; 805 goto out_free_name;
799 806
800 (*rawp)[0] = tmp; 807 (*rawp)[0] = tmp;
801 808 *rawp = ltrim(*rawp);
802 if ((*rawp)[0] != '\0') {
803 (*rawp)++;
804 while (isspace((*rawp)[0]))
805 ++(*rawp);
806 }
807 809
808 return 0; 810 return 0;
809 811
@@ -1148,7 +1150,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1148{ 1150{
1149 struct annotation *notes = symbol__annotation(sym); 1151 struct annotation *notes = symbol__annotation(sym);
1150 struct disasm_line *dl; 1152 struct disasm_line *dl;
1151 char *line = NULL, *parsed_line, *tmp, *tmp2, *c; 1153 char *line = NULL, *parsed_line, *tmp, *tmp2;
1152 size_t line_len; 1154 size_t line_len;
1153 s64 line_ip, offset = -1; 1155 s64 line_ip, offset = -1;
1154 regmatch_t match[2]; 1156 regmatch_t match[2];
@@ -1159,32 +1161,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1159 if (!line) 1161 if (!line)
1160 return -1; 1162 return -1;
1161 1163
1162 while (line_len != 0 && isspace(line[line_len - 1]))
1163 line[--line_len] = '\0';
1164
1165 c = strchr(line, '\n');
1166 if (c)
1167 *c = 0;
1168
1169 line_ip = -1; 1164 line_ip = -1;
1170 parsed_line = line; 1165 parsed_line = rtrim(line);
1171 1166
1172 /* /filename:linenr ? Save line number and ignore. */ 1167 /* /filename:linenr ? Save line number and ignore. */
1173 if (regexec(&file_lineno, line, 2, match, 0) == 0) { 1168 if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
1174 *line_nr = atoi(line + match[1].rm_so); 1169 *line_nr = atoi(parsed_line + match[1].rm_so);
1175 return 0; 1170 return 0;
1176 } 1171 }
1177 1172
1178 /* 1173 tmp = ltrim(parsed_line);
1179 * Strip leading spaces:
1180 */
1181 tmp = line;
1182 while (*tmp) {
1183 if (*tmp != ' ')
1184 break;
1185 tmp++;
1186 }
1187
1188 if (*tmp) { 1174 if (*tmp) {
1189 /* 1175 /*
1190 * Parse hexa addresses followed by ':' 1176 * Parse hexa addresses followed by ':'
@@ -1307,6 +1293,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
1307{ 1293{
1308 char linkname[PATH_MAX]; 1294 char linkname[PATH_MAX];
1309 char *build_id_filename; 1295 char *build_id_filename;
1296 char *build_id_path = NULL;
1310 1297
1311 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && 1298 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
1312 !dso__is_kcore(dso)) 1299 !dso__is_kcore(dso))
@@ -1322,8 +1309,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
1322 goto fallback; 1309 goto fallback;
1323 } 1310 }
1324 1311
1312 build_id_path = strdup(filename);
1313 if (!build_id_path)
1314 return -1;
1315
1316 dirname(build_id_path);
1317
1325 if (dso__is_kcore(dso) || 1318 if (dso__is_kcore(dso) ||
1326 readlink(filename, linkname, sizeof(linkname)) < 0 || 1319 readlink(build_id_path, linkname, sizeof(linkname)) < 0 ||
1327 strstr(linkname, DSO__NAME_KALLSYMS) || 1320 strstr(linkname, DSO__NAME_KALLSYMS) ||
1328 access(filename, R_OK)) { 1321 access(filename, R_OK)) {
1329fallback: 1322fallback:
@@ -1335,6 +1328,7 @@ fallback:
1335 __symbol__join_symfs(filename, filename_size, dso->long_name); 1328 __symbol__join_symfs(filename, filename_size, dso->long_name);
1336 } 1329 }
1337 1330
1331 free(build_id_path);
1338 return 0; 1332 return 0;
1339} 1333}
1340 1334
@@ -1435,7 +1429,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
1435 snprintf(command, sizeof(command), 1429 snprintf(command, sizeof(command),
1436 "%s %s%s --start-address=0x%016" PRIx64 1430 "%s %s%s --start-address=0x%016" PRIx64
1437 " --stop-address=0x%016" PRIx64 1431 " --stop-address=0x%016" PRIx64
1438 " -l -d %s %s -C %s 2>/dev/null|grep -v %s|expand", 1432 " -l -d %s %s -C %s 2>/dev/null|grep -v %s:|expand",
1439 objdump_path ? objdump_path : "objdump", 1433 objdump_path ? objdump_path : "objdump",
1440 disassembler_style ? "-M " : "", 1434 disassembler_style ? "-M " : "",
1441 disassembler_style ? disassembler_style : "", 1435 disassembler_style ? disassembler_style : "",
@@ -1482,6 +1476,12 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
1482 1476
1483 nline = 0; 1477 nline = 0;
1484 while (!feof(file)) { 1478 while (!feof(file)) {
1479 /*
1480 * The source code line number (lineno) needs to be kept in
1481 * accross calls to symbol__parse_objdump_line(), so that it
1482 * can associate it with the instructions till the next one.
1483 * See disasm_line__new() and struct disasm_line::line_nr.
1484 */
1485 if (symbol__parse_objdump_line(sym, map, arch, file, privsize, 1485 if (symbol__parse_objdump_line(sym, map, arch, file, privsize,
1486 &lineno) < 0) 1486 &lineno) < 0)
1487 break; 1487 break;
@@ -1651,24 +1651,31 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
1651 start = map__rip_2objdump(map, sym->start); 1651 start = map__rip_2objdump(map, sym->start);
1652 1652
1653 for (i = 0; i < len; i++) { 1653 for (i = 0; i < len; i++) {
1654 u64 offset; 1654 u64 offset, nr_samples;
1655 double percent_max = 0.0; 1655 double percent_max = 0.0;
1656 1656
1657 src_line->nr_pcnt = nr_pcnt; 1657 src_line->nr_pcnt = nr_pcnt;
1658 1658
1659 for (k = 0; k < nr_pcnt; k++) { 1659 for (k = 0; k < nr_pcnt; k++) {
1660 double percent = 0.0;
1661
1660 h = annotation__histogram(notes, evidx + k); 1662 h = annotation__histogram(notes, evidx + k);
1661 src_line->samples[k].percent = 100.0 * h->addr[i] / h->sum; 1663 nr_samples = h->addr[i];
1664 if (h->sum)
1665 percent = 100.0 * nr_samples / h->sum;
1662 1666
1663 if (src_line->samples[k].percent > percent_max) 1667 if (percent > percent_max)
1664 percent_max = src_line->samples[k].percent; 1668 percent_max = percent;
1669 src_line->samples[k].percent = percent;
1670 src_line->samples[k].nr = nr_samples;
1665 } 1671 }
1666 1672
1667 if (percent_max <= 0.5) 1673 if (percent_max <= 0.5)
1668 goto next; 1674 goto next;
1669 1675
1670 offset = start + i; 1676 offset = start + i;
1671 src_line->path = get_srcline(map->dso, offset, NULL, false); 1677 src_line->path = get_srcline(map->dso, offset, NULL,
1678 false, true);
1672 insert_source_line(&tmp_root, src_line); 1679 insert_source_line(&tmp_root, src_line);
1673 1680
1674 next: 1681 next:
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 09776b5af991..948aa8e6fd39 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -98,7 +98,7 @@ struct cyc_hist {
98struct source_line_samples { 98struct source_line_samples {
99 double percent; 99 double percent;
100 double percent_sum; 100 double percent_sum;
101 double nr; 101 u64 nr;
102}; 102};
103 103
104struct source_line { 104struct source_line {
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index c5a6e0b12452..0daf63b9ee3e 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -13,10 +13,10 @@
13 * 13 *
14 */ 14 */
15 15
16#include <inttypes.h>
16#include <sys/types.h> 17#include <sys/types.h>
17#include <sys/mman.h> 18#include <sys/mman.h>
18#include <stdbool.h> 19#include <stdbool.h>
19#include <ctype.h>
20#include <string.h> 20#include <string.h>
21#include <limits.h> 21#include <limits.h>
22#include <errno.h> 22#include <errno.h>
@@ -46,7 +46,6 @@
46#include "cpumap.h" 46#include "cpumap.h"
47#include "thread_map.h" 47#include "thread_map.h"
48#include "asm/bug.h" 48#include "asm/bug.h"
49#include "symbol/kallsyms.h"
50#include "auxtrace.h" 49#include "auxtrace.h"
51 50
52#include <linux/hash.h> 51#include <linux/hash.h>
@@ -59,6 +58,9 @@
59#include "intel-pt.h" 58#include "intel-pt.h"
60#include "intel-bts.h" 59#include "intel-bts.h"
61 60
61#include "sane_ctype.h"
62#include "symbol/kallsyms.h"
63
62int auxtrace_mmap__mmap(struct auxtrace_mmap *mm, 64int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
63 struct auxtrace_mmap_params *mp, 65 struct auxtrace_mmap_params *mp,
64 void *userpg, int fd) 66 void *userpg, int fd)
@@ -1826,7 +1828,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt)
1826 filt->addr = start; 1828 filt->addr = start;
1827 if (filt->range && !filt->size && !filt->sym_to) { 1829 if (filt->range && !filt->size && !filt->sym_to) {
1828 filt->size = size; 1830 filt->size = size;
1829 no_size = !!size; 1831 no_size = !size;
1830 } 1832 }
1831 } 1833 }
1832 1834
@@ -1840,7 +1842,7 @@ static int addr_filter__resolve_kernel_syms(struct addr_filter *filt)
1840 if (err) 1842 if (err)
1841 return err; 1843 return err;
1842 filt->size = start + size - filt->addr; 1844 filt->size = start + size - filt->addr;
1843 no_size = !!size; 1845 no_size = !size;
1844 } 1846 }
1845 1847
1846 /* The very last symbol in kallsyms does not imply a particular size */ 1848 /* The very last symbol in kallsyms does not imply a particular size */
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index 26fb1ee5746a..9f0de72d58e2 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -17,6 +17,7 @@
17#define __PERF_AUXTRACE_H 17#define __PERF_AUXTRACE_H
18 18
19#include <sys/types.h> 19#include <sys/types.h>
20#include <errno.h>
20#include <stdbool.h> 21#include <stdbool.h>
21#include <stddef.h> 22#include <stddef.h>
22#include <linux/list.h> 23#include <linux/list.h>
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index bc6bc7062eb4..4bd2d1d882af 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -9,7 +9,9 @@
9#include <bpf/libbpf.h> 9#include <bpf/libbpf.h>
10#include <bpf/bpf.h> 10#include <bpf/bpf.h>
11#include <linux/err.h> 11#include <linux/err.h>
12#include <linux/kernel.h>
12#include <linux/string.h> 13#include <linux/string.h>
14#include <errno.h>
13#include "perf.h" 15#include "perf.h"
14#include "debug.h" 16#include "debug.h"
15#include "bpf-loader.h" 17#include "bpf-loader.h"
@@ -17,6 +19,7 @@
17#include "probe-event.h" 19#include "probe-event.h"
18#include "probe-finder.h" // for MAX_PROBES 20#include "probe-finder.h" // for MAX_PROBES
19#include "parse-events.h" 21#include "parse-events.h"
22#include "strfilter.h"
20#include "llvm-utils.h" 23#include "llvm-utils.h"
21#include "c++/clang-c.h" 24#include "c++/clang-c.h"
22 25
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index f2b737b225f2..48863867878b 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -85,6 +85,8 @@ int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err,
85 char *buf, size_t size); 85 char *buf, size_t size);
86 86
87#else 87#else
88#include <errno.h>
89
88static inline struct bpf_object * 90static inline struct bpf_object *
89bpf__prepare_load(const char *filename __maybe_unused, 91bpf__prepare_load(const char *filename __maybe_unused,
90 bool source __maybe_unused) 92 bool source __maybe_unused)
diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c
index 6cdbee119ceb..1356220a9f1b 100644
--- a/tools/perf/util/bpf-prologue.c
+++ b/tools/perf/util/bpf-prologue.c
@@ -12,6 +12,7 @@
12#include "bpf-loader.h" 12#include "bpf-loader.h"
13#include "bpf-prologue.h" 13#include "bpf-prologue.h"
14#include "probe-finder.h" 14#include "probe-finder.h"
15#include <errno.h>
15#include <dwarf-regs.h> 16#include <dwarf-regs.h>
16#include <linux/filter.h> 17#include <linux/filter.h>
17 18
diff --git a/tools/perf/util/bpf-prologue.h b/tools/perf/util/bpf-prologue.h
index d94cbea12899..ba564838375f 100644
--- a/tools/perf/util/bpf-prologue.h
+++ b/tools/perf/util/bpf-prologue.h
@@ -18,6 +18,8 @@ int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
18 struct bpf_insn *new_prog, size_t *new_cnt, 18 struct bpf_insn *new_prog, size_t *new_cnt,
19 size_t cnt_space); 19 size_t cnt_space);
20#else 20#else
21#include <errno.h>
22
21static inline int 23static inline int
22bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused, 24bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused,
23 int nargs __maybe_unused, 25 int nargs __maybe_unused,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index e528c40739cc..168cc49654e7 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -7,18 +7,26 @@
7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com> 7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include <dirent.h>
11#include <errno.h>
10#include <stdio.h> 12#include <stdio.h>
13#include <sys/stat.h>
14#include <sys/types.h>
11#include "build-id.h" 15#include "build-id.h"
12#include "event.h" 16#include "event.h"
13#include "symbol.h" 17#include "symbol.h"
18#include "thread.h"
14#include <linux/kernel.h> 19#include <linux/kernel.h>
15#include "debug.h" 20#include "debug.h"
16#include "session.h" 21#include "session.h"
17#include "tool.h" 22#include "tool.h"
18#include "header.h" 23#include "header.h"
19#include "vdso.h" 24#include "vdso.h"
25#include "path.h"
20#include "probe-file.h" 26#include "probe-file.h"
27#include "strlist.h"
21 28
29#include "sane_ctype.h"
22 30
23static bool no_buildid_cache; 31static bool no_buildid_cache;
24 32
@@ -182,13 +190,17 @@ char *build_id_cache__origname(const char *sbuild_id)
182 char buf[PATH_MAX]; 190 char buf[PATH_MAX];
183 char *ret = NULL, *p; 191 char *ret = NULL, *p;
184 size_t offs = 5; /* == strlen("../..") */ 192 size_t offs = 5; /* == strlen("../..") */
193 ssize_t len;
185 194
186 linkname = build_id_cache__linkname(sbuild_id, NULL, 0); 195 linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
187 if (!linkname) 196 if (!linkname)
188 return NULL; 197 return NULL;
189 198
190 if (readlink(linkname, buf, PATH_MAX) < 0) 199 len = readlink(linkname, buf, sizeof(buf) - 1);
200 if (len <= 0)
191 goto out; 201 goto out;
202 buf[len] = '\0';
203
192 /* The link should be "../..<origpath>/<sbuild_id>" */ 204 /* The link should be "../..<origpath>/<sbuild_id>" */
193 p = strrchr(buf, '/'); /* Cut off the "/<sbuild_id>" */ 205 p = strrchr(buf, '/'); /* Cut off the "/<sbuild_id>" */
194 if (p && (p > buf + offs)) { 206 if (p && (p > buf + offs)) {
@@ -443,14 +455,14 @@ void disable_buildid_cache(void)
443} 455}
444 456
445static bool lsdir_bid_head_filter(const char *name __maybe_unused, 457static bool lsdir_bid_head_filter(const char *name __maybe_unused,
446 struct dirent *d __maybe_unused) 458 struct dirent *d)
447{ 459{
448 return (strlen(d->d_name) == 2) && 460 return (strlen(d->d_name) == 2) &&
449 isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]); 461 isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
450} 462}
451 463
452static bool lsdir_bid_tail_filter(const char *name __maybe_unused, 464static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
453 struct dirent *d __maybe_unused) 465 struct dirent *d)
454{ 466{
455 int i = 0; 467 int i = 0;
456 while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3) 468 while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
@@ -690,7 +702,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
690 err = 0; 702 err = 0;
691 703
692 /* Update SDT cache : error is just warned */ 704 /* Update SDT cache : error is just warned */
693 if (build_id_cache__add_sdt_cache(sbuild_id, realname) < 0) 705 if (realname && build_id_cache__add_sdt_cache(sbuild_id, realname) < 0)
694 pr_debug4("Failed to update/scan SDT cache for %s\n", realname); 706 pr_debug4("Failed to update/scan SDT cache for %s\n", realname);
695 707
696out_free: 708out_free:
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index d27990610f9f..8a89b195c1fc 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -5,7 +5,6 @@
5#define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1) 5#define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1)
6 6
7#include "tool.h" 7#include "tool.h"
8#include "strlist.h"
9#include <linux/types.h> 8#include <linux/types.h>
10 9
11extern struct perf_tool build_id__mark_dso_hit_ops; 10extern struct perf_tool build_id__mark_dso_hit_ops;
@@ -34,6 +33,9 @@ char *build_id_cache__origname(const char *sbuild_id);
34char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); 33char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
35char *build_id_cache__cachedir(const char *sbuild_id, const char *name, 34char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
36 bool is_kallsyms, bool is_vdso); 35 bool is_kallsyms, bool is_vdso);
36
37struct strlist;
38
37struct strlist *build_id_cache__list_all(bool validonly); 39struct strlist *build_id_cache__list_all(bool validonly);
38char *build_id_cache__complement(const char *incomplete_sbuild_id); 40char *build_id_cache__complement(const char *incomplete_sbuild_id);
39int build_id_cache__list_build_ids(const char *pathname, 41int build_id_cache__list_build_ids(const char *pathname,
@@ -42,6 +44,10 @@ bool build_id_cache__cached(const char *sbuild_id);
42int build_id_cache__add_s(const char *sbuild_id, 44int build_id_cache__add_s(const char *sbuild_id,
43 const char *name, bool is_kallsyms, bool is_vdso); 45 const char *name, bool is_kallsyms, bool is_vdso);
44int build_id_cache__remove_s(const char *sbuild_id); 46int build_id_cache__remove_s(const char *sbuild_id);
47
48extern char buildid_dir[];
49
50void set_buildid_dir(const char *dir);
45void disable_buildid_cache(void); 51void disable_buildid_cache(void);
46 52
47#endif 53#endif
diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h
index 0eadd792ab1f..ccafcf72b37a 100644
--- a/tools/perf/util/c++/clang-c.h
+++ b/tools/perf/util/c++/clang-c.h
@@ -20,6 +20,7 @@ extern int perf_clang__compile_bpf(const char *filename,
20 size_t *p_obj_buf_sz); 20 size_t *p_obj_buf_sz);
21#else 21#else
22 22
23#include <errno.h>
23 24
24static inline void perf_clang__init(void) { } 25static inline void perf_clang__init(void) { }
25static inline void perf_clang__cleanup(void) { } 26static inline void perf_clang__cleanup(void) { }
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 512c0c83fbc6..0328f297a748 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -15,7 +15,6 @@
15#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" 15#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
16#define PERF_PAGER_ENVIRONMENT "PERF_PAGER" 16#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
17 17
18char *alias_lookup(const char *alias);
19int split_cmdline(char *cmdline, const char ***argv); 18int split_cmdline(char *cmdline, const char ***argv);
20 19
21#define alloc_nr(x) (((x)+16)*3/2) 20#define alloc_nr(x) (((x)+16)*3/2)
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index aba953421a03..81fc29ac798f 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -9,6 +9,7 @@
9 * 9 *
10 */ 10 */
11 11
12#include <inttypes.h>
12#include <stdlib.h> 13#include <stdlib.h>
13#include <stdio.h> 14#include <stdio.h>
14#include <stdbool.h> 15#include <stdbool.h>
@@ -23,6 +24,21 @@
23#include "machine.h" 24#include "machine.h"
24#include "callchain.h" 25#include "callchain.h"
25 26
27#define CALLCHAIN_PARAM_DEFAULT \
28 .mode = CHAIN_GRAPH_ABS, \
29 .min_percent = 0.5, \
30 .order = ORDER_CALLEE, \
31 .key = CCKEY_FUNCTION, \
32 .value = CCVAL_PERCENT, \
33
34struct callchain_param callchain_param = {
35 CALLCHAIN_PARAM_DEFAULT
36};
37
38struct callchain_param callchain_param_default = {
39 CALLCHAIN_PARAM_DEFAULT
40};
41
26__thread struct callchain_cursor callchain_cursor; 42__thread struct callchain_cursor callchain_cursor;
27 43
28int parse_callchain_record_opt(const char *arg, struct callchain_param *param) 44int parse_callchain_record_opt(const char *arg, struct callchain_param *param)
@@ -80,6 +96,10 @@ static int parse_callchain_sort_key(const char *value)
80 callchain_param.key = CCKEY_ADDRESS; 96 callchain_param.key = CCKEY_ADDRESS;
81 return 0; 97 return 0;
82 } 98 }
99 if (!strncmp(value, "srcline", strlen(value))) {
100 callchain_param.key = CCKEY_SRCLINE;
101 return 0;
102 }
83 if (!strncmp(value, "branch", strlen(value))) { 103 if (!strncmp(value, "branch", strlen(value))) {
84 callchain_param.branch_callstack = 1; 104 callchain_param.branch_callstack = 1;
85 return 0; 105 return 0;
@@ -108,11 +128,37 @@ static int parse_callchain_value(const char *value)
108 return -1; 128 return -1;
109} 129}
110 130
131static int get_stack_size(const char *str, unsigned long *_size)
132{
133 char *endptr;
134 unsigned long size;
135 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
136
137 size = strtoul(str, &endptr, 0);
138
139 do {
140 if (*endptr)
141 break;
142
143 size = round_up(size, sizeof(u64));
144 if (!size || size > max_size)
145 break;
146
147 *_size = size;
148 return 0;
149
150 } while (0);
151
152 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
153 max_size, str);
154 return -1;
155}
156
111static int 157static int
112__parse_callchain_report_opt(const char *arg, bool allow_record_opt) 158__parse_callchain_report_opt(const char *arg, bool allow_record_opt)
113{ 159{
114 char *tok; 160 char *tok;
115 char *endptr; 161 char *endptr, *saveptr = NULL;
116 bool minpcnt_set = false; 162 bool minpcnt_set = false;
117 bool record_opt_set = false; 163 bool record_opt_set = false;
118 bool try_stack_size = false; 164 bool try_stack_size = false;
@@ -123,7 +169,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
123 if (!arg) 169 if (!arg)
124 return 0; 170 return 0;
125 171
126 while ((tok = strtok((char *)arg, ",")) != NULL) { 172 while ((tok = strtok_r((char *)arg, ",", &saveptr)) != NULL) {
127 if (!strncmp(tok, "none", strlen(tok))) { 173 if (!strncmp(tok, "none", strlen(tok))) {
128 callchain_param.mode = CHAIN_NONE; 174 callchain_param.mode = CHAIN_NONE;
129 callchain_param.enabled = false; 175 callchain_param.enabled = false;
@@ -191,6 +237,68 @@ int parse_callchain_top_opt(const char *arg)
191 return __parse_callchain_report_opt(arg, true); 237 return __parse_callchain_report_opt(arg, true);
192} 238}
193 239
240int parse_callchain_record(const char *arg, struct callchain_param *param)
241{
242 char *tok, *name, *saveptr = NULL;
243 char *buf;
244 int ret = -1;
245
246 /* We need buffer that we know we can write to. */
247 buf = malloc(strlen(arg) + 1);
248 if (!buf)
249 return -ENOMEM;
250
251 strcpy(buf, arg);
252
253 tok = strtok_r((char *)buf, ",", &saveptr);
254 name = tok ? : (char *)buf;
255
256 do {
257 /* Framepointer style */
258 if (!strncmp(name, "fp", sizeof("fp"))) {
259 if (!strtok_r(NULL, ",", &saveptr)) {
260 param->record_mode = CALLCHAIN_FP;
261 ret = 0;
262 } else
263 pr_err("callchain: No more arguments "
264 "needed for --call-graph fp\n");
265 break;
266
267 /* Dwarf style */
268 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
269 const unsigned long default_stack_dump_size = 8192;
270
271 ret = 0;
272 param->record_mode = CALLCHAIN_DWARF;
273 param->dump_size = default_stack_dump_size;
274
275 tok = strtok_r(NULL, ",", &saveptr);
276 if (tok) {
277 unsigned long size = 0;
278
279 ret = get_stack_size(tok, &size);
280 param->dump_size = size;
281 }
282 } else if (!strncmp(name, "lbr", sizeof("lbr"))) {
283 if (!strtok_r(NULL, ",", &saveptr)) {
284 param->record_mode = CALLCHAIN_LBR;
285 ret = 0;
286 } else
287 pr_err("callchain: No more arguments "
288 "needed for --call-graph lbr\n");
289 break;
290 } else {
291 pr_err("callchain: Unknown --call-graph option "
292 "value: %s\n", arg);
293 break;
294 }
295
296 } while (0);
297
298 free(buf);
299 return ret;
300}
301
194int perf_callchain_config(const char *var, const char *value) 302int perf_callchain_config(const char *var, const char *value)
195{ 303{
196 char *endptr; 304 char *endptr;
@@ -510,14 +618,51 @@ enum match_result {
510 MATCH_GT, 618 MATCH_GT,
511}; 619};
512 620
621static enum match_result match_chain_srcline(struct callchain_cursor_node *node,
622 struct callchain_list *cnode)
623{
624 char *left = get_srcline(cnode->ms.map->dso,
625 map__rip_2objdump(cnode->ms.map, cnode->ip),
626 cnode->ms.sym, true, false);
627 char *right = get_srcline(node->map->dso,
628 map__rip_2objdump(node->map, node->ip),
629 node->sym, true, false);
630 enum match_result ret = MATCH_EQ;
631 int cmp;
632
633 if (left && right)
634 cmp = strcmp(left, right);
635 else if (!left && right)
636 cmp = 1;
637 else if (left && !right)
638 cmp = -1;
639 else if (cnode->ip == node->ip)
640 cmp = 0;
641 else
642 cmp = (cnode->ip < node->ip) ? -1 : 1;
643
644 if (cmp != 0)
645 ret = cmp < 0 ? MATCH_LT : MATCH_GT;
646
647 free_srcline(left);
648 free_srcline(right);
649 return ret;
650}
651
513static enum match_result match_chain(struct callchain_cursor_node *node, 652static enum match_result match_chain(struct callchain_cursor_node *node,
514 struct callchain_list *cnode) 653 struct callchain_list *cnode)
515{ 654{
516 struct symbol *sym = node->sym; 655 struct symbol *sym = node->sym;
517 u64 left, right; 656 u64 left, right;
518 657
519 if (cnode->ms.sym && sym && 658 if (callchain_param.key == CCKEY_SRCLINE) {
520 callchain_param.key == CCKEY_FUNCTION) { 659 enum match_result match = match_chain_srcline(node, cnode);
660
661 if (match != MATCH_ERROR)
662 return match;
663 }
664
665 if (cnode->ms.sym && sym && callchain_param.key == CCKEY_FUNCTION) {
521 left = cnode->ms.sym->start; 666 left = cnode->ms.sym->start;
522 right = sym->start; 667 right = sym->start;
523 } else { 668 } else {
@@ -911,15 +1056,16 @@ out:
911char *callchain_list__sym_name(struct callchain_list *cl, 1056char *callchain_list__sym_name(struct callchain_list *cl,
912 char *bf, size_t bfsize, bool show_dso) 1057 char *bf, size_t bfsize, bool show_dso)
913{ 1058{
1059 bool show_addr = callchain_param.key == CCKEY_ADDRESS;
1060 bool show_srcline = show_addr || callchain_param.key == CCKEY_SRCLINE;
914 int printed; 1061 int printed;
915 1062
916 if (cl->ms.sym) { 1063 if (cl->ms.sym) {
917 if (callchain_param.key == CCKEY_ADDRESS && 1064 if (show_srcline && cl->ms.map && !cl->srcline)
918 cl->ms.map && !cl->srcline)
919 cl->srcline = get_srcline(cl->ms.map->dso, 1065 cl->srcline = get_srcline(cl->ms.map->dso,
920 map__rip_2objdump(cl->ms.map, 1066 map__rip_2objdump(cl->ms.map,
921 cl->ip), 1067 cl->ip),
922 cl->ms.sym, false); 1068 cl->ms.sym, false, show_addr);
923 if (cl->srcline) 1069 if (cl->srcline)
924 printed = scnprintf(bf, bfsize, "%s %s", 1070 printed = scnprintf(bf, bfsize, "%s %s",
925 cl->ms.sym->name, cl->srcline); 1071 cl->ms.sym->name, cl->srcline);
@@ -1063,63 +1209,100 @@ int callchain_branch_counts(struct callchain_root *root,
1063 cycles_count); 1209 cycles_count);
1064} 1210}
1065 1211
1066static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, 1212static int counts_str_build(char *bf, int bfsize,
1067 u64 branch_count, u64 predicted_count, 1213 u64 branch_count, u64 predicted_count,
1068 u64 abort_count, u64 cycles_count, 1214 u64 abort_count, u64 cycles_count,
1069 u64 iter_count, u64 samples_count) 1215 u64 iter_count, u64 samples_count)
1070{ 1216{
1071 double predicted_percent = 0.0; 1217 double predicted_percent = 0.0;
1072 const char *null_str = ""; 1218 const char *null_str = "";
1073 char iter_str[32]; 1219 char iter_str[32];
1074 char *str; 1220 char cycle_str[32];
1075 u64 cycles = 0; 1221 char *istr, *cstr;
1076 1222 u64 cycles;
1077 if (branch_count == 0) {
1078 if (fp)
1079 return fprintf(fp, " (calltrace)");
1080 1223
1224 if (branch_count == 0)
1081 return scnprintf(bf, bfsize, " (calltrace)"); 1225 return scnprintf(bf, bfsize, " (calltrace)");
1082 } 1226
1227 cycles = cycles_count / branch_count;
1083 1228
1084 if (iter_count && samples_count) { 1229 if (iter_count && samples_count) {
1085 scnprintf(iter_str, sizeof(iter_str), 1230 if (cycles > 0)
1086 ", iterations:%" PRId64 "", 1231 scnprintf(iter_str, sizeof(iter_str),
1087 iter_count / samples_count); 1232 " iterations:%" PRId64 "",
1088 str = iter_str; 1233 iter_count / samples_count);
1234 else
1235 scnprintf(iter_str, sizeof(iter_str),
1236 "iterations:%" PRId64 "",
1237 iter_count / samples_count);
1238 istr = iter_str;
1239 } else
1240 istr = (char *)null_str;
1241
1242 if (cycles > 0) {
1243 scnprintf(cycle_str, sizeof(cycle_str),
1244 "cycles:%" PRId64 "", cycles);
1245 cstr = cycle_str;
1089 } else 1246 } else
1090 str = (char *)null_str; 1247 cstr = (char *)null_str;
1091 1248
1092 predicted_percent = predicted_count * 100.0 / branch_count; 1249 predicted_percent = predicted_count * 100.0 / branch_count;
1093 cycles = cycles_count / branch_count;
1094 1250
1095 if ((predicted_percent >= 100.0) && (abort_count == 0)) { 1251 if ((predicted_count == branch_count) && (abort_count == 0)) {
1096 if (fp) 1252 if ((cycles > 0) || (istr != (char *)null_str))
1097 return fprintf(fp, " (cycles:%" PRId64 "%s)", 1253 return scnprintf(bf, bfsize, " (%s%s)", cstr, istr);
1098 cycles, str); 1254 else
1255 return scnprintf(bf, bfsize, "%s", (char *)null_str);
1256 }
1099 1257
1100 return scnprintf(bf, bfsize, " (cycles:%" PRId64 "%s)", 1258 if ((predicted_count < branch_count) && (abort_count == 0)) {
1101 cycles, str); 1259 if ((cycles > 0) || (istr != (char *)null_str))
1260 return scnprintf(bf, bfsize,
1261 " (predicted:%.1f%% %s%s)",
1262 predicted_percent, cstr, istr);
1263 else {
1264 return scnprintf(bf, bfsize,
1265 " (predicted:%.1f%%)",
1266 predicted_percent);
1267 }
1102 } 1268 }
1103 1269
1104 if ((predicted_percent < 100.0) && (abort_count == 0)) { 1270 if ((predicted_count == branch_count) && (abort_count > 0)) {
1105 if (fp) 1271 if ((cycles > 0) || (istr != (char *)null_str))
1106 return fprintf(fp, 1272 return scnprintf(bf, bfsize,
1107 " (predicted:%.1f%%, cycles:%" PRId64 "%s)", 1273 " (abort:%" PRId64 " %s%s)",
1108 predicted_percent, cycles, str); 1274 abort_count, cstr, istr);
1275 else
1276 return scnprintf(bf, bfsize,
1277 " (abort:%" PRId64 ")",
1278 abort_count);
1279 }
1109 1280
1281 if ((cycles > 0) || (istr != (char *)null_str))
1110 return scnprintf(bf, bfsize, 1282 return scnprintf(bf, bfsize,
1111 " (predicted:%.1f%%, cycles:%" PRId64 "%s)", 1283 " (predicted:%.1f%% abort:%" PRId64 " %s%s)",
1112 predicted_percent, cycles, str); 1284 predicted_percent, abort_count, cstr, istr);
1113 } 1285
1286 return scnprintf(bf, bfsize,
1287 " (predicted:%.1f%% abort:%" PRId64 ")",
1288 predicted_percent, abort_count);
1289}
1290
1291static int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
1292 u64 branch_count, u64 predicted_count,
1293 u64 abort_count, u64 cycles_count,
1294 u64 iter_count, u64 samples_count)
1295{
1296 char str[128];
1297
1298 counts_str_build(str, sizeof(str), branch_count,
1299 predicted_count, abort_count, cycles_count,
1300 iter_count, samples_count);
1114 1301
1115 if (fp) 1302 if (fp)
1116 return fprintf(fp, 1303 return fprintf(fp, "%s", str);
1117 " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
1118 predicted_percent, abort_count, cycles, str);
1119 1304
1120 return scnprintf(bf, bfsize, 1305 return scnprintf(bf, bfsize, "%s", str);
1121 " (predicted:%.1f%%, abort:%" PRId64 ", cycles:%" PRId64 "%s)",
1122 predicted_percent, abort_count, cycles, str);
1123} 1306}
1124 1307
1125int callchain_list_counts__printf_value(struct callchain_node *node, 1308int callchain_list_counts__printf_value(struct callchain_node *node,
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 4f4b60f1558a..c56c23dbbf72 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -77,7 +77,8 @@ typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
77 77
78enum chain_key { 78enum chain_key {
79 CCKEY_FUNCTION, 79 CCKEY_FUNCTION,
80 CCKEY_ADDRESS 80 CCKEY_ADDRESS,
81 CCKEY_SRCLINE
81}; 82};
82 83
83enum chain_value { 84enum chain_value {
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index eafbf11442b2..03347748f3fa 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -4,6 +4,7 @@
4#include "evsel.h" 4#include "evsel.h"
5#include "cgroup.h" 5#include "cgroup.h"
6#include "evlist.h" 6#include "evlist.h"
7#include <linux/stringify.h>
7 8
8int nr_cgroups; 9int nr_cgroups;
9 10
@@ -27,8 +28,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
27 path_v1[0] = '\0'; 28 path_v1[0] = '\0';
28 path_v2[0] = '\0'; 29 path_v2[0] = '\0';
29 30
30 while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %" 31 while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
31 STR(PATH_MAX)"s %*d %*d\n", 32 __stringify(PATH_MAX)"s %*d %*d\n",
32 mountpoint, type, tokens) == 3) { 33 mountpoint, type, tokens) == 3) {
33 34
34 if (!path_v1[0] && !strcmp(type, "cgroup")) { 35 if (!path_v1[0] && !strcmp(type, "cgroup")) {
@@ -127,19 +128,19 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
127 goto found; 128 goto found;
128 n++; 129 n++;
129 } 130 }
130 if (atomic_read(&cgrp->refcnt) == 0) 131 if (refcount_read(&cgrp->refcnt) == 0)
131 free(cgrp); 132 free(cgrp);
132 133
133 return -1; 134 return -1;
134found: 135found:
135 atomic_inc(&cgrp->refcnt); 136 refcount_inc(&cgrp->refcnt);
136 counter->cgrp = cgrp; 137 counter->cgrp = cgrp;
137 return 0; 138 return 0;
138} 139}
139 140
140void close_cgroup(struct cgroup_sel *cgrp) 141void close_cgroup(struct cgroup_sel *cgrp)
141{ 142{
142 if (cgrp && atomic_dec_and_test(&cgrp->refcnt)) { 143 if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
143 close(cgrp->fd); 144 close(cgrp->fd);
144 zfree(&cgrp->name); 145 zfree(&cgrp->name);
145 free(cgrp); 146 free(cgrp);
diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h
index 31f8dcdbd7ef..d91966b97cbd 100644
--- a/tools/perf/util/cgroup.h
+++ b/tools/perf/util/cgroup.h
@@ -1,14 +1,14 @@
1#ifndef __CGROUP_H__ 1#ifndef __CGROUP_H__
2#define __CGROUP_H__ 2#define __CGROUP_H__
3 3
4#include <linux/atomic.h> 4#include <linux/refcount.h>
5 5
6struct option; 6struct option;
7 7
8struct cgroup_sel { 8struct cgroup_sel {
9 char *name; 9 char *name;
10 int fd; 10 int fd;
11 atomic_t refcnt; 11 refcount_t refcnt;
12}; 12};
13 13
14 14
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
index f0dcd0ee0afa..4b4f00df58a8 100644
--- a/tools/perf/util/cloexec.c
+++ b/tools/perf/util/cloexec.c
@@ -1,3 +1,4 @@
1#include <errno.h>
1#include <sched.h> 2#include <sched.h>
2#include "util.h" 3#include "util.h"
3#include "../perf.h" 4#include "../perf.h"
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
index d0d465953d36..94a5a7d829d5 100644
--- a/tools/perf/util/cloexec.h
+++ b/tools/perf/util/cloexec.h
@@ -3,10 +3,4 @@
3 3
4unsigned long perf_event_open_cloexec_flag(void); 4unsigned long perf_event_open_cloexec_flag(void);
5 5
6#ifdef __GLIBC_PREREQ
7#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__)
8int sched_getcpu(void) __THROW;
9#endif
10#endif
11
12#endif /* __PERF_CLOEXEC_H */ 6#endif /* __PERF_CLOEXEC_H */
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index a93997f16dec..52122bcc3170 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -1,6 +1,8 @@
1#ifndef __PERF_COLOR_H 1#ifndef __PERF_COLOR_H
2#define __PERF_COLOR_H 2#define __PERF_COLOR_H
3 3
4#include <stdio.h>
5
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ 6/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24 7#define COLOR_MAXLEN 24
6 8
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index 21b7ff382c3f..7bc981b6bf29 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -1,13 +1,15 @@
1#include "comm.h" 1#include "comm.h"
2#include "util.h" 2#include "util.h"
3#include <errno.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <stdio.h> 5#include <stdio.h>
5#include <linux/atomic.h> 6#include <string.h>
7#include <linux/refcount.h>
6 8
7struct comm_str { 9struct comm_str {
8 char *str; 10 char *str;
9 struct rb_node rb_node; 11 struct rb_node rb_node;
10 atomic_t refcnt; 12 refcount_t refcnt;
11}; 13};
12 14
13/* Should perhaps be moved to struct machine */ 15/* Should perhaps be moved to struct machine */
@@ -16,13 +18,13 @@ static struct rb_root comm_str_root;
16static struct comm_str *comm_str__get(struct comm_str *cs) 18static struct comm_str *comm_str__get(struct comm_str *cs)
17{ 19{
18 if (cs) 20 if (cs)
19 atomic_inc(&cs->refcnt); 21 refcount_inc(&cs->refcnt);
20 return cs; 22 return cs;
21} 23}
22 24
23static void comm_str__put(struct comm_str *cs) 25static void comm_str__put(struct comm_str *cs)
24{ 26{
25 if (cs && atomic_dec_and_test(&cs->refcnt)) { 27 if (cs && refcount_dec_and_test(&cs->refcnt)) {
26 rb_erase(&cs->rb_node, &comm_str_root); 28 rb_erase(&cs->rb_node, &comm_str_root);
27 zfree(&cs->str); 29 zfree(&cs->str);
28 free(cs); 30 free(cs);
@@ -43,7 +45,7 @@ static struct comm_str *comm_str__alloc(const char *str)
43 return NULL; 45 return NULL;
44 } 46 }
45 47
46 atomic_set(&cs->refcnt, 0); 48 refcount_set(&cs->refcnt, 1);
47 49
48 return cs; 50 return cs;
49} 51}
@@ -61,7 +63,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
61 63
62 cmp = strcmp(str, iter->str); 64 cmp = strcmp(str, iter->str);
63 if (!cmp) 65 if (!cmp)
64 return iter; 66 return comm_str__get(iter);
65 67
66 if (cmp < 0) 68 if (cmp < 0)
67 p = &(*p)->rb_left; 69 p = &(*p)->rb_left;
@@ -95,8 +97,6 @@ struct comm *comm__new(const char *str, u64 timestamp, bool exec)
95 return NULL; 97 return NULL;
96 } 98 }
97 99
98 comm_str__get(comm->comm_str);
99
100 return comm; 100 return comm;
101} 101}
102 102
@@ -108,7 +108,6 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec)
108 if (!new) 108 if (!new)
109 return -ENOMEM; 109 return -ENOMEM;
110 110
111 comm_str__get(new);
112 comm_str__put(old); 111 comm_str__put(old);
113 comm->comm_str = new; 112 comm->comm_str = new;
114 comm->start = timestamp; 113 comm->start = timestamp;
diff --git a/tools/perf/util/compress.h b/tools/perf/util/compress.h
new file mode 100644
index 000000000000..67fd1bb7c2b7
--- /dev/null
+++ b/tools/perf/util/compress.h
@@ -0,0 +1,12 @@
1#ifndef PERF_COMPRESS_H
2#define PERF_COMPRESS_H
3
4#ifdef HAVE_ZLIB_SUPPORT
5int gzip_decompress_to_file(const char *input, int output_fd);
6#endif
7
8#ifdef HAVE_LZMA_SUPPORT
9int lzma_decompress_to_file(const char *input, int output_fd);
10#endif
11
12#endif /* PERF_COMPRESS_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 0c7d5a4975cd..8d724f0fa5a8 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -8,12 +8,19 @@
8 * Copyright (C) Johannes Schindelin, 2005 8 * Copyright (C) Johannes Schindelin, 2005
9 * 9 *
10 */ 10 */
11#include <errno.h>
12#include <sys/param.h>
11#include "util.h" 13#include "util.h"
12#include "cache.h" 14#include "cache.h"
13#include <subcmd/exec-cmd.h> 15#include <subcmd/exec-cmd.h>
14#include "util/hist.h" /* perf_hist_config */ 16#include "util/hist.h" /* perf_hist_config */
15#include "util/llvm-utils.h" /* perf_llvm_config */ 17#include "util/llvm-utils.h" /* perf_llvm_config */
16#include "config.h" 18#include "config.h"
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <unistd.h>
22
23#include "sane_ctype.h"
17 24
18#define MAXNAME (256) 25#define MAXNAME (256)
19 26
@@ -627,6 +634,8 @@ static int perf_config_set__init(struct perf_config_set *set)
627{ 634{
628 int ret = -1; 635 int ret = -1;
629 const char *home = NULL; 636 const char *home = NULL;
637 char *user_config;
638 struct stat st;
630 639
631 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 640 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
632 if (config_exclusive_filename) 641 if (config_exclusive_filename)
@@ -637,35 +646,41 @@ static int perf_config_set__init(struct perf_config_set *set)
637 } 646 }
638 647
639 home = getenv("HOME"); 648 home = getenv("HOME");
640 if (perf_config_global() && home) {
641 char *user_config = strdup(mkpath("%s/.perfconfig", home));
642 struct stat st;
643 649
644 if (user_config == NULL) { 650 /*
645 warning("Not enough memory to process %s/.perfconfig, " 651 * Skip reading user config if:
646 "ignoring it.", home); 652 * - there is no place to read it from (HOME)
647 goto out; 653 * - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
648 } 654 */
655 if (!home || !*home || !perf_config_global())
656 return 0;
649 657
650 if (stat(user_config, &st) < 0) { 658 user_config = strdup(mkpath("%s/.perfconfig", home));
651 if (errno == ENOENT) 659 if (user_config == NULL) {
652 ret = 0; 660 warning("Not enough memory to process %s/.perfconfig, "
653 goto out_free; 661 "ignoring it.", home);
654 } 662 goto out;
663 }
655 664
656 ret = 0; 665 if (stat(user_config, &st) < 0) {
666 if (errno == ENOENT)
667 ret = 0;
668 goto out_free;
669 }
657 670
658 if (st.st_uid && (st.st_uid != geteuid())) { 671 ret = 0;
659 warning("File %s not owned by current user or root, "
660 "ignoring it.", user_config);
661 goto out_free;
662 }
663 672
664 if (st.st_size) 673 if (st.st_uid && (st.st_uid != geteuid())) {
665 ret = perf_config_from_file(collect_config, user_config, set); 674 warning("File %s not owned by current user or root, "
666out_free: 675 "ignoring it.", user_config);
667 free(user_config); 676 goto out_free;
668 } 677 }
678
679 if (st.st_size)
680 ret = perf_config_from_file(collect_config, user_config, set);
681
682out_free:
683 free(user_config);
669out: 684out:
670 return ret; 685 return ret;
671} 686}
diff --git a/tools/perf/util/counts.c b/tools/perf/util/counts.c
index e3fde313deb2..c4af82ab7808 100644
--- a/tools/perf/util/counts.c
+++ b/tools/perf/util/counts.c
@@ -1,6 +1,8 @@
1#include <errno.h>
1#include <stdlib.h> 2#include <stdlib.h>
2#include "evsel.h" 3#include "evsel.h"
3#include "counts.h" 4#include "counts.h"
5#include "util.h"
4 6
5struct perf_counts *perf_counts__new(int ncpus, int nthreads) 7struct perf_counts *perf_counts__new(int ncpus, int nthreads)
6{ 8{
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 8c7504939113..37b3bb79ee08 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -3,11 +3,14 @@
3#include "../perf.h" 3#include "../perf.h"
4#include "cpumap.h" 4#include "cpumap.h"
5#include <assert.h> 5#include <assert.h>
6#include <dirent.h>
6#include <stdio.h> 7#include <stdio.h>
7#include <stdlib.h> 8#include <stdlib.h>
8#include <linux/bitmap.h> 9#include <linux/bitmap.h>
9#include "asm/bug.h" 10#include "asm/bug.h"
10 11
12#include "sane_ctype.h"
13
11static int max_cpu_num; 14static int max_cpu_num;
12static int max_present_cpu_num; 15static int max_present_cpu_num;
13static int max_node_num; 16static int max_node_num;
@@ -29,7 +32,7 @@ static struct cpu_map *cpu_map__default_new(void)
29 cpus->map[i] = i; 32 cpus->map[i] = i;
30 33
31 cpus->nr = nr_cpus; 34 cpus->nr = nr_cpus;
32 atomic_set(&cpus->refcnt, 1); 35 refcount_set(&cpus->refcnt, 1);
33 } 36 }
34 37
35 return cpus; 38 return cpus;
@@ -43,7 +46,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
43 if (cpus != NULL) { 46 if (cpus != NULL) {
44 cpus->nr = nr_cpus; 47 cpus->nr = nr_cpus;
45 memcpy(cpus->map, tmp_cpus, payload_size); 48 memcpy(cpus->map, tmp_cpus, payload_size);
46 atomic_set(&cpus->refcnt, 1); 49 refcount_set(&cpus->refcnt, 1);
47 } 50 }
48 51
49 return cpus; 52 return cpus;
@@ -252,7 +255,7 @@ struct cpu_map *cpu_map__dummy_new(void)
252 if (cpus != NULL) { 255 if (cpus != NULL) {
253 cpus->nr = 1; 256 cpus->nr = 1;
254 cpus->map[0] = -1; 257 cpus->map[0] = -1;
255 atomic_set(&cpus->refcnt, 1); 258 refcount_set(&cpus->refcnt, 1);
256 } 259 }
257 260
258 return cpus; 261 return cpus;
@@ -269,7 +272,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
269 for (i = 0; i < nr; i++) 272 for (i = 0; i < nr; i++)
270 cpus->map[i] = -1; 273 cpus->map[i] = -1;
271 274
272 atomic_set(&cpus->refcnt, 1); 275 refcount_set(&cpus->refcnt, 1);
273 } 276 }
274 277
275 return cpus; 278 return cpus;
@@ -278,7 +281,7 @@ struct cpu_map *cpu_map__empty_new(int nr)
278static void cpu_map__delete(struct cpu_map *map) 281static void cpu_map__delete(struct cpu_map *map)
279{ 282{
280 if (map) { 283 if (map) {
281 WARN_ONCE(atomic_read(&map->refcnt) != 0, 284 WARN_ONCE(refcount_read(&map->refcnt) != 0,
282 "cpu_map refcnt unbalanced\n"); 285 "cpu_map refcnt unbalanced\n");
283 free(map); 286 free(map);
284 } 287 }
@@ -287,13 +290,13 @@ static void cpu_map__delete(struct cpu_map *map)
287struct cpu_map *cpu_map__get(struct cpu_map *map) 290struct cpu_map *cpu_map__get(struct cpu_map *map)
288{ 291{
289 if (map) 292 if (map)
290 atomic_inc(&map->refcnt); 293 refcount_inc(&map->refcnt);
291 return map; 294 return map;
292} 295}
293 296
294void cpu_map__put(struct cpu_map *map) 297void cpu_map__put(struct cpu_map *map)
295{ 298{
296 if (map && atomic_dec_and_test(&map->refcnt)) 299 if (map && refcount_dec_and_test(&map->refcnt))
297 cpu_map__delete(map); 300 cpu_map__delete(map);
298} 301}
299 302
@@ -357,7 +360,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
357 /* ensure we process id in increasing order */ 360 /* ensure we process id in increasing order */
358 qsort(c->map, c->nr, sizeof(int), cmp_ids); 361 qsort(c->map, c->nr, sizeof(int), cmp_ids);
359 362
360 atomic_set(&c->refcnt, 1); 363 refcount_set(&c->refcnt, 1);
361 *res = c; 364 *res = c;
362 return 0; 365 return 0;
363} 366}
@@ -673,3 +676,49 @@ size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size)
673 pr_debug("cpumask list: %s\n", buf); 676 pr_debug("cpumask list: %s\n", buf);
674 return ret; 677 return ret;
675} 678}
679
680static char hex_char(unsigned char val)
681{
682 if (val < 10)
683 return val + '0';
684 if (val < 16)
685 return val - 10 + 'a';
686 return '?';
687}
688
689size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size)
690{
691 int i, cpu;
692 char *ptr = buf;
693 unsigned char *bitmap;
694 int last_cpu = cpu_map__cpu(map, map->nr - 1);
695
696 bitmap = zalloc((last_cpu + 7) / 8);
697 if (bitmap == NULL) {
698 buf[0] = '\0';
699 return 0;
700 }
701
702 for (i = 0; i < map->nr; i++) {
703 cpu = cpu_map__cpu(map, i);
704 bitmap[cpu / 8] |= 1 << (cpu % 8);
705 }
706
707 for (cpu = last_cpu / 4 * 4; cpu >= 0; cpu -= 4) {
708 unsigned char bits = bitmap[cpu / 8];
709
710 if (cpu % 8)
711 bits >>= 4;
712 else
713 bits &= 0xf;
714
715 *ptr++ = hex_char(bits);
716 if ((cpu % 32) == 0 && cpu > 0)
717 *ptr++ = ',';
718 }
719 *ptr = '\0';
720 free(bitmap);
721
722 buf[size - 1] = '\0';
723 return ptr - buf;
724}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 1a0549af8f5c..6b8bff87481d 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -3,13 +3,13 @@
3 3
4#include <stdio.h> 4#include <stdio.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include <linux/atomic.h> 6#include <linux/refcount.h>
7 7
8#include "perf.h" 8#include "perf.h"
9#include "util/debug.h" 9#include "util/debug.h"
10 10
11struct cpu_map { 11struct cpu_map {
12 atomic_t refcnt; 12 refcount_t refcnt;
13 int nr; 13 int nr;
14 int map[]; 14 int map[];
15}; 15};
@@ -20,6 +20,7 @@ struct cpu_map *cpu_map__dummy_new(void);
20struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); 20struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
21struct cpu_map *cpu_map__read(FILE *file); 21struct cpu_map *cpu_map__read(FILE *file);
22size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size); 22size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size);
23size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size);
23size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 24size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
24int cpu_map__get_socket_id(int cpu); 25int cpu_map__get_socket_id(int cpu);
25int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); 26int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index d4a5a21c2a7e..4b261c2ec0f1 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * No surprises, and works with signed and unsigned chars. 4 * No surprises, and works with signed and unsigned chars.
5 */ 5 */
6#include "util.h" 6#include "sane_ctype.h"
7 7
8enum { 8enum {
9 S = GIT_SPACE, 9 S = GIT_SPACE,
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 4e6cbc99f08e..89d50318833d 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -7,7 +7,10 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9 9
10#include <errno.h>
11#include <inttypes.h>
10#include <linux/compiler.h> 12#include <linux/compiler.h>
13#include <linux/kernel.h>
11#include <babeltrace/ctf-writer/writer.h> 14#include <babeltrace/ctf-writer/writer.h>
12#include <babeltrace/ctf-writer/clock.h> 15#include <babeltrace/ctf-writer/clock.h>
13#include <babeltrace/ctf-writer/stream.h> 16#include <babeltrace/ctf-writer/stream.h>
@@ -27,6 +30,7 @@
27#include "evsel.h" 30#include "evsel.h"
28#include "machine.h" 31#include "machine.h"
29#include "config.h" 32#include "config.h"
33#include "sane_ctype.h"
30 34
31#define pr_N(n, fmt, ...) \ 35#define pr_N(n, fmt, ...) \
32 eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) 36 eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
@@ -1468,6 +1472,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
1468 .lost = perf_event__process_lost, 1472 .lost = perf_event__process_lost,
1469 .tracing_data = perf_event__process_tracing_data, 1473 .tracing_data = perf_event__process_tracing_data,
1470 .build_id = perf_event__process_build_id, 1474 .build_id = perf_event__process_build_id,
1475 .namespaces = perf_event__process_namespaces,
1471 .ordered_events = true, 1476 .ordered_events = true,
1472 .ordering_requires_timestamps = true, 1477 .ordering_requires_timestamps = true,
1473 }, 1478 },
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 60bfc9ca1e22..e84bbc8ec058 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -2,6 +2,7 @@
2#include <linux/kernel.h> 2#include <linux/kernel.h>
3#include <sys/types.h> 3#include <sys/types.h>
4#include <sys/stat.h> 4#include <sys/stat.h>
5#include <errno.h>
5#include <unistd.h> 6#include <unistd.h>
6#include <string.h> 7#include <string.h>
7 8
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 03eb81f30d0d..a5b3777ffee6 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -2,19 +2,26 @@
2 2
3#include "../perf.h" 3#include "../perf.h"
4 4
5#include <inttypes.h>
5#include <string.h> 6#include <string.h>
6#include <stdarg.h> 7#include <stdarg.h>
7#include <stdio.h> 8#include <stdio.h>
9#include <sys/wait.h>
8#include <api/debug.h> 10#include <api/debug.h>
9#include <linux/time64.h> 11#include <linux/time64.h>
10 12#ifdef HAVE_BACKTRACE_SUPPORT
13#include <execinfo.h>
14#endif
11#include "cache.h" 15#include "cache.h"
12#include "color.h" 16#include "color.h"
13#include "event.h" 17#include "event.h"
14#include "debug.h" 18#include "debug.h"
19#include "print_binary.h"
15#include "util.h" 20#include "util.h"
16#include "target.h" 21#include "target.h"
17 22
23#include "sane_ctype.h"
24
18int verbose; 25int verbose;
19bool dump_trace = false, quiet = false; 26bool dump_trace = false, quiet = false;
20int debug_ordered_events; 27int debug_ordered_events;
@@ -244,3 +251,31 @@ void perf_debug_setup(void)
244{ 251{
245 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 252 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
246} 253}
254
255/* Obtain a backtrace and print it to stdout. */
256#ifdef HAVE_BACKTRACE_SUPPORT
257void dump_stack(void)
258{
259 void *array[16];
260 size_t size = backtrace(array, ARRAY_SIZE(array));
261 char **strings = backtrace_symbols(array, size);
262 size_t i;
263
264 printf("Obtained %zd stack frames.\n", size);
265
266 for (i = 0; i < size; i++)
267 printf("%s\n", strings[i]);
268
269 free(strings);
270}
271#else
272void dump_stack(void) {}
273#endif
274
275void sighandler_dump_stack(int sig)
276{
277 psignal(sig, "perf");
278 dump_stack();
279 signal(sig, SIG_DFL);
280 raise(sig);
281}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 98832f5531d3..8a23ea1a71c7 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -56,4 +56,7 @@ int perf_debug_option(const char *str);
56void perf_debug_setup(void); 56void perf_debug_setup(void);
57int perf_quiet_option(void); 57int perf_quiet_option(void);
58 58
59void dump_stack(void);
60void sighandler_dump_stack(int sig);
61
59#endif /* __PERF_DEBUG_H */ 62#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
index 3e6062ab2cdd..cb66d334f532 100644
--- a/tools/perf/util/demangle-java.c
+++ b/tools/perf/util/demangle-java.c
@@ -7,6 +7,8 @@
7 7
8#include "demangle-java.h" 8#include "demangle-java.h"
9 9
10#include "sane_ctype.h"
11
10enum { 12enum {
11 MODE_PREFIX = 0, 13 MODE_PREFIX = 0,
12 MODE_CLASS = 1, 14 MODE_CLASS = 1,
diff --git a/tools/perf/util/drv_configs.c b/tools/perf/util/drv_configs.c
index 1647f285c629..eec754243f4d 100644
--- a/tools/perf/util/drv_configs.c
+++ b/tools/perf/util/drv_configs.c
@@ -17,6 +17,7 @@
17#include "evlist.h" 17#include "evlist.h"
18#include "evsel.h" 18#include "evsel.h"
19#include "pmu.h" 19#include "pmu.h"
20#include <errno.h>
20 21
21static int 22static int
22perf_evsel__apply_drv_configs(struct perf_evsel *evsel, 23perf_evsel__apply_drv_configs(struct perf_evsel *evsel,
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index d38b62a700ca..a96a99d2369f 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1,12 +1,20 @@
1#include <asm/bug.h> 1#include <asm/bug.h>
2#include <linux/kernel.h>
2#include <sys/time.h> 3#include <sys/time.h>
3#include <sys/resource.h> 4#include <sys/resource.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <errno.h>
9#include "compress.h"
10#include "path.h"
4#include "symbol.h" 11#include "symbol.h"
5#include "dso.h" 12#include "dso.h"
6#include "machine.h" 13#include "machine.h"
7#include "auxtrace.h" 14#include "auxtrace.h"
8#include "util.h" 15#include "util.h"
9#include "debug.h" 16#include "debug.h"
17#include "string2.h"
10#include "vdso.h" 18#include "vdso.h"
11 19
12static const char * const debuglink_paths[] = { 20static const char * const debuglink_paths[] = {
@@ -1109,7 +1117,7 @@ struct dso *dso__new(const char *name)
1109 INIT_LIST_HEAD(&dso->node); 1117 INIT_LIST_HEAD(&dso->node);
1110 INIT_LIST_HEAD(&dso->data.open_entry); 1118 INIT_LIST_HEAD(&dso->data.open_entry);
1111 pthread_mutex_init(&dso->lock, NULL); 1119 pthread_mutex_init(&dso->lock, NULL);
1112 atomic_set(&dso->refcnt, 1); 1120 refcount_set(&dso->refcnt, 1);
1113 } 1121 }
1114 1122
1115 return dso; 1123 return dso;
@@ -1147,13 +1155,13 @@ void dso__delete(struct dso *dso)
1147struct dso *dso__get(struct dso *dso) 1155struct dso *dso__get(struct dso *dso)
1148{ 1156{
1149 if (dso) 1157 if (dso)
1150 atomic_inc(&dso->refcnt); 1158 refcount_inc(&dso->refcnt);
1151 return dso; 1159 return dso;
1152} 1160}
1153 1161
1154void dso__put(struct dso *dso) 1162void dso__put(struct dso *dso)
1155{ 1163{
1156 if (dso && atomic_dec_and_test(&dso->refcnt)) 1164 if (dso && refcount_dec_and_test(&dso->refcnt))
1157 dso__delete(dso); 1165 dso__delete(dso);
1158} 1166}
1159 1167
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ecc4bbd3f82e..12350b171727 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_DSO 1#ifndef __PERF_DSO
2#define __PERF_DSO 2#define __PERF_DSO
3 3
4#include <linux/atomic.h> 4#include <linux/refcount.h>
5#include <linux/types.h> 5#include <linux/types.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include <sys/types.h> 7#include <sys/types.h>
@@ -187,7 +187,7 @@ struct dso {
187 void *priv; 187 void *priv;
188 u64 db_id; 188 u64 db_id;
189 }; 189 };
190 atomic_t refcnt; 190 refcount_t refcnt;
191 char name[0]; 191 char name[0];
192}; 192};
193 193
diff --git a/tools/perf/util/dump-insn.c b/tools/perf/util/dump-insn.c
new file mode 100644
index 000000000000..ffbdb19f05d0
--- /dev/null
+++ b/tools/perf/util/dump-insn.c
@@ -0,0 +1,14 @@
1#include <linux/compiler.h>
2#include "dump-insn.h"
3
4/* Fallback code */
5
6__weak
7const char *dump_insn(struct perf_insn *x __maybe_unused,
8 u64 ip __maybe_unused, u8 *inbuf __maybe_unused,
9 int inlen __maybe_unused, int *lenp)
10{
11 if (lenp)
12 *lenp = 0;
13 return "?";
14}
diff --git a/tools/perf/util/dump-insn.h b/tools/perf/util/dump-insn.h
new file mode 100644
index 000000000000..90fb115981cf
--- /dev/null
+++ b/tools/perf/util/dump-insn.h
@@ -0,0 +1,22 @@
1#ifndef __PERF_DUMP_INSN_H
2#define __PERF_DUMP_INSN_H 1
3
4#define MAXINSN 15
5
6#include <linux/types.h>
7
8struct thread;
9
10struct perf_insn {
11 /* Initialized by callers: */
12 struct thread *thread;
13 u8 cpumode;
14 bool is64bit;
15 int cpu;
16 /* Temporary */
17 char out[256];
18};
19
20const char *dump_insn(struct perf_insn *x, u64 ip,
21 u8 *inbuf, int inlen, int *lenp);
22#endif
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 41e068e94349..f5acda13dcfa 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -17,10 +17,13 @@
17 * 17 *
18 */ 18 */
19 19
20#include <errno.h>
21#include <inttypes.h>
20#include <stdbool.h> 22#include <stdbool.h>
21#include "util.h" 23#include "util.h"
22#include "debug.h" 24#include "debug.h"
23#include "dwarf-aux.h" 25#include "dwarf-aux.h"
26#include "string2.h"
24 27
25/** 28/**
26 * cu_find_realpath - Find the realpath of the target file 29 * cu_find_realpath - Find the realpath of the target file
diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c
index 62bc4a86a970..c708395b3cb6 100644
--- a/tools/perf/util/dwarf-regs.c
+++ b/tools/perf/util/dwarf-regs.c
@@ -8,6 +8,7 @@
8#include <debug.h> 8#include <debug.h>
9#include <dwarf-regs.h> 9#include <dwarf-regs.h>
10#include <elf.h> 10#include <elf.h>
11#include <linux/kernel.h>
11 12
12#ifndef EM_AARCH64 13#ifndef EM_AARCH64
13#define EM_AARCH64 183 /* ARM 64 bit */ 14#define EM_AARCH64 183 /* ARM 64 bit */
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 075fc77286bf..9e21538c42ae 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -1,6 +1,7 @@
1#include "cpumap.h" 1#include "cpumap.h"
2#include "env.h" 2#include "env.h"
3#include "util.h" 3#include "util.h"
4#include <errno.h>
4 5
5struct perf_env perf_env; 6struct perf_env perf_env;
6 7
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 4ea7ce72ed9c..dc5c3bb69d73 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,15 +1,24 @@
1#include <dirent.h>
2#include <errno.h>
3#include <inttypes.h>
4#include <linux/kernel.h>
1#include <linux/types.h> 5#include <linux/types.h>
2#include <linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
3#include <api/fs/fs.h> 10#include <api/fs/fs.h>
11#include <linux/perf_event.h>
4#include "event.h" 12#include "event.h"
5#include "debug.h" 13#include "debug.h"
6#include "hist.h" 14#include "hist.h"
7#include "machine.h" 15#include "machine.h"
8#include "sort.h" 16#include "sort.h"
9#include "string.h" 17#include "string2.h"
10#include "strlist.h" 18#include "strlist.h"
11#include "thread.h" 19#include "thread.h"
12#include "thread_map.h" 20#include "thread_map.h"
21#include "sane_ctype.h"
13#include "symbol/kallsyms.h" 22#include "symbol/kallsyms.h"
14#include "asm/bug.h" 23#include "asm/bug.h"
15#include "stat.h" 24#include "stat.h"
@@ -31,6 +40,7 @@ static const char *perf_event__names[] = {
31 [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES", 40 [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES",
32 [PERF_RECORD_SWITCH] = "SWITCH", 41 [PERF_RECORD_SWITCH] = "SWITCH",
33 [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE", 42 [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE",
43 [PERF_RECORD_NAMESPACES] = "NAMESPACES",
34 [PERF_RECORD_HEADER_ATTR] = "ATTR", 44 [PERF_RECORD_HEADER_ATTR] = "ATTR",
35 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 45 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
36 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 46 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
@@ -49,6 +59,16 @@ static const char *perf_event__names[] = {
49 [PERF_RECORD_TIME_CONV] = "TIME_CONV", 59 [PERF_RECORD_TIME_CONV] = "TIME_CONV",
50}; 60};
51 61
62static const char *perf_ns__names[] = {
63 [NET_NS_INDEX] = "net",
64 [UTS_NS_INDEX] = "uts",
65 [IPC_NS_INDEX] = "ipc",
66 [PID_NS_INDEX] = "pid",
67 [USER_NS_INDEX] = "user",
68 [MNT_NS_INDEX] = "mnt",
69 [CGROUP_NS_INDEX] = "cgroup",
70};
71
52const char *perf_event__name(unsigned int id) 72const char *perf_event__name(unsigned int id)
53{ 73{
54 if (id >= ARRAY_SIZE(perf_event__names)) 74 if (id >= ARRAY_SIZE(perf_event__names))
@@ -58,6 +78,13 @@ const char *perf_event__name(unsigned int id)
58 return perf_event__names[id]; 78 return perf_event__names[id];
59} 79}
60 80
81static const char *perf_ns__name(unsigned int id)
82{
83 if (id >= ARRAY_SIZE(perf_ns__names))
84 return "UNKNOWN";
85 return perf_ns__names[id];
86}
87
61static int perf_tool__process_synth_event(struct perf_tool *tool, 88static int perf_tool__process_synth_event(struct perf_tool *tool,
62 union perf_event *event, 89 union perf_event *event,
63 struct machine *machine, 90 struct machine *machine,
@@ -88,7 +115,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
88 int fd; 115 int fd;
89 size_t size = 0; 116 size_t size = 0;
90 ssize_t n; 117 ssize_t n;
91 char *nl, *name, *tgids, *ppids; 118 char *name, *tgids, *ppids;
92 119
93 *tgid = -1; 120 *tgid = -1;
94 *ppid = -1; 121 *ppid = -1;
@@ -115,10 +142,10 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
115 ppids = strstr(bf, "PPid:"); 142 ppids = strstr(bf, "PPid:");
116 143
117 if (name) { 144 if (name) {
118 name += 5; /* strlen("Name:") */ 145 char *nl;
119 146
120 while (*name && isspace(*name)) 147 name += 5; /* strlen("Name:") */
121 ++name; 148 name = ltrim(name);
122 149
123 nl = strchr(name, '\n'); 150 nl = strchr(name, '\n');
124 if (nl) 151 if (nl)
@@ -203,6 +230,58 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
203 return tgid; 230 return tgid;
204} 231}
205 232
233static void perf_event__get_ns_link_info(pid_t pid, const char *ns,
234 struct perf_ns_link_info *ns_link_info)
235{
236 struct stat64 st;
237 char proc_ns[128];
238
239 sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);
240 if (stat64(proc_ns, &st) == 0) {
241 ns_link_info->dev = st.st_dev;
242 ns_link_info->ino = st.st_ino;
243 }
244}
245
246int perf_event__synthesize_namespaces(struct perf_tool *tool,
247 union perf_event *event,
248 pid_t pid, pid_t tgid,
249 perf_event__handler_t process,
250 struct machine *machine)
251{
252 u32 idx;
253 struct perf_ns_link_info *ns_link_info;
254
255 if (!tool || !tool->namespace_events)
256 return 0;
257
258 memset(&event->namespaces, 0, (sizeof(event->namespaces) +
259 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
260 machine->id_hdr_size));
261
262 event->namespaces.pid = tgid;
263 event->namespaces.tid = pid;
264
265 event->namespaces.nr_namespaces = NR_NAMESPACES;
266
267 ns_link_info = event->namespaces.link_info;
268
269 for (idx = 0; idx < event->namespaces.nr_namespaces; idx++)
270 perf_event__get_ns_link_info(pid, perf_ns__name(idx),
271 &ns_link_info[idx]);
272
273 event->namespaces.header.type = PERF_RECORD_NAMESPACES;
274
275 event->namespaces.header.size = (sizeof(event->namespaces) +
276 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
277 machine->id_hdr_size);
278
279 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
280 return -1;
281
282 return 0;
283}
284
206static int perf_event__synthesize_fork(struct perf_tool *tool, 285static int perf_event__synthesize_fork(struct perf_tool *tool,
207 union perf_event *event, 286 union perf_event *event,
208 pid_t pid, pid_t tgid, pid_t ppid, 287 pid_t pid, pid_t tgid, pid_t ppid,
@@ -255,8 +334,8 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
255 if (machine__is_default_guest(machine)) 334 if (machine__is_default_guest(machine))
256 return 0; 335 return 0;
257 336
258 snprintf(filename, sizeof(filename), "%s/proc/%d/maps", 337 snprintf(filename, sizeof(filename), "%s/proc/%d/task/%d/maps",
259 machine->root_dir, pid); 338 machine->root_dir, pid, pid);
260 339
261 fp = fopen(filename, "r"); 340 fp = fopen(filename, "r");
262 if (fp == NULL) { 341 if (fp == NULL) {
@@ -434,8 +513,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
434static int __event__synthesize_thread(union perf_event *comm_event, 513static int __event__synthesize_thread(union perf_event *comm_event,
435 union perf_event *mmap_event, 514 union perf_event *mmap_event,
436 union perf_event *fork_event, 515 union perf_event *fork_event,
516 union perf_event *namespaces_event,
437 pid_t pid, int full, 517 pid_t pid, int full,
438 perf_event__handler_t process, 518 perf_event__handler_t process,
439 struct perf_tool *tool, 519 struct perf_tool *tool,
440 struct machine *machine, 520 struct machine *machine,
441 bool mmap_data, 521 bool mmap_data,
@@ -455,6 +535,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
455 if (tgid == -1) 535 if (tgid == -1)
456 return -1; 536 return -1;
457 537
538 if (perf_event__synthesize_namespaces(tool, namespaces_event, pid,
539 tgid, process, machine) < 0)
540 return -1;
541
542
458 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 543 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
459 process, machine, mmap_data, 544 process, machine, mmap_data,
460 proc_map_timeout); 545 proc_map_timeout);
@@ -488,6 +573,11 @@ static int __event__synthesize_thread(union perf_event *comm_event,
488 if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 573 if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
489 ppid, process, machine) < 0) 574 ppid, process, machine) < 0)
490 break; 575 break;
576
577 if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,
578 tgid, process, machine) < 0)
579 break;
580
491 /* 581 /*
492 * Send the prepared comm event 582 * Send the prepared comm event
493 */ 583 */
@@ -516,6 +606,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
516 unsigned int proc_map_timeout) 606 unsigned int proc_map_timeout)
517{ 607{
518 union perf_event *comm_event, *mmap_event, *fork_event; 608 union perf_event *comm_event, *mmap_event, *fork_event;
609 union perf_event *namespaces_event;
519 int err = -1, thread, j; 610 int err = -1, thread, j;
520 611
521 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 612 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
@@ -530,10 +621,16 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
530 if (fork_event == NULL) 621 if (fork_event == NULL)
531 goto out_free_mmap; 622 goto out_free_mmap;
532 623
624 namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
625 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
626 machine->id_hdr_size);
627 if (namespaces_event == NULL)
628 goto out_free_fork;
629
533 err = 0; 630 err = 0;
534 for (thread = 0; thread < threads->nr; ++thread) { 631 for (thread = 0; thread < threads->nr; ++thread) {
535 if (__event__synthesize_thread(comm_event, mmap_event, 632 if (__event__synthesize_thread(comm_event, mmap_event,
536 fork_event, 633 fork_event, namespaces_event,
537 thread_map__pid(threads, thread), 0, 634 thread_map__pid(threads, thread), 0,
538 process, tool, machine, 635 process, tool, machine,
539 mmap_data, proc_map_timeout)) { 636 mmap_data, proc_map_timeout)) {
@@ -559,7 +656,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
559 /* if not, generate events for it */ 656 /* if not, generate events for it */
560 if (need_leader && 657 if (need_leader &&
561 __event__synthesize_thread(comm_event, mmap_event, 658 __event__synthesize_thread(comm_event, mmap_event,
562 fork_event, 659 fork_event, namespaces_event,
563 comm_event->comm.pid, 0, 660 comm_event->comm.pid, 0,
564 process, tool, machine, 661 process, tool, machine,
565 mmap_data, proc_map_timeout)) { 662 mmap_data, proc_map_timeout)) {
@@ -568,6 +665,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
568 } 665 }
569 } 666 }
570 } 667 }
668 free(namespaces_event);
669out_free_fork:
571 free(fork_event); 670 free(fork_event);
572out_free_mmap: 671out_free_mmap:
573 free(mmap_event); 672 free(mmap_event);
@@ -587,6 +686,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
587 char proc_path[PATH_MAX]; 686 char proc_path[PATH_MAX];
588 struct dirent *dirent; 687 struct dirent *dirent;
589 union perf_event *comm_event, *mmap_event, *fork_event; 688 union perf_event *comm_event, *mmap_event, *fork_event;
689 union perf_event *namespaces_event;
590 int err = -1; 690 int err = -1;
591 691
592 if (machine__is_default_guest(machine)) 692 if (machine__is_default_guest(machine))
@@ -604,11 +704,17 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
604 if (fork_event == NULL) 704 if (fork_event == NULL)
605 goto out_free_mmap; 705 goto out_free_mmap;
606 706
707 namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
708 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
709 machine->id_hdr_size);
710 if (namespaces_event == NULL)
711 goto out_free_fork;
712
607 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 713 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
608 proc = opendir(proc_path); 714 proc = opendir(proc_path);
609 715
610 if (proc == NULL) 716 if (proc == NULL)
611 goto out_free_fork; 717 goto out_free_namespaces;
612 718
613 while ((dirent = readdir(proc)) != NULL) { 719 while ((dirent = readdir(proc)) != NULL) {
614 char *end; 720 char *end;
@@ -620,13 +726,16 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
620 * We may race with exiting thread, so don't stop just because 726 * We may race with exiting thread, so don't stop just because
621 * one thread couldn't be synthesized. 727 * one thread couldn't be synthesized.
622 */ 728 */
623 __event__synthesize_thread(comm_event, mmap_event, fork_event, pid, 729 __event__synthesize_thread(comm_event, mmap_event, fork_event,
624 1, process, tool, machine, mmap_data, 730 namespaces_event, pid, 1, process,
731 tool, machine, mmap_data,
625 proc_map_timeout); 732 proc_map_timeout);
626 } 733 }
627 734
628 err = 0; 735 err = 0;
629 closedir(proc); 736 closedir(proc);
737out_free_namespaces:
738 free(namespaces_event);
630out_free_fork: 739out_free_fork:
631 free(fork_event); 740 free(fork_event);
632out_free_mmap: 741out_free_mmap:
@@ -659,15 +768,16 @@ static int find_symbol_cb(void *arg, const char *name, char type,
659 return 1; 768 return 1;
660} 769}
661 770
662u64 kallsyms__get_function_start(const char *kallsyms_filename, 771int kallsyms__get_function_start(const char *kallsyms_filename,
663 const char *symbol_name) 772 const char *symbol_name, u64 *addr)
664{ 773{
665 struct process_symbol_args args = { .name = symbol_name, }; 774 struct process_symbol_args args = { .name = symbol_name, };
666 775
667 if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0) 776 if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0)
668 return 0; 777 return -1;
669 778
670 return args.start; 779 *addr = args.start;
780 return 0;
671} 781}
672 782
673int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 783int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
@@ -1008,6 +1118,33 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
1008 return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); 1118 return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid);
1009} 1119}
1010 1120
1121size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp)
1122{
1123 size_t ret = 0;
1124 struct perf_ns_link_info *ns_link_info;
1125 u32 nr_namespaces, idx;
1126
1127 ns_link_info = event->namespaces.link_info;
1128 nr_namespaces = event->namespaces.nr_namespaces;
1129
1130 ret += fprintf(fp, " %d/%d - nr_namespaces: %u\n\t\t[",
1131 event->namespaces.pid,
1132 event->namespaces.tid,
1133 nr_namespaces);
1134
1135 for (idx = 0; idx < nr_namespaces; idx++) {
1136 if (idx && (idx % 4 == 0))
1137 ret += fprintf(fp, "\n\t\t ");
1138
1139 ret += fprintf(fp, "%u/%s: %" PRIu64 "/%#" PRIx64 "%s", idx,
1140 perf_ns__name(idx), (u64)ns_link_info[idx].dev,
1141 (u64)ns_link_info[idx].ino,
1142 ((idx + 1) != nr_namespaces) ? ", " : "]\n");
1143 }
1144
1145 return ret;
1146}
1147
1011int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 1148int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
1012 union perf_event *event, 1149 union perf_event *event,
1013 struct perf_sample *sample, 1150 struct perf_sample *sample,
@@ -1016,6 +1153,14 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
1016 return machine__process_comm_event(machine, event, sample); 1153 return machine__process_comm_event(machine, event, sample);
1017} 1154}
1018 1155
1156int perf_event__process_namespaces(struct perf_tool *tool __maybe_unused,
1157 union perf_event *event,
1158 struct perf_sample *sample,
1159 struct machine *machine)
1160{
1161 return machine__process_namespaces_event(machine, event, sample);
1162}
1163
1019int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 1164int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
1020 union perf_event *event, 1165 union perf_event *event,
1021 struct perf_sample *sample, 1166 struct perf_sample *sample,
@@ -1153,11 +1298,12 @@ int perf_event__process_exit(struct perf_tool *tool __maybe_unused,
1153 1298
1154size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp) 1299size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp)
1155{ 1300{
1156 return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s]\n", 1301 return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s%s]\n",
1157 event->aux.aux_offset, event->aux.aux_size, 1302 event->aux.aux_offset, event->aux.aux_size,
1158 event->aux.flags, 1303 event->aux.flags,
1159 event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "", 1304 event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "",
1160 event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : ""); 1305 event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : "",
1306 event->aux.flags & PERF_AUX_FLAG_PARTIAL ? "P" : "");
1161} 1307}
1162 1308
1163size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp) 1309size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp)
@@ -1196,6 +1342,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
1196 case PERF_RECORD_MMAP: 1342 case PERF_RECORD_MMAP:
1197 ret += perf_event__fprintf_mmap(event, fp); 1343 ret += perf_event__fprintf_mmap(event, fp);
1198 break; 1344 break;
1345 case PERF_RECORD_NAMESPACES:
1346 ret += perf_event__fprintf_namespaces(event, fp);
1347 break;
1199 case PERF_RECORD_MMAP2: 1348 case PERF_RECORD_MMAP2:
1200 ret += perf_event__fprintf_mmap2(event, fp); 1349 ret += perf_event__fprintf_mmap2(event, fp);
1201 break; 1350 break;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c735c53a26f8..7c3fa1c8cbcd 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -3,9 +3,9 @@
3 3
4#include <limits.h> 4#include <limits.h>
5#include <stdio.h> 5#include <stdio.h>
6#include <linux/kernel.h>
6 7
7#include "../perf.h" 8#include "../perf.h"
8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10#include "perf_regs.h" 10#include "perf_regs.h"
11 11
@@ -39,6 +39,13 @@ struct comm_event {
39 char comm[16]; 39 char comm[16];
40}; 40};
41 41
42struct namespaces_event {
43 struct perf_event_header header;
44 u32 pid, tid;
45 u64 nr_namespaces;
46 struct perf_ns_link_info link_info[];
47};
48
42struct fork_event { 49struct fork_event {
43 struct perf_event_header header; 50 struct perf_event_header header;
44 u32 pid, ppid; 51 u32 pid, ppid;
@@ -222,7 +229,7 @@ struct build_id_event {
222enum perf_user_event_type { /* above any possible kernel type */ 229enum perf_user_event_type { /* above any possible kernel type */
223 PERF_RECORD_USER_TYPE_START = 64, 230 PERF_RECORD_USER_TYPE_START = 64,
224 PERF_RECORD_HEADER_ATTR = 64, 231 PERF_RECORD_HEADER_ATTR = 64,
225 PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */ 232 PERF_RECORD_HEADER_EVENT_TYPE = 65, /* deprecated */
226 PERF_RECORD_HEADER_TRACING_DATA = 66, 233 PERF_RECORD_HEADER_TRACING_DATA = 66,
227 PERF_RECORD_HEADER_BUILD_ID = 67, 234 PERF_RECORD_HEADER_BUILD_ID = 67,
228 PERF_RECORD_FINISHED_ROUND = 68, 235 PERF_RECORD_FINISHED_ROUND = 68,
@@ -269,6 +276,7 @@ struct events_stats {
269 u64 total_lost; 276 u64 total_lost;
270 u64 total_lost_samples; 277 u64 total_lost_samples;
271 u64 total_aux_lost; 278 u64 total_aux_lost;
279 u64 total_aux_partial;
272 u64 total_invalid_chains; 280 u64 total_invalid_chains;
273 u32 nr_events[PERF_RECORD_HEADER_MAX]; 281 u32 nr_events[PERF_RECORD_HEADER_MAX];
274 u32 nr_non_filtered_samples; 282 u32 nr_non_filtered_samples;
@@ -485,6 +493,7 @@ union perf_event {
485 struct mmap_event mmap; 493 struct mmap_event mmap;
486 struct mmap2_event mmap2; 494 struct mmap2_event mmap2;
487 struct comm_event comm; 495 struct comm_event comm;
496 struct namespaces_event namespaces;
488 struct fork_event fork; 497 struct fork_event fork;
489 struct lost_event lost; 498 struct lost_event lost;
490 struct lost_samples_event lost_samples; 499 struct lost_samples_event lost_samples;
@@ -587,6 +596,10 @@ int perf_event__process_switch(struct perf_tool *tool,
587 union perf_event *event, 596 union perf_event *event,
588 struct perf_sample *sample, 597 struct perf_sample *sample,
589 struct machine *machine); 598 struct machine *machine);
599int perf_event__process_namespaces(struct perf_tool *tool,
600 union perf_event *event,
601 struct perf_sample *sample,
602 struct machine *machine);
590int perf_event__process_mmap(struct perf_tool *tool, 603int perf_event__process_mmap(struct perf_tool *tool,
591 union perf_event *event, 604 union perf_event *event,
592 struct perf_sample *sample, 605 struct perf_sample *sample,
@@ -636,6 +649,12 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
636 perf_event__handler_t process, 649 perf_event__handler_t process,
637 struct machine *machine); 650 struct machine *machine);
638 651
652int perf_event__synthesize_namespaces(struct perf_tool *tool,
653 union perf_event *event,
654 pid_t pid, pid_t tgid,
655 perf_event__handler_t process,
656 struct machine *machine);
657
639int perf_event__synthesize_mmap_events(struct perf_tool *tool, 658int perf_event__synthesize_mmap_events(struct perf_tool *tool,
640 union perf_event *event, 659 union perf_event *event,
641 pid_t pid, pid_t tgid, 660 pid_t pid, pid_t tgid,
@@ -653,12 +672,21 @@ size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
653size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); 672size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
654size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); 673size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
655size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); 674size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
675size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp);
656size_t perf_event__fprintf(union perf_event *event, FILE *fp); 676size_t perf_event__fprintf(union perf_event *event, FILE *fp);
657 677
658u64 kallsyms__get_function_start(const char *kallsyms_filename, 678int kallsyms__get_function_start(const char *kallsyms_filename,
659 const char *symbol_name); 679 const char *symbol_name, u64 *addr);
660 680
661void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max); 681void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max);
662void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, 682void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
663 u16 type, int max); 683 u16 type, int max);
684
685void event_attr_init(struct perf_event_attr *attr);
686
687int perf_event_paranoid(void);
688
689extern int sysctl_perf_event_max_stack;
690extern int sysctl_perf_event_max_contexts_per_stack;
691
664#endif /* __PERF_RECORD_H */ 692#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index b601f2814a30..46c0faf6c502 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -8,6 +8,8 @@
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include <api/fs/fs.h> 10#include <api/fs/fs.h>
11#include <errno.h>
12#include <inttypes.h>
11#include <poll.h> 13#include <poll.h>
12#include "cpumap.h" 14#include "cpumap.h"
13#include "thread_map.h" 15#include "thread_map.h"
@@ -15,12 +17,15 @@
15#include "evlist.h" 17#include "evlist.h"
16#include "evsel.h" 18#include "evsel.h"
17#include "debug.h" 19#include "debug.h"
20#include "units.h"
18#include "asm/bug.h" 21#include "asm/bug.h"
22#include <signal.h>
19#include <unistd.h> 23#include <unistd.h>
20 24
21#include "parse-events.h" 25#include "parse-events.h"
22#include <subcmd/parse-options.h> 26#include <subcmd/parse-options.h>
23 27
28#include <sys/ioctl.h>
24#include <sys/mman.h> 29#include <sys/mman.h>
25 30
26#include <linux/bitops.h> 31#include <linux/bitops.h>
@@ -777,7 +782,7 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *md, bool check_messu
777 /* 782 /*
778 * Check if event was unmapped due to a POLLHUP/POLLERR. 783 * Check if event was unmapped due to a POLLHUP/POLLERR.
779 */ 784 */
780 if (!atomic_read(&md->refcnt)) 785 if (!refcount_read(&md->refcnt))
781 return NULL; 786 return NULL;
782 787
783 head = perf_mmap__read_head(md); 788 head = perf_mmap__read_head(md);
@@ -794,7 +799,7 @@ perf_mmap__read_backward(struct perf_mmap *md)
794 /* 799 /*
795 * Check if event was unmapped due to a POLLHUP/POLLERR. 800 * Check if event was unmapped due to a POLLHUP/POLLERR.
796 */ 801 */
797 if (!atomic_read(&md->refcnt)) 802 if (!refcount_read(&md->refcnt))
798 return NULL; 803 return NULL;
799 804
800 head = perf_mmap__read_head(md); 805 head = perf_mmap__read_head(md);
@@ -856,7 +861,7 @@ void perf_mmap__read_catchup(struct perf_mmap *md)
856{ 861{
857 u64 head; 862 u64 head;
858 863
859 if (!atomic_read(&md->refcnt)) 864 if (!refcount_read(&md->refcnt))
860 return; 865 return;
861 866
862 head = perf_mmap__read_head(md); 867 head = perf_mmap__read_head(md);
@@ -875,14 +880,14 @@ static bool perf_mmap__empty(struct perf_mmap *md)
875 880
876static void perf_mmap__get(struct perf_mmap *map) 881static void perf_mmap__get(struct perf_mmap *map)
877{ 882{
878 atomic_inc(&map->refcnt); 883 refcount_inc(&map->refcnt);
879} 884}
880 885
881static void perf_mmap__put(struct perf_mmap *md) 886static void perf_mmap__put(struct perf_mmap *md)
882{ 887{
883 BUG_ON(md->base && atomic_read(&md->refcnt) == 0); 888 BUG_ON(md->base && refcount_read(&md->refcnt) == 0);
884 889
885 if (atomic_dec_and_test(&md->refcnt)) 890 if (refcount_dec_and_test(&md->refcnt))
886 perf_mmap__munmap(md); 891 perf_mmap__munmap(md);
887} 892}
888 893
@@ -894,7 +899,7 @@ void perf_mmap__consume(struct perf_mmap *md, bool overwrite)
894 perf_mmap__write_tail(md, old); 899 perf_mmap__write_tail(md, old);
895 } 900 }
896 901
897 if (atomic_read(&md->refcnt) == 1 && perf_mmap__empty(md)) 902 if (refcount_read(&md->refcnt) == 1 && perf_mmap__empty(md))
898 perf_mmap__put(md); 903 perf_mmap__put(md);
899} 904}
900 905
@@ -937,7 +942,7 @@ static void perf_mmap__munmap(struct perf_mmap *map)
937 munmap(map->base, perf_mmap__mmap_len(map)); 942 munmap(map->base, perf_mmap__mmap_len(map));
938 map->base = NULL; 943 map->base = NULL;
939 map->fd = -1; 944 map->fd = -1;
940 atomic_set(&map->refcnt, 0); 945 refcount_set(&map->refcnt, 0);
941 } 946 }
942 auxtrace_mmap__munmap(&map->auxtrace_mmap); 947 auxtrace_mmap__munmap(&map->auxtrace_mmap);
943} 948}
@@ -974,8 +979,19 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist)
974 if (!map) 979 if (!map)
975 return NULL; 980 return NULL;
976 981
977 for (i = 0; i < evlist->nr_mmaps; i++) 982 for (i = 0; i < evlist->nr_mmaps; i++) {
978 map[i].fd = -1; 983 map[i].fd = -1;
984 /*
985 * When the perf_mmap() call is made we grab one refcount, plus
986 * one extra to let perf_evlist__mmap_consume() get the last
987 * events after all real references (perf_mmap__get()) are
988 * dropped.
989 *
990 * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
991 * thus does perf_mmap__get() on it.
992 */
993 refcount_set(&map[i].refcnt, 0);
994 }
979 return map; 995 return map;
980} 996}
981 997
@@ -1001,7 +1017,7 @@ static int perf_mmap__mmap(struct perf_mmap *map,
1001 * evlist layer can't just drop it when filtering events in 1017 * evlist layer can't just drop it when filtering events in
1002 * perf_evlist__filter_pollfd(). 1018 * perf_evlist__filter_pollfd().
1003 */ 1019 */
1004 atomic_set(&map->refcnt, 2); 1020 refcount_set(&map->refcnt, 2);
1005 map->prev = 0; 1021 map->prev = 0;
1006 map->mask = mp->mask; 1022 map->mask = mp->mask;
1007 map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, 1023 map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot,
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 389b9ccdf8c7..94cea4398a13 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -1,7 +1,8 @@
1#ifndef __PERF_EVLIST_H 1#ifndef __PERF_EVLIST_H
2#define __PERF_EVLIST_H 1 2#define __PERF_EVLIST_H 1
3 3
4#include <linux/atomic.h> 4#include <linux/kernel.h>
5#include <linux/refcount.h>
5#include <linux/list.h> 6#include <linux/list.h>
6#include <api/fd/array.h> 7#include <api/fd/array.h>
7#include <stdio.h> 8#include <stdio.h>
@@ -10,6 +11,7 @@
10#include "evsel.h" 11#include "evsel.h"
11#include "util.h" 12#include "util.h"
12#include "auxtrace.h" 13#include "auxtrace.h"
14#include <signal.h>
13#include <unistd.h> 15#include <unistd.h>
14 16
15struct pollfd; 17struct pollfd;
@@ -29,7 +31,7 @@ struct perf_mmap {
29 void *base; 31 void *base;
30 int mask; 32 int mask;
31 int fd; 33 int fd;
32 atomic_t refcnt; 34 refcount_t refcnt;
33 u64 prev; 35 u64 prev;
34 struct auxtrace_mmap auxtrace_mmap; 36 struct auxtrace_mmap auxtrace_mmap;
35 char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8))); 37 char event_copy[PERF_SAMPLE_MAX_SIZE] __attribute__((aligned(8)));
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ac59710b79e0..e4f7902d5afa 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -8,16 +8,20 @@
8 */ 8 */
9 9
10#include <byteswap.h> 10#include <byteswap.h>
11#include <errno.h>
12#include <inttypes.h>
11#include <linux/bitops.h> 13#include <linux/bitops.h>
12#include <api/fs/tracing_path.h> 14#include <api/fs/tracing_path.h>
13#include <traceevent/event-parse.h> 15#include <traceevent/event-parse.h>
14#include <linux/hw_breakpoint.h> 16#include <linux/hw_breakpoint.h>
15#include <linux/perf_event.h> 17#include <linux/perf_event.h>
16#include <linux/err.h> 18#include <linux/err.h>
19#include <sys/ioctl.h>
17#include <sys/resource.h> 20#include <sys/resource.h>
18#include "asm/bug.h" 21#include "asm/bug.h"
19#include "callchain.h" 22#include "callchain.h"
20#include "cgroup.h" 23#include "cgroup.h"
24#include "event.h"
21#include "evsel.h" 25#include "evsel.h"
22#include "evlist.h" 26#include "evlist.h"
23#include "util.h" 27#include "util.h"
@@ -30,6 +34,8 @@
30#include "stat.h" 34#include "stat.h"
31#include "util/parse-branch-options.h" 35#include "util/parse-branch-options.h"
32 36
37#include "sane_ctype.h"
38
33static struct { 39static struct {
34 bool sample_id_all; 40 bool sample_id_all;
35 bool exclude_guest; 41 bool exclude_guest;
@@ -236,6 +242,10 @@ void perf_evsel__init(struct perf_evsel *evsel,
236 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 242 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
237 perf_evsel__calc_id_pos(evsel); 243 perf_evsel__calc_id_pos(evsel);
238 evsel->cmdline_group_boundary = false; 244 evsel->cmdline_group_boundary = false;
245 evsel->metric_expr = NULL;
246 evsel->metric_name = NULL;
247 evsel->metric_events = NULL;
248 evsel->collect_stat = false;
239} 249}
240 250
241struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) 251struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
@@ -932,6 +942,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
932 attr->mmap2 = track && !perf_missing_features.mmap2; 942 attr->mmap2 = track && !perf_missing_features.mmap2;
933 attr->comm = track; 943 attr->comm = track;
934 944
945 if (opts->record_namespaces)
946 attr->namespaces = track;
947
935 if (opts->record_switch_events) 948 if (opts->record_switch_events)
936 attr->context_switch = track; 949 attr->context_switch = track;
937 950
@@ -1232,7 +1245,7 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
1232 if (FD(evsel, cpu, thread) < 0) 1245 if (FD(evsel, cpu, thread) < 0)
1233 return -EINVAL; 1246 return -EINVAL;
1234 1247
1235 if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) < 0) 1248 if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) <= 0)
1236 return -errno; 1249 return -errno;
1237 1250
1238 return 0; 1251 return 0;
@@ -1250,7 +1263,7 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
1250 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0) 1263 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0)
1251 return -ENOMEM; 1264 return -ENOMEM;
1252 1265
1253 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) 1266 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) <= 0)
1254 return -errno; 1267 return -errno;
1255 1268
1256 perf_evsel__compute_deltas(evsel, cpu, thread, &count); 1269 perf_evsel__compute_deltas(evsel, cpu, thread, &count);
@@ -2450,11 +2463,17 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2450 int err, char *msg, size_t size) 2463 int err, char *msg, size_t size)
2451{ 2464{
2452 char sbuf[STRERR_BUFSIZE]; 2465 char sbuf[STRERR_BUFSIZE];
2466 int printed = 0;
2453 2467
2454 switch (err) { 2468 switch (err) {
2455 case EPERM: 2469 case EPERM:
2456 case EACCES: 2470 case EACCES:
2457 return scnprintf(msg, size, 2471 if (err == EPERM)
2472 printed = scnprintf(msg, size,
2473 "No permission to enable %s event.\n\n",
2474 perf_evsel__name(evsel));
2475
2476 return scnprintf(msg + printed, size - printed,
2458 "You may not have permission to collect %sstats.\n\n" 2477 "You may not have permission to collect %sstats.\n\n"
2459 "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n" 2478 "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
2460 "which controls use of the performance events system by\n" 2479 "which controls use of the performance events system by\n"
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 06ef6f29efa1..d101695c482c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -131,6 +131,11 @@ struct perf_evsel {
131 bool cmdline_group_boundary; 131 bool cmdline_group_boundary;
132 struct list_head config_terms; 132 struct list_head config_terms;
133 int bpf_fd; 133 int bpf_fd;
134 bool merged_stat;
135 const char * metric_expr;
136 const char * metric_name;
137 struct perf_evsel **metric_events;
138 bool collect_stat;
134}; 139};
135 140
136union u64_swap { 141union u64_swap {
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index 4ef5184819a0..e415aee6a245 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -1,9 +1,11 @@
1#include <inttypes.h>
1#include <stdio.h> 2#include <stdio.h>
2#include <stdbool.h> 3#include <stdbool.h>
3#include <traceevent/event-parse.h> 4#include <traceevent/event-parse.h>
4#include "evsel.h" 5#include "evsel.h"
5#include "callchain.h" 6#include "callchain.h"
6#include "map.h" 7#include "map.h"
8#include "strlist.h"
7#include "symbol.h" 9#include "symbol.h"
8 10
9static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) 11static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
new file mode 100644
index 000000000000..9c2760a1a96e
--- /dev/null
+++ b/tools/perf/util/expr.h
@@ -0,0 +1,25 @@
1#ifndef PARSE_CTX_H
2#define PARSE_CTX_H 1
3
4#define EXPR_MAX_OTHER 8
5#define MAX_PARSE_ID EXPR_MAX_OTHER
6
7struct parse_id {
8 const char *name;
9 double val;
10};
11
12struct parse_ctx {
13 int num_ids;
14 struct parse_id ids[MAX_PARSE_ID];
15};
16
17void expr__ctx_init(struct parse_ctx *ctx);
18void expr__add_id(struct parse_ctx *ctx, const char *id, double val);
19#ifndef IN_EXPR_Y
20int expr__parse(double *final_val, struct parse_ctx *ctx, const char **pp);
21#endif
22int expr__find_other(const char *p, const char *one, const char ***other,
23 int *num_other);
24
25#endif
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
new file mode 100644
index 000000000000..954556bea36e
--- /dev/null
+++ b/tools/perf/util/expr.y
@@ -0,0 +1,173 @@
1/* Simple expression parser */
2%{
3#include "util.h"
4#include "util/debug.h"
5#define IN_EXPR_Y 1
6#include "expr.h"
7#include <string.h>
8
9#define MAXIDLEN 256
10%}
11
12%pure-parser
13%parse-param { double *final_val }
14%parse-param { struct parse_ctx *ctx }
15%parse-param { const char **pp }
16%lex-param { const char **pp }
17
18%union {
19 double num;
20 char id[MAXIDLEN+1];
21}
22
23%token <num> NUMBER
24%token <id> ID
25%left '|'
26%left '^'
27%left '&'
28%left '-' '+'
29%left '*' '/' '%'
30%left NEG NOT
31%type <num> expr
32
33%{
34static int expr__lex(YYSTYPE *res, const char **pp);
35
36static void expr__error(double *final_val __maybe_unused,
37 struct parse_ctx *ctx __maybe_unused,
38 const char **pp __maybe_unused,
39 const char *s)
40{
41 pr_debug("%s\n", s);
42}
43
44static int lookup_id(struct parse_ctx *ctx, char *id, double *val)
45{
46 int i;
47
48 for (i = 0; i < ctx->num_ids; i++) {
49 if (!strcasecmp(ctx->ids[i].name, id)) {
50 *val = ctx->ids[i].val;
51 return 0;
52 }
53 }
54 return -1;
55}
56
57%}
58%%
59
60all_expr: expr { *final_val = $1; }
61 ;
62
63expr: NUMBER
64 | ID { if (lookup_id(ctx, $1, &$$) < 0) {
65 pr_debug("%s not found", $1);
66 YYABORT;
67 }
68 }
69 | expr '+' expr { $$ = $1 + $3; }
70 | expr '-' expr { $$ = $1 - $3; }
71 | expr '*' expr { $$ = $1 * $3; }
72 | expr '/' expr { if ($3 == 0) YYABORT; $$ = $1 / $3; }
73 | expr '%' expr { if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; }
74 | '-' expr %prec NEG { $$ = -$2; }
75 | '(' expr ')' { $$ = $2; }
76 ;
77
78%%
79
80static int expr__symbol(YYSTYPE *res, const char *p, const char **pp)
81{
82 char *dst = res->id;
83 const char *s = p;
84
85 while (isalnum(*p) || *p == '_' || *p == '.') {
86 if (p - s >= MAXIDLEN)
87 return -1;
88 *dst++ = *p++;
89 }
90 *dst = 0;
91 *pp = p;
92 return ID;
93}
94
95static int expr__lex(YYSTYPE *res, const char **pp)
96{
97 int tok;
98 const char *s;
99 const char *p = *pp;
100
101 while (isspace(*p))
102 p++;
103 s = p;
104 switch (*p++) {
105 case 'a' ... 'z':
106 case 'A' ... 'Z':
107 return expr__symbol(res, p - 1, pp);
108 case '0' ... '9': case '.':
109 res->num = strtod(s, (char **)&p);
110 tok = NUMBER;
111 break;
112 default:
113 tok = *s;
114 break;
115 }
116 *pp = p;
117 return tok;
118}
119
120/* Caller must make sure id is allocated */
121void expr__add_id(struct parse_ctx *ctx, const char *name, double val)
122{
123 int idx;
124 assert(ctx->num_ids < MAX_PARSE_ID);
125 idx = ctx->num_ids++;
126 ctx->ids[idx].name = name;
127 ctx->ids[idx].val = val;
128}
129
130void expr__ctx_init(struct parse_ctx *ctx)
131{
132 ctx->num_ids = 0;
133}
134
135int expr__find_other(const char *p, const char *one, const char ***other,
136 int *num_otherp)
137{
138 const char *orig = p;
139 int err = -1;
140 int num_other;
141
142 *other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *));
143 if (!*other)
144 return -1;
145
146 num_other = 0;
147 for (;;) {
148 YYSTYPE val;
149 int tok = expr__lex(&val, &p);
150 if (tok == 0) {
151 err = 0;
152 break;
153 }
154 if (tok == ID && strcasecmp(one, val.id)) {
155 if (num_other >= EXPR_MAX_OTHER - 1) {
156 pr_debug("Too many extra events in %s\n", orig);
157 break;
158 }
159 (*other)[num_other] = strdup(val.id);
160 if (!(*other)[num_other])
161 return -1;
162 num_other++;
163 }
164 }
165 (*other)[num_other] = NULL;
166 *num_otherp = num_other;
167 if (err) {
168 *num_otherp = 0;
169 free(*other);
170 *other = NULL;
171 }
172 return err;
173}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 05714d548584..314a07151fb7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,4 +1,8 @@
1#include <errno.h>
2#include <inttypes.h>
1#include "util.h" 3#include "util.h"
4#include "string2.h"
5#include <sys/param.h>
2#include <sys/types.h> 6#include <sys/types.h>
3#include <byteswap.h> 7#include <byteswap.h>
4#include <unistd.h> 8#include <unistd.h>
@@ -7,11 +11,15 @@
7#include <linux/list.h> 11#include <linux/list.h>
8#include <linux/kernel.h> 12#include <linux/kernel.h>
9#include <linux/bitops.h> 13#include <linux/bitops.h>
14#include <sys/stat.h>
15#include <sys/types.h>
10#include <sys/utsname.h> 16#include <sys/utsname.h>
17#include <unistd.h>
11 18
12#include "evlist.h" 19#include "evlist.h"
13#include "evsel.h" 20#include "evsel.h"
14#include "header.h" 21#include "header.h"
22#include "memswap.h"
15#include "../perf.h" 23#include "../perf.h"
16#include "trace-event.h" 24#include "trace-event.h"
17#include "session.h" 25#include "session.h"
@@ -26,6 +34,8 @@
26#include <api/fs/fs.h> 34#include <api/fs/fs.h>
27#include "asm/bug.h" 35#include "asm/bug.h"
28 36
37#include "sane_ctype.h"
38
29/* 39/*
30 * magic2 = "PERFILE2" 40 * magic2 = "PERFILE2"
31 * must be a numerical value to let the endianness 41 * must be a numerical value to let the endianness
@@ -370,15 +380,11 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
370 struct perf_evlist *evlist __maybe_unused) 380 struct perf_evlist *evlist __maybe_unused)
371{ 381{
372 char buf[MAXPATHLEN]; 382 char buf[MAXPATHLEN];
373 char proc[32];
374 u32 n; 383 u32 n;
375 int i, ret; 384 int i, ret;
376 385
377 /* 386 /* actual path to perf binary */
378 * actual atual path to perf binary 387 ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
379 */
380 sprintf(proc, "/proc/%d/exe", getpid());
381 ret = readlink(proc, buf, sizeof(buf));
382 if (ret <= 0) 388 if (ret <= 0)
383 return -1; 389 return -1;
384 390
@@ -2274,6 +2280,9 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
2274 perf_header__process_sections(header, fd, &hd, 2280 perf_header__process_sections(header, fd, &hd,
2275 perf_file_section__fprintf_info); 2281 perf_file_section__fprintf_info);
2276 2282
2283 if (session->file->is_pipe)
2284 return 0;
2285
2277 fprintf(fp, "# missing features: "); 2286 fprintf(fp, "# missing features: ");
2278 for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) { 2287 for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) {
2279 if (bit) 2288 if (bit)
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
index 2821f8d77e52..1c88ad6425b8 100644
--- a/tools/perf/util/help-unknown-cmd.c
+++ b/tools/perf/util/help-unknown-cmd.c
@@ -1,21 +1,18 @@
1#include "cache.h" 1#include "cache.h"
2#include "config.h" 2#include "config.h"
3#include <poll.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <subcmd/help.h> 5#include <subcmd/help.h>
5#include "../builtin.h" 6#include "../builtin.h"
6#include "levenshtein.h" 7#include "levenshtein.h"
7 8
8static int autocorrect; 9static int autocorrect;
9static struct cmdnames aliases;
10 10
11static int perf_unknown_cmd_config(const char *var, const char *value, 11static int perf_unknown_cmd_config(const char *var, const char *value,
12 void *cb __maybe_unused) 12 void *cb __maybe_unused)
13{ 13{
14 if (!strcmp(var, "help.autocorrect")) 14 if (!strcmp(var, "help.autocorrect"))
15 autocorrect = perf_config_int(var,value); 15 autocorrect = perf_config_int(var,value);
16 /* Also use aliases for command lookup */
17 if (!prefixcmp(var, "alias."))
18 add_cmdname(&aliases, var + 6, strlen(var + 6));
19 16
20 return 0; 17 return 0;
21} 18}
@@ -59,14 +56,12 @@ const char *help_unknown_cmd(const char *cmd)
59 56
60 memset(&main_cmds, 0, sizeof(main_cmds)); 57 memset(&main_cmds, 0, sizeof(main_cmds));
61 memset(&other_cmds, 0, sizeof(main_cmds)); 58 memset(&other_cmds, 0, sizeof(main_cmds));
62 memset(&aliases, 0, sizeof(aliases));
63 59
64 perf_config(perf_unknown_cmd_config, NULL); 60 perf_config(perf_unknown_cmd_config, NULL);
65 61
66 load_command_list("perf-", &main_cmds, &other_cmds); 62 load_command_list("perf-", &main_cmds, &other_cmds);
67 63
68 if (add_cmd_list(&main_cmds, &aliases) < 0 || 64 if (add_cmd_list(&main_cmds, &other_cmds) < 0) {
69 add_cmd_list(&main_cmds, &other_cmds) < 0) {
70 fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n"); 65 fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n");
71 goto end; 66 goto end;
72 } 67 }
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index eaf72a938fb4..cf0186a088c1 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -3,12 +3,17 @@
3#include "hist.h" 3#include "hist.h"
4#include "map.h" 4#include "map.h"
5#include "session.h" 5#include "session.h"
6#include "namespaces.h"
6#include "sort.h" 7#include "sort.h"
7#include "evlist.h" 8#include "evlist.h"
8#include "evsel.h" 9#include "evsel.h"
9#include "annotate.h" 10#include "annotate.h"
11#include "srcline.h"
12#include "thread.h"
10#include "ui/progress.h" 13#include "ui/progress.h"
14#include <errno.h>
11#include <math.h> 15#include <math.h>
16#include <sys/param.h>
12 17
13static bool hists__filter_entry_by_dso(struct hists *hists, 18static bool hists__filter_entry_by_dso(struct hists *hists,
14 struct hist_entry *he); 19 struct hist_entry *he);
@@ -169,6 +174,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
169 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); 174 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
170 } 175 }
171 176
177 hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
172 hists__new_col_len(hists, HISTC_CPU, 3); 178 hists__new_col_len(hists, HISTC_CPU, 3);
173 hists__new_col_len(hists, HISTC_SOCKET, 6); 179 hists__new_col_len(hists, HISTC_SOCKET, 6);
174 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); 180 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
@@ -574,9 +580,14 @@ __hists__add_entry(struct hists *hists,
574 bool sample_self, 580 bool sample_self,
575 struct hist_entry_ops *ops) 581 struct hist_entry_ops *ops)
576{ 582{
583 struct namespaces *ns = thread__namespaces(al->thread);
577 struct hist_entry entry = { 584 struct hist_entry entry = {
578 .thread = al->thread, 585 .thread = al->thread,
579 .comm = thread__comm(al->thread), 586 .comm = thread__comm(al->thread),
587 .cgroup_id = {
588 .dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
589 .ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
590 },
580 .ms = { 591 .ms = {
581 .map = al->map, 592 .map = al->map,
582 .sym = al->sym, 593 .sym = al->sym,
@@ -1129,6 +1140,11 @@ void hist_entry__delete(struct hist_entry *he)
1129 zfree(&he->mem_info); 1140 zfree(&he->mem_info);
1130 } 1141 }
1131 1142
1143 if (he->inline_node) {
1144 inline_node__delete(he->inline_node);
1145 he->inline_node = NULL;
1146 }
1147
1132 zfree(&he->stat_acc); 1148 zfree(&he->stat_acc);
1133 free_srcline(he->srcline); 1149 free_srcline(he->srcline);
1134 if (he->srcfile && he->srcfile[0]) 1150 if (he->srcfile && he->srcfile[0])
@@ -2447,7 +2463,7 @@ int parse_filter_percentage(const struct option *opt __maybe_unused,
2447 else if (!strcmp(arg, "absolute")) 2463 else if (!strcmp(arg, "absolute"))
2448 symbol_conf.filter_relative = false; 2464 symbol_conf.filter_relative = false;
2449 else { 2465 else {
2450 pr_debug("Invalud percentage: %s\n", arg); 2466 pr_debug("Invalid percentage: %s\n", arg);
2451 return -1; 2467 return -1;
2452 } 2468 }
2453 2469
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 28c216e3d5b7..ee3670a388df 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -30,6 +30,7 @@ enum hist_column {
30 HISTC_DSO, 30 HISTC_DSO,
31 HISTC_THREAD, 31 HISTC_THREAD,
32 HISTC_COMM, 32 HISTC_COMM,
33 HISTC_CGROUP_ID,
33 HISTC_PARENT, 34 HISTC_PARENT,
34 HISTC_CPU, 35 HISTC_CPU,
35 HISTC_SOCKET, 36 HISTC_SOCKET,
@@ -57,6 +58,7 @@ enum hist_column {
57 HISTC_SRCLINE_FROM, 58 HISTC_SRCLINE_FROM,
58 HISTC_SRCLINE_TO, 59 HISTC_SRCLINE_TO,
59 HISTC_TRACE, 60 HISTC_TRACE,
61 HISTC_SYM_SIZE,
60 HISTC_NR_COLS, /* Last entry */ 62 HISTC_NR_COLS, /* Last entry */
61}; 63};
62 64
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
index 6c2eb5da4afc..b2834ac7b1f5 100644
--- a/tools/perf/util/intel-bts.c
+++ b/tools/perf/util/intel-bts.c
@@ -14,7 +14,9 @@
14 */ 14 */
15 15
16#include <endian.h> 16#include <endian.h>
17#include <errno.h>
17#include <byteswap.h> 18#include <byteswap.h>
19#include <inttypes.h>
18#include <linux/kernel.h> 20#include <linux/kernel.h>
19#include <linux/types.h> 21#include <linux/types.h>
20#include <linux/bitops.h> 22#include <linux/bitops.h>
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
index 4f3c758d875d..54818828023b 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c
@@ -26,6 +26,7 @@
26#include "insn.c" 26#include "insn.c"
27 27
28#include "intel-pt-insn-decoder.h" 28#include "intel-pt-insn-decoder.h"
29#include "dump-insn.h"
29 30
30#if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN 31#if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN
31#error Instruction buffer size too small 32#error Instruction buffer size too small
@@ -39,6 +40,8 @@ static void intel_pt_insn_decoder(struct insn *insn,
39 enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH; 40 enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH;
40 int ext; 41 int ext;
41 42
43 intel_pt_insn->rel = 0;
44
42 if (insn_is_avx(insn)) { 45 if (insn_is_avx(insn)) {
43 intel_pt_insn->op = INTEL_PT_OP_OTHER; 46 intel_pt_insn->op = INTEL_PT_OP_OTHER;
44 intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH; 47 intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;
@@ -177,6 +180,29 @@ int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
177 return 0; 180 return 0;
178} 181}
179 182
183const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
184 u8 *inbuf, int inlen, int *lenp)
185{
186 struct insn insn;
187 int n, i;
188 int left;
189
190 insn_init(&insn, inbuf, inlen, x->is64bit);
191 insn_get_length(&insn);
192 if (!insn_complete(&insn) || insn.length > inlen)
193 return "<bad>";
194 if (lenp)
195 *lenp = insn.length;
196 left = sizeof(x->out);
197 n = snprintf(x->out, left, "insn: ");
198 left -= n;
199 for (i = 0; i < insn.length; i++) {
200 n += snprintf(x->out + n, left, "%02x ", inbuf[i]);
201 left -= n;
202 }
203 return x->out;
204}
205
180const char *branch_name[] = { 206const char *branch_name[] = {
181 [INTEL_PT_OP_OTHER] = "Other", 207 [INTEL_PT_OP_OTHER] = "Other",
182 [INTEL_PT_OP_CALL] = "Call", 208 [INTEL_PT_OP_CALL] = "Call",
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index da20cd5612e9..4c7718f87a08 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -13,6 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16#include <inttypes.h>
16#include <stdio.h> 17#include <stdio.h>
17#include <stdbool.h> 18#include <stdbool.h>
18#include <errno.h> 19#include <errno.h>
@@ -22,6 +23,7 @@
22#include "../perf.h" 23#include "../perf.h"
23#include "session.h" 24#include "session.h"
24#include "machine.h" 25#include "machine.h"
26#include "memswap.h"
25#include "sort.h" 27#include "sort.h"
26#include "tool.h" 28#include "tool.h"
27#include "event.h" 29#include "event.h"
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
index c9a941ef0f6d..9084930e1757 100644
--- a/tools/perf/util/jitdump.c
+++ b/tools/perf/util/jitdump.c
@@ -1,5 +1,6 @@
1#include <sys/sysmacros.h> 1#include <sys/sysmacros.h>
2#include <sys/types.h> 2#include <sys/types.h>
3#include <errno.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <string.h> 6#include <string.h>
@@ -9,13 +10,13 @@
9#include <byteswap.h> 10#include <byteswap.h>
10#include <sys/stat.h> 11#include <sys/stat.h>
11#include <sys/mman.h> 12#include <sys/mman.h>
13#include <linux/stringify.h>
12 14
13#include "util.h" 15#include "util.h"
14#include "event.h" 16#include "event.h"
15#include "debug.h" 17#include "debug.h"
16#include "evlist.h" 18#include "evlist.h"
17#include "symbol.h" 19#include "symbol.h"
18#include "strlist.h"
19#include <elf.h> 20#include <elf.h>
20 21
21#include "tsc.h" 22#include "tsc.h"
@@ -25,6 +26,8 @@
25#include "genelf.h" 26#include "genelf.h"
26#include "../builtin.h" 27#include "../builtin.h"
27 28
29#include "sane_ctype.h"
30
28struct jit_buf_desc { 31struct jit_buf_desc {
29 struct perf_data_file *output; 32 struct perf_data_file *output;
30 struct perf_session *session; 33 struct perf_session *session;
@@ -181,7 +184,7 @@ jit_open(struct jit_buf_desc *jd, const char *name)
181 jd->use_arch_timestamp); 184 jd->use_arch_timestamp);
182 185
183 if (header.version > JITHEADER_VERSION) { 186 if (header.version > JITHEADER_VERSION) {
184 pr_err("wrong jitdump version %u, expected " STR(JITHEADER_VERSION), 187 pr_err("wrong jitdump version %u, expected " __stringify(JITHEADER_VERSION),
185 header.version); 188 header.version);
186 goto error; 189 goto error;
187 } 190 }
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 824356488ce6..c6a15f204c03 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -12,6 +12,7 @@
12#include "llvm-utils.h" 12#include "llvm-utils.h"
13#include "config.h" 13#include "config.h"
14#include "util.h" 14#include "util.h"
15#include <sys/wait.h>
15 16
16#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ 17#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
17 "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ 18 "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c
index 9ddea5cecd94..4ca7c5c6cdcd 100644
--- a/tools/perf/util/lzma.c
+++ b/tools/perf/util/lzma.c
@@ -1,6 +1,8 @@
1#include <errno.h>
1#include <lzma.h> 2#include <lzma.h>
2#include <stdio.h> 3#include <stdio.h>
3#include <linux/compiler.h> 4#include <linux/compiler.h>
5#include "compress.h"
4#include "util.h" 6#include "util.h"
5#include "debug.h" 7#include "debug.h"
6 8
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 71c9720d4973..d97e014c3df3 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1,3 +1,7 @@
1#include <dirent.h>
2#include <errno.h>
3#include <inttypes.h>
4#include <regex.h>
1#include "callchain.h" 5#include "callchain.h"
2#include "debug.h" 6#include "debug.h"
3#include "event.h" 7#include "event.h"
@@ -10,9 +14,15 @@
10#include "thread.h" 14#include "thread.h"
11#include "vdso.h" 15#include "vdso.h"
12#include <stdbool.h> 16#include <stdbool.h>
13#include <symbol/kallsyms.h> 17#include <sys/types.h>
18#include <sys/stat.h>
19#include <unistd.h>
14#include "unwind.h" 20#include "unwind.h"
15#include "linux/hash.h" 21#include "linux/hash.h"
22#include "asm/bug.h"
23
24#include "sane_ctype.h"
25#include <symbol/kallsyms.h>
16 26
17static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock); 27static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);
18 28
@@ -501,6 +511,37 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
501 return err; 511 return err;
502} 512}
503 513
514int machine__process_namespaces_event(struct machine *machine __maybe_unused,
515 union perf_event *event,
516 struct perf_sample *sample __maybe_unused)
517{
518 struct thread *thread = machine__findnew_thread(machine,
519 event->namespaces.pid,
520 event->namespaces.tid);
521 int err = 0;
522
523 WARN_ONCE(event->namespaces.nr_namespaces > NR_NAMESPACES,
524 "\nWARNING: kernel seems to support more namespaces than perf"
525 " tool.\nTry updating the perf tool..\n\n");
526
527 WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES,
528 "\nWARNING: perf tool seems to support more namespaces than"
529 " the kernel.\nTry updating the kernel..\n\n");
530
531 if (dump_trace)
532 perf_event__fprintf_namespaces(event, stdout);
533
534 if (thread == NULL ||
535 thread__set_namespaces(thread, sample->time, &event->namespaces)) {
536 dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n");
537 err = -1;
538 }
539
540 thread__put(thread);
541
542 return err;
543}
544
504int machine__process_lost_event(struct machine *machine __maybe_unused, 545int machine__process_lost_event(struct machine *machine __maybe_unused,
505 union perf_event *event, struct perf_sample *sample __maybe_unused) 546 union perf_event *event, struct perf_sample *sample __maybe_unused)
506{ 547{
@@ -755,11 +796,11 @@ const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
755 * Returns the name of the start symbol in *symbol_name. Pass in NULL as 796 * Returns the name of the start symbol in *symbol_name. Pass in NULL as
756 * symbol_name if it's not that important. 797 * symbol_name if it's not that important.
757 */ 798 */
758static u64 machine__get_running_kernel_start(struct machine *machine, 799static int machine__get_running_kernel_start(struct machine *machine,
759 const char **symbol_name) 800 const char **symbol_name, u64 *start)
760{ 801{
761 char filename[PATH_MAX]; 802 char filename[PATH_MAX];
762 int i; 803 int i, err = -1;
763 const char *name; 804 const char *name;
764 u64 addr = 0; 805 u64 addr = 0;
765 806
@@ -769,21 +810,28 @@ static u64 machine__get_running_kernel_start(struct machine *machine,
769 return 0; 810 return 0;
770 811
771 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { 812 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
772 addr = kallsyms__get_function_start(filename, name); 813 err = kallsyms__get_function_start(filename, name, &addr);
773 if (addr) 814 if (!err)
774 break; 815 break;
775 } 816 }
776 817
818 if (err)
819 return -1;
820
777 if (symbol_name) 821 if (symbol_name)
778 *symbol_name = name; 822 *symbol_name = name;
779 823
780 return addr; 824 *start = addr;
825 return 0;
781} 826}
782 827
783int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 828int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
784{ 829{
785 int type; 830 int type;
786 u64 start = machine__get_running_kernel_start(machine, NULL); 831 u64 start = 0;
832
833 if (machine__get_running_kernel_start(machine, NULL, &start))
834 return -1;
787 835
788 /* In case of renewal the kernel map, destroy previous one */ 836 /* In case of renewal the kernel map, destroy previous one */
789 machine__destroy_kernel_maps(machine); 837 machine__destroy_kernel_maps(machine);
@@ -1144,8 +1192,8 @@ static int machine__create_modules(struct machine *machine)
1144int machine__create_kernel_maps(struct machine *machine) 1192int machine__create_kernel_maps(struct machine *machine)
1145{ 1193{
1146 struct dso *kernel = machine__get_kernel(machine); 1194 struct dso *kernel = machine__get_kernel(machine);
1147 const char *name; 1195 const char *name = NULL;
1148 u64 addr; 1196 u64 addr = 0;
1149 int ret; 1197 int ret;
1150 1198
1151 if (kernel == NULL) 1199 if (kernel == NULL)
@@ -1170,8 +1218,7 @@ int machine__create_kernel_maps(struct machine *machine)
1170 */ 1218 */
1171 map_groups__fixup_end(&machine->kmaps); 1219 map_groups__fixup_end(&machine->kmaps);
1172 1220
1173 addr = machine__get_running_kernel_start(machine, &name); 1221 if (machine__get_running_kernel_start(machine, &name, &addr)) {
1174 if (!addr) {
1175 } else if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) { 1222 } else if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) {
1176 machine__destroy_kernel_maps(machine); 1223 machine__destroy_kernel_maps(machine);
1177 return -1; 1224 return -1;
@@ -1439,7 +1486,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th,
1439 if (machine->last_match == th) 1486 if (machine->last_match == th)
1440 machine->last_match = NULL; 1487 machine->last_match = NULL;
1441 1488
1442 BUG_ON(atomic_read(&th->refcnt) == 0); 1489 BUG_ON(refcount_read(&th->refcnt) == 0);
1443 if (lock) 1490 if (lock)
1444 pthread_rwlock_wrlock(&machine->threads_lock); 1491 pthread_rwlock_wrlock(&machine->threads_lock);
1445 rb_erase_init(&th->rb_node, &machine->threads); 1492 rb_erase_init(&th->rb_node, &machine->threads);
@@ -1538,6 +1585,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
1538 ret = machine__process_comm_event(machine, event, sample); break; 1585 ret = machine__process_comm_event(machine, event, sample); break;
1539 case PERF_RECORD_MMAP: 1586 case PERF_RECORD_MMAP:
1540 ret = machine__process_mmap_event(machine, event, sample); break; 1587 ret = machine__process_mmap_event(machine, event, sample); break;
1588 case PERF_RECORD_NAMESPACES:
1589 ret = machine__process_namespaces_event(machine, event, sample); break;
1541 case PERF_RECORD_MMAP2: 1590 case PERF_RECORD_MMAP2:
1542 ret = machine__process_mmap2_event(machine, event, sample); break; 1591 ret = machine__process_mmap2_event(machine, event, sample); break;
1543 case PERF_RECORD_FORK: 1592 case PERF_RECORD_FORK:
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index a28305029711..3cdb1340f917 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -97,6 +97,9 @@ int machine__process_itrace_start_event(struct machine *machine,
97 union perf_event *event); 97 union perf_event *event);
98int machine__process_switch_event(struct machine *machine, 98int machine__process_switch_event(struct machine *machine,
99 union perf_event *event); 99 union perf_event *event);
100int machine__process_namespaces_event(struct machine *machine,
101 union perf_event *event,
102 struct perf_sample *sample);
100int machine__process_mmap_event(struct machine *machine, union perf_event *event, 103int machine__process_mmap_event(struct machine *machine, union perf_event *event,
101 struct perf_sample *sample); 104 struct perf_sample *sample);
102int machine__process_mmap2_event(struct machine *machine, union perf_event *event, 105int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 0a943e7b1ea7..2179b2deb730 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -9,13 +9,13 @@
9#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 9#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
10#include "map.h" 10#include "map.h"
11#include "thread.h" 11#include "thread.h"
12#include "strlist.h"
13#include "vdso.h" 12#include "vdso.h"
14#include "build-id.h" 13#include "build-id.h"
15#include "util.h" 14#include "util.h"
16#include "debug.h" 15#include "debug.h"
17#include "machine.h" 16#include "machine.h"
18#include <linux/string.h> 17#include <linux/string.h>
18#include "srcline.h"
19#include "unwind.h" 19#include "unwind.h"
20 20
21static void __maps__insert(struct maps *maps, struct map *map); 21static void __maps__insert(struct maps *maps, struct map *map);
@@ -141,7 +141,7 @@ void map__init(struct map *map, enum map_type type,
141 RB_CLEAR_NODE(&map->rb_node); 141 RB_CLEAR_NODE(&map->rb_node);
142 map->groups = NULL; 142 map->groups = NULL;
143 map->erange_warned = false; 143 map->erange_warned = false;
144 atomic_set(&map->refcnt, 1); 144 refcount_set(&map->refcnt, 1);
145} 145}
146 146
147struct map *map__new(struct machine *machine, u64 start, u64 len, 147struct map *map__new(struct machine *machine, u64 start, u64 len,
@@ -255,7 +255,7 @@ void map__delete(struct map *map)
255 255
256void map__put(struct map *map) 256void map__put(struct map *map)
257{ 257{
258 if (map && atomic_dec_and_test(&map->refcnt)) 258 if (map && refcount_dec_and_test(&map->refcnt))
259 map__delete(map); 259 map__delete(map);
260} 260}
261 261
@@ -325,11 +325,6 @@ int map__load(struct map *map)
325 return 0; 325 return 0;
326} 326}
327 327
328int __weak arch__compare_symbol_names(const char *namea, const char *nameb)
329{
330 return strcmp(namea, nameb);
331}
332
333struct symbol *map__find_symbol(struct map *map, u64 addr) 328struct symbol *map__find_symbol(struct map *map, u64 addr)
334{ 329{
335 if (map__load(map) < 0) 330 if (map__load(map) < 0)
@@ -354,7 +349,7 @@ struct map *map__clone(struct map *from)
354 struct map *map = memdup(from, sizeof(*map)); 349 struct map *map = memdup(from, sizeof(*map));
355 350
356 if (map != NULL) { 351 if (map != NULL) {
357 atomic_set(&map->refcnt, 1); 352 refcount_set(&map->refcnt, 1);
358 RB_CLEAR_NODE(&map->rb_node); 353 RB_CLEAR_NODE(&map->rb_node);
359 dso__get(map->dso); 354 dso__get(map->dso);
360 map->groups = NULL; 355 map->groups = NULL;
@@ -405,7 +400,8 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
405 400
406 if (map && map->dso) { 401 if (map && map->dso) {
407 srcline = get_srcline(map->dso, 402 srcline = get_srcline(map->dso,
408 map__rip_2objdump(map, addr), NULL, true); 403 map__rip_2objdump(map, addr), NULL,
404 true, true);
409 if (srcline != SRCLINE_UNKNOWN) 405 if (srcline != SRCLINE_UNKNOWN)
410 ret = fprintf(fp, "%s%s", prefix, srcline); 406 ret = fprintf(fp, "%s%s", prefix, srcline);
411 free_srcline(srcline); 407 free_srcline(srcline);
@@ -485,7 +481,7 @@ void map_groups__init(struct map_groups *mg, struct machine *machine)
485 maps__init(&mg->maps[i]); 481 maps__init(&mg->maps[i]);
486 } 482 }
487 mg->machine = machine; 483 mg->machine = machine;
488 atomic_set(&mg->refcnt, 1); 484 refcount_set(&mg->refcnt, 1);
489} 485}
490 486
491static void __maps__purge(struct maps *maps) 487static void __maps__purge(struct maps *maps)
@@ -547,7 +543,7 @@ void map_groups__delete(struct map_groups *mg)
547 543
548void map_groups__put(struct map_groups *mg) 544void map_groups__put(struct map_groups *mg)
549{ 545{
550 if (mg && atomic_dec_and_test(&mg->refcnt)) 546 if (mg && refcount_dec_and_test(&mg->refcnt))
551 map_groups__delete(mg); 547 map_groups__delete(mg);
552} 548}
553 549
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index abdacf800c98..f9e8ac8a52cd 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_MAP_H 1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H 2#define __PERF_MAP_H
3 3
4#include <linux/atomic.h> 4#include <linux/refcount.h>
5#include <linux/compiler.h> 5#include <linux/compiler.h>
6#include <linux/list.h> 6#include <linux/list.h>
7#include <linux/rbtree.h> 7#include <linux/rbtree.h>
@@ -51,7 +51,7 @@ struct map {
51 51
52 struct dso *dso; 52 struct dso *dso;
53 struct map_groups *groups; 53 struct map_groups *groups;
54 atomic_t refcnt; 54 refcount_t refcnt;
55}; 55};
56 56
57struct kmap { 57struct kmap {
@@ -67,7 +67,7 @@ struct maps {
67struct map_groups { 67struct map_groups {
68 struct maps maps[MAP__NR_TYPES]; 68 struct maps maps[MAP__NR_TYPES];
69 struct machine *machine; 69 struct machine *machine;
70 atomic_t refcnt; 70 refcount_t refcnt;
71}; 71};
72 72
73struct map_groups *map_groups__new(struct machine *machine); 73struct map_groups *map_groups__new(struct machine *machine);
@@ -77,7 +77,7 @@ bool map_groups__empty(struct map_groups *mg);
77static inline struct map_groups *map_groups__get(struct map_groups *mg) 77static inline struct map_groups *map_groups__get(struct map_groups *mg)
78{ 78{
79 if (mg) 79 if (mg)
80 atomic_inc(&mg->refcnt); 80 refcount_inc(&mg->refcnt);
81 return mg; 81 return mg;
82} 82}
83 83
@@ -130,13 +130,14 @@ struct thread;
130 */ 130 */
131#define __map__for_each_symbol_by_name(map, sym_name, pos) \ 131#define __map__for_each_symbol_by_name(map, sym_name, pos) \
132 for (pos = map__find_symbol_by_name(map, sym_name); \ 132 for (pos = map__find_symbol_by_name(map, sym_name); \
133 pos && arch__compare_symbol_names(pos->name, sym_name) == 0; \ 133 pos && \
134 !symbol__match_symbol_name(pos->name, sym_name, \
135 SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); \
134 pos = symbol__next_by_name(pos)) 136 pos = symbol__next_by_name(pos))
135 137
136#define map__for_each_symbol_by_name(map, sym_name, pos) \ 138#define map__for_each_symbol_by_name(map, sym_name, pos) \
137 __map__for_each_symbol_by_name(map, sym_name, (pos)) 139 __map__for_each_symbol_by_name(map, sym_name, (pos))
138 140
139int arch__compare_symbol_names(const char *namea, const char *nameb);
140void map__init(struct map *map, enum map_type type, 141void map__init(struct map *map, enum map_type type,
141 u64 start, u64 end, u64 pgoff, struct dso *dso); 142 u64 start, u64 end, u64 pgoff, struct dso *dso);
142struct map *map__new(struct machine *machine, u64 start, u64 len, 143struct map *map__new(struct machine *machine, u64 start, u64 len,
@@ -150,7 +151,7 @@ struct map *map__clone(struct map *map);
150static inline struct map *map__get(struct map *map) 151static inline struct map *map__get(struct map *map)
151{ 152{
152 if (map) 153 if (map)
153 atomic_inc(&map->refcnt); 154 refcount_inc(&map->refcnt);
154 return map; 155 return map;
155} 156}
156 157
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
index 1d4ab53c60ca..06f5a3a4295c 100644
--- a/tools/perf/util/mem-events.c
+++ b/tools/perf/util/mem-events.c
@@ -6,6 +6,7 @@
6#include <sys/stat.h> 6#include <sys/stat.h>
7#include <unistd.h> 7#include <unistd.h>
8#include <api/fs/fs.h> 8#include <api/fs/fs.h>
9#include <linux/kernel.h>
9#include "mem-events.h" 10#include "mem-events.h"
10#include "debug.h" 11#include "debug.h"
11#include "symbol.h" 12#include "symbol.h"
@@ -205,8 +206,8 @@ int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
205static const char * const snoop_access[] = { 206static const char * const snoop_access[] = {
206 "N/A", 207 "N/A",
207 "None", 208 "None",
208 "Miss",
209 "Hit", 209 "Hit",
210 "Miss",
210 "HitM", 211 "HitM",
211}; 212};
212 213
diff --git a/tools/perf/util/memswap.c b/tools/perf/util/memswap.c
new file mode 100644
index 000000000000..55f7faa8d9ec
--- /dev/null
+++ b/tools/perf/util/memswap.c
@@ -0,0 +1,24 @@
1#include <byteswap.h>
2#include "memswap.h"
3#include <linux/types.h>
4
5void mem_bswap_32(void *src, int byte_size)
6{
7 u32 *m = src;
8 while (byte_size > 0) {
9 *m = bswap_32(*m);
10 byte_size -= sizeof(u32);
11 ++m;
12 }
13}
14
15void mem_bswap_64(void *src, int byte_size)
16{
17 u64 *m = src;
18
19 while (byte_size > 0) {
20 *m = bswap_64(*m);
21 byte_size -= sizeof(u64);
22 ++m;
23 }
24}
diff --git a/tools/perf/util/memswap.h b/tools/perf/util/memswap.h
new file mode 100644
index 000000000000..7d1b1c34bb57
--- /dev/null
+++ b/tools/perf/util/memswap.h
@@ -0,0 +1,7 @@
1#ifndef PERF_MEMSWAP_H_
2#define PERF_MEMSWAP_H_
3
4void mem_bswap_64(void *src, int byte_size);
5void mem_bswap_32(void *src, int byte_size);
6
7#endif /* PERF_MEMSWAP_H_ */
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c
new file mode 100644
index 000000000000..67dcbcc73c7d
--- /dev/null
+++ b/tools/perf/util/namespaces.c
@@ -0,0 +1,37 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
7 */
8
9#include "namespaces.h"
10#include "util.h"
11#include "event.h"
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15
16struct namespaces *namespaces__new(struct namespaces_event *event)
17{
18 struct namespaces *namespaces;
19 u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
20 sizeof(struct perf_ns_link_info));
21
22 namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
23 if (!namespaces)
24 return NULL;
25
26 namespaces->end_time = -1;
27
28 if (event)
29 memcpy(namespaces->link_info, event->link_info, link_info_size);
30
31 return namespaces;
32}
33
34void namespaces__free(struct namespaces *namespaces)
35{
36 free(namespaces);
37}
diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h
new file mode 100644
index 000000000000..468f1e9a1484
--- /dev/null
+++ b/tools/perf/util/namespaces.h
@@ -0,0 +1,26 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
7 */
8
9#ifndef __PERF_NAMESPACES_H
10#define __PERF_NAMESPACES_H
11
12#include "../perf.h"
13#include <linux/list.h>
14
15struct namespaces_event;
16
17struct namespaces {
18 struct list_head list;
19 u64 end_time;
20 struct perf_ns_link_info link_info[];
21};
22
23struct namespaces *namespaces__new(struct namespaces_event *event);
24void namespaces__free(struct namespaces *namespaces);
25
26#endif /* __PERF_NAMESPACES_H */
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
index fe84df1875aa..4de398cfb577 100644
--- a/tools/perf/util/ordered-events.c
+++ b/tools/perf/util/ordered-events.c
@@ -1,3 +1,5 @@
1#include <errno.h>
2#include <inttypes.h>
1#include <linux/list.h> 3#include <linux/list.h>
2#include <linux/compiler.h> 4#include <linux/compiler.h>
3#include <linux/string.h> 5#include <linux/string.h>
@@ -79,7 +81,7 @@ static union perf_event *dup_event(struct ordered_events *oe,
79 81
80static void free_dup_event(struct ordered_events *oe, union perf_event *event) 82static void free_dup_event(struct ordered_events *oe, union perf_event *event)
81{ 83{
82 if (oe->copy_on_queue) { 84 if (event && oe->copy_on_queue) {
83 oe->cur_alloc_size -= event->header.size; 85 oe->cur_alloc_size -= event->header.size;
84 free(event); 86 free(event);
85 } 87 }
@@ -150,6 +152,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve
150 list_move(&event->list, &oe->cache); 152 list_move(&event->list, &oe->cache);
151 oe->nr_events--; 153 oe->nr_events--;
152 free_dup_event(oe, event->event); 154 free_dup_event(oe, event->event);
155 event->event = NULL;
153} 156}
154 157
155int ordered_events__queue(struct ordered_events *oe, union perf_event *event, 158int ordered_events__queue(struct ordered_events *oe, union perf_event *event,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 67a8aebc67ab..01e779b91c8e 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,13 +1,18 @@
1#include <linux/hw_breakpoint.h> 1#include <linux/hw_breakpoint.h>
2#include <linux/err.h> 2#include <linux/err.h>
3#include "util.h" 3#include <dirent.h>
4#include <errno.h>
5#include <sys/ioctl.h>
6#include <sys/param.h>
7#include "term.h"
4#include "../perf.h" 8#include "../perf.h"
5#include "evlist.h" 9#include "evlist.h"
6#include "evsel.h" 10#include "evsel.h"
7#include <subcmd/parse-options.h> 11#include <subcmd/parse-options.h>
8#include "parse-events.h" 12#include "parse-events.h"
9#include <subcmd/exec-cmd.h> 13#include <subcmd/exec-cmd.h>
10#include "string.h" 14#include "string2.h"
15#include "strlist.h"
11#include "symbol.h" 16#include "symbol.h"
12#include "cache.h" 17#include "cache.h"
13#include "header.h" 18#include "header.h"
@@ -316,8 +321,9 @@ __add_event(struct list_head *list, int *idx,
316 return NULL; 321 return NULL;
317 322
318 (*idx)++; 323 (*idx)++;
319 evsel->cpus = cpu_map__get(cpus); 324 evsel->cpus = cpu_map__get(cpus);
320 evsel->own_cpus = cpu_map__get(cpus); 325 evsel->own_cpus = cpu_map__get(cpus);
326 evsel->system_wide = !!cpus;
321 327
322 if (name) 328 if (name)
323 evsel->name = strdup(name); 329 evsel->name = strdup(name);
@@ -1254,11 +1260,59 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
1254 evsel->scale = info.scale; 1260 evsel->scale = info.scale;
1255 evsel->per_pkg = info.per_pkg; 1261 evsel->per_pkg = info.per_pkg;
1256 evsel->snapshot = info.snapshot; 1262 evsel->snapshot = info.snapshot;
1263 evsel->metric_expr = info.metric_expr;
1264 evsel->metric_name = info.metric_name;
1257 } 1265 }
1258 1266
1259 return evsel ? 0 : -ENOMEM; 1267 return evsel ? 0 : -ENOMEM;
1260} 1268}
1261 1269
1270int parse_events_multi_pmu_add(struct parse_events_evlist *data,
1271 char *str, struct list_head **listp)
1272{
1273 struct list_head *head;
1274 struct parse_events_term *term;
1275 struct list_head *list;
1276 struct perf_pmu *pmu = NULL;
1277 int ok = 0;
1278
1279 *listp = NULL;
1280 /* Add it for all PMUs that support the alias */
1281 list = malloc(sizeof(struct list_head));
1282 if (!list)
1283 return -1;
1284 INIT_LIST_HEAD(list);
1285 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
1286 struct perf_pmu_alias *alias;
1287
1288 list_for_each_entry(alias, &pmu->aliases, list) {
1289 if (!strcasecmp(alias->name, str)) {
1290 head = malloc(sizeof(struct list_head));
1291 if (!head)
1292 return -1;
1293 INIT_LIST_HEAD(head);
1294 if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
1295 str, 1, false, &str, NULL) < 0)
1296 return -1;
1297 list_add_tail(&term->list, head);
1298
1299 if (!parse_events_add_pmu(data, list,
1300 pmu->name, head)) {
1301 pr_debug("%s -> %s/%s/\n", str,
1302 pmu->name, alias->str);
1303 ok++;
1304 }
1305
1306 parse_events_terms__delete(head);
1307 }
1308 }
1309 }
1310 if (!ok)
1311 return -1;
1312 *listp = list;
1313 return 0;
1314}
1315
1262int parse_events__modifier_group(struct list_head *list, 1316int parse_events__modifier_group(struct list_head *list,
1263 char *event_mod) 1317 char *event_mod)
1264{ 1318{
@@ -2276,7 +2330,7 @@ out_enomem:
2276 * Print the help text for the event symbols: 2330 * Print the help text for the event symbols:
2277 */ 2331 */
2278void print_events(const char *event_glob, bool name_only, bool quiet_flag, 2332void print_events(const char *event_glob, bool name_only, bool quiet_flag,
2279 bool long_desc) 2333 bool long_desc, bool details_flag)
2280{ 2334{
2281 print_symbol_events(event_glob, PERF_TYPE_HARDWARE, 2335 print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
2282 event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 2336 event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
@@ -2286,7 +2340,8 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag,
2286 2340
2287 print_hwcache_events(event_glob, name_only); 2341 print_hwcache_events(event_glob, name_only);
2288 2342
2289 print_pmu_events(event_glob, name_only, quiet_flag, long_desc); 2343 print_pmu_events(event_glob, name_only, quiet_flag, long_desc,
2344 details_flag);
2290 2345
2291 if (event_glob != NULL) 2346 if (event_glob != NULL)
2292 return; 2347 return;
@@ -2415,6 +2470,31 @@ int parse_events_term__clone(struct parse_events_term **new,
2415 return new_term(new, &temp, term->val.str, term->val.num); 2470 return new_term(new, &temp, term->val.str, term->val.num);
2416} 2471}
2417 2472
2473int parse_events_copy_term_list(struct list_head *old,
2474 struct list_head **new)
2475{
2476 struct parse_events_term *term, *n;
2477 int ret;
2478
2479 if (!old) {
2480 *new = NULL;
2481 return 0;
2482 }
2483
2484 *new = malloc(sizeof(struct list_head));
2485 if (!*new)
2486 return -ENOMEM;
2487 INIT_LIST_HEAD(*new);
2488
2489 list_for_each_entry (term, old, list) {
2490 ret = parse_events_term__clone(&n, term);
2491 if (ret)
2492 return ret;
2493 list_add_tail(&n->list, *new);
2494 }
2495 return 0;
2496}
2497
2418void parse_events_terms__purge(struct list_head *terms) 2498void parse_events_terms__purge(struct list_head *terms)
2419{ 2499{
2420 struct parse_events_term *term, *h; 2500 struct parse_events_term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 1af6a267c21b..a235f4d6d5e5 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -8,6 +8,7 @@
8#include <stdbool.h> 8#include <stdbool.h>
9#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/perf_event.h> 10#include <linux/perf_event.h>
11#include <string.h>
11 12
12struct list_head; 13struct list_head;
13struct perf_evsel; 14struct perf_evsel;
@@ -166,6 +167,14 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
166int parse_events_add_pmu(struct parse_events_evlist *data, 167int parse_events_add_pmu(struct parse_events_evlist *data,
167 struct list_head *list, char *name, 168 struct list_head *list, char *name,
168 struct list_head *head_config); 169 struct list_head *head_config);
170
171int parse_events_multi_pmu_add(struct parse_events_evlist *data,
172 char *str,
173 struct list_head **listp);
174
175int parse_events_copy_term_list(struct list_head *old,
176 struct list_head **new);
177
169enum perf_pmu_event_symbol_type 178enum perf_pmu_event_symbol_type
170perf_pmu__parse_check(const char *name); 179perf_pmu__parse_check(const char *name);
171void parse_events__set_leader(char *name, struct list_head *list); 180void parse_events__set_leader(char *name, struct list_head *list);
@@ -175,7 +184,7 @@ void parse_events_evlist_error(struct parse_events_evlist *data,
175 int idx, const char *str); 184 int idx, const char *str);
176 185
177void print_events(const char *event_glob, bool name_only, bool quiet, 186void print_events(const char *event_glob, bool name_only, bool quiet,
178 bool long_desc); 187 bool long_desc, bool details_flag);
179 188
180struct event_symbol { 189struct event_symbol {
181 const char *symbol; 190 const char *symbol;
@@ -196,4 +205,23 @@ int is_valid_tracepoint(const char *event_string);
196int valid_event_mount(const char *eventfs); 205int valid_event_mount(const char *eventfs);
197char *parse_events_formats_error_string(char *additional_terms); 206char *parse_events_formats_error_string(char *additional_terms);
198 207
208#ifdef HAVE_LIBELF_SUPPORT
209/*
210 * If the probe point starts with '%',
211 * or starts with "sdt_" and has a ':' but no '=',
212 * then it should be a SDT/cached probe point.
213 */
214static inline bool is_sdt_event(char *str)
215{
216 return (str[0] == '%' ||
217 (!strncmp(str, "sdt_", 4) &&
218 !!strchr(str, ':') && !strchr(str, '=')));
219}
220#else
221static inline bool is_sdt_event(char *str __maybe_unused)
222{
223 return false;
224}
225#endif /* HAVE_LIBELF_SUPPORT */
226
199#endif /* __PERF_PARSE_EVENTS_H */ 227#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 30f018ea1370..04fd8c9af9f9 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -226,68 +226,55 @@ event_pmu:
226PE_NAME opt_event_config 226PE_NAME opt_event_config
227{ 227{
228 struct parse_events_evlist *data = _data; 228 struct parse_events_evlist *data = _data;
229 struct list_head *list; 229 struct list_head *list, *orig_terms, *terms;
230
231 if (parse_events_copy_term_list($2, &orig_terms))
232 YYABORT;
230 233
231 ALLOC_LIST(list); 234 ALLOC_LIST(list);
232 ABORT_ON(parse_events_add_pmu(data, list, $1, $2)); 235 if (parse_events_add_pmu(data, list, $1, $2)) {
236 struct perf_pmu *pmu = NULL;
237 int ok = 0;
238
239 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
240 char *name = pmu->name;
241
242 if (!strncmp(name, "uncore_", 7) &&
243 strncmp($1, "uncore_", 7))
244 name += 7;
245 if (!strncmp($1, name, strlen($1))) {
246 if (parse_events_copy_term_list(orig_terms, &terms))
247 YYABORT;
248 if (!parse_events_add_pmu(data, list, pmu->name, terms))
249 ok++;
250 parse_events_terms__delete(terms);
251 }
252 }
253 if (!ok)
254 YYABORT;
255 }
233 parse_events_terms__delete($2); 256 parse_events_terms__delete($2);
257 parse_events_terms__delete(orig_terms);
234 $$ = list; 258 $$ = list;
235} 259}
236| 260|
237PE_KERNEL_PMU_EVENT sep_dc 261PE_KERNEL_PMU_EVENT sep_dc
238{ 262{
239 struct parse_events_evlist *data = _data;
240 struct list_head *head;
241 struct parse_events_term *term;
242 struct list_head *list; 263 struct list_head *list;
243 struct perf_pmu *pmu = NULL;
244 int ok = 0;
245
246 /* Add it for all PMUs that support the alias */
247 ALLOC_LIST(list);
248 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
249 struct perf_pmu_alias *alias;
250
251 list_for_each_entry(alias, &pmu->aliases, list) {
252 if (!strcasecmp(alias->name, $1)) {
253 ALLOC_LIST(head);
254 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
255 $1, 1, false, &@1, NULL));
256 list_add_tail(&term->list, head);
257
258 if (!parse_events_add_pmu(data, list,
259 pmu->name, head)) {
260 pr_debug("%s -> %s/%s/\n", $1,
261 pmu->name, alias->str);
262 ok++;
263 }
264 264
265 parse_events_terms__delete(head); 265 if (parse_events_multi_pmu_add(_data, $1, &list) < 0)
266 }
267 }
268 }
269 if (!ok)
270 YYABORT; 266 YYABORT;
271 $$ = list; 267 $$ = list;
272} 268}
273| 269|
274PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc 270PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
275{ 271{
276 struct parse_events_evlist *data = _data;
277 struct list_head *head;
278 struct parse_events_term *term;
279 struct list_head *list; 272 struct list_head *list;
280 char pmu_name[128]; 273 char pmu_name[128];
281 snprintf(&pmu_name, 128, "%s-%s", $1, $3);
282 274
283 ALLOC_LIST(head); 275 snprintf(&pmu_name, 128, "%s-%s", $1, $3);
284 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, 276 if (parse_events_multi_pmu_add(_data, pmu_name, &list) < 0)
285 &pmu_name, 1, false, &@1, NULL)); 277 YYABORT;
286 list_add_tail(&term->list, head);
287
288 ALLOC_LIST(list);
289 ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
290 parse_events_terms__delete(head);
291 $$ = list; 278 $$ = list;
292} 279}
293 280
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index 7c7630be5a89..50ec3bc87a60 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -11,8 +11,13 @@
11 * which is what it's designed for. 11 * which is what it's designed for.
12 */ 12 */
13#include "cache.h" 13#include "cache.h"
14#include "util.h" 14#include "path.h"
15#include <linux/kernel.h>
15#include <limits.h> 16#include <limits.h>
17#include <stdio.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <unistd.h>
16 21
17static char bad_path[] = "/bad-path/"; 22static char bad_path[] = "/bad-path/";
18/* 23/*
@@ -50,3 +55,24 @@ char *mkpath(const char *fmt, ...)
50 return bad_path; 55 return bad_path;
51 return cleanup_path(pathname); 56 return cleanup_path(pathname);
52} 57}
58
59int path__join(char *bf, size_t size, const char *path1, const char *path2)
60{
61 return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
62}
63
64int path__join3(char *bf, size_t size, const char *path1, const char *path2, const char *path3)
65{
66 return scnprintf(bf, size, "%s%s%s%s%s", path1, path1[0] ? "/" : "",
67 path2, path2[0] ? "/" : "", path3);
68}
69
70bool is_regular_file(const char *file)
71{
72 struct stat st;
73
74 if (stat(file, &st))
75 return false;
76
77 return S_ISREG(st.st_mode);
78}
diff --git a/tools/perf/util/path.h b/tools/perf/util/path.h
new file mode 100644
index 000000000000..9a276a58e3c2
--- /dev/null
+++ b/tools/perf/util/path.h
@@ -0,0 +1,9 @@
1#ifndef _PERF_PATH_H
2#define _PERF_PATH_H
3
4int path__join(char *bf, size_t size, const char *path1, const char *path2);
5int path__join3(char *bf, size_t size, const char *path1, const char *path2, const char *path3);
6
7bool is_regular_file(const char *file);
8
9#endif /* _PERF_PATH_H */
diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c
index cb368306b12b..d55092964da2 100644
--- a/tools/perf/util/perf-hooks.c
+++ b/tools/perf/util/perf-hooks.c
@@ -9,6 +9,7 @@
9#include <stdlib.h> 9#include <stdlib.h>
10#include <setjmp.h> 10#include <setjmp.h>
11#include <linux/err.h> 11#include <linux/err.h>
12#include <linux/kernel.h>
12#include "util/util.h" 13#include "util/util.h"
13#include "util/debug.h" 14#include "util/debug.h"
14#include "util/perf-hooks.h" 15#include "util/perf-hooks.h"
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index c4023f22f287..b2ae039eff85 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -6,6 +6,12 @@ const struct sample_reg __weak sample_reg_masks[] = {
6 SMPL_REG_END 6 SMPL_REG_END
7}; 7};
8 8
9int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused,
10 char **new_op __maybe_unused)
11{
12 return SDT_ARG_SKIP;
13}
14
9#ifdef HAVE_PERF_REGS_SUPPORT 15#ifdef HAVE_PERF_REGS_SUPPORT
10int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) 16int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
11{ 17{
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 679d6e493962..32b37d19dcc3 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -15,6 +15,13 @@ struct sample_reg {
15 15
16extern const struct sample_reg sample_reg_masks[]; 16extern const struct sample_reg sample_reg_masks[];
17 17
18enum {
19 SDT_ARG_VALID = 0,
20 SDT_ARG_SKIP,
21};
22
23int arch_sdt_arg_parse_op(char *old_op, char **new_op);
24
18#ifdef HAVE_PERF_REGS_SUPPORT 25#ifdef HAVE_PERF_REGS_SUPPORT
19#include <perf_regs.h> 26#include <perf_regs.h>
20 27
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 12f84dd2ac5d..ac16a9db1fb5 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,6 +1,8 @@
1#include <linux/list.h> 1#include <linux/list.h>
2#include <linux/compiler.h> 2#include <linux/compiler.h>
3#include <sys/types.h> 3#include <sys/types.h>
4#include <errno.h>
5#include <sys/stat.h>
4#include <unistd.h> 6#include <unistd.h>
5#include <stdio.h> 7#include <stdio.h>
6#include <stdbool.h> 8#include <stdbool.h>
@@ -15,6 +17,7 @@
15#include "header.h" 17#include "header.h"
16#include "pmu-events/pmu-events.h" 18#include "pmu-events/pmu-events.h"
17#include "cache.h" 19#include "cache.h"
20#include "string2.h"
18 21
19struct perf_pmu_format { 22struct perf_pmu_format {
20 char *name; 23 char *name;
@@ -231,7 +234,9 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
231static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 234static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
232 char *desc, char *val, 235 char *desc, char *val,
233 char *long_desc, char *topic, 236 char *long_desc, char *topic,
234 char *unit, char *perpkg) 237 char *unit, char *perpkg,
238 char *metric_expr,
239 char *metric_name)
235{ 240{
236 struct perf_pmu_alias *alias; 241 struct perf_pmu_alias *alias;
237 int ret; 242 int ret;
@@ -265,6 +270,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
265 perf_pmu__parse_snapshot(alias, dir, name); 270 perf_pmu__parse_snapshot(alias, dir, name);
266 } 271 }
267 272
273 alias->metric_expr = metric_expr ? strdup(metric_expr) : NULL;
274 alias->metric_name = metric_name ? strdup(metric_name): NULL;
268 alias->desc = desc ? strdup(desc) : NULL; 275 alias->desc = desc ? strdup(desc) : NULL;
269 alias->long_desc = long_desc ? strdup(long_desc) : 276 alias->long_desc = long_desc ? strdup(long_desc) :
270 desc ? strdup(desc) : NULL; 277 desc ? strdup(desc) : NULL;
@@ -294,7 +301,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
294 buf[ret] = 0; 301 buf[ret] = 0;
295 302
296 return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 303 return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
297 NULL); 304 NULL, NULL, NULL);
298} 305}
299 306
300static inline bool pmu_alias_info_file(char *name) 307static inline bool pmu_alias_info_file(char *name)
@@ -564,7 +571,9 @@ static void pmu_add_cpu_aliases(struct list_head *head, const char *name)
564 __perf_pmu__new_alias(head, NULL, (char *)pe->name, 571 __perf_pmu__new_alias(head, NULL, (char *)pe->name,
565 (char *)pe->desc, (char *)pe->event, 572 (char *)pe->desc, (char *)pe->event,
566 (char *)pe->long_desc, (char *)pe->topic, 573 (char *)pe->long_desc, (char *)pe->topic,
567 (char *)pe->unit, (char *)pe->perpkg); 574 (char *)pe->unit, (char *)pe->perpkg,
575 (char *)pe->metric_expr,
576 (char *)pe->metric_name);
568 } 577 }
569 578
570out: 579out:
@@ -991,6 +1000,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
991 info->unit = NULL; 1000 info->unit = NULL;
992 info->scale = 0.0; 1001 info->scale = 0.0;
993 info->snapshot = false; 1002 info->snapshot = false;
1003 info->metric_expr = NULL;
1004 info->metric_name = NULL;
994 1005
995 list_for_each_entry_safe(term, h, head_terms, list) { 1006 list_for_each_entry_safe(term, h, head_terms, list) {
996 alias = pmu_find_alias(pmu, term); 1007 alias = pmu_find_alias(pmu, term);
@@ -1006,6 +1017,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
1006 1017
1007 if (alias->per_pkg) 1018 if (alias->per_pkg)
1008 info->per_pkg = true; 1019 info->per_pkg = true;
1020 info->metric_expr = alias->metric_expr;
1021 info->metric_name = alias->metric_name;
1009 1022
1010 list_del(&term->list); 1023 list_del(&term->list);
1011 free(term); 1024 free(term);
@@ -1100,6 +1113,8 @@ struct sevent {
1100 char *topic; 1113 char *topic;
1101 char *str; 1114 char *str;
1102 char *pmu; 1115 char *pmu;
1116 char *metric_expr;
1117 char *metric_name;
1103}; 1118};
1104 1119
1105static int cmp_sevent(const void *a, const void *b) 1120static int cmp_sevent(const void *a, const void *b)
@@ -1136,13 +1151,12 @@ static void wordwrap(char *s, int start, int max, int corr)
1136 break; 1151 break;
1137 s += wlen; 1152 s += wlen;
1138 column += n; 1153 column += n;
1139 while (isspace(*s)) 1154 s = ltrim(s);
1140 s++;
1141 } 1155 }
1142} 1156}
1143 1157
1144void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, 1158void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
1145 bool long_desc) 1159 bool long_desc, bool details_flag)
1146{ 1160{
1147 struct perf_pmu *pmu; 1161 struct perf_pmu *pmu;
1148 struct perf_pmu_alias *alias; 1162 struct perf_pmu_alias *alias;
@@ -1198,6 +1212,8 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
1198 aliases[j].topic = alias->topic; 1212 aliases[j].topic = alias->topic;
1199 aliases[j].str = alias->str; 1213 aliases[j].str = alias->str;
1200 aliases[j].pmu = pmu->name; 1214 aliases[j].pmu = pmu->name;
1215 aliases[j].metric_expr = alias->metric_expr;
1216 aliases[j].metric_name = alias->metric_name;
1201 j++; 1217 j++;
1202 } 1218 }
1203 if (pmu->selectable && 1219 if (pmu->selectable &&
@@ -1232,8 +1248,14 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
1232 printf("%*s", 8, "["); 1248 printf("%*s", 8, "[");
1233 wordwrap(aliases[j].desc, 8, columns, 0); 1249 wordwrap(aliases[j].desc, 8, columns, 0);
1234 printf("]\n"); 1250 printf("]\n");
1235 if (verbose > 0) 1251 if (details_flag) {
1236 printf("%*s%s/%s/\n", 8, "", aliases[j].pmu, aliases[j].str); 1252 printf("%*s%s/%s/ ", 8, "", aliases[j].pmu, aliases[j].str);
1253 if (aliases[j].metric_name)
1254 printf(" MetricName: %s", aliases[j].metric_name);
1255 if (aliases[j].metric_expr)
1256 printf(" MetricExpr: %s", aliases[j].metric_expr);
1257 putchar('\n');
1258 }
1237 } else 1259 } else
1238 printf(" %-50s [Kernel PMU event]\n", aliases[j].name); 1260 printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
1239 printed++; 1261 printed++;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 00852ddc7741..ea7f450dc609 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -31,6 +31,8 @@ struct perf_pmu {
31 31
32struct perf_pmu_info { 32struct perf_pmu_info {
33 const char *unit; 33 const char *unit;
34 const char *metric_expr;
35 const char *metric_name;
34 double scale; 36 double scale;
35 bool per_pkg; 37 bool per_pkg;
36 bool snapshot; 38 bool snapshot;
@@ -50,6 +52,8 @@ struct perf_pmu_alias {
50 double scale; 52 double scale;
51 bool per_pkg; 53 bool per_pkg;
52 bool snapshot; 54 bool snapshot;
55 char *metric_expr;
56 char *metric_name;
53}; 57};
54 58
55struct perf_pmu *perf_pmu__find(const char *name); 59struct perf_pmu *perf_pmu__find(const char *name);
@@ -76,7 +80,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
76struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 80struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
77 81
78void print_pmu_events(const char *event_glob, bool name_only, bool quiet, 82void print_pmu_events(const char *event_glob, bool name_only, bool quiet,
79 bool long_desc); 83 bool long_desc, bool details_flag);
80bool pmu_have_event(const char *pname, const char *name); 84bool pmu_have_event(const char *pname, const char *name);
81 85
82int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 86int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
diff --git a/tools/perf/util/print_binary.c b/tools/perf/util/print_binary.c
new file mode 100644
index 000000000000..e908177b9976
--- /dev/null
+++ b/tools/perf/util/print_binary.c
@@ -0,0 +1,55 @@
1#include "print_binary.h"
2#include <linux/log2.h>
3#include "sane_ctype.h"
4
5void print_binary(unsigned char *data, size_t len,
6 size_t bytes_per_line, print_binary_t printer,
7 void *extra)
8{
9 size_t i, j, mask;
10
11 if (!printer)
12 return;
13
14 bytes_per_line = roundup_pow_of_two(bytes_per_line);
15 mask = bytes_per_line - 1;
16
17 printer(BINARY_PRINT_DATA_BEGIN, 0, extra);
18 for (i = 0; i < len; i++) {
19 if ((i & mask) == 0) {
20 printer(BINARY_PRINT_LINE_BEGIN, -1, extra);
21 printer(BINARY_PRINT_ADDR, i, extra);
22 }
23
24 printer(BINARY_PRINT_NUM_DATA, data[i], extra);
25
26 if (((i & mask) == mask) || i == len - 1) {
27 for (j = 0; j < mask-(i & mask); j++)
28 printer(BINARY_PRINT_NUM_PAD, -1, extra);
29
30 printer(BINARY_PRINT_SEP, i, extra);
31 for (j = i & ~mask; j <= i; j++)
32 printer(BINARY_PRINT_CHAR_DATA, data[j], extra);
33 for (j = 0; j < mask-(i & mask); j++)
34 printer(BINARY_PRINT_CHAR_PAD, i, extra);
35 printer(BINARY_PRINT_LINE_END, -1, extra);
36 }
37 }
38 printer(BINARY_PRINT_DATA_END, -1, extra);
39}
40
41int is_printable_array(char *p, unsigned int len)
42{
43 unsigned int i;
44
45 if (!p || !len || p[len - 1] != 0)
46 return 0;
47
48 len--;
49
50 for (i = 0; i < len; i++) {
51 if (!isprint(p[i]) && !isspace(p[i]))
52 return 0;
53 }
54 return 1;
55}
diff --git a/tools/perf/util/print_binary.h b/tools/perf/util/print_binary.h
new file mode 100644
index 000000000000..da0427263d2d
--- /dev/null
+++ b/tools/perf/util/print_binary.h
@@ -0,0 +1,28 @@
1#ifndef PERF_PRINT_BINARY_H
2#define PERF_PRINT_BINARY_H
3
4#include <stddef.h>
5
6enum binary_printer_ops {
7 BINARY_PRINT_DATA_BEGIN,
8 BINARY_PRINT_LINE_BEGIN,
9 BINARY_PRINT_ADDR,
10 BINARY_PRINT_NUM_DATA,
11 BINARY_PRINT_NUM_PAD,
12 BINARY_PRINT_SEP,
13 BINARY_PRINT_CHAR_DATA,
14 BINARY_PRINT_CHAR_PAD,
15 BINARY_PRINT_LINE_END,
16 BINARY_PRINT_DATA_END,
17};
18
19typedef void (*print_binary_t)(enum binary_printer_ops op,
20 unsigned int val, void *extra);
21
22void print_binary(unsigned char *data, size_t len,
23 size_t bytes_per_line, print_binary_t printer,
24 void *extra);
25
26int is_printable_array(char *p, unsigned int len);
27
28#endif /* PERF_PRINT_BINARY_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 28fb62c32678..84e7e698411e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -19,6 +19,7 @@
19 * 19 *
20 */ 20 */
21 21
22#include <inttypes.h>
22#include <sys/utsname.h> 23#include <sys/utsname.h>
23#include <sys/types.h> 24#include <sys/types.h>
24#include <sys/stat.h> 25#include <sys/stat.h>
@@ -35,6 +36,7 @@
35#include "util.h" 36#include "util.h"
36#include "event.h" 37#include "event.h"
37#include "strlist.h" 38#include "strlist.h"
39#include "strfilter.h"
38#include "debug.h" 40#include "debug.h"
39#include "cache.h" 41#include "cache.h"
40#include "color.h" 42#include "color.h"
@@ -46,8 +48,10 @@
46#include "probe-finder.h" 48#include "probe-finder.h"
47#include "probe-file.h" 49#include "probe-file.h"
48#include "session.h" 50#include "session.h"
51#include "string2.h"
52
53#include "sane_ctype.h"
49 54
50#define MAX_CMDLEN 256
51#define PERFPROBE_GROUP "probe" 55#define PERFPROBE_GROUP "probe"
52 56
53bool probe_event_dry_run; /* Dry run flag */ 57bool probe_event_dry_run; /* Dry run flag */
@@ -757,7 +761,9 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
757 } 761 }
758 762
759 for (i = 0; i < ntevs; i++) { 763 for (i = 0; i < ntevs; i++) {
760 if (!tevs[i].point.address || tevs[i].point.retprobe) 764 if (!tevs[i].point.address)
765 continue;
766 if (tevs[i].point.retprobe && !kretprobe_offset_is_supported())
761 continue; 767 continue;
762 /* If we found a wrong one, mark it by NULL symbol */ 768 /* If we found a wrong one, mark it by NULL symbol */
763 if (kprobe_warn_out_range(tevs[i].point.symbol, 769 if (kprobe_warn_out_range(tevs[i].point.symbol,
@@ -1339,14 +1345,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
1339 if (!arg) 1345 if (!arg)
1340 return -EINVAL; 1346 return -EINVAL;
1341 1347
1342 /* 1348 if (is_sdt_event(arg)) {
1343 * If the probe point starts with '%',
1344 * or starts with "sdt_" and has a ':' but no '=',
1345 * then it should be a SDT/cached probe point.
1346 */
1347 if (arg[0] == '%' ||
1348 (!strncmp(arg, "sdt_", 4) &&
1349 !!strchr(arg, ':') && !strchr(arg, '='))) {
1350 pev->sdt = true; 1349 pev->sdt = true;
1351 if (arg[0] == '%') 1350 if (arg[0] == '%')
1352 arg++; 1351 arg++;
@@ -1528,11 +1527,6 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
1528 return -EINVAL; 1527 return -EINVAL;
1529 } 1528 }
1530 1529
1531 if (pp->retprobe && !pp->function) {
1532 semantic_error("Return probe requires an entry function.\n");
1533 return -EINVAL;
1534 }
1535
1536 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 1530 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
1537 semantic_error("Offset/Line/Lazy pattern can't be used with " 1531 semantic_error("Offset/Line/Lazy pattern can't be used with "
1538 "return probe.\n"); 1532 "return probe.\n");
@@ -2841,7 +2835,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2841 } 2835 }
2842 2836
2843 /* Note that the symbols in the kmodule are not relocated */ 2837 /* Note that the symbols in the kmodule are not relocated */
2844 if (!pev->uprobes && !pp->retprobe && !pev->target) { 2838 if (!pev->uprobes && !pev->target &&
2839 (!pp->retprobe || kretprobe_offset_is_supported())) {
2845 reloc_sym = kernel_get_ref_reloc_sym(); 2840 reloc_sym = kernel_get_ref_reloc_sym();
2846 if (!reloc_sym) { 2841 if (!reloc_sym) {
2847 pr_warning("Relocated base symbol is not found!\n"); 2842 pr_warning("Relocated base symbol is not found!\n");
@@ -3057,7 +3052,7 @@ concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs,
3057 struct probe_trace_event *new_tevs; 3052 struct probe_trace_event *new_tevs;
3058 int ret = 0; 3053 int ret = 0;
3059 3054
3060 if (ntevs == 0) { 3055 if (*ntevs == 0) {
3061 *tevs = *tevs2; 3056 *tevs = *tevs2;
3062 *ntevs = ntevs2; 3057 *ntevs = ntevs2;
3063 *tevs2 = NULL; 3058 *tevs2 = NULL;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5d4e94061402..373842656fb6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -3,8 +3,6 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "intlist.h" 5#include "intlist.h"
6#include "strlist.h"
7#include "strfilter.h"
8 6
9/* Probe related configurations */ 7/* Probe related configurations */
10struct probe_conf { 8struct probe_conf {
@@ -107,6 +105,8 @@ struct line_range {
107 struct intlist *line_list; /* Visible lines */ 105 struct intlist *line_list; /* Visible lines */
108}; 106};
109 107
108struct strlist;
109
110/* List of variables */ 110/* List of variables */
111struct variable_list { 111struct variable_list {
112 struct probe_trace_point point; /* Actual probepoint */ 112 struct probe_trace_point point; /* Actual probepoint */
@@ -153,6 +153,9 @@ int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs);
153int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); 153int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs);
154int show_probe_trace_events(struct perf_probe_event *pevs, int npevs); 154int show_probe_trace_events(struct perf_probe_event *pevs, int npevs);
155void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); 155void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs);
156
157struct strfilter;
158
156int del_perf_probe_events(struct strfilter *filter); 159int del_perf_probe_events(struct strfilter *filter);
157 160
158int show_perf_probe_event(const char *group, const char *event, 161int show_perf_probe_event(const char *group, const char *event,
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 436b64731f65..d679389e627c 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -14,10 +14,15 @@
14 * GNU General Public License for more details. 14 * GNU General Public License for more details.
15 * 15 *
16 */ 16 */
17#include <errno.h>
18#include <sys/stat.h>
19#include <sys/types.h>
17#include <sys/uio.h> 20#include <sys/uio.h>
21#include <unistd.h>
18#include "util.h" 22#include "util.h"
19#include "event.h" 23#include "event.h"
20#include "strlist.h" 24#include "strlist.h"
25#include "strfilter.h"
21#include "debug.h" 26#include "debug.h"
22#include "cache.h" 27#include "cache.h"
23#include "color.h" 28#include "color.h"
@@ -27,8 +32,11 @@
27#include "probe-event.h" 32#include "probe-event.h"
28#include "probe-file.h" 33#include "probe-file.h"
29#include "session.h" 34#include "session.h"
35#include "perf_regs.h"
36#include "string2.h"
30 37
31#define MAX_CMDLEN 256 38/* 4096 - 2 ('\n' + '\0') */
39#define MAX_CMDLEN 4094
32 40
33static void print_open_warning(int err, bool uprobe) 41static void print_open_warning(int err, bool uprobe)
34{ 42{
@@ -70,7 +78,7 @@ static void print_both_open_warning(int kerr, int uerr)
70 } 78 }
71} 79}
72 80
73static int open_probe_events(const char *trace_file, bool readwrite) 81int open_trace_file(const char *trace_file, bool readwrite)
74{ 82{
75 char buf[PATH_MAX]; 83 char buf[PATH_MAX];
76 int ret; 84 int ret;
@@ -92,12 +100,12 @@ static int open_probe_events(const char *trace_file, bool readwrite)
92 100
93static int open_kprobe_events(bool readwrite) 101static int open_kprobe_events(bool readwrite)
94{ 102{
95 return open_probe_events("kprobe_events", readwrite); 103 return open_trace_file("kprobe_events", readwrite);
96} 104}
97 105
98static int open_uprobe_events(bool readwrite) 106static int open_uprobe_events(bool readwrite)
99{ 107{
100 return open_probe_events("uprobe_events", readwrite); 108 return open_trace_file("uprobe_events", readwrite);
101} 109}
102 110
103int probe_file__open(int flag) 111int probe_file__open(int flag)
@@ -687,6 +695,110 @@ static unsigned long long sdt_note__get_addr(struct sdt_note *note)
687 : (unsigned long long)note->addr.a64[0]; 695 : (unsigned long long)note->addr.a64[0];
688} 696}
689 697
698static const char * const type_to_suffix[] = {
699 ":s64", "", "", "", ":s32", "", ":s16", ":s8",
700 "", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
701};
702
703/*
704 * Isolate the string number and convert it into a decimal value;
705 * this will be an index to get suffix of the uprobe name (defining
706 * the type)
707 */
708static int sdt_arg_parse_size(char *n_ptr, const char **suffix)
709{
710 long type_idx;
711
712 type_idx = strtol(n_ptr, NULL, 10);
713 if (type_idx < -8 || type_idx > 8) {
714 pr_debug4("Failed to get a valid sdt type\n");
715 return -1;
716 }
717
718 *suffix = type_to_suffix[type_idx + 8];
719 return 0;
720}
721
722static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
723{
724 char *op, *desc = strdup(arg), *new_op = NULL;
725 const char *suffix = "";
726 int ret = -1;
727
728 if (desc == NULL) {
729 pr_debug4("Allocation error\n");
730 return ret;
731 }
732
733 /*
734 * Argument is in N@OP format. N is size of the argument and OP is
735 * the actual assembly operand. N can be omitted; in that case
736 * argument is just OP(without @).
737 */
738 op = strchr(desc, '@');
739 if (op) {
740 op[0] = '\0';
741 op++;
742
743 if (sdt_arg_parse_size(desc, &suffix))
744 goto error;
745 } else {
746 op = desc;
747 }
748
749 ret = arch_sdt_arg_parse_op(op, &new_op);
750
751 if (ret < 0)
752 goto error;
753
754 if (ret == SDT_ARG_VALID) {
755 ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
756 if (ret < 0)
757 goto error;
758 }
759
760 ret = 0;
761error:
762 free(desc);
763 free(new_op);
764 return ret;
765}
766
767static char *synthesize_sdt_probe_command(struct sdt_note *note,
768 const char *pathname,
769 const char *sdtgrp)
770{
771 struct strbuf buf;
772 char *ret = NULL, **args;
773 int i, args_count;
774
775 if (strbuf_init(&buf, 32) < 0)
776 return NULL;
777
778 if (strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
779 sdtgrp, note->name, pathname,
780 sdt_note__get_addr(note)) < 0)
781 goto error;
782
783 if (!note->args)
784 goto out;
785
786 if (note->args) {
787 args = argv_split(note->args, &args_count);
788
789 for (i = 0; i < args_count; ++i) {
790 if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0)
791 goto error;
792 }
793 }
794
795out:
796 ret = strbuf_detach(&buf, NULL);
797error:
798 strbuf_release(&buf);
799 return ret;
800}
801
690int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname) 802int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
691{ 803{
692 struct probe_cache_entry *entry = NULL; 804 struct probe_cache_entry *entry = NULL;
@@ -723,11 +835,12 @@ int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
723 entry->pev.group = strdup(sdtgrp); 835 entry->pev.group = strdup(sdtgrp);
724 list_add_tail(&entry->node, &pcache->entries); 836 list_add_tail(&entry->node, &pcache->entries);
725 } 837 }
726 ret = asprintf(&buf, "p:%s/%s %s:0x%llx", 838 buf = synthesize_sdt_probe_command(note, pathname, sdtgrp);
727 sdtgrp, note->name, pathname, 839 if (!buf) {
728 sdt_note__get_addr(note)); 840 ret = -ENOMEM;
729 if (ret < 0)
730 break; 841 break;
842 }
843
731 strlist__add(entry->tevlist, buf); 844 strlist__add(entry->tevlist, buf);
732 free(buf); 845 free(buf);
733 entry = NULL; 846 entry = NULL;
@@ -877,59 +990,72 @@ int probe_cache__show_all_caches(struct strfilter *filter)
877 return 0; 990 return 0;
878} 991}
879 992
993enum ftrace_readme {
994 FTRACE_README_PROBE_TYPE_X = 0,
995 FTRACE_README_KRETPROBE_OFFSET,
996 FTRACE_README_END,
997};
998
880static struct { 999static struct {
881 const char *pattern; 1000 const char *pattern;
882 bool avail; 1001 bool avail;
883 bool checked; 1002} ftrace_readme_table[] = {
884} probe_type_table[] = { 1003#define DEFINE_TYPE(idx, pat) \
885#define DEFINE_TYPE(idx, pat, def_avail) \ 1004 [idx] = {.pattern = pat, .avail = false}
886 [idx] = {.pattern = pat, .avail = (def_avail)} 1005 DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
887 DEFINE_TYPE(PROBE_TYPE_U, "* u8/16/32/64,*", true), 1006 DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
888 DEFINE_TYPE(PROBE_TYPE_S, "* s8/16/32/64,*", true),
889 DEFINE_TYPE(PROBE_TYPE_X, "* x8/16/32/64,*", false),
890 DEFINE_TYPE(PROBE_TYPE_STRING, "* string,*", true),
891 DEFINE_TYPE(PROBE_TYPE_BITFIELD,
892 "* b<bit-width>@<bit-offset>/<container-size>", true),
893}; 1007};
894 1008
895bool probe_type_is_available(enum probe_type type) 1009static bool scan_ftrace_readme(enum ftrace_readme type)
896{ 1010{
1011 int fd;
897 FILE *fp; 1012 FILE *fp;
898 char *buf = NULL; 1013 char *buf = NULL;
899 size_t len = 0; 1014 size_t len = 0;
900 bool target_line = false; 1015 bool ret = false;
901 bool ret = probe_type_table[type].avail; 1016 static bool scanned = false;
902 1017
903 if (type >= PROBE_TYPE_END) 1018 if (scanned)
904 return false; 1019 goto result;
905 /* We don't have to check the type which supported by default */
906 if (ret || probe_type_table[type].checked)
907 return ret;
908 1020
909 if (asprintf(&buf, "%s/README", tracing_path) < 0) 1021 fd = open_trace_file("README", false);
1022 if (fd < 0)
910 return ret; 1023 return ret;
911 1024
912 fp = fopen(buf, "r"); 1025 fp = fdopen(fd, "r");
913 if (!fp) 1026 if (!fp) {
914 goto end; 1027 close(fd);
915 1028 return ret;
916 zfree(&buf);
917 while (getline(&buf, &len, fp) > 0 && !ret) {
918 if (!target_line) {
919 target_line = !!strstr(buf, " type: ");
920 if (!target_line)
921 continue;
922 } else if (strstr(buf, "\t ") != buf)
923 break;
924 ret = strglobmatch(buf, probe_type_table[type].pattern);
925 } 1029 }
926 /* Cache the result */ 1030
927 probe_type_table[type].checked = true; 1031 while (getline(&buf, &len, fp) > 0)
928 probe_type_table[type].avail = ret; 1032 for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)
1033 if (!ftrace_readme_table[i].avail)
1034 ftrace_readme_table[i].avail =
1035 strglobmatch(buf, ftrace_readme_table[i].pattern);
1036 scanned = true;
929 1037
930 fclose(fp); 1038 fclose(fp);
931end:
932 free(buf); 1039 free(buf);
933 1040
934 return ret; 1041result:
1042 if (type >= FTRACE_README_END)
1043 return false;
1044
1045 return ftrace_readme_table[type].avail;
1046}
1047
1048bool probe_type_is_available(enum probe_type type)
1049{
1050 if (type >= PROBE_TYPE_END)
1051 return false;
1052 else if (type == PROBE_TYPE_X)
1053 return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
1054
1055 return true;
1056}
1057
1058bool kretprobe_offset_is_supported(void)
1059{
1060 return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
935} 1061}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index eba44c3e9dca..5ecc9d3925db 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -1,10 +1,11 @@
1#ifndef __PROBE_FILE_H 1#ifndef __PROBE_FILE_H
2#define __PROBE_FILE_H 2#define __PROBE_FILE_H
3 3
4#include "strlist.h"
5#include "strfilter.h"
6#include "probe-event.h" 4#include "probe-event.h"
7 5
6struct strlist;
7struct strfilter;
8
8/* Cache of probe definitions */ 9/* Cache of probe definitions */
9struct probe_cache_entry { 10struct probe_cache_entry {
10 struct list_head node; 11 struct list_head node;
@@ -35,11 +36,13 @@ enum probe_type {
35 36
36/* probe-file.c depends on libelf */ 37/* probe-file.c depends on libelf */
37#ifdef HAVE_LIBELF_SUPPORT 38#ifdef HAVE_LIBELF_SUPPORT
39int open_trace_file(const char *trace_file, bool readwrite);
38int probe_file__open(int flag); 40int probe_file__open(int flag);
39int probe_file__open_both(int *kfd, int *ufd, int flag); 41int probe_file__open_both(int *kfd, int *ufd, int flag);
40struct strlist *probe_file__get_namelist(int fd); 42struct strlist *probe_file__get_namelist(int fd);
41struct strlist *probe_file__get_rawlist(int fd); 43struct strlist *probe_file__get_rawlist(int fd);
42int probe_file__add_event(int fd, struct probe_trace_event *tev); 44int probe_file__add_event(int fd, struct probe_trace_event *tev);
45
43int probe_file__del_events(int fd, struct strfilter *filter); 46int probe_file__del_events(int fd, struct strfilter *filter);
44int probe_file__get_events(int fd, struct strfilter *filter, 47int probe_file__get_events(int fd, struct strfilter *filter,
45 struct strlist *plist); 48 struct strlist *plist);
@@ -64,6 +67,7 @@ struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
64 const char *group, const char *event); 67 const char *group, const char *event);
65int probe_cache__show_all_caches(struct strfilter *filter); 68int probe_cache__show_all_caches(struct strfilter *filter);
66bool probe_type_is_available(enum probe_type type); 69bool probe_type_is_available(enum probe_type type);
70bool kretprobe_offset_is_supported(void);
67#else /* ! HAVE_LIBELF_SUPPORT */ 71#else /* ! HAVE_LIBELF_SUPPORT */
68static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused) 72static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused)
69{ 73{
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 57cd268d4275..a5731de0e5eb 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -19,6 +19,7 @@
19 * 19 *
20 */ 20 */
21 21
22#include <inttypes.h>
22#include <sys/utsname.h> 23#include <sys/utsname.h>
23#include <sys/types.h> 24#include <sys/types.h>
24#include <sys/stat.h> 25#include <sys/stat.h>
@@ -37,9 +38,11 @@
37#include "debug.h" 38#include "debug.h"
38#include "intlist.h" 39#include "intlist.h"
39#include "util.h" 40#include "util.h"
41#include "strlist.h"
40#include "symbol.h" 42#include "symbol.h"
41#include "probe-finder.h" 43#include "probe-finder.h"
42#include "probe-file.h" 44#include "probe-file.h"
45#include "string2.h"
43 46
44/* Kprobe tracer basic type is up to u64 */ 47/* Kprobe tracer basic type is up to u64 */
45#define MAX_BASIC_TYPE_BITS 64 48#define MAX_BASIC_TYPE_BITS 64
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 2956c5198652..27f061551012 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -2,9 +2,9 @@
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "util.h"
6#include "intlist.h" 5#include "intlist.h"
7#include "probe-event.h" 6#include "probe-event.h"
7#include "sane_ctype.h"
8 8
9#define MAX_PROBE_BUFFER 1024 9#define MAX_PROBE_BUFFER 1024
10#define MAX_PROBES 128 10#define MAX_PROBES 128
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 0546a4304347..9f3b0d9754a8 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -21,8 +21,10 @@ util/cgroup.c
21util/parse-branch-options.c 21util/parse-branch-options.c
22util/rblist.c 22util/rblist.c
23util/counts.c 23util/counts.c
24util/print_binary.c
24util/strlist.c 25util/strlist.c
25util/trace-event.c 26util/trace-event.c
26../lib/rbtree.c 27../lib/rbtree.c
27util/string.c 28util/string.c
28util/symbol_fprintf.c 29util/symbol_fprintf.c
30util/units.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index a5fbc012e3df..c129e99114ae 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -4,12 +4,26 @@
4#include <poll.h> 4#include <poll.h>
5#include <linux/err.h> 5#include <linux/err.h>
6#include "evlist.h" 6#include "evlist.h"
7#include "callchain.h"
7#include "evsel.h" 8#include "evsel.h"
8#include "event.h" 9#include "event.h"
9#include "cpumap.h" 10#include "cpumap.h"
11#include "print_binary.h"
10#include "thread_map.h" 12#include "thread_map.h"
11 13
12/* 14/*
15 * Provide these two so that we don't have to link against callchain.c and
16 * start dragging hist.c, etc.
17 */
18struct callchain_param callchain_param;
19
20int parse_callchain_record(const char *arg __maybe_unused,
21 struct callchain_param *param __maybe_unused)
22{
23 return 0;
24}
25
26/*
13 * Support debug printing even though util/debug.c is not linked. That means 27 * Support debug printing even though util/debug.c is not linked. That means
14 * implementing 'verbose' and 'eprintf'. 28 * implementing 'verbose' and 'eprintf'.
15 */ 29 */
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index 293534c1a474..1ba8920151d8 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -1,3 +1,4 @@
1#include <errno.h>
1#include <stdlib.h> 2#include <stdlib.h>
2#include "strbuf.h" 3#include "strbuf.h"
3#include "quote.h" 4#include "quote.h"
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 98bf584853ea..d91bdf5a1aa4 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -2,6 +2,7 @@
2#include "evsel.h" 2#include "evsel.h"
3#include "cpumap.h" 3#include "cpumap.h"
4#include "parse-events.h" 4#include "parse-events.h"
5#include <errno.h>
5#include <api/fs/fs.h> 6#include <api/fs/fs.h>
6#include "util.h" 7#include "util.h"
7#include "cloexec.h" 8#include "cloexec.h"
diff --git a/tools/perf/util/sane_ctype.h b/tools/perf/util/sane_ctype.h
new file mode 100644
index 000000000000..4308c22c22ad
--- /dev/null
+++ b/tools/perf/util/sane_ctype.h
@@ -0,0 +1,51 @@
1#ifndef _PERF_SANE_CTYPE_H
2#define _PERF_SANE_CTYPE_H
3
4extern const char *graph_line;
5extern const char *graph_dotted_line;
6extern const char *spaces;
7extern const char *dots;
8
9/* Sane ctype - no locale, and works with signed chars */
10#undef isascii
11#undef isspace
12#undef isdigit
13#undef isxdigit
14#undef isalpha
15#undef isprint
16#undef isalnum
17#undef islower
18#undef isupper
19#undef tolower
20#undef toupper
21
22extern unsigned char sane_ctype[256];
23#define GIT_SPACE 0x01
24#define GIT_DIGIT 0x02
25#define GIT_ALPHA 0x04
26#define GIT_GLOB_SPECIAL 0x08
27#define GIT_REGEX_SPECIAL 0x10
28#define GIT_PRINT_EXTRA 0x20
29#define GIT_PRINT 0x3E
30#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
31#define isascii(x) (((x) & ~0x7f) == 0)
32#define isspace(x) sane_istest(x,GIT_SPACE)
33#define isdigit(x) sane_istest(x,GIT_DIGIT)
34#define isxdigit(x) \
35 (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
36#define isalpha(x) sane_istest(x,GIT_ALPHA)
37#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
38#define isprint(x) sane_istest(x,GIT_PRINT)
39#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20))
40#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20))
41#define tolower(x) sane_case((unsigned char)(x), 0x20)
42#define toupper(x) sane_case((unsigned char)(x), 0)
43
44static inline int sane_case(int x, int high)
45{
46 if (sane_istest(x, GIT_ALPHA))
47 x = (x & ~0x20) | high;
48 return x;
49}
50
51#endif /* _PERF_SANE_CTYPE_H */
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index dff043a29589..7b79c413486b 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -19,6 +19,7 @@
19 * 19 *
20 */ 20 */
21 21
22#include <inttypes.h>
22#include <stdio.h> 23#include <stdio.h>
23#include <stdlib.h> 24#include <stdlib.h>
24#include <string.h> 25#include <string.h>
@@ -27,7 +28,9 @@
27#include <linux/bitmap.h> 28#include <linux/bitmap.h>
28#include <linux/time64.h> 29#include <linux/time64.h>
29 30
30#include "../util.h" 31#include <stdbool.h>
32/* perl needs the following define, right after including stdbool.h */
33#define HAS_BOOL
31#include <EXTERN.h> 34#include <EXTERN.h>
32#include <perl.h> 35#include <perl.h>
33 36
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 783326cfbaa6..9d92af7d0718 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -21,6 +21,7 @@
21 21
22#include <Python.h> 22#include <Python.h>
23 23
24#include <inttypes.h>
24#include <stdio.h> 25#include <stdio.h>
25#include <stdlib.h> 26#include <stdlib.h>
26#include <string.h> 27#include <string.h>
@@ -45,6 +46,7 @@
45#include "../call-path.h" 46#include "../call-path.h"
46#include "thread_map.h" 47#include "thread_map.h"
47#include "cpumap.h" 48#include "cpumap.h"
49#include "print_binary.h"
48#include "stat.h" 50#include "stat.h"
49 51
50PyMODINIT_FUNC initperf_trace_context(void); 52PyMODINIT_FUNC initperf_trace_context(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1dd617d116b5..7dc1096264c5 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,8 @@
1#include <errno.h>
2#include <inttypes.h>
1#include <linux/kernel.h> 3#include <linux/kernel.h>
2#include <traceevent/event-parse.h> 4#include <traceevent/event-parse.h>
5#include <api/fs/fs.h>
3 6
4#include <byteswap.h> 7#include <byteswap.h>
5#include <unistd.h> 8#include <unistd.h>
@@ -8,6 +11,7 @@
8 11
9#include "evlist.h" 12#include "evlist.h"
10#include "evsel.h" 13#include "evsel.h"
14#include "memswap.h"
11#include "session.h" 15#include "session.h"
12#include "tool.h" 16#include "tool.h"
13#include "sort.h" 17#include "sort.h"
@@ -16,6 +20,7 @@
16#include "perf_regs.h" 20#include "perf_regs.h"
17#include "asm/bug.h" 21#include "asm/bug.h"
18#include "auxtrace.h" 22#include "auxtrace.h"
23#include "thread.h"
19#include "thread-stack.h" 24#include "thread-stack.h"
20#include "stat.h" 25#include "stat.h"
21 26
@@ -139,8 +144,14 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
139 if (perf_session__open(session) < 0) 144 if (perf_session__open(session) < 0)
140 goto out_close; 145 goto out_close;
141 146
142 perf_session__set_id_hdr_size(session); 147 /*
143 perf_session__set_comm_exec(session); 148 * set session attributes that are present in perf.data
149 * but not in pipe-mode.
150 */
151 if (!file->is_pipe) {
152 perf_session__set_id_hdr_size(session);
153 perf_session__set_comm_exec(session);
154 }
144 } 155 }
145 } else { 156 } else {
146 session->machines.host.env = &perf_env; 157 session->machines.host.env = &perf_env;
@@ -155,7 +166,11 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
155 pr_warning("Cannot read kernel map\n"); 166 pr_warning("Cannot read kernel map\n");
156 } 167 }
157 168
158 if (tool && tool->ordering_requires_timestamps && 169 /*
170 * In pipe-mode, evlist is empty until PERF_RECORD_HEADER_ATTR is
171 * processed, so perf_evlist__sample_id_all is not meaningful here.
172 */
173 if ((!file || !file->is_pipe) && tool && tool->ordering_requires_timestamps &&
159 tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) { 174 tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
160 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 175 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
161 tool->ordered_events = false; 176 tool->ordered_events = false;
@@ -1239,6 +1254,8 @@ static int machines__deliver_event(struct machines *machines,
1239 return tool->mmap2(tool, event, sample, machine); 1254 return tool->mmap2(tool, event, sample, machine);
1240 case PERF_RECORD_COMM: 1255 case PERF_RECORD_COMM:
1241 return tool->comm(tool, event, sample, machine); 1256 return tool->comm(tool, event, sample, machine);
1257 case PERF_RECORD_NAMESPACES:
1258 return tool->namespaces(tool, event, sample, machine);
1242 case PERF_RECORD_FORK: 1259 case PERF_RECORD_FORK:
1243 return tool->fork(tool, event, sample, machine); 1260 return tool->fork(tool, event, sample, machine);
1244 case PERF_RECORD_EXIT: 1261 case PERF_RECORD_EXIT:
@@ -1258,9 +1275,12 @@ static int machines__deliver_event(struct machines *machines,
1258 case PERF_RECORD_UNTHROTTLE: 1275 case PERF_RECORD_UNTHROTTLE:
1259 return tool->unthrottle(tool, event, sample, machine); 1276 return tool->unthrottle(tool, event, sample, machine);
1260 case PERF_RECORD_AUX: 1277 case PERF_RECORD_AUX:
1261 if (tool->aux == perf_event__process_aux && 1278 if (tool->aux == perf_event__process_aux) {
1262 (event->aux.flags & PERF_AUX_FLAG_TRUNCATED)) 1279 if (event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
1263 evlist->stats.total_aux_lost += 1; 1280 evlist->stats.total_aux_lost += 1;
1281 if (event->aux.flags & PERF_AUX_FLAG_PARTIAL)
1282 evlist->stats.total_aux_partial += 1;
1283 }
1264 return tool->aux(tool, event, sample, machine); 1284 return tool->aux(tool, event, sample, machine);
1265 case PERF_RECORD_ITRACE_START: 1285 case PERF_RECORD_ITRACE_START:
1266 return tool->itrace_start(tool, event, sample, machine); 1286 return tool->itrace_start(tool, event, sample, machine);
@@ -1494,6 +1514,11 @@ int perf_session__register_idle_thread(struct perf_session *session)
1494 err = -1; 1514 err = -1;
1495 } 1515 }
1496 1516
1517 if (thread == NULL || thread__set_namespaces(thread, 0, NULL)) {
1518 pr_err("problem inserting idle task.\n");
1519 err = -1;
1520 }
1521
1497 /* machine__findnew_thread() got the thread, so put it */ 1522 /* machine__findnew_thread() got the thread, so put it */
1498 thread__put(thread); 1523 thread__put(thread);
1499 return err; 1524 return err;
@@ -1548,6 +1573,23 @@ static void perf_session__warn_about_errors(const struct perf_session *session)
1548 stats->nr_events[PERF_RECORD_AUX]); 1573 stats->nr_events[PERF_RECORD_AUX]);
1549 } 1574 }
1550 1575
1576 if (session->tool->aux == perf_event__process_aux &&
1577 stats->total_aux_partial != 0) {
1578 bool vmm_exclusive = false;
1579
1580 (void)sysfs__read_bool("module/kvm_intel/parameters/vmm_exclusive",
1581 &vmm_exclusive);
1582
1583 ui__warning("AUX data had gaps in it %" PRIu64 " times out of %u!\n\n"
1584 "Are you running a KVM guest in the background?%s\n\n",
1585 stats->total_aux_partial,
1586 stats->nr_events[PERF_RECORD_AUX],
1587 vmm_exclusive ?
1588 "\nReloading kvm_intel module with vmm_exclusive=0\n"
1589 "will reduce the gaps to only guest's timeslices." :
1590 "");
1591 }
1592
1551 if (stats->nr_unknown_events != 0) { 1593 if (stats->nr_unknown_events != 0) {
1552 ui__warning("Found %u unknown events!\n\n" 1594 ui__warning("Found %u unknown events!\n\n"
1553 "Is this an older tool processing a perf.data " 1595 "Is this an older tool processing a perf.data "
@@ -1628,6 +1670,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
1628 buf = malloc(cur_size); 1670 buf = malloc(cur_size);
1629 if (!buf) 1671 if (!buf)
1630 return -errno; 1672 return -errno;
1673 ordered_events__set_copy_on_queue(oe, true);
1631more: 1674more:
1632 event = buf; 1675 event = buf;
1633 err = readn(fd, event, sizeof(struct perf_event_header)); 1676 err = readn(fd, event, sizeof(struct perf_event_header));
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 4bd758553450..47b5e7dbcb18 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -5,14 +5,14 @@
5#include "event.h" 5#include "event.h"
6#include "header.h" 6#include "header.h"
7#include "machine.h" 7#include "machine.h"
8#include "symbol.h"
9#include "thread.h"
10#include "data.h" 8#include "data.h"
11#include "ordered-events.h" 9#include "ordered-events.h"
10#include <linux/kernel.h>
12#include <linux/rbtree.h> 11#include <linux/rbtree.h>
13#include <linux/perf_event.h> 12#include <linux/perf_event.h>
14 13
15struct ip_callchain; 14struct ip_callchain;
15struct symbol;
16struct thread; 16struct thread;
17 17
18struct auxtrace; 18struct auxtrace;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 0ff622288d24..5762ae4e9e91 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,12 +1,18 @@
1#include <errno.h>
2#include <inttypes.h>
3#include <regex.h>
1#include <sys/mman.h> 4#include <sys/mman.h>
2#include "sort.h" 5#include "sort.h"
3#include "hist.h" 6#include "hist.h"
4#include "comm.h" 7#include "comm.h"
5#include "symbol.h" 8#include "symbol.h"
9#include "thread.h"
6#include "evsel.h" 10#include "evsel.h"
7#include "evlist.h" 11#include "evlist.h"
12#include "strlist.h"
8#include <traceevent/event-parse.h> 13#include <traceevent/event-parse.h>
9#include "mem-events.h" 14#include "mem-events.h"
15#include <linux/kernel.h>
10 16
11regex_t parent_regex; 17regex_t parent_regex;
12const char default_parent_pattern[] = "^sys_|^do_page_fault"; 18const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -323,7 +329,7 @@ char *hist_entry__get_srcline(struct hist_entry *he)
323 return SRCLINE_UNKNOWN; 329 return SRCLINE_UNKNOWN;
324 330
325 return get_srcline(map->dso, map__rip_2objdump(map, he->ip), 331 return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
326 he->ms.sym, true); 332 he->ms.sym, true, true);
327} 333}
328 334
329static int64_t 335static int64_t
@@ -366,7 +372,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
366 left->branch_info->srcline_from = get_srcline(map->dso, 372 left->branch_info->srcline_from = get_srcline(map->dso,
367 map__rip_2objdump(map, 373 map__rip_2objdump(map,
368 left->branch_info->from.al_addr), 374 left->branch_info->from.al_addr),
369 left->branch_info->from.sym, true); 375 left->branch_info->from.sym,
376 true, true);
370 } 377 }
371 if (!right->branch_info->srcline_from) { 378 if (!right->branch_info->srcline_from) {
372 struct map *map = right->branch_info->from.map; 379 struct map *map = right->branch_info->from.map;
@@ -376,7 +383,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
376 right->branch_info->srcline_from = get_srcline(map->dso, 383 right->branch_info->srcline_from = get_srcline(map->dso,
377 map__rip_2objdump(map, 384 map__rip_2objdump(map,
378 right->branch_info->from.al_addr), 385 right->branch_info->from.al_addr),
379 right->branch_info->from.sym, true); 386 right->branch_info->from.sym,
387 true, true);
380 } 388 }
381 return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); 389 return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
382} 390}
@@ -407,7 +415,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
407 left->branch_info->srcline_to = get_srcline(map->dso, 415 left->branch_info->srcline_to = get_srcline(map->dso,
408 map__rip_2objdump(map, 416 map__rip_2objdump(map,
409 left->branch_info->to.al_addr), 417 left->branch_info->to.al_addr),
410 left->branch_info->from.sym, true); 418 left->branch_info->from.sym,
419 true, true);
411 } 420 }
412 if (!right->branch_info->srcline_to) { 421 if (!right->branch_info->srcline_to) {
413 struct map *map = right->branch_info->to.map; 422 struct map *map = right->branch_info->to.map;
@@ -417,7 +426,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
417 right->branch_info->srcline_to = get_srcline(map->dso, 426 right->branch_info->srcline_to = get_srcline(map->dso,
418 map__rip_2objdump(map, 427 map__rip_2objdump(map,
419 right->branch_info->to.al_addr), 428 right->branch_info->to.al_addr),
420 right->branch_info->to.sym, true); 429 right->branch_info->to.sym,
430 true, true);
421 } 431 }
422 return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); 432 return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
423} 433}
@@ -448,7 +458,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e)
448 return no_srcfile; 458 return no_srcfile;
449 459
450 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), 460 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
451 e->ms.sym, false, true); 461 e->ms.sym, false, true, true);
452 if (!strcmp(sf, SRCLINE_UNKNOWN)) 462 if (!strcmp(sf, SRCLINE_UNKNOWN))
453 return no_srcfile; 463 return no_srcfile;
454 p = strchr(sf, ':'); 464 p = strchr(sf, ':');
@@ -536,6 +546,46 @@ struct sort_entry sort_cpu = {
536 .se_width_idx = HISTC_CPU, 546 .se_width_idx = HISTC_CPU,
537}; 547};
538 548
549/* --sort cgroup_id */
550
551static int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev)
552{
553 return (int64_t)(right_dev - left_dev);
554}
555
556static int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino)
557{
558 return (int64_t)(right_ino - left_ino);
559}
560
561static int64_t
562sort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right)
563{
564 int64_t ret;
565
566 ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev);
567 if (ret != 0)
568 return ret;
569
570 return _sort__cgroup_inode_cmp(right->cgroup_id.ino,
571 left->cgroup_id.ino);
572}
573
574static int hist_entry__cgroup_id_snprintf(struct hist_entry *he,
575 char *bf, size_t size,
576 unsigned int width __maybe_unused)
577{
578 return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev,
579 he->cgroup_id.ino);
580}
581
582struct sort_entry sort_cgroup_id = {
583 .se_header = "cgroup id (dev/inode)",
584 .se_cmp = sort__cgroup_id_cmp,
585 .se_snprintf = hist_entry__cgroup_id_snprintf,
586 .se_width_idx = HISTC_CGROUP_ID,
587};
588
539/* --sort socket */ 589/* --sort socket */
540 590
541static int64_t 591static int64_t
@@ -846,6 +896,9 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
846static int64_t 896static int64_t
847sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) 897sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
848{ 898{
899 if (!left->branch_info || !right->branch_info)
900 return cmp_null(left->branch_info, right->branch_info);
901
849 return left->branch_info->flags.cycles - 902 return left->branch_info->flags.cycles -
850 right->branch_info->flags.cycles; 903 right->branch_info->flags.cycles;
851} 904}
@@ -853,6 +906,8 @@ sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
853static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf, 906static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
854 size_t size, unsigned int width) 907 size_t size, unsigned int width)
855{ 908{
909 if (!he->branch_info)
910 return scnprintf(bf, size, "%-.*s", width, "N/A");
856 if (he->branch_info->flags.cycles == 0) 911 if (he->branch_info->flags.cycles == 0)
857 return repsep_snprintf(bf, size, "%-*s", width, "-"); 912 return repsep_snprintf(bf, size, "%-*s", width, "-");
858 return repsep_snprintf(bf, size, "%-*hd", width, 913 return repsep_snprintf(bf, size, "%-*hd", width,
@@ -1396,6 +1451,46 @@ struct sort_entry sort_transaction = {
1396 .se_width_idx = HISTC_TRANSACTION, 1451 .se_width_idx = HISTC_TRANSACTION,
1397}; 1452};
1398 1453
1454/* --sort symbol_size */
1455
1456static int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r)
1457{
1458 int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0;
1459 int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0;
1460
1461 return size_l < size_r ? -1 :
1462 size_l == size_r ? 0 : 1;
1463}
1464
1465static int64_t
1466sort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right)
1467{
1468 return _sort__sym_size_cmp(right->ms.sym, left->ms.sym);
1469}
1470
1471static int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf,
1472 size_t bf_size, unsigned int width)
1473{
1474 if (sym)
1475 return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym));
1476
1477 return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
1478}
1479
1480static int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf,
1481 size_t size, unsigned int width)
1482{
1483 return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width);
1484}
1485
1486struct sort_entry sort_sym_size = {
1487 .se_header = "Symbol size",
1488 .se_cmp = sort__sym_size_cmp,
1489 .se_snprintf = hist_entry__sym_size_snprintf,
1490 .se_width_idx = HISTC_SYM_SIZE,
1491};
1492
1493
1399struct sort_dimension { 1494struct sort_dimension {
1400 const char *name; 1495 const char *name;
1401 struct sort_entry *entry; 1496 struct sort_entry *entry;
@@ -1418,6 +1513,8 @@ static struct sort_dimension common_sort_dimensions[] = {
1418 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 1513 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1419 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1514 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1420 DIM(SORT_TRACE, "trace", sort_trace), 1515 DIM(SORT_TRACE, "trace", sort_trace),
1516 DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
1517 DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
1421}; 1518};
1422 1519
1423#undef DIM 1520#undef DIM
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 796c847e2f00..b7c75597e18f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -2,7 +2,7 @@
2#define __PERF_SORT_H 2#define __PERF_SORT_H
3#include "../builtin.h" 3#include "../builtin.h"
4 4
5#include "util.h" 5#include <regex.h>
6 6
7#include "color.h" 7#include "color.h"
8#include <linux/list.h> 8#include <linux/list.h>
@@ -11,7 +11,6 @@
11#include "symbol.h" 11#include "symbol.h"
12#include "string.h" 12#include "string.h"
13#include "callchain.h" 13#include "callchain.h"
14#include "strlist.h"
15#include "values.h" 14#include "values.h"
16 15
17#include "../perf.h" 16#include "../perf.h"
@@ -21,7 +20,9 @@
21#include <subcmd/parse-options.h> 20#include <subcmd/parse-options.h>
22#include "parse-events.h" 21#include "parse-events.h"
23#include "hist.h" 22#include "hist.h"
24#include "thread.h" 23#include "srcline.h"
24
25struct thread;
25 26
26extern regex_t parent_regex; 27extern regex_t parent_regex;
27extern const char *sort_order; 28extern const char *sort_order;
@@ -54,6 +55,11 @@ struct he_stat {
54 u32 nr_events; 55 u32 nr_events;
55}; 56};
56 57
58struct namespace_id {
59 u64 dev;
60 u64 ino;
61};
62
57struct hist_entry_diff { 63struct hist_entry_diff {
58 bool computed; 64 bool computed;
59 union { 65 union {
@@ -91,6 +97,7 @@ struct hist_entry {
91 struct map_symbol ms; 97 struct map_symbol ms;
92 struct thread *thread; 98 struct thread *thread;
93 struct comm *comm; 99 struct comm *comm;
100 struct namespace_id cgroup_id;
94 u64 ip; 101 u64 ip;
95 u64 transaction; 102 u64 transaction;
96 s32 socket; 103 s32 socket;
@@ -122,6 +129,7 @@ struct hist_entry {
122 }; 129 };
123 char *srcline; 130 char *srcline;
124 char *srcfile; 131 char *srcfile;
132 struct inline_node *inline_node;
125 struct symbol *parent; 133 struct symbol *parent;
126 struct branch_info *branch_info; 134 struct branch_info *branch_info;
127 struct hists *hists; 135 struct hists *hists;
@@ -211,6 +219,8 @@ enum sort_type {
211 SORT_GLOBAL_WEIGHT, 219 SORT_GLOBAL_WEIGHT,
212 SORT_TRANSACTION, 220 SORT_TRANSACTION,
213 SORT_TRACE, 221 SORT_TRACE,
222 SORT_SYM_SIZE,
223 SORT_CGROUP_ID,
214 224
215 /* branch stack specific sort keys */ 225 /* branch stack specific sort keys */
216 __SORT_BRANCH_STACK, 226 __SORT_BRANCH_STACK,
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index b4db3f48e3b0..df051a52393c 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -1,3 +1,4 @@
1#include <inttypes.h>
1#include <stdio.h> 2#include <stdio.h>
2#include <stdlib.h> 3#include <stdlib.h>
3#include <string.h> 4#include <string.h>
@@ -7,11 +8,59 @@
7#include "util/dso.h" 8#include "util/dso.h"
8#include "util/util.h" 9#include "util/util.h"
9#include "util/debug.h" 10#include "util/debug.h"
11#include "util/callchain.h"
12#include "srcline.h"
10 13
11#include "symbol.h" 14#include "symbol.h"
12 15
13bool srcline_full_filename; 16bool srcline_full_filename;
14 17
18static const char *dso__name(struct dso *dso)
19{
20 const char *dso_name;
21
22 if (dso->symsrc_filename)
23 dso_name = dso->symsrc_filename;
24 else
25 dso_name = dso->long_name;
26
27 if (dso_name[0] == '[')
28 return NULL;
29
30 if (!strncmp(dso_name, "/tmp/perf-", 10))
31 return NULL;
32
33 return dso_name;
34}
35
36static int inline_list__append(char *filename, char *funcname, int line_nr,
37 struct inline_node *node, struct dso *dso)
38{
39 struct inline_list *ilist;
40 char *demangled;
41
42 ilist = zalloc(sizeof(*ilist));
43 if (ilist == NULL)
44 return -1;
45
46 ilist->filename = filename;
47 ilist->line_nr = line_nr;
48
49 if (dso != NULL) {
50 demangled = dso__demangle_sym(dso, 0, funcname);
51 if (demangled == NULL) {
52 ilist->funcname = funcname;
53 } else {
54 ilist->funcname = demangled;
55 free(funcname);
56 }
57 }
58
59 list_add_tail(&ilist->list, &node->val);
60
61 return 0;
62}
63
15#ifdef HAVE_LIBBFD_SUPPORT 64#ifdef HAVE_LIBBFD_SUPPORT
16 65
17/* 66/*
@@ -151,9 +200,17 @@ static void addr2line_cleanup(struct a2l_data *a2l)
151 200
152#define MAX_INLINE_NEST 1024 201#define MAX_INLINE_NEST 1024
153 202
203static void inline_list__reverse(struct inline_node *node)
204{
205 struct inline_list *ilist, *n;
206
207 list_for_each_entry_safe_reverse(ilist, n, &node->val, list)
208 list_move_tail(&ilist->list, &node->val);
209}
210
154static int addr2line(const char *dso_name, u64 addr, 211static int addr2line(const char *dso_name, u64 addr,
155 char **file, unsigned int *line, struct dso *dso, 212 char **file, unsigned int *line, struct dso *dso,
156 bool unwind_inlines) 213 bool unwind_inlines, struct inline_node *node)
157{ 214{
158 int ret = 0; 215 int ret = 0;
159 struct a2l_data *a2l = dso->a2l; 216 struct a2l_data *a2l = dso->a2l;
@@ -178,8 +235,21 @@ static int addr2line(const char *dso_name, u64 addr,
178 235
179 while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, 236 while (bfd_find_inliner_info(a2l->abfd, &a2l->filename,
180 &a2l->funcname, &a2l->line) && 237 &a2l->funcname, &a2l->line) &&
181 cnt++ < MAX_INLINE_NEST) 238 cnt++ < MAX_INLINE_NEST) {
182 ; 239
240 if (node != NULL) {
241 if (inline_list__append(strdup(a2l->filename),
242 strdup(a2l->funcname),
243 a2l->line, node,
244 dso) != 0)
245 return 0;
246 }
247 }
248
249 if ((node != NULL) &&
250 (callchain_param.order != ORDER_CALLEE)) {
251 inline_list__reverse(node);
252 }
183 } 253 }
184 254
185 if (a2l->found && a2l->filename) { 255 if (a2l->found && a2l->filename) {
@@ -205,18 +275,68 @@ void dso__free_a2l(struct dso *dso)
205 dso->a2l = NULL; 275 dso->a2l = NULL;
206} 276}
207 277
278static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
279 struct dso *dso)
280{
281 char *file = NULL;
282 unsigned int line = 0;
283 struct inline_node *node;
284
285 node = zalloc(sizeof(*node));
286 if (node == NULL) {
287 perror("not enough memory for the inline node");
288 return NULL;
289 }
290
291 INIT_LIST_HEAD(&node->val);
292 node->addr = addr;
293
294 if (!addr2line(dso_name, addr, &file, &line, dso, TRUE, node))
295 goto out_free_inline_node;
296
297 if (list_empty(&node->val))
298 goto out_free_inline_node;
299
300 return node;
301
302out_free_inline_node:
303 inline_node__delete(node);
304 return NULL;
305}
306
208#else /* HAVE_LIBBFD_SUPPORT */ 307#else /* HAVE_LIBBFD_SUPPORT */
209 308
309static int filename_split(char *filename, unsigned int *line_nr)
310{
311 char *sep;
312
313 sep = strchr(filename, '\n');
314 if (sep)
315 *sep = '\0';
316
317 if (!strcmp(filename, "??:0"))
318 return 0;
319
320 sep = strchr(filename, ':');
321 if (sep) {
322 *sep++ = '\0';
323 *line_nr = strtoul(sep, NULL, 0);
324 return 1;
325 }
326
327 return 0;
328}
329
210static int addr2line(const char *dso_name, u64 addr, 330static int addr2line(const char *dso_name, u64 addr,
211 char **file, unsigned int *line_nr, 331 char **file, unsigned int *line_nr,
212 struct dso *dso __maybe_unused, 332 struct dso *dso __maybe_unused,
213 bool unwind_inlines __maybe_unused) 333 bool unwind_inlines __maybe_unused,
334 struct inline_node *node __maybe_unused)
214{ 335{
215 FILE *fp; 336 FILE *fp;
216 char cmd[PATH_MAX]; 337 char cmd[PATH_MAX];
217 char *filename = NULL; 338 char *filename = NULL;
218 size_t len; 339 size_t len;
219 char *sep;
220 int ret = 0; 340 int ret = 0;
221 341
222 scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64, 342 scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
@@ -233,23 +353,14 @@ static int addr2line(const char *dso_name, u64 addr,
233 goto out; 353 goto out;
234 } 354 }
235 355
236 sep = strchr(filename, '\n'); 356 ret = filename_split(filename, line_nr);
237 if (sep) 357 if (ret != 1) {
238 *sep = '\0';
239
240 if (!strcmp(filename, "??:0")) {
241 pr_debug("no debugging info in %s\n", dso_name);
242 free(filename); 358 free(filename);
243 goto out; 359 goto out;
244 } 360 }
245 361
246 sep = strchr(filename, ':'); 362 *file = filename;
247 if (sep) { 363
248 *sep++ = '\0';
249 *file = filename;
250 *line_nr = strtoul(sep, NULL, 0);
251 ret = 1;
252 }
253out: 364out:
254 pclose(fp); 365 pclose(fp);
255 return ret; 366 return ret;
@@ -259,6 +370,58 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
259{ 370{
260} 371}
261 372
373static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
374 struct dso *dso __maybe_unused)
375{
376 FILE *fp;
377 char cmd[PATH_MAX];
378 struct inline_node *node;
379 char *filename = NULL;
380 size_t len;
381 unsigned int line_nr = 0;
382
383 scnprintf(cmd, sizeof(cmd), "addr2line -e %s -i %016"PRIx64,
384 dso_name, addr);
385
386 fp = popen(cmd, "r");
387 if (fp == NULL) {
388 pr_err("popen failed for %s\n", dso_name);
389 return NULL;
390 }
391
392 node = zalloc(sizeof(*node));
393 if (node == NULL) {
394 perror("not enough memory for the inline node");
395 goto out;
396 }
397
398 INIT_LIST_HEAD(&node->val);
399 node->addr = addr;
400
401 while (getline(&filename, &len, fp) != -1) {
402 if (filename_split(filename, &line_nr) != 1) {
403 free(filename);
404 goto out;
405 }
406
407 if (inline_list__append(filename, NULL, line_nr, node,
408 NULL) != 0)
409 goto out;
410
411 filename = NULL;
412 }
413
414out:
415 pclose(fp);
416
417 if (list_empty(&node->val)) {
418 inline_node__delete(node);
419 return NULL;
420 }
421
422 return node;
423}
424
262#endif /* HAVE_LIBBFD_SUPPORT */ 425#endif /* HAVE_LIBBFD_SUPPORT */
263 426
264/* 427/*
@@ -268,7 +431,7 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
268#define A2L_FAIL_LIMIT 123 431#define A2L_FAIL_LIMIT 123
269 432
270char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 433char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
271 bool show_sym, bool unwind_inlines) 434 bool show_sym, bool show_addr, bool unwind_inlines)
272{ 435{
273 char *file = NULL; 436 char *file = NULL;
274 unsigned line = 0; 437 unsigned line = 0;
@@ -278,18 +441,11 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
278 if (!dso->has_srcline) 441 if (!dso->has_srcline)
279 goto out; 442 goto out;
280 443
281 if (dso->symsrc_filename) 444 dso_name = dso__name(dso);
282 dso_name = dso->symsrc_filename; 445 if (dso_name == NULL)
283 else
284 dso_name = dso->long_name;
285
286 if (dso_name[0] == '[')
287 goto out;
288
289 if (!strncmp(dso_name, "/tmp/perf-", 10))
290 goto out; 446 goto out;
291 447
292 if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines)) 448 if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines, NULL))
293 goto out; 449 goto out;
294 450
295 if (asprintf(&srcline, "%s:%u", 451 if (asprintf(&srcline, "%s:%u",
@@ -309,6 +465,11 @@ out:
309 dso->has_srcline = 0; 465 dso->has_srcline = 0;
310 dso__free_a2l(dso); 466 dso__free_a2l(dso);
311 } 467 }
468
469 if (!show_addr)
470 return (show_sym && sym) ?
471 strndup(sym->name, sym->namelen) : NULL;
472
312 if (sym) { 473 if (sym) {
313 if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "", 474 if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
314 addr - sym->start) < 0) 475 addr - sym->start) < 0)
@@ -325,7 +486,32 @@ void free_srcline(char *srcline)
325} 486}
326 487
327char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, 488char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
328 bool show_sym) 489 bool show_sym, bool show_addr)
490{
491 return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
492}
493
494struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr)
329{ 495{
330 return __get_srcline(dso, addr, sym, show_sym, false); 496 const char *dso_name;
497
498 dso_name = dso__name(dso);
499 if (dso_name == NULL)
500 return NULL;
501
502 return addr2inlines(dso_name, addr, dso);
503}
504
505void inline_node__delete(struct inline_node *node)
506{
507 struct inline_list *ilist, *tmp;
508
509 list_for_each_entry_safe(ilist, tmp, &node->val, list) {
510 list_del_init(&ilist->list);
511 zfree(&ilist->filename);
512 zfree(&ilist->funcname);
513 free(ilist);
514 }
515
516 free(node);
331} 517}
diff --git a/tools/perf/util/srcline.h b/tools/perf/util/srcline.h
new file mode 100644
index 000000000000..7b52ba88676e
--- /dev/null
+++ b/tools/perf/util/srcline.h
@@ -0,0 +1,34 @@
1#ifndef PERF_SRCLINE_H
2#define PERF_SRCLINE_H
3
4#include <linux/list.h>
5#include <linux/types.h>
6
7struct dso;
8struct symbol;
9
10extern bool srcline_full_filename;
11char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
12 bool show_sym, bool show_addr);
13char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
14 bool show_sym, bool show_addr, bool unwind_inlines);
15void free_srcline(char *srcline);
16
17#define SRCLINE_UNKNOWN ((char *) "??:0")
18
19struct inline_list {
20 char *filename;
21 char *funcname;
22 unsigned int line_nr;
23 struct list_head list;
24};
25
26struct inline_node {
27 u64 addr;
28 struct list_head val;
29};
30
31struct inline_node *dso__parse_addr_inlines(struct dso *dso, u64 addr);
32void inline_node__delete(struct inline_node *node);
33
34#endif /* PERF_SRCLINE_H */
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 8a2bbd2a4d82..ac10cc675d39 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -3,6 +3,9 @@
3#include "stat.h" 3#include "stat.h"
4#include "color.h" 4#include "color.h"
5#include "pmu.h" 5#include "pmu.h"
6#include "rblist.h"
7#include "evlist.h"
8#include "expr.h"
6 9
7enum { 10enum {
8 CTX_BIT_USER = 1 << 0, 11 CTX_BIT_USER = 1 << 0,
@@ -41,13 +44,73 @@ static struct stats runtime_topdown_slots_issued[NUM_CTX][MAX_NR_CPUS];
41static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS]; 44static struct stats runtime_topdown_slots_retired[NUM_CTX][MAX_NR_CPUS];
42static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS]; 45static struct stats runtime_topdown_fetch_bubbles[NUM_CTX][MAX_NR_CPUS];
43static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS]; 46static struct stats runtime_topdown_recovery_bubbles[NUM_CTX][MAX_NR_CPUS];
47static struct rblist runtime_saved_values;
44static bool have_frontend_stalled; 48static bool have_frontend_stalled;
45 49
46struct stats walltime_nsecs_stats; 50struct stats walltime_nsecs_stats;
47 51
52struct saved_value {
53 struct rb_node rb_node;
54 struct perf_evsel *evsel;
55 int cpu;
56 int ctx;
57 struct stats stats;
58};
59
60static int saved_value_cmp(struct rb_node *rb_node, const void *entry)
61{
62 struct saved_value *a = container_of(rb_node,
63 struct saved_value,
64 rb_node);
65 const struct saved_value *b = entry;
66
67 if (a->ctx != b->ctx)
68 return a->ctx - b->ctx;
69 if (a->cpu != b->cpu)
70 return a->cpu - b->cpu;
71 return a->evsel - b->evsel;
72}
73
74static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused,
75 const void *entry)
76{
77 struct saved_value *nd = malloc(sizeof(struct saved_value));
78
79 if (!nd)
80 return NULL;
81 memcpy(nd, entry, sizeof(struct saved_value));
82 return &nd->rb_node;
83}
84
85static struct saved_value *saved_value_lookup(struct perf_evsel *evsel,
86 int cpu, int ctx,
87 bool create)
88{
89 struct rb_node *nd;
90 struct saved_value dm = {
91 .cpu = cpu,
92 .ctx = ctx,
93 .evsel = evsel,
94 };
95 nd = rblist__find(&runtime_saved_values, &dm);
96 if (nd)
97 return container_of(nd, struct saved_value, rb_node);
98 if (create) {
99 rblist__add_node(&runtime_saved_values, &dm);
100 nd = rblist__find(&runtime_saved_values, &dm);
101 if (nd)
102 return container_of(nd, struct saved_value, rb_node);
103 }
104 return NULL;
105}
106
48void perf_stat__init_shadow_stats(void) 107void perf_stat__init_shadow_stats(void)
49{ 108{
50 have_frontend_stalled = pmu_have_event("cpu", "stalled-cycles-frontend"); 109 have_frontend_stalled = pmu_have_event("cpu", "stalled-cycles-frontend");
110 rblist__init(&runtime_saved_values);
111 runtime_saved_values.node_cmp = saved_value_cmp;
112 runtime_saved_values.node_new = saved_value_new;
113 /* No delete for now */
51} 114}
52 115
53static int evsel_context(struct perf_evsel *evsel) 116static int evsel_context(struct perf_evsel *evsel)
@@ -70,6 +133,8 @@ static int evsel_context(struct perf_evsel *evsel)
70 133
71void perf_stat__reset_shadow_stats(void) 134void perf_stat__reset_shadow_stats(void)
72{ 135{
136 struct rb_node *pos, *next;
137
73 memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats)); 138 memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats));
74 memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats)); 139 memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats));
75 memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats)); 140 memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats));
@@ -92,6 +157,15 @@ void perf_stat__reset_shadow_stats(void)
92 memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued)); 157 memset(runtime_topdown_slots_issued, 0, sizeof(runtime_topdown_slots_issued));
93 memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles)); 158 memset(runtime_topdown_fetch_bubbles, 0, sizeof(runtime_topdown_fetch_bubbles));
94 memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles)); 159 memset(runtime_topdown_recovery_bubbles, 0, sizeof(runtime_topdown_recovery_bubbles));
160
161 next = rb_first(&runtime_saved_values.entries);
162 while (next) {
163 pos = next;
164 next = rb_next(pos);
165 memset(&container_of(pos, struct saved_value, rb_node)->stats,
166 0,
167 sizeof(struct stats));
168 }
95} 169}
96 170
97/* 171/*
@@ -143,6 +217,12 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
143 update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]); 217 update_stats(&runtime_dtlb_cache_stats[ctx][cpu], count[0]);
144 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB)) 218 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
145 update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]); 219 update_stats(&runtime_itlb_cache_stats[ctx][cpu], count[0]);
220
221 if (counter->collect_stat) {
222 struct saved_value *v = saved_value_lookup(counter, cpu, ctx,
223 true);
224 update_stats(&v->stats, count[0]);
225 }
146} 226}
147 227
148/* used for get_ratio_color() */ 228/* used for get_ratio_color() */
@@ -172,6 +252,95 @@ static const char *get_ratio_color(enum grc_type type, double ratio)
172 return color; 252 return color;
173} 253}
174 254
255static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list,
256 const char *name)
257{
258 struct perf_evsel *c2;
259
260 evlist__for_each_entry (evsel_list, c2) {
261 if (!strcasecmp(c2->name, name))
262 return c2;
263 }
264 return NULL;
265}
266
267/* Mark MetricExpr target events and link events using them to them. */
268void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list)
269{
270 struct perf_evsel *counter, *leader, **metric_events, *oc;
271 bool found;
272 const char **metric_names;
273 int i;
274 int num_metric_names;
275
276 evlist__for_each_entry(evsel_list, counter) {
277 bool invalid = false;
278
279 leader = counter->leader;
280 if (!counter->metric_expr)
281 continue;
282 metric_events = counter->metric_events;
283 if (!metric_events) {
284 if (expr__find_other(counter->metric_expr, counter->name,
285 &metric_names, &num_metric_names) < 0)
286 continue;
287
288 metric_events = calloc(sizeof(struct perf_evsel *),
289 num_metric_names + 1);
290 if (!metric_events)
291 return;
292 counter->metric_events = metric_events;
293 }
294
295 for (i = 0; i < num_metric_names; i++) {
296 found = false;
297 if (leader) {
298 /* Search in group */
299 for_each_group_member (oc, leader) {
300 if (!strcasecmp(oc->name, metric_names[i])) {
301 found = true;
302 break;
303 }
304 }
305 }
306 if (!found) {
307 /* Search ignoring groups */
308 oc = perf_stat__find_event(evsel_list, metric_names[i]);
309 }
310 if (!oc) {
311 /* Deduping one is good enough to handle duplicated PMUs. */
312 static char *printed;
313
314 /*
315 * Adding events automatically would be difficult, because
316 * it would risk creating groups that are not schedulable.
317 * perf stat doesn't understand all the scheduling constraints
318 * of events. So we ask the user instead to add the missing
319 * events.
320 */
321 if (!printed || strcasecmp(printed, metric_names[i])) {
322 fprintf(stderr,
323 "Add %s event to groups to get metric expression for %s\n",
324 metric_names[i],
325 counter->name);
326 printed = strdup(metric_names[i]);
327 }
328 invalid = true;
329 continue;
330 }
331 metric_events[i] = oc;
332 oc->collect_stat = true;
333 }
334 metric_events[i] = NULL;
335 free(metric_names);
336 if (invalid) {
337 free(metric_events);
338 counter->metric_events = NULL;
339 counter->metric_expr = NULL;
340 }
341 }
342}
343
175static void print_stalled_cycles_frontend(int cpu, 344static void print_stalled_cycles_frontend(int cpu,
176 struct perf_evsel *evsel, double avg, 345 struct perf_evsel *evsel, double avg,
177 struct perf_stat_output_ctx *out) 346 struct perf_stat_output_ctx *out)
@@ -614,6 +783,34 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
614 be_bound * 100.); 783 be_bound * 100.);
615 else 784 else
616 print_metric(ctxp, NULL, NULL, name, 0); 785 print_metric(ctxp, NULL, NULL, name, 0);
786 } else if (evsel->metric_expr) {
787 struct parse_ctx pctx;
788 int i;
789
790 expr__ctx_init(&pctx);
791 expr__add_id(&pctx, evsel->name, avg);
792 for (i = 0; evsel->metric_events[i]; i++) {
793 struct saved_value *v;
794
795 v = saved_value_lookup(evsel->metric_events[i], cpu, ctx, false);
796 if (!v)
797 break;
798 expr__add_id(&pctx, evsel->metric_events[i]->name,
799 avg_stats(&v->stats));
800 }
801 if (!evsel->metric_events[i]) {
802 const char *p = evsel->metric_expr;
803
804 if (expr__parse(&ratio, &pctx, &p) == 0)
805 print_metric(ctxp, NULL, "%8.1f",
806 evsel->metric_name ?
807 evsel->metric_name :
808 out->force_header ? evsel->name : "",
809 ratio);
810 else
811 print_metric(ctxp, NULL, NULL, "", 0);
812 } else
813 print_metric(ctxp, NULL, NULL, "", 0);
617 } else if (runtime_nsecs_stats[cpu].n != 0) { 814 } else if (runtime_nsecs_stats[cpu].n != 0) {
618 char unit = 'M'; 815 char unit = 'M';
619 char unit_buf[10]; 816 char unit_buf[10];
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 0d51334a9b46..c58174443dc1 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -1,3 +1,5 @@
1#include <errno.h>
2#include <inttypes.h>
1#include <math.h> 3#include <math.h>
2#include "stat.h" 4#include "stat.h"
3#include "evlist.h" 5#include "evlist.h"
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index c29bb94c48a4..0a65ae23f495 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -85,11 +85,13 @@ struct perf_stat_output_ctx {
85 void *ctx; 85 void *ctx;
86 print_metric_t print_metric; 86 print_metric_t print_metric;
87 new_line_t new_line; 87 new_line_t new_line;
88 bool force_header;
88}; 89};
89 90
90void perf_stat__print_shadow_stats(struct perf_evsel *evsel, 91void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
91 double avg, int cpu, 92 double avg, int cpu,
92 struct perf_stat_output_ctx *out); 93 struct perf_stat_output_ctx *out);
94void perf_stat__collect_metric_expr(struct perf_evlist *);
93 95
94int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw); 96int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
95void perf_evlist__free_stats(struct perf_evlist *evlist); 97void perf_evlist__free_stats(struct perf_evlist *evlist);
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 817593908d47..aafe908b82b5 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -1,15 +1,7 @@
1#include "debug.h" 1#include "debug.h"
2#include "util.h" 2#include "util.h"
3#include <linux/kernel.h> 3#include <linux/kernel.h>
4 4#include <errno.h>
5int prefixcmp(const char *str, const char *prefix)
6{
7 for (; ; str++, prefix++)
8 if (!*prefix)
9 return 0;
10 else if (*str != *prefix)
11 return (unsigned char)*prefix - (unsigned char)*str;
12}
13 5
14/* 6/*
15 * Used as the default ->buf value, so that people can always assume 7 * Used as the default ->buf value, so that people can always assume
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
index efb53772e0ec..4dc0af669a30 100644
--- a/tools/perf/util/strfilter.c
+++ b/tools/perf/util/strfilter.c
@@ -1,7 +1,10 @@
1#include "util.h" 1#include "util.h"
2#include "string.h" 2#include "string2.h"
3#include "strfilter.h" 3#include "strfilter.h"
4 4
5#include <errno.h>
6#include "sane_ctype.h"
7
5/* Operators */ 8/* Operators */
6static const char *OP_and = "&"; /* Logical AND */ 9static const char *OP_and = "&"; /* Logical AND */
7static const char *OP_or = "|"; /* Logical OR */ 10static const char *OP_or = "|"; /* Logical OR */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index bddca519dd58..cca53b693a48 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,5 +1,9 @@
1#include "util.h" 1#include "string2.h"
2#include "linux/string.h" 2#include <linux/kernel.h>
3#include <linux/string.h>
4#include <stdlib.h>
5
6#include "sane_ctype.h"
3 7
4#define K 1024LL 8#define K 1024LL
5/* 9/*
@@ -99,8 +103,10 @@ static int count_argc(const char *str)
99void argv_free(char **argv) 103void argv_free(char **argv)
100{ 104{
101 char **p; 105 char **p;
102 for (p = argv; *p; p++) 106 for (p = argv; *p; p++) {
103 zfree(p); 107 free(*p);
108 *p = NULL;
109 }
104 110
105 free(argv); 111 free(argv);
106} 112}
@@ -120,7 +126,7 @@ void argv_free(char **argv)
120char **argv_split(const char *str, int *argcp) 126char **argv_split(const char *str, int *argcp)
121{ 127{
122 int argc = count_argc(str); 128 int argc = count_argc(str);
123 char **argv = zalloc(sizeof(*argv) * (argc+1)); 129 char **argv = calloc(argc + 1, sizeof(*argv));
124 char **argvp; 130 char **argvp;
125 131
126 if (argv == NULL) 132 if (argv == NULL)
@@ -322,12 +328,8 @@ char *strxfrchar(char *s, char from, char to)
322 */ 328 */
323char *ltrim(char *s) 329char *ltrim(char *s)
324{ 330{
325 int len = strlen(s); 331 while (isspace(*s))
326
327 while (len && isspace(*s)) {
328 len--;
329 s++; 332 s++;
330 }
331 333
332 return s; 334 return s;
333} 335}
@@ -381,7 +383,7 @@ char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints
381 goto out_err_overflow; 383 goto out_err_overflow;
382 384
383 if (i > 0) 385 if (i > 0)
384 printed += snprintf(e + printed, size - printed, " %s ", or_and); 386 printed += scnprintf(e + printed, size - printed, " %s ", or_and);
385 printed += scnprintf(e + printed, size - printed, 387 printed += scnprintf(e + printed, size - printed,
386 "%s %s %d", var, eq_neq, ints[i]); 388 "%s %s %d", var, eq_neq, ints[i]);
387 } 389 }
diff --git a/tools/perf/util/string2.h b/tools/perf/util/string2.h
new file mode 100644
index 000000000000..2f619681bd6a
--- /dev/null
+++ b/tools/perf/util/string2.h
@@ -0,0 +1,42 @@
1#ifndef PERF_STRING_H
2#define PERF_STRING_H
3
4#include <linux/types.h>
5#include <stddef.h>
6#include <string.h>
7
8s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp);
10void argv_free(char **argv);
11bool strglobmatch(const char *str, const char *pat);
12bool strglobmatch_nocase(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
14static inline bool strisglob(const char *str)
15{
16 return strpbrk(str, "*?[") != NULL;
17}
18int strtailcmp(const char *s1, const char *s2);
19char *strxfrchar(char *s, char from, char to);
20
21char *ltrim(char *s);
22char *rtrim(char *s);
23
24static inline char *trim(char *s)
25{
26 return ltrim(rtrim(s));
27}
28
29char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints);
30
31static inline char *asprintf_expr_in_ints(const char *var, size_t nints, int *ints)
32{
33 return asprintf_expr_inout_ints(var, true, nints, ints);
34}
35
36static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int *ints)
37{
38 return asprintf_expr_inout_ints(var, false, nints, ints);
39}
40
41
42#endif /* PERF_STRING_H */
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 0d3dfcb919b4..9de5434bb49e 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -10,6 +10,7 @@
10#include <stdio.h> 10#include <stdio.h>
11#include <stdlib.h> 11#include <stdlib.h>
12#include <string.h> 12#include <string.h>
13#include <unistd.h>
13 14
14static 15static
15struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry) 16struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 4e59ddeb4eda..e7ee47f7377a 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -10,8 +10,9 @@
10#include "demangle-rust.h" 10#include "demangle-rust.h"
11#include "machine.h" 11#include "machine.h"
12#include "vdso.h" 12#include "vdso.h"
13#include <symbol/kallsyms.h>
14#include "debug.h" 13#include "debug.h"
14#include "sane_ctype.h"
15#include <symbol/kallsyms.h>
15 16
16#ifndef EM_AARCH64 17#ifndef EM_AARCH64
17#define EM_AARCH64 183 /* ARM 64 bit */ 18#define EM_AARCH64 183 /* ARM 64 bit */
@@ -390,6 +391,11 @@ out_elf_end:
390 return 0; 391 return 0;
391} 392}
392 393
394char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name)
395{
396 return demangle_sym(dso, kmodule, elf_name);
397}
398
393/* 399/*
394 * Align offset to 4 bytes as needed for note name and descriptor data. 400 * Align offset to 4 bytes as needed for note name and descriptor data.
395 */ 401 */
@@ -1828,7 +1834,7 @@ void kcore_extract__delete(struct kcore_extract *kce)
1828static int populate_sdt_note(Elf **elf, const char *data, size_t len, 1834static int populate_sdt_note(Elf **elf, const char *data, size_t len,
1829 struct list_head *sdt_notes) 1835 struct list_head *sdt_notes)
1830{ 1836{
1831 const char *provider, *name; 1837 const char *provider, *name, *args;
1832 struct sdt_note *tmp = NULL; 1838 struct sdt_note *tmp = NULL;
1833 GElf_Ehdr ehdr; 1839 GElf_Ehdr ehdr;
1834 GElf_Addr base_off = 0; 1840 GElf_Addr base_off = 0;
@@ -1887,6 +1893,25 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len,
1887 goto out_free_prov; 1893 goto out_free_prov;
1888 } 1894 }
1889 1895
1896 args = memchr(name, '\0', data + len - name);
1897
1898 /*
1899 * There is no argument if:
1900 * - We reached the end of the note;
1901 * - There is not enough room to hold a potential string;
1902 * - The argument string is empty or just contains ':'.
1903 */
1904 if (args == NULL || data + len - args < 2 ||
1905 args[1] == ':' || args[1] == '\0')
1906 tmp->args = NULL;
1907 else {
1908 tmp->args = strdup(++args);
1909 if (!tmp->args) {
1910 ret = -ENOMEM;
1911 goto out_free_name;
1912 }
1913 }
1914
1890 if (gelf_getclass(*elf) == ELFCLASS32) { 1915 if (gelf_getclass(*elf) == ELFCLASS32) {
1891 memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr)); 1916 memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr));
1892 tmp->bit32 = true; 1917 tmp->bit32 = true;
@@ -1898,7 +1923,7 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len,
1898 if (!gelf_getehdr(*elf, &ehdr)) { 1923 if (!gelf_getehdr(*elf, &ehdr)) {
1899 pr_debug("%s : cannot get elf header.\n", __func__); 1924 pr_debug("%s : cannot get elf header.\n", __func__);
1900 ret = -EBADF; 1925 ret = -EBADF;
1901 goto out_free_name; 1926 goto out_free_args;
1902 } 1927 }
1903 1928
1904 /* Adjust the prelink effect : 1929 /* Adjust the prelink effect :
@@ -1923,6 +1948,8 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len,
1923 list_add_tail(&tmp->note_list, sdt_notes); 1948 list_add_tail(&tmp->note_list, sdt_notes);
1924 return 0; 1949 return 0;
1925 1950
1951out_free_args:
1952 free(tmp->args);
1926out_free_name: 1953out_free_name:
1927 free(tmp->name); 1954 free(tmp->name);
1928out_free_prov: 1955out_free_prov:
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 11cdde980545..40bf5d4c0bfd 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,6 +1,7 @@
1#include "symbol.h" 1#include "symbol.h"
2#include "util.h" 2#include "util.h"
3 3
4#include <errno.h>
4#include <stdio.h> 5#include <stdio.h>
5#include <fcntl.h> 6#include <fcntl.h>
6#include <string.h> 7#include <string.h>
@@ -373,3 +374,10 @@ int kcore_copy(const char *from_dir __maybe_unused,
373void symbol__elf_init(void) 374void symbol__elf_init(void)
374{ 375{
375} 376}
377
378char *dso__demangle_sym(struct dso *dso __maybe_unused,
379 int kmodule __maybe_unused,
380 char *elf_name __maybe_unused)
381{
382 return NULL;
383}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 9b4d8ba22fed..8f2b068ff756 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -3,6 +3,7 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <string.h> 5#include <string.h>
6#include <linux/kernel.h>
6#include <sys/types.h> 7#include <sys/types.h>
7#include <sys/stat.h> 8#include <sys/stat.h>
8#include <sys/param.h> 9#include <sys/param.h>
@@ -18,6 +19,8 @@
18#include "strlist.h" 19#include "strlist.h"
19#include "intlist.h" 20#include "intlist.h"
20#include "header.h" 21#include "header.h"
22#include "path.h"
23#include "sane_ctype.h"
21 24
22#include <elf.h> 25#include <elf.h>
23#include <limits.h> 26#include <limits.h>
@@ -87,6 +90,17 @@ static int prefix_underscores_count(const char *str)
87 return tail - str; 90 return tail - str;
88} 91}
89 92
93int __weak arch__compare_symbol_names(const char *namea, const char *nameb)
94{
95 return strcmp(namea, nameb);
96}
97
98int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb,
99 unsigned int n)
100{
101 return strncmp(namea, nameb, n);
102}
103
90int __weak arch__choose_best_symbol(struct symbol *syma, 104int __weak arch__choose_best_symbol(struct symbol *syma,
91 struct symbol *symb __maybe_unused) 105 struct symbol *symb __maybe_unused)
92{ 106{
@@ -396,8 +410,26 @@ static void symbols__sort_by_name(struct rb_root *symbols,
396 } 410 }
397} 411}
398 412
413int symbol__match_symbol_name(const char *name, const char *str,
414 enum symbol_tag_include includes)
415{
416 const char *versioning;
417
418 if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY &&
419 (versioning = strstr(name, "@@"))) {
420 int len = strlen(str);
421
422 if (len < versioning - name)
423 len = versioning - name;
424
425 return arch__compare_symbol_names_n(name, str, len);
426 } else
427 return arch__compare_symbol_names(name, str);
428}
429
399static struct symbol *symbols__find_by_name(struct rb_root *symbols, 430static struct symbol *symbols__find_by_name(struct rb_root *symbols,
400 const char *name) 431 const char *name,
432 enum symbol_tag_include includes)
401{ 433{
402 struct rb_node *n; 434 struct rb_node *n;
403 struct symbol_name_rb_node *s = NULL; 435 struct symbol_name_rb_node *s = NULL;
@@ -411,11 +443,11 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
411 int cmp; 443 int cmp;
412 444
413 s = rb_entry(n, struct symbol_name_rb_node, rb_node); 445 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
414 cmp = arch__compare_symbol_names(name, s->sym.name); 446 cmp = symbol__match_symbol_name(s->sym.name, name, includes);
415 447
416 if (cmp < 0) 448 if (cmp > 0)
417 n = n->rb_left; 449 n = n->rb_left;
418 else if (cmp > 0) 450 else if (cmp < 0)
419 n = n->rb_right; 451 n = n->rb_right;
420 else 452 else
421 break; 453 break;
@@ -424,16 +456,17 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
424 if (n == NULL) 456 if (n == NULL)
425 return NULL; 457 return NULL;
426 458
427 /* return first symbol that has same name (if any) */ 459 if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY)
428 for (n = rb_prev(n); n; n = rb_prev(n)) { 460 /* return first symbol that has same name (if any) */
429 struct symbol_name_rb_node *tmp; 461 for (n = rb_prev(n); n; n = rb_prev(n)) {
462 struct symbol_name_rb_node *tmp;
430 463
431 tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 464 tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
432 if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 465 if (arch__compare_symbol_names(tmp->sym.name, s->sym.name))
433 break; 466 break;
434 467
435 s = tmp; 468 s = tmp;
436 } 469 }
437 470
438 return &s->sym; 471 return &s->sym;
439} 472}
@@ -463,7 +496,7 @@ void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym)
463struct symbol *dso__find_symbol(struct dso *dso, 496struct symbol *dso__find_symbol(struct dso *dso,
464 enum map_type type, u64 addr) 497 enum map_type type, u64 addr)
465{ 498{
466 if (dso->last_find_result[type].addr != addr) { 499 if (dso->last_find_result[type].addr != addr || dso->last_find_result[type].symbol == NULL) {
467 dso->last_find_result[type].addr = addr; 500 dso->last_find_result[type].addr = addr;
468 dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr); 501 dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr);
469 } 502 }
@@ -500,7 +533,12 @@ struct symbol *symbol__next_by_name(struct symbol *sym)
500struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 533struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
501 const char *name) 534 const char *name)
502{ 535{
503 return symbols__find_by_name(&dso->symbol_names[type], name); 536 struct symbol *s = symbols__find_by_name(&dso->symbol_names[type], name,
537 SYMBOL_TAG_INCLUDE__NONE);
538 if (!s)
539 s = symbols__find_by_name(&dso->symbol_names[type], name,
540 SYMBOL_TAG_INCLUDE__DEFAULT_ONLY);
541 return s;
504} 542}
505 543
506void dso__sort_by_name(struct dso *dso, enum map_type type) 544void dso__sort_by_name(struct dso *dso, enum map_type type)
@@ -1072,8 +1110,9 @@ static int validate_kcore_addresses(const char *kallsyms_filename,
1072 if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1110 if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
1073 u64 start; 1111 u64 start;
1074 1112
1075 start = kallsyms__get_function_start(kallsyms_filename, 1113 if (kallsyms__get_function_start(kallsyms_filename,
1076 kmap->ref_reloc_sym->name); 1114 kmap->ref_reloc_sym->name, &start))
1115 return -ENOENT;
1077 if (start != kmap->ref_reloc_sym->addr) 1116 if (start != kmap->ref_reloc_sym->addr)
1078 return -EINVAL; 1117 return -EINVAL;
1079 } 1118 }
@@ -1245,9 +1284,7 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1245 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1284 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1246 return 0; 1285 return 0;
1247 1286
1248 addr = kallsyms__get_function_start(filename, 1287 if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr))
1249 kmap->ref_reloc_sym->name);
1250 if (!addr)
1251 return -1; 1288 return -1;
1252 1289
1253 *delta = addr - kmap->ref_reloc_sym->addr; 1290 *delta = addr - kmap->ref_reloc_sym->addr;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 6c358b7ed336..41ebba9a2eb2 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -13,7 +13,7 @@
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h" 14#include "build-id.h"
15#include "event.h" 15#include "event.h"
16#include "util.h" 16#include "path.h"
17 17
18#ifdef HAVE_LIBELF_SUPPORT 18#ifdef HAVE_LIBELF_SUPPORT
19#include <libelf.h> 19#include <libelf.h>
@@ -118,7 +118,8 @@ struct symbol_conf {
118 show_ref_callgraph, 118 show_ref_callgraph,
119 hide_unresolved, 119 hide_unresolved,
120 raw_trace, 120 raw_trace,
121 report_hierarchy; 121 report_hierarchy,
122 inline_name;
122 const char *vmlinux_name, 123 const char *vmlinux_name,
123 *kallsyms_name, 124 *kallsyms_name,
124 *source_prefix, 125 *source_prefix,
@@ -305,6 +306,8 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
305int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, 306int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
306 struct map *map); 307 struct map *map);
307 308
309char *dso__demangle_sym(struct dso *dso, int kmodule, char *elf_name);
310
308void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel); 311void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel);
309void symbols__insert(struct rb_root *symbols, struct symbol *sym); 312void symbols__insert(struct rb_root *symbols, struct symbol *sym);
310void symbols__fixup_duplicate(struct rb_root *symbols); 313void symbols__fixup_duplicate(struct rb_root *symbols);
@@ -345,12 +348,24 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym);
345#define SYMBOL_A 0 348#define SYMBOL_A 0
346#define SYMBOL_B 1 349#define SYMBOL_B 1
347 350
351int arch__compare_symbol_names(const char *namea, const char *nameb);
352int arch__compare_symbol_names_n(const char *namea, const char *nameb,
353 unsigned int n);
348int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb); 354int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb);
349 355
356enum symbol_tag_include {
357 SYMBOL_TAG_INCLUDE__NONE = 0,
358 SYMBOL_TAG_INCLUDE__DEFAULT_ONLY
359};
360
361int symbol__match_symbol_name(const char *namea, const char *nameb,
362 enum symbol_tag_include includes);
363
350/* structure containing an SDT note's info */ 364/* structure containing an SDT note's info */
351struct sdt_note { 365struct sdt_note {
352 char *name; /* name of the note*/ 366 char *name; /* name of the note*/
353 char *provider; /* provider name */ 367 char *provider; /* provider name */
368 char *args;
354 bool bit32; /* whether the location is 32 bits? */ 369 bool bit32; /* whether the location is 32 bits? */
355 union { /* location, base and semaphore addrs */ 370 union { /* location, base and semaphore addrs */
356 Elf64_Addr a64[3]; 371 Elf64_Addr a64[3];
diff --git a/tools/perf/util/term.c b/tools/perf/util/term.c
index 90b47d8aa19c..8f254a74d97d 100644
--- a/tools/perf/util/term.c
+++ b/tools/perf/util/term.c
@@ -1,4 +1,8 @@
1#include "util.h" 1#include "term.h"
2#include <stdlib.h>
3#include <termios.h>
4#include <unistd.h>
5#include <sys/ioctl.h>
2 6
3void get_term_dimensions(struct winsize *ws) 7void get_term_dimensions(struct winsize *ws)
4{ 8{
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index d3301529f6a7..dd17d6a38d3a 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -15,6 +15,7 @@
15 15
16#include <linux/rbtree.h> 16#include <linux/rbtree.h>
17#include <linux/list.h> 17#include <linux/list.h>
18#include <errno.h>
18#include "thread.h" 19#include "thread.h"
19#include "event.h" 20#include "event.h"
20#include "machine.h" 21#include "machine.h"
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index f5af87f66663..378c418ca0c1 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -1,12 +1,15 @@
1#include "../perf.h" 1#include "../perf.h"
2#include <errno.h>
2#include <stdlib.h> 3#include <stdlib.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <string.h> 5#include <string.h>
6#include <linux/kernel.h>
5#include "session.h" 7#include "session.h"
6#include "thread.h" 8#include "thread.h"
7#include "thread-stack.h" 9#include "thread-stack.h"
8#include "util.h" 10#include "util.h"
9#include "debug.h" 11#include "debug.h"
12#include "namespaces.h"
10#include "comm.h" 13#include "comm.h"
11#include "unwind.h" 14#include "unwind.h"
12 15
@@ -40,6 +43,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
40 thread->tid = tid; 43 thread->tid = tid;
41 thread->ppid = -1; 44 thread->ppid = -1;
42 thread->cpu = -1; 45 thread->cpu = -1;
46 INIT_LIST_HEAD(&thread->namespaces_list);
43 INIT_LIST_HEAD(&thread->comm_list); 47 INIT_LIST_HEAD(&thread->comm_list);
44 48
45 comm_str = malloc(32); 49 comm_str = malloc(32);
@@ -53,7 +57,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
53 goto err_thread; 57 goto err_thread;
54 58
55 list_add(&comm->list, &thread->comm_list); 59 list_add(&comm->list, &thread->comm_list);
56 atomic_set(&thread->refcnt, 1); 60 refcount_set(&thread->refcnt, 1);
57 RB_CLEAR_NODE(&thread->rb_node); 61 RB_CLEAR_NODE(&thread->rb_node);
58 } 62 }
59 63
@@ -66,7 +70,8 @@ err_thread:
66 70
67void thread__delete(struct thread *thread) 71void thread__delete(struct thread *thread)
68{ 72{
69 struct comm *comm, *tmp; 73 struct namespaces *namespaces, *tmp_namespaces;
74 struct comm *comm, *tmp_comm;
70 75
71 BUG_ON(!RB_EMPTY_NODE(&thread->rb_node)); 76 BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));
72 77
@@ -76,7 +81,12 @@ void thread__delete(struct thread *thread)
76 map_groups__put(thread->mg); 81 map_groups__put(thread->mg);
77 thread->mg = NULL; 82 thread->mg = NULL;
78 } 83 }
79 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 84 list_for_each_entry_safe(namespaces, tmp_namespaces,
85 &thread->namespaces_list, list) {
86 list_del(&namespaces->list);
87 namespaces__free(namespaces);
88 }
89 list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
80 list_del(&comm->list); 90 list_del(&comm->list);
81 comm__free(comm); 91 comm__free(comm);
82 } 92 }
@@ -88,13 +98,13 @@ void thread__delete(struct thread *thread)
88struct thread *thread__get(struct thread *thread) 98struct thread *thread__get(struct thread *thread)
89{ 99{
90 if (thread) 100 if (thread)
91 atomic_inc(&thread->refcnt); 101 refcount_inc(&thread->refcnt);
92 return thread; 102 return thread;
93} 103}
94 104
95void thread__put(struct thread *thread) 105void thread__put(struct thread *thread)
96{ 106{
97 if (thread && atomic_dec_and_test(&thread->refcnt)) { 107 if (thread && refcount_dec_and_test(&thread->refcnt)) {
98 /* 108 /*
99 * Remove it from the dead_threads list, as last reference 109 * Remove it from the dead_threads list, as last reference
100 * is gone. 110 * is gone.
@@ -104,6 +114,38 @@ void thread__put(struct thread *thread)
104 } 114 }
105} 115}
106 116
117struct namespaces *thread__namespaces(const struct thread *thread)
118{
119 if (list_empty(&thread->namespaces_list))
120 return NULL;
121
122 return list_first_entry(&thread->namespaces_list, struct namespaces, list);
123}
124
125int thread__set_namespaces(struct thread *thread, u64 timestamp,
126 struct namespaces_event *event)
127{
128 struct namespaces *new, *curr = thread__namespaces(thread);
129
130 new = namespaces__new(event);
131 if (!new)
132 return -ENOMEM;
133
134 list_add(&new->list, &thread->namespaces_list);
135
136 if (timestamp && curr) {
137 /*
138 * setns syscall must have changed few or all the namespaces
139 * of this thread. Update end time for the namespaces
140 * previously used.
141 */
142 curr = list_next_entry(new, list);
143 curr->end_time = timestamp;
144 }
145
146 return 0;
147}
148
107struct comm *thread__comm(const struct thread *thread) 149struct comm *thread__comm(const struct thread *thread)
108{ 150{
109 if (list_empty(&thread->comm_list)) 151 if (list_empty(&thread->comm_list))
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 99263cb6e6b6..4eb849e9098f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_THREAD_H 1#ifndef __PERF_THREAD_H
2#define __PERF_THREAD_H 2#define __PERF_THREAD_H
3 3
4#include <linux/atomic.h> 4#include <linux/refcount.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <linux/list.h> 6#include <linux/list.h>
7#include <unistd.h> 7#include <unistd.h>
@@ -23,11 +23,12 @@ struct thread {
23 pid_t tid; 23 pid_t tid;
24 pid_t ppid; 24 pid_t ppid;
25 int cpu; 25 int cpu;
26 atomic_t refcnt; 26 refcount_t refcnt;
27 char shortname[3]; 27 char shortname[3];
28 bool comm_set; 28 bool comm_set;
29 int comm_len; 29 int comm_len;
30 bool dead; /* if set thread has exited */ 30 bool dead; /* if set thread has exited */
31 struct list_head namespaces_list;
31 struct list_head comm_list; 32 struct list_head comm_list;
32 u64 db_id; 33 u64 db_id;
33 34
@@ -40,6 +41,7 @@ struct thread {
40}; 41};
41 42
42struct machine; 43struct machine;
44struct namespaces;
43struct comm; 45struct comm;
44 46
45struct thread *thread__new(pid_t pid, pid_t tid); 47struct thread *thread__new(pid_t pid, pid_t tid);
@@ -62,6 +64,10 @@ static inline void thread__exited(struct thread *thread)
62 thread->dead = true; 64 thread->dead = true;
63} 65}
64 66
67struct namespaces *thread__namespaces(const struct thread *thread);
68int thread__set_namespaces(struct thread *thread, u64 timestamp,
69 struct namespaces_event *event);
70
65int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp, 71int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp,
66 bool exec); 72 bool exec);
67static inline int thread__set_comm(struct thread *thread, const char *comm, 73static inline int thread__set_comm(struct thread *thread, const char *comm,
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 7c3fcc538a70..63ead7b06324 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -1,4 +1,5 @@
1#include <dirent.h> 1#include <dirent.h>
2#include <errno.h>
2#include <limits.h> 3#include <limits.h>
3#include <stdbool.h> 4#include <stdbool.h>
4#include <stdlib.h> 5#include <stdlib.h>
@@ -6,6 +7,7 @@
6#include <sys/types.h> 7#include <sys/types.h>
7#include <sys/stat.h> 8#include <sys/stat.h>
8#include <unistd.h> 9#include <unistd.h>
10#include "string2.h"
9#include "strlist.h" 11#include "strlist.h"
10#include <string.h> 12#include <string.h>
11#include <api/fs/fs.h> 13#include <api/fs/fs.h>
@@ -66,7 +68,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
66 for (i = 0; i < items; i++) 68 for (i = 0; i < items; i++)
67 thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); 69 thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
68 threads->nr = items; 70 threads->nr = items;
69 atomic_set(&threads->refcnt, 1); 71 refcount_set(&threads->refcnt, 1);
70 } 72 }
71 73
72 for (i=0; i<items; i++) 74 for (i=0; i<items; i++)
@@ -83,7 +85,7 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
83 if (threads != NULL) { 85 if (threads != NULL) {
84 thread_map__set_pid(threads, 0, tid); 86 thread_map__set_pid(threads, 0, tid);
85 threads->nr = 1; 87 threads->nr = 1;
86 atomic_set(&threads->refcnt, 1); 88 refcount_set(&threads->refcnt, 1);
87 } 89 }
88 90
89 return threads; 91 return threads;
@@ -105,7 +107,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
105 goto out_free_threads; 107 goto out_free_threads;
106 108
107 threads->nr = 0; 109 threads->nr = 0;
108 atomic_set(&threads->refcnt, 1); 110 refcount_set(&threads->refcnt, 1);
109 111
110 while ((dirent = readdir(proc)) != NULL) { 112 while ((dirent = readdir(proc)) != NULL) {
111 char *end; 113 char *end;
@@ -235,7 +237,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
235out: 237out:
236 strlist__delete(slist); 238 strlist__delete(slist);
237 if (threads) 239 if (threads)
238 atomic_set(&threads->refcnt, 1); 240 refcount_set(&threads->refcnt, 1);
239 return threads; 241 return threads;
240 242
241out_free_namelist: 243out_free_namelist:
@@ -255,7 +257,7 @@ struct thread_map *thread_map__new_dummy(void)
255 if (threads != NULL) { 257 if (threads != NULL) {
256 thread_map__set_pid(threads, 0, -1); 258 thread_map__set_pid(threads, 0, -1);
257 threads->nr = 1; 259 threads->nr = 1;
258 atomic_set(&threads->refcnt, 1); 260 refcount_set(&threads->refcnt, 1);
259 } 261 }
260 return threads; 262 return threads;
261} 263}
@@ -300,7 +302,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
300 } 302 }
301out: 303out:
302 if (threads) 304 if (threads)
303 atomic_set(&threads->refcnt, 1); 305 refcount_set(&threads->refcnt, 1);
304 return threads; 306 return threads;
305 307
306out_free_threads: 308out_free_threads:
@@ -326,7 +328,7 @@ static void thread_map__delete(struct thread_map *threads)
326 if (threads) { 328 if (threads) {
327 int i; 329 int i;
328 330
329 WARN_ONCE(atomic_read(&threads->refcnt) != 0, 331 WARN_ONCE(refcount_read(&threads->refcnt) != 0,
330 "thread map refcnt unbalanced\n"); 332 "thread map refcnt unbalanced\n");
331 for (i = 0; i < threads->nr; i++) 333 for (i = 0; i < threads->nr; i++)
332 free(thread_map__comm(threads, i)); 334 free(thread_map__comm(threads, i));
@@ -337,13 +339,13 @@ static void thread_map__delete(struct thread_map *threads)
337struct thread_map *thread_map__get(struct thread_map *map) 339struct thread_map *thread_map__get(struct thread_map *map)
338{ 340{
339 if (map) 341 if (map)
340 atomic_inc(&map->refcnt); 342 refcount_inc(&map->refcnt);
341 return map; 343 return map;
342} 344}
343 345
344void thread_map__put(struct thread_map *map) 346void thread_map__put(struct thread_map *map)
345{ 347{
346 if (map && atomic_dec_and_test(&map->refcnt)) 348 if (map && refcount_dec_and_test(&map->refcnt))
347 thread_map__delete(map); 349 thread_map__delete(map);
348} 350}
349 351
@@ -423,7 +425,7 @@ static void thread_map__copy_event(struct thread_map *threads,
423 threads->map[i].comm = strndup(event->entries[i].comm, 16); 425 threads->map[i].comm = strndup(event->entries[i].comm, 16);
424 } 426 }
425 427
426 atomic_set(&threads->refcnt, 1); 428 refcount_set(&threads->refcnt, 1);
427} 429}
428 430
429struct thread_map *thread_map__new_event(struct thread_map_event *event) 431struct thread_map *thread_map__new_event(struct thread_map_event *event)
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index ea0ef08c6303..bd34d7a0b9fa 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -3,7 +3,7 @@
3 3
4#include <sys/types.h> 4#include <sys/types.h>
5#include <stdio.h> 5#include <stdio.h>
6#include <linux/atomic.h> 6#include <linux/refcount.h>
7 7
8struct thread_map_data { 8struct thread_map_data {
9 pid_t pid; 9 pid_t pid;
@@ -11,7 +11,7 @@ struct thread_map_data {
11}; 11};
12 12
13struct thread_map { 13struct thread_map {
14 atomic_t refcnt; 14 refcount_t refcnt;
15 int nr; 15 int nr;
16 struct thread_map_data map[]; 16 struct thread_map_data map[];
17}; 17};
diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c
index d1b21c72206d..5b5d0214debd 100644
--- a/tools/perf/util/time-utils.c
+++ b/tools/perf/util/time-utils.c
@@ -117,3 +117,28 @@ bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp)
117 117
118 return false; 118 return false;
119} 119}
120
121int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
122{
123 u64 sec = timestamp / NSEC_PER_SEC;
124 u64 usec = (timestamp % NSEC_PER_SEC) / NSEC_PER_USEC;
125
126 return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
127}
128
129int fetch_current_timestamp(char *buf, size_t sz)
130{
131 struct timeval tv;
132 struct tm tm;
133 char dt[32];
134
135 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
136 return -1;
137
138 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
139 return -1;
140
141 scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
142
143 return 0;
144}
diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h
index c1f197c4af6c..8656be08513b 100644
--- a/tools/perf/util/time-utils.h
+++ b/tools/perf/util/time-utils.h
@@ -1,6 +1,9 @@
1#ifndef _TIME_UTILS_H_ 1#ifndef _TIME_UTILS_H_
2#define _TIME_UTILS_H_ 2#define _TIME_UTILS_H_
3 3
4#include <stddef.h>
5#include <linux/types.h>
6
4struct perf_time_interval { 7struct perf_time_interval {
5 u64 start, end; 8 u64 start, end;
6}; 9};
@@ -11,4 +14,8 @@ int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr);
11 14
12bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp); 15bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp);
13 16
17int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
18
19int fetch_current_timestamp(char *buf, size_t sz);
20
14#endif 21#endif
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index ac2590a3de2d..829471a1c6d7 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -40,6 +40,7 @@ struct perf_tool {
40 event_op mmap, 40 event_op mmap,
41 mmap2, 41 mmap2,
42 comm, 42 comm,
43 namespaces,
43 fork, 44 fork,
44 exit, 45 exit,
45 lost, 46 lost,
@@ -66,6 +67,7 @@ struct perf_tool {
66 event_op3 auxtrace; 67 event_op3 auxtrace;
67 bool ordered_events; 68 bool ordered_events;
68 bool ordering_requires_timestamps; 69 bool ordering_requires_timestamps;
70 bool namespace_events;
69}; 71};
70 72
71#endif /* __PERF_TOOL_H */ 73#endif /* __PERF_TOOL_H */
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index b2940c88734a..9bdfb78a9a35 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -5,7 +5,7 @@
5#include <linux/types.h> 5#include <linux/types.h>
6#include <stddef.h> 6#include <stddef.h>
7#include <stdbool.h> 7#include <stdbool.h>
8#include <termios.h> 8#include <sys/ioctl.h>
9 9
10struct perf_evlist; 10struct perf_evlist;
11struct perf_evsel; 11struct perf_evsel;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index de0078e21408..746bbee645d9 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -21,13 +21,14 @@
21#include <stdio.h> 21#include <stdio.h>
22#include <stdlib.h> 22#include <stdlib.h>
23#include <string.h> 23#include <string.h>
24#include <ctype.h>
25#include <errno.h> 24#include <errno.h>
26 25
27#include "../perf.h" 26#include "../perf.h"
28#include "util.h" 27#include "util.h"
29#include "trace-event.h" 28#include "trace-event.h"
30 29
30#include "sane_ctype.h"
31
31static int get_common_field(struct scripting_context *context, 32static int get_common_field(struct scripting_context *context,
32 int *offset, int *size, const char *type) 33 int *offset, int *size, const char *type)
33{ 34{
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 27420159bf69..8a9a677f7576 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -192,7 +192,7 @@ static int read_ftrace_printk(struct pevent *pevent)
192 if (!size) 192 if (!size)
193 return 0; 193 return 0;
194 194
195 buf = malloc(size); 195 buf = malloc(size + 1);
196 if (buf == NULL) 196 if (buf == NULL)
197 return -1; 197 return -1;
198 198
@@ -201,6 +201,8 @@ static int read_ftrace_printk(struct pevent *pevent)
201 return -1; 201 return -1;
202 } 202 }
203 203
204 buf[size] = '\0';
205
204 parse_ftrace_printk(pevent, buf, size); 206 parse_ftrace_printk(pevent, buf, size);
205 207
206 free(buf); 208 free(buf);
diff --git a/tools/perf/util/units.c b/tools/perf/util/units.c
new file mode 100644
index 000000000000..4767ec2c5ef6
--- /dev/null
+++ b/tools/perf/util/units.c
@@ -0,0 +1,68 @@
1#include "units.h"
2#include <inttypes.h>
3#include <limits.h>
4#include <stdlib.h>
5#include <string.h>
6#include <linux/kernel.h>
7#include <linux/time64.h>
8
9unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
10{
11 struct parse_tag *i = tags;
12
13 while (i->tag) {
14 char *s = strchr(str, i->tag);
15
16 if (s) {
17 unsigned long int value;
18 char *endptr;
19
20 value = strtoul(str, &endptr, 10);
21 if (s != endptr)
22 break;
23
24 if (value > ULONG_MAX / i->mult)
25 break;
26 value *= i->mult;
27 return value;
28 }
29 i++;
30 }
31
32 return (unsigned long) -1;
33}
34
35unsigned long convert_unit(unsigned long value, char *unit)
36{
37 *unit = ' ';
38
39 if (value > 1000) {
40 value /= 1000;
41 *unit = 'K';
42 }
43
44 if (value > 1000) {
45 value /= 1000;
46 *unit = 'M';
47 }
48
49 if (value > 1000) {
50 value /= 1000;
51 *unit = 'G';
52 }
53
54 return value;
55}
56
57int unit_number__scnprintf(char *buf, size_t size, u64 n)
58{
59 char unit[4] = "BKMG";
60 int i = 0;
61
62 while (((n / 1024) > 1) && (i < 3)) {
63 n /= 1024;
64 i++;
65 }
66
67 return scnprintf(buf, size, "%" PRIu64 "%c", n, unit[i]);
68}
diff --git a/tools/perf/util/units.h b/tools/perf/util/units.h
new file mode 100644
index 000000000000..f02c87317150
--- /dev/null
+++ b/tools/perf/util/units.h
@@ -0,0 +1,17 @@
1#ifndef PERF_UNIT_H
2#define PERF_UNIT_H
3
4#include <stddef.h>
5#include <linux/types.h>
6
7struct parse_tag {
8 char tag;
9 int mult;
10};
11
12unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
13
14unsigned long convert_unit(unsigned long value, char *unit);
15int unit_number__scnprintf(char *buf, size_t size, u64 n);
16
17#endif /* PERF_UNIT_H */
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 783a53fb7a4e..f90e11a555b2 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -12,6 +12,7 @@
12#include "event.h" 12#include "event.h"
13#include "perf_regs.h" 13#include "perf_regs.h"
14#include "callchain.h" 14#include "callchain.h"
15#include "util.h"
15 16
16static char *debuginfo_path; 17static char *debuginfo_path;
17 18
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
index 58328669ed16..4a2b269a7b3b 100644
--- a/tools/perf/util/unwind-libdw.h
+++ b/tools/perf/util/unwind-libdw.h
@@ -2,10 +2,12 @@
2#define __PERF_UNWIND_LIBDW_H 2#define __PERF_UNWIND_LIBDW_H
3 3
4#include <elfutils/libdwfl.h> 4#include <elfutils/libdwfl.h>
5#include "event.h"
6#include "thread.h"
7#include "unwind.h" 5#include "unwind.h"
8 6
7struct machine;
8struct perf_sample;
9struct thread;
10
9bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg); 11bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg);
10 12
11struct unwind_info { 13struct unwind_info {
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index bfb9b7987692..f8455bed6e65 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -16,8 +16,10 @@
16 */ 16 */
17 17
18#include <elf.h> 18#include <elf.h>
19#include <errno.h>
19#include <gelf.h> 20#include <gelf.h>
20#include <fcntl.h> 21#include <fcntl.h>
22#include <inttypes.h>
21#include <string.h> 23#include <string.h>
22#include <unistd.h> 24#include <unistd.h>
23#include <sys/mman.h> 25#include <sys/mman.h>
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 61fb1e90ff51..bfbdcc6198c9 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -1,10 +1,13 @@
1#ifndef __UNWIND_H 1#ifndef __UNWIND_H
2#define __UNWIND_H 2#define __UNWIND_H
3 3
4#include <linux/compiler.h>
4#include <linux/types.h> 5#include <linux/types.h>
5#include "event.h" 6
6#include "symbol.h" 7struct map;
7#include "thread.h" 8struct perf_sample;
9struct symbol;
10struct thread;
8 11
9struct unwind_entry { 12struct unwind_entry {
10 struct map *map; 13 struct map *map;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index d8b45cea54d0..28c9f335006c 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -3,38 +3,22 @@
3#include "debug.h" 3#include "debug.h"
4#include <api/fs/fs.h> 4#include <api/fs/fs.h>
5#include <sys/mman.h> 5#include <sys/mman.h>
6#include <sys/stat.h>
6#include <sys/utsname.h> 7#include <sys/utsname.h>
7#ifdef HAVE_BACKTRACE_SUPPORT 8#include <dirent.h>
8#include <execinfo.h> 9#include <inttypes.h>
9#endif 10#include <signal.h>
10#include <stdio.h> 11#include <stdio.h>
11#include <stdlib.h> 12#include <stdlib.h>
12#include <string.h> 13#include <string.h>
13#include <errno.h> 14#include <errno.h>
14#include <limits.h> 15#include <limits.h>
15#include <byteswap.h>
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/log2.h> 17#include <linux/log2.h>
18#include <linux/time64.h> 18#include <linux/time64.h>
19#include <unistd.h> 19#include <unistd.h>
20#include "callchain.h"
21#include "strlist.h" 20#include "strlist.h"
22 21
23#define CALLCHAIN_PARAM_DEFAULT \
24 .mode = CHAIN_GRAPH_ABS, \
25 .min_percent = 0.5, \
26 .order = ORDER_CALLEE, \
27 .key = CCKEY_FUNCTION, \
28 .value = CCVAL_PERCENT, \
29
30struct callchain_param callchain_param = {
31 CALLCHAIN_PARAM_DEFAULT
32};
33
34struct callchain_param callchain_param_default = {
35 CALLCHAIN_PARAM_DEFAULT
36};
37
38/* 22/*
39 * XXX We need to find a better place for these things... 23 * XXX We need to find a better place for these things...
40 */ 24 */
@@ -269,28 +253,6 @@ int copyfile(const char *from, const char *to)
269 return copyfile_mode(from, to, 0755); 253 return copyfile_mode(from, to, 0755);
270} 254}
271 255
272unsigned long convert_unit(unsigned long value, char *unit)
273{
274 *unit = ' ';
275
276 if (value > 1000) {
277 value /= 1000;
278 *unit = 'K';
279 }
280
281 if (value > 1000) {
282 value /= 1000;
283 *unit = 'M';
284 }
285
286 if (value > 1000) {
287 value /= 1000;
288 *unit = 'G';
289 }
290
291 return value;
292}
293
294static ssize_t ion(bool is_read, int fd, void *buf, size_t n) 256static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
295{ 257{
296 void *buf_start = buf; 258 void *buf_start = buf;
@@ -372,171 +334,6 @@ int hex2u64(const char *ptr, u64 *long_val)
372 return p - ptr; 334 return p - ptr;
373} 335}
374 336
375/* Obtain a backtrace and print it to stdout. */
376#ifdef HAVE_BACKTRACE_SUPPORT
377void dump_stack(void)
378{
379 void *array[16];
380 size_t size = backtrace(array, ARRAY_SIZE(array));
381 char **strings = backtrace_symbols(array, size);
382 size_t i;
383
384 printf("Obtained %zd stack frames.\n", size);
385
386 for (i = 0; i < size; i++)
387 printf("%s\n", strings[i]);
388
389 free(strings);
390}
391#else
392void dump_stack(void) {}
393#endif
394
395void sighandler_dump_stack(int sig)
396{
397 psignal(sig, "perf");
398 dump_stack();
399 signal(sig, SIG_DFL);
400 raise(sig);
401}
402
403int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
404{
405 u64 sec = timestamp / NSEC_PER_SEC;
406 u64 usec = (timestamp % NSEC_PER_SEC) / NSEC_PER_USEC;
407
408 return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
409}
410
411unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
412{
413 struct parse_tag *i = tags;
414
415 while (i->tag) {
416 char *s;
417
418 s = strchr(str, i->tag);
419 if (s) {
420 unsigned long int value;
421 char *endptr;
422
423 value = strtoul(str, &endptr, 10);
424 if (s != endptr)
425 break;
426
427 if (value > ULONG_MAX / i->mult)
428 break;
429 value *= i->mult;
430 return value;
431 }
432 i++;
433 }
434
435 return (unsigned long) -1;
436}
437
438int get_stack_size(const char *str, unsigned long *_size)
439{
440 char *endptr;
441 unsigned long size;
442 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
443
444 size = strtoul(str, &endptr, 0);
445
446 do {
447 if (*endptr)
448 break;
449
450 size = round_up(size, sizeof(u64));
451 if (!size || size > max_size)
452 break;
453
454 *_size = size;
455 return 0;
456
457 } while (0);
458
459 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
460 max_size, str);
461 return -1;
462}
463
464int parse_callchain_record(const char *arg, struct callchain_param *param)
465{
466 char *tok, *name, *saveptr = NULL;
467 char *buf;
468 int ret = -1;
469
470 /* We need buffer that we know we can write to. */
471 buf = malloc(strlen(arg) + 1);
472 if (!buf)
473 return -ENOMEM;
474
475 strcpy(buf, arg);
476
477 tok = strtok_r((char *)buf, ",", &saveptr);
478 name = tok ? : (char *)buf;
479
480 do {
481 /* Framepointer style */
482 if (!strncmp(name, "fp", sizeof("fp"))) {
483 if (!strtok_r(NULL, ",", &saveptr)) {
484 param->record_mode = CALLCHAIN_FP;
485 ret = 0;
486 } else
487 pr_err("callchain: No more arguments "
488 "needed for --call-graph fp\n");
489 break;
490
491 /* Dwarf style */
492 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
493 const unsigned long default_stack_dump_size = 8192;
494
495 ret = 0;
496 param->record_mode = CALLCHAIN_DWARF;
497 param->dump_size = default_stack_dump_size;
498
499 tok = strtok_r(NULL, ",", &saveptr);
500 if (tok) {
501 unsigned long size = 0;
502
503 ret = get_stack_size(tok, &size);
504 param->dump_size = size;
505 }
506 } else if (!strncmp(name, "lbr", sizeof("lbr"))) {
507 if (!strtok_r(NULL, ",", &saveptr)) {
508 param->record_mode = CALLCHAIN_LBR;
509 ret = 0;
510 } else
511 pr_err("callchain: No more arguments "
512 "needed for --call-graph lbr\n");
513 break;
514 } else {
515 pr_err("callchain: Unknown --call-graph option "
516 "value: %s\n", arg);
517 break;
518 }
519
520 } while (0);
521
522 free(buf);
523 return ret;
524}
525
526const char *get_filename_for_perf_kvm(void)
527{
528 const char *filename;
529
530 if (perf_host && !perf_guest)
531 filename = strdup("perf.data.host");
532 else if (!perf_host && perf_guest)
533 filename = strdup("perf.data.guest");
534 else
535 filename = strdup("perf.data.kvm");
536
537 return filename;
538}
539
540int perf_event_paranoid(void) 337int perf_event_paranoid(void)
541{ 338{
542 int value; 339 int value;
@@ -547,27 +344,6 @@ int perf_event_paranoid(void)
547 return value; 344 return value;
548} 345}
549 346
550void mem_bswap_32(void *src, int byte_size)
551{
552 u32 *m = src;
553 while (byte_size > 0) {
554 *m = bswap_32(*m);
555 byte_size -= sizeof(u32);
556 ++m;
557 }
558}
559
560void mem_bswap_64(void *src, int byte_size)
561{
562 u64 *m = src;
563
564 while (byte_size > 0) {
565 *m = bswap_64(*m);
566 byte_size -= sizeof(u64);
567 ++m;
568 }
569}
570
571bool find_process(const char *name) 347bool find_process(const char *name)
572{ 348{
573 size_t len = strlen(name); 349 size_t len = strlen(name);
@@ -696,7 +472,8 @@ const char *perf_tip(const char *dirpath)
696 472
697 tips = strlist__new("tips.txt", &conf); 473 tips = strlist__new("tips.txt", &conf);
698 if (tips == NULL) 474 if (tips == NULL)
699 return errno == ENOENT ? NULL : "Tip: get more memory! ;-p"; 475 return errno == ENOENT ? NULL :
476 "Tip: check path of tips.txt or get more memory! ;-p";
700 477
701 if (strlist__nr_entries(tips) == 0) 478 if (strlist__nr_entries(tips) == 0)
702 goto out; 479 goto out;
@@ -710,95 +487,3 @@ out:
710 487
711 return tip; 488 return tip;
712} 489}
713
714bool is_regular_file(const char *file)
715{
716 struct stat st;
717
718 if (stat(file, &st))
719 return false;
720
721 return S_ISREG(st.st_mode);
722}
723
724int fetch_current_timestamp(char *buf, size_t sz)
725{
726 struct timeval tv;
727 struct tm tm;
728 char dt[32];
729
730 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
731 return -1;
732
733 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
734 return -1;
735
736 scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
737
738 return 0;
739}
740
741void print_binary(unsigned char *data, size_t len,
742 size_t bytes_per_line, print_binary_t printer,
743 void *extra)
744{
745 size_t i, j, mask;
746
747 if (!printer)
748 return;
749
750 bytes_per_line = roundup_pow_of_two(bytes_per_line);
751 mask = bytes_per_line - 1;
752
753 printer(BINARY_PRINT_DATA_BEGIN, 0, extra);
754 for (i = 0; i < len; i++) {
755 if ((i & mask) == 0) {
756 printer(BINARY_PRINT_LINE_BEGIN, -1, extra);
757 printer(BINARY_PRINT_ADDR, i, extra);
758 }
759
760 printer(BINARY_PRINT_NUM_DATA, data[i], extra);
761
762 if (((i & mask) == mask) || i == len - 1) {
763 for (j = 0; j < mask-(i & mask); j++)
764 printer(BINARY_PRINT_NUM_PAD, -1, extra);
765
766 printer(BINARY_PRINT_SEP, i, extra);
767 for (j = i & ~mask; j <= i; j++)
768 printer(BINARY_PRINT_CHAR_DATA, data[j], extra);
769 for (j = 0; j < mask-(i & mask); j++)
770 printer(BINARY_PRINT_CHAR_PAD, i, extra);
771 printer(BINARY_PRINT_LINE_END, -1, extra);
772 }
773 }
774 printer(BINARY_PRINT_DATA_END, -1, extra);
775}
776
777int is_printable_array(char *p, unsigned int len)
778{
779 unsigned int i;
780
781 if (!p || !len || p[len - 1] != 0)
782 return 0;
783
784 len--;
785
786 for (i = 0; i < len; i++) {
787 if (!isprint(p[i]) && !isspace(p[i]))
788 return 0;
789 }
790 return 1;
791}
792
793int unit_number__scnprintf(char *buf, size_t size, u64 n)
794{
795 char unit[4] = "BKMG";
796 int i = 0;
797
798 while (((n / 1024) > 1) && (i < 3)) {
799 n /= 1024;
800 i++;
801 }
802
803 return scnprintf(buf, size, "%" PRIu64 "%c", n, unit[i]);
804}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c74708da8571..5dfb9bb6482d 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -1,125 +1,17 @@
1#ifndef GIT_COMPAT_UTIL_H 1#ifndef GIT_COMPAT_UTIL_H
2#define GIT_COMPAT_UTIL_H 2#define GIT_COMPAT_UTIL_H
3 3
4#ifndef FLEX_ARRAY
5/*
6 * See if our compiler is known to support flexible array members.
7 */
8#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
9# define FLEX_ARRAY /* empty */
10#elif defined(__GNUC__)
11# if (__GNUC__ >= 3)
12# define FLEX_ARRAY /* empty */
13# else
14# define FLEX_ARRAY 0 /* older GNU extension */
15# endif
16#endif
17
18/*
19 * Otherwise, default to safer but a bit wasteful traditional style
20 */
21#ifndef FLEX_ARRAY
22# define FLEX_ARRAY 1
23#endif
24#endif
25
26#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
27
28#ifdef __GNUC__
29#define TYPEOF(x) (__typeof__(x))
30#else
31#define TYPEOF(x)
32#endif
33
34#define MSB(x, bits) ((x) & TYPEOF(x)(~0ULL << (sizeof(x) * 8 - (bits))))
35#define HAS_MULTI_BITS(i) ((i) & ((i) - 1)) /* checks if an integer has more than 1 bit set */
36
37/* Approximation of the length of the decimal representation of this type. */
38#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
39
40#define _ALL_SOURCE 1 4#define _ALL_SOURCE 1
41#define _BSD_SOURCE 1 5#define _BSD_SOURCE 1
42/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ 6/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
43#define _DEFAULT_SOURCE 1 7#define _DEFAULT_SOURCE 1
44#define HAS_BOOL
45 8
46#include <unistd.h>
47#include <stdio.h>
48#include <sys/stat.h>
49#include <sys/statfs.h>
50#include <fcntl.h> 9#include <fcntl.h>
51#include <stdbool.h> 10#include <stdbool.h>
52#include <stddef.h> 11#include <stddef.h>
53#include <stdlib.h> 12#include <stdlib.h>
54#include <stdarg.h> 13#include <stdarg.h>
55#include <string.h>
56#include <term.h>
57#include <errno.h>
58#include <limits.h>
59#include <sys/param.h>
60#include <sys/types.h>
61#include <dirent.h>
62#include <sys/time.h>
63#include <time.h>
64#include <signal.h>
65#include <fnmatch.h>
66#include <assert.h>
67#include <regex.h>
68#include <utime.h>
69#include <sys/wait.h>
70#include <poll.h>
71#include <sys/socket.h>
72#include <sys/ioctl.h>
73#include <inttypes.h>
74#include <linux/kernel.h>
75#include <linux/types.h> 14#include <linux/types.h>
76#include <sys/ttydefaults.h>
77#include <api/fs/tracing_path.h>
78#include <termios.h>
79#include <linux/bitops.h>
80#include <termios.h>
81#include "strlist.h"
82
83extern const char *graph_line;
84extern const char *graph_dotted_line;
85extern const char *spaces;
86extern const char *dots;
87extern char buildid_dir[];
88
89/* On most systems <limits.h> would have given us this, but
90 * not on some systems (e.g. GNU/Hurd).
91 */
92#ifndef PATH_MAX
93#define PATH_MAX 4096
94#endif
95
96#ifndef PRIuMAX
97#define PRIuMAX "llu"
98#endif
99
100#ifndef PRIu32
101#define PRIu32 "u"
102#endif
103
104#ifndef PRIx32
105#define PRIx32 "x"
106#endif
107
108#ifndef PATH_SEP
109#define PATH_SEP ':'
110#endif
111
112#ifndef STRIP_EXTENSION
113#define STRIP_EXTENSION ""
114#endif
115
116#ifndef has_dos_drive_prefix
117#define has_dos_drive_prefix(path) 0
118#endif
119
120#ifndef is_dir_sep
121#define is_dir_sep(c) ((c) == '/')
122#endif
123 15
124#ifdef __GNUC__ 16#ifdef __GNUC__
125#define NORETURN __attribute__((__noreturn__)) 17#define NORETURN __attribute__((__noreturn__))
@@ -130,8 +22,6 @@ extern char buildid_dir[];
130#endif 22#endif
131#endif 23#endif
132 24
133#define PERF_GTK_DSO "libperf-gtk.so"
134
135/* General helper functions */ 25/* General helper functions */
136void usage(const char *err) NORETURN; 26void usage(const char *err) NORETURN;
137void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); 27void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
@@ -140,25 +30,6 @@ void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
140 30
141void set_warning_routine(void (*routine)(const char *err, va_list params)); 31void set_warning_routine(void (*routine)(const char *err, va_list params));
142 32
143int prefixcmp(const char *str, const char *prefix);
144void set_buildid_dir(const char *dir);
145
146#ifdef __GLIBC_PREREQ
147#if __GLIBC_PREREQ(2, 1)
148#define HAVE_STRCHRNUL
149#endif
150#endif
151
152#ifndef HAVE_STRCHRNUL
153#define strchrnul gitstrchrnul
154static inline char *gitstrchrnul(const char *s, int c)
155{
156 while (*s && *s != c)
157 s++;
158 return (char *)s;
159}
160#endif
161
162static inline void *zalloc(size_t size) 33static inline void *zalloc(size_t size)
163{ 34{
164 return calloc(1, size); 35 return calloc(1, size);
@@ -166,47 +37,8 @@ static inline void *zalloc(size_t size)
166 37
167#define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) 38#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
168 39
169/* Sane ctype - no locale, and works with signed chars */ 40struct dirent;
170#undef isascii 41struct strlist;
171#undef isspace
172#undef isdigit
173#undef isxdigit
174#undef isalpha
175#undef isprint
176#undef isalnum
177#undef islower
178#undef isupper
179#undef tolower
180#undef toupper
181
182extern unsigned char sane_ctype[256];
183#define GIT_SPACE 0x01
184#define GIT_DIGIT 0x02
185#define GIT_ALPHA 0x04
186#define GIT_GLOB_SPECIAL 0x08
187#define GIT_REGEX_SPECIAL 0x10
188#define GIT_PRINT_EXTRA 0x20
189#define GIT_PRINT 0x3E
190#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
191#define isascii(x) (((x) & ~0x7f) == 0)
192#define isspace(x) sane_istest(x,GIT_SPACE)
193#define isdigit(x) sane_istest(x,GIT_DIGIT)
194#define isxdigit(x) \
195 (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
196#define isalpha(x) sane_istest(x,GIT_ALPHA)
197#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
198#define isprint(x) sane_istest(x,GIT_PRINT)
199#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20))
200#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20))
201#define tolower(x) sane_case((unsigned char)(x), 0x20)
202#define toupper(x) sane_case((unsigned char)(x), 0)
203
204static inline int sane_case(int x, int high)
205{
206 if (sane_istest(x, GIT_ALPHA))
207 x = (x & ~0x20) | high;
208 return x;
209}
210 42
211int mkdir_p(char *path, mode_t mode); 43int mkdir_p(char *path, mode_t mode);
212int rm_rf(const char *path); 44int rm_rf(const char *path);
@@ -216,112 +48,17 @@ int copyfile(const char *from, const char *to);
216int copyfile_mode(const char *from, const char *to, mode_t mode); 48int copyfile_mode(const char *from, const char *to, mode_t mode);
217int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); 49int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size);
218 50
219s64 perf_atoll(const char *str);
220char **argv_split(const char *str, int *argcp);
221void argv_free(char **argv);
222bool strglobmatch(const char *str, const char *pat);
223bool strglobmatch_nocase(const char *str, const char *pat);
224bool strlazymatch(const char *str, const char *pat);
225static inline bool strisglob(const char *str)
226{
227 return strpbrk(str, "*?[") != NULL;
228}
229int strtailcmp(const char *s1, const char *s2);
230char *strxfrchar(char *s, char from, char to);
231unsigned long convert_unit(unsigned long value, char *unit);
232ssize_t readn(int fd, void *buf, size_t n); 51ssize_t readn(int fd, void *buf, size_t n);
233ssize_t writen(int fd, void *buf, size_t n); 52ssize_t writen(int fd, void *buf, size_t n);
234 53
235struct perf_event_attr;
236
237void event_attr_init(struct perf_event_attr *attr);
238
239#define _STR(x) #x
240#define STR(x) _STR(x)
241
242size_t hex_width(u64 v); 54size_t hex_width(u64 v);
243int hex2u64(const char *ptr, u64 *val); 55int hex2u64(const char *ptr, u64 *val);
244 56
245char *ltrim(char *s);
246char *rtrim(char *s);
247
248static inline char *trim(char *s)
249{
250 return ltrim(rtrim(s));
251}
252
253void dump_stack(void);
254void sighandler_dump_stack(int sig);
255
256extern unsigned int page_size; 57extern unsigned int page_size;
257extern int cacheline_size; 58extern int cacheline_size;
258extern int sysctl_perf_event_max_stack;
259extern int sysctl_perf_event_max_contexts_per_stack;
260
261struct parse_tag {
262 char tag;
263 int mult;
264};
265
266unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
267
268#define SRCLINE_UNKNOWN ((char *) "??:0")
269
270static inline int path__join(char *bf, size_t size,
271 const char *path1, const char *path2)
272{
273 return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
274}
275
276static inline int path__join3(char *bf, size_t size,
277 const char *path1, const char *path2,
278 const char *path3)
279{
280 return scnprintf(bf, size, "%s%s%s%s%s",
281 path1, path1[0] ? "/" : "",
282 path2, path2[0] ? "/" : "", path3);
283}
284
285struct dso;
286struct symbol;
287 59
288extern bool srcline_full_filename;
289char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
290 bool show_sym);
291char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
292 bool show_sym, bool unwind_inlines);
293void free_srcline(char *srcline);
294
295int perf_event_paranoid(void);
296
297void mem_bswap_64(void *src, int byte_size);
298void mem_bswap_32(void *src, int byte_size);
299
300const char *get_filename_for_perf_kvm(void);
301bool find_process(const char *name); 60bool find_process(const char *name);
302 61
303#ifdef HAVE_ZLIB_SUPPORT
304int gzip_decompress_to_file(const char *input, int output_fd);
305#endif
306
307#ifdef HAVE_LZMA_SUPPORT
308int lzma_decompress_to_file(const char *input, int output_fd);
309#endif
310
311char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints);
312
313static inline char *asprintf_expr_in_ints(const char *var, size_t nints, int *ints)
314{
315 return asprintf_expr_inout_ints(var, true, nints, ints);
316}
317
318static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int *ints)
319{
320 return asprintf_expr_inout_ints(var, false, nints, ints);
321}
322
323int get_stack_size(const char *str, unsigned long *_size);
324
325int fetch_kernel_version(unsigned int *puint, 62int fetch_kernel_version(unsigned int *puint,
326 char *str, size_t str_sz); 63 char *str, size_t str_sz);
327#define KVER_VERSION(x) (((x) >> 16) & 0xff) 64#define KVER_VERSION(x) (((x) >> 16) & 0xff)
@@ -331,37 +68,9 @@ int fetch_kernel_version(unsigned int *puint,
331#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) 68#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
332 69
333const char *perf_tip(const char *dirpath); 70const char *perf_tip(const char *dirpath);
334bool is_regular_file(const char *file);
335int fetch_current_timestamp(char *buf, size_t sz);
336 71
337enum binary_printer_ops { 72#ifndef HAVE_SCHED_GETCPU_SUPPORT
338 BINARY_PRINT_DATA_BEGIN, 73int sched_getcpu(void);
339 BINARY_PRINT_LINE_BEGIN,
340 BINARY_PRINT_ADDR,
341 BINARY_PRINT_NUM_DATA,
342 BINARY_PRINT_NUM_PAD,
343 BINARY_PRINT_SEP,
344 BINARY_PRINT_CHAR_DATA,
345 BINARY_PRINT_CHAR_PAD,
346 BINARY_PRINT_LINE_END,
347 BINARY_PRINT_DATA_END,
348};
349
350typedef void (*print_binary_t)(enum binary_printer_ops,
351 unsigned int val,
352 void *extra);
353
354void print_binary(unsigned char *data, size_t len,
355 size_t bytes_per_line, print_binary_t printer,
356 void *extra);
357
358#if !defined(__GLIBC__) && !defined(__ANDROID__)
359extern int sched_getcpu(void);
360#endif 74#endif
361 75
362int is_printable_array(char *p, unsigned int len);
363
364int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
365
366int unit_number__scnprintf(char *buf, size_t size, u64 n);
367#endif /* GIT_COMPAT_UTIL_H */ 76#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 5074be4ed467..5de2e15e2eda 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -1,4 +1,7 @@
1#include <inttypes.h>
2#include <stdio.h>
1#include <stdlib.h> 3#include <stdlib.h>
4#include <errno.h>
2 5
3#include "util.h" 6#include "util.h"
4#include "values.h" 7#include "values.h"
@@ -108,24 +111,45 @@ static int perf_read_values__findnew_thread(struct perf_read_values *values,
108 return i; 111 return i;
109} 112}
110 113
111static void perf_read_values__enlarge_counters(struct perf_read_values *values) 114static int perf_read_values__enlarge_counters(struct perf_read_values *values)
112{ 115{
113 int i; 116 char **countername;
117 int i, counters_max = values->counters_max * 2;
118 u64 *counterrawid = realloc(values->counterrawid, counters_max * sizeof(*values->counterrawid));
119
120 if (!counterrawid) {
121 pr_debug("failed to enlarge read_values rawid array");
122 goto out_enomem;
123 }
114 124
115 values->counters_max *= 2; 125 countername = realloc(values->countername, counters_max * sizeof(*values->countername));
116 values->counterrawid = realloc(values->counterrawid, 126 if (!countername) {
117 values->counters_max * sizeof(*values->counterrawid)); 127 pr_debug("failed to enlarge read_values rawid array");
118 values->countername = realloc(values->countername, 128 goto out_free_rawid;
119 values->counters_max * sizeof(*values->countername)); 129 }
120 if (!values->counterrawid || !values->countername)
121 die("failed to enlarge read_values counters arrays");
122 130
123 for (i = 0; i < values->threads; i++) { 131 for (i = 0; i < values->threads; i++) {
124 values->value[i] = realloc(values->value[i], 132 u64 *value = realloc(values->value[i], counters_max * sizeof(**values->value));
125 values->counters_max * sizeof(**values->value)); 133
126 if (!values->value[i]) 134 if (value) {
127 die("failed to enlarge read_values counters arrays"); 135 pr_debug("failed to enlarge read_values ->values array");
136 goto out_free_name;
137 }
138
139 values->value[i] = value;
128 } 140 }
141
142 values->counters_max = counters_max;
143 values->counterrawid = counterrawid;
144 values->countername = countername;
145
146 return 0;
147out_free_name:
148 free(countername);
149out_free_rawid:
150 free(counterrawid);
151out_enomem:
152 return -ENOMEM;
129} 153}
130 154
131static int perf_read_values__findnew_counter(struct perf_read_values *values, 155static int perf_read_values__findnew_counter(struct perf_read_values *values,
@@ -137,8 +161,11 @@ static int perf_read_values__findnew_counter(struct perf_read_values *values,
137 if (values->counterrawid[i] == rawid) 161 if (values->counterrawid[i] == rawid)
138 return i; 162 return i;
139 163
140 if (values->counters == values->counters_max) 164 if (values->counters == values->counters_max) {
141 perf_read_values__enlarge_counters(values); 165 i = perf_read_values__enlarge_counters(values);
166 if (i)
167 return i;
168 }
142 169
143 i = values->counters++; 170 i = values->counters++;
144 values->counterrawid[i] = rawid; 171 values->counterrawid[i] = rawid;
@@ -172,8 +199,10 @@ static void perf_read_values__display_pretty(FILE *fp,
172 int *counterwidth; 199 int *counterwidth;
173 200
174 counterwidth = malloc(values->counters * sizeof(*counterwidth)); 201 counterwidth = malloc(values->counters * sizeof(*counterwidth));
175 if (!counterwidth) 202 if (!counterwidth) {
176 die("failed to allocate counterwidth array"); 203 fprintf(fp, "INTERNAL ERROR: Failed to allocate counterwidth array\n");
204 return;
205 }
177 tidwidth = 3; 206 tidwidth = 3;
178 pidwidth = 3; 207 pidwidth = 3;
179 for (j = 0; j < values->counters; j++) 208 for (j = 0; j < values->counters; j++)
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index 7bdcad484225..d3c39eec89a8 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -1,4 +1,4 @@
1 1#include <errno.h>
2#include <unistd.h> 2#include <unistd.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
diff --git a/tools/perf/util/xyarray.c b/tools/perf/util/xyarray.c
index c10ba41ef3f6..7251fdbabced 100644
--- a/tools/perf/util/xyarray.c
+++ b/tools/perf/util/xyarray.c
@@ -1,5 +1,7 @@
1#include "xyarray.h" 1#include "xyarray.h"
2#include "util.h" 2#include "util.h"
3#include <stdlib.h>
4#include <string.h>
3 5
4struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size) 6struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
5{ 7{
diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c
index 495a449fc25c..1329d843eb7b 100644
--- a/tools/perf/util/zlib.c
+++ b/tools/perf/util/zlib.c
@@ -4,6 +4,7 @@
4#include <sys/mman.h> 4#include <sys/mman.h>
5#include <zlib.h> 5#include <zlib.h>
6 6
7#include "util/compress.h"
7#include "util/util.h" 8#include "util/util.h"
8#include "util/debug.h" 9#include "util/debug.h"
9 10
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
index 93b0aa74ca03..39c2c7d067bb 100644
--- a/tools/power/cpupower/utils/helpers/cpuid.c
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -156,6 +156,7 @@ out:
156 */ 156 */
157 case 0x2C: /* Westmere EP - Gulftown */ 157 case 0x2C: /* Westmere EP - Gulftown */
158 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; 158 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
159 break;
159 case 0x2A: /* SNB */ 160 case 0x2A: /* SNB */
160 case 0x2D: /* SNB Xeon */ 161 case 0x2D: /* SNB Xeon */
161 case 0x3A: /* IVB */ 162 case 0x3A: /* IVB */
diff --git a/tools/power/pm-graph/Makefile b/tools/power/pm-graph/Makefile
new file mode 100644
index 000000000000..4d0ccc89e6c6
--- /dev/null
+++ b/tools/power/pm-graph/Makefile
@@ -0,0 +1,28 @@
1PREFIX ?= /usr
2DESTDIR ?=
3
4all:
5 @echo "Nothing to build"
6
7install :
8 install -d $(DESTDIR)$(PREFIX)/lib/pm-graph
9 install analyze_suspend.py $(DESTDIR)$(PREFIX)/lib/pm-graph
10 install analyze_boot.py $(DESTDIR)$(PREFIX)/lib/pm-graph
11
12 ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py $(DESTDIR)$(PREFIX)/bin/bootgraph
13 ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
14
15 install -d $(DESTDIR)$(PREFIX)/share/man/man8
16 install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
17 install sleepgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
18
19uninstall :
20 rm $(DESTDIR)$(PREFIX)/share/man/man8/bootgraph.8
21 rm $(DESTDIR)$(PREFIX)/share/man/man8/sleepgraph.8
22
23 rm $(DESTDIR)$(PREFIX)/bin/bootgraph
24 rm $(DESTDIR)$(PREFIX)/bin/sleepgraph
25
26 rm $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_boot.py
27 rm $(DESTDIR)$(PREFIX)/lib/pm-graph/analyze_suspend.py
28 rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph
diff --git a/tools/power/pm-graph/analyze_boot.py b/tools/power/pm-graph/analyze_boot.py
new file mode 100755
index 000000000000..3e1dcbbf1adc
--- /dev/null
+++ b/tools/power/pm-graph/analyze_boot.py
@@ -0,0 +1,824 @@
1#!/usr/bin/python
2#
3# Tool for analyzing boot timing
4# Copyright (c) 2013, Intel Corporation.
5#
6# This program is free software; you can redistribute it and/or modify it
7# under the terms and conditions of the GNU General Public License,
8# version 2, as published by the Free Software Foundation.
9#
10# This program is distributed in the hope it will be useful, but WITHOUT
11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13# more details.
14#
15# Authors:
16# Todd Brandt <todd.e.brandt@linux.intel.com>
17#
18# Description:
19# This tool is designed to assist kernel and OS developers in optimizing
20# their linux stack's boot time. It creates an html representation of
21# the kernel boot timeline up to the start of the init process.
22#
23
24# ----------------- LIBRARIES --------------------
25
26import sys
27import time
28import os
29import string
30import re
31import platform
32import shutil
33from datetime import datetime, timedelta
34from subprocess import call, Popen, PIPE
35import analyze_suspend as aslib
36
37# ----------------- CLASSES --------------------
38
39# Class: SystemValues
40# Description:
41# A global, single-instance container used to
42# store system values and test parameters
43class SystemValues(aslib.SystemValues):
44 title = 'BootGraph'
45 version = 2.0
46 hostname = 'localhost'
47 testtime = ''
48 kernel = ''
49 dmesgfile = ''
50 ftracefile = ''
51 htmlfile = 'bootgraph.html'
52 outfile = ''
53 phoronix = False
54 addlogs = False
55 useftrace = False
56 usedevsrc = True
57 suspendmode = 'boot'
58 max_graph_depth = 2
59 graph_filter = 'do_one_initcall'
60 reboot = False
61 manual = False
62 iscronjob = False
63 timeformat = '%.6f'
64 def __init__(self):
65 if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ):
66 self.phoronix = True
67 self.addlogs = True
68 self.outfile = os.environ['LOG_FILE']
69 self.htmlfile = os.environ['LOG_FILE']
70 self.hostname = platform.node()
71 self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
72 if os.path.exists('/proc/version'):
73 fp = open('/proc/version', 'r')
74 val = fp.read().strip()
75 fp.close()
76 self.kernel = self.kernelVersion(val)
77 else:
78 self.kernel = 'unknown'
79 def kernelVersion(self, msg):
80 return msg.split()[2]
81 def kernelParams(self):
82 cmdline = 'initcall_debug log_buf_len=32M'
83 if self.useftrace:
84 cmdline += ' trace_buf_size=128M trace_clock=global '\
85 'trace_options=nooverwrite,funcgraph-abstime,funcgraph-cpu,'\
86 'funcgraph-duration,funcgraph-proc,funcgraph-tail,'\
87 'nofuncgraph-overhead,context-info,graph-time '\
88 'ftrace=function_graph '\
89 'ftrace_graph_max_depth=%d '\
90 'ftrace_graph_filter=%s' % \
91 (self.max_graph_depth, self.graph_filter)
92 return cmdline
93 def setGraphFilter(self, val):
94 fp = open(self.tpath+'available_filter_functions')
95 master = fp.read().split('\n')
96 fp.close()
97 for i in val.split(','):
98 func = i.strip()
99 if func not in master:
100 doError('function "%s" not available for ftrace' % func)
101 self.graph_filter = val
102 def cronjobCmdString(self):
103 cmdline = '%s -cronjob' % os.path.abspath(sys.argv[0])
104 args = iter(sys.argv[1:])
105 for arg in args:
106 if arg in ['-h', '-v', '-cronjob', '-reboot']:
107 continue
108 elif arg in ['-o', '-dmesg', '-ftrace', '-filter']:
109 args.next()
110 continue
111 cmdline += ' '+arg
112 if self.graph_filter != 'do_one_initcall':
113 cmdline += ' -filter "%s"' % self.graph_filter
114 cmdline += ' -o "%s"' % os.path.abspath(self.htmlfile)
115 return cmdline
116 def manualRebootRequired(self):
117 cmdline = self.kernelParams()
118 print 'To generate a new timeline manually, follow these steps:\n'
119 print '1. Add the CMDLINE string to your kernel command line.'
120 print '2. Reboot the system.'
121 print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n'
122 print 'CMDLINE="%s"' % cmdline
123 sys.exit()
124
125sysvals = SystemValues()
126
127# Class: Data
128# Description:
129# The primary container for test data.
130class Data(aslib.Data):
131 dmesg = {} # root data structure
132 start = 0.0 # test start
133 end = 0.0 # test end
134 dmesgtext = [] # dmesg text file in memory
135 testnumber = 0
136 idstr = ''
137 html_device_id = 0
138 valid = False
139 initstart = 0.0
140 boottime = ''
141 phases = ['boot']
142 do_one_initcall = False
143 def __init__(self, num):
144 self.testnumber = num
145 self.idstr = 'a'
146 self.dmesgtext = []
147 self.dmesg = {
148 'boot': {'list': dict(), 'start': -1.0, 'end': -1.0, 'row': 0, 'color': '#dddddd'}
149 }
150 def deviceTopology(self):
151 return ''
152 def newAction(self, phase, name, start, end, ret, ulen):
153 # new device callback for a specific phase
154 self.html_device_id += 1
155 devid = '%s%d' % (self.idstr, self.html_device_id)
156 list = self.dmesg[phase]['list']
157 length = -1.0
158 if(start >= 0 and end >= 0):
159 length = end - start
160 i = 2
161 origname = name
162 while(name in list):
163 name = '%s[%d]' % (origname, i)
164 i += 1
165 list[name] = {'name': name, 'start': start, 'end': end,
166 'pid': 0, 'length': length, 'row': 0, 'id': devid,
167 'ret': ret, 'ulen': ulen }
168 return name
169 def deviceMatch(self, cg):
170 if cg.end - cg.start == 0:
171 return True
172 list = self.dmesg['boot']['list']
173 for devname in list:
174 dev = list[devname]
175 if cg.name == 'do_one_initcall':
176 if(cg.start <= dev['start'] and cg.end >= dev['end'] and dev['length'] > 0):
177 dev['ftrace'] = cg
178 self.do_one_initcall = True
179 return True
180 else:
181 if(cg.start > dev['start'] and cg.end < dev['end']):
182 if 'ftraces' not in dev:
183 dev['ftraces'] = []
184 dev['ftraces'].append(cg)
185 return True
186 return False
187
188# ----------------- FUNCTIONS --------------------
189
190# Function: loadKernelLog
191# Description:
192# Load a raw kernel log from dmesg
193def loadKernelLog():
194 data = Data(0)
195 data.dmesg['boot']['start'] = data.start = ktime = 0.0
196 sysvals.stamp = {
197 'time': datetime.now().strftime('%B %d %Y, %I:%M:%S %p'),
198 'host': sysvals.hostname,
199 'mode': 'boot', 'kernel': ''}
200
201 devtemp = dict()
202 if(sysvals.dmesgfile):
203 lf = open(sysvals.dmesgfile, 'r')
204 else:
205 lf = Popen('dmesg', stdout=PIPE).stdout
206 for line in lf:
207 line = line.replace('\r\n', '')
208 idx = line.find('[')
209 if idx > 1:
210 line = line[idx:]
211 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
212 if(not m):
213 continue
214 ktime = float(m.group('ktime'))
215 if(ktime > 120):
216 break
217 msg = m.group('msg')
218 data.end = data.initstart = ktime
219 data.dmesgtext.append(line)
220 if(ktime == 0.0 and re.match('^Linux version .*', msg)):
221 if(not sysvals.stamp['kernel']):
222 sysvals.stamp['kernel'] = sysvals.kernelVersion(msg)
223 continue
224 m = re.match('.* setting system clock to (?P<t>.*) UTC.*', msg)
225 if(m):
226 bt = datetime.strptime(m.group('t'), '%Y-%m-%d %H:%M:%S')
227 bt = bt - timedelta(seconds=int(ktime))
228 data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S')
229 sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p')
230 continue
231 m = re.match('^calling *(?P<f>.*)\+.*', msg)
232 if(m):
233 devtemp[m.group('f')] = ktime
234 continue
235 m = re.match('^initcall *(?P<f>.*)\+.* returned (?P<r>.*) after (?P<t>.*) usecs', msg)
236 if(m):
237 data.valid = True
238 f, r, t = m.group('f', 'r', 't')
239 if(f in devtemp):
240 data.newAction('boot', f, devtemp[f], ktime, int(r), int(t))
241 data.end = ktime
242 del devtemp[f]
243 continue
244 if(re.match('^Freeing unused kernel memory.*', msg)):
245 break
246
247 data.dmesg['boot']['end'] = data.end
248 lf.close()
249 return data
250
251# Function: loadTraceLog
252# Description:
253# Check if trace is available and copy to a temp file
254def loadTraceLog(data):
255 # load the data to a temp file if none given
256 if not sysvals.ftracefile:
257 lib = aslib.sysvals
258 aslib.rootCheck(True)
259 if not lib.verifyFtrace():
260 doError('ftrace not available')
261 if lib.fgetVal('current_tracer').strip() != 'function_graph':
262 doError('ftrace not configured for a boot callgraph')
263 sysvals.ftracefile = '/tmp/boot_ftrace.%s.txt' % os.getpid()
264 call('cat '+lib.tpath+'trace > '+sysvals.ftracefile, shell=True)
265 if not sysvals.ftracefile:
266 doError('No trace data available')
267
268 # parse the trace log
269 ftemp = dict()
270 tp = aslib.TestProps()
271 tp.setTracerType('function_graph')
272 tf = open(sysvals.ftracefile, 'r')
273 for line in tf:
274 if line[0] == '#':
275 continue
276 m = re.match(tp.ftrace_line_fmt, line.strip())
277 if(not m):
278 continue
279 m_time, m_proc, m_pid, m_msg, m_dur = \
280 m.group('time', 'proc', 'pid', 'msg', 'dur')
281 if float(m_time) > data.end:
282 break
283 if(m_time and m_pid and m_msg):
284 t = aslib.FTraceLine(m_time, m_msg, m_dur)
285 pid = int(m_pid)
286 else:
287 continue
288 if t.fevent or t.fkprobe:
289 continue
290 key = (m_proc, pid)
291 if(key not in ftemp):
292 ftemp[key] = []
293 ftemp[key].append(aslib.FTraceCallGraph(pid))
294 cg = ftemp[key][-1]
295 if(cg.addLine(t)):
296 ftemp[key].append(aslib.FTraceCallGraph(pid))
297 tf.close()
298
299 # add the callgraph data to the device hierarchy
300 for key in ftemp:
301 proc, pid = key
302 for cg in ftemp[key]:
303 if len(cg.list) < 1 or cg.invalid:
304 continue
305 if(not cg.postProcess()):
306 print('Sanity check failed for %s-%d' % (proc, pid))
307 continue
308 # match cg data to devices
309 if not data.deviceMatch(cg):
310 print ' BAD: %s %s-%d [%f - %f]' % (cg.name, proc, pid, cg.start, cg.end)
311
312# Function: colorForName
313# Description:
314# Generate a repeatable color from a list for a given name
315def colorForName(name):
316 list = [
317 ('c1', '#ec9999'),
318 ('c2', '#ffc1a6'),
319 ('c3', '#fff0a6'),
320 ('c4', '#adf199'),
321 ('c5', '#9fadea'),
322 ('c6', '#a699c1'),
323 ('c7', '#ad99b4'),
324 ('c8', '#eaffea'),
325 ('c9', '#dcecfb'),
326 ('c10', '#ffffea')
327 ]
328 i = 0
329 total = 0
330 count = len(list)
331 while i < len(name):
332 total += ord(name[i])
333 i += 1
334 return list[total % count]
335
336def cgOverview(cg, minlen):
337 stats = dict()
338 large = []
339 for l in cg.list:
340 if l.fcall and l.depth == 1:
341 if l.length >= minlen:
342 large.append(l)
343 if l.name not in stats:
344 stats[l.name] = [0, 0.0]
345 stats[l.name][0] += (l.length * 1000.0)
346 stats[l.name][1] += 1
347 return (large, stats)
348
349# Function: createBootGraph
350# Description:
351# Create the output html file from the resident test data
352# Arguments:
353# testruns: array of Data objects from parseKernelLog or parseTraceLog
354# Output:
355# True if the html file was created, false if it failed
356def createBootGraph(data, embedded):
357 # html function templates
358 html_srccall = '<div id={6} title="{5}" class="srccall" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{0}</div>\n'
359 html_timetotal = '<table class="time1">\n<tr>'\
360 '<td class="blue">Time from Kernel Boot to start of User Mode: <b>{0} ms</b></td>'\
361 '</tr>\n</table>\n'
362
363 # device timeline
364 devtl = aslib.Timeline(100, 20)
365
366 # write the test title and general info header
367 devtl.createHeader(sysvals, 'noftrace')
368
369 # Generate the header for this timeline
370 t0 = data.start
371 tMax = data.end
372 tTotal = tMax - t0
373 if(tTotal == 0):
374 print('ERROR: No timeline data')
375 return False
376 boot_time = '%.0f'%(tTotal*1000)
377 devtl.html += html_timetotal.format(boot_time)
378
379 # determine the maximum number of rows we need to draw
380 phase = 'boot'
381 list = data.dmesg[phase]['list']
382 devlist = []
383 for devname in list:
384 d = aslib.DevItem(0, phase, list[devname])
385 devlist.append(d)
386 devtl.getPhaseRows(devlist)
387 devtl.calcTotalRows()
388
389 # draw the timeline background
390 devtl.createZoomBox()
391 boot = data.dmesg[phase]
392 length = boot['end']-boot['start']
393 left = '%.3f' % (((boot['start']-t0)*100.0)/tTotal)
394 width = '%.3f' % ((length*100.0)/tTotal)
395 devtl.html += devtl.html_tblock.format(phase, left, width, devtl.scaleH)
396 devtl.html += devtl.html_phase.format('0', '100', \
397 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \
398 'white', '')
399
400 # draw the device timeline
401 num = 0
402 devstats = dict()
403 for devname in sorted(list):
404 cls, color = colorForName(devname)
405 dev = list[devname]
406 info = '@|%.3f|%.3f|%.3f|%d' % (dev['start']*1000.0, dev['end']*1000.0,
407 dev['ulen']/1000.0, dev['ret'])
408 devstats[dev['id']] = {'info':info}
409 dev['color'] = color
410 height = devtl.phaseRowHeight(0, phase, dev['row'])
411 top = '%.6f' % ((dev['row']*height) + devtl.scaleH)
412 left = '%.6f' % (((dev['start']-t0)*100)/tTotal)
413 width = '%.6f' % (((dev['end']-dev['start'])*100)/tTotal)
414 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)
415 devtl.html += devtl.html_device.format(dev['id'],
416 devname+length+'kernel_mode', left, top, '%.3f'%height,
417 width, devname, ' '+cls, '')
418 rowtop = devtl.phaseRowTop(0, phase, dev['row'])
419 height = '%.6f' % (devtl.rowH / 2)
420 top = '%.6f' % (rowtop + devtl.scaleH + (devtl.rowH / 2))
421 if data.do_one_initcall:
422 if('ftrace' not in dev):
423 continue
424 cg = dev['ftrace']
425 large, stats = cgOverview(cg, 0.001)
426 devstats[dev['id']]['fstat'] = stats
427 for l in large:
428 left = '%f' % (((l.time-t0)*100)/tTotal)
429 width = '%f' % (l.length*100/tTotal)
430 title = '%s (%0.3fms)' % (l.name, l.length * 1000.0)
431 devtl.html += html_srccall.format(l.name, left,
432 top, height, width, title, 'x%d'%num)
433 num += 1
434 continue
435 if('ftraces' not in dev):
436 continue
437 for cg in dev['ftraces']:
438 left = '%f' % (((cg.start-t0)*100)/tTotal)
439 width = '%f' % ((cg.end-cg.start)*100/tTotal)
440 cglen = (cg.end - cg.start) * 1000.0
441 title = '%s (%0.3fms)' % (cg.name, cglen)
442 cg.id = 'x%d' % num
443 devtl.html += html_srccall.format(cg.name, left,
444 top, height, width, title, dev['id']+cg.id)
445 num += 1
446
447 # draw the time scale, try to make the number of labels readable
448 devtl.createTimeScale(t0, tMax, tTotal, phase)
449 devtl.html += '</div>\n'
450
451 # timeline is finished
452 devtl.html += '</div>\n</div>\n'
453
454 if(sysvals.outfile == sysvals.htmlfile):
455 hf = open(sysvals.htmlfile, 'a')
456 else:
457 hf = open(sysvals.htmlfile, 'w')
458
459 # add the css if this is not an embedded run
460 extra = '\
461 .c1 {background:rgba(209,0,0,0.4);}\n\
462 .c2 {background:rgba(255,102,34,0.4);}\n\
463 .c3 {background:rgba(255,218,33,0.4);}\n\
464 .c4 {background:rgba(51,221,0,0.4);}\n\
465 .c5 {background:rgba(17,51,204,0.4);}\n\
466 .c6 {background:rgba(34,0,102,0.4);}\n\
467 .c7 {background:rgba(51,0,68,0.4);}\n\
468 .c8 {background:rgba(204,255,204,0.4);}\n\
469 .c9 {background:rgba(169,208,245,0.4);}\n\
470 .c10 {background:rgba(255,255,204,0.4);}\n\
471 .vt {transform:rotate(-60deg);transform-origin:0 0;}\n\
472 table.fstat {table-layout:fixed;padding:150px 15px 0 0;font-size:10px;column-width:30px;}\n\
473 .fstat th {width:55px;}\n\
474 .fstat td {text-align:left;width:35px;}\n\
475 .srccall {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\
476 .srccall:hover {color:white;font-weight:bold;border:1px solid white;}\n'
477 if(not embedded):
478 aslib.addCSS(hf, sysvals, 1, False, extra)
479
480 # write the device timeline
481 hf.write(devtl.html)
482
483 # add boot specific html
484 statinfo = 'var devstats = {\n'
485 for n in sorted(devstats):
486 statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info'])
487 if 'fstat' in devstats[n]:
488 funcs = devstats[n]['fstat']
489 for f in sorted(funcs, key=funcs.get, reverse=True):
490 if funcs[f][0] < 0.01 and len(funcs) > 10:
491 break
492 statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1])
493 statinfo += '\t],\n'
494 statinfo += '};\n'
495 html = \
496 '<div id="devicedetailtitle"></div>\n'\
497 '<div id="devicedetail" style="display:none;">\n'\
498 '<div id="devicedetail0">\n'\
499 '<div id="kernel_mode" class="phaselet" style="left:0%;width:100%;background:#DDDDDD"></div>\n'\
500 '</div>\n</div>\n'\
501 '<script type="text/javascript">\n'+statinfo+\
502 '</script>\n'
503 hf.write(html)
504
505 # add the callgraph html
506 if(sysvals.usecallgraph):
507 aslib.addCallgraphs(sysvals, hf, data)
508
509 # add the dmesg log as a hidden div
510 if sysvals.addlogs:
511 hf.write('<div id="dmesglog" style="display:none;">\n')
512 for line in data.dmesgtext:
513 line = line.replace('<', '&lt').replace('>', '&gt')
514 hf.write(line)
515 hf.write('</div>\n')
516
517 if(not embedded):
518 # write the footer and close
519 aslib.addScriptCode(hf, [data])
520 hf.write('</body>\n</html>\n')
521 else:
522 # embedded out will be loaded in a page, skip the js
523 hf.write('<div id=bounds style=display:none>%f,%f</div>' % \
524 (data.start*1000, data.initstart*1000))
525 hf.close()
526 return True
527
528# Function: updateCron
529# Description:
530# (restore=False) Set the tool to run automatically on reboot
531# (restore=True) Restore the original crontab
532def updateCron(restore=False):
533 if not restore:
534 sysvals.rootUser(True)
535 crondir = '/var/spool/cron/crontabs/'
536 cronfile = crondir+'root'
537 backfile = crondir+'root-analyze_boot-backup'
538 if not os.path.exists(crondir):
539 doError('%s not found' % crondir)
540 out = Popen(['which', 'crontab'], stdout=PIPE).stdout.read()
541 if not out:
542 doError('crontab not found')
543 # on restore: move the backup cron back into place
544 if restore:
545 if os.path.exists(backfile):
546 shutil.move(backfile, cronfile)
547 return
548 # backup current cron and install new one with reboot
549 if os.path.exists(cronfile):
550 shutil.move(cronfile, backfile)
551 else:
552 fp = open(backfile, 'w')
553 fp.close()
554 res = -1
555 try:
556 fp = open(backfile, 'r')
557 op = open(cronfile, 'w')
558 for line in fp:
559 if '@reboot' not in line:
560 op.write(line)
561 continue
562 fp.close()
563 op.write('@reboot python %s\n' % sysvals.cronjobCmdString())
564 op.close()
565 res = call('crontab %s' % cronfile, shell=True)
566 except Exception, e:
567 print 'Exception: %s' % str(e)
568 shutil.move(backfile, cronfile)
569 res = -1
570 if res != 0:
571 doError('crontab failed')
572
573# Function: updateGrub
574# Description:
575# update grub.cfg for all kernels with our parameters
576def updateGrub(restore=False):
577 # call update-grub on restore
578 if restore:
579 try:
580 call(['update-grub'], stderr=PIPE, stdout=PIPE,
581 env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'})
582 except Exception, e:
583 print 'Exception: %s\n' % str(e)
584 return
585 # verify we can do this
586 sysvals.rootUser(True)
587 grubfile = '/etc/default/grub'
588 if not os.path.exists(grubfile):
589 print 'ERROR: Unable to set the kernel parameters via grub.\n'
590 sysvals.manualRebootRequired()
591 out = Popen(['which', 'update-grub'], stdout=PIPE).stdout.read()
592 if not out:
593 print 'ERROR: Unable to set the kernel parameters via grub.\n'
594 sysvals.manualRebootRequired()
595
596 # extract the option and create a grub config without it
597 tgtopt = 'GRUB_CMDLINE_LINUX_DEFAULT'
598 cmdline = ''
599 tempfile = '/etc/default/grub.analyze_boot'
600 shutil.move(grubfile, tempfile)
601 res = -1
602 try:
603 fp = open(tempfile, 'r')
604 op = open(grubfile, 'w')
605 cont = False
606 for line in fp:
607 line = line.strip()
608 if len(line) == 0 or line[0] == '#':
609 continue
610 opt = line.split('=')[0].strip()
611 if opt == tgtopt:
612 cmdline = line.split('=', 1)[1].strip('\\')
613 if line[-1] == '\\':
614 cont = True
615 elif cont:
616 cmdline += line.strip('\\')
617 if line[-1] != '\\':
618 cont = False
619 else:
620 op.write('%s\n' % line)
621 fp.close()
622 # if the target option value is in quotes, strip them
623 sp = '"'
624 val = cmdline.strip()
625 if val[0] == '\'' or val[0] == '"':
626 sp = val[0]
627 val = val.strip(sp)
628 cmdline = val
629 # append our cmd line options
630 if len(cmdline) > 0:
631 cmdline += ' '
632 cmdline += sysvals.kernelParams()
633 # write out the updated target option
634 op.write('\n%s=%s%s%s\n' % (tgtopt, sp, cmdline, sp))
635 op.close()
636 res = call('update-grub')
637 os.remove(grubfile)
638 except Exception, e:
639 print 'Exception: %s' % str(e)
640 res = -1
641 # cleanup
642 shutil.move(tempfile, grubfile)
643 if res != 0:
644 doError('update-grub failed')
645
646# Function: doError
647# Description:
648# generic error function for catastrphic failures
649# Arguments:
650# msg: the error message to print
651# help: True if printHelp should be called after, False otherwise
652def doError(msg, help=False):
653 if help == True:
654 printHelp()
655 print 'ERROR: %s\n' % msg
656 sys.exit()
657
658# Function: printHelp
659# Description:
660# print out the help text
661def printHelp():
662 print('')
663 print('%s v%.1f' % (sysvals.title, sysvals.version))
664 print('Usage: bootgraph <options> <command>')
665 print('')
666 print('Description:')
667 print(' This tool reads in a dmesg log of linux kernel boot and')
668 print(' creates an html representation of the boot timeline up to')
669 print(' the start of the init process.')
670 print('')
671 print(' If no specific command is given the tool reads the current dmesg')
672 print(' and/or ftrace log and outputs bootgraph.html')
673 print('')
674 print('Options:')
675 print(' -h Print this help text')
676 print(' -v Print the current tool version')
677 print(' -addlogs Add the dmesg log to the html output')
678 print(' -o file Html timeline name (default: bootgraph.html)')
679 print(' [advanced]')
680 print(' -f Use ftrace to add function detail (default: disabled)')
681 print(' -callgraph Add callgraph detail, can be very large (default: disabled)')
682 print(' -maxdepth N limit the callgraph data to N call levels (default: 2)')
683 print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
684 print(' -timeprec N Number of significant digits in timestamps (0:S, 3:ms, [6:us])')
685 print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')
686 print(' -filter list Limit ftrace to comma-delimited list of functions (default: do_one_initcall)')
687 print(' [commands]')
688 print(' -reboot Reboot the machine automatically and generate a new timeline')
689 print(' -manual Show the requirements to generate a new timeline manually')
690 print(' -dmesg file Load a stored dmesg file (used with -ftrace)')
691 print(' -ftrace file Load a stored ftrace file (used with -dmesg)')
692 print(' -flistall Print all functions capable of being captured in ftrace')
693 print('')
694 return True
695
696# ----------------- MAIN --------------------
697# exec start (skipped if script is loaded as library)
698if __name__ == '__main__':
699 # loop through the command line arguments
700 cmd = ''
701 simplecmds = ['-updategrub', '-flistall']
702 args = iter(sys.argv[1:])
703 for arg in args:
704 if(arg == '-h'):
705 printHelp()
706 sys.exit()
707 elif(arg == '-v'):
708 print("Version %.1f" % sysvals.version)
709 sys.exit()
710 elif(arg in simplecmds):
711 cmd = arg[1:]
712 elif(arg == '-f'):
713 sysvals.useftrace = True
714 elif(arg == '-callgraph'):
715 sysvals.useftrace = True
716 sysvals.usecallgraph = True
717 elif(arg == '-mincg'):
718 sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0)
719 elif(arg == '-timeprec'):
720 sysvals.setPrecision(aslib.getArgInt('-timeprec', args, 0, 6))
721 elif(arg == '-maxdepth'):
722 sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000)
723 elif(arg == '-filter'):
724 try:
725 val = args.next()
726 except:
727 doError('No filter functions supplied', True)
728 aslib.rootCheck(True)
729 sysvals.setGraphFilter(val)
730 elif(arg == '-ftrace'):
731 try:
732 val = args.next()
733 except:
734 doError('No ftrace file supplied', True)
735 if(os.path.exists(val) == False):
736 doError('%s does not exist' % val)
737 sysvals.ftracefile = val
738 elif(arg == '-addlogs'):
739 sysvals.addlogs = True
740 elif(arg == '-expandcg'):
741 sysvals.cgexp = True
742 elif(arg == '-dmesg'):
743 try:
744 val = args.next()
745 except:
746 doError('No dmesg file supplied', True)
747 if(os.path.exists(val) == False):
748 doError('%s does not exist' % val)
749 if(sysvals.htmlfile == val or sysvals.outfile == val):
750 doError('Output filename collision')
751 sysvals.dmesgfile = val
752 elif(arg == '-o'):
753 try:
754 val = args.next()
755 except:
756 doError('No HTML filename supplied', True)
757 if(sysvals.dmesgfile == val or sysvals.ftracefile == val):
758 doError('Output filename collision')
759 sysvals.htmlfile = val
760 elif(arg == '-reboot'):
761 if sysvals.iscronjob:
762 doError('-reboot and -cronjob are incompatible')
763 sysvals.reboot = True
764 elif(arg == '-manual'):
765 sysvals.reboot = True
766 sysvals.manual = True
767 # remaining options are only for cron job use
768 elif(arg == '-cronjob'):
769 sysvals.iscronjob = True
770 if sysvals.reboot:
771 doError('-reboot and -cronjob are incompatible')
772 else:
773 doError('Invalid argument: '+arg, True)
774
775 if cmd != '':
776 if cmd == 'updategrub':
777 updateGrub()
778 elif cmd == 'flistall':
779 sysvals.getFtraceFilterFunctions(False)
780 sys.exit()
781
782 # update grub, setup a cronjob, and reboot
783 if sysvals.reboot:
784 if not sysvals.manual:
785 updateGrub()
786 updateCron()
787 call('reboot')
788 else:
789 sysvals.manualRebootRequired()
790 sys.exit()
791
792 # disable the cronjob
793 if sysvals.iscronjob:
794 updateCron(True)
795 updateGrub(True)
796
797 data = loadKernelLog()
798 if sysvals.useftrace:
799 loadTraceLog(data)
800 if sysvals.iscronjob:
801 try:
802 sysvals.fsetVal('0', 'tracing_on')
803 except:
804 pass
805
806 if(sysvals.outfile and sysvals.phoronix):
807 fp = open(sysvals.outfile, 'w')
808 fp.write('pass %s initstart %.3f end %.3f boot %s\n' %
809 (data.valid, data.initstart*1000, data.end*1000, data.boottime))
810 fp.close()
811 if(not data.valid):
812 if sysvals.dmesgfile:
813 doError('No initcall data found in %s' % sysvals.dmesgfile)
814 else:
815 doError('No initcall data found, is initcall_debug enabled?')
816
817 print(' Host: %s' % sysvals.hostname)
818 print(' Test time: %s' % sysvals.testtime)
819 print(' Boot time: %s' % data.boottime)
820 print('Kernel Version: %s' % sysvals.kernel)
821 print(' Kernel start: %.3f' % (data.start * 1000))
822 print(' init start: %.3f' % (data.initstart * 1000))
823
824 createBootGraph(data, sysvals.phoronix)
diff --git a/tools/power/pm-graph/analyze_suspend.py b/tools/power/pm-graph/analyze_suspend.py
new file mode 100755
index 000000000000..a9206e67fc1f
--- /dev/null
+++ b/tools/power/pm-graph/analyze_suspend.py
@@ -0,0 +1,5309 @@
1#!/usr/bin/python
2#
3# Tool for analyzing suspend/resume timing
4# Copyright (c) 2013, Intel Corporation.
5#
6# This program is free software; you can redistribute it and/or modify it
7# under the terms and conditions of the GNU General Public License,
8# version 2, as published by the Free Software Foundation.
9#
10# This program is distributed in the hope it will be useful, but WITHOUT
11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13# more details.
14#
15# Authors:
16# Todd Brandt <todd.e.brandt@linux.intel.com>
17#
18# Links:
19# Home Page
20# https://01.org/suspendresume
21# Source repo
22# https://github.com/01org/pm-graph
23#
24# Description:
25# This tool is designed to assist kernel and OS developers in optimizing
26# their linux stack's suspend/resume time. Using a kernel image built
27# with a few extra options enabled, the tool will execute a suspend and
28# will capture dmesg and ftrace data until resume is complete. This data
29# is transformed into a device timeline and a callgraph to give a quick
30# and detailed view of which devices and callbacks are taking the most
31# time in suspend/resume. The output is a single html file which can be
32# viewed in firefox or chrome.
33#
34# The following kernel build options are required:
35# CONFIG_PM_DEBUG=y
36# CONFIG_PM_SLEEP_DEBUG=y
37# CONFIG_FTRACE=y
38# CONFIG_FUNCTION_TRACER=y
39# CONFIG_FUNCTION_GRAPH_TRACER=y
40# CONFIG_KPROBES=y
41# CONFIG_KPROBES_ON_FTRACE=y
42#
43# For kernel versions older than 3.15:
44# The following additional kernel parameters are required:
45# (e.g. in file /etc/default/grub)
46# GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..."
47#
48
49# ----------------- LIBRARIES --------------------
50
51import sys
52import time
53import os
54import string
55import re
56import platform
57from datetime import datetime
58import struct
59import ConfigParser
60from threading import Thread
61from subprocess import call, Popen, PIPE
62
63# ----------------- CLASSES --------------------
64
65# Class: SystemValues
66# Description:
67# A global, single-instance container used to
68# store system values and test parameters
69class SystemValues:
70 title = 'SleepGraph'
71 version = '4.6'
72 ansi = False
73 verbose = False
74 addlogs = False
75 mindevlen = 0.0
76 mincglen = 0.0
77 cgphase = ''
78 cgtest = -1
79 max_graph_depth = 0
80 callloopmaxgap = 0.0001
81 callloopmaxlen = 0.005
82 srgap = 0
83 cgexp = False
84 outdir = ''
85 testdir = '.'
86 tpath = '/sys/kernel/debug/tracing/'
87 fpdtpath = '/sys/firmware/acpi/tables/FPDT'
88 epath = '/sys/kernel/debug/tracing/events/power/'
89 traceevents = [
90 'suspend_resume',
91 'device_pm_callback_end',
92 'device_pm_callback_start'
93 ]
94 logmsg = ''
95 testcommand = ''
96 mempath = '/dev/mem'
97 powerfile = '/sys/power/state'
98 suspendmode = 'mem'
99 hostname = 'localhost'
100 prefix = 'test'
101 teststamp = ''
102 dmesgstart = 0.0
103 dmesgfile = ''
104 ftracefile = ''
105 htmlfile = ''
106 embedded = False
107 rtcwake = True
108 rtcwaketime = 15
109 rtcpath = ''
110 devicefilter = []
111 stamp = 0
112 execcount = 1
113 x2delay = 0
114 usecallgraph = False
115 usetraceevents = False
116 usetraceeventsonly = False
117 usetracemarkers = True
118 usekprobes = True
119 usedevsrc = False
120 useprocmon = False
121 notestrun = False
122 mixedphaseheight = True
123 devprops = dict()
124 predelay = 0
125 postdelay = 0
126 procexecfmt = 'ps - (?P<ps>.*)$'
127 devpropfmt = '# Device Properties: .*'
128 tracertypefmt = '# tracer: (?P<t>.*)'
129 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
130 stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\
131 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\
132 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'
133 tracefuncs = {
134 'sys_sync': dict(),
135 'pm_prepare_console': dict(),
136 'pm_notifier_call_chain': dict(),
137 'freeze_processes': dict(),
138 'freeze_kernel_threads': dict(),
139 'pm_restrict_gfp_mask': dict(),
140 'acpi_suspend_begin': dict(),
141 'suspend_console': dict(),
142 'acpi_pm_prepare': dict(),
143 'syscore_suspend': dict(),
144 'arch_enable_nonboot_cpus_end': dict(),
145 'syscore_resume': dict(),
146 'acpi_pm_finish': dict(),
147 'resume_console': dict(),
148 'acpi_pm_end': dict(),
149 'pm_restore_gfp_mask': dict(),
150 'thaw_processes': dict(),
151 'pm_restore_console': dict(),
152 'CPU_OFF': {
153 'func':'_cpu_down',
154 'args_x86_64': {'cpu':'%di:s32'},
155 'format': 'CPU_OFF[{cpu}]'
156 },
157 'CPU_ON': {
158 'func':'_cpu_up',
159 'args_x86_64': {'cpu':'%di:s32'},
160 'format': 'CPU_ON[{cpu}]'
161 },
162 }
163 dev_tracefuncs = {
164 # general wait/delay/sleep
165 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 },
166 'schedule_timeout_uninterruptible': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
167 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
168 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 },
169 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 },
170 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 },
171 'acpi_os_stall': {'ub': 1},
172 # ACPI
173 'acpi_resume_power_resources': dict(),
174 'acpi_ps_parse_aml': dict(),
175 # filesystem
176 'ext4_sync_fs': dict(),
177 # 80211
178 'iwlagn_mac_start': dict(),
179 'iwlagn_alloc_bcast_station': dict(),
180 'iwl_trans_pcie_start_hw': dict(),
181 'iwl_trans_pcie_start_fw': dict(),
182 'iwl_run_init_ucode': dict(),
183 'iwl_load_ucode_wait_alive': dict(),
184 'iwl_alive_start': dict(),
185 'iwlagn_mac_stop': dict(),
186 'iwlagn_mac_suspend': dict(),
187 'iwlagn_mac_resume': dict(),
188 'iwlagn_mac_add_interface': dict(),
189 'iwlagn_mac_remove_interface': dict(),
190 'iwlagn_mac_change_interface': dict(),
191 'iwlagn_mac_config': dict(),
192 'iwlagn_configure_filter': dict(),
193 'iwlagn_mac_hw_scan': dict(),
194 'iwlagn_bss_info_changed': dict(),
195 'iwlagn_mac_channel_switch': dict(),
196 'iwlagn_mac_flush': dict(),
197 # ATA
198 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} },
199 # i915
200 'i915_gem_resume': dict(),
201 'i915_restore_state': dict(),
202 'intel_opregion_setup': dict(),
203 'g4x_pre_enable_dp': dict(),
204 'vlv_pre_enable_dp': dict(),
205 'chv_pre_enable_dp': dict(),
206 'g4x_enable_dp': dict(),
207 'vlv_enable_dp': dict(),
208 'intel_hpd_init': dict(),
209 'intel_opregion_register': dict(),
210 'intel_dp_detect': dict(),
211 'intel_hdmi_detect': dict(),
212 'intel_opregion_init': dict(),
213 'intel_fbdev_set_suspend': dict(),
214 }
215 kprobes = dict()
216 timeformat = '%.3f'
217 def __init__(self):
218 # if this is a phoronix test run, set some default options
219 if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ):
220 self.embedded = True
221 self.addlogs = True
222 self.htmlfile = os.environ['LOG_FILE']
223 self.archargs = 'args_'+platform.machine()
224 self.hostname = platform.node()
225 if(self.hostname == ''):
226 self.hostname = 'localhost'
227 rtc = "rtc0"
228 if os.path.exists('/dev/rtc'):
229 rtc = os.readlink('/dev/rtc')
230 rtc = '/sys/class/rtc/'+rtc
231 if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \
232 os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'):
233 self.rtcpath = rtc
234 if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()):
235 self.ansi = True
236 def rootUser(self, fatal=False):
237 if 'USER' in os.environ and os.environ['USER'] == 'root':
238 return True
239 if fatal:
240 doError('This command must be run as root')
241 return False
242 def setPrecision(self, num):
243 if num < 0 or num > 6:
244 return
245 self.timeformat = '%.{0}f'.format(num)
246 def setOutputFolder(self, value):
247 args = dict()
248 n = datetime.now()
249 args['date'] = n.strftime('%y%m%d')
250 args['time'] = n.strftime('%H%M%S')
251 args['hostname'] = self.hostname
252 self.outdir = value.format(**args)
253 def setOutputFile(self):
254 if((self.htmlfile == '') and (self.dmesgfile != '')):
255 m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile)
256 if(m):
257 self.htmlfile = m.group('name')+'.html'
258 if((self.htmlfile == '') and (self.ftracefile != '')):
259 m = re.match('(?P<name>.*)_ftrace\.txt$', self.ftracefile)
260 if(m):
261 self.htmlfile = m.group('name')+'.html'
262 if(self.htmlfile == ''):
263 self.htmlfile = 'output.html'
264 def initTestOutput(self, subdir, testpath=''):
265 self.prefix = self.hostname
266 v = open('/proc/version', 'r').read().strip()
267 kver = string.split(v)[2]
268 n = datetime.now()
269 testtime = n.strftime('suspend-%m%d%y-%H%M%S')
270 if not testpath:
271 testpath = n.strftime('suspend-%y%m%d-%H%M%S')
272 if(subdir != "."):
273 self.testdir = subdir+"/"+testpath
274 else:
275 self.testdir = testpath
276 self.teststamp = \
277 '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver
278 if(self.embedded):
279 self.dmesgfile = \
280 '/tmp/'+testtime+'_'+self.suspendmode+'_dmesg.txt'
281 self.ftracefile = \
282 '/tmp/'+testtime+'_'+self.suspendmode+'_ftrace.txt'
283 return
284 self.dmesgfile = \
285 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'
286 self.ftracefile = \
287 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'
288 self.htmlfile = \
289 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html'
290 if not os.path.isdir(self.testdir):
291 os.mkdir(self.testdir)
292 def setDeviceFilter(self, value):
293 self.devicefilter = []
294 if value:
295 value = value.split(',')
296 for i in value:
297 self.devicefilter.append(i.strip())
298 def rtcWakeAlarmOn(self):
299 call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True)
300 outD = open(self.rtcpath+'/date', 'r').read().strip()
301 outT = open(self.rtcpath+'/time', 'r').read().strip()
302 mD = re.match('^(?P<y>[0-9]*)-(?P<m>[0-9]*)-(?P<d>[0-9]*)', outD)
303 mT = re.match('^(?P<h>[0-9]*):(?P<m>[0-9]*):(?P<s>[0-9]*)', outT)
304 if(mD and mT):
305 # get the current time from hardware
306 utcoffset = int((datetime.now() - datetime.utcnow()).total_seconds())
307 dt = datetime(\
308 int(mD.group('y')), int(mD.group('m')), int(mD.group('d')),
309 int(mT.group('h')), int(mT.group('m')), int(mT.group('s')))
310 nowtime = int(dt.strftime('%s')) + utcoffset
311 else:
312 # if hardware time fails, use the software time
313 nowtime = int(datetime.now().strftime('%s'))
314 alarm = nowtime + self.rtcwaketime
315 call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True)
316 def rtcWakeAlarmOff(self):
317 call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True)
318 def initdmesg(self):
319 # get the latest time stamp from the dmesg log
320 fp = Popen('dmesg', stdout=PIPE).stdout
321 ktime = '0'
322 for line in fp:
323 line = line.replace('\r\n', '')
324 idx = line.find('[')
325 if idx > 1:
326 line = line[idx:]
327 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
328 if(m):
329 ktime = m.group('ktime')
330 fp.close()
331 self.dmesgstart = float(ktime)
332 def getdmesg(self):
333 # store all new dmesg lines since initdmesg was called
334 fp = Popen('dmesg', stdout=PIPE).stdout
335 op = open(self.dmesgfile, 'a')
336 for line in fp:
337 line = line.replace('\r\n', '')
338 idx = line.find('[')
339 if idx > 1:
340 line = line[idx:]
341 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
342 if(not m):
343 continue
344 ktime = float(m.group('ktime'))
345 if ktime > self.dmesgstart:
346 op.write(line)
347 fp.close()
348 op.close()
349 def addFtraceFilterFunctions(self, file):
350 fp = open(file)
351 list = fp.read().split('\n')
352 fp.close()
353 for i in list:
354 if len(i) < 2:
355 continue
356 self.tracefuncs[i] = dict()
357 def getFtraceFilterFunctions(self, current):
358 rootCheck(True)
359 if not current:
360 call('cat '+self.tpath+'available_filter_functions', shell=True)
361 return
362 fp = open(self.tpath+'available_filter_functions')
363 master = fp.read().split('\n')
364 fp.close()
365 for i in self.tracefuncs:
366 if 'func' in self.tracefuncs[i]:
367 i = self.tracefuncs[i]['func']
368 if i in master:
369 print i
370 else:
371 print self.colorText(i)
372 def setFtraceFilterFunctions(self, list):
373 fp = open(self.tpath+'available_filter_functions')
374 master = fp.read().split('\n')
375 fp.close()
376 flist = ''
377 for i in list:
378 if i not in master:
379 continue
380 if ' [' in i:
381 flist += i.split(' ')[0]+'\n'
382 else:
383 flist += i+'\n'
384 fp = open(self.tpath+'set_graph_function', 'w')
385 fp.write(flist)
386 fp.close()
387 def basicKprobe(self, name):
388 self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name}
389 def defaultKprobe(self, name, kdata):
390 k = kdata
391 for field in ['name', 'format', 'func']:
392 if field not in k:
393 k[field] = name
394 if self.archargs in k:
395 k['args'] = k[self.archargs]
396 else:
397 k['args'] = dict()
398 k['format'] = name
399 self.kprobes[name] = k
400 def kprobeColor(self, name):
401 if name not in self.kprobes or 'color' not in self.kprobes[name]:
402 return ''
403 return self.kprobes[name]['color']
404 def kprobeDisplayName(self, name, dataraw):
405 if name not in self.kprobes:
406 self.basicKprobe(name)
407 data = ''
408 quote=0
409 # first remvoe any spaces inside quotes, and the quotes
410 for c in dataraw:
411 if c == '"':
412 quote = (quote + 1) % 2
413 if quote and c == ' ':
414 data += '_'
415 elif c != '"':
416 data += c
417 fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args']
418 arglist = dict()
419 # now process the args
420 for arg in sorted(args):
421 arglist[arg] = ''
422 m = re.match('.* '+arg+'=(?P<arg>.*) ', data);
423 if m:
424 arglist[arg] = m.group('arg')
425 else:
426 m = re.match('.* '+arg+'=(?P<arg>.*)', data);
427 if m:
428 arglist[arg] = m.group('arg')
429 out = fmt.format(**arglist)
430 out = out.replace(' ', '_').replace('"', '')
431 return out
432 def kprobeText(self, kname, kprobe):
433 name = fmt = func = kname
434 args = dict()
435 if 'name' in kprobe:
436 name = kprobe['name']
437 if 'format' in kprobe:
438 fmt = kprobe['format']
439 if 'func' in kprobe:
440 func = kprobe['func']
441 if self.archargs in kprobe:
442 args = kprobe[self.archargs]
443 if 'args' in kprobe:
444 args = kprobe['args']
445 if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func):
446 doError('Kprobe "%s" has format info in the function name "%s"' % (name, func))
447 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt):
448 if arg not in args:
449 doError('Kprobe "%s" is missing argument "%s"' % (name, arg))
450 val = 'p:%s_cal %s' % (name, func)
451 for i in sorted(args):
452 val += ' %s=%s' % (i, args[i])
453 val += '\nr:%s_ret %s $retval\n' % (name, func)
454 return val
455 def addKprobes(self, output=False):
456 if len(sysvals.kprobes) < 1:
457 return
458 if output:
459 print(' kprobe functions in this kernel:')
460 # first test each kprobe
461 rejects = []
462 # sort kprobes: trace, ub-dev, custom, dev
463 kpl = [[], [], [], []]
464 for name in sorted(self.kprobes):
465 res = self.colorText('YES', 32)
466 if not self.testKprobe(name, self.kprobes[name]):
467 res = self.colorText('NO')
468 rejects.append(name)
469 else:
470 if name in self.tracefuncs:
471 kpl[0].append(name)
472 elif name in self.dev_tracefuncs:
473 if 'ub' in self.dev_tracefuncs[name]:
474 kpl[1].append(name)
475 else:
476 kpl[3].append(name)
477 else:
478 kpl[2].append(name)
479 if output:
480 print(' %s: %s' % (name, res))
481 kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3]
482 # remove all failed ones from the list
483 for name in rejects:
484 self.kprobes.pop(name)
485 # set the kprobes all at once
486 self.fsetVal('', 'kprobe_events')
487 kprobeevents = ''
488 for kp in kplist:
489 kprobeevents += self.kprobeText(kp, self.kprobes[kp])
490 self.fsetVal(kprobeevents, 'kprobe_events')
491 # verify that the kprobes were set as ordered
492 check = self.fgetVal('kprobe_events')
493 linesout = len(kprobeevents.split('\n')) - 1
494 linesack = len(check.split('\n')) - 1
495 if output:
496 res = '%d/%d' % (linesack, linesout)
497 if linesack < linesout:
498 res = self.colorText(res, 31)
499 else:
500 res = self.colorText(res, 32)
501 print(' working kprobe functions enabled: %s' % res)
502 self.fsetVal('1', 'events/kprobes/enable')
503 def testKprobe(self, kname, kprobe):
504 self.fsetVal('0', 'events/kprobes/enable')
505 kprobeevents = self.kprobeText(kname, kprobe)
506 if not kprobeevents:
507 return False
508 try:
509 self.fsetVal(kprobeevents, 'kprobe_events')
510 check = self.fgetVal('kprobe_events')
511 except:
512 return False
513 linesout = len(kprobeevents.split('\n'))
514 linesack = len(check.split('\n'))
515 if linesack < linesout:
516 return False
517 return True
518 def fsetVal(self, val, path, mode='w'):
519 file = self.tpath+path
520 if not os.path.exists(file):
521 return False
522 try:
523 fp = open(file, mode, 0)
524 fp.write(val)
525 fp.flush()
526 fp.close()
527 except:
528 pass
529 return True
530 def fgetVal(self, path):
531 file = self.tpath+path
532 res = ''
533 if not os.path.exists(file):
534 return res
535 try:
536 fp = open(file, 'r')
537 res = fp.read()
538 fp.close()
539 except:
540 pass
541 return res
542 def cleanupFtrace(self):
543 if(self.usecallgraph or self.usetraceevents):
544 self.fsetVal('0', 'events/kprobes/enable')
545 self.fsetVal('', 'kprobe_events')
546 def setupAllKprobes(self):
547 for name in self.tracefuncs:
548 self.defaultKprobe(name, self.tracefuncs[name])
549 for name in self.dev_tracefuncs:
550 self.defaultKprobe(name, self.dev_tracefuncs[name])
551 def isCallgraphFunc(self, name):
552 if len(self.tracefuncs) < 1 and self.suspendmode == 'command':
553 return True
554 for i in self.tracefuncs:
555 if 'func' in self.tracefuncs[i]:
556 f = self.tracefuncs[i]['func']
557 else:
558 f = i
559 if name == f:
560 return True
561 return False
562 def initFtrace(self, testing=False):
563 print('INITIALIZING FTRACE...')
564 # turn trace off
565 self.fsetVal('0', 'tracing_on')
566 self.cleanupFtrace()
567 # set the trace clock to global
568 self.fsetVal('global', 'trace_clock')
569 # set trace buffer to a huge value
570 self.fsetVal('nop', 'current_tracer')
571 self.fsetVal('131073', 'buffer_size_kb')
572 # go no further if this is just a status check
573 if testing:
574 return
575 # initialize the callgraph trace
576 if(self.usecallgraph):
577 # set trace type
578 self.fsetVal('function_graph', 'current_tracer')
579 self.fsetVal('', 'set_ftrace_filter')
580 # set trace format options
581 self.fsetVal('print-parent', 'trace_options')
582 self.fsetVal('funcgraph-abstime', 'trace_options')
583 self.fsetVal('funcgraph-cpu', 'trace_options')
584 self.fsetVal('funcgraph-duration', 'trace_options')
585 self.fsetVal('funcgraph-proc', 'trace_options')
586 self.fsetVal('funcgraph-tail', 'trace_options')
587 self.fsetVal('nofuncgraph-overhead', 'trace_options')
588 self.fsetVal('context-info', 'trace_options')
589 self.fsetVal('graph-time', 'trace_options')
590 self.fsetVal('%d' % self.max_graph_depth, 'max_graph_depth')
591 cf = ['dpm_run_callback']
592 if(self.usetraceeventsonly):
593 cf += ['dpm_prepare', 'dpm_complete']
594 for fn in self.tracefuncs:
595 if 'func' in self.tracefuncs[fn]:
596 cf.append(self.tracefuncs[fn]['func'])
597 else:
598 cf.append(fn)
599 self.setFtraceFilterFunctions(cf)
600 # initialize the kprobe trace
601 elif self.usekprobes:
602 for name in self.tracefuncs:
603 self.defaultKprobe(name, self.tracefuncs[name])
604 if self.usedevsrc:
605 for name in self.dev_tracefuncs:
606 self.defaultKprobe(name, self.dev_tracefuncs[name])
607 print('INITIALIZING KPROBES...')
608 self.addKprobes(self.verbose)
609 if(self.usetraceevents):
610 # turn trace events on
611 events = iter(self.traceevents)
612 for e in events:
613 self.fsetVal('1', 'events/power/'+e+'/enable')
614 # clear the trace buffer
615 self.fsetVal('', 'trace')
616 def verifyFtrace(self):
617 # files needed for any trace data
618 files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock',
619 'trace_marker', 'trace_options', 'tracing_on']
620 # files needed for callgraph trace data
621 tp = self.tpath
622 if(self.usecallgraph):
623 files += [
624 'available_filter_functions',
625 'set_ftrace_filter',
626 'set_graph_function'
627 ]
628 for f in files:
629 if(os.path.exists(tp+f) == False):
630 return False
631 return True
632 def verifyKprobes(self):
633 # files needed for kprobes to work
634 files = ['kprobe_events', 'events']
635 tp = self.tpath
636 for f in files:
637 if(os.path.exists(tp+f) == False):
638 return False
639 return True
640 def colorText(self, str, color=31):
641 if not self.ansi:
642 return str
643 return '\x1B[%d;40m%s\x1B[m' % (color, str)
644
645sysvals = SystemValues()
646suspendmodename = {
647 'freeze': 'Freeze (S0)',
648 'standby': 'Standby (S1)',
649 'mem': 'Suspend (S3)',
650 'disk': 'Hibernate (S4)'
651}
652
653# Class: DevProps
654# Description:
655# Simple class which holds property values collected
656# for all the devices used in the timeline.
657class DevProps:
658 syspath = ''
659 altname = ''
660 async = True
661 xtraclass = ''
662 xtrainfo = ''
663 def out(self, dev):
664 return '%s,%s,%d;' % (dev, self.altname, self.async)
665 def debug(self, dev):
666 print '%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.async)
667 def altName(self, dev):
668 if not self.altname or self.altname == dev:
669 return dev
670 return '%s [%s]' % (self.altname, dev)
671 def xtraClass(self):
672 if self.xtraclass:
673 return ' '+self.xtraclass
674 if not self.async:
675 return ' sync'
676 return ''
677 def xtraInfo(self):
678 if self.xtraclass:
679 return ' '+self.xtraclass
680 if self.async:
681 return ' async_device'
682 return ' sync_device'
683
684# Class: DeviceNode
685# Description:
686# A container used to create a device hierachy, with a single root node
687# and a tree of child nodes. Used by Data.deviceTopology()
688class DeviceNode:
689 name = ''
690 children = 0
691 depth = 0
692 def __init__(self, nodename, nodedepth):
693 self.name = nodename
694 self.children = []
695 self.depth = nodedepth
696
697# Class: Data
698# Description:
699# The primary container for suspend/resume test data. There is one for
700# each test run. The data is organized into a cronological hierarchy:
701# Data.dmesg {
702# phases {
703# 10 sequential, non-overlapping phases of S/R
704# contents: times for phase start/end, order/color data for html
705# devlist {
706# device callback or action list for this phase
707# device {
708# a single device callback or generic action
709# contents: start/stop times, pid/cpu/driver info
710# parents/children, html id for timeline/callgraph
711# optionally includes an ftrace callgraph
712# optionally includes dev/ps data
713# }
714# }
715# }
716# }
717#
718class Data:
719 dmesg = {} # root data structure
720 phases = [] # ordered list of phases
721 start = 0.0 # test start
722 end = 0.0 # test end
723 tSuspended = 0.0 # low-level suspend start
724 tResumed = 0.0 # low-level resume start
725 tKernSus = 0.0 # kernel level suspend start
726 tKernRes = 0.0 # kernel level resume end
727 tLow = 0.0 # time spent in low-level suspend (standby/freeze)
728 fwValid = False # is firmware data available
729 fwSuspend = 0 # time spent in firmware suspend
730 fwResume = 0 # time spent in firmware resume
731 dmesgtext = [] # dmesg text file in memory
732 pstl = 0 # process timeline
733 testnumber = 0
734 idstr = ''
735 html_device_id = 0
736 stamp = 0
737 outfile = ''
738 devpids = []
739 kerror = False
740 def __init__(self, num):
741 idchar = 'abcdefghij'
742 self.pstl = dict()
743 self.testnumber = num
744 self.idstr = idchar[num]
745 self.dmesgtext = []
746 self.phases = []
747 self.dmesg = { # fixed list of 10 phases
748 'suspend_prepare': {'list': dict(), 'start': -1.0, 'end': -1.0,
749 'row': 0, 'color': '#CCFFCC', 'order': 0},
750 'suspend': {'list': dict(), 'start': -1.0, 'end': -1.0,
751 'row': 0, 'color': '#88FF88', 'order': 1},
752 'suspend_late': {'list': dict(), 'start': -1.0, 'end': -1.0,
753 'row': 0, 'color': '#00AA00', 'order': 2},
754 'suspend_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0,
755 'row': 0, 'color': '#008888', 'order': 3},
756 'suspend_machine': {'list': dict(), 'start': -1.0, 'end': -1.0,
757 'row': 0, 'color': '#0000FF', 'order': 4},
758 'resume_machine': {'list': dict(), 'start': -1.0, 'end': -1.0,
759 'row': 0, 'color': '#FF0000', 'order': 5},
760 'resume_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0,
761 'row': 0, 'color': '#FF9900', 'order': 6},
762 'resume_early': {'list': dict(), 'start': -1.0, 'end': -1.0,
763 'row': 0, 'color': '#FFCC00', 'order': 7},
764 'resume': {'list': dict(), 'start': -1.0, 'end': -1.0,
765 'row': 0, 'color': '#FFFF88', 'order': 8},
766 'resume_complete': {'list': dict(), 'start': -1.0, 'end': -1.0,
767 'row': 0, 'color': '#FFFFCC', 'order': 9}
768 }
769 self.phases = self.sortedPhases()
770 self.devicegroups = []
771 for phase in self.phases:
772 self.devicegroups.append([phase])
773 self.errorinfo = {'suspend':[],'resume':[]}
774 def extractErrorInfo(self, dmesg):
775 error = ''
776 tm = 0.0
777 for i in range(len(dmesg)):
778 if 'Call Trace:' in dmesg[i]:
779 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) .*', dmesg[i])
780 if not m:
781 continue
782 tm = float(m.group('ktime'))
783 if tm < self.start or tm > self.end:
784 continue
785 for j in range(i-10, i+1):
786 error += dmesg[j]
787 continue
788 if error:
789 m = re.match('[ \t]*\[ *[0-9\.]*\] \[\<[0-9a-fA-F]*\>\] .*', dmesg[i])
790 if m:
791 error += dmesg[i]
792 else:
793 if tm < self.tSuspended:
794 dir = 'suspend'
795 else:
796 dir = 'resume'
797 error = error.replace('<', '&lt').replace('>', '&gt')
798 vprint('kernel error found in %s at %f' % (dir, tm))
799 self.errorinfo[dir].append((tm, error))
800 self.kerror = True
801 error = ''
802 def setStart(self, time):
803 self.start = time
804 def setEnd(self, time):
805 self.end = time
806 def isTraceEventOutsideDeviceCalls(self, pid, time):
807 for phase in self.phases:
808 list = self.dmesg[phase]['list']
809 for dev in list:
810 d = list[dev]
811 if(d['pid'] == pid and time >= d['start'] and
812 time < d['end']):
813 return False
814 return True
815 def sourcePhase(self, start):
816 for phase in self.phases:
817 pend = self.dmesg[phase]['end']
818 if start <= pend:
819 return phase
820 return 'resume_complete'
821 def sourceDevice(self, phaselist, start, end, pid, type):
822 tgtdev = ''
823 for phase in phaselist:
824 list = self.dmesg[phase]['list']
825 for devname in list:
826 dev = list[devname]
827 # pid must match
828 if dev['pid'] != pid:
829 continue
830 devS = dev['start']
831 devE = dev['end']
832 if type == 'device':
833 # device target event is entirely inside the source boundary
834 if(start < devS or start >= devE or end <= devS or end > devE):
835 continue
836 elif type == 'thread':
837 # thread target event will expand the source boundary
838 if start < devS:
839 dev['start'] = start
840 if end > devE:
841 dev['end'] = end
842 tgtdev = dev
843 break
844 return tgtdev
845 def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata):
846 # try to place the call in a device
847 tgtdev = self.sourceDevice(self.phases, start, end, pid, 'device')
848 # calls with device pids that occur outside device bounds are dropped
849 # TODO: include these somehow
850 if not tgtdev and pid in self.devpids:
851 return False
852 # try to place the call in a thread
853 if not tgtdev:
854 tgtdev = self.sourceDevice(self.phases, start, end, pid, 'thread')
855 # create new thread blocks, expand as new calls are found
856 if not tgtdev:
857 if proc == '<...>':
858 threadname = 'kthread-%d' % (pid)
859 else:
860 threadname = '%s-%d' % (proc, pid)
861 tgtphase = self.sourcePhase(start)
862 self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '')
863 return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)
864 # this should not happen
865 if not tgtdev:
866 vprint('[%f - %f] %s-%d %s %s %s' % \
867 (start, end, proc, pid, kprobename, cdata, rdata))
868 return False
869 # place the call data inside the src element of the tgtdev
870 if('src' not in tgtdev):
871 tgtdev['src'] = []
872 dtf = sysvals.dev_tracefuncs
873 ubiquitous = False
874 if kprobename in dtf and 'ub' in dtf[kprobename]:
875 ubiquitous = True
876 title = cdata+' '+rdata
877 mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)'
878 m = re.match(mstr, title)
879 if m:
880 c = m.group('caller')
881 a = m.group('args').strip()
882 r = m.group('ret')
883 if len(r) > 6:
884 r = ''
885 else:
886 r = 'ret=%s ' % r
887 if ubiquitous and c in dtf and 'ub' in dtf[c]:
888 return False
889 color = sysvals.kprobeColor(kprobename)
890 e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color)
891 tgtdev['src'].append(e)
892 return True
893 def overflowDevices(self):
894 # get a list of devices that extend beyond the end of this test run
895 devlist = []
896 for phase in self.phases:
897 list = self.dmesg[phase]['list']
898 for devname in list:
899 dev = list[devname]
900 if dev['end'] > self.end:
901 devlist.append(dev)
902 return devlist
903 def mergeOverlapDevices(self, devlist):
904 # merge any devices that overlap devlist
905 for dev in devlist:
906 devname = dev['name']
907 for phase in self.phases:
908 list = self.dmesg[phase]['list']
909 if devname not in list:
910 continue
911 tdev = list[devname]
912 o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start'])
913 if o <= 0:
914 continue
915 dev['end'] = tdev['end']
916 if 'src' not in dev or 'src' not in tdev:
917 continue
918 dev['src'] += tdev['src']
919 del list[devname]
920 def usurpTouchingThread(self, name, dev):
921 # the caller test has priority of this thread, give it to him
922 for phase in self.phases:
923 list = self.dmesg[phase]['list']
924 if name in list:
925 tdev = list[name]
926 if tdev['start'] - dev['end'] < 0.1:
927 dev['end'] = tdev['end']
928 if 'src' not in dev:
929 dev['src'] = []
930 if 'src' in tdev:
931 dev['src'] += tdev['src']
932 del list[name]
933 break
934 def stitchTouchingThreads(self, testlist):
935 # merge any threads between tests that touch
936 for phase in self.phases:
937 list = self.dmesg[phase]['list']
938 for devname in list:
939 dev = list[devname]
940 if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']:
941 continue
942 for data in testlist:
943 data.usurpTouchingThread(devname, dev)
944 def optimizeDevSrc(self):
945 # merge any src call loops to reduce timeline size
946 for phase in self.phases:
947 list = self.dmesg[phase]['list']
948 for dev in list:
949 if 'src' not in list[dev]:
950 continue
951 src = list[dev]['src']
952 p = 0
953 for e in sorted(src, key=lambda event: event.time):
954 if not p or not e.repeat(p):
955 p = e
956 continue
957 # e is another iteration of p, move it into p
958 p.end = e.end
959 p.length = p.end - p.time
960 p.count += 1
961 src.remove(e)
962 def trimTimeVal(self, t, t0, dT, left):
963 if left:
964 if(t > t0):
965 if(t - dT < t0):
966 return t0
967 return t - dT
968 else:
969 return t
970 else:
971 if(t < t0 + dT):
972 if(t > t0):
973 return t0 + dT
974 return t + dT
975 else:
976 return t
977 def trimTime(self, t0, dT, left):
978 self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left)
979 self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left)
980 self.start = self.trimTimeVal(self.start, t0, dT, left)
981 self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left)
982 self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left)
983 self.end = self.trimTimeVal(self.end, t0, dT, left)
984 for phase in self.phases:
985 p = self.dmesg[phase]
986 p['start'] = self.trimTimeVal(p['start'], t0, dT, left)
987 p['end'] = self.trimTimeVal(p['end'], t0, dT, left)
988 list = p['list']
989 for name in list:
990 d = list[name]
991 d['start'] = self.trimTimeVal(d['start'], t0, dT, left)
992 d['end'] = self.trimTimeVal(d['end'], t0, dT, left)
993 if('ftrace' in d):
994 cg = d['ftrace']
995 cg.start = self.trimTimeVal(cg.start, t0, dT, left)
996 cg.end = self.trimTimeVal(cg.end, t0, dT, left)
997 for line in cg.list:
998 line.time = self.trimTimeVal(line.time, t0, dT, left)
999 if('src' in d):
1000 for e in d['src']:
1001 e.time = self.trimTimeVal(e.time, t0, dT, left)
1002 def normalizeTime(self, tZero):
1003 # trim out any standby or freeze clock time
1004 if(self.tSuspended != self.tResumed):
1005 if(self.tResumed > tZero):
1006 self.trimTime(self.tSuspended, \
1007 self.tResumed-self.tSuspended, True)
1008 else:
1009 self.trimTime(self.tSuspended, \
1010 self.tResumed-self.tSuspended, False)
1011 def setPhase(self, phase, ktime, isbegin):
1012 if(isbegin):
1013 self.dmesg[phase]['start'] = ktime
1014 else:
1015 self.dmesg[phase]['end'] = ktime
1016 def dmesgSortVal(self, phase):
1017 return self.dmesg[phase]['order']
1018 def sortedPhases(self):
1019 return sorted(self.dmesg, key=self.dmesgSortVal)
1020 def sortedDevices(self, phase):
1021 list = self.dmesg[phase]['list']
1022 slist = []
1023 tmp = dict()
1024 for devname in list:
1025 dev = list[devname]
1026 if dev['length'] == 0:
1027 continue
1028 tmp[dev['start']] = devname
1029 for t in sorted(tmp):
1030 slist.append(tmp[t])
1031 return slist
1032 def fixupInitcalls(self, phase):
1033 # if any calls never returned, clip them at system resume end
1034 phaselist = self.dmesg[phase]['list']
1035 for devname in phaselist:
1036 dev = phaselist[devname]
1037 if(dev['end'] < 0):
1038 for p in self.phases:
1039 if self.dmesg[p]['end'] > dev['start']:
1040 dev['end'] = self.dmesg[p]['end']
1041 break
1042 vprint('%s (%s): callback didnt return' % (devname, phase))
1043 def deviceFilter(self, devicefilter):
1044 for phase in self.phases:
1045 list = self.dmesg[phase]['list']
1046 rmlist = []
1047 for name in list:
1048 keep = False
1049 for filter in devicefilter:
1050 if filter in name or \
1051 ('drv' in list[name] and filter in list[name]['drv']):
1052 keep = True
1053 if not keep:
1054 rmlist.append(name)
1055 for name in rmlist:
1056 del list[name]
1057 def fixupInitcallsThatDidntReturn(self):
1058 # if any calls never returned, clip them at system resume end
1059 for phase in self.phases:
1060 self.fixupInitcalls(phase)
1061 def phaseOverlap(self, phases):
1062 rmgroups = []
1063 newgroup = []
1064 for group in self.devicegroups:
1065 for phase in phases:
1066 if phase not in group:
1067 continue
1068 for p in group:
1069 if p not in newgroup:
1070 newgroup.append(p)
1071 if group not in rmgroups:
1072 rmgroups.append(group)
1073 for group in rmgroups:
1074 self.devicegroups.remove(group)
1075 self.devicegroups.append(newgroup)
1076 def newActionGlobal(self, name, start, end, pid=-1, color=''):
1077 # which phase is this device callback or action in
1078 targetphase = 'none'
1079 htmlclass = ''
1080 overlap = 0.0
1081 phases = []
1082 for phase in self.phases:
1083 pstart = self.dmesg[phase]['start']
1084 pend = self.dmesg[phase]['end']
1085 # see if the action overlaps this phase
1086 o = max(0, min(end, pend) - max(start, pstart))
1087 if o > 0:
1088 phases.append(phase)
1089 # set the target phase to the one that overlaps most
1090 if o > overlap:
1091 if overlap > 0 and phase == 'post_resume':
1092 continue
1093 targetphase = phase
1094 overlap = o
1095 # if no target phase was found, pin it to the edge
1096 if targetphase == 'none':
1097 p0start = self.dmesg[self.phases[0]]['start']
1098 if start <= p0start:
1099 targetphase = self.phases[0]
1100 else:
1101 targetphase = self.phases[-1]
1102 if pid == -2:
1103 htmlclass = ' bg'
1104 elif pid == -3:
1105 htmlclass = ' ps'
1106 if len(phases) > 1:
1107 htmlclass = ' bg'
1108 self.phaseOverlap(phases)
1109 if targetphase in self.phases:
1110 newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color)
1111 return (targetphase, newname)
1112 return False
1113 def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''):
1114 # new device callback for a specific phase
1115 self.html_device_id += 1
1116 devid = '%s%d' % (self.idstr, self.html_device_id)
1117 list = self.dmesg[phase]['list']
1118 length = -1.0
1119 if(start >= 0 and end >= 0):
1120 length = end - start
1121 if pid == -2:
1122 i = 2
1123 origname = name
1124 while(name in list):
1125 name = '%s[%d]' % (origname, i)
1126 i += 1
1127 list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid,
1128 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv }
1129 if htmlclass:
1130 list[name]['htmlclass'] = htmlclass
1131 if color:
1132 list[name]['color'] = color
1133 return name
1134 def deviceChildren(self, devname, phase):
1135 devlist = []
1136 list = self.dmesg[phase]['list']
1137 for child in list:
1138 if(list[child]['par'] == devname):
1139 devlist.append(child)
1140 return devlist
1141 def printDetails(self):
1142 vprint('Timeline Details:')
1143 vprint(' test start: %f' % self.start)
1144 vprint('kernel suspend start: %f' % self.tKernSus)
1145 for phase in self.phases:
1146 dc = len(self.dmesg[phase]['list'])
1147 vprint(' %16s: %f - %f (%d devices)' % (phase, \
1148 self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc))
1149 vprint(' kernel resume end: %f' % self.tKernRes)
1150 vprint(' test end: %f' % self.end)
1151 def deviceChildrenAllPhases(self, devname):
1152 devlist = []
1153 for phase in self.phases:
1154 list = self.deviceChildren(devname, phase)
1155 for dev in list:
1156 if dev not in devlist:
1157 devlist.append(dev)
1158 return devlist
1159 def masterTopology(self, name, list, depth):
1160 node = DeviceNode(name, depth)
1161 for cname in list:
1162 # avoid recursions
1163 if name == cname:
1164 continue
1165 clist = self.deviceChildrenAllPhases(cname)
1166 cnode = self.masterTopology(cname, clist, depth+1)
1167 node.children.append(cnode)
1168 return node
1169 def printTopology(self, node):
1170 html = ''
1171 if node.name:
1172 info = ''
1173 drv = ''
1174 for phase in self.phases:
1175 list = self.dmesg[phase]['list']
1176 if node.name in list:
1177 s = list[node.name]['start']
1178 e = list[node.name]['end']
1179 if list[node.name]['drv']:
1180 drv = ' {'+list[node.name]['drv']+'}'
1181 info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000))
1182 html += '<li><b>'+node.name+drv+'</b>'
1183 if info:
1184 html += '<ul>'+info+'</ul>'
1185 html += '</li>'
1186 if len(node.children) > 0:
1187 html += '<ul>'
1188 for cnode in node.children:
1189 html += self.printTopology(cnode)
1190 html += '</ul>'
1191 return html
1192 def rootDeviceList(self):
1193 # list of devices graphed
1194 real = []
1195 for phase in self.dmesg:
1196 list = self.dmesg[phase]['list']
1197 for dev in list:
1198 if list[dev]['pid'] >= 0 and dev not in real:
1199 real.append(dev)
1200 # list of top-most root devices
1201 rootlist = []
1202 for phase in self.dmesg:
1203 list = self.dmesg[phase]['list']
1204 for dev in list:
1205 pdev = list[dev]['par']
1206 pid = list[dev]['pid']
1207 if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)):
1208 continue
1209 if pdev and pdev not in real and pdev not in rootlist:
1210 rootlist.append(pdev)
1211 return rootlist
1212 def deviceTopology(self):
1213 rootlist = self.rootDeviceList()
1214 master = self.masterTopology('', rootlist, 0)
1215 return self.printTopology(master)
1216 def selectTimelineDevices(self, widfmt, tTotal, mindevlen):
1217 # only select devices that will actually show up in html
1218 self.tdevlist = dict()
1219 for phase in self.dmesg:
1220 devlist = []
1221 list = self.dmesg[phase]['list']
1222 for dev in list:
1223 length = (list[dev]['end'] - list[dev]['start']) * 1000
1224 width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal)
1225 if width != '0.000000' and length >= mindevlen:
1226 devlist.append(dev)
1227 self.tdevlist[phase] = devlist
1228 def addHorizontalDivider(self, devname, devend):
1229 phase = 'suspend_prepare'
1230 self.newAction(phase, devname, -2, '', \
1231 self.start, devend, '', ' sec', '')
1232 if phase not in self.tdevlist:
1233 self.tdevlist[phase] = []
1234 self.tdevlist[phase].append(devname)
1235 d = DevItem(0, phase, self.dmesg[phase]['list'][devname])
1236 return d
1237 def addProcessUsageEvent(self, name, times):
1238 # get the start and end times for this process
1239 maxC = 0
1240 tlast = 0
1241 start = -1
1242 end = -1
1243 for t in sorted(times):
1244 if tlast == 0:
1245 tlast = t
1246 continue
1247 if name in self.pstl[t]:
1248 if start == -1 or tlast < start:
1249 start = tlast
1250 if end == -1 or t > end:
1251 end = t
1252 tlast = t
1253 if start == -1 or end == -1:
1254 return 0
1255 # add a new action for this process and get the object
1256 out = self.newActionGlobal(name, start, end, -3)
1257 if not out:
1258 return 0
1259 phase, devname = out
1260 dev = self.dmesg[phase]['list'][devname]
1261 # get the cpu exec data
1262 tlast = 0
1263 clast = 0
1264 cpuexec = dict()
1265 for t in sorted(times):
1266 if tlast == 0 or t <= start or t > end:
1267 tlast = t
1268 continue
1269 list = self.pstl[t]
1270 c = 0
1271 if name in list:
1272 c = list[name]
1273 if c > maxC:
1274 maxC = c
1275 if c != clast:
1276 key = (tlast, t)
1277 cpuexec[key] = c
1278 tlast = t
1279 clast = c
1280 dev['cpuexec'] = cpuexec
1281 return maxC
1282 def createProcessUsageEvents(self):
1283 # get an array of process names
1284 proclist = []
1285 for t in self.pstl:
1286 pslist = self.pstl[t]
1287 for ps in pslist:
1288 if ps not in proclist:
1289 proclist.append(ps)
1290 # get a list of data points for suspend and resume
1291 tsus = []
1292 tres = []
1293 for t in sorted(self.pstl):
1294 if t < self.tSuspended:
1295 tsus.append(t)
1296 else:
1297 tres.append(t)
1298 # process the events for suspend and resume
1299 if len(proclist) > 0:
1300 vprint('Process Execution:')
1301 for ps in proclist:
1302 c = self.addProcessUsageEvent(ps, tsus)
1303 if c > 0:
1304 vprint('%25s (sus): %d' % (ps, c))
1305 c = self.addProcessUsageEvent(ps, tres)
1306 if c > 0:
1307 vprint('%25s (res): %d' % (ps, c))
1308
1309# Class: DevFunction
1310# Description:
1311# A container for kprobe function data we want in the dev timeline
1312class DevFunction:
1313 row = 0
1314 count = 1
1315 def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color):
1316 self.name = name
1317 self.args = args
1318 self.caller = caller
1319 self.ret = ret
1320 self.time = start
1321 self.length = end - start
1322 self.end = end
1323 self.ubiquitous = u
1324 self.proc = proc
1325 self.pid = pid
1326 self.color = color
1327 def title(self):
1328 cnt = ''
1329 if self.count > 1:
1330 cnt = '(x%d)' % self.count
1331 l = '%0.3fms' % (self.length * 1000)
1332 if self.ubiquitous:
1333 title = '%s(%s)%s <- %s, %s(%s)' % \
1334 (self.name, self.args, cnt, self.caller, self.ret, l)
1335 else:
1336 title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l)
1337 return title.replace('"', '')
1338 def text(self):
1339 if self.count > 1:
1340 text = '%s(x%d)' % (self.name, self.count)
1341 else:
1342 text = self.name
1343 return text
1344 def repeat(self, tgt):
1345 # is the tgt call just a repeat of this call (e.g. are we in a loop)
1346 dt = self.time - tgt.end
1347 # only combine calls if -all- attributes are identical
1348 if tgt.caller == self.caller and \
1349 tgt.name == self.name and tgt.args == self.args and \
1350 tgt.proc == self.proc and tgt.pid == self.pid and \
1351 tgt.ret == self.ret and dt >= 0 and \
1352 dt <= sysvals.callloopmaxgap and \
1353 self.length < sysvals.callloopmaxlen:
1354 return True
1355 return False
1356
1357# Class: FTraceLine
1358# Description:
1359# A container for a single line of ftrace data. There are six basic types:
1360# callgraph line:
1361# call: " dpm_run_callback() {"
1362# return: " }"
1363# leaf: " dpm_run_callback();"
1364# trace event:
1365# tracing_mark_write: SUSPEND START or RESUME COMPLETE
1366# suspend_resume: phase or custom exec block data
1367# device_pm_callback: device callback info
1368class FTraceLine:
1369 time = 0.0
1370 length = 0.0
1371 fcall = False
1372 freturn = False
1373 fevent = False
1374 fkprobe = False
1375 depth = 0
1376 name = ''
1377 type = ''
1378 def __init__(self, t, m='', d=''):
1379 self.time = float(t)
1380 if not m and not d:
1381 return
1382 # is this a trace event
1383 if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)):
1384 if(d == 'traceevent'):
1385 # nop format trace event
1386 msg = m
1387 else:
1388 # function_graph format trace event
1389 em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)
1390 msg = em.group('msg')
1391
1392 emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg)
1393 if(emm):
1394 self.name = emm.group('msg')
1395 self.type = emm.group('call')
1396 else:
1397 self.name = msg
1398 km = re.match('^(?P<n>.*)_cal$', self.type)
1399 if km:
1400 self.fcall = True
1401 self.fkprobe = True
1402 self.type = km.group('n')
1403 return
1404 km = re.match('^(?P<n>.*)_ret$', self.type)
1405 if km:
1406 self.freturn = True
1407 self.fkprobe = True
1408 self.type = km.group('n')
1409 return
1410 self.fevent = True
1411 return
1412 # convert the duration to seconds
1413 if(d):
1414 self.length = float(d)/1000000
1415 # the indentation determines the depth
1416 match = re.match('^(?P<d> *)(?P<o>.*)$', m)
1417 if(not match):
1418 return
1419 self.depth = self.getDepth(match.group('d'))
1420 m = match.group('o')
1421 # function return
1422 if(m[0] == '}'):
1423 self.freturn = True
1424 if(len(m) > 1):
1425 # includes comment with function name
1426 match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m)
1427 if(match):
1428 self.name = match.group('n').strip()
1429 # function call
1430 else:
1431 self.fcall = True
1432 # function call with children
1433 if(m[-1] == '{'):
1434 match = re.match('^(?P<n>.*) *\(.*', m)
1435 if(match):
1436 self.name = match.group('n').strip()
1437 # function call with no children (leaf)
1438 elif(m[-1] == ';'):
1439 self.freturn = True
1440 match = re.match('^(?P<n>.*) *\(.*', m)
1441 if(match):
1442 self.name = match.group('n').strip()
1443 # something else (possibly a trace marker)
1444 else:
1445 self.name = m
1446 def getDepth(self, str):
1447 return len(str)/2
1448 def debugPrint(self, dev=''):
1449 if(self.freturn and self.fcall):
1450 print('%s -- %f (%02d): %s(); (%.3f us)' % (dev, self.time, \
1451 self.depth, self.name, self.length*1000000))
1452 elif(self.freturn):
1453 print('%s -- %f (%02d): %s} (%.3f us)' % (dev, self.time, \
1454 self.depth, self.name, self.length*1000000))
1455 else:
1456 print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \
1457 self.depth, self.name, self.length*1000000))
1458 def startMarker(self):
1459 # Is this the starting line of a suspend?
1460 if not self.fevent:
1461 return False
1462 if sysvals.usetracemarkers:
1463 if(self.name == 'SUSPEND START'):
1464 return True
1465 return False
1466 else:
1467 if(self.type == 'suspend_resume' and
1468 re.match('suspend_enter\[.*\] begin', self.name)):
1469 return True
1470 return False
1471 def endMarker(self):
1472 # Is this the ending line of a resume?
1473 if not self.fevent:
1474 return False
1475 if sysvals.usetracemarkers:
1476 if(self.name == 'RESUME COMPLETE'):
1477 return True
1478 return False
1479 else:
1480 if(self.type == 'suspend_resume' and
1481 re.match('thaw_processes\[.*\] end', self.name)):
1482 return True
1483 return False
1484
1485# Class: FTraceCallGraph
1486# Description:
1487# A container for the ftrace callgraph of a single recursive function.
1488# This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph
1489# Each instance is tied to a single device in a single phase, and is
1490# comprised of an ordered list of FTraceLine objects
1491class FTraceCallGraph:
1492 id = ''
1493 start = -1.0
1494 end = -1.0
1495 list = []
1496 invalid = False
1497 depth = 0
1498 pid = 0
1499 name = ''
1500 def __init__(self, pid):
1501 self.start = -1.0
1502 self.end = -1.0
1503 self.list = []
1504 self.depth = 0
1505 self.pid = pid
1506 def addLine(self, line, debug=False):
1507 # if this is already invalid, just leave
1508 if(self.invalid):
1509 return False
1510 # invalidate on too much data or bad depth
1511 if(len(self.list) >= 1000000 or self.depth < 0):
1512 self.invalidate(line)
1513 return False
1514 # compare current depth with this lines pre-call depth
1515 prelinedep = line.depth
1516 if(line.freturn and not line.fcall):
1517 prelinedep += 1
1518 last = 0
1519 lasttime = line.time
1520 virtualfname = 'execution_misalignment'
1521 if len(self.list) > 0:
1522 last = self.list[-1]
1523 lasttime = last.time
1524 # handle low misalignments by inserting returns
1525 if prelinedep < self.depth:
1526 if debug and last:
1527 print '-------- task %d --------' % self.pid
1528 last.debugPrint()
1529 idx = 0
1530 # add return calls to get the depth down
1531 while prelinedep < self.depth:
1532 if debug:
1533 print 'MISALIGN LOW (add returns): C%d - eC%d' % (self.depth, prelinedep)
1534 self.depth -= 1
1535 if idx == 0 and last and last.fcall and not last.freturn:
1536 # special case, turn last call into a leaf
1537 last.depth = self.depth
1538 last.freturn = True
1539 last.length = line.time - last.time
1540 if debug:
1541 last.debugPrint()
1542 else:
1543 vline = FTraceLine(lasttime)
1544 vline.depth = self.depth
1545 vline.name = virtualfname
1546 vline.freturn = True
1547 self.list.append(vline)
1548 if debug:
1549 vline.debugPrint()
1550 idx += 1
1551 if debug:
1552 line.debugPrint()
1553 print ''
1554 # handle high misalignments by inserting calls
1555 elif prelinedep > self.depth:
1556 if debug and last:
1557 print '-------- task %d --------' % self.pid
1558 last.debugPrint()
1559 idx = 0
1560 # add calls to get the depth up
1561 while prelinedep > self.depth:
1562 if debug:
1563 print 'MISALIGN HIGH (add calls): C%d - eC%d' % (self.depth, prelinedep)
1564 if idx == 0 and line.freturn and not line.fcall:
1565 # special case, turn this return into a leaf
1566 line.fcall = True
1567 prelinedep -= 1
1568 else:
1569 vline = FTraceLine(lasttime)
1570 vline.depth = self.depth
1571 vline.name = virtualfname
1572 vline.fcall = True
1573 if debug:
1574 vline.debugPrint()
1575 self.list.append(vline)
1576 self.depth += 1
1577 if not last:
1578 self.start = vline.time
1579 idx += 1
1580 if debug:
1581 line.debugPrint()
1582 print ''
1583 # process the call and set the new depth
1584 if(line.fcall and not line.freturn):
1585 self.depth += 1
1586 elif(line.freturn and not line.fcall):
1587 self.depth -= 1
1588 if len(self.list) < 1:
1589 self.start = line.time
1590 self.list.append(line)
1591 if(line.depth == 0 and line.freturn):
1592 if(self.start < 0):
1593 self.start = line.time
1594 self.end = line.time
1595 if line.fcall:
1596 self.end += line.length
1597 if self.list[0].name == virtualfname:
1598 self.invalid = True
1599 return True
1600 return False
1601 def invalidate(self, line):
1602 if(len(self.list) > 0):
1603 first = self.list[0]
1604 self.list = []
1605 self.list.append(first)
1606 self.invalid = True
1607 id = 'task %s' % (self.pid)
1608 window = '(%f - %f)' % (self.start, line.time)
1609 if(self.depth < 0):
1610 vprint('Too much data for '+id+\
1611 ' (buffer overflow), ignoring this callback')
1612 else:
1613 vprint('Too much data for '+id+\
1614 ' '+window+', ignoring this callback')
1615 def slice(self, t0, tN):
1616 minicg = FTraceCallGraph(0)
1617 count = -1
1618 firstdepth = 0
1619 for l in self.list:
1620 if(l.time < t0 or l.time > tN):
1621 continue
1622 if(count < 0):
1623 if(not l.fcall or l.name == 'dev_driver_string'):
1624 continue
1625 firstdepth = l.depth
1626 count = 0
1627 l.depth -= firstdepth
1628 minicg.addLine(l)
1629 if((count == 0 and l.freturn and l.fcall) or
1630 (count > 0 and l.depth <= 0)):
1631 break
1632 count += 1
1633 return minicg
1634 def repair(self, enddepth):
1635 # bring the depth back to 0 with additional returns
1636 fixed = False
1637 last = self.list[-1]
1638 for i in reversed(range(enddepth)):
1639 t = FTraceLine(last.time)
1640 t.depth = i
1641 t.freturn = True
1642 fixed = self.addLine(t)
1643 if fixed:
1644 self.end = last.time
1645 return True
1646 return False
1647 def postProcess(self, debug=False):
1648 if len(self.list) > 0:
1649 self.name = self.list[0].name
1650 stack = dict()
1651 cnt = 0
1652 last = 0
1653 for l in self.list:
1654 # ftrace bug: reported duration is not reliable
1655 # check each leaf and clip it at max possible length
1656 if(last and last.freturn and last.fcall):
1657 if last.length > l.time - last.time:
1658 last.length = l.time - last.time
1659 if(l.fcall and not l.freturn):
1660 stack[l.depth] = l
1661 cnt += 1
1662 elif(l.freturn and not l.fcall):
1663 if(l.depth not in stack):
1664 if debug:
1665 print 'Post Process Error: Depth missing'
1666 l.debugPrint()
1667 return False
1668 # calculate call length from call/return lines
1669 stack[l.depth].length = l.time - stack[l.depth].time
1670 stack.pop(l.depth)
1671 l.length = 0
1672 cnt -= 1
1673 last = l
1674 if(cnt == 0):
1675 # trace caught the whole call tree
1676 return True
1677 elif(cnt < 0):
1678 if debug:
1679 print 'Post Process Error: Depth is less than 0'
1680 return False
1681 # trace ended before call tree finished
1682 return self.repair(cnt)
1683 def deviceMatch(self, pid, data):
1684 found = False
1685 # add the callgraph data to the device hierarchy
1686 borderphase = {
1687 'dpm_prepare': 'suspend_prepare',
1688 'dpm_complete': 'resume_complete'
1689 }
1690 if(self.name in borderphase):
1691 p = borderphase[self.name]
1692 list = data.dmesg[p]['list']
1693 for devname in list:
1694 dev = list[devname]
1695 if(pid == dev['pid'] and
1696 self.start <= dev['start'] and
1697 self.end >= dev['end']):
1698 dev['ftrace'] = self.slice(dev['start'], dev['end'])
1699 found = True
1700 return found
1701 for p in data.phases:
1702 if(data.dmesg[p]['start'] <= self.start and
1703 self.start <= data.dmesg[p]['end']):
1704 list = data.dmesg[p]['list']
1705 for devname in list:
1706 dev = list[devname]
1707 if(pid == dev['pid'] and
1708 self.start <= dev['start'] and
1709 self.end >= dev['end']):
1710 dev['ftrace'] = self
1711 found = True
1712 break
1713 break
1714 return found
1715 def newActionFromFunction(self, data):
1716 name = self.name
1717 if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']:
1718 return
1719 fs = self.start
1720 fe = self.end
1721 if fs < data.start or fe > data.end:
1722 return
1723 phase = ''
1724 for p in data.phases:
1725 if(data.dmesg[p]['start'] <= self.start and
1726 self.start < data.dmesg[p]['end']):
1727 phase = p
1728 break
1729 if not phase:
1730 return
1731 out = data.newActionGlobal(name, fs, fe, -2)
1732 if out:
1733 phase, myname = out
1734 data.dmesg[phase]['list'][myname]['ftrace'] = self
1735 def debugPrint(self):
1736 print('[%f - %f] %s (%d)') % (self.start, self.end, self.name, self.pid)
1737 for l in self.list:
1738 if(l.freturn and l.fcall):
1739 print('%f (%02d): %s(); (%.3f us)' % (l.time, \
1740 l.depth, l.name, l.length*1000000))
1741 elif(l.freturn):
1742 print('%f (%02d): %s} (%.3f us)' % (l.time, \
1743 l.depth, l.name, l.length*1000000))
1744 else:
1745 print('%f (%02d): %s() { (%.3f us)' % (l.time, \
1746 l.depth, l.name, l.length*1000000))
1747 print(' ')
1748
1749class DevItem:
1750 def __init__(self, test, phase, dev):
1751 self.test = test
1752 self.phase = phase
1753 self.dev = dev
1754 def isa(self, cls):
1755 if 'htmlclass' in self.dev and cls in self.dev['htmlclass']:
1756 return True
1757 return False
1758
1759# Class: Timeline
1760# Description:
1761# A container for a device timeline which calculates
1762# all the html properties to display it correctly
1763class Timeline:
1764 html = ''
1765 height = 0 # total timeline height
1766 scaleH = 20 # timescale (top) row height
1767 rowH = 30 # device row height
1768 bodyH = 0 # body height
1769 rows = 0 # total timeline rows
1770 rowlines = dict()
1771 rowheight = dict()
1772 html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n'
1773 html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n'
1774 html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n'
1775 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n'
1776 def __init__(self, rowheight, scaleheight):
1777 self.rowH = rowheight
1778 self.scaleH = scaleheight
1779 self.html = ''
1780 def createHeader(self, sv, suppress=''):
1781 if(not sv.stamp['time']):
1782 return
1783 self.html += '<div class="version"><a href="https://01.org/suspendresume">%s v%s</a></div>' \
1784 % (sv.title, sv.version)
1785 if sv.logmsg and 'log' not in suppress:
1786 self.html += '<button id="showtest" class="logbtn">log</button>'
1787 if sv.addlogs and 'dmesg' not in suppress:
1788 self.html += '<button id="showdmesg" class="logbtn">dmesg</button>'
1789 if sv.addlogs and sv.ftracefile and 'ftrace' not in suppress:
1790 self.html += '<button id="showftrace" class="logbtn">ftrace</button>'
1791 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n'
1792 self.html += headline_stamp.format(sv.stamp['host'], sv.stamp['kernel'],
1793 sv.stamp['mode'], sv.stamp['time'])
1794 # Function: getDeviceRows
1795 # Description:
1796 # determine how may rows the device funcs will take
1797 # Arguments:
1798 # rawlist: the list of devices/actions for a single phase
1799 # Output:
1800 # The total number of rows needed to display this phase of the timeline
1801 def getDeviceRows(self, rawlist):
1802 # clear all rows and set them to undefined
1803 sortdict = dict()
1804 for item in rawlist:
1805 item.row = -1
1806 sortdict[item] = item.length
1807 sortlist = sorted(sortdict, key=sortdict.get, reverse=True)
1808 remaining = len(sortlist)
1809 rowdata = dict()
1810 row = 1
1811 # try to pack each row with as many ranges as possible
1812 while(remaining > 0):
1813 if(row not in rowdata):
1814 rowdata[row] = []
1815 for i in sortlist:
1816 if(i.row >= 0):
1817 continue
1818 s = i.time
1819 e = i.time + i.length
1820 valid = True
1821 for ritem in rowdata[row]:
1822 rs = ritem.time
1823 re = ritem.time + ritem.length
1824 if(not (((s <= rs) and (e <= rs)) or
1825 ((s >= re) and (e >= re)))):
1826 valid = False
1827 break
1828 if(valid):
1829 rowdata[row].append(i)
1830 i.row = row
1831 remaining -= 1
1832 row += 1
1833 return row
1834 # Function: getPhaseRows
1835 # Description:
1836 # Organize the timeline entries into the smallest
1837 # number of rows possible, with no entry overlapping
1838 # Arguments:
1839 # devlist: the list of devices/actions in a group of contiguous phases
1840 # Output:
1841 # The total number of rows needed to display this phase of the timeline
1842 def getPhaseRows(self, devlist, row=0):
1843 # clear all rows and set them to undefined
1844 remaining = len(devlist)
1845 rowdata = dict()
1846 sortdict = dict()
1847 myphases = []
1848 # initialize all device rows to -1 and calculate devrows
1849 for item in devlist:
1850 dev = item.dev
1851 tp = (item.test, item.phase)
1852 if tp not in myphases:
1853 myphases.append(tp)
1854 dev['row'] = -1
1855 # sort by length 1st, then name 2nd
1856 sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name'])
1857 if 'src' in dev:
1858 dev['devrows'] = self.getDeviceRows(dev['src'])
1859 # sort the devlist by length so that large items graph on top
1860 sortlist = sorted(sortdict, key=sortdict.get, reverse=True)
1861 orderedlist = []
1862 for item in sortlist:
1863 if item.dev['pid'] == -2:
1864 orderedlist.append(item)
1865 for item in sortlist:
1866 if item not in orderedlist:
1867 orderedlist.append(item)
1868 # try to pack each row with as many devices as possible
1869 while(remaining > 0):
1870 rowheight = 1
1871 if(row not in rowdata):
1872 rowdata[row] = []
1873 for item in orderedlist:
1874 dev = item.dev
1875 if(dev['row'] < 0):
1876 s = dev['start']
1877 e = dev['end']
1878 valid = True
1879 for ritem in rowdata[row]:
1880 rs = ritem.dev['start']
1881 re = ritem.dev['end']
1882 if(not (((s <= rs) and (e <= rs)) or
1883 ((s >= re) and (e >= re)))):
1884 valid = False
1885 break
1886 if(valid):
1887 rowdata[row].append(item)
1888 dev['row'] = row
1889 remaining -= 1
1890 if 'devrows' in dev and dev['devrows'] > rowheight:
1891 rowheight = dev['devrows']
1892 for t, p in myphases:
1893 if t not in self.rowlines or t not in self.rowheight:
1894 self.rowlines[t] = dict()
1895 self.rowheight[t] = dict()
1896 if p not in self.rowlines[t] or p not in self.rowheight[t]:
1897 self.rowlines[t][p] = dict()
1898 self.rowheight[t][p] = dict()
1899 rh = self.rowH
1900 # section headers should use a different row height
1901 if len(rowdata[row]) == 1 and \
1902 'htmlclass' in rowdata[row][0].dev and \
1903 'sec' in rowdata[row][0].dev['htmlclass']:
1904 rh = 15
1905 self.rowlines[t][p][row] = rowheight
1906 self.rowheight[t][p][row] = rowheight * rh
1907 row += 1
1908 if(row > self.rows):
1909 self.rows = int(row)
1910 return row
1911 def phaseRowHeight(self, test, phase, row):
1912 return self.rowheight[test][phase][row]
1913 def phaseRowTop(self, test, phase, row):
1914 top = 0
1915 for i in sorted(self.rowheight[test][phase]):
1916 if i >= row:
1917 break
1918 top += self.rowheight[test][phase][i]
1919 return top
1920 def calcTotalRows(self):
1921 # Calculate the heights and offsets for the header and rows
1922 maxrows = 0
1923 standardphases = []
1924 for t in self.rowlines:
1925 for p in self.rowlines[t]:
1926 total = 0
1927 for i in sorted(self.rowlines[t][p]):
1928 total += self.rowlines[t][p][i]
1929 if total > maxrows:
1930 maxrows = total
1931 if total == len(self.rowlines[t][p]):
1932 standardphases.append((t, p))
1933 self.height = self.scaleH + (maxrows*self.rowH)
1934 self.bodyH = self.height - self.scaleH
1935 # if there is 1 line per row, draw them the standard way
1936 for t, p in standardphases:
1937 for i in sorted(self.rowheight[t][p]):
1938 self.rowheight[t][p][i] = self.bodyH/len(self.rowlines[t][p])
1939 def createZoomBox(self, mode='command', testcount=1):
1940 # Create bounding box, add buttons
1941 html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n'
1942 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n'
1943 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail{0}</button>'
1944 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n'
1945 if mode != 'command':
1946 if testcount > 1:
1947 self.html += html_devlist2
1948 self.html += html_devlist1.format('1')
1949 else:
1950 self.html += html_devlist1.format('')
1951 self.html += html_zoombox
1952 self.html += html_timeline.format('dmesg', self.height)
1953 # Function: createTimeScale
1954 # Description:
1955 # Create the timescale for a timeline block
1956 # Arguments:
1957 # m0: start time (mode begin)
1958 # mMax: end time (mode end)
1959 # tTotal: total timeline time
1960 # mode: suspend or resume
1961 # Output:
1962 # The html code needed to display the time scale
1963 def createTimeScale(self, m0, mMax, tTotal, mode):
1964 timescale = '<div class="t" style="right:{0}%">{1}</div>\n'
1965 rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">{0}</div>\n'
1966 output = '<div class="timescale">\n'
1967 # set scale for timeline
1968 mTotal = mMax - m0
1969 tS = 0.1
1970 if(tTotal <= 0):
1971 return output+'</div>\n'
1972 if(tTotal > 4):
1973 tS = 1
1974 divTotal = int(mTotal/tS) + 1
1975 divEdge = (mTotal - tS*(divTotal-1))*100/mTotal
1976 for i in range(divTotal):
1977 htmlline = ''
1978 if(mode == 'suspend'):
1979 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge)
1980 val = '%0.fms' % (float(i-divTotal+1)*tS*1000)
1981 if(i == divTotal - 1):
1982 val = mode
1983 htmlline = timescale.format(pos, val)
1984 else:
1985 pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal))
1986 val = '%0.fms' % (float(i)*tS*1000)
1987 htmlline = timescale.format(pos, val)
1988 if(i == 0):
1989 htmlline = rline.format(mode)
1990 output += htmlline
1991 self.html += output+'</div>\n'
1992
1993# Class: TestProps
1994# Description:
1995# A list of values describing the properties of these test runs
1996class TestProps:
1997 stamp = ''
1998 S0i3 = False
1999 fwdata = []
2000 ftrace_line_fmt_fg = \
2001 '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\
2002 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\
2003 '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)'
2004 ftrace_line_fmt_nop = \
2005 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\
2006 '(?P<flags>.{4}) *(?P<time>[0-9\.]*): *'+\
2007 '(?P<msg>.*)'
2008 ftrace_line_fmt = ftrace_line_fmt_nop
2009 cgformat = False
2010 data = 0
2011 ktemp = dict()
2012 def __init__(self):
2013 self.ktemp = dict()
2014 def setTracerType(self, tracer):
2015 if(tracer == 'function_graph'):
2016 self.cgformat = True
2017 self.ftrace_line_fmt = self.ftrace_line_fmt_fg
2018 elif(tracer == 'nop'):
2019 self.ftrace_line_fmt = self.ftrace_line_fmt_nop
2020 else:
2021 doError('Invalid tracer format: [%s]' % tracer)
2022
2023# Class: TestRun
2024# Description:
2025# A container for a suspend/resume test run. This is necessary as
2026# there could be more than one, and they need to be separate.
2027class TestRun:
2028 ftemp = dict()
2029 ttemp = dict()
2030 data = 0
2031 def __init__(self, dataobj):
2032 self.data = dataobj
2033 self.ftemp = dict()
2034 self.ttemp = dict()
2035
2036class ProcessMonitor:
2037 proclist = dict()
2038 running = False
2039 def procstat(self):
2040 c = ['cat /proc/[1-9]*/stat 2>/dev/null']
2041 process = Popen(c, shell=True, stdout=PIPE)
2042 running = dict()
2043 for line in process.stdout:
2044 data = line.split()
2045 pid = data[0]
2046 name = re.sub('[()]', '', data[1])
2047 user = int(data[13])
2048 kern = int(data[14])
2049 kjiff = ujiff = 0
2050 if pid not in self.proclist:
2051 self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern}
2052 else:
2053 val = self.proclist[pid]
2054 ujiff = user - val['user']
2055 kjiff = kern - val['kern']
2056 val['user'] = user
2057 val['kern'] = kern
2058 if ujiff > 0 or kjiff > 0:
2059 running[pid] = ujiff + kjiff
2060 process.wait()
2061 out = ''
2062 for pid in running:
2063 jiffies = running[pid]
2064 val = self.proclist[pid]
2065 if out:
2066 out += ','
2067 out += '%s-%s %d' % (val['name'], pid, jiffies)
2068 return 'ps - '+out
2069 def processMonitor(self, tid):
2070 while self.running:
2071 out = self.procstat()
2072 if out:
2073 sysvals.fsetVal(out, 'trace_marker')
2074 def start(self):
2075 self.thread = Thread(target=self.processMonitor, args=(0,))
2076 self.running = True
2077 self.thread.start()
2078 def stop(self):
2079 self.running = False
2080
2081# ----------------- FUNCTIONS --------------------
2082
2083# Function: vprint
2084# Description:
2085# verbose print (prints only with -verbose option)
2086# Arguments:
2087# msg: the debug/log message to print
2088def vprint(msg):
2089 sysvals.logmsg += msg+'\n'
2090 if(sysvals.verbose):
2091 print(msg)
2092
2093# Function: parseStamp
2094# Description:
2095# Pull in the stamp comment line from the data file(s),
2096# create the stamp, and add it to the global sysvals object
2097# Arguments:
2098# m: the valid re.match output for the stamp line
2099def parseStamp(line, data):
2100 m = re.match(sysvals.stampfmt, line)
2101 data.stamp = {'time': '', 'host': '', 'mode': ''}
2102 dt = datetime(int(m.group('y'))+2000, int(m.group('m')),
2103 int(m.group('d')), int(m.group('H')), int(m.group('M')),
2104 int(m.group('S')))
2105 data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p')
2106 data.stamp['host'] = m.group('host')
2107 data.stamp['mode'] = m.group('mode')
2108 data.stamp['kernel'] = m.group('kernel')
2109 sysvals.hostname = data.stamp['host']
2110 sysvals.suspendmode = data.stamp['mode']
2111 if sysvals.suspendmode == 'command' and sysvals.ftracefile != '':
2112 modes = ['on', 'freeze', 'standby', 'mem']
2113 out = Popen(['grep', 'suspend_enter', sysvals.ftracefile],
2114 stderr=PIPE, stdout=PIPE).stdout.read()
2115 m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out)
2116 if m and m.group('mode') in ['1', '2', '3']:
2117 sysvals.suspendmode = modes[int(m.group('mode'))]
2118 data.stamp['mode'] = sysvals.suspendmode
2119 if not sysvals.stamp:
2120 sysvals.stamp = data.stamp
2121
2122# Function: doesTraceLogHaveTraceEvents
2123# Description:
2124# Quickly determine if the ftrace log has some or all of the trace events
2125# required for primary parsing. Set the usetraceevents and/or
2126# usetraceeventsonly flags in the global sysvals object
2127def doesTraceLogHaveTraceEvents():
2128 # check for kprobes
2129 sysvals.usekprobes = False
2130 out = call('grep -q "_cal: (" '+sysvals.ftracefile, shell=True)
2131 if(out == 0):
2132 sysvals.usekprobes = True
2133 # check for callgraph data on trace event blocks
2134 out = call('grep -q "_cpu_down()" '+sysvals.ftracefile, shell=True)
2135 if(out == 0):
2136 sysvals.usekprobes = True
2137 out = Popen(['head', '-1', sysvals.ftracefile],
2138 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
2139 m = re.match(sysvals.stampfmt, out)
2140 if m and m.group('mode') == 'command':
2141 sysvals.usetraceeventsonly = True
2142 sysvals.usetraceevents = True
2143 return
2144 # figure out what level of trace events are supported
2145 sysvals.usetraceeventsonly = True
2146 sysvals.usetraceevents = False
2147 for e in sysvals.traceevents:
2148 out = call('grep -q "'+e+': " '+sysvals.ftracefile, shell=True)
2149 if(out != 0):
2150 sysvals.usetraceeventsonly = False
2151 if(e == 'suspend_resume' and out == 0):
2152 sysvals.usetraceevents = True
2153 # determine is this log is properly formatted
2154 for e in ['SUSPEND START', 'RESUME COMPLETE']:
2155 out = call('grep -q "'+e+'" '+sysvals.ftracefile, shell=True)
2156 if(out != 0):
2157 sysvals.usetracemarkers = False
2158
2159# Function: appendIncompleteTraceLog
2160# Description:
2161# [deprecated for kernel 3.15 or newer]
2162# Legacy support of ftrace outputs that lack the device_pm_callback
2163# and/or suspend_resume trace events. The primary data should be
2164# taken from dmesg, and this ftrace is used only for callgraph data
2165# or custom actions in the timeline. The data is appended to the Data
2166# objects provided.
2167# Arguments:
2168# testruns: the array of Data objects obtained from parseKernelLog
2169def appendIncompleteTraceLog(testruns):
2170 # create TestRun vessels for ftrace parsing
2171 testcnt = len(testruns)
2172 testidx = 0
2173 testrun = []
2174 for data in testruns:
2175 testrun.append(TestRun(data))
2176
2177 # extract the callgraph and traceevent data
2178 vprint('Analyzing the ftrace data...')
2179 tp = TestProps()
2180 tf = open(sysvals.ftracefile, 'r')
2181 data = 0
2182 for line in tf:
2183 # remove any latent carriage returns
2184 line = line.replace('\r\n', '')
2185 # grab the time stamp
2186 m = re.match(sysvals.stampfmt, line)
2187 if(m):
2188 tp.stamp = line
2189 continue
2190 # determine the trace data type (required for further parsing)
2191 m = re.match(sysvals.tracertypefmt, line)
2192 if(m):
2193 tp.setTracerType(m.group('t'))
2194 continue
2195 # device properties line
2196 if(re.match(sysvals.devpropfmt, line)):
2197 devProps(line)
2198 continue
2199 # parse only valid lines, if this is not one move on
2200 m = re.match(tp.ftrace_line_fmt, line)
2201 if(not m):
2202 continue
2203 # gather the basic message data from the line
2204 m_time = m.group('time')
2205 m_pid = m.group('pid')
2206 m_msg = m.group('msg')
2207 if(tp.cgformat):
2208 m_param3 = m.group('dur')
2209 else:
2210 m_param3 = 'traceevent'
2211 if(m_time and m_pid and m_msg):
2212 t = FTraceLine(m_time, m_msg, m_param3)
2213 pid = int(m_pid)
2214 else:
2215 continue
2216 # the line should be a call, return, or event
2217 if(not t.fcall and not t.freturn and not t.fevent):
2218 continue
2219 # look for the suspend start marker
2220 if(t.startMarker()):
2221 data = testrun[testidx].data
2222 parseStamp(tp.stamp, data)
2223 data.setStart(t.time)
2224 continue
2225 if(not data):
2226 continue
2227 # find the end of resume
2228 if(t.endMarker()):
2229 data.setEnd(t.time)
2230 testidx += 1
2231 if(testidx >= testcnt):
2232 break
2233 continue
2234 # trace event processing
2235 if(t.fevent):
2236 # general trace events have two types, begin and end
2237 if(re.match('(?P<name>.*) begin$', t.name)):
2238 isbegin = True
2239 elif(re.match('(?P<name>.*) end$', t.name)):
2240 isbegin = False
2241 else:
2242 continue
2243 m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name)
2244 if(m):
2245 val = m.group('val')
2246 if val == '0':
2247 name = m.group('name')
2248 else:
2249 name = m.group('name')+'['+val+']'
2250 else:
2251 m = re.match('(?P<name>.*) .*', t.name)
2252 name = m.group('name')
2253 # special processing for trace events
2254 if re.match('dpm_prepare\[.*', name):
2255 continue
2256 elif re.match('machine_suspend.*', name):
2257 continue
2258 elif re.match('suspend_enter\[.*', name):
2259 if(not isbegin):
2260 data.dmesg['suspend_prepare']['end'] = t.time
2261 continue
2262 elif re.match('dpm_suspend\[.*', name):
2263 if(not isbegin):
2264 data.dmesg['suspend']['end'] = t.time
2265 continue
2266 elif re.match('dpm_suspend_late\[.*', name):
2267 if(isbegin):
2268 data.dmesg['suspend_late']['start'] = t.time
2269 else:
2270 data.dmesg['suspend_late']['end'] = t.time
2271 continue
2272 elif re.match('dpm_suspend_noirq\[.*', name):
2273 if(isbegin):
2274 data.dmesg['suspend_noirq']['start'] = t.time
2275 else:
2276 data.dmesg['suspend_noirq']['end'] = t.time
2277 continue
2278 elif re.match('dpm_resume_noirq\[.*', name):
2279 if(isbegin):
2280 data.dmesg['resume_machine']['end'] = t.time
2281 data.dmesg['resume_noirq']['start'] = t.time
2282 else:
2283 data.dmesg['resume_noirq']['end'] = t.time
2284 continue
2285 elif re.match('dpm_resume_early\[.*', name):
2286 if(isbegin):
2287 data.dmesg['resume_early']['start'] = t.time
2288 else:
2289 data.dmesg['resume_early']['end'] = t.time
2290 continue
2291 elif re.match('dpm_resume\[.*', name):
2292 if(isbegin):
2293 data.dmesg['resume']['start'] = t.time
2294 else:
2295 data.dmesg['resume']['end'] = t.time
2296 continue
2297 elif re.match('dpm_complete\[.*', name):
2298 if(isbegin):
2299 data.dmesg['resume_complete']['start'] = t.time
2300 else:
2301 data.dmesg['resume_complete']['end'] = t.time
2302 continue
2303 # skip trace events inside devices calls
2304 if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)):
2305 continue
2306 # global events (outside device calls) are simply graphed
2307 if(isbegin):
2308 # store each trace event in ttemp
2309 if(name not in testrun[testidx].ttemp):
2310 testrun[testidx].ttemp[name] = []
2311 testrun[testidx].ttemp[name].append(\
2312 {'begin': t.time, 'end': t.time})
2313 else:
2314 # finish off matching trace event in ttemp
2315 if(name in testrun[testidx].ttemp):
2316 testrun[testidx].ttemp[name][-1]['end'] = t.time
2317 # call/return processing
2318 elif sysvals.usecallgraph:
2319 # create a callgraph object for the data
2320 if(pid not in testrun[testidx].ftemp):
2321 testrun[testidx].ftemp[pid] = []
2322 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid))
2323 # when the call is finished, see which device matches it
2324 cg = testrun[testidx].ftemp[pid][-1]
2325 if(cg.addLine(t)):
2326 testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid))
2327 tf.close()
2328
2329 for test in testrun:
2330 # add the traceevent data to the device hierarchy
2331 if(sysvals.usetraceevents):
2332 for name in test.ttemp:
2333 for event in test.ttemp[name]:
2334 test.data.newActionGlobal(name, event['begin'], event['end'])
2335
2336 # add the callgraph data to the device hierarchy
2337 for pid in test.ftemp:
2338 for cg in test.ftemp[pid]:
2339 if len(cg.list) < 1 or cg.invalid:
2340 continue
2341 if(not cg.postProcess()):
2342 id = 'task %s cpu %s' % (pid, m.group('cpu'))
2343 vprint('Sanity check failed for '+\
2344 id+', ignoring this callback')
2345 continue
2346 callstart = cg.start
2347 callend = cg.end
2348 for p in test.data.phases:
2349 if(test.data.dmesg[p]['start'] <= callstart and
2350 callstart <= test.data.dmesg[p]['end']):
2351 list = test.data.dmesg[p]['list']
2352 for devname in list:
2353 dev = list[devname]
2354 if(pid == dev['pid'] and
2355 callstart <= dev['start'] and
2356 callend >= dev['end']):
2357 dev['ftrace'] = cg
2358 break
2359
2360 test.data.printDetails()
2361
2362# Function: parseTraceLog
2363# Description:
2364# Analyze an ftrace log output file generated from this app during
2365# the execution phase. Used when the ftrace log is the primary data source
2366# and includes the suspend_resume and device_pm_callback trace events
2367# The ftrace filename is taken from sysvals
2368# Output:
2369# An array of Data objects
2370def parseTraceLog():
2371 vprint('Analyzing the ftrace data...')
2372 if(os.path.exists(sysvals.ftracefile) == False):
2373 doError('%s does not exist' % sysvals.ftracefile)
2374
2375 sysvals.setupAllKprobes()
2376 tracewatch = []
2377 if sysvals.usekprobes:
2378 tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',
2379 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF']
2380
2381 # extract the callgraph and traceevent data
2382 tp = TestProps()
2383 testruns = []
2384 testdata = []
2385 testrun = 0
2386 data = 0
2387 tf = open(sysvals.ftracefile, 'r')
2388 phase = 'suspend_prepare'
2389 for line in tf:
2390 # remove any latent carriage returns
2391 line = line.replace('\r\n', '')
2392 # stamp line: each stamp means a new test run
2393 m = re.match(sysvals.stampfmt, line)
2394 if(m):
2395 tp.stamp = line
2396 continue
2397 # firmware line: pull out any firmware data
2398 m = re.match(sysvals.firmwarefmt, line)
2399 if(m):
2400 tp.fwdata.append((int(m.group('s')), int(m.group('r'))))
2401 continue
2402 # tracer type line: determine the trace data type
2403 m = re.match(sysvals.tracertypefmt, line)
2404 if(m):
2405 tp.setTracerType(m.group('t'))
2406 continue
2407 # device properties line
2408 if(re.match(sysvals.devpropfmt, line)):
2409 devProps(line)
2410 continue
2411 # ignore all other commented lines
2412 if line[0] == '#':
2413 continue
2414 # ftrace line: parse only valid lines
2415 m = re.match(tp.ftrace_line_fmt, line)
2416 if(not m):
2417 continue
2418 # gather the basic message data from the line
2419 m_time = m.group('time')
2420 m_proc = m.group('proc')
2421 m_pid = m.group('pid')
2422 m_msg = m.group('msg')
2423 if(tp.cgformat):
2424 m_param3 = m.group('dur')
2425 else:
2426 m_param3 = 'traceevent'
2427 if(m_time and m_pid and m_msg):
2428 t = FTraceLine(m_time, m_msg, m_param3)
2429 pid = int(m_pid)
2430 else:
2431 continue
2432 # the line should be a call, return, or event
2433 if(not t.fcall and not t.freturn and not t.fevent):
2434 continue
2435 # find the start of suspend
2436 if(t.startMarker()):
2437 phase = 'suspend_prepare'
2438 data = Data(len(testdata))
2439 testdata.append(data)
2440 testrun = TestRun(data)
2441 testruns.append(testrun)
2442 parseStamp(tp.stamp, data)
2443 data.setStart(t.time)
2444 data.tKernSus = t.time
2445 continue
2446 if(not data):
2447 continue
2448 # process cpu exec line
2449 if t.type == 'tracing_mark_write':
2450 m = re.match(sysvals.procexecfmt, t.name)
2451 if(m):
2452 proclist = dict()
2453 for ps in m.group('ps').split(','):
2454 val = ps.split()
2455 if not val:
2456 continue
2457 name = val[0].replace('--', '-')
2458 proclist[name] = int(val[1])
2459 data.pstl[t.time] = proclist
2460 continue
2461 # find the end of resume
2462 if(t.endMarker()):
2463 data.setEnd(t.time)
2464 if data.tKernRes == 0.0:
2465 data.tKernRes = t.time
2466 if data.dmesg['resume_complete']['end'] < 0:
2467 data.dmesg['resume_complete']['end'] = t.time
2468 if sysvals.suspendmode == 'mem' and len(tp.fwdata) > data.testnumber:
2469 data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
2470 if(data.tSuspended != 0 and data.tResumed != 0 and \
2471 (data.fwSuspend > 0 or data.fwResume > 0)):
2472 data.fwValid = True
2473 if(not sysvals.usetracemarkers):
2474 # no trace markers? then quit and be sure to finish recording
2475 # the event we used to trigger resume end
2476 if(len(testrun.ttemp['thaw_processes']) > 0):
2477 # if an entry exists, assume this is its end
2478 testrun.ttemp['thaw_processes'][-1]['end'] = t.time
2479 break
2480 continue
2481 # trace event processing
2482 if(t.fevent):
2483 if(phase == 'post_resume'):
2484 data.setEnd(t.time)
2485 if(t.type == 'suspend_resume'):
2486 # suspend_resume trace events have two types, begin and end
2487 if(re.match('(?P<name>.*) begin$', t.name)):
2488 isbegin = True
2489 elif(re.match('(?P<name>.*) end$', t.name)):
2490 isbegin = False
2491 else:
2492 continue
2493 m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name)
2494 if(m):
2495 val = m.group('val')
2496 if val == '0':
2497 name = m.group('name')
2498 else:
2499 name = m.group('name')+'['+val+']'
2500 else:
2501 m = re.match('(?P<name>.*) .*', t.name)
2502 name = m.group('name')
2503 # ignore these events
2504 if(name.split('[')[0] in tracewatch):
2505 continue
2506 # -- phase changes --
2507 # start of kernel suspend
2508 if(re.match('suspend_enter\[.*', t.name)):
2509 if(isbegin):
2510 data.dmesg[phase]['start'] = t.time
2511 data.tKernSus = t.time
2512 continue
2513 # suspend_prepare start
2514 elif(re.match('dpm_prepare\[.*', t.name)):
2515 phase = 'suspend_prepare'
2516 if(not isbegin):
2517 data.dmesg[phase]['end'] = t.time
2518 continue
2519 # suspend start
2520 elif(re.match('dpm_suspend\[.*', t.name)):
2521 phase = 'suspend'
2522 data.setPhase(phase, t.time, isbegin)
2523 continue
2524 # suspend_late start
2525 elif(re.match('dpm_suspend_late\[.*', t.name)):
2526 phase = 'suspend_late'
2527 data.setPhase(phase, t.time, isbegin)
2528 continue
2529 # suspend_noirq start
2530 elif(re.match('dpm_suspend_noirq\[.*', t.name)):
2531 phase = 'suspend_noirq'
2532 data.setPhase(phase, t.time, isbegin)
2533 if(not isbegin):
2534 phase = 'suspend_machine'
2535 data.dmesg[phase]['start'] = t.time
2536 continue
2537 # suspend_machine/resume_machine
2538 elif(re.match('machine_suspend\[.*', t.name)):
2539 if(isbegin):
2540 phase = 'suspend_machine'
2541 data.dmesg[phase]['end'] = t.time
2542 data.tSuspended = t.time
2543 else:
2544 if(sysvals.suspendmode in ['mem', 'disk'] and not tp.S0i3):
2545 data.dmesg['suspend_machine']['end'] = t.time
2546 data.tSuspended = t.time
2547 phase = 'resume_machine'
2548 data.dmesg[phase]['start'] = t.time
2549 data.tResumed = t.time
2550 data.tLow = data.tResumed - data.tSuspended
2551 continue
2552 # acpi_suspend
2553 elif(re.match('acpi_suspend\[.*', t.name)):
2554 # acpi_suspend[0] S0i3
2555 if(re.match('acpi_suspend\[0\] begin', t.name)):
2556 if(sysvals.suspendmode == 'mem'):
2557 tp.S0i3 = True
2558 data.dmesg['suspend_machine']['end'] = t.time
2559 data.tSuspended = t.time
2560 continue
2561 # resume_noirq start
2562 elif(re.match('dpm_resume_noirq\[.*', t.name)):
2563 phase = 'resume_noirq'
2564 data.setPhase(phase, t.time, isbegin)
2565 if(isbegin):
2566 data.dmesg['resume_machine']['end'] = t.time
2567 continue
2568 # resume_early start
2569 elif(re.match('dpm_resume_early\[.*', t.name)):
2570 phase = 'resume_early'
2571 data.setPhase(phase, t.time, isbegin)
2572 continue
2573 # resume start
2574 elif(re.match('dpm_resume\[.*', t.name)):
2575 phase = 'resume'
2576 data.setPhase(phase, t.time, isbegin)
2577 continue
2578 # resume complete start
2579 elif(re.match('dpm_complete\[.*', t.name)):
2580 phase = 'resume_complete'
2581 if(isbegin):
2582 data.dmesg[phase]['start'] = t.time
2583 continue
2584 # skip trace events inside devices calls
2585 if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)):
2586 continue
2587 # global events (outside device calls) are graphed
2588 if(name not in testrun.ttemp):
2589 testrun.ttemp[name] = []
2590 if(isbegin):
2591 # create a new list entry
2592 testrun.ttemp[name].append(\
2593 {'begin': t.time, 'end': t.time, 'pid': pid})
2594 else:
2595 if(len(testrun.ttemp[name]) > 0):
2596 # if an entry exists, assume this is its end
2597 testrun.ttemp[name][-1]['end'] = t.time
2598 elif(phase == 'post_resume'):
2599 # post resume events can just have ends
2600 testrun.ttemp[name].append({
2601 'begin': data.dmesg[phase]['start'],
2602 'end': t.time})
2603 # device callback start
2604 elif(t.type == 'device_pm_callback_start'):
2605 m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\
2606 t.name);
2607 if(not m):
2608 continue
2609 drv = m.group('drv')
2610 n = m.group('d')
2611 p = m.group('p')
2612 if(n and p):
2613 data.newAction(phase, n, pid, p, t.time, -1, drv)
2614 if pid not in data.devpids:
2615 data.devpids.append(pid)
2616 # device callback finish
2617 elif(t.type == 'device_pm_callback_end'):
2618 m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name);
2619 if(not m):
2620 continue
2621 n = m.group('d')
2622 list = data.dmesg[phase]['list']
2623 if(n in list):
2624 dev = list[n]
2625 dev['length'] = t.time - dev['start']
2626 dev['end'] = t.time
2627 # kprobe event processing
2628 elif(t.fkprobe):
2629 kprobename = t.type
2630 kprobedata = t.name
2631 key = (kprobename, pid)
2632 # displayname is generated from kprobe data
2633 displayname = ''
2634 if(t.fcall):
2635 displayname = sysvals.kprobeDisplayName(kprobename, kprobedata)
2636 if not displayname:
2637 continue
2638 if(key not in tp.ktemp):
2639 tp.ktemp[key] = []
2640 tp.ktemp[key].append({
2641 'pid': pid,
2642 'begin': t.time,
2643 'end': t.time,
2644 'name': displayname,
2645 'cdata': kprobedata,
2646 'proc': m_proc,
2647 })
2648 elif(t.freturn):
2649 if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1:
2650 continue
2651 e = tp.ktemp[key][-1]
2652 if e['begin'] < 0.0 or t.time - e['begin'] < 0.000001:
2653 tp.ktemp[key].pop()
2654 else:
2655 e['end'] = t.time
2656 e['rdata'] = kprobedata
2657 # end of kernel resume
2658 if(kprobename == 'pm_notifier_call_chain' or \
2659 kprobename == 'pm_restore_console'):
2660 data.dmesg[phase]['end'] = t.time
2661 data.tKernRes = t.time
2662
2663 # callgraph processing
2664 elif sysvals.usecallgraph:
2665 # create a callgraph object for the data
2666 key = (m_proc, pid)
2667 if(key not in testrun.ftemp):
2668 testrun.ftemp[key] = []
2669 testrun.ftemp[key].append(FTraceCallGraph(pid))
2670 # when the call is finished, see which device matches it
2671 cg = testrun.ftemp[key][-1]
2672 if(cg.addLine(t)):
2673 testrun.ftemp[key].append(FTraceCallGraph(pid))
2674 tf.close()
2675
2676 if sysvals.suspendmode == 'command':
2677 for test in testruns:
2678 for p in test.data.phases:
2679 if p == 'suspend_prepare':
2680 test.data.dmesg[p]['start'] = test.data.start
2681 test.data.dmesg[p]['end'] = test.data.end
2682 else:
2683 test.data.dmesg[p]['start'] = test.data.end
2684 test.data.dmesg[p]['end'] = test.data.end
2685 test.data.tSuspended = test.data.end
2686 test.data.tResumed = test.data.end
2687 test.data.tLow = 0
2688 test.data.fwValid = False
2689
2690 # dev source and procmon events can be unreadable with mixed phase height
2691 if sysvals.usedevsrc or sysvals.useprocmon:
2692 sysvals.mixedphaseheight = False
2693
2694 for i in range(len(testruns)):
2695 test = testruns[i]
2696 data = test.data
2697 # find the total time range for this test (begin, end)
2698 tlb, tle = data.start, data.end
2699 if i < len(testruns) - 1:
2700 tle = testruns[i+1].data.start
2701 # add the process usage data to the timeline
2702 if sysvals.useprocmon:
2703 data.createProcessUsageEvents()
2704 # add the traceevent data to the device hierarchy
2705 if(sysvals.usetraceevents):
2706 # add actual trace funcs
2707 for name in test.ttemp:
2708 for event in test.ttemp[name]:
2709 data.newActionGlobal(name, event['begin'], event['end'], event['pid'])
2710 # add the kprobe based virtual tracefuncs as actual devices
2711 for key in tp.ktemp:
2712 name, pid = key
2713 if name not in sysvals.tracefuncs:
2714 continue
2715 for e in tp.ktemp[key]:
2716 kb, ke = e['begin'], e['end']
2717 if kb == ke or tlb > kb or tle <= kb:
2718 continue
2719 color = sysvals.kprobeColor(name)
2720 data.newActionGlobal(e['name'], kb, ke, pid, color)
2721 # add config base kprobes and dev kprobes
2722 if sysvals.usedevsrc:
2723 for key in tp.ktemp:
2724 name, pid = key
2725 if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs:
2726 continue
2727 for e in tp.ktemp[key]:
2728 kb, ke = e['begin'], e['end']
2729 if kb == ke or tlb > kb or tle <= kb:
2730 continue
2731 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb,
2732 ke, e['cdata'], e['rdata'])
2733 if sysvals.usecallgraph:
2734 # add the callgraph data to the device hierarchy
2735 sortlist = dict()
2736 for key in test.ftemp:
2737 proc, pid = key
2738 for cg in test.ftemp[key]:
2739 if len(cg.list) < 1 or cg.invalid:
2740 continue
2741 if(not cg.postProcess()):
2742 id = 'task %s' % (pid)
2743 vprint('Sanity check failed for '+\
2744 id+', ignoring this callback')
2745 continue
2746 # match cg data to devices
2747 if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, data):
2748 sortkey = '%f%f%d' % (cg.start, cg.end, pid)
2749 sortlist[sortkey] = cg
2750 # create blocks for orphan cg data
2751 for sortkey in sorted(sortlist):
2752 cg = sortlist[sortkey]
2753 name = cg.name
2754 if sysvals.isCallgraphFunc(name):
2755 vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name))
2756 cg.newActionFromFunction(data)
2757
2758 if sysvals.suspendmode == 'command':
2759 for data in testdata:
2760 data.printDetails()
2761 return testdata
2762
2763 # fill in any missing phases
2764 for data in testdata:
2765 lp = data.phases[0]
2766 for p in data.phases:
2767 if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0):
2768 vprint('WARNING: phase "%s" is missing!' % p)
2769 if(data.dmesg[p]['start'] < 0):
2770 data.dmesg[p]['start'] = data.dmesg[lp]['end']
2771 if(p == 'resume_machine'):
2772 data.tSuspended = data.dmesg[lp]['end']
2773 data.tResumed = data.dmesg[lp]['end']
2774 data.tLow = 0
2775 if(data.dmesg[p]['end'] < 0):
2776 data.dmesg[p]['end'] = data.dmesg[p]['start']
2777 if(p != lp and not ('machine' in p and 'machine' in lp)):
2778 data.dmesg[lp]['end'] = data.dmesg[p]['start']
2779 lp = p
2780
2781 if(len(sysvals.devicefilter) > 0):
2782 data.deviceFilter(sysvals.devicefilter)
2783 data.fixupInitcallsThatDidntReturn()
2784 if sysvals.usedevsrc:
2785 data.optimizeDevSrc()
2786 data.printDetails()
2787
2788 # x2: merge any overlapping devices between test runs
2789 if sysvals.usedevsrc and len(testdata) > 1:
2790 tc = len(testdata)
2791 for i in range(tc - 1):
2792 devlist = testdata[i].overflowDevices()
2793 for j in range(i + 1, tc):
2794 testdata[j].mergeOverlapDevices(devlist)
2795 testdata[0].stitchTouchingThreads(testdata[1:])
2796 return testdata
2797
2798# Function: loadKernelLog
2799# Description:
2800# [deprecated for kernel 3.15.0 or newer]
2801# load the dmesg file into memory and fix up any ordering issues
2802# The dmesg filename is taken from sysvals
2803# Output:
2804# An array of empty Data objects with only their dmesgtext attributes set
2805def loadKernelLog(justtext=False):
2806 vprint('Analyzing the dmesg data...')
2807 if(os.path.exists(sysvals.dmesgfile) == False):
2808 doError('%s does not exist' % sysvals.dmesgfile)
2809
2810 if justtext:
2811 dmesgtext = []
2812 # there can be multiple test runs in a single file
2813 tp = TestProps()
2814 tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown')
2815 testruns = []
2816 data = 0
2817 lf = open(sysvals.dmesgfile, 'r')
2818 for line in lf:
2819 line = line.replace('\r\n', '')
2820 idx = line.find('[')
2821 if idx > 1:
2822 line = line[idx:]
2823 m = re.match(sysvals.stampfmt, line)
2824 if(m):
2825 tp.stamp = line
2826 continue
2827 m = re.match(sysvals.firmwarefmt, line)
2828 if(m):
2829 tp.fwdata.append((int(m.group('s')), int(m.group('r'))))
2830 continue
2831 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
2832 if(not m):
2833 continue
2834 msg = m.group("msg")
2835 if justtext:
2836 dmesgtext.append(line)
2837 continue
2838 if(re.match('PM: Syncing filesystems.*', msg)):
2839 if(data):
2840 testruns.append(data)
2841 data = Data(len(testruns))
2842 parseStamp(tp.stamp, data)
2843 if len(tp.fwdata) > data.testnumber:
2844 data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
2845 if(data.fwSuspend > 0 or data.fwResume > 0):
2846 data.fwValid = True
2847 if(not data):
2848 continue
2849 m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg)
2850 if(m):
2851 sysvals.stamp['kernel'] = m.group('k')
2852 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
2853 if(m):
2854 sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m')
2855 data.dmesgtext.append(line)
2856 lf.close()
2857
2858 if justtext:
2859 return dmesgtext
2860 if data:
2861 testruns.append(data)
2862 if len(testruns) < 1:
2863 doError(' dmesg log has no suspend/resume data: %s' \
2864 % sysvals.dmesgfile)
2865
2866 # fix lines with same timestamp/function with the call and return swapped
2867 for data in testruns:
2868 last = ''
2869 for line in data.dmesgtext:
2870 mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\
2871 '(?P<f>.*)\+ @ .*, parent: .*', line)
2872 mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\
2873 '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last)
2874 if(mc and mr and (mc.group('t') == mr.group('t')) and
2875 (mc.group('f') == mr.group('f'))):
2876 i = data.dmesgtext.index(last)
2877 j = data.dmesgtext.index(line)
2878 data.dmesgtext[i] = line
2879 data.dmesgtext[j] = last
2880 last = line
2881 return testruns
2882
2883# Function: parseKernelLog
2884# Description:
2885# [deprecated for kernel 3.15.0 or newer]
2886# Analyse a dmesg log output file generated from this app during
2887# the execution phase. Create a set of device structures in memory
2888# for subsequent formatting in the html output file
2889# This call is only for legacy support on kernels where the ftrace
2890# data lacks the suspend_resume or device_pm_callbacks trace events.
2891# Arguments:
2892# data: an empty Data object (with dmesgtext) obtained from loadKernelLog
2893# Output:
2894# The filled Data object
2895def parseKernelLog(data):
2896 phase = 'suspend_runtime'
2897
2898 if(data.fwValid):
2899 vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \
2900 (data.fwSuspend, data.fwResume))
2901
2902 # dmesg phase match table
2903 dm = {
2904 'suspend_prepare': 'PM: Syncing filesystems.*',
2905 'suspend': 'PM: Entering [a-z]* sleep.*',
2906 'suspend_late': 'PM: suspend of devices complete after.*',
2907 'suspend_noirq': 'PM: late suspend of devices complete after.*',
2908 'suspend_machine': 'PM: noirq suspend of devices complete after.*',
2909 'resume_machine': 'ACPI: Low-level resume complete.*',
2910 'resume_noirq': 'ACPI: Waking up from system sleep state.*',
2911 'resume_early': 'PM: noirq resume of devices complete after.*',
2912 'resume': 'PM: early resume of devices complete after.*',
2913 'resume_complete': 'PM: resume of devices complete after.*',
2914 'post_resume': '.*Restarting tasks \.\.\..*',
2915 }
2916 if(sysvals.suspendmode == 'standby'):
2917 dm['resume_machine'] = 'PM: Restoring platform NVS memory'
2918 elif(sysvals.suspendmode == 'disk'):
2919 dm['suspend_late'] = 'PM: freeze of devices complete after.*'
2920 dm['suspend_noirq'] = 'PM: late freeze of devices complete after.*'
2921 dm['suspend_machine'] = 'PM: noirq freeze of devices complete after.*'
2922 dm['resume_machine'] = 'PM: Restoring platform NVS memory'
2923 dm['resume_early'] = 'PM: noirq restore of devices complete after.*'
2924 dm['resume'] = 'PM: early restore of devices complete after.*'
2925 dm['resume_complete'] = 'PM: restore of devices complete after.*'
2926 elif(sysvals.suspendmode == 'freeze'):
2927 dm['resume_machine'] = 'ACPI: resume from mwait'
2928
2929 # action table (expected events that occur and show up in dmesg)
2930 at = {
2931 'sync_filesystems': {
2932 'smsg': 'PM: Syncing filesystems.*',
2933 'emsg': 'PM: Preparing system for mem sleep.*' },
2934 'freeze_user_processes': {
2935 'smsg': 'Freezing user space processes .*',
2936 'emsg': 'Freezing remaining freezable tasks.*' },
2937 'freeze_tasks': {
2938 'smsg': 'Freezing remaining freezable tasks.*',
2939 'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' },
2940 'ACPI prepare': {
2941 'smsg': 'ACPI: Preparing to enter system sleep state.*',
2942 'emsg': 'PM: Saving platform NVS memory.*' },
2943 'PM vns': {
2944 'smsg': 'PM: Saving platform NVS memory.*',
2945 'emsg': 'Disabling non-boot CPUs .*' },
2946 }
2947
2948 t0 = -1.0
2949 cpu_start = -1.0
2950 prevktime = -1.0
2951 actions = dict()
2952 for line in data.dmesgtext:
2953 # parse each dmesg line into the time and message
2954 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
2955 if(m):
2956 val = m.group('ktime')
2957 try:
2958 ktime = float(val)
2959 except:
2960 continue
2961 msg = m.group('msg')
2962 # initialize data start to first line time
2963 if t0 < 0:
2964 data.setStart(ktime)
2965 t0 = ktime
2966 else:
2967 continue
2968
2969 # hack for determining resume_machine end for freeze
2970 if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \
2971 and phase == 'resume_machine' and \
2972 re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)):
2973 data.dmesg['resume_machine']['end'] = ktime
2974 phase = 'resume_noirq'
2975 data.dmesg[phase]['start'] = ktime
2976
2977 # suspend start
2978 if(re.match(dm['suspend_prepare'], msg)):
2979 phase = 'suspend_prepare'
2980 data.dmesg[phase]['start'] = ktime
2981 data.setStart(ktime)
2982 data.tKernSus = ktime
2983 # suspend start
2984 elif(re.match(dm['suspend'], msg)):
2985 data.dmesg['suspend_prepare']['end'] = ktime
2986 phase = 'suspend'
2987 data.dmesg[phase]['start'] = ktime
2988 # suspend_late start
2989 elif(re.match(dm['suspend_late'], msg)):
2990 data.dmesg['suspend']['end'] = ktime
2991 phase = 'suspend_late'
2992 data.dmesg[phase]['start'] = ktime
2993 # suspend_noirq start
2994 elif(re.match(dm['suspend_noirq'], msg)):
2995 data.dmesg['suspend_late']['end'] = ktime
2996 phase = 'suspend_noirq'
2997 data.dmesg[phase]['start'] = ktime
2998 # suspend_machine start
2999 elif(re.match(dm['suspend_machine'], msg)):
3000 data.dmesg['suspend_noirq']['end'] = ktime
3001 phase = 'suspend_machine'
3002 data.dmesg[phase]['start'] = ktime
3003 # resume_machine start
3004 elif(re.match(dm['resume_machine'], msg)):
3005 if(sysvals.suspendmode in ['freeze', 'standby']):
3006 data.tSuspended = prevktime
3007 data.dmesg['suspend_machine']['end'] = prevktime
3008 else:
3009 data.tSuspended = ktime
3010 data.dmesg['suspend_machine']['end'] = ktime
3011 phase = 'resume_machine'
3012 data.tResumed = ktime
3013 data.tLow = data.tResumed - data.tSuspended
3014 data.dmesg[phase]['start'] = ktime
3015 # resume_noirq start
3016 elif(re.match(dm['resume_noirq'], msg)):
3017 data.dmesg['resume_machine']['end'] = ktime
3018 phase = 'resume_noirq'
3019 data.dmesg[phase]['start'] = ktime
3020 # resume_early start
3021 elif(re.match(dm['resume_early'], msg)):
3022 data.dmesg['resume_noirq']['end'] = ktime
3023 phase = 'resume_early'
3024 data.dmesg[phase]['start'] = ktime
3025 # resume start
3026 elif(re.match(dm['resume'], msg)):
3027 data.dmesg['resume_early']['end'] = ktime
3028 phase = 'resume'
3029 data.dmesg[phase]['start'] = ktime
3030 # resume complete start
3031 elif(re.match(dm['resume_complete'], msg)):
3032 data.dmesg['resume']['end'] = ktime
3033 phase = 'resume_complete'
3034 data.dmesg[phase]['start'] = ktime
3035 # post resume start
3036 elif(re.match(dm['post_resume'], msg)):
3037 data.dmesg['resume_complete']['end'] = ktime
3038 data.setEnd(ktime)
3039 data.tKernRes = ktime
3040 break
3041
3042 # -- device callbacks --
3043 if(phase in data.phases):
3044 # device init call
3045 if(re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)):
3046 sm = re.match('calling (?P<f>.*)\+ @ '+\
3047 '(?P<n>.*), parent: (?P<p>.*)', msg);
3048 f = sm.group('f')
3049 n = sm.group('n')
3050 p = sm.group('p')
3051 if(f and n and p):
3052 data.newAction(phase, f, int(n), p, ktime, -1, '')
3053 # device init return
3054 elif(re.match('call (?P<f>.*)\+ returned .* after '+\
3055 '(?P<t>.*) usecs', msg)):
3056 sm = re.match('call (?P<f>.*)\+ returned .* after '+\
3057 '(?P<t>.*) usecs(?P<a>.*)', msg);
3058 f = sm.group('f')
3059 t = sm.group('t')
3060 list = data.dmesg[phase]['list']
3061 if(f in list):
3062 dev = list[f]
3063 dev['length'] = int(t)
3064 dev['end'] = ktime
3065
3066 # if trace events are not available, these are better than nothing
3067 if(not sysvals.usetraceevents):
3068 # look for known actions
3069 for a in at:
3070 if(re.match(at[a]['smsg'], msg)):
3071 if(a not in actions):
3072 actions[a] = []
3073 actions[a].append({'begin': ktime, 'end': ktime})
3074 if(re.match(at[a]['emsg'], msg)):
3075 if(a in actions):
3076 actions[a][-1]['end'] = ktime
3077 # now look for CPU on/off events
3078 if(re.match('Disabling non-boot CPUs .*', msg)):
3079 # start of first cpu suspend
3080 cpu_start = ktime
3081 elif(re.match('Enabling non-boot CPUs .*', msg)):
3082 # start of first cpu resume
3083 cpu_start = ktime
3084 elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)):
3085 # end of a cpu suspend, start of the next
3086 m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)
3087 cpu = 'CPU'+m.group('cpu')
3088 if(cpu not in actions):
3089 actions[cpu] = []
3090 actions[cpu].append({'begin': cpu_start, 'end': ktime})
3091 cpu_start = ktime
3092 elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)):
3093 # end of a cpu resume, start of the next
3094 m = re.match('CPU(?P<cpu>[0-9]*) is up', msg)
3095 cpu = 'CPU'+m.group('cpu')
3096 if(cpu not in actions):
3097 actions[cpu] = []
3098 actions[cpu].append({'begin': cpu_start, 'end': ktime})
3099 cpu_start = ktime
3100 prevktime = ktime
3101
3102 # fill in any missing phases
3103 lp = data.phases[0]
3104 for p in data.phases:
3105 if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0):
3106 print('WARNING: phase "%s" is missing, something went wrong!' % p)
3107 print(' In %s, this dmesg line denotes the start of %s:' % \
3108 (sysvals.suspendmode, p))
3109 print(' "%s"' % dm[p])
3110 if(data.dmesg[p]['start'] < 0):
3111 data.dmesg[p]['start'] = data.dmesg[lp]['end']
3112 if(p == 'resume_machine'):
3113 data.tSuspended = data.dmesg[lp]['end']
3114 data.tResumed = data.dmesg[lp]['end']
3115 data.tLow = 0
3116 if(data.dmesg[p]['end'] < 0):
3117 data.dmesg[p]['end'] = data.dmesg[p]['start']
3118 lp = p
3119
3120 # fill in any actions we've found
3121 for name in actions:
3122 for event in actions[name]:
3123 data.newActionGlobal(name, event['begin'], event['end'])
3124
3125 data.printDetails()
3126 if(len(sysvals.devicefilter) > 0):
3127 data.deviceFilter(sysvals.devicefilter)
3128 data.fixupInitcallsThatDidntReturn()
3129 return True
3130
3131def callgraphHTML(sv, hf, num, cg, title, color, devid):
3132 html_func_top = '<article id="{0}" class="atop" style="background:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n'
3133 html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n'
3134 html_func_end = '</article>\n'
3135 html_func_leaf = '<article>{0} {1}</article>\n'
3136
3137 cgid = devid
3138 if cg.id:
3139 cgid += cg.id
3140 cglen = (cg.end - cg.start) * 1000
3141 if cglen < sv.mincglen:
3142 return num
3143
3144 fmt = '<r>(%.3f ms @ '+sv.timeformat+' to '+sv.timeformat+')</r>'
3145 flen = fmt % (cglen, cg.start, cg.end)
3146 hf.write(html_func_top.format(cgid, color, num, title, flen))
3147 num += 1
3148 for line in cg.list:
3149 if(line.length < 0.000000001):
3150 flen = ''
3151 else:
3152 fmt = '<n>(%.3f ms @ '+sv.timeformat+')</n>'
3153 flen = fmt % (line.length*1000, line.time)
3154 if(line.freturn and line.fcall):
3155 hf.write(html_func_leaf.format(line.name, flen))
3156 elif(line.freturn):
3157 hf.write(html_func_end)
3158 else:
3159 hf.write(html_func_start.format(num, line.name, flen))
3160 num += 1
3161 hf.write(html_func_end)
3162 return num
3163
3164def addCallgraphs(sv, hf, data):
3165 hf.write('<section id="callgraphs" class="callgraph">\n')
3166 # write out the ftrace data converted to html
3167 num = 0
3168 for p in data.phases:
3169 if sv.cgphase and p != sv.cgphase:
3170 continue
3171 list = data.dmesg[p]['list']
3172 for devname in data.sortedDevices(p):
3173 dev = list[devname]
3174 color = 'white'
3175 if 'color' in data.dmesg[p]:
3176 color = data.dmesg[p]['color']
3177 if 'color' in dev:
3178 color = dev['color']
3179 name = devname
3180 if(devname in sv.devprops):
3181 name = sv.devprops[devname].altName(devname)
3182 if sv.suspendmode in suspendmodename:
3183 name += ' '+p
3184 if('ftrace' in dev):
3185 cg = dev['ftrace']
3186 num = callgraphHTML(sv, hf, num, cg,
3187 name, color, dev['id'])
3188 if('ftraces' in dev):
3189 for cg in dev['ftraces']:
3190 num = callgraphHTML(sv, hf, num, cg,
3191 name+' &rarr; '+cg.name, color, dev['id'])
3192
3193 hf.write('\n\n </section>\n')
3194
3195# Function: createHTMLSummarySimple
3196# Description:
3197# Create summary html file for a series of tests
3198# Arguments:
3199# testruns: array of Data objects from parseTraceLog
3200def createHTMLSummarySimple(testruns, htmlfile, folder):
3201 # write the html header first (html head, css code, up to body start)
3202 html = '<!DOCTYPE html>\n<html>\n<head>\n\
3203 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\
3204 <title>SleepGraph Summary</title>\n\
3205 <style type=\'text/css\'>\n\
3206 .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\
3207 table {width:100%;border-collapse: collapse;}\n\
3208 .summary {border:1px solid;}\n\
3209 th {border: 1px solid black;background:#222;color:white;}\n\
3210 td {font: 16px "Times New Roman";text-align: center;}\n\
3211 tr.alt td {background:#ddd;}\n\
3212 tr.avg td {background:#aaa;}\n\
3213 </style>\n</head>\n<body>\n'
3214
3215 # group test header
3216 html += '<div class="stamp">%s (%d tests)</div>\n' % (folder, len(testruns))
3217 th = '\t<th>{0}</th>\n'
3218 td = '\t<td>{0}</td>\n'
3219 tdlink = '\t<td><a href="{0}">html</a></td>\n'
3220
3221 # table header
3222 html += '<table class="summary">\n<tr>\n' + th.format('#') +\
3223 th.format('Mode') + th.format('Host') + th.format('Kernel') +\
3224 th.format('Test Time') + th.format('Suspend') + th.format('Resume') +\
3225 th.format('Detail') + '</tr>\n'
3226
3227 # test data, 1 row per test
3228 avg = '<tr class="avg"><td></td><td></td><td></td><td></td>'+\
3229 '<td>Average of {0} {1} tests</td><td>{2}</td><td>{3}</td><td></td></tr>\n'
3230 sTimeAvg = rTimeAvg = 0.0
3231 mode = ''
3232 num = 0
3233 for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'])):
3234 if mode != data['mode']:
3235 # test average line
3236 if(num > 0):
3237 sTimeAvg /= (num - 1)
3238 rTimeAvg /= (num - 1)
3239 html += avg.format('%d' % (num - 1), mode,
3240 '%3.3f ms' % sTimeAvg, '%3.3f ms' % rTimeAvg)
3241 sTimeAvg = rTimeAvg = 0.0
3242 mode = data['mode']
3243 num = 1
3244 # alternate row color
3245 if num % 2 == 1:
3246 html += '<tr class="alt">\n'
3247 else:
3248 html += '<tr>\n'
3249 html += td.format("%d" % num)
3250 num += 1
3251 # basic info
3252 for item in ['mode', 'host', 'kernel', 'time']:
3253 val = "unknown"
3254 if(item in data):
3255 val = data[item]
3256 html += td.format(val)
3257 # suspend time
3258 sTime = float(data['suspend'])
3259 sTimeAvg += sTime
3260 html += td.format('%.3f ms' % sTime)
3261 # resume time
3262 rTime = float(data['resume'])
3263 rTimeAvg += rTime
3264 html += td.format('%.3f ms' % rTime)
3265 # link to the output html
3266 html += tdlink.format(data['url']) + '</tr>\n'
3267 # last test average line
3268 if(num > 0):
3269 sTimeAvg /= (num - 1)
3270 rTimeAvg /= (num - 1)
3271 html += avg.format('%d' % (num - 1), mode,
3272 '%3.3f ms' % sTimeAvg, '%3.3f ms' % rTimeAvg)
3273
3274 # flush the data to file
3275 hf = open(htmlfile, 'w')
3276 hf.write(html+'</table>\n</body>\n</html>\n')
3277 hf.close()
3278
3279def ordinal(value):
3280 suffix = 'th'
3281 if value < 10 or value > 19:
3282 if value % 10 == 1:
3283 suffix = 'st'
3284 elif value % 10 == 2:
3285 suffix = 'nd'
3286 elif value % 10 == 3:
3287 suffix = 'rd'
3288 return '%d%s' % (value, suffix)
3289
3290# Function: createHTML
3291# Description:
3292# Create the output html file from the resident test data
3293# Arguments:
3294# testruns: array of Data objects from parseKernelLog or parseTraceLog
3295# Output:
3296# True if the html file was created, false if it failed
3297def createHTML(testruns):
3298 if len(testruns) < 1:
3299 print('ERROR: Not enough test data to build a timeline')
3300 return
3301
3302 kerror = False
3303 for data in testruns:
3304 if data.kerror:
3305 kerror = True
3306 data.normalizeTime(testruns[-1].tSuspended)
3307
3308 # html function templates
3309 html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR&rarr;</div>\n'
3310 html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n'
3311 html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n'
3312 html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}">&nbsp;{2}</div>\n'
3313 html_timetotal = '<table class="time1">\n<tr>'\
3314 '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\
3315 '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\
3316 '</tr>\n</table>\n'
3317 html_timetotal2 = '<table class="time1">\n<tr>'\
3318 '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\
3319 '<td class="gray" title="time spent in low-power mode with clock running">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\
3320 '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\
3321 '</tr>\n</table>\n'
3322 html_timetotal3 = '<table class="time1">\n<tr>'\
3323 '<td class="green">Execution Time: <b>{0} ms</b></td>'\
3324 '<td class="yellow">Command: <b>{1}</b></td>'\
3325 '</tr>\n</table>\n'
3326 html_timegroups = '<table class="time2">\n<tr>'\
3327 '<td class="green" title="time from kernel enter_state({5}) to firmware mode [kernel time only]">{4}Kernel Suspend: {0} ms</td>'\
3328 '<td class="purple">{4}Firmware Suspend: {1} ms</td>'\
3329 '<td class="purple">{4}Firmware Resume: {2} ms</td>'\
3330 '<td class="yellow" title="time from firmware mode to return from kernel enter_state({5}) [kernel time only]">{4}Kernel Resume: {3} ms</td>'\
3331 '</tr>\n</table>\n'
3332
3333 # html format variables
3334 scaleH = 20
3335 if kerror:
3336 scaleH = 40
3337
3338 # device timeline
3339 vprint('Creating Device Timeline...')
3340
3341 devtl = Timeline(30, scaleH)
3342
3343 # write the test title and general info header
3344 devtl.createHeader(sysvals)
3345
3346 # Generate the header for this timeline
3347 for data in testruns:
3348 tTotal = data.end - data.start
3349 sktime = (data.dmesg['suspend_machine']['end'] - \
3350 data.tKernSus) * 1000
3351 rktime = (data.dmesg['resume_complete']['end'] - \
3352 data.dmesg['resume_machine']['start']) * 1000
3353 if(tTotal == 0):
3354 print('ERROR: No timeline data')
3355 sys.exit()
3356 if(data.tLow > 0):
3357 low_time = '%.0f'%(data.tLow*1000)
3358 if sysvals.suspendmode == 'command':
3359 run_time = '%.0f'%((data.end-data.start)*1000)
3360 if sysvals.testcommand:
3361 testdesc = sysvals.testcommand
3362 else:
3363 testdesc = 'unknown'
3364 if(len(testruns) > 1):
3365 testdesc = ordinal(data.testnumber+1)+' '+testdesc
3366 thtml = html_timetotal3.format(run_time, testdesc)
3367 devtl.html += thtml
3368 elif data.fwValid:
3369 suspend_time = '%.0f'%(sktime + (data.fwSuspend/1000000.0))
3370 resume_time = '%.0f'%(rktime + (data.fwResume/1000000.0))
3371 testdesc1 = 'Total'
3372 testdesc2 = ''
3373 stitle = 'time from kernel enter_state(%s) to low-power mode [kernel & firmware time]' % sysvals.suspendmode
3374 rtitle = 'time from low-power mode to return from kernel enter_state(%s) [firmware & kernel time]' % sysvals.suspendmode
3375 if(len(testruns) > 1):
3376 testdesc1 = testdesc2 = ordinal(data.testnumber+1)
3377 testdesc2 += ' '
3378 if(data.tLow == 0):
3379 thtml = html_timetotal.format(suspend_time, \
3380 resume_time, testdesc1, stitle, rtitle)
3381 else:
3382 thtml = html_timetotal2.format(suspend_time, low_time, \
3383 resume_time, testdesc1, stitle, rtitle)
3384 devtl.html += thtml
3385 sftime = '%.3f'%(data.fwSuspend / 1000000.0)
3386 rftime = '%.3f'%(data.fwResume / 1000000.0)
3387 devtl.html += html_timegroups.format('%.3f'%sktime, \
3388 sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode)
3389 else:
3390 suspend_time = '%.3f' % sktime
3391 resume_time = '%.3f' % rktime
3392 testdesc = 'Kernel'
3393 stitle = 'time from kernel enter_state(%s) to firmware mode [kernel time only]' % sysvals.suspendmode
3394 rtitle = 'time from firmware mode to return from kernel enter_state(%s) [kernel time only]' % sysvals.suspendmode
3395 if(len(testruns) > 1):
3396 testdesc = ordinal(data.testnumber+1)+' '+testdesc
3397 if(data.tLow == 0):
3398 thtml = html_timetotal.format(suspend_time, \
3399 resume_time, testdesc, stitle, rtitle)
3400 else:
3401 thtml = html_timetotal2.format(suspend_time, low_time, \
3402 resume_time, testdesc, stitle, rtitle)
3403 devtl.html += thtml
3404
3405 # time scale for potentially multiple datasets
3406 t0 = testruns[0].start
3407 tMax = testruns[-1].end
3408 tTotal = tMax - t0
3409
3410 # determine the maximum number of rows we need to draw
3411 fulllist = []
3412 threadlist = []
3413 pscnt = 0
3414 devcnt = 0
3415 for data in testruns:
3416 data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen)
3417 for group in data.devicegroups:
3418 devlist = []
3419 for phase in group:
3420 for devname in data.tdevlist[phase]:
3421 d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname])
3422 devlist.append(d)
3423 if d.isa('kth'):
3424 threadlist.append(d)
3425 else:
3426 if d.isa('ps'):
3427 pscnt += 1
3428 else:
3429 devcnt += 1
3430 fulllist.append(d)
3431 if sysvals.mixedphaseheight:
3432 devtl.getPhaseRows(devlist)
3433 if not sysvals.mixedphaseheight:
3434 if len(threadlist) > 0 and len(fulllist) > 0:
3435 if pscnt > 0 and devcnt > 0:
3436 msg = 'user processes & device pm callbacks'
3437 elif pscnt > 0:
3438 msg = 'user processes'
3439 else:
3440 msg = 'device pm callbacks'
3441 d = testruns[0].addHorizontalDivider(msg, testruns[-1].end)
3442 fulllist.insert(0, d)
3443 devtl.getPhaseRows(fulllist)
3444 if len(threadlist) > 0:
3445 d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end)
3446 threadlist.insert(0, d)
3447 devtl.getPhaseRows(threadlist, devtl.rows)
3448 devtl.calcTotalRows()
3449
3450 # draw the full timeline
3451 devtl.createZoomBox(sysvals.suspendmode, len(testruns))
3452 phases = {'suspend':[],'resume':[]}
3453 for phase in data.dmesg:
3454 if 'resume' in phase:
3455 phases['resume'].append(phase)
3456 else:
3457 phases['suspend'].append(phase)
3458
3459 # draw each test run chronologically
3460 for data in testruns:
3461 # now draw the actual timeline blocks
3462 for dir in phases:
3463 # draw suspend and resume blocks separately
3464 bname = '%s%d' % (dir[0], data.testnumber)
3465 if dir == 'suspend':
3466 m0 = data.start
3467 mMax = data.tSuspended
3468 left = '%f' % (((m0-t0)*100.0)/tTotal)
3469 else:
3470 m0 = data.tSuspended
3471 mMax = data.end
3472 # in an x2 run, remove any gap between blocks
3473 if len(testruns) > 1 and data.testnumber == 0:
3474 mMax = testruns[1].start
3475 left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal)
3476 mTotal = mMax - m0
3477 # if a timeline block is 0 length, skip altogether
3478 if mTotal == 0:
3479 continue
3480 width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal)
3481 devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH)
3482 for b in sorted(phases[dir]):
3483 # draw the phase color background
3484 phase = data.dmesg[b]
3485 length = phase['end']-phase['start']
3486 left = '%f' % (((phase['start']-m0)*100.0)/mTotal)
3487 width = '%f' % ((length*100.0)/mTotal)
3488 devtl.html += devtl.html_phase.format(left, width, \
3489 '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \
3490 data.dmesg[b]['color'], '')
3491 for e in data.errorinfo[dir]:
3492 # draw red lines for any kernel errors found
3493 t, err = e
3494 right = '%f' % (((mMax-t)*100.0)/mTotal)
3495 devtl.html += html_error.format(right, err)
3496 for b in sorted(phases[dir]):
3497 # draw the devices for this phase
3498 phaselist = data.dmesg[b]['list']
3499 for d in data.tdevlist[b]:
3500 name = d
3501 drv = ''
3502 dev = phaselist[d]
3503 xtraclass = ''
3504 xtrainfo = ''
3505 xtrastyle = ''
3506 if 'htmlclass' in dev:
3507 xtraclass = dev['htmlclass']
3508 if 'color' in dev:
3509 xtrastyle = 'background:%s;' % dev['color']
3510 if(d in sysvals.devprops):
3511 name = sysvals.devprops[d].altName(d)
3512 xtraclass = sysvals.devprops[d].xtraClass()
3513 xtrainfo = sysvals.devprops[d].xtraInfo()
3514 elif xtraclass == ' kth':
3515 xtrainfo = ' kernel_thread'
3516 if('drv' in dev and dev['drv']):
3517 drv = ' {%s}' % dev['drv']
3518 rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row'])
3519 rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row'])
3520 top = '%.3f' % (rowtop + devtl.scaleH)
3521 left = '%f' % (((dev['start']-m0)*100)/mTotal)
3522 width = '%f' % (((dev['end']-dev['start'])*100)/mTotal)
3523 length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)
3524 title = name+drv+xtrainfo+length
3525 if sysvals.suspendmode == 'command':
3526 title += sysvals.testcommand
3527 elif xtraclass == ' ps':
3528 if 'suspend' in b:
3529 title += 'pre_suspend_process'
3530 else:
3531 title += 'post_resume_process'
3532 else:
3533 title += b
3534 devtl.html += devtl.html_device.format(dev['id'], \
3535 title, left, top, '%.3f'%rowheight, width, \
3536 d+drv, xtraclass, xtrastyle)
3537 if('cpuexec' in dev):
3538 for t in sorted(dev['cpuexec']):
3539 start, end = t
3540 j = float(dev['cpuexec'][t]) / 5
3541 if j > 1.0:
3542 j = 1.0
3543 height = '%.3f' % (rowheight/3)
3544 top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3)
3545 left = '%f' % (((start-m0)*100)/mTotal)
3546 width = '%f' % ((end-start)*100/mTotal)
3547 color = 'rgba(255, 0, 0, %f)' % j
3548 devtl.html += \
3549 html_cpuexec.format(left, top, height, width, color)
3550 if('src' not in dev):
3551 continue
3552 # draw any trace events for this device
3553 for e in dev['src']:
3554 height = '%.3f' % devtl.rowH
3555 top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH))
3556 left = '%f' % (((e.time-m0)*100)/mTotal)
3557 width = '%f' % (e.length*100/mTotal)
3558 xtrastyle = ''
3559 if e.color:
3560 xtrastyle = 'background:%s;' % e.color
3561 devtl.html += \
3562 html_traceevent.format(e.title(), \
3563 left, top, height, width, e.text(), '', xtrastyle)
3564 # draw the time scale, try to make the number of labels readable
3565 devtl.createTimeScale(m0, mMax, tTotal, dir)
3566 devtl.html += '</div>\n'
3567
3568 # timeline is finished
3569 devtl.html += '</div>\n</div>\n'
3570
3571 # draw a legend which describes the phases by color
3572 if sysvals.suspendmode != 'command':
3573 data = testruns[-1]
3574 devtl.html += '<div class="legend">\n'
3575 pdelta = 100.0/len(data.phases)
3576 pmargin = pdelta / 4.0
3577 for phase in data.phases:
3578 tmp = phase.split('_')
3579 id = tmp[0][0]
3580 if(len(tmp) > 1):
3581 id += tmp[1][0]
3582 order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin)
3583 name = string.replace(phase, '_', ' &nbsp;')
3584 devtl.html += html_legend.format(order, \
3585 data.dmesg[phase]['color'], name, id)
3586 devtl.html += '</div>\n'
3587
3588 hf = open(sysvals.htmlfile, 'w')
3589
3590 # no header or css if its embedded
3591 if(sysvals.embedded):
3592 hf.write('pass True tSus %.3f tRes %.3f tLow %.3f fwvalid %s tSus %.3f tRes %.3f\n' %
3593 (data.tSuspended-data.start, data.end-data.tSuspended, data.tLow, data.fwValid, \
3594 data.fwSuspend/1000000, data.fwResume/1000000))
3595 else:
3596 addCSS(hf, sysvals, len(testruns), kerror)
3597
3598 # write the device timeline
3599 hf.write(devtl.html)
3600 hf.write('<div id="devicedetailtitle"></div>\n')
3601 hf.write('<div id="devicedetail" style="display:none;">\n')
3602 # draw the colored boxes for the device detail section
3603 for data in testruns:
3604 hf.write('<div id="devicedetail%d">\n' % data.testnumber)
3605 pscolor = 'linear-gradient(to top left, #ccc, #eee)'
3606 hf.write(devtl.html_phaselet.format('pre_suspend_process', \
3607 '0', '0', pscolor))
3608 for b in data.phases:
3609 phase = data.dmesg[b]
3610 length = phase['end']-phase['start']
3611 left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal)
3612 width = '%.3f' % ((length*100.0)/tTotal)
3613 hf.write(devtl.html_phaselet.format(b, left, width, \
3614 data.dmesg[b]['color']))
3615 hf.write(devtl.html_phaselet.format('post_resume_process', \
3616 '0', '0', pscolor))
3617 if sysvals.suspendmode == 'command':
3618 hf.write(devtl.html_phaselet.format('cmdexec', '0', '0', pscolor))
3619 hf.write('</div>\n')
3620 hf.write('</div>\n')
3621
3622 # write the ftrace data (callgraph)
3623 if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest:
3624 data = testruns[sysvals.cgtest]
3625 else:
3626 data = testruns[-1]
3627 if(sysvals.usecallgraph and not sysvals.embedded):
3628 addCallgraphs(sysvals, hf, data)
3629
3630 # add the test log as a hidden div
3631 if sysvals.logmsg:
3632 hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n')
3633 # add the dmesg log as a hidden div
3634 if sysvals.addlogs and sysvals.dmesgfile:
3635 hf.write('<div id="dmesglog" style="display:none;">\n')
3636 lf = open(sysvals.dmesgfile, 'r')
3637 for line in lf:
3638 line = line.replace('<', '&lt').replace('>', '&gt')
3639 hf.write(line)
3640 lf.close()
3641 hf.write('</div>\n')
3642 # add the ftrace log as a hidden div
3643 if sysvals.addlogs and sysvals.ftracefile:
3644 hf.write('<div id="ftracelog" style="display:none;">\n')
3645 lf = open(sysvals.ftracefile, 'r')
3646 for line in lf:
3647 hf.write(line)
3648 lf.close()
3649 hf.write('</div>\n')
3650
3651 if(not sysvals.embedded):
3652 # write the footer and close
3653 addScriptCode(hf, testruns)
3654 hf.write('</body>\n</html>\n')
3655 else:
3656 # embedded out will be loaded in a page, skip the js
3657 t0 = (testruns[0].start - testruns[-1].tSuspended) * 1000
3658 tMax = (testruns[-1].end - testruns[-1].tSuspended) * 1000
3659 # add js code in a div entry for later evaluation
3660 detail = 'var bounds = [%f,%f];\n' % (t0, tMax)
3661 detail += 'var devtable = [\n'
3662 for data in testruns:
3663 topo = data.deviceTopology()
3664 detail += '\t"%s",\n' % (topo)
3665 detail += '];\n'
3666 hf.write('<div id=customcode style=display:none>\n'+detail+'</div>\n')
3667 hf.close()
3668 return True
3669
3670def addCSS(hf, sv, testcount=1, kerror=False, extra=''):
3671 kernel = sv.stamp['kernel']
3672 host = sv.hostname[0].upper()+sv.hostname[1:]
3673 mode = sv.suspendmode
3674 if sv.suspendmode in suspendmodename:
3675 mode = suspendmodename[sv.suspendmode]
3676 title = host+' '+mode+' '+kernel
3677
3678 # various format changes by flags
3679 cgchk = 'checked'
3680 cgnchk = 'not(:checked)'
3681 if sv.cgexp:
3682 cgchk = 'not(:checked)'
3683 cgnchk = 'checked'
3684
3685 hoverZ = 'z-index:8;'
3686 if sv.usedevsrc:
3687 hoverZ = ''
3688
3689 devlistpos = 'absolute'
3690 if testcount > 1:
3691 devlistpos = 'relative'
3692
3693 scaleTH = 20
3694 if kerror:
3695 scaleTH = 60
3696
3697 # write the html header first (html head, css code, up to body start)
3698 html_header = '<!DOCTYPE html>\n<html>\n<head>\n\
3699 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\
3700 <title>'+title+'</title>\n\
3701 <style type=\'text/css\'>\n\
3702 body {overflow-y:scroll;}\n\
3703 .stamp {width:100%;text-align:center;background:gray;line-height:30px;color:white;font:25px Arial;}\n\
3704 .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\
3705 .callgraph article * {padding-left:28px;}\n\
3706 h1 {color:black;font:bold 30px Times;}\n\
3707 t0 {color:black;font:bold 30px Times;}\n\
3708 t1 {color:black;font:30px Times;}\n\
3709 t2 {color:black;font:25px Times;}\n\
3710 t3 {color:black;font:20px Times;white-space:nowrap;}\n\
3711 t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\
3712 cS {font:bold 13px Times;}\n\
3713 table {width:100%;}\n\
3714 .gray {background:rgba(80,80,80,0.1);}\n\
3715 .green {background:rgba(204,255,204,0.4);}\n\
3716 .purple {background:rgba(128,0,128,0.2);}\n\
3717 .yellow {background:rgba(255,255,204,0.4);}\n\
3718 .blue {background:rgba(169,208,245,0.4);}\n\
3719 .time1 {font:22px Arial;border:1px solid;}\n\
3720 .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\
3721 td {text-align:center;}\n\
3722 r {color:#500000;font:15px Tahoma;}\n\
3723 n {color:#505050;font:15px Tahoma;}\n\
3724 .tdhl {color:red;}\n\
3725 .hide {display:none;}\n\
3726 .pf {display:none;}\n\
3727 .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
3728 .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
3729 .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\
3730 .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\
3731 .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\
3732 .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\
3733 .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\
3734 .thread:hover {background:white;border:1px solid red;'+hoverZ+'}\n\
3735 .thread.sec,.thread.sec:hover {background:black;border:0;color:white;line-height:15px;font-size:10px;}\n\
3736 .hover {background:white;border:1px solid red;'+hoverZ+'}\n\
3737 .hover.sync {background:white;}\n\
3738 .hover.bg,.hover.kth,.hover.sync,.hover.ps {background:white;}\n\
3739 .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\
3740 .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\
3741 .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\
3742 .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\
3743 .phaselet {float:left;overflow:hidden;border:0px;text-align:center;min-height:100px;font-size:24px;}\n\
3744 .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\
3745 .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\
3746 .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\
3747 .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\
3748 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\
3749 .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\
3750 .devlist {position:'+devlistpos+';width:190px;}\n\
3751 a:link {color:white;text-decoration:none;}\n\
3752 a:visited {color:white;}\n\
3753 a:hover {color:white;}\n\
3754 a:active {color:white;}\n\
3755 .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\
3756 #devicedetail {min-height:100px;box-shadow:5px 5px 20px black;}\n\
3757 .tblock {position:absolute;height:100%;background:#ddd;}\n\
3758 .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\
3759 .bg {z-index:1;}\n\
3760'+extra+'\
3761 </style>\n</head>\n<body>\n'
3762 hf.write(html_header)
3763
3764# Function: addScriptCode
3765# Description:
3766# Adds the javascript code to the output html
3767# Arguments:
3768# hf: the open html file pointer
3769# testruns: array of Data objects from parseKernelLog or parseTraceLog
3770def addScriptCode(hf, testruns):
3771 t0 = testruns[0].start * 1000
3772 tMax = testruns[-1].end * 1000
3773 # create an array in javascript memory with the device details
3774 detail = ' var devtable = [];\n'
3775 for data in testruns:
3776 topo = data.deviceTopology()
3777 detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo)
3778 detail += ' var bounds = [%f,%f];\n' % (t0, tMax)
3779 # add the code which will manipulate the data in the browser
3780 script_code = \
3781 '<script type="text/javascript">\n'+detail+\
3782 ' var resolution = -1;\n'\
3783 ' var dragval = [0, 0];\n'\
3784 ' function redrawTimescale(t0, tMax, tS) {\n'\
3785 ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;">\';\n'\
3786 ' var tTotal = tMax - t0;\n'\
3787 ' var list = document.getElementsByClassName("tblock");\n'\
3788 ' for (var i = 0; i < list.length; i++) {\n'\
3789 ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\
3790 ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\
3791 ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\
3792 ' var mMax = m0 + mTotal;\n'\
3793 ' var html = "";\n'\
3794 ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\
3795 ' if(divTotal > 1000) continue;\n'\
3796 ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\
3797 ' var pos = 0.0, val = 0.0;\n'\
3798 ' for (var j = 0; j < divTotal; j++) {\n'\
3799 ' var htmlline = "";\n'\
3800 ' var mode = list[i].id[5];\n'\
3801 ' if(mode == "s") {\n'\
3802 ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\
3803 ' val = (j-divTotal+1)*tS;\n'\
3804 ' if(j == divTotal - 1)\n'\
3805 ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S&rarr;</cS></div>\';\n'\
3806 ' else\n'\
3807 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\
3808 ' } else {\n'\
3809 ' pos = 100 - (((j)*tS*100)/mTotal);\n'\
3810 ' val = (j)*tS;\n'\
3811 ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\
3812 ' if(j == 0)\n'\
3813 ' if(mode == "r")\n'\
3814 ' htmlline = rline+"<cS>&larr;R</cS></div>";\n'\
3815 ' else\n'\
3816 ' htmlline = rline+"<cS>0ms</div>";\n'\
3817 ' }\n'\
3818 ' html += htmlline;\n'\
3819 ' }\n'\
3820 ' timescale.innerHTML = html;\n'\
3821 ' }\n'\
3822 ' }\n'\
3823 ' function zoomTimeline() {\n'\
3824 ' var dmesg = document.getElementById("dmesg");\n'\
3825 ' var zoombox = document.getElementById("dmesgzoombox");\n'\
3826 ' var left = zoombox.scrollLeft;\n'\
3827 ' var val = parseFloat(dmesg.style.width);\n'\
3828 ' var newval = 100;\n'\
3829 ' var sh = window.outerWidth / 2;\n'\
3830 ' if(this.id == "zoomin") {\n'\
3831 ' newval = val * 1.2;\n'\
3832 ' if(newval > 910034) newval = 910034;\n'\
3833 ' dmesg.style.width = newval+"%";\n'\
3834 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\
3835 ' } else if (this.id == "zoomout") {\n'\
3836 ' newval = val / 1.2;\n'\
3837 ' if(newval < 100) newval = 100;\n'\
3838 ' dmesg.style.width = newval+"%";\n'\
3839 ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\
3840 ' } else {\n'\
3841 ' zoombox.scrollLeft = 0;\n'\
3842 ' dmesg.style.width = "100%";\n'\
3843 ' }\n'\
3844 ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\
3845 ' var t0 = bounds[0];\n'\
3846 ' var tMax = bounds[1];\n'\
3847 ' var tTotal = tMax - t0;\n'\
3848 ' var wTotal = tTotal * 100.0 / newval;\n'\
3849 ' var idx = 7*window.innerWidth/1100;\n'\
3850 ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\
3851 ' if(i >= tS.length) i = tS.length - 1;\n'\
3852 ' if(tS[i] == resolution) return;\n'\
3853 ' resolution = tS[i];\n'\
3854 ' redrawTimescale(t0, tMax, tS[i]);\n'\
3855 ' }\n'\
3856 ' function deviceName(title) {\n'\
3857 ' var name = title.slice(0, title.indexOf(" ("));\n'\
3858 ' return name;\n'\
3859 ' }\n'\
3860 ' function deviceHover() {\n'\
3861 ' var name = deviceName(this.title);\n'\
3862 ' var dmesg = document.getElementById("dmesg");\n'\
3863 ' var dev = dmesg.getElementsByClassName("thread");\n'\
3864 ' var cpu = -1;\n'\
3865 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\
3866 ' cpu = parseInt(name.slice(7));\n'\
3867 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\
3868 ' cpu = parseInt(name.slice(8));\n'\
3869 ' for (var i = 0; i < dev.length; i++) {\n'\
3870 ' dname = deviceName(dev[i].title);\n'\
3871 ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\
3872 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\
3873 ' (name == dname))\n'\
3874 ' {\n'\
3875 ' dev[i].className = "hover "+cname;\n'\
3876 ' } else {\n'\
3877 ' dev[i].className = cname;\n'\
3878 ' }\n'\
3879 ' }\n'\
3880 ' }\n'\
3881 ' function deviceUnhover() {\n'\
3882 ' var dmesg = document.getElementById("dmesg");\n'\
3883 ' var dev = dmesg.getElementsByClassName("thread");\n'\
3884 ' for (var i = 0; i < dev.length; i++) {\n'\
3885 ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\
3886 ' }\n'\
3887 ' }\n'\
3888 ' function deviceTitle(title, total, cpu) {\n'\
3889 ' var prefix = "Total";\n'\
3890 ' if(total.length > 3) {\n'\
3891 ' prefix = "Average";\n'\
3892 ' total[1] = (total[1]+total[3])/2;\n'\
3893 ' total[2] = (total[2]+total[4])/2;\n'\
3894 ' }\n'\
3895 ' var devtitle = document.getElementById("devicedetailtitle");\n'\
3896 ' var name = deviceName(title);\n'\
3897 ' if(cpu >= 0) name = "CPU"+cpu;\n'\
3898 ' var driver = "";\n'\
3899 ' var tS = "<t2>(</t2>";\n'\
3900 ' var tR = "<t2>)</t2>";\n'\
3901 ' if(total[1] > 0)\n'\
3902 ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\
3903 ' if(total[2] > 0)\n'\
3904 ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\
3905 ' var s = title.indexOf("{");\n'\
3906 ' var e = title.indexOf("}");\n'\
3907 ' if((s >= 0) && (e >= 0))\n'\
3908 ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\
3909 ' if(total[1] > 0 && total[2] > 0)\n'\
3910 ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\
3911 ' else\n'\
3912 ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\
3913 ' return name;\n'\
3914 ' }\n'\
3915 ' function deviceDetail() {\n'\
3916 ' var devinfo = document.getElementById("devicedetail");\n'\
3917 ' devinfo.style.display = "block";\n'\
3918 ' var name = deviceName(this.title);\n'\
3919 ' var cpu = -1;\n'\
3920 ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\
3921 ' cpu = parseInt(name.slice(7));\n'\
3922 ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\
3923 ' cpu = parseInt(name.slice(8));\n'\
3924 ' var dmesg = document.getElementById("dmesg");\n'\
3925 ' var dev = dmesg.getElementsByClassName("thread");\n'\
3926 ' var idlist = [];\n'\
3927 ' var pdata = [[]];\n'\
3928 ' if(document.getElementById("devicedetail1"))\n'\
3929 ' pdata = [[], []];\n'\
3930 ' var pd = pdata[0];\n'\
3931 ' var total = [0.0, 0.0, 0.0];\n'\
3932 ' for (var i = 0; i < dev.length; i++) {\n'\
3933 ' dname = deviceName(dev[i].title);\n'\
3934 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\
3935 ' (name == dname))\n'\
3936 ' {\n'\
3937 ' idlist[idlist.length] = dev[i].id;\n'\
3938 ' var tidx = 1;\n'\
3939 ' if(dev[i].id[0] == "a") {\n'\
3940 ' pd = pdata[0];\n'\
3941 ' } else {\n'\
3942 ' if(pdata.length == 1) pdata[1] = [];\n'\
3943 ' if(total.length == 3) total[3]=total[4]=0.0;\n'\
3944 ' pd = pdata[1];\n'\
3945 ' tidx = 3;\n'\
3946 ' }\n'\
3947 ' var info = dev[i].title.split(" ");\n'\
3948 ' var pname = info[info.length-1];\n'\
3949 ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\
3950 ' total[0] += pd[pname];\n'\
3951 ' if(pname.indexOf("suspend") >= 0)\n'\
3952 ' total[tidx] += pd[pname];\n'\
3953 ' else\n'\
3954 ' total[tidx+1] += pd[pname];\n'\
3955 ' }\n'\
3956 ' }\n'\
3957 ' var devname = deviceTitle(this.title, total, cpu);\n'\
3958 ' var left = 0.0;\n'\
3959 ' for (var t = 0; t < pdata.length; t++) {\n'\
3960 ' pd = pdata[t];\n'\
3961 ' devinfo = document.getElementById("devicedetail"+t);\n'\
3962 ' var phases = devinfo.getElementsByClassName("phaselet");\n'\
3963 ' for (var i = 0; i < phases.length; i++) {\n'\
3964 ' if(phases[i].id in pd) {\n'\
3965 ' var w = 100.0*pd[phases[i].id]/total[0];\n'\
3966 ' var fs = 32;\n'\
3967 ' if(w < 8) fs = 4*w | 0;\n'\
3968 ' var fs2 = fs*3/4;\n'\
3969 ' phases[i].style.width = w+"%";\n'\
3970 ' phases[i].style.left = left+"%";\n'\
3971 ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\
3972 ' left += w;\n'\
3973 ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\
3974 ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\
3975 ' phases[i].innerHTML = time+pname;\n'\
3976 ' } else {\n'\
3977 ' phases[i].style.width = "0%";\n'\
3978 ' phases[i].style.left = left+"%";\n'\
3979 ' }\n'\
3980 ' }\n'\
3981 ' }\n'\
3982 ' if(typeof devstats !== \'undefined\')\n'\
3983 ' callDetail(this.id, this.title);\n'\
3984 ' var cglist = document.getElementById("callgraphs");\n'\
3985 ' if(!cglist) return;\n'\
3986 ' var cg = cglist.getElementsByClassName("atop");\n'\
3987 ' if(cg.length < 10) return;\n'\
3988 ' for (var i = 0; i < cg.length; i++) {\n'\
3989 ' cgid = cg[i].id.split("x")[0]\n'\
3990 ' if(idlist.indexOf(cgid) >= 0) {\n'\
3991 ' cg[i].style.display = "block";\n'\
3992 ' } else {\n'\
3993 ' cg[i].style.display = "none";\n'\
3994 ' }\n'\
3995 ' }\n'\
3996 ' }\n'\
3997 ' function callDetail(devid, devtitle) {\n'\
3998 ' if(!(devid in devstats) || devstats[devid].length < 1)\n'\
3999 ' return;\n'\
4000 ' var list = devstats[devid];\n'\
4001 ' var tmp = devtitle.split(" ");\n'\
4002 ' var name = tmp[0], phase = tmp[tmp.length-1];\n'\
4003 ' var dd = document.getElementById(phase);\n'\
4004 ' var total = parseFloat(tmp[1].slice(1));\n'\
4005 ' var mlist = [];\n'\
4006 ' var maxlen = 0;\n'\
4007 ' var info = []\n'\
4008 ' for(var i in list) {\n'\
4009 ' if(list[i][0] == "@") {\n'\
4010 ' info = list[i].split("|");\n'\
4011 ' continue;\n'\
4012 ' }\n'\
4013 ' var tmp = list[i].split("|");\n'\
4014 ' var t = parseFloat(tmp[0]), f = tmp[1], c = parseInt(tmp[2]);\n'\
4015 ' var p = (t*100.0/total).toFixed(2);\n'\
4016 ' mlist[mlist.length] = [f, c, t.toFixed(2), p+"%"];\n'\
4017 ' if(f.length > maxlen)\n'\
4018 ' maxlen = f.length;\n'\
4019 ' }\n'\
4020 ' var pad = 5;\n'\
4021 ' if(mlist.length == 0) pad = 30;\n'\
4022 ' var html = \'<div style="padding-top:\'+pad+\'px"><t3> <b>\'+name+\':</b>\';\n'\
4023 ' if(info.length > 2)\n'\
4024 ' html += " start=<b>"+info[1]+"</b>, end=<b>"+info[2]+"</b>";\n'\
4025 ' if(info.length > 3)\n'\
4026 ' html += ", length<i>(w/o overhead)</i>=<b>"+info[3]+" ms</b>";\n'\
4027 ' if(info.length > 4)\n'\
4028 ' html += ", return=<b>"+info[4]+"</b>";\n'\
4029 ' html += "</t3></div>";\n'\
4030 ' if(mlist.length > 0) {\n'\
4031 ' html += \'<table class=fstat style="padding-top:\'+(maxlen*5)+\'px;"><tr><th>Function</th>\';\n'\
4032 ' for(var i in mlist)\n'\
4033 ' html += "<td class=vt>"+mlist[i][0]+"</td>";\n'\
4034 ' html += "</tr><tr><th>Calls</th>";\n'\
4035 ' for(var i in mlist)\n'\
4036 ' html += "<td>"+mlist[i][1]+"</td>";\n'\
4037 ' html += "</tr><tr><th>Time(ms)</th>";\n'\
4038 ' for(var i in mlist)\n'\
4039 ' html += "<td>"+mlist[i][2]+"</td>";\n'\
4040 ' html += "</tr><tr><th>Percent</th>";\n'\
4041 ' for(var i in mlist)\n'\
4042 ' html += "<td>"+mlist[i][3]+"</td>";\n'\
4043 ' html += "</tr></table>";\n'\
4044 ' }\n'\
4045 ' dd.innerHTML = html;\n'\
4046 ' var height = (maxlen*5)+100;\n'\
4047 ' dd.style.height = height+"px";\n'\
4048 ' document.getElementById("devicedetail").style.height = height+"px";\n'\
4049 ' }\n'\
4050 ' function callSelect() {\n'\
4051 ' var cglist = document.getElementById("callgraphs");\n'\
4052 ' if(!cglist) return;\n'\
4053 ' var cg = cglist.getElementsByClassName("atop");\n'\
4054 ' for (var i = 0; i < cg.length; i++) {\n'\
4055 ' if(this.id == cg[i].id) {\n'\
4056 ' cg[i].style.display = "block";\n'\
4057 ' } else {\n'\
4058 ' cg[i].style.display = "none";\n'\
4059 ' }\n'\
4060 ' }\n'\
4061 ' }\n'\
4062 ' function devListWindow(e) {\n'\
4063 ' var win = window.open();\n'\
4064 ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\
4065 ' "<style type=\\"text/css\\">"+\n'\
4066 ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\
4067 ' "</style>"\n'\
4068 ' var dt = devtable[0];\n'\
4069 ' if(e.target.id != "devlist1")\n'\
4070 ' dt = devtable[1];\n'\
4071 ' win.document.write(html+dt);\n'\
4072 ' }\n'\
4073 ' function errWindow() {\n'\
4074 ' var text = this.id;\n'\
4075 ' var win = window.open();\n'\
4076 ' win.document.write("<pre>"+text+"</pre>");\n'\
4077 ' win.document.close();\n'\
4078 ' }\n'\
4079 ' function logWindow(e) {\n'\
4080 ' var name = e.target.id.slice(4);\n'\
4081 ' var win = window.open();\n'\
4082 ' var log = document.getElementById(name+"log");\n'\
4083 ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\
4084 ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\
4085 ' win.document.close();\n'\
4086 ' }\n'\
4087 ' function onClickPhase(e) {\n'\
4088 ' }\n'\
4089 ' function onMouseDown(e) {\n'\
4090 ' dragval[0] = e.clientX;\n'\
4091 ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\
4092 ' document.onmousemove = onMouseMove;\n'\
4093 ' }\n'\
4094 ' function onMouseMove(e) {\n'\
4095 ' var zoombox = document.getElementById("dmesgzoombox");\n'\
4096 ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\
4097 ' }\n'\
4098 ' function onMouseUp(e) {\n'\
4099 ' document.onmousemove = null;\n'\
4100 ' }\n'\
4101 ' function onKeyPress(e) {\n'\
4102 ' var c = e.charCode;\n'\
4103 ' if(c != 42 && c != 43 && c != 45) return;\n'\
4104 ' var click = document.createEvent("Events");\n'\
4105 ' click.initEvent("click", true, false);\n'\
4106 ' if(c == 43) \n'\
4107 ' document.getElementById("zoomin").dispatchEvent(click);\n'\
4108 ' else if(c == 45)\n'\
4109 ' document.getElementById("zoomout").dispatchEvent(click);\n'\
4110 ' else if(c == 42)\n'\
4111 ' document.getElementById("zoomdef").dispatchEvent(click);\n'\
4112 ' }\n'\
4113 ' window.addEventListener("resize", function () {zoomTimeline();});\n'\
4114 ' window.addEventListener("load", function () {\n'\
4115 ' var dmesg = document.getElementById("dmesg");\n'\
4116 ' dmesg.style.width = "100%"\n'\
4117 ' dmesg.onmousedown = onMouseDown;\n'\
4118 ' document.onmouseup = onMouseUp;\n'\
4119 ' document.onkeypress = onKeyPress;\n'\
4120 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\
4121 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\
4122 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\
4123 ' var list = document.getElementsByClassName("square");\n'\
4124 ' for (var i = 0; i < list.length; i++)\n'\
4125 ' list[i].onclick = onClickPhase;\n'\
4126 ' var list = document.getElementsByClassName("err");\n'\
4127 ' for (var i = 0; i < list.length; i++)\n'\
4128 ' list[i].onclick = errWindow;\n'\
4129 ' var list = document.getElementsByClassName("logbtn");\n'\
4130 ' for (var i = 0; i < list.length; i++)\n'\
4131 ' list[i].onclick = logWindow;\n'\
4132 ' list = document.getElementsByClassName("devlist");\n'\
4133 ' for (var i = 0; i < list.length; i++)\n'\
4134 ' list[i].onclick = devListWindow;\n'\
4135 ' var dev = dmesg.getElementsByClassName("thread");\n'\
4136 ' for (var i = 0; i < dev.length; i++) {\n'\
4137 ' dev[i].onclick = deviceDetail;\n'\
4138 ' dev[i].onmouseover = deviceHover;\n'\
4139 ' dev[i].onmouseout = deviceUnhover;\n'\
4140 ' }\n'\
4141 ' var dev = dmesg.getElementsByClassName("srccall");\n'\
4142 ' for (var i = 0; i < dev.length; i++)\n'\
4143 ' dev[i].onclick = callSelect;\n'\
4144 ' zoomTimeline();\n'\
4145 ' });\n'\
4146 '</script>\n'
4147 hf.write(script_code);
4148
4149# Function: executeSuspend
4150# Description:
4151# Execute system suspend through the sysfs interface, then copy the output
4152# dmesg and ftrace files to the test output directory.
4153def executeSuspend():
4154 pm = ProcessMonitor()
4155 tp = sysvals.tpath
4156 fwdata = []
4157 # mark the start point in the kernel ring buffer just as we start
4158 sysvals.initdmesg()
4159 # start ftrace
4160 if(sysvals.usecallgraph or sysvals.usetraceevents):
4161 print('START TRACING')
4162 sysvals.fsetVal('1', 'tracing_on')
4163 if sysvals.useprocmon:
4164 pm.start()
4165 # execute however many s/r runs requested
4166 for count in range(1,sysvals.execcount+1):
4167 # x2delay in between test runs
4168 if(count > 1 and sysvals.x2delay > 0):
4169 sysvals.fsetVal('WAIT %d' % sysvals.x2delay, 'trace_marker')
4170 time.sleep(sysvals.x2delay/1000.0)
4171 sysvals.fsetVal('WAIT END', 'trace_marker')
4172 # start message
4173 if sysvals.testcommand != '':
4174 print('COMMAND START')
4175 else:
4176 if(sysvals.rtcwake):
4177 print('SUSPEND START')
4178 else:
4179 print('SUSPEND START (press a key to resume)')
4180 # set rtcwake
4181 if(sysvals.rtcwake):
4182 print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
4183 sysvals.rtcWakeAlarmOn()
4184 # start of suspend trace marker
4185 if(sysvals.usecallgraph or sysvals.usetraceevents):
4186 sysvals.fsetVal('SUSPEND START', 'trace_marker')
4187 # predelay delay
4188 if(count == 1 and sysvals.predelay > 0):
4189 sysvals.fsetVal('WAIT %d' % sysvals.predelay, 'trace_marker')
4190 time.sleep(sysvals.predelay/1000.0)
4191 sysvals.fsetVal('WAIT END', 'trace_marker')
4192 # initiate suspend or command
4193 if sysvals.testcommand != '':
4194 call(sysvals.testcommand+' 2>&1', shell=True);
4195 else:
4196 pf = open(sysvals.powerfile, 'w')
4197 pf.write(sysvals.suspendmode)
4198 # execution will pause here
4199 try:
4200 pf.close()
4201 except:
4202 pass
4203 if(sysvals.rtcwake):
4204 sysvals.rtcWakeAlarmOff()
4205 # postdelay delay
4206 if(count == sysvals.execcount and sysvals.postdelay > 0):
4207 sysvals.fsetVal('WAIT %d' % sysvals.postdelay, 'trace_marker')
4208 time.sleep(sysvals.postdelay/1000.0)
4209 sysvals.fsetVal('WAIT END', 'trace_marker')
4210 # return from suspend
4211 print('RESUME COMPLETE')
4212 if(sysvals.usecallgraph or sysvals.usetraceevents):
4213 sysvals.fsetVal('RESUME COMPLETE', 'trace_marker')
4214 if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
4215 fwdata.append(getFPDT(False))
4216 # stop ftrace
4217 if(sysvals.usecallgraph or sysvals.usetraceevents):
4218 if sysvals.useprocmon:
4219 pm.stop()
4220 sysvals.fsetVal('0', 'tracing_on')
4221 print('CAPTURING TRACE')
4222 writeDatafileHeader(sysvals.ftracefile, fwdata)
4223 call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True)
4224 sysvals.fsetVal('', 'trace')
4225 devProps()
4226 # grab a copy of the dmesg output
4227 print('CAPTURING DMESG')
4228 writeDatafileHeader(sysvals.dmesgfile, fwdata)
4229 sysvals.getdmesg()
4230
4231def writeDatafileHeader(filename, fwdata):
4232 fp = open(filename, 'a')
4233 fp.write(sysvals.teststamp+'\n')
4234 if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
4235 for fw in fwdata:
4236 if(fw):
4237 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))
4238 fp.close()
4239
4240# Function: setUSBDevicesAuto
4241# Description:
4242# Set the autosuspend control parameter of all USB devices to auto
4243# This can be dangerous, so use at your own risk, most devices are set
4244# to always-on since the kernel cant determine if the device can
4245# properly autosuspend
4246def setUSBDevicesAuto():
4247 rootCheck(True)
4248 for dirname, dirnames, filenames in os.walk('/sys/devices'):
4249 if(re.match('.*/usb[0-9]*.*', dirname) and
4250 'idVendor' in filenames and 'idProduct' in filenames):
4251 call('echo auto > %s/power/control' % dirname, shell=True)
4252 name = dirname.split('/')[-1]
4253 desc = Popen(['cat', '%s/product' % dirname],
4254 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
4255 ctrl = Popen(['cat', '%s/power/control' % dirname],
4256 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
4257 print('control is %s for %6s: %s' % (ctrl, name, desc))
4258
4259# Function: yesno
4260# Description:
4261# Print out an equivalent Y or N for a set of known parameter values
4262# Output:
4263# 'Y', 'N', or ' ' if the value is unknown
4264def yesno(val):
4265 yesvals = ['auto', 'enabled', 'active', '1']
4266 novals = ['on', 'disabled', 'suspended', 'forbidden', 'unsupported']
4267 if val in yesvals:
4268 return 'Y'
4269 elif val in novals:
4270 return 'N'
4271 return ' '
4272
4273# Function: ms2nice
4274# Description:
4275# Print out a very concise time string in minutes and seconds
4276# Output:
4277# The time string, e.g. "1901m16s"
4278def ms2nice(val):
4279 ms = 0
4280 try:
4281 ms = int(val)
4282 except:
4283 return 0.0
4284 m = ms / 60000
4285 s = (ms / 1000) - (m * 60)
4286 return '%3dm%2ds' % (m, s)
4287
4288# Function: detectUSB
4289# Description:
4290# Detect all the USB hosts and devices currently connected and add
4291# a list of USB device names to sysvals for better timeline readability
4292def detectUSB():
4293 field = {'idVendor':'', 'idProduct':'', 'product':'', 'speed':''}
4294 power = {'async':'', 'autosuspend':'', 'autosuspend_delay_ms':'',
4295 'control':'', 'persist':'', 'runtime_enabled':'',
4296 'runtime_status':'', 'runtime_usage':'',
4297 'runtime_active_time':'',
4298 'runtime_suspended_time':'',
4299 'active_duration':'',
4300 'connected_duration':''}
4301
4302 print('LEGEND')
4303 print('---------------------------------------------------------------------------------------------')
4304 print(' A = async/sync PM queue Y/N D = autosuspend delay (seconds)')
4305 print(' S = autosuspend Y/N rACTIVE = runtime active (min/sec)')
4306 print(' P = persist across suspend Y/N rSUSPEN = runtime suspend (min/sec)')
4307 print(' E = runtime suspend enabled/forbidden Y/N ACTIVE = active duration (min/sec)')
4308 print(' R = runtime status active/suspended Y/N CONNECT = connected duration (min/sec)')
4309 print(' U = runtime usage count')
4310 print('---------------------------------------------------------------------------------------------')
4311 print(' NAME ID DESCRIPTION SPEED A S P E R U D rACTIVE rSUSPEN ACTIVE CONNECT')
4312 print('---------------------------------------------------------------------------------------------')
4313
4314 for dirname, dirnames, filenames in os.walk('/sys/devices'):
4315 if(re.match('.*/usb[0-9]*.*', dirname) and
4316 'idVendor' in filenames and 'idProduct' in filenames):
4317 for i in field:
4318 field[i] = Popen(['cat', '%s/%s' % (dirname, i)],
4319 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
4320 name = dirname.split('/')[-1]
4321 for i in power:
4322 power[i] = Popen(['cat', '%s/power/%s' % (dirname, i)],
4323 stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
4324 if(re.match('usb[0-9]*', name)):
4325 first = '%-8s' % name
4326 else:
4327 first = '%8s' % name
4328 print('%s [%s:%s] %-20s %-4s %1s %1s %1s %1s %1s %1s %1s %s %s %s %s' % \
4329 (first, field['idVendor'], field['idProduct'], \
4330 field['product'][0:20], field['speed'], \
4331 yesno(power['async']), \
4332 yesno(power['control']), \
4333 yesno(power['persist']), \
4334 yesno(power['runtime_enabled']), \
4335 yesno(power['runtime_status']), \
4336 power['runtime_usage'], \
4337 power['autosuspend'], \
4338 ms2nice(power['runtime_active_time']), \
4339 ms2nice(power['runtime_suspended_time']), \
4340 ms2nice(power['active_duration']), \
4341 ms2nice(power['connected_duration'])))
4342
4343# Function: devProps
4344# Description:
4345# Retrieve a list of properties for all devices in the trace log
4346def devProps(data=0):
4347 props = dict()
4348
4349 if data:
4350 idx = data.index(': ') + 2
4351 if idx >= len(data):
4352 return
4353 devlist = data[idx:].split(';')
4354 for dev in devlist:
4355 f = dev.split(',')
4356 if len(f) < 3:
4357 continue
4358 dev = f[0]
4359 props[dev] = DevProps()
4360 props[dev].altname = f[1]
4361 if int(f[2]):
4362 props[dev].async = True
4363 else:
4364 props[dev].async = False
4365 sysvals.devprops = props
4366 if sysvals.suspendmode == 'command' and 'testcommandstring' in props:
4367 sysvals.testcommand = props['testcommandstring'].altname
4368 return
4369
4370 if(os.path.exists(sysvals.ftracefile) == False):
4371 doError('%s does not exist' % sysvals.ftracefile)
4372
4373 # first get the list of devices we need properties for
4374 msghead = 'Additional data added by AnalyzeSuspend'
4375 alreadystamped = False
4376 tp = TestProps()
4377 tf = open(sysvals.ftracefile, 'r')
4378 for line in tf:
4379 if msghead in line:
4380 alreadystamped = True
4381 continue
4382 # determine the trace data type (required for further parsing)
4383 m = re.match(sysvals.tracertypefmt, line)
4384 if(m):
4385 tp.setTracerType(m.group('t'))
4386 continue
4387 # parse only valid lines, if this is not one move on
4388 m = re.match(tp.ftrace_line_fmt, line)
4389 if(not m or 'device_pm_callback_start' not in line):
4390 continue
4391 m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg'));
4392 if(not m):
4393 continue
4394 dev = m.group('d')
4395 if dev not in props:
4396 props[dev] = DevProps()
4397 tf.close()
4398
4399 if not alreadystamped and sysvals.suspendmode == 'command':
4400 out = '#\n# '+msghead+'\n# Device Properties: '
4401 out += 'testcommandstring,%s,0;' % (sysvals.testcommand)
4402 with open(sysvals.ftracefile, 'a') as fp:
4403 fp.write(out+'\n')
4404 sysvals.devprops = props
4405 return
4406
4407 # now get the syspath for each of our target devices
4408 for dirname, dirnames, filenames in os.walk('/sys/devices'):
4409 if(re.match('.*/power', dirname) and 'async' in filenames):
4410 dev = dirname.split('/')[-2]
4411 if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)):
4412 props[dev].syspath = dirname[:-6]
4413
4414 # now fill in the properties for our target devices
4415 for dev in props:
4416 dirname = props[dev].syspath
4417 if not dirname or not os.path.exists(dirname):
4418 continue
4419 with open(dirname+'/power/async') as fp:
4420 text = fp.read()
4421 props[dev].async = False
4422 if 'enabled' in text:
4423 props[dev].async = True
4424 fields = os.listdir(dirname)
4425 if 'product' in fields:
4426 with open(dirname+'/product') as fp:
4427 props[dev].altname = fp.read()
4428 elif 'name' in fields:
4429 with open(dirname+'/name') as fp:
4430 props[dev].altname = fp.read()
4431 elif 'model' in fields:
4432 with open(dirname+'/model') as fp:
4433 props[dev].altname = fp.read()
4434 elif 'description' in fields:
4435 with open(dirname+'/description') as fp:
4436 props[dev].altname = fp.read()
4437 elif 'id' in fields:
4438 with open(dirname+'/id') as fp:
4439 props[dev].altname = fp.read()
4440 elif 'idVendor' in fields and 'idProduct' in fields:
4441 idv, idp = '', ''
4442 with open(dirname+'/idVendor') as fp:
4443 idv = fp.read().strip()
4444 with open(dirname+'/idProduct') as fp:
4445 idp = fp.read().strip()
4446 props[dev].altname = '%s:%s' % (idv, idp)
4447
4448 if props[dev].altname:
4449 out = props[dev].altname.strip().replace('\n', ' ')
4450 out = out.replace(',', ' ')
4451 out = out.replace(';', ' ')
4452 props[dev].altname = out
4453
4454 # and now write the data to the ftrace file
4455 if not alreadystamped:
4456 out = '#\n# '+msghead+'\n# Device Properties: '
4457 for dev in sorted(props):
4458 out += props[dev].out(dev)
4459 with open(sysvals.ftracefile, 'a') as fp:
4460 fp.write(out+'\n')
4461
4462 sysvals.devprops = props
4463
4464# Function: getModes
4465# Description:
4466# Determine the supported power modes on this system
4467# Output:
4468# A string list of the available modes
4469def getModes():
4470 modes = ''
4471 if(os.path.exists(sysvals.powerfile)):
4472 fp = open(sysvals.powerfile, 'r')
4473 modes = string.split(fp.read())
4474 fp.close()
4475 return modes
4476
4477# Function: getFPDT
4478# Description:
4479# Read the acpi bios tables and pull out FPDT, the firmware data
4480# Arguments:
4481# output: True to output the info to stdout, False otherwise
4482def getFPDT(output):
4483 rectype = {}
4484 rectype[0] = 'Firmware Basic Boot Performance Record'
4485 rectype[1] = 'S3 Performance Table Record'
4486 prectype = {}
4487 prectype[0] = 'Basic S3 Resume Performance Record'
4488 prectype[1] = 'Basic S3 Suspend Performance Record'
4489
4490 rootCheck(True)
4491 if(not os.path.exists(sysvals.fpdtpath)):
4492 if(output):
4493 doError('file does not exist: %s' % sysvals.fpdtpath)
4494 return False
4495 if(not os.access(sysvals.fpdtpath, os.R_OK)):
4496 if(output):
4497 doError('file is not readable: %s' % sysvals.fpdtpath)
4498 return False
4499 if(not os.path.exists(sysvals.mempath)):
4500 if(output):
4501 doError('file does not exist: %s' % sysvals.mempath)
4502 return False
4503 if(not os.access(sysvals.mempath, os.R_OK)):
4504 if(output):
4505 doError('file is not readable: %s' % sysvals.mempath)
4506 return False
4507
4508 fp = open(sysvals.fpdtpath, 'rb')
4509 buf = fp.read()
4510 fp.close()
4511
4512 if(len(buf) < 36):
4513 if(output):
4514 doError('Invalid FPDT table data, should '+\
4515 'be at least 36 bytes')
4516 return False
4517
4518 table = struct.unpack('4sIBB6s8sI4sI', buf[0:36])
4519 if(output):
4520 print('')
4521 print('Firmware Performance Data Table (%s)' % table[0])
4522 print(' Signature : %s' % table[0])
4523 print(' Table Length : %u' % table[1])
4524 print(' Revision : %u' % table[2])
4525 print(' Checksum : 0x%x' % table[3])
4526 print(' OEM ID : %s' % table[4])
4527 print(' OEM Table ID : %s' % table[5])
4528 print(' OEM Revision : %u' % table[6])
4529 print(' Creator ID : %s' % table[7])
4530 print(' Creator Revision : 0x%x' % table[8])
4531 print('')
4532
4533 if(table[0] != 'FPDT'):
4534 if(output):
4535 doError('Invalid FPDT table')
4536 return False
4537 if(len(buf) <= 36):
4538 return False
4539 i = 0
4540 fwData = [0, 0]
4541 records = buf[36:]
4542 fp = open(sysvals.mempath, 'rb')
4543 while(i < len(records)):
4544 header = struct.unpack('HBB', records[i:i+4])
4545 if(header[0] not in rectype):
4546 i += header[1]
4547 continue
4548 if(header[1] != 16):
4549 i += header[1]
4550 continue
4551 addr = struct.unpack('Q', records[i+8:i+16])[0]
4552 try:
4553 fp.seek(addr)
4554 first = fp.read(8)
4555 except:
4556 if(output):
4557 print('Bad address 0x%x in %s' % (addr, sysvals.mempath))
4558 return [0, 0]
4559 rechead = struct.unpack('4sI', first)
4560 recdata = fp.read(rechead[1]-8)
4561 if(rechead[0] == 'FBPT'):
4562 record = struct.unpack('HBBIQQQQQ', recdata)
4563 if(output):
4564 print('%s (%s)' % (rectype[header[0]], rechead[0]))
4565 print(' Reset END : %u ns' % record[4])
4566 print(' OS Loader LoadImage Start : %u ns' % record[5])
4567 print(' OS Loader StartImage Start : %u ns' % record[6])
4568 print(' ExitBootServices Entry : %u ns' % record[7])
4569 print(' ExitBootServices Exit : %u ns' % record[8])
4570 elif(rechead[0] == 'S3PT'):
4571 if(output):
4572 print('%s (%s)' % (rectype[header[0]], rechead[0]))
4573 j = 0
4574 while(j < len(recdata)):
4575 prechead = struct.unpack('HBB', recdata[j:j+4])
4576 if(prechead[0] not in prectype):
4577 continue
4578 if(prechead[0] == 0):
4579 record = struct.unpack('IIQQ', recdata[j:j+prechead[1]])
4580 fwData[1] = record[2]
4581 if(output):
4582 print(' %s' % prectype[prechead[0]])
4583 print(' Resume Count : %u' % \
4584 record[1])
4585 print(' FullResume : %u ns' % \
4586 record[2])
4587 print(' AverageResume : %u ns' % \
4588 record[3])
4589 elif(prechead[0] == 1):
4590 record = struct.unpack('QQ', recdata[j+4:j+prechead[1]])
4591 fwData[0] = record[1] - record[0]
4592 if(output):
4593 print(' %s' % prectype[prechead[0]])
4594 print(' SuspendStart : %u ns' % \
4595 record[0])
4596 print(' SuspendEnd : %u ns' % \
4597 record[1])
4598 print(' SuspendTime : %u ns' % \
4599 fwData[0])
4600 j += prechead[1]
4601 if(output):
4602 print('')
4603 i += header[1]
4604 fp.close()
4605 return fwData
4606
4607# Function: statusCheck
4608# Description:
4609# Verify that the requested command and options will work, and
4610# print the results to the terminal
4611# Output:
4612# True if the test will work, False if not
4613def statusCheck(probecheck=False):
4614 status = True
4615
4616 print('Checking this system (%s)...' % platform.node())
4617
4618 # check we have root access
4619 res = sysvals.colorText('NO (No features of this tool will work!)')
4620 if(rootCheck(False)):
4621 res = 'YES'
4622 print(' have root access: %s' % res)
4623 if(res != 'YES'):
4624 print(' Try running this script with sudo')
4625 return False
4626
4627 # check sysfs is mounted
4628 res = sysvals.colorText('NO (No features of this tool will work!)')
4629 if(os.path.exists(sysvals.powerfile)):
4630 res = 'YES'
4631 print(' is sysfs mounted: %s' % res)
4632 if(res != 'YES'):
4633 return False
4634
4635 # check target mode is a valid mode
4636 if sysvals.suspendmode != 'command':
4637 res = sysvals.colorText('NO')
4638 modes = getModes()
4639 if(sysvals.suspendmode in modes):
4640 res = 'YES'
4641 else:
4642 status = False
4643 print(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res))
4644 if(res == 'NO'):
4645 print(' valid power modes are: %s' % modes)
4646 print(' please choose one with -m')
4647
4648 # check if ftrace is available
4649 res = sysvals.colorText('NO')
4650 ftgood = sysvals.verifyFtrace()
4651 if(ftgood):
4652 res = 'YES'
4653 elif(sysvals.usecallgraph):
4654 status = False
4655 print(' is ftrace supported: %s' % res)
4656
4657 # check if kprobes are available
4658 res = sysvals.colorText('NO')
4659 sysvals.usekprobes = sysvals.verifyKprobes()
4660 if(sysvals.usekprobes):
4661 res = 'YES'
4662 else:
4663 sysvals.usedevsrc = False
4664 print(' are kprobes supported: %s' % res)
4665
4666 # what data source are we using
4667 res = 'DMESG'
4668 if(ftgood):
4669 sysvals.usetraceeventsonly = True
4670 sysvals.usetraceevents = False
4671 for e in sysvals.traceevents:
4672 check = False
4673 if(os.path.exists(sysvals.epath+e)):
4674 check = True
4675 if(not check):
4676 sysvals.usetraceeventsonly = False
4677 if(e == 'suspend_resume' and check):
4678 sysvals.usetraceevents = True
4679 if(sysvals.usetraceevents and sysvals.usetraceeventsonly):
4680 res = 'FTRACE (all trace events found)'
4681 elif(sysvals.usetraceevents):
4682 res = 'DMESG and FTRACE (suspend_resume trace event found)'
4683 print(' timeline data source: %s' % res)
4684
4685 # check if rtcwake
4686 res = sysvals.colorText('NO')
4687 if(sysvals.rtcpath != ''):
4688 res = 'YES'
4689 elif(sysvals.rtcwake):
4690 status = False
4691 print(' is rtcwake supported: %s' % res)
4692
4693 if not probecheck:
4694 return status
4695
4696 # verify kprobes
4697 if sysvals.usekprobes:
4698 for name in sysvals.tracefuncs:
4699 sysvals.defaultKprobe(name, sysvals.tracefuncs[name])
4700 if sysvals.usedevsrc:
4701 for name in sysvals.dev_tracefuncs:
4702 sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name])
4703 sysvals.addKprobes(True)
4704
4705 return status
4706
4707# Function: doError
4708# Description:
4709# generic error function for catastrphic failures
4710# Arguments:
4711# msg: the error message to print
4712# help: True if printHelp should be called after, False otherwise
4713def doError(msg, help=False):
4714 if(help == True):
4715 printHelp()
4716 print('ERROR: %s\n') % msg
4717 sys.exit()
4718
4719# Function: rootCheck
4720# Description:
4721# quick check to see if we have root access
4722def rootCheck(fatal):
4723 if(os.access(sysvals.powerfile, os.W_OK)):
4724 return True
4725 if fatal:
4726 doError('This command requires sysfs mount and root access')
4727 return False
4728
4729# Function: getArgInt
4730# Description:
4731# pull out an integer argument from the command line with checks
4732def getArgInt(name, args, min, max, main=True):
4733 if main:
4734 try:
4735 arg = args.next()
4736 except:
4737 doError(name+': no argument supplied', True)
4738 else:
4739 arg = args
4740 try:
4741 val = int(arg)
4742 except:
4743 doError(name+': non-integer value given', True)
4744 if(val < min or val > max):
4745 doError(name+': value should be between %d and %d' % (min, max), True)
4746 return val
4747
4748# Function: getArgFloat
4749# Description:
4750# pull out a float argument from the command line with checks
4751def getArgFloat(name, args, min, max, main=True):
4752 if main:
4753 try:
4754 arg = args.next()
4755 except:
4756 doError(name+': no argument supplied', True)
4757 else:
4758 arg = args
4759 try:
4760 val = float(arg)
4761 except:
4762 doError(name+': non-numerical value given', True)
4763 if(val < min or val > max):
4764 doError(name+': value should be between %f and %f' % (min, max), True)
4765 return val
4766
4767def processData():
4768 print('PROCESSING DATA')
4769 if(sysvals.usetraceeventsonly):
4770 testruns = parseTraceLog()
4771 if sysvals.dmesgfile:
4772 dmesgtext = loadKernelLog(True)
4773 for data in testruns:
4774 data.extractErrorInfo(dmesgtext)
4775 else:
4776 testruns = loadKernelLog()
4777 for data in testruns:
4778 parseKernelLog(data)
4779 if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)):
4780 appendIncompleteTraceLog(testruns)
4781 createHTML(testruns)
4782
4783# Function: rerunTest
4784# Description:
4785# generate an output from an existing set of ftrace/dmesg logs
4786def rerunTest():
4787 if sysvals.ftracefile:
4788 doesTraceLogHaveTraceEvents()
4789 if not sysvals.dmesgfile and not sysvals.usetraceeventsonly:
4790 doError('recreating this html output requires a dmesg file')
4791 sysvals.setOutputFile()
4792 vprint('Output file: %s' % sysvals.htmlfile)
4793 if(os.path.exists(sysvals.htmlfile) and not os.access(sysvals.htmlfile, os.W_OK)):
4794 doError('missing permission to write to %s' % sysvals.htmlfile)
4795 processData()
4796
4797# Function: runTest
4798# Description:
4799# execute a suspend/resume, gather the logs, and generate the output
4800def runTest(subdir, testpath=''):
4801 # prepare for the test
4802 sysvals.initFtrace()
4803 sysvals.initTestOutput(subdir, testpath)
4804 vprint('Output files:\n\t%s\n\t%s\n\t%s' % \
4805 (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile))
4806
4807 # execute the test
4808 executeSuspend()
4809 sysvals.cleanupFtrace()
4810 processData()
4811
4812 # if running as root, change output dir owner to sudo_user
4813 if os.path.isdir(sysvals.testdir) and os.getuid() == 0 and \
4814 'SUDO_USER' in os.environ:
4815 cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1'
4816 call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True)
4817
4818def find_in_html(html, strs, div=False):
4819 for str in strs:
4820 l = len(str)
4821 i = html.find(str)
4822 if i >= 0:
4823 break
4824 if i < 0:
4825 return ''
4826 if not div:
4827 return re.search(r'[-+]?\d*\.\d+|\d+', html[i+l:i+l+50]).group()
4828 n = html[i+l:].find('</div>')
4829 if n < 0:
4830 return ''
4831 return html[i+l:i+l+n]
4832
4833# Function: runSummary
4834# Description:
4835# create a summary of tests in a sub-directory
4836def runSummary(subdir, local=True):
4837 inpath = os.path.abspath(subdir)
4838 outpath = inpath
4839 if local:
4840 outpath = os.path.abspath('.')
4841 print('Generating a summary of folder "%s"' % inpath)
4842 testruns = []
4843 for dirname, dirnames, filenames in os.walk(subdir):
4844 for filename in filenames:
4845 if(not re.match('.*.html', filename)):
4846 continue
4847 file = os.path.join(dirname, filename)
4848 html = open(file, 'r').read(10000)
4849 suspend = find_in_html(html,
4850 ['Kernel Suspend: ', 'Kernel Suspend Time: '])
4851 resume = find_in_html(html,
4852 ['Kernel Resume: ', 'Kernel Resume Time: '])
4853 line = find_in_html(html, ['<div class="stamp">'], True)
4854 stmp = line.split()
4855 if not suspend or not resume or len(stmp) < 4:
4856 continue
4857 data = {
4858 'host': stmp[0],
4859 'kernel': stmp[1],
4860 'mode': stmp[2],
4861 'time': string.join(stmp[3:], ' '),
4862 'suspend': suspend,
4863 'resume': resume,
4864 'url': os.path.relpath(file, outpath),
4865 }
4866 if len(stmp) == 7:
4867 data['kernel'] = 'unknown'
4868 data['mode'] = stmp[1]
4869 data['time'] = string.join(stmp[2:], ' ')
4870 testruns.append(data)
4871 outfile = os.path.join(outpath, 'summary.html')
4872 print('Summary file: %s' % outfile)
4873 createHTMLSummarySimple(testruns, outfile, inpath)
4874
4875# Function: checkArgBool
4876# Description:
4877# check if a boolean string value is true or false
4878def checkArgBool(value):
4879 yes = ['1', 'true', 'yes', 'on']
4880 if value.lower() in yes:
4881 return True
4882 return False
4883
4884# Function: configFromFile
4885# Description:
4886# Configure the script via the info in a config file
4887def configFromFile(file):
4888 Config = ConfigParser.ConfigParser()
4889
4890 Config.read(file)
4891 sections = Config.sections()
4892 overridekprobes = False
4893 overridedevkprobes = False
4894 if 'Settings' in sections:
4895 for opt in Config.options('Settings'):
4896 value = Config.get('Settings', opt).lower()
4897 if(opt.lower() == 'verbose'):
4898 sysvals.verbose = checkArgBool(value)
4899 elif(opt.lower() == 'addlogs'):
4900 sysvals.addlogs = checkArgBool(value)
4901 elif(opt.lower() == 'dev'):
4902 sysvals.usedevsrc = checkArgBool(value)
4903 elif(opt.lower() == 'proc'):
4904 sysvals.useprocmon = checkArgBool(value)
4905 elif(opt.lower() == 'x2'):
4906 if checkArgBool(value):
4907 sysvals.execcount = 2
4908 elif(opt.lower() == 'callgraph'):
4909 sysvals.usecallgraph = checkArgBool(value)
4910 elif(opt.lower() == 'override-timeline-functions'):
4911 overridekprobes = checkArgBool(value)
4912 elif(opt.lower() == 'override-dev-timeline-functions'):
4913 overridedevkprobes = checkArgBool(value)
4914 elif(opt.lower() == 'devicefilter'):
4915 sysvals.setDeviceFilter(value)
4916 elif(opt.lower() == 'expandcg'):
4917 sysvals.cgexp = checkArgBool(value)
4918 elif(opt.lower() == 'srgap'):
4919 if checkArgBool(value):
4920 sysvals.srgap = 5
4921 elif(opt.lower() == 'mode'):
4922 sysvals.suspendmode = value
4923 elif(opt.lower() == 'command'):
4924 sysvals.testcommand = value
4925 elif(opt.lower() == 'x2delay'):
4926 sysvals.x2delay = getArgInt('-x2delay', value, 0, 60000, False)
4927 elif(opt.lower() == 'predelay'):
4928 sysvals.predelay = getArgInt('-predelay', value, 0, 60000, False)
4929 elif(opt.lower() == 'postdelay'):
4930 sysvals.postdelay = getArgInt('-postdelay', value, 0, 60000, False)
4931 elif(opt.lower() == 'maxdepth'):
4932 sysvals.max_graph_depth = getArgInt('-maxdepth', value, 0, 1000, False)
4933 elif(opt.lower() == 'rtcwake'):
4934 if value.lower() == 'off':
4935 sysvals.rtcwake = False
4936 else:
4937 sysvals.rtcwake = True
4938 sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False)
4939 elif(opt.lower() == 'timeprec'):
4940 sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False))
4941 elif(opt.lower() == 'mindev'):
4942 sysvals.mindevlen = getArgFloat('-mindev', value, 0.0, 10000.0, False)
4943 elif(opt.lower() == 'callloop-maxgap'):
4944 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', value, 0.0, 1.0, False)
4945 elif(opt.lower() == 'callloop-maxlen'):
4946 sysvals.callloopmaxgap = getArgFloat('-callloop-maxlen', value, 0.0, 1.0, False)
4947 elif(opt.lower() == 'mincg'):
4948 sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False)
4949 elif(opt.lower() == 'output-dir'):
4950 sysvals.setOutputFolder(value)
4951
4952 if sysvals.suspendmode == 'command' and not sysvals.testcommand:
4953 doError('No command supplied for mode "command"')
4954
4955 # compatibility errors
4956 if sysvals.usedevsrc and sysvals.usecallgraph:
4957 doError('-dev is not compatible with -f')
4958 if sysvals.usecallgraph and sysvals.useprocmon:
4959 doError('-proc is not compatible with -f')
4960
4961 if overridekprobes:
4962 sysvals.tracefuncs = dict()
4963 if overridedevkprobes:
4964 sysvals.dev_tracefuncs = dict()
4965
4966 kprobes = dict()
4967 kprobesec = 'dev_timeline_functions_'+platform.machine()
4968 if kprobesec in sections:
4969 for name in Config.options(kprobesec):
4970 text = Config.get(kprobesec, name)
4971 kprobes[name] = (text, True)
4972 kprobesec = 'timeline_functions_'+platform.machine()
4973 if kprobesec in sections:
4974 for name in Config.options(kprobesec):
4975 if name in kprobes:
4976 doError('Duplicate timeline function found "%s"' % (name))
4977 text = Config.get(kprobesec, name)
4978 kprobes[name] = (text, False)
4979
4980 for name in kprobes:
4981 function = name
4982 format = name
4983 color = ''
4984 args = dict()
4985 text, dev = kprobes[name]
4986 data = text.split()
4987 i = 0
4988 for val in data:
4989 # bracketted strings are special formatting, read them separately
4990 if val[0] == '[' and val[-1] == ']':
4991 for prop in val[1:-1].split(','):
4992 p = prop.split('=')
4993 if p[0] == 'color':
4994 try:
4995 color = int(p[1], 16)
4996 color = '#'+p[1]
4997 except:
4998 color = p[1]
4999 continue
5000 # first real arg should be the format string
5001 if i == 0:
5002 format = val
5003 # all other args are actual function args
5004 else:
5005 d = val.split('=')
5006 args[d[0]] = d[1]
5007 i += 1
5008 if not function or not format:
5009 doError('Invalid kprobe: %s' % name)
5010 for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format):
5011 if arg not in args:
5012 doError('Kprobe "%s" is missing argument "%s"' % (name, arg))
5013 if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs):
5014 doError('Duplicate timeline function found "%s"' % (name))
5015
5016 kp = {
5017 'name': name,
5018 'func': function,
5019 'format': format,
5020 sysvals.archargs: args
5021 }
5022 if color:
5023 kp['color'] = color
5024 if dev:
5025 sysvals.dev_tracefuncs[name] = kp
5026 else:
5027 sysvals.tracefuncs[name] = kp
5028
5029# Function: printHelp
5030# Description:
5031# print out the help text
5032def printHelp():
5033 modes = getModes()
5034
5035 print('')
5036 print('%s v%s' % (sysvals.title, sysvals.version))
5037 print('Usage: sudo sleepgraph <options> <commands>')
5038 print('')
5039 print('Description:')
5040 print(' This tool is designed to assist kernel and OS developers in optimizing')
5041 print(' their linux stack\'s suspend/resume time. Using a kernel image built')
5042 print(' with a few extra options enabled, the tool will execute a suspend and')
5043 print(' capture dmesg and ftrace data until resume is complete. This data is')
5044 print(' transformed into a device timeline and an optional callgraph to give')
5045 print(' a detailed view of which devices/subsystems are taking the most')
5046 print(' time in suspend/resume.')
5047 print('')
5048 print(' If no specific command is given, the default behavior is to initiate')
5049 print(' a suspend/resume and capture the dmesg/ftrace output as an html timeline.')
5050 print('')
5051 print(' Generates output files in subdirectory: suspend-mmddyy-HHMMSS')
5052 print(' HTML output: <hostname>_<mode>.html')
5053 print(' raw dmesg output: <hostname>_<mode>_dmesg.txt')
5054 print(' raw ftrace output: <hostname>_<mode>_ftrace.txt')
5055 print('')
5056 print('Options:')
5057 print(' -h Print this help text')
5058 print(' -v Print the current tool version')
5059 print(' -config fn Pull arguments and config options from file fn')
5060 print(' -verbose Print extra information during execution and analysis')
5061 print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode)
5062 print(' -o subdir Override the output subdirectory')
5063 print(' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)')
5064 print(' -addlogs Add the dmesg and ftrace logs to the html output')
5065 print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)')
5066 print(' [advanced]')
5067 print(' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"')
5068 print(' -proc Add usermode process info into the timeline (default: disabled)')
5069 print(' -dev Add kernel function calls and threads to the timeline (default: disabled)')
5070 print(' -x2 Run two suspend/resumes back to back (default: disabled)')
5071 print(' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)')
5072 print(' -predelay t Include t ms delay before 1st suspend (default: 0 ms)')
5073 print(' -postdelay t Include t ms delay after last resume (default: 0 ms)')
5074 print(' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)')
5075 print(' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will')
5076 print(' be created in a new subdirectory with a summary page.')
5077 print(' [debug]')
5078 print(' -f Use ftrace to create device callgraphs (default: disabled)')
5079 print(' -maxdepth N limit the callgraph data to N call levels (default: 0=all)')
5080 print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')
5081 print(' -fadd file Add functions to be graphed in the timeline from a list in a text file')
5082 print(' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names')
5083 print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
5084 print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)')
5085 print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)')
5086 print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)')
5087 print(' [commands]')
5088 print(' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)')
5089 print(' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)')
5090 print(' -summary directory Create a summary of all test in this dir')
5091 print(' -modes List available suspend modes')
5092 print(' -status Test to see if the system is enabled to run this tool')
5093 print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table')
5094 print(' -usbtopo Print out the current USB topology with power info')
5095 print(' -usbauto Enable autosuspend for all connected USB devices')
5096 print(' -flist Print the list of functions currently being captured in ftrace')
5097 print(' -flistall Print all functions capable of being captured in ftrace')
5098 print('')
5099 return True
5100
5101# ----------------- MAIN --------------------
5102# exec start (skipped if script is loaded as library)
5103if __name__ == '__main__':
5104 cmd = ''
5105 cmdarg = ''
5106 multitest = {'run': False, 'count': 0, 'delay': 0}
5107 simplecmds = ['-modes', '-fpdt', '-flist', '-flistall', '-usbtopo', '-usbauto', '-status']
5108 # loop through the command line arguments
5109 args = iter(sys.argv[1:])
5110 for arg in args:
5111 if(arg == '-m'):
5112 try:
5113 val = args.next()
5114 except:
5115 doError('No mode supplied', True)
5116 if val == 'command' and not sysvals.testcommand:
5117 doError('No command supplied for mode "command"', True)
5118 sysvals.suspendmode = val
5119 elif(arg in simplecmds):
5120 cmd = arg[1:]
5121 elif(arg == '-h'):
5122 printHelp()
5123 sys.exit()
5124 elif(arg == '-v'):
5125 print("Version %s" % sysvals.version)
5126 sys.exit()
5127 elif(arg == '-x2'):
5128 sysvals.execcount = 2
5129 elif(arg == '-x2delay'):
5130 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000)
5131 elif(arg == '-predelay'):
5132 sysvals.predelay = getArgInt('-predelay', args, 0, 60000)
5133 elif(arg == '-postdelay'):
5134 sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000)
5135 elif(arg == '-f'):
5136 sysvals.usecallgraph = True
5137 elif(arg == '-addlogs'):
5138 sysvals.addlogs = True
5139 elif(arg == '-verbose'):
5140 sysvals.verbose = True
5141 elif(arg == '-proc'):
5142 sysvals.useprocmon = True
5143 elif(arg == '-dev'):
5144 sysvals.usedevsrc = True
5145 elif(arg == '-maxdepth'):
5146 sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000)
5147 elif(arg == '-rtcwake'):
5148 try:
5149 val = args.next()
5150 except:
5151 doError('No rtcwake time supplied', True)
5152 if val.lower() == 'off':
5153 sysvals.rtcwake = False
5154 else:
5155 sysvals.rtcwake = True
5156 sysvals.rtcwaketime = getArgInt('-rtcwake', val, 0, 3600, False)
5157 elif(arg == '-timeprec'):
5158 sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6))
5159 elif(arg == '-mindev'):
5160 sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0)
5161 elif(arg == '-mincg'):
5162 sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0)
5163 elif(arg == '-cgtest'):
5164 sysvals.cgtest = getArgInt('-cgtest', args, 0, 1)
5165 elif(arg == '-cgphase'):
5166 try:
5167 val = args.next()
5168 except:
5169 doError('No phase name supplied', True)
5170 d = Data(0)
5171 if val not in d.phases:
5172 doError('Invalid phase, valid phaess are %s' % d.phases, True)
5173 sysvals.cgphase = val
5174 elif(arg == '-callloop-maxgap'):
5175 sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0)
5176 elif(arg == '-callloop-maxlen'):
5177 sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0)
5178 elif(arg == '-cmd'):
5179 try:
5180 val = args.next()
5181 except:
5182 doError('No command string supplied', True)
5183 sysvals.testcommand = val
5184 sysvals.suspendmode = 'command'
5185 elif(arg == '-expandcg'):
5186 sysvals.cgexp = True
5187 elif(arg == '-srgap'):
5188 sysvals.srgap = 5
5189 elif(arg == '-multi'):
5190 multitest['run'] = True
5191 multitest['count'] = getArgInt('-multi n (exec count)', args, 2, 1000000)
5192 multitest['delay'] = getArgInt('-multi d (delay between tests)', args, 0, 3600)
5193 elif(arg == '-o'):
5194 try:
5195 val = args.next()
5196 except:
5197 doError('No subdirectory name supplied', True)
5198 sysvals.setOutputFolder(val)
5199 elif(arg == '-config'):
5200 try:
5201 val = args.next()
5202 except:
5203 doError('No text file supplied', True)
5204 if(os.path.exists(val) == False):
5205 doError('%s does not exist' % val)
5206 configFromFile(val)
5207 elif(arg == '-fadd'):
5208 try:
5209 val = args.next()
5210 except:
5211 doError('No text file supplied', True)
5212 if(os.path.exists(val) == False):
5213 doError('%s does not exist' % val)
5214 sysvals.addFtraceFilterFunctions(val)
5215 elif(arg == '-dmesg'):
5216 try:
5217 val = args.next()
5218 except:
5219 doError('No dmesg file supplied', True)
5220 sysvals.notestrun = True
5221 sysvals.dmesgfile = val
5222 if(os.path.exists(sysvals.dmesgfile) == False):
5223 doError('%s does not exist' % sysvals.dmesgfile)
5224 elif(arg == '-ftrace'):
5225 try:
5226 val = args.next()
5227 except:
5228 doError('No ftrace file supplied', True)
5229 sysvals.notestrun = True
5230 sysvals.ftracefile = val
5231 if(os.path.exists(sysvals.ftracefile) == False):
5232 doError('%s does not exist' % sysvals.ftracefile)
5233 elif(arg == '-summary'):
5234 try:
5235 val = args.next()
5236 except:
5237 doError('No directory supplied', True)
5238 cmd = 'summary'
5239 cmdarg = val
5240 sysvals.notestrun = True
5241 if(os.path.isdir(val) == False):
5242 doError('%s is not accesible' % val)
5243 elif(arg == '-filter'):
5244 try:
5245 val = args.next()
5246 except:
5247 doError('No devnames supplied', True)
5248 sysvals.setDeviceFilter(val)
5249 else:
5250 doError('Invalid argument: '+arg, True)
5251
5252 # compatibility errors
5253 if(sysvals.usecallgraph and sysvals.usedevsrc):
5254 doError('-dev is not compatible with -f')
5255 if(sysvals.usecallgraph and sysvals.useprocmon):
5256 doError('-proc is not compatible with -f')
5257
5258 # callgraph size cannot exceed device size
5259 if sysvals.mincglen < sysvals.mindevlen:
5260 sysvals.mincglen = sysvals.mindevlen
5261
5262 # just run a utility command and exit
5263 if(cmd != ''):
5264 if(cmd == 'status'):
5265 statusCheck(True)
5266 elif(cmd == 'fpdt'):
5267 getFPDT(True)
5268 elif(cmd == 'usbtopo'):
5269 detectUSB()
5270 elif(cmd == 'modes'):
5271 print getModes()
5272 elif(cmd == 'flist'):
5273 sysvals.getFtraceFilterFunctions(True)
5274 elif(cmd == 'flistall'):
5275 sysvals.getFtraceFilterFunctions(False)
5276 elif(cmd == 'usbauto'):
5277 setUSBDevicesAuto()
5278 elif(cmd == 'summary'):
5279 runSummary(cmdarg, True)
5280 sys.exit()
5281
5282 # if instructed, re-analyze existing data files
5283 if(sysvals.notestrun):
5284 rerunTest()
5285 sys.exit()
5286
5287 # verify that we can run a test
5288 if(not statusCheck()):
5289 print('Check FAILED, aborting the test run!')
5290 sys.exit()
5291
5292 if multitest['run']:
5293 # run multiple tests in a separate subdirectory
5294 s = 'x%d' % multitest['count']
5295 if not sysvals.outdir:
5296 sysvals.outdir = datetime.now().strftime('suspend-'+s+'-%m%d%y-%H%M%S')
5297 if not os.path.isdir(sysvals.outdir):
5298 os.mkdir(sysvals.outdir)
5299 for i in range(multitest['count']):
5300 if(i != 0):
5301 print('Waiting %d seconds...' % (multitest['delay']))
5302 time.sleep(multitest['delay'])
5303 print('TEST (%d/%d) START' % (i+1, multitest['count']))
5304 runTest(sysvals.outdir)
5305 print('TEST (%d/%d) COMPLETE' % (i+1, multitest['count']))
5306 runSummary(sysvals.outdir, False)
5307 else:
5308 # run the test in the current directory
5309 runTest('.', sysvals.outdir)
diff --git a/tools/power/pm-graph/bootgraph.8 b/tools/power/pm-graph/bootgraph.8
new file mode 100644
index 000000000000..55272a67b0e7
--- /dev/null
+++ b/tools/power/pm-graph/bootgraph.8
@@ -0,0 +1,132 @@
1.TH BOOTGRAPH 8
2.SH NAME
3bootgraph \- Kernel boot timing analysis
4.SH SYNOPSIS
5.ft B
6.B bootgraph
7.RB [ OPTIONS ]
8.RB [ COMMAND ]
9.SH DESCRIPTION
10\fBbootgraph \fP reads the dmesg log from kernel boot and
11creates an html representation of the initcall timeline up to the start
12of the init process.
13.PP
14If no specific command is given, the tool reads the current dmesg log and
15outputs bootgraph.html.
16.PP
17The tool can also augment the timeline with ftrace data on custom target
18functions as well as full trace callgraphs.
19.SH OPTIONS
20.TP
21\fB-h\fR
22Print this help text
23.TP
24\fB-v\fR
25Print the current tool version
26.TP
27\fB-addlogs\fR
28Add the dmesg log to the html output. It will be viewable by
29clicking a button in the timeline.
30.TP
31\fB-o \fIfile\fR
32Override the HTML output filename (default: bootgraph.html)
33.SS "Ftrace Debug"
34.TP
35\fB-f\fR
36Use ftrace to add function detail (default: disabled)
37.TP
38\fB-callgraph\fR
39Use ftrace to create initcall callgraphs (default: disabled). If -filter
40is not used there will be one callgraph per initcall. This can produce
41very large outputs, i.e. 10MB - 100MB.
42.TP
43\fB-maxdepth \fIlevel\fR
44limit the callgraph trace depth to \fIlevel\fR (default: 2). This is
45the best way to limit the output size when using -callgraph.
46.TP
47\fB-mincg \fIt\fR
48Discard all callgraphs shorter than \fIt\fR milliseconds (default: 0=all).
49This reduces the html file size as there can be many tiny callgraphs
50which are barely visible in the timeline.
51The value is a float: e.g. 0.001 represents 1 us.
52.TP
53\fB-timeprec \fIn\fR
54Number of significant digits in timestamps (0:S, 3:ms, [6:us])
55.TP
56\fB-expandcg\fR
57pre-expand the callgraph data in the html output (default: disabled)
58.TP
59\fB-filter \fI"func1,func2,..."\fR
60Instead of tracing each initcall, trace a custom list of functions (default: do_one_initcall)
61
62.SH COMMANDS
63.TP
64\fB-reboot\fR
65Reboot the machine and generate a new timeline automatically. Works in 4 steps.
66 1. updates grub with the required kernel parameters
67 2. installs a cron job which re-runs the tool after reboot
68 3. reboots the system
69 4. after startup, extracts the data and generates the timeline
70.TP
71\fB-manual\fR
72Show the requirements to generate a new timeline manually. Requires 3 steps.
73 1. append the string to the kernel command line via your native boot manager.
74 2. reboot the system
75 3. after startup, re-run the tool with the same arguments and no command
76.TP
77\fB-dmesg \fIfile\fR
78Create HTML output from an existing dmesg file.
79.TP
80\fB-ftrace \fIfile\fR
81Create HTML output from an existing ftrace file (used with -dmesg).
82.TP
83\fB-flistall\fR
84Print all ftrace functions capable of being captured. These are all the
85possible values you can add to trace via the -filter argument.
86
87.SH EXAMPLES
88Create a timeline using the current dmesg log.
89.IP
90\f(CW$ bootgraph\fR
91.PP
92Create a timeline using the current dmesg and ftrace log.
93.IP
94\f(CW$ bootgraph -callgraph\fR
95.PP
96Create a timeline using the current dmesg, add the log to the html and change the name.
97.IP
98\f(CW$ bootgraph -addlogs -o myboot.html\fR
99.PP
100Capture a new boot timeline by automatically rebooting the machine.
101.IP
102\f(CW$ sudo bootgraph -reboot -addlogs -o latestboot.html\fR
103.PP
104Capture a new boot timeline with function trace data.
105.IP
106\f(CW$ sudo bootgraph -reboot -f\fR
107.PP
108Capture a new boot timeline with trace & callgraph data. Skip callgraphs smaller than 5ms.
109.IP
110\f(CW$ sudo bootgraph -reboot -callgraph -mincg 5\fR
111.PP
112Capture a new boot timeline with callgraph data over custom functions.
113.IP
114\f(CW$ sudo bootgraph -reboot -callgraph -filter "acpi_ps_parse_aml,msleep"\fR
115.PP
116Capture a brand new boot timeline with manual reboot.
117.IP
118\f(CW$ sudo bootgraph -callgraph -manual\fR
119.IP
120\f(CW$ vi /etc/default/grub # add the CMDLINE string to your kernel params\fR
121.IP
122\f(CW$ sudo reboot # reboot the machine\fR
123.IP
124\f(CW$ sudo bootgraph -callgraph # re-run the tool after restart\fR
125.PP
126
127.SH "SEE ALSO"
128dmesg(1), update-grub(8), crontab(1), reboot(8)
129.PP
130.SH AUTHOR
131.nf
132Written by Todd Brandt <todd.e.brandt@linux.intel.com>
diff --git a/tools/power/pm-graph/sleepgraph.8 b/tools/power/pm-graph/sleepgraph.8
new file mode 100644
index 000000000000..610e72ebbc06
--- /dev/null
+++ b/tools/power/pm-graph/sleepgraph.8
@@ -0,0 +1,243 @@
1.TH SLEEPGRAPH 8
2.SH NAME
3sleepgraph \- Suspend/Resume timing analysis
4.SH SYNOPSIS
5.ft B
6.B sleepgraph
7.RB [ OPTIONS ]
8.RB [ COMMAND ]
9.SH DESCRIPTION
10\fBsleepgraph \fP is designed to assist kernel and OS developers
11in optimizing their linux stack's suspend/resume time. Using a kernel
12image built with a few extra options enabled, the tool will execute a
13suspend and capture dmesg and ftrace data until resume is complete.
14This data is transformed into a device timeline and an optional
15callgraph to give a detailed view of which devices/subsystems are
16taking the most time in suspend/resume.
17.PP
18If no specific command is given, the default behavior is to initiate
19a suspend/resume.
20.PP
21Generates output files in subdirectory: suspend-yymmdd-HHMMSS
22 html timeline : <hostname>_<mode>.html
23 raw dmesg file : <hostname>_<mode>_dmesg.txt
24 raw ftrace file : <hostname>_<mode>_ftrace.txt
25.SH OPTIONS
26.TP
27\fB-h\fR
28Print the help text.
29.TP
30\fB-v\fR
31Print the current tool version.
32.TP
33\fB-verbose\fR
34Print extra information during execution and analysis.
35.TP
36\fB-config \fIfile\fR
37Pull arguments and config options from a file.
38.TP
39\fB-m \fImode\fR
40Mode to initiate for suspend e.g. standby, freeze, mem (default: mem).
41.TP
42\fB-o \fIsubdir\fR
43Override the output subdirectory. Use {date}, {time}, {hostname} for current values.
44.sp
45e.g. suspend-{hostname}-{date}-{time}
46.TP
47\fB-rtcwake \fIt\fR | off
48Use rtcwake to autoresume after \fIt\fR seconds (default: 15). Set t to "off" to
49disable rtcwake and require a user keypress to resume.
50.TP
51\fB-addlogs\fR
52Add the dmesg and ftrace logs to the html output. They will be viewable by
53clicking buttons in the timeline.
54
55.SS "Advanced"
56.TP
57\fB-cmd \fIstr\fR
58Run the timeline over a custom suspend command, e.g. pm-suspend. By default
59the tool forces suspend via /sys/power/state so this allows testing over
60an OS's official suspend method. The output file will change to
61hostname_command.html and will autodetect which suspend mode was triggered.
62.TP
63\fB-filter \fI"d1,d2,..."\fR
64Filter out all but these device callbacks. These strings can be device names
65or module names. e.g. 0000:00:02.0, ata5, i915, usb, etc.
66.TP
67\fB-mindev \fIt\fR
68Discard all device callbacks shorter than \fIt\fR milliseconds (default: 0.0).
69This reduces the html file size as there can be many tiny callbacks which are barely
70visible. The value is a float: e.g. 0.001 represents 1 us.
71.TP
72\fB-proc\fR
73Add usermode process info into the timeline (default: disabled).
74.TP
75\fB-dev\fR
76Add kernel source calls and threads to the timeline (default: disabled).
77.TP
78\fB-x2\fR
79Run two suspend/resumes back to back (default: disabled).
80.TP
81\fB-x2delay \fIt\fR
82Include \fIt\fR ms delay between multiple test runs (default: 0 ms).
83.TP
84\fB-predelay \fIt\fR
85Include \fIt\fR ms delay before 1st suspend (default: 0 ms).
86.TP
87\fB-postdelay \fIt\fR
88Include \fIt\fR ms delay after last resume (default: 0 ms).
89.TP
90\fB-multi \fIn d\fR
91Execute \fIn\fR consecutive tests at \fId\fR seconds intervals. The outputs will
92be created in a new subdirectory with a summary page: suspend-xN-{date}-{time}.
93
94.SS "Ftrace Debug"
95.TP
96\fB-f\fR
97Use ftrace to create device callgraphs (default: disabled). This can produce
98very large outputs, i.e. 10MB - 100MB.
99.TP
100\fB-maxdepth \fIlevel\fR
101limit the callgraph trace depth to \fIlevel\fR (default: 0=all). This is
102the best way to limit the output size when using callgraphs via -f.
103.TP
104\fB-expandcg\fR
105pre-expand the callgraph data in the html output (default: disabled)
106.TP
107\fB-fadd \fIfile\fR
108Add functions to be graphed in the timeline from a list in a text file
109.TP
110\fB-mincg \fIt\fR
111Discard all callgraphs shorter than \fIt\fR milliseconds (default: 0.0).
112This reduces the html file size as there can be many tiny callgraphs
113which are barely visible in the timeline.
114The value is a float: e.g. 0.001 represents 1 us.
115.TP
116\fB-cgphase \fIp\fR
117Only show callgraph data for phase \fIp\fR (e.g. suspend_late).
118.TP
119\fB-cgtest \fIn\fR
120In an x2 run, only show callgraph data for test \fIn\fR (e.g. 0 or 1).
121.TP
122\fB-timeprec \fIn\fR
123Number of significant digits in timestamps (0:S, [3:ms], 6:us).
124
125.SH COMMANDS
126.TP
127\fB-ftrace \fIfile\fR
128Create HTML output from an existing ftrace file.
129.TP
130\fB-dmesg \fIfile\fR
131Create HTML output from an existing dmesg file.
132.TP
133\fB-summary \fIindir\fR
134Create a summary page of all tests in \fIindir\fR. Creates summary.html
135in the current folder. The output page is a table of tests with
136suspend and resume values sorted by suspend mode, host, and kernel.
137Includes test averages by mode and links to the test html files.
138.TP
139\fB-modes\fR
140List available suspend modes.
141.TP
142\fB-status\fR
143Test to see if the system is able to run this tool. Use this along
144with any options you intend to use to see if they will work.
145.TP
146\fB-fpdt\fR
147Print out the contents of the ACPI Firmware Performance Data Table.
148.TP
149\fB-usbtopo\fR
150Print out the current USB topology with power info.
151.TP
152\fB-usbauto\fR
153Enable autosuspend for all connected USB devices.
154.TP
155\fB-flist\fR
156Print the list of ftrace functions currently being captured. Functions
157that are not available as symbols in the current kernel are shown in red.
158By default, the tool traces a list of important suspend/resume functions
159in order to better fill out the timeline. If the user has added their own
160with -fadd they will also be checked.
161.TP
162\fB-flistall\fR
163Print all ftrace functions capable of being captured. These are all the
164possible values you can add to trace via the -fadd argument.
165
166.SH EXAMPLES
167.SS "Simple Commands"
168Check which suspend modes are currently supported.
169.IP
170\f(CW$ sleepgraph -modes\fR
171.PP
172Read the Firmware Performance Data Table (FPDT)
173.IP
174\f(CW$ sudo sleepgraph -fpdt\fR
175.PP
176Print out the current USB power topology
177.IP
178\f(CW$ sleepgraph -usbtopo
179.PP
180Verify that you can run a command with a set of arguments
181.IP
182\f(CW$ sudo sleepgraph -f -rtcwake 30 -status
183.PP
184Generate a summary of all timelines in a particular folder.
185.IP
186\f(CW$ sleepgraph -summary ~/workspace/myresults/\fR
187.PP
188Re-generate the html output from a previous run's dmesg and ftrace log.
189.IP
190\f(CW$ sleepgraph -dmesg myhost_mem_dmesg.txt -ftrace myhost_mem_ftrace.txt\fR
191.PP
192
193.SS "Capturing Simple Timelines"
194Execute a mem suspend with a 15 second wakeup. Include the logs in the html.
195.IP
196\f(CW$ sudo sleepgraph -rtcwake 15 -addlogs\fR
197.PP
198Execute a standby with a 15 second wakeup. Change the output folder name.
199.IP
200\f(CW$ sudo sleepgraph -m standby -rtcwake 15 -o "standby-{hostname}-{date}-{time}"\fR
201.PP
202Execute a freeze with no wakeup (require keypress). Change output folder name.
203.IP
204\f(CW$ sudo sleepgraph -m freeze -rtcwake off -o "freeze-{hostname}-{date}-{time}"\fR
205.PP
206
207.SS "Capturing Advanced Timelines"
208Execute a suspend & include dev mode source calls, limit callbacks to 5ms or larger.
209.IP
210\f(CW$ sudo sleepgraph -m mem -rtcwake 15 -dev -mindev 5\fR
211.PP
212Run two suspends back to back, include a 500ms delay before, after, and in between runs.
213.IP
214\f(CW$ sudo sleepgraph -m mem -rtcwake 15 -x2 -predelay 500 -x2delay 500 -postdelay 500\fR
215.PP
216Do a batch run of 10 freezes with 30 seconds delay between runs.
217.IP
218\f(CW$ sudo sleepgraph -m freeze -rtcwake 15 -multi 10 30\fR
219.PP
220Execute a suspend using a custom command.
221.IP
222\f(CW$ sudo sleepgraph -cmd "echo mem > /sys/power/state" -rtcwake 15\fR
223.PP
224
225
226.SS "Capturing Timelines with Callgraph Data"
227Add device callgraphs. Limit the trace depth and only show callgraphs 10ms or larger.
228.IP
229\f(CW$ sudo sleepgraph -m mem -rtcwake 15 -f -maxdepth 5 -mincg 10\fR
230.PP
231Capture a full callgraph across all suspend, then filter the html by a single phase.
232.IP
233\f(CW$ sudo sleepgraph -m mem -rtcwake 15 -f\fR
234.IP
235\f(CW$ sleepgraph -dmesg host_mem_dmesg.txt -ftrace host_mem_ftrace.txt -f -cgphase resume
236.PP
237
238.SH "SEE ALSO"
239dmesg(1)
240.PP
241.SH AUTHOR
242.nf
243Written by Todd Brandt <todd.e.brandt@linux.intel.com>
diff --git a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
index fd706ac0f347..0b24dd9d01ff 100755
--- a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
+++ b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
@@ -353,6 +353,14 @@ def split_csv():
353 os.system('grep -m 1 common_cpu cpu.csv > cpu{:0>3}.csv'.format(index)) 353 os.system('grep -m 1 common_cpu cpu.csv > cpu{:0>3}.csv'.format(index))
354 os.system('grep CPU_{:0>3} cpu.csv >> cpu{:0>3}.csv'.format(index, index)) 354 os.system('grep CPU_{:0>3} cpu.csv >> cpu{:0>3}.csv'.format(index, index))
355 355
356def fix_ownership(path):
357 """Change the owner of the file to SUDO_UID, if required"""
358
359 uid = os.environ.get('SUDO_UID')
360 gid = os.environ.get('SUDO_GID')
361 if uid is not None:
362 os.chown(path, int(uid), int(gid))
363
356def cleanup_data_files(): 364def cleanup_data_files():
357 """ clean up existing data files """ 365 """ clean up existing data files """
358 366
@@ -518,12 +526,16 @@ else:
518 526
519if not os.path.exists('results'): 527if not os.path.exists('results'):
520 os.mkdir('results') 528 os.mkdir('results')
529 # The regular user needs to own the directory, not root.
530 fix_ownership('results')
521 531
522os.chdir('results') 532os.chdir('results')
523if os.path.exists(testname): 533if os.path.exists(testname):
524 print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.') 534 print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.')
525 sys.exit() 535 sys.exit()
526os.mkdir(testname) 536os.mkdir(testname)
537# The regular user needs to own the directory, not root.
538fix_ownership(testname)
527os.chdir(testname) 539os.chdir(testname)
528 540
529# Temporary (or perhaps not) 541# Temporary (or perhaps not)
@@ -566,4 +578,9 @@ plot_scaled_cpu()
566plot_boost_cpu() 578plot_boost_cpu()
567plot_ghz_cpu() 579plot_ghz_cpu()
568 580
581# It is preferrable, but not necessary, that the regular user owns the files, not root.
582for root, dirs, files in os.walk('.'):
583 for f in files:
584 fix_ownership(f)
585
569os.chdir('../../') 586os.chdir('../../')
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index fedca3285326..ccf2a69365cc 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -100,6 +100,8 @@ The system configuration dump (if --quiet is not used) is followed by statistics
100\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. These numbers are from hardware residency counters. 100\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. These numbers are from hardware residency counters.
101\fBCoreTmp\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. 101\fBCoreTmp\fP Degrees Celsius reported by the per-core Digital Thermal Sensor.
102\fBPkgTtmp\fP Degrees Celsius reported by the per-package Package Thermal Monitor. 102\fBPkgTtmp\fP Degrees Celsius reported by the per-package Package Thermal Monitor.
103\fBGFX%rc6\fP The percentage of time the GPU is in the "render C6" state, rc6, during the measurement interval. From /sys/class/drm/card0/power/rc6_residency_ms.
104\fBGFXMHz\fP Instantaneous snapshot of what sysfs presents at the end of the measurement interval. From /sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz.
103\fBPkg%pc2, Pkg%pc3, Pkg%pc6, Pkg%pc7\fP percentage residency in hardware package idle states. These numbers are from hardware residency counters. 105\fBPkg%pc2, Pkg%pc3, Pkg%pc6, Pkg%pc7\fP percentage residency in hardware package idle states. These numbers are from hardware residency counters.
104\fBPkgWatt\fP Watts consumed by the whole package. 106\fBPkgWatt\fP Watts consumed by the whole package.
105\fBCorWatt\fP Watts consumed by the core part of the package. 107\fBCorWatt\fP Watts consumed by the core part of the package.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 828dccd3f01e..b11294730771 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1142,7 +1142,7 @@ delta_thread(struct thread_data *new, struct thread_data *old,
1142 * it is possible for mperf's non-halted cycles + idle states 1142 * it is possible for mperf's non-halted cycles + idle states
1143 * to exceed TSC's all cycles: show c1 = 0% in that case. 1143 * to exceed TSC's all cycles: show c1 = 0% in that case.
1144 */ 1144 */
1145 if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc) 1145 if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > (old->tsc * tsc_tweak))
1146 old->c1 = 0; 1146 old->c1 = 0;
1147 else { 1147 else {
1148 /* normal case, derive c1 */ 1148 /* normal case, derive c1 */
@@ -2485,8 +2485,10 @@ int snapshot_gfx_mhz(void)
2485 2485
2486 if (fp == NULL) 2486 if (fp == NULL)
2487 fp = fopen_or_die("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", "r"); 2487 fp = fopen_or_die("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", "r");
2488 else 2488 else {
2489 rewind(fp); 2489 rewind(fp);
2490 fflush(fp);
2491 }
2490 2492
2491 retval = fscanf(fp, "%d", &gfx_cur_mhz); 2493 retval = fscanf(fp, "%d", &gfx_cur_mhz);
2492 if (retval != 1) 2494 if (retval != 1)
@@ -3111,7 +3113,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3111 return 0; 3113 return 0;
3112 3114
3113 fprintf(outf, "cpu%d: MSR_HWP_CAPABILITIES: 0x%08llx " 3115 fprintf(outf, "cpu%d: MSR_HWP_CAPABILITIES: 0x%08llx "
3114 "(high 0x%x guar 0x%x eff 0x%x low 0x%x)\n", 3116 "(high %d guar %d eff %d low %d)\n",
3115 cpu, msr, 3117 cpu, msr,
3116 (unsigned int)HWP_HIGHEST_PERF(msr), 3118 (unsigned int)HWP_HIGHEST_PERF(msr),
3117 (unsigned int)HWP_GUARANTEED_PERF(msr), 3119 (unsigned int)HWP_GUARANTEED_PERF(msr),
@@ -3122,7 +3124,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3122 return 0; 3124 return 0;
3123 3125
3124 fprintf(outf, "cpu%d: MSR_HWP_REQUEST: 0x%08llx " 3126 fprintf(outf, "cpu%d: MSR_HWP_REQUEST: 0x%08llx "
3125 "(min 0x%x max 0x%x des 0x%x epp 0x%x window 0x%x pkg 0x%x)\n", 3127 "(min %d max %d des %d epp 0x%x window 0x%x pkg 0x%x)\n",
3126 cpu, msr, 3128 cpu, msr,
3127 (unsigned int)(((msr) >> 0) & 0xff), 3129 (unsigned int)(((msr) >> 0) & 0xff),
3128 (unsigned int)(((msr) >> 8) & 0xff), 3130 (unsigned int)(((msr) >> 8) & 0xff),
@@ -3136,7 +3138,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3136 return 0; 3138 return 0;
3137 3139
3138 fprintf(outf, "cpu%d: MSR_HWP_REQUEST_PKG: 0x%08llx " 3140 fprintf(outf, "cpu%d: MSR_HWP_REQUEST_PKG: 0x%08llx "
3139 "(min 0x%x max 0x%x des 0x%x epp 0x%x window 0x%x)\n", 3141 "(min %d max %d des %d epp 0x%x window 0x%x)\n",
3140 cpu, msr, 3142 cpu, msr,
3141 (unsigned int)(((msr) >> 0) & 0xff), 3143 (unsigned int)(((msr) >> 0) & 0xff),
3142 (unsigned int)(((msr) >> 8) & 0xff), 3144 (unsigned int)(((msr) >> 8) & 0xff),
@@ -3353,17 +3355,19 @@ void rapl_probe(unsigned int family, unsigned int model)
3353 case INTEL_FAM6_SKYLAKE_DESKTOP: /* SKL */ 3355 case INTEL_FAM6_SKYLAKE_DESKTOP: /* SKL */
3354 case INTEL_FAM6_KABYLAKE_MOBILE: /* KBL */ 3356 case INTEL_FAM6_KABYLAKE_MOBILE: /* KBL */
3355 case INTEL_FAM6_KABYLAKE_DESKTOP: /* KBL */ 3357 case INTEL_FAM6_KABYLAKE_DESKTOP: /* KBL */
3356 do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO; 3358 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_GFX | RAPL_PKG_POWER_INFO;
3357 BIC_PRESENT(BIC_PKG__); 3359 BIC_PRESENT(BIC_PKG__);
3358 BIC_PRESENT(BIC_RAM__); 3360 BIC_PRESENT(BIC_RAM__);
3359 if (rapl_joules) { 3361 if (rapl_joules) {
3360 BIC_PRESENT(BIC_Pkg_J); 3362 BIC_PRESENT(BIC_Pkg_J);
3361 BIC_PRESENT(BIC_Cor_J); 3363 BIC_PRESENT(BIC_Cor_J);
3362 BIC_PRESENT(BIC_RAM_J); 3364 BIC_PRESENT(BIC_RAM_J);
3365 BIC_PRESENT(BIC_GFX_J);
3363 } else { 3366 } else {
3364 BIC_PRESENT(BIC_PkgWatt); 3367 BIC_PRESENT(BIC_PkgWatt);
3365 BIC_PRESENT(BIC_CorWatt); 3368 BIC_PRESENT(BIC_CorWatt);
3366 BIC_PRESENT(BIC_RAMWatt); 3369 BIC_PRESENT(BIC_RAMWatt);
3370 BIC_PRESENT(BIC_GFXWatt);
3367 } 3371 }
3368 break; 3372 break;
3369 case INTEL_FAM6_HASWELL_X: /* HSX */ 3373 case INTEL_FAM6_HASWELL_X: /* HSX */
@@ -3478,7 +3482,7 @@ void perf_limit_reasons_probe(unsigned int family, unsigned int model)
3478int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p) 3482int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p)
3479{ 3483{
3480 unsigned long long msr; 3484 unsigned long long msr;
3481 unsigned int dts; 3485 unsigned int dts, dts2;
3482 int cpu; 3486 int cpu;
3483 3487
3484 if (!(do_dts || do_ptm)) 3488 if (!(do_dts || do_ptm))
@@ -3503,7 +3507,6 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
3503 fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n", 3507 fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
3504 cpu, msr, tcc_activation_temp - dts); 3508 cpu, msr, tcc_activation_temp - dts);
3505 3509
3506#ifdef THERM_DEBUG
3507 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr)) 3510 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr))
3508 return 0; 3511 return 0;
3509 3512
@@ -3511,11 +3514,10 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
3511 dts2 = (msr >> 8) & 0x7F; 3514 dts2 = (msr >> 8) & 0x7F;
3512 fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", 3515 fprintf(outf, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
3513 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2); 3516 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
3514#endif
3515 } 3517 }
3516 3518
3517 3519
3518 if (do_dts) { 3520 if (do_dts && debug) {
3519 unsigned int resolution; 3521 unsigned int resolution;
3520 3522
3521 if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr)) 3523 if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
@@ -3526,7 +3528,6 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
3526 fprintf(outf, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n", 3528 fprintf(outf, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
3527 cpu, msr, tcc_activation_temp - dts, resolution); 3529 cpu, msr, tcc_activation_temp - dts, resolution);
3528 3530
3529#ifdef THERM_DEBUG
3530 if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr)) 3531 if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr))
3531 return 0; 3532 return 0;
3532 3533
@@ -3534,7 +3535,6 @@ int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p
3534 dts2 = (msr >> 8) & 0x7F; 3535 dts2 = (msr >> 8) & 0x7F;
3535 fprintf(outf, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", 3536 fprintf(outf, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
3536 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2); 3537 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
3537#endif
3538 } 3538 }
3539 3539
3540 return 0; 3540 return 0;
@@ -4578,7 +4578,7 @@ int get_and_dump_counters(void)
4578} 4578}
4579 4579
4580void print_version() { 4580void print_version() {
4581 fprintf(outf, "turbostat version 17.02.24" 4581 fprintf(outf, "turbostat version 17.04.12"
4582 " - Len Brown <lenb@kernel.org>\n"); 4582 " - Len Brown <lenb@kernel.org>\n");
4583} 4583}
4584 4584
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index 621578aa12d6..fc74db62fef4 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -43,6 +43,15 @@ ifneq ($(CC), clang)
43EXTRA_WARNINGS += -Wstrict-aliasing=3 43EXTRA_WARNINGS += -Wstrict-aliasing=3
44endif 44endif
45 45
46# Hack to avoid type-punned warnings on old systems such as RHEL5:
47# We should be changing CFLAGS and checking gcc version, but this
48# will do for now and keep the above -Wstrict-aliasing=3 in place
49# in newer systems.
50# Needed for the __raw_cmpxchg in tools/arch/x86/include/asm/cmpxchg.h
51ifneq ($(filter 3.%,$(MAKE_VERSION)),) # make-3
52EXTRA_WARNINGS += -fno-strict-aliasing
53endif
54
46ifneq ($(findstring $(MAKEFLAGS), w),w) 55ifneq ($(findstring $(MAKEFLAGS), w),w)
47PRINT_DIR = --no-print-directory 56PRINT_DIR = --no-print-directory
48else 57else
diff --git a/tools/spi/spidev_test.c b/tools/spi/spidev_test.c
index 816f119c9b7b..8c590cd1171a 100644
--- a/tools/spi/spidev_test.c
+++ b/tools/spi/spidev_test.c
@@ -18,6 +18,7 @@
18#include <string.h> 18#include <string.h>
19#include <getopt.h> 19#include <getopt.h>
20#include <fcntl.h> 20#include <fcntl.h>
21#include <time.h>
21#include <sys/ioctl.h> 22#include <sys/ioctl.h>
22#include <linux/ioctl.h> 23#include <linux/ioctl.h>
23#include <sys/stat.h> 24#include <sys/stat.h>
@@ -40,6 +41,9 @@ static char *output_file;
40static uint32_t speed = 500000; 41static uint32_t speed = 500000;
41static uint16_t delay; 42static uint16_t delay;
42static int verbose; 43static int verbose;
44static int transfer_size;
45static int iterations;
46static int interval = 5; /* interval in seconds for showing transfer rate */
43 47
44uint8_t default_tx[] = { 48uint8_t default_tx[] = {
45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 49 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -156,13 +160,13 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
156 close(out_fd); 160 close(out_fd);
157 } 161 }
158 162
159 if (verbose || !output_file) 163 if (verbose)
160 hex_dump(rx, len, 32, "RX"); 164 hex_dump(rx, len, 32, "RX");
161} 165}
162 166
163static void print_usage(const char *prog) 167static void print_usage(const char *prog)
164{ 168{
165 printf("Usage: %s [-DsbdlHOLC3]\n", prog); 169 printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog);
166 puts(" -D --device device to use (default /dev/spidev1.1)\n" 170 puts(" -D --device device to use (default /dev/spidev1.1)\n"
167 " -s --speed max speed (Hz)\n" 171 " -s --speed max speed (Hz)\n"
168 " -d --delay delay (usec)\n" 172 " -d --delay delay (usec)\n"
@@ -180,7 +184,9 @@ static void print_usage(const char *prog)
180 " -N --no-cs no chip select\n" 184 " -N --no-cs no chip select\n"
181 " -R --ready slave pulls low to pause\n" 185 " -R --ready slave pulls low to pause\n"
182 " -2 --dual dual transfer\n" 186 " -2 --dual dual transfer\n"
183 " -4 --quad quad transfer\n"); 187 " -4 --quad quad transfer\n"
188 " -S --size transfer size\n"
189 " -I --iter iterations\n");
184 exit(1); 190 exit(1);
185} 191}
186 192
@@ -205,11 +211,13 @@ static void parse_opts(int argc, char *argv[])
205 { "dual", 0, 0, '2' }, 211 { "dual", 0, 0, '2' },
206 { "verbose", 0, 0, 'v' }, 212 { "verbose", 0, 0, 'v' },
207 { "quad", 0, 0, '4' }, 213 { "quad", 0, 0, '4' },
214 { "size", 1, 0, 'S' },
215 { "iter", 1, 0, 'I' },
208 { NULL, 0, 0, 0 }, 216 { NULL, 0, 0, 0 },
209 }; 217 };
210 int c; 218 int c;
211 219
212 c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v", 220 c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:vS:I:",
213 lopts, NULL); 221 lopts, NULL);
214 222
215 if (c == -1) 223 if (c == -1)
@@ -270,6 +278,12 @@ static void parse_opts(int argc, char *argv[])
270 case '4': 278 case '4':
271 mode |= SPI_TX_QUAD; 279 mode |= SPI_TX_QUAD;
272 break; 280 break;
281 case 'S':
282 transfer_size = atoi(optarg);
283 break;
284 case 'I':
285 iterations = atoi(optarg);
286 break;
273 default: 287 default:
274 print_usage(argv[0]); 288 print_usage(argv[0]);
275 break; 289 break;
@@ -336,6 +350,57 @@ static void transfer_file(int fd, char *filename)
336 close(tx_fd); 350 close(tx_fd);
337} 351}
338 352
353static uint64_t _read_count;
354static uint64_t _write_count;
355
356static void show_transfer_rate(void)
357{
358 static uint64_t prev_read_count, prev_write_count;
359 double rx_rate, tx_rate;
360
361 rx_rate = ((_read_count - prev_read_count) * 8) / (interval*1000.0);
362 tx_rate = ((_write_count - prev_write_count) * 8) / (interval*1000.0);
363
364 printf("rate: tx %.1fkbps, rx %.1fkbps\n", rx_rate, tx_rate);
365
366 prev_read_count = _read_count;
367 prev_write_count = _write_count;
368}
369
370static void transfer_buf(int fd, int len)
371{
372 uint8_t *tx;
373 uint8_t *rx;
374 int i;
375
376 tx = malloc(len);
377 if (!tx)
378 pabort("can't allocate tx buffer");
379 for (i = 0; i < len; i++)
380 tx[i] = random();
381
382 rx = malloc(len);
383 if (!rx)
384 pabort("can't allocate rx buffer");
385
386 transfer(fd, tx, rx, len);
387
388 _write_count += len;
389 _read_count += len;
390
391 if (mode & SPI_LOOP) {
392 if (memcmp(tx, rx, len)) {
393 fprintf(stderr, "transfer error !\n");
394 hex_dump(tx, len, 32, "TX");
395 hex_dump(rx, len, 32, "RX");
396 exit(1);
397 }
398 }
399
400 free(rx);
401 free(tx);
402}
403
339int main(int argc, char *argv[]) 404int main(int argc, char *argv[])
340{ 405{
341 int ret = 0; 406 int ret = 0;
@@ -391,7 +456,25 @@ int main(int argc, char *argv[])
391 transfer_escaped_string(fd, input_tx); 456 transfer_escaped_string(fd, input_tx);
392 else if (input_file) 457 else if (input_file)
393 transfer_file(fd, input_file); 458 transfer_file(fd, input_file);
394 else 459 else if (transfer_size) {
460 struct timespec last_stat;
461
462 clock_gettime(CLOCK_MONOTONIC, &last_stat);
463
464 while (iterations-- > 0) {
465 struct timespec current;
466
467 transfer_buf(fd, transfer_size);
468
469 clock_gettime(CLOCK_MONOTONIC, &current);
470 if (current.tv_sec - last_stat.tv_sec > interval) {
471 show_transfer_rate();
472 last_stat = current;
473 }
474 }
475 printf("total: tx %.1fKB, rx %.1fKB\n",
476 _write_count/1024.0, _read_count/1024.0);
477 } else
395 transfer(fd, default_tx, default_rx, sizeof(default_tx)); 478 transfer(fd, default_tx, default_rx, sizeof(default_tx));
396 479
397 close(fd); 480 close(fd);
diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild
index 405212be044a..d870520da68b 100644
--- a/tools/testing/nvdimm/Kbuild
+++ b/tools/testing/nvdimm/Kbuild
@@ -28,7 +28,10 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o
28obj-$(CONFIG_ND_BLK) += nd_blk.o 28obj-$(CONFIG_ND_BLK) += nd_blk.o
29obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o 29obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o
30obj-$(CONFIG_ACPI_NFIT) += nfit.o 30obj-$(CONFIG_ACPI_NFIT) += nfit.o
31obj-$(CONFIG_DEV_DAX) += dax.o 31ifeq ($(CONFIG_DAX),m)
32obj-$(CONFIG_DAX) += dax.o
33endif
34obj-$(CONFIG_DEV_DAX) += device_dax.o
32obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o 35obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
33 36
34nfit-y := $(ACPI_SRC)/core.o 37nfit-y := $(ACPI_SRC)/core.o
@@ -48,9 +51,13 @@ nd_blk-y += config_check.o
48nd_e820-y := $(NVDIMM_SRC)/e820.o 51nd_e820-y := $(NVDIMM_SRC)/e820.o
49nd_e820-y += config_check.o 52nd_e820-y += config_check.o
50 53
51dax-y := $(DAX_SRC)/dax.o 54dax-y := $(DAX_SRC)/super.o
52dax-y += config_check.o 55dax-y += config_check.o
53 56
57device_dax-y := $(DAX_SRC)/device.o
58device_dax-y += dax-dev.o
59device_dax-y += config_check.o
60
54dax_pmem-y := $(DAX_SRC)/pmem.o 61dax_pmem-y := $(DAX_SRC)/pmem.o
55dax_pmem-y += config_check.o 62dax_pmem-y += config_check.o
56 63
diff --git a/tools/testing/nvdimm/dax-dev.c b/tools/testing/nvdimm/dax-dev.c
new file mode 100644
index 000000000000..36ee3d8797c3
--- /dev/null
+++ b/tools/testing/nvdimm/dax-dev.c
@@ -0,0 +1,49 @@
1/*
2 * Copyright (c) 2016, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13#include "test/nfit_test.h"
14#include <linux/mm.h>
15#include "../../../drivers/dax/dax-private.h"
16
17phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff,
18 unsigned long size)
19{
20 struct resource *res;
21 phys_addr_t addr;
22 int i;
23
24 for (i = 0; i < dev_dax->num_resources; i++) {
25 res = &dev_dax->res[i];
26 addr = pgoff * PAGE_SIZE + res->start;
27 if (addr >= res->start && addr <= res->end)
28 break;
29 pgoff -= PHYS_PFN(resource_size(res));
30 }
31
32 if (i < dev_dax->num_resources) {
33 res = &dev_dax->res[i];
34 if (addr + size - 1 <= res->end) {
35 if (get_nfit_res(addr)) {
36 struct page *page;
37
38 if (dev_dax->region->align > PAGE_SIZE)
39 return -1;
40
41 page = vmalloc_to_page((void *)addr);
42 return PFN_PHYS(page_to_pfn(page));
43 } else
44 return addr;
45 }
46 }
47
48 return -1;
49}
diff --git a/tools/testing/nvdimm/pmem-dax.c b/tools/testing/nvdimm/pmem-dax.c
index c9b8c48f85fc..b53596ad601b 100644
--- a/tools/testing/nvdimm/pmem-dax.c
+++ b/tools/testing/nvdimm/pmem-dax.c
@@ -15,13 +15,13 @@
15#include <pmem.h> 15#include <pmem.h>
16#include <nd.h> 16#include <nd.h>
17 17
18long pmem_direct_access(struct block_device *bdev, sector_t sector, 18long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
19 void **kaddr, pfn_t *pfn, long size) 19 long nr_pages, void **kaddr, pfn_t *pfn)
20{ 20{
21 struct pmem_device *pmem = bdev->bd_queue->queuedata; 21 resource_size_t offset = PFN_PHYS(pgoff) + pmem->data_offset;
22 resource_size_t offset = sector * 512 + pmem->data_offset;
23 22
24 if (unlikely(is_bad_pmem(&pmem->bb, sector, size))) 23 if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512,
24 PFN_PHYS(nr_pages))))
25 return -EIO; 25 return -EIO;
26 26
27 /* 27 /*
@@ -34,11 +34,10 @@ long pmem_direct_access(struct block_device *bdev, sector_t sector,
34 *kaddr = pmem->virt_addr + offset; 34 *kaddr = pmem->virt_addr + offset;
35 page = vmalloc_to_page(pmem->virt_addr + offset); 35 page = vmalloc_to_page(pmem->virt_addr + offset);
36 *pfn = page_to_pfn_t(page); 36 *pfn = page_to_pfn_t(page);
37 dev_dbg_ratelimited(disk_to_dev(bdev->bd_disk)->parent, 37 pr_debug_ratelimited("%s: pmem: %p pgoff: %#lx pfn: %#lx\n",
38 "%s: sector: %#llx pfn: %#lx\n", __func__, 38 __func__, pmem, pgoff, page_to_pfn(page));
39 (unsigned long long) sector, page_to_pfn(page));
40 39
41 return PAGE_SIZE; 40 return 1;
42 } 41 }
43 42
44 *kaddr = pmem->virt_addr + offset; 43 *kaddr = pmem->virt_addr + offset;
@@ -49,6 +48,6 @@ long pmem_direct_access(struct block_device *bdev, sector_t sector,
49 * requested range. 48 * requested range.
50 */ 49 */
51 if (unlikely(pmem->bb.count)) 50 if (unlikely(pmem->bb.count))
52 return size; 51 return nr_pages;
53 return pmem->size - pmem->pfn_pad - offset; 52 return PHYS_PFN(pmem->size - pmem->pfn_pad - offset);
54} 53}
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 798f17655433..c2187178fb13 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -132,6 +132,7 @@ static u32 handle[] = {
132 [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), 132 [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),
133 [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), 133 [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
134 [5] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0), 134 [5] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0),
135 [6] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 1),
135}; 136};
136 137
137static unsigned long dimm_fail_cmd_flags[NUM_DCR]; 138static unsigned long dimm_fail_cmd_flags[NUM_DCR];
@@ -728,8 +729,8 @@ static int nfit_test0_alloc(struct nfit_test *t)
728static int nfit_test1_alloc(struct nfit_test *t) 729static int nfit_test1_alloc(struct nfit_test *t)
729{ 730{
730 size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2 731 size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2
731 + sizeof(struct acpi_nfit_memory_map) 732 + sizeof(struct acpi_nfit_memory_map) * 2
732 + offsetof(struct acpi_nfit_control_region, window_size); 733 + offsetof(struct acpi_nfit_control_region, window_size) * 2;
733 int i; 734 int i;
734 735
735 t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma); 736 t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma);
@@ -906,6 +907,7 @@ static void nfit_test0_setup(struct nfit_test *t)
906 memdev->address = 0; 907 memdev->address = 0;
907 memdev->interleave_index = 0; 908 memdev->interleave_index = 0;
908 memdev->interleave_ways = 2; 909 memdev->interleave_ways = 2;
910 memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED;
909 911
910 /* mem-region2 (spa1, dimm0) */ 912 /* mem-region2 (spa1, dimm0) */
911 memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 2; 913 memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 2;
@@ -921,6 +923,7 @@ static void nfit_test0_setup(struct nfit_test *t)
921 memdev->address = SPA0_SIZE/2; 923 memdev->address = SPA0_SIZE/2;
922 memdev->interleave_index = 0; 924 memdev->interleave_index = 0;
923 memdev->interleave_ways = 4; 925 memdev->interleave_ways = 4;
926 memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED;
924 927
925 /* mem-region3 (spa1, dimm1) */ 928 /* mem-region3 (spa1, dimm1) */
926 memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 3; 929 memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 3;
@@ -951,6 +954,7 @@ static void nfit_test0_setup(struct nfit_test *t)
951 memdev->address = SPA0_SIZE/2; 954 memdev->address = SPA0_SIZE/2;
952 memdev->interleave_index = 0; 955 memdev->interleave_index = 0;
953 memdev->interleave_ways = 4; 956 memdev->interleave_ways = 4;
957 memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED;
954 958
955 /* mem-region5 (spa1, dimm3) */ 959 /* mem-region5 (spa1, dimm3) */
956 memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 5; 960 memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 5;
@@ -1086,6 +1090,7 @@ static void nfit_test0_setup(struct nfit_test *t)
1086 memdev->address = 0; 1090 memdev->address = 0;
1087 memdev->interleave_index = 0; 1091 memdev->interleave_index = 0;
1088 memdev->interleave_ways = 1; 1092 memdev->interleave_ways = 1;
1093 memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED;
1089 1094
1090 offset = offset + sizeof(struct acpi_nfit_memory_map) * 14; 1095 offset = offset + sizeof(struct acpi_nfit_memory_map) * 14;
1091 /* dcr-descriptor0: blk */ 1096 /* dcr-descriptor0: blk */
@@ -1384,6 +1389,7 @@ static void nfit_test0_setup(struct nfit_test *t)
1384 memdev->address = 0; 1389 memdev->address = 0;
1385 memdev->interleave_index = 0; 1390 memdev->interleave_index = 0;
1386 memdev->interleave_ways = 1; 1391 memdev->interleave_ways = 1;
1392 memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED;
1387 1393
1388 /* mem-region16 (spa/bdw4, dimm4) */ 1394 /* mem-region16 (spa/bdw4, dimm4) */
1389 memdev = nfit_buf + offset + 1395 memdev = nfit_buf + offset +
@@ -1486,6 +1492,34 @@ static void nfit_test1_setup(struct nfit_test *t)
1486 dcr->code = NFIT_FIC_BYTE; 1492 dcr->code = NFIT_FIC_BYTE;
1487 dcr->windows = 0; 1493 dcr->windows = 0;
1488 1494
1495 offset += dcr->header.length;
1496 memdev = nfit_buf + offset;
1497 memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
1498 memdev->header.length = sizeof(*memdev);
1499 memdev->device_handle = handle[6];
1500 memdev->physical_id = 0;
1501 memdev->region_id = 0;
1502 memdev->range_index = 0;
1503 memdev->region_index = 0+2;
1504 memdev->region_size = SPA2_SIZE;
1505 memdev->region_offset = 0;
1506 memdev->address = 0;
1507 memdev->interleave_index = 0;
1508 memdev->interleave_ways = 1;
1509 memdev->flags = ACPI_NFIT_MEM_MAP_FAILED;
1510
1511 /* dcr-descriptor1 */
1512 offset += sizeof(*memdev);
1513 dcr = nfit_buf + offset;
1514 dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
1515 dcr->header.length = offsetof(struct acpi_nfit_control_region,
1516 window_size);
1517 dcr->region_index = 0+2;
1518 dcr_common_init(dcr);
1519 dcr->serial_number = ~handle[6];
1520 dcr->code = NFIT_FIC_BYTE;
1521 dcr->windows = 0;
1522
1489 post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); 1523 post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE);
1490 1524
1491 acpi_desc = &t->acpi_desc; 1525 acpi_desc = &t->acpi_desc;
@@ -1817,6 +1851,10 @@ static int nfit_test_probe(struct platform_device *pdev)
1817 if (rc) 1851 if (rc)
1818 return rc; 1852 return rc;
1819 1853
1854 rc = devm_add_action_or_reset(&pdev->dev, acpi_nfit_shutdown, acpi_desc);
1855 if (rc)
1856 return rc;
1857
1820 if (nfit_test->setup != nfit_test0_setup) 1858 if (nfit_test->setup != nfit_test0_setup)
1821 return 0; 1859 return 0;
1822 1860
@@ -1907,7 +1945,7 @@ static __init int nfit_test_init(void)
1907 case 1: 1945 case 1:
1908 nfit_test->num_pm = 1; 1946 nfit_test->num_pm = 1;
1909 nfit_test->dcr_idx = NUM_DCR; 1947 nfit_test->dcr_idx = NUM_DCR;
1910 nfit_test->num_dcr = 1; 1948 nfit_test->num_dcr = 2;
1911 nfit_test->alloc = nfit_test1_alloc; 1949 nfit_test->alloc = nfit_test1_alloc;
1912 nfit_test->setup = nfit_test1_setup; 1950 nfit_test->setup = nfit_test1_setup;
1913 break; 1951 break;
@@ -1924,6 +1962,7 @@ static __init int nfit_test_init(void)
1924 put_device(&pdev->dev); 1962 put_device(&pdev->dev);
1925 goto err_register; 1963 goto err_register;
1926 } 1964 }
1965 get_device(&pdev->dev);
1927 1966
1928 rc = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 1967 rc = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
1929 if (rc) 1968 if (rc)
@@ -1942,6 +1981,10 @@ static __init int nfit_test_init(void)
1942 if (instances[i]) 1981 if (instances[i])
1943 platform_device_unregister(&instances[i]->pdev); 1982 platform_device_unregister(&instances[i]->pdev);
1944 nfit_test_teardown(); 1983 nfit_test_teardown();
1984 for (i = 0; i < NUM_NFITS; i++)
1985 if (instances[i])
1986 put_device(&instances[i]->pdev.dev);
1987
1945 return rc; 1988 return rc;
1946} 1989}
1947 1990
@@ -1949,10 +1992,13 @@ static __exit void nfit_test_exit(void)
1949{ 1992{
1950 int i; 1993 int i;
1951 1994
1952 platform_driver_unregister(&nfit_test_driver);
1953 for (i = 0; i < NUM_NFITS; i++) 1995 for (i = 0; i < NUM_NFITS; i++)
1954 platform_device_unregister(&instances[i]->pdev); 1996 platform_device_unregister(&instances[i]->pdev);
1997 platform_driver_unregister(&nfit_test_driver);
1955 nfit_test_teardown(); 1998 nfit_test_teardown();
1999
2000 for (i = 0; i < NUM_NFITS; i++)
2001 put_device(&instances[i]->pdev.dev);
1956 class_destroy(nfit_test_dimm); 2002 class_destroy(nfit_test_dimm);
1957} 2003}
1958 2004
diff --git a/tools/testing/selftests/.gitignore b/tools/testing/selftests/.gitignore
index f0600d20ce7d..91750352459d 100644
--- a/tools/testing/selftests/.gitignore
+++ b/tools/testing/selftests/.gitignore
@@ -1 +1,5 @@
1kselftest 1kselftest
2gpiogpio-event-mon
3gpiogpio-hammer
4gpioinclude/
5gpiolsgpio
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index d8593f1251ec..26ce4f7168be 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -39,7 +39,7 @@ TARGETS += x86
39TARGETS += zram 39TARGETS += zram
40#Please keep the TARGETS list alphabetically sorted 40#Please keep the TARGETS list alphabetically sorted
41# Run "make quicktest=1 run_tests" or 41# Run "make quicktest=1 run_tests" or
42# "make quicktest=1 kselftest from top level Makefile 42# "make quicktest=1 kselftest" from top level Makefile
43 43
44TARGETS_HOTPLUG = cpu-hotplug 44TARGETS_HOTPLUG = cpu-hotplug
45TARGETS_HOTPLUG += memory-hotplug 45TARGETS_HOTPLUG += memory-hotplug
@@ -133,4 +133,4 @@ clean:
133 make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\ 133 make OUTPUT=$$BUILD_TARGET -C $$TARGET clean;\
134 done; 134 done;
135 135
136.PHONY: install 136.PHONY: all run_tests hotplug run_hotplug clean_hotplug run_pstore_crash install clean
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 6a1ad58cb66f..f389b02d43a0 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,16 +1,26 @@
1LIBDIR := ../../../lib 1LIBDIR := ../../../lib
2BPFDIR := $(LIBDIR)/bpf 2BPFDIR := $(LIBDIR)/bpf
3APIDIR := ../../../include/uapi
4GENDIR := ../../../../include/generated
5GENHDR := $(GENDIR)/autoconf.h
3 6
4CFLAGS += -Wall -O2 -I../../../include/uapi -I$(LIBDIR) 7ifneq ($(wildcard $(GENHDR)),)
5LDLIBS += -lcap 8 GENFLAGS := -DHAVE_GENHDR
9endif
6 10
7TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map 11CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
12LDLIBS += -lcap -lelf
13
14TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
15 test_align
16
17TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o
8 18
9TEST_PROGS := test_kmod.sh 19TEST_PROGS := test_kmod.sh
10 20
11include ../lib.mk 21include ../lib.mk
12 22
13BPFOBJ := $(OUTPUT)/bpf.o 23BPFOBJ := $(OUTPUT)/libbpf.a
14 24
15$(TEST_GEN_PROGS): $(BPFOBJ) 25$(TEST_GEN_PROGS): $(BPFOBJ)
16 26
@@ -21,3 +31,11 @@ force:
21 31
22$(BPFOBJ): force 32$(BPFOBJ): force
23 $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/ 33 $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/
34
35CLANG ?= clang
36
37%.o: %.c
38 $(CLANG) -I. -I./include/uapi -I../../../include/uapi \
39 -I../../../../samples/bpf/ \
40 -Wno-compare-distinct-pointer-types \
41 -O2 -target bpf -c $< -o $@
diff --git a/tools/testing/selftests/bpf/bpf_endian.h b/tools/testing/selftests/bpf/bpf_endian.h
new file mode 100644
index 000000000000..19d0604f8694
--- /dev/null
+++ b/tools/testing/selftests/bpf/bpf_endian.h
@@ -0,0 +1,23 @@
1#ifndef __BPF_ENDIAN__
2#define __BPF_ENDIAN__
3
4#include <asm/byteorder.h>
5
6#if __BYTE_ORDER == __LITTLE_ENDIAN
7# define __bpf_ntohs(x) __builtin_bswap16(x)
8# define __bpf_htons(x) __builtin_bswap16(x)
9#elif __BYTE_ORDER == __BIG_ENDIAN
10# define __bpf_ntohs(x) (x)
11# define __bpf_htons(x) (x)
12#else
13# error "Fix your __BYTE_ORDER?!"
14#endif
15
16#define bpf_htons(x) \
17 (__builtin_constant_p(x) ? \
18 __constant_htons(x) : __bpf_htons(x))
19#define bpf_ntohs(x) \
20 (__builtin_constant_p(x) ? \
21 __constant_ntohs(x) : __bpf_ntohs(x))
22
23#endif
diff --git a/tools/testing/selftests/bpf/bpf_util.h b/tools/testing/selftests/bpf/bpf_util.h
index 84a5d1823f02..20ecbaa0d85d 100644
--- a/tools/testing/selftests/bpf/bpf_util.h
+++ b/tools/testing/selftests/bpf/bpf_util.h
@@ -35,4 +35,11 @@ static inline unsigned int bpf_num_possible_cpus(void)
35 return possible_cpus; 35 return possible_cpus;
36} 36}
37 37
38#define __bpf_percpu_val_align __attribute__((__aligned__(8)))
39
40#define BPF_DECLARE_PERCPU(type, name) \
41 struct { type v; /* padding */ } __bpf_percpu_val_align \
42 name[bpf_num_possible_cpus()]
43#define bpf_percpu(name, cpu) name[(cpu)].v
44
38#endif /* __BPF_UTIL__ */ 45#endif /* __BPF_UTIL__ */
diff --git a/tools/testing/selftests/bpf/gnu/stubs.h b/tools/testing/selftests/bpf/gnu/stubs.h
new file mode 100644
index 000000000000..719225b16626
--- /dev/null
+++ b/tools/testing/selftests/bpf/gnu/stubs.h
@@ -0,0 +1 @@
/* dummy .h to trick /usr/include/features.h to work with 'clang -target bpf' */
diff --git a/tools/testing/selftests/bpf/include/uapi/linux/types.h b/tools/testing/selftests/bpf/include/uapi/linux/types.h
new file mode 100644
index 000000000000..51841848fbfe
--- /dev/null
+++ b/tools/testing/selftests/bpf/include/uapi/linux/types.h
@@ -0,0 +1,22 @@
1#ifndef _UAPI_LINUX_TYPES_H
2#define _UAPI_LINUX_TYPES_H
3
4#include <asm-generic/int-ll64.h>
5
6/* copied from linux:include/uapi/linux/types.h */
7#define __bitwise
8typedef __u16 __bitwise __le16;
9typedef __u16 __bitwise __be16;
10typedef __u32 __bitwise __le32;
11typedef __u32 __bitwise __be32;
12typedef __u64 __bitwise __le64;
13typedef __u64 __bitwise __be64;
14
15typedef __u16 __bitwise __sum16;
16typedef __u32 __bitwise __wsum;
17
18#define __aligned_u64 __u64 __attribute__((aligned(8)))
19#define __aligned_be64 __be64 __attribute__((aligned(8)))
20#define __aligned_le64 __le64 __attribute__((aligned(8)))
21
22#endif /* _UAPI_LINUX_TYPES_H */
diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c
new file mode 100644
index 000000000000..9644d4e069de
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_align.c
@@ -0,0 +1,453 @@
1#include <asm/types.h>
2#include <linux/types.h>
3#include <stdint.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <errno.h>
8#include <string.h>
9#include <stddef.h>
10#include <stdbool.h>
11
12#include <linux/unistd.h>
13#include <linux/filter.h>
14#include <linux/bpf_perf_event.h>
15#include <linux/bpf.h>
16
17#include <bpf/bpf.h>
18
19#include "../../../include/linux/filter.h"
20
21#ifndef ARRAY_SIZE
22# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
23#endif
24
25#define MAX_INSNS 512
26#define MAX_MATCHES 16
27
28struct bpf_align_test {
29 const char *descr;
30 struct bpf_insn insns[MAX_INSNS];
31 enum {
32 UNDEF,
33 ACCEPT,
34 REJECT
35 } result;
36 enum bpf_prog_type prog_type;
37 const char *matches[MAX_MATCHES];
38};
39
40static struct bpf_align_test tests[] = {
41 {
42 .descr = "mov",
43 .insns = {
44 BPF_MOV64_IMM(BPF_REG_3, 2),
45 BPF_MOV64_IMM(BPF_REG_3, 4),
46 BPF_MOV64_IMM(BPF_REG_3, 8),
47 BPF_MOV64_IMM(BPF_REG_3, 16),
48 BPF_MOV64_IMM(BPF_REG_3, 32),
49 BPF_MOV64_IMM(BPF_REG_0, 0),
50 BPF_EXIT_INSN(),
51 },
52 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
53 .matches = {
54 "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
55 "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
56 "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
57 "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
58 "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
59 },
60 },
61 {
62 .descr = "shift",
63 .insns = {
64 BPF_MOV64_IMM(BPF_REG_3, 1),
65 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
66 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
67 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
68 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
69 BPF_ALU64_IMM(BPF_RSH, BPF_REG_3, 4),
70 BPF_MOV64_IMM(BPF_REG_4, 32),
71 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
72 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
73 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
74 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
75 BPF_MOV64_IMM(BPF_REG_0, 0),
76 BPF_EXIT_INSN(),
77 },
78 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
79 .matches = {
80 "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
81 "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
82 "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
83 "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
84 "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
85 "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
86 "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
87 "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
88 "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
89 "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
90 "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
91 },
92 },
93 {
94 .descr = "addsub",
95 .insns = {
96 BPF_MOV64_IMM(BPF_REG_3, 4),
97 BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 4),
98 BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 2),
99 BPF_MOV64_IMM(BPF_REG_4, 8),
100 BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
101 BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2),
102 BPF_MOV64_IMM(BPF_REG_0, 0),
103 BPF_EXIT_INSN(),
104 },
105 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
106 .matches = {
107 "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
108 "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp",
109 "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp",
110 "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
111 "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp",
112 "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
113 },
114 },
115 {
116 .descr = "mul",
117 .insns = {
118 BPF_MOV64_IMM(BPF_REG_3, 7),
119 BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 1),
120 BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 2),
121 BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 4),
122 BPF_MOV64_IMM(BPF_REG_0, 0),
123 BPF_EXIT_INSN(),
124 },
125 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
126 .matches = {
127 "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
128 "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
129 "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
130 "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp",
131 },
132 },
133
134#define PREP_PKT_POINTERS \
135 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \
136 offsetof(struct __sk_buff, data)), \
137 BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \
138 offsetof(struct __sk_buff, data_end))
139
140#define LOAD_UNKNOWN(DST_REG) \
141 PREP_PKT_POINTERS, \
142 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), \
143 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), \
144 BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_0, 1), \
145 BPF_EXIT_INSN(), \
146 BPF_LDX_MEM(BPF_B, DST_REG, BPF_REG_2, 0)
147
148 {
149 .descr = "unknown shift",
150 .insns = {
151 LOAD_UNKNOWN(BPF_REG_3),
152 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
153 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
154 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
155 BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
156 LOAD_UNKNOWN(BPF_REG_4),
157 BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 5),
158 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
159 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
160 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
161 BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
162 BPF_MOV64_IMM(BPF_REG_0, 0),
163 BPF_EXIT_INSN(),
164 },
165 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
166 .matches = {
167 "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
168 "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp",
169 "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp",
170 "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp",
171 "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp",
172 "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp",
173 "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp",
174 "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp",
175 "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp",
176 "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp",
177 "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp",
178 },
179 },
180 {
181 .descr = "unknown mul",
182 .insns = {
183 LOAD_UNKNOWN(BPF_REG_3),
184 BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
185 BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 1),
186 BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
187 BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
188 BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
189 BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 4),
190 BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
191 BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 8),
192 BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
193 BPF_MOV64_IMM(BPF_REG_0, 0),
194 BPF_EXIT_INSN(),
195 },
196 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
197 .matches = {
198 "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
199 "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
200 "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp",
201 "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
202 "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp",
203 "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
204 "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp",
205 "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
206 "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp",
207 "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp"
208 },
209 },
210 {
211 .descr = "packet const offset",
212 .insns = {
213 PREP_PKT_POINTERS,
214 BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
215
216 BPF_MOV64_IMM(BPF_REG_0, 0),
217
218 /* Skip over ethernet header. */
219 BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
220 BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
221 BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
222 BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
223 BPF_EXIT_INSN(),
224
225 BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 0),
226 BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 1),
227 BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 2),
228 BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 3),
229 BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 0),
230 BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 2),
231 BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
232
233 BPF_MOV64_IMM(BPF_REG_0, 0),
234 BPF_EXIT_INSN(),
235 },
236 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
237 .matches = {
238 "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp",
239 "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp",
240 "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp",
241 "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp",
242 "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
243 "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
244 },
245 },
246 {
247 .descr = "packet variable offset",
248 .insns = {
249 LOAD_UNKNOWN(BPF_REG_6),
250 BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
251
252 /* First, add a constant to the R5 packet pointer,
253 * then a variable with a known alignment.
254 */
255 BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
256 BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
257 BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
258 BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
259 BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
260 BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
261 BPF_EXIT_INSN(),
262 BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
263
264 /* Now, test in the other direction. Adding first
265 * the variable offset to R5, then the constant.
266 */
267 BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
268 BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
269 BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
270 BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
271 BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
272 BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
273 BPF_EXIT_INSN(),
274 BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
275
276 /* Test multiple accumulations of unknown values
277 * into a packet pointer.
278 */
279 BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
280 BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
281 BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
282 BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4),
283 BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
284 BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
285 BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
286 BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
287 BPF_EXIT_INSN(),
288 BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
289
290 BPF_MOV64_IMM(BPF_REG_0, 0),
291 BPF_EXIT_INSN(),
292 },
293 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
294 .matches = {
295 /* Calculated offset in R6 has unknown value, but known
296 * alignment of 4.
297 */
298 "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp",
299
300 /* Offset is added to packet pointer R5, resulting in known
301 * auxiliary alignment and offset.
302 */
303 "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
304
305 /* At the time the word size load is performed from R5,
306 * it's total offset is NET_IP_ALIGN + reg->off (0) +
307 * reg->aux_off (14) which is 16. Then the variable
308 * offset is considered using reg->aux_off_align which
309 * is 4 and meets the load's requirements.
310 */
311 "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
312
313
314 /* Variable offset is added to R5 packet pointer,
315 * resulting in auxiliary alignment of 4.
316 */
317 "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
318
319 /* Constant offset is added to R5, resulting in
320 * reg->off of 14.
321 */
322 "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
323
324 /* At the time the word size load is performed from R5,
325 * it's total offset is NET_IP_ALIGN + reg->off (14) which
326 * is 16. Then the variable offset is considered using
327 * reg->aux_off_align which is 4 and meets the load's
328 * requirements.
329 */
330 "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
331
332 /* Constant offset is added to R5 packet pointer,
333 * resulting in reg->off value of 14.
334 */
335 "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp",
336 /* Variable offset is added to R5, resulting in an
337 * auxiliary offset of 14, and an auxiliary alignment of 4.
338 */
339 "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
340 /* Constant is added to R5 again, setting reg->off to 4. */
341 "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
342 /* And once more we add a variable, which causes an accumulation
343 * of reg->off into reg->aux_off_align, with resulting value of
344 * 18. The auxiliary alignment stays at 4.
345 */
346 "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
347 /* At the time the word size load is performed from R5,
348 * it's total offset is NET_IP_ALIGN + reg->off (0) +
349 * reg->aux_off (18) which is 20. Then the variable offset
350 * is considered using reg->aux_off_align which is 4 and meets
351 * the load's requirements.
352 */
353 "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
354 },
355 },
356};
357
358static int probe_filter_length(const struct bpf_insn *fp)
359{
360 int len;
361
362 for (len = MAX_INSNS - 1; len > 0; --len)
363 if (fp[len].code != 0 || fp[len].imm != 0)
364 break;
365 return len + 1;
366}
367
368static char bpf_vlog[32768];
369
370static int do_test_single(struct bpf_align_test *test)
371{
372 struct bpf_insn *prog = test->insns;
373 int prog_type = test->prog_type;
374 int prog_len, i;
375 int fd_prog;
376 int ret;
377
378 prog_len = probe_filter_length(prog);
379 fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
380 prog, prog_len, 1, "GPL", 0,
381 bpf_vlog, sizeof(bpf_vlog));
382 if (fd_prog < 0) {
383 printf("Failed to load program.\n");
384 printf("%s", bpf_vlog);
385 ret = 1;
386 } else {
387 ret = 0;
388 for (i = 0; i < MAX_MATCHES; i++) {
389 const char *t, *m = test->matches[i];
390
391 if (!m)
392 break;
393 t = strstr(bpf_vlog, m);
394 if (!t) {
395 printf("Failed to find match: %s\n", m);
396 ret = 1;
397 printf("%s", bpf_vlog);
398 break;
399 }
400 }
401 close(fd_prog);
402 }
403 return ret;
404}
405
406static int do_test(unsigned int from, unsigned int to)
407{
408 int all_pass = 0;
409 int all_fail = 0;
410 unsigned int i;
411
412 for (i = from; i < to; i++) {
413 struct bpf_align_test *test = &tests[i];
414 int fail;
415
416 printf("Test %3d: %s ... ",
417 i, test->descr);
418 fail = do_test_single(test);
419 if (fail) {
420 all_fail++;
421 printf("FAIL\n");
422 } else {
423 all_pass++;
424 printf("PASS\n");
425 }
426 }
427 printf("Results: %d pass %d fail\n",
428 all_pass, all_fail);
429 return 0;
430}
431
432int main(int argc, char **argv)
433{
434 unsigned int from = 0, to = ARRAY_SIZE(tests);
435
436 if (argc == 3) {
437 unsigned int l = atoi(argv[argc - 2]);
438 unsigned int u = atoi(argv[argc - 1]);
439
440 if (l < to && u < to) {
441 from = l;
442 to = u + 1;
443 }
444 } else if (argc == 2) {
445 unsigned int t = atoi(argv[argc - 1]);
446
447 if (t < to) {
448 from = t;
449 to = t + 1;
450 }
451 }
452 return do_test(from, to);
453}
diff --git a/tools/testing/selftests/bpf/test_iptunnel_common.h b/tools/testing/selftests/bpf/test_iptunnel_common.h
new file mode 100644
index 000000000000..e4cd252a1b20
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_iptunnel_common.h
@@ -0,0 +1,37 @@
1/* Copyright (c) 2016 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#ifndef _TEST_IPTNL_COMMON_H
8#define _TEST_IPTNL_COMMON_H
9
10#include <linux/types.h>
11
12#define MAX_IPTNL_ENTRIES 256U
13
14struct vip {
15 union {
16 __u32 v6[4];
17 __u32 v4;
18 } daddr;
19 __u16 dport;
20 __u16 family;
21 __u8 protocol;
22};
23
24struct iptnl_info {
25 union {
26 __u32 v6[4];
27 __u32 v4;
28 } saddr;
29 union {
30 __u32 v6[4];
31 __u32 v4;
32 } daddr;
33 __u16 family;
34 __u8 dmac[6];
35};
36
37#endif
diff --git a/tools/testing/selftests/bpf/test_l4lb.c b/tools/testing/selftests/bpf/test_l4lb.c
new file mode 100644
index 000000000000..1e10c9590991
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_l4lb.c
@@ -0,0 +1,473 @@
1/* Copyright (c) 2017 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <stddef.h>
8#include <stdbool.h>
9#include <string.h>
10#include <linux/pkt_cls.h>
11#include <linux/bpf.h>
12#include <linux/in.h>
13#include <linux/if_ether.h>
14#include <linux/ip.h>
15#include <linux/ipv6.h>
16#include <linux/icmp.h>
17#include <linux/icmpv6.h>
18#include <linux/tcp.h>
19#include <linux/udp.h>
20#include "bpf_helpers.h"
21#include "test_iptunnel_common.h"
22#include "bpf_endian.h"
23
24int _version SEC("version") = 1;
25
26static inline __u32 rol32(__u32 word, unsigned int shift)
27{
28 return (word << shift) | (word >> ((-shift) & 31));
29}
30
31/* copy paste of jhash from kernel sources to make sure llvm
32 * can compile it into valid sequence of bpf instructions
33 */
34#define __jhash_mix(a, b, c) \
35{ \
36 a -= c; a ^= rol32(c, 4); c += b; \
37 b -= a; b ^= rol32(a, 6); a += c; \
38 c -= b; c ^= rol32(b, 8); b += a; \
39 a -= c; a ^= rol32(c, 16); c += b; \
40 b -= a; b ^= rol32(a, 19); a += c; \
41 c -= b; c ^= rol32(b, 4); b += a; \
42}
43
44#define __jhash_final(a, b, c) \
45{ \
46 c ^= b; c -= rol32(b, 14); \
47 a ^= c; a -= rol32(c, 11); \
48 b ^= a; b -= rol32(a, 25); \
49 c ^= b; c -= rol32(b, 16); \
50 a ^= c; a -= rol32(c, 4); \
51 b ^= a; b -= rol32(a, 14); \
52 c ^= b; c -= rol32(b, 24); \
53}
54
55#define JHASH_INITVAL 0xdeadbeef
56
57typedef unsigned int u32;
58
59static inline u32 jhash(const void *key, u32 length, u32 initval)
60{
61 u32 a, b, c;
62 const unsigned char *k = key;
63
64 a = b = c = JHASH_INITVAL + length + initval;
65
66 while (length > 12) {
67 a += *(u32 *)(k);
68 b += *(u32 *)(k + 4);
69 c += *(u32 *)(k + 8);
70 __jhash_mix(a, b, c);
71 length -= 12;
72 k += 12;
73 }
74 switch (length) {
75 case 12: c += (u32)k[11]<<24;
76 case 11: c += (u32)k[10]<<16;
77 case 10: c += (u32)k[9]<<8;
78 case 9: c += k[8];
79 case 8: b += (u32)k[7]<<24;
80 case 7: b += (u32)k[6]<<16;
81 case 6: b += (u32)k[5]<<8;
82 case 5: b += k[4];
83 case 4: a += (u32)k[3]<<24;
84 case 3: a += (u32)k[2]<<16;
85 case 2: a += (u32)k[1]<<8;
86 case 1: a += k[0];
87 __jhash_final(a, b, c);
88 case 0: /* Nothing left to add */
89 break;
90 }
91
92 return c;
93}
94
95static inline u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval)
96{
97 a += initval;
98 b += initval;
99 c += initval;
100 __jhash_final(a, b, c);
101 return c;
102}
103
104static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
105{
106 return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2));
107}
108
109#define PCKT_FRAGMENTED 65343
110#define IPV4_HDR_LEN_NO_OPT 20
111#define IPV4_PLUS_ICMP_HDR 28
112#define IPV6_PLUS_ICMP_HDR 48
113#define RING_SIZE 2
114#define MAX_VIPS 12
115#define MAX_REALS 5
116#define CTL_MAP_SIZE 16
117#define CH_RINGS_SIZE (MAX_VIPS * RING_SIZE)
118#define F_IPV6 (1 << 0)
119#define F_HASH_NO_SRC_PORT (1 << 0)
120#define F_ICMP (1 << 0)
121#define F_SYN_SET (1 << 1)
122
123struct packet_description {
124 union {
125 __be32 src;
126 __be32 srcv6[4];
127 };
128 union {
129 __be32 dst;
130 __be32 dstv6[4];
131 };
132 union {
133 __u32 ports;
134 __u16 port16[2];
135 };
136 __u8 proto;
137 __u8 flags;
138};
139
140struct ctl_value {
141 union {
142 __u64 value;
143 __u32 ifindex;
144 __u8 mac[6];
145 };
146};
147
148struct vip_meta {
149 __u32 flags;
150 __u32 vip_num;
151};
152
153struct real_definition {
154 union {
155 __be32 dst;
156 __be32 dstv6[4];
157 };
158 __u8 flags;
159};
160
161struct vip_stats {
162 __u64 bytes;
163 __u64 pkts;
164};
165
166struct eth_hdr {
167 unsigned char eth_dest[ETH_ALEN];
168 unsigned char eth_source[ETH_ALEN];
169 unsigned short eth_proto;
170};
171
172struct bpf_map_def SEC("maps") vip_map = {
173 .type = BPF_MAP_TYPE_HASH,
174 .key_size = sizeof(struct vip),
175 .value_size = sizeof(struct vip_meta),
176 .max_entries = MAX_VIPS,
177};
178
179struct bpf_map_def SEC("maps") ch_rings = {
180 .type = BPF_MAP_TYPE_ARRAY,
181 .key_size = sizeof(__u32),
182 .value_size = sizeof(__u32),
183 .max_entries = CH_RINGS_SIZE,
184};
185
186struct bpf_map_def SEC("maps") reals = {
187 .type = BPF_MAP_TYPE_ARRAY,
188 .key_size = sizeof(__u32),
189 .value_size = sizeof(struct real_definition),
190 .max_entries = MAX_REALS,
191};
192
193struct bpf_map_def SEC("maps") stats = {
194 .type = BPF_MAP_TYPE_PERCPU_ARRAY,
195 .key_size = sizeof(__u32),
196 .value_size = sizeof(struct vip_stats),
197 .max_entries = MAX_VIPS,
198};
199
200struct bpf_map_def SEC("maps") ctl_array = {
201 .type = BPF_MAP_TYPE_ARRAY,
202 .key_size = sizeof(__u32),
203 .value_size = sizeof(struct ctl_value),
204 .max_entries = CTL_MAP_SIZE,
205};
206
207static __always_inline __u32 get_packet_hash(struct packet_description *pckt,
208 bool ipv6)
209{
210 if (ipv6)
211 return jhash_2words(jhash(pckt->srcv6, 16, MAX_VIPS),
212 pckt->ports, CH_RINGS_SIZE);
213 else
214 return jhash_2words(pckt->src, pckt->ports, CH_RINGS_SIZE);
215}
216
217static __always_inline bool get_packet_dst(struct real_definition **real,
218 struct packet_description *pckt,
219 struct vip_meta *vip_info,
220 bool is_ipv6)
221{
222 __u32 hash = get_packet_hash(pckt, is_ipv6) % RING_SIZE;
223 __u32 key = RING_SIZE * vip_info->vip_num + hash;
224 __u32 *real_pos;
225
226 real_pos = bpf_map_lookup_elem(&ch_rings, &key);
227 if (!real_pos)
228 return false;
229 key = *real_pos;
230 *real = bpf_map_lookup_elem(&reals, &key);
231 if (!(*real))
232 return false;
233 return true;
234}
235
236static __always_inline int parse_icmpv6(void *data, void *data_end, __u64 off,
237 struct packet_description *pckt)
238{
239 struct icmp6hdr *icmp_hdr;
240 struct ipv6hdr *ip6h;
241
242 icmp_hdr = data + off;
243 if (icmp_hdr + 1 > data_end)
244 return TC_ACT_SHOT;
245 if (icmp_hdr->icmp6_type != ICMPV6_PKT_TOOBIG)
246 return TC_ACT_OK;
247 off += sizeof(struct icmp6hdr);
248 ip6h = data + off;
249 if (ip6h + 1 > data_end)
250 return TC_ACT_SHOT;
251 pckt->proto = ip6h->nexthdr;
252 pckt->flags |= F_ICMP;
253 memcpy(pckt->srcv6, ip6h->daddr.s6_addr32, 16);
254 memcpy(pckt->dstv6, ip6h->saddr.s6_addr32, 16);
255 return TC_ACT_UNSPEC;
256}
257
258static __always_inline int parse_icmp(void *data, void *data_end, __u64 off,
259 struct packet_description *pckt)
260{
261 struct icmphdr *icmp_hdr;
262 struct iphdr *iph;
263
264 icmp_hdr = data + off;
265 if (icmp_hdr + 1 > data_end)
266 return TC_ACT_SHOT;
267 if (icmp_hdr->type != ICMP_DEST_UNREACH ||
268 icmp_hdr->code != ICMP_FRAG_NEEDED)
269 return TC_ACT_OK;
270 off += sizeof(struct icmphdr);
271 iph = data + off;
272 if (iph + 1 > data_end)
273 return TC_ACT_SHOT;
274 if (iph->ihl != 5)
275 return TC_ACT_SHOT;
276 pckt->proto = iph->protocol;
277 pckt->flags |= F_ICMP;
278 pckt->src = iph->daddr;
279 pckt->dst = iph->saddr;
280 return TC_ACT_UNSPEC;
281}
282
283static __always_inline bool parse_udp(void *data, __u64 off, void *data_end,
284 struct packet_description *pckt)
285{
286 struct udphdr *udp;
287 udp = data + off;
288
289 if (udp + 1 > data_end)
290 return false;
291
292 if (!(pckt->flags & F_ICMP)) {
293 pckt->port16[0] = udp->source;
294 pckt->port16[1] = udp->dest;
295 } else {
296 pckt->port16[0] = udp->dest;
297 pckt->port16[1] = udp->source;
298 }
299 return true;
300}
301
302static __always_inline bool parse_tcp(void *data, __u64 off, void *data_end,
303 struct packet_description *pckt)
304{
305 struct tcphdr *tcp;
306
307 tcp = data + off;
308 if (tcp + 1 > data_end)
309 return false;
310
311 if (tcp->syn)
312 pckt->flags |= F_SYN_SET;
313
314 if (!(pckt->flags & F_ICMP)) {
315 pckt->port16[0] = tcp->source;
316 pckt->port16[1] = tcp->dest;
317 } else {
318 pckt->port16[0] = tcp->dest;
319 pckt->port16[1] = tcp->source;
320 }
321 return true;
322}
323
324static __always_inline int process_packet(void *data, __u64 off, void *data_end,
325 bool is_ipv6, struct __sk_buff *skb)
326{
327 void *pkt_start = (void *)(long)skb->data;
328 struct packet_description pckt = {};
329 struct eth_hdr *eth = pkt_start;
330 struct bpf_tunnel_key tkey = {};
331 struct vip_stats *data_stats;
332 struct real_definition *dst;
333 struct vip_meta *vip_info;
334 struct ctl_value *cval;
335 __u32 v4_intf_pos = 1;
336 __u32 v6_intf_pos = 2;
337 struct ipv6hdr *ip6h;
338 struct vip vip = {};
339 struct iphdr *iph;
340 int tun_flag = 0;
341 __u16 pkt_bytes;
342 __u64 iph_len;
343 __u32 ifindex;
344 __u8 protocol;
345 __u32 vip_num;
346 int action;
347
348 tkey.tunnel_ttl = 64;
349 if (is_ipv6) {
350 ip6h = data + off;
351 if (ip6h + 1 > data_end)
352 return TC_ACT_SHOT;
353
354 iph_len = sizeof(struct ipv6hdr);
355 protocol = ip6h->nexthdr;
356 pckt.proto = protocol;
357 pkt_bytes = bpf_ntohs(ip6h->payload_len);
358 off += iph_len;
359 if (protocol == IPPROTO_FRAGMENT) {
360 return TC_ACT_SHOT;
361 } else if (protocol == IPPROTO_ICMPV6) {
362 action = parse_icmpv6(data, data_end, off, &pckt);
363 if (action >= 0)
364 return action;
365 off += IPV6_PLUS_ICMP_HDR;
366 } else {
367 memcpy(pckt.srcv6, ip6h->saddr.s6_addr32, 16);
368 memcpy(pckt.dstv6, ip6h->daddr.s6_addr32, 16);
369 }
370 } else {
371 iph = data + off;
372 if (iph + 1 > data_end)
373 return TC_ACT_SHOT;
374 if (iph->ihl != 5)
375 return TC_ACT_SHOT;
376
377 protocol = iph->protocol;
378 pckt.proto = protocol;
379 pkt_bytes = bpf_ntohs(iph->tot_len);
380 off += IPV4_HDR_LEN_NO_OPT;
381
382 if (iph->frag_off & PCKT_FRAGMENTED)
383 return TC_ACT_SHOT;
384 if (protocol == IPPROTO_ICMP) {
385 action = parse_icmp(data, data_end, off, &pckt);
386 if (action >= 0)
387 return action;
388 off += IPV4_PLUS_ICMP_HDR;
389 } else {
390 pckt.src = iph->saddr;
391 pckt.dst = iph->daddr;
392 }
393 }
394 protocol = pckt.proto;
395
396 if (protocol == IPPROTO_TCP) {
397 if (!parse_tcp(data, off, data_end, &pckt))
398 return TC_ACT_SHOT;
399 } else if (protocol == IPPROTO_UDP) {
400 if (!parse_udp(data, off, data_end, &pckt))
401 return TC_ACT_SHOT;
402 } else {
403 return TC_ACT_SHOT;
404 }
405
406 if (is_ipv6)
407 memcpy(vip.daddr.v6, pckt.dstv6, 16);
408 else
409 vip.daddr.v4 = pckt.dst;
410
411 vip.dport = pckt.port16[1];
412 vip.protocol = pckt.proto;
413 vip_info = bpf_map_lookup_elem(&vip_map, &vip);
414 if (!vip_info) {
415 vip.dport = 0;
416 vip_info = bpf_map_lookup_elem(&vip_map, &vip);
417 if (!vip_info)
418 return TC_ACT_SHOT;
419 pckt.port16[1] = 0;
420 }
421
422 if (vip_info->flags & F_HASH_NO_SRC_PORT)
423 pckt.port16[0] = 0;
424
425 if (!get_packet_dst(&dst, &pckt, vip_info, is_ipv6))
426 return TC_ACT_SHOT;
427
428 if (dst->flags & F_IPV6) {
429 cval = bpf_map_lookup_elem(&ctl_array, &v6_intf_pos);
430 if (!cval)
431 return TC_ACT_SHOT;
432 ifindex = cval->ifindex;
433 memcpy(tkey.remote_ipv6, dst->dstv6, 16);
434 tun_flag = BPF_F_TUNINFO_IPV6;
435 } else {
436 cval = bpf_map_lookup_elem(&ctl_array, &v4_intf_pos);
437 if (!cval)
438 return TC_ACT_SHOT;
439 ifindex = cval->ifindex;
440 tkey.remote_ipv4 = dst->dst;
441 }
442 vip_num = vip_info->vip_num;
443 data_stats = bpf_map_lookup_elem(&stats, &vip_num);
444 if (!data_stats)
445 return TC_ACT_SHOT;
446 data_stats->pkts++;
447 data_stats->bytes += pkt_bytes;
448 bpf_skb_set_tunnel_key(skb, &tkey, sizeof(tkey), tun_flag);
449 *(u32 *)eth->eth_dest = tkey.remote_ipv4;
450 return bpf_redirect(ifindex, 0);
451}
452
453SEC("l4lb-demo")
454int balancer_ingress(struct __sk_buff *ctx)
455{
456 void *data_end = (void *)(long)ctx->data_end;
457 void *data = (void *)(long)ctx->data;
458 struct eth_hdr *eth = data;
459 __u32 eth_proto;
460 __u32 nh_off;
461
462 nh_off = sizeof(struct eth_hdr);
463 if (data + nh_off > data_end)
464 return TC_ACT_SHOT;
465 eth_proto = eth->eth_proto;
466 if (eth_proto == bpf_htons(ETH_P_IP))
467 return process_packet(data, nh_off, data_end, false, ctx);
468 else if (eth_proto == bpf_htons(ETH_P_IPV6))
469 return process_packet(data, nh_off, data_end, true, ctx);
470 else
471 return TC_ACT_SHOT;
472}
473char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_lru_map.c b/tools/testing/selftests/bpf/test_lru_map.c
index 00b0aff56e2e..8c10c9180c1a 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -22,7 +22,7 @@
22#include "bpf_util.h" 22#include "bpf_util.h"
23 23
24#define LOCAL_FREE_TARGET (128) 24#define LOCAL_FREE_TARGET (128)
25#define PERCPU_FREE_TARGET (16) 25#define PERCPU_FREE_TARGET (4)
26 26
27static int nr_cpus; 27static int nr_cpus;
28 28
@@ -191,12 +191,7 @@ static void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free)
191 int next_cpu = 0; 191 int next_cpu = 0;
192 192
193 if (map_flags & BPF_F_NO_COMMON_LRU) 193 if (map_flags & BPF_F_NO_COMMON_LRU)
194 /* Ther percpu lru list (i.e each cpu has its own LRU 194 /* This test is only applicable to common LRU list */
195 * list) does not have a local free list. Hence,
196 * it will only free old nodes till there is no free
197 * from the LRU list. Hence, this test does not apply
198 * to BPF_F_NO_COMMON_LRU
199 */
200 return; 195 return;
201 196
202 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 197 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
@@ -227,7 +222,7 @@ static void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free)
227 for (key = 1; key < end_key; key++) { 222 for (key = 1; key < end_key; key++) {
228 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 223 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
229 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 224 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
230 BPF_NOEXIST)); 225 BPF_NOEXIST));
231 } 226 }
232 227
233 /* Insert 1+tgt_free to 2*tgt_free 228 /* Insert 1+tgt_free to 2*tgt_free
@@ -273,12 +268,7 @@ static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
273 int next_cpu = 0; 268 int next_cpu = 0;
274 269
275 if (map_flags & BPF_F_NO_COMMON_LRU) 270 if (map_flags & BPF_F_NO_COMMON_LRU)
276 /* Ther percpu lru list (i.e each cpu has its own LRU 271 /* This test is only applicable to common LRU list */
277 * list) does not have a local free list. Hence,
278 * it will only free old nodes till there is no free
279 * from the LRU list. Hence, this test does not apply
280 * to BPF_F_NO_COMMON_LRU
281 */
282 return; 272 return;
283 273
284 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 274 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
@@ -290,11 +280,7 @@ static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
290 assert(batch_size * 2 == tgt_free); 280 assert(batch_size * 2 == tgt_free);
291 281
292 map_size = tgt_free + batch_size; 282 map_size = tgt_free + batch_size;
293 if (map_flags & BPF_F_NO_COMMON_LRU) 283 lru_map_fd = create_map(map_type, map_flags, map_size);
294 lru_map_fd = create_map(map_type, map_flags,
295 map_size * nr_cpus);
296 else
297 lru_map_fd = create_map(map_type, map_flags, map_size);
298 assert(lru_map_fd != -1); 284 assert(lru_map_fd != -1);
299 285
300 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size); 286 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
@@ -341,7 +327,7 @@ static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
341 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 327 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
342 assert(value[0] == 4321); 328 assert(value[0] == 4321);
343 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 329 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
344 BPF_NOEXIST)); 330 BPF_NOEXIST));
345 } 331 }
346 332
347 value[0] = 1234; 333 value[0] = 1234;
@@ -361,7 +347,7 @@ static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
361 assert(!bpf_map_update_elem(lru_map_fd, &key, value, 347 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
362 BPF_NOEXIST)); 348 BPF_NOEXIST));
363 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 349 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
364 BPF_NOEXIST)); 350 BPF_NOEXIST));
365 } 351 }
366 352
367 assert(map_equal(lru_map_fd, expected_map_fd)); 353 assert(map_equal(lru_map_fd, expected_map_fd));
@@ -387,6 +373,10 @@ static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
387 unsigned int map_size; 373 unsigned int map_size;
388 int next_cpu = 0; 374 int next_cpu = 0;
389 375
376 if (map_flags & BPF_F_NO_COMMON_LRU)
377 /* This test is only applicable to common LRU list */
378 return;
379
390 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 380 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
391 map_flags); 381 map_flags);
392 382
@@ -396,11 +386,7 @@ static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
396 assert(batch_size * 2 == tgt_free); 386 assert(batch_size * 2 == tgt_free);
397 387
398 map_size = tgt_free * 2; 388 map_size = tgt_free * 2;
399 if (map_flags & BPF_F_NO_COMMON_LRU) 389 lru_map_fd = create_map(map_type, map_flags, map_size);
400 lru_map_fd = create_map(map_type, map_flags,
401 map_size * nr_cpus);
402 else
403 lru_map_fd = create_map(map_type, map_flags, map_size);
404 assert(lru_map_fd != -1); 390 assert(lru_map_fd != -1);
405 391
406 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size); 392 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
@@ -419,7 +405,7 @@ static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
419 for (key = 1; key < end_key; key++) { 405 for (key = 1; key < end_key; key++) {
420 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 406 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
421 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 407 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
422 BPF_NOEXIST)); 408 BPF_NOEXIST));
423 } 409 }
424 410
425 /* Add 1+2*tgt_free to tgt_free*5/2 411 /* Add 1+2*tgt_free to tgt_free*5/2
@@ -431,7 +417,7 @@ static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
431 assert(!bpf_map_update_elem(lru_map_fd, &key, value, 417 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
432 BPF_NOEXIST)); 418 BPF_NOEXIST));
433 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 419 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
434 BPF_NOEXIST)); 420 BPF_NOEXIST));
435 } 421 }
436 422
437 assert(map_equal(lru_map_fd, expected_map_fd)); 423 assert(map_equal(lru_map_fd, expected_map_fd));
@@ -491,7 +477,7 @@ static void test_lru_sanity4(int map_type, int map_flags, unsigned int tgt_free)
491 assert(!bpf_map_update_elem(lru_map_fd, &key, value, 477 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
492 BPF_NOEXIST)); 478 BPF_NOEXIST));
493 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 479 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
494 BPF_NOEXIST)); 480 BPF_NOEXIST));
495 } 481 }
496 482
497 assert(map_equal(lru_map_fd, expected_map_fd)); 483 assert(map_equal(lru_map_fd, expected_map_fd));
@@ -566,6 +552,65 @@ static void test_lru_sanity5(int map_type, int map_flags)
566 printf("Pass\n"); 552 printf("Pass\n");
567} 553}
568 554
555/* Test list rotation for BPF_F_NO_COMMON_LRU map */
556static void test_lru_sanity6(int map_type, int map_flags, int tgt_free)
557{
558 int lru_map_fd, expected_map_fd;
559 unsigned long long key, value[nr_cpus];
560 unsigned int map_size = tgt_free * 2;
561 int next_cpu = 0;
562
563 if (!(map_flags & BPF_F_NO_COMMON_LRU))
564 return;
565
566 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
567 map_flags);
568
569 assert(sched_next_online(0, &next_cpu) != -1);
570
571 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, map_size);
572 assert(expected_map_fd != -1);
573
574 lru_map_fd = create_map(map_type, map_flags, map_size * nr_cpus);
575 assert(lru_map_fd != -1);
576
577 value[0] = 1234;
578
579 for (key = 1; key <= tgt_free; key++) {
580 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
581 BPF_NOEXIST));
582 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
583 BPF_NOEXIST));
584 }
585
586 for (; key <= tgt_free * 2; key++) {
587 unsigned long long stable_key;
588
589 /* Make ref bit sticky for key: [1, tgt_free] */
590 for (stable_key = 1; stable_key <= tgt_free; stable_key++) {
591 /* Mark the ref bit */
592 assert(!bpf_map_lookup_elem(lru_map_fd, &stable_key,
593 value));
594 }
595 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
596 BPF_NOEXIST));
597 }
598
599 for (; key <= tgt_free * 3; key++) {
600 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
601 BPF_NOEXIST));
602 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
603 BPF_NOEXIST));
604 }
605
606 assert(map_equal(lru_map_fd, expected_map_fd));
607
608 close(expected_map_fd);
609 close(lru_map_fd);
610
611 printf("Pass\n");
612}
613
569int main(int argc, char **argv) 614int main(int argc, char **argv)
570{ 615{
571 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 616 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
@@ -593,6 +638,7 @@ int main(int argc, char **argv)
593 test_lru_sanity3(map_types[t], map_flags[f], tgt_free); 638 test_lru_sanity3(map_types[t], map_flags[f], tgt_free);
594 test_lru_sanity4(map_types[t], map_flags[f], tgt_free); 639 test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
595 test_lru_sanity5(map_types[t], map_flags[f]); 640 test_lru_sanity5(map_types[t], map_flags[f]);
641 test_lru_sanity6(map_types[t], map_flags[f], tgt_free);
596 642
597 printf("\n"); 643 printf("\n");
598 } 644 }
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index a0aa2009b0e0..93314524de0d 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -28,7 +28,7 @@ static int map_flags;
28 28
29static void test_hashmap(int task, void *data) 29static void test_hashmap(int task, void *data)
30{ 30{
31 long long key, next_key, value; 31 long long key, next_key, first_key, value;
32 int fd; 32 int fd;
33 33
34 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 34 fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
@@ -89,10 +89,13 @@ static void test_hashmap(int task, void *data)
89 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT); 89 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
90 90
91 /* Iterate over two elements. */ 91 /* Iterate over two elements. */
92 assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
93 (first_key == 1 || first_key == 2));
92 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && 94 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
93 (next_key == 1 || next_key == 2)); 95 (next_key == first_key));
94 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && 96 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
95 (next_key == 1 || next_key == 2)); 97 (next_key == 1 || next_key == 2) &&
98 (next_key != first_key));
96 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 && 99 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 &&
97 errno == ENOENT); 100 errno == ENOENT);
98 101
@@ -105,6 +108,8 @@ static void test_hashmap(int task, void *data)
105 108
106 key = 0; 109 key = 0;
107 /* Check that map is empty. */ 110 /* Check that map is empty. */
111 assert(bpf_map_get_next_key(fd, NULL, &next_key) == -1 &&
112 errno == ENOENT);
108 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 && 113 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 &&
109 errno == ENOENT); 114 errno == ENOENT);
110 115
@@ -132,20 +137,20 @@ static void test_hashmap_sizes(int task, void *data)
132static void test_hashmap_percpu(int task, void *data) 137static void test_hashmap_percpu(int task, void *data)
133{ 138{
134 unsigned int nr_cpus = bpf_num_possible_cpus(); 139 unsigned int nr_cpus = bpf_num_possible_cpus();
135 long long value[nr_cpus]; 140 BPF_DECLARE_PERCPU(long, value);
136 long long key, next_key; 141 long long key, next_key, first_key;
137 int expected_key_mask = 0; 142 int expected_key_mask = 0;
138 int fd, i; 143 int fd, i;
139 144
140 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key), 145 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
141 sizeof(value[0]), 2, map_flags); 146 sizeof(bpf_percpu(value, 0)), 2, map_flags);
142 if (fd < 0) { 147 if (fd < 0) {
143 printf("Failed to create hashmap '%s'!\n", strerror(errno)); 148 printf("Failed to create hashmap '%s'!\n", strerror(errno));
144 exit(1); 149 exit(1);
145 } 150 }
146 151
147 for (i = 0; i < nr_cpus; i++) 152 for (i = 0; i < nr_cpus; i++)
148 value[i] = i + 100; 153 bpf_percpu(value, i) = i + 100;
149 154
150 key = 1; 155 key = 1;
151 /* Insert key=1 element. */ 156 /* Insert key=1 element. */
@@ -165,8 +170,9 @@ static void test_hashmap_percpu(int task, void *data)
165 /* Check that key=1 can be found. Value could be 0 if the lookup 170 /* Check that key=1 can be found. Value could be 0 if the lookup
166 * was run from a different CPU. 171 * was run from a different CPU.
167 */ 172 */
168 value[0] = 1; 173 bpf_percpu(value, 0) = 1;
169 assert(bpf_map_lookup_elem(fd, &key, value) == 0 && value[0] == 100); 174 assert(bpf_map_lookup_elem(fd, &key, value) == 0 &&
175 bpf_percpu(value, 0) == 100);
170 176
171 key = 2; 177 key = 2;
172 /* Check that key=2 is not found. */ 178 /* Check that key=2 is not found. */
@@ -193,14 +199,20 @@ static void test_hashmap_percpu(int task, void *data)
193 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT); 199 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
194 200
195 /* Iterate over two elements. */ 201 /* Iterate over two elements. */
202 assert(bpf_map_get_next_key(fd, NULL, &first_key) == 0 &&
203 ((expected_key_mask & first_key) == first_key));
196 while (!bpf_map_get_next_key(fd, &key, &next_key)) { 204 while (!bpf_map_get_next_key(fd, &key, &next_key)) {
205 if (first_key) {
206 assert(next_key == first_key);
207 first_key = 0;
208 }
197 assert((expected_key_mask & next_key) == next_key); 209 assert((expected_key_mask & next_key) == next_key);
198 expected_key_mask &= ~next_key; 210 expected_key_mask &= ~next_key;
199 211
200 assert(bpf_map_lookup_elem(fd, &next_key, value) == 0); 212 assert(bpf_map_lookup_elem(fd, &next_key, value) == 0);
201 213
202 for (i = 0; i < nr_cpus; i++) 214 for (i = 0; i < nr_cpus; i++)
203 assert(value[i] == i + 100); 215 assert(bpf_percpu(value, i) == i + 100);
204 216
205 key = next_key; 217 key = next_key;
206 } 218 }
@@ -219,6 +231,8 @@ static void test_hashmap_percpu(int task, void *data)
219 231
220 key = 0; 232 key = 0;
221 /* Check that map is empty. */ 233 /* Check that map is empty. */
234 assert(bpf_map_get_next_key(fd, NULL, &next_key) == -1 &&
235 errno == ENOENT);
222 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 && 236 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 &&
223 errno == ENOENT); 237 errno == ENOENT);
224 238
@@ -264,6 +278,8 @@ static void test_arraymap(int task, void *data)
264 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT); 278 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
265 279
266 /* Iterate over two elements. */ 280 /* Iterate over two elements. */
281 assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
282 next_key == 0);
267 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && 283 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
268 next_key == 0); 284 next_key == 0);
269 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && 285 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
@@ -281,34 +297,36 @@ static void test_arraymap(int task, void *data)
281static void test_arraymap_percpu(int task, void *data) 297static void test_arraymap_percpu(int task, void *data)
282{ 298{
283 unsigned int nr_cpus = bpf_num_possible_cpus(); 299 unsigned int nr_cpus = bpf_num_possible_cpus();
300 BPF_DECLARE_PERCPU(long, values);
284 int key, next_key, fd, i; 301 int key, next_key, fd, i;
285 long values[nr_cpus];
286 302
287 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), 303 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
288 sizeof(values[0]), 2, 0); 304 sizeof(bpf_percpu(values, 0)), 2, 0);
289 if (fd < 0) { 305 if (fd < 0) {
290 printf("Failed to create arraymap '%s'!\n", strerror(errno)); 306 printf("Failed to create arraymap '%s'!\n", strerror(errno));
291 exit(1); 307 exit(1);
292 } 308 }
293 309
294 for (i = 0; i < nr_cpus; i++) 310 for (i = 0; i < nr_cpus; i++)
295 values[i] = i + 100; 311 bpf_percpu(values, i) = i + 100;
296 312
297 key = 1; 313 key = 1;
298 /* Insert key=1 element. */ 314 /* Insert key=1 element. */
299 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); 315 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
300 316
301 values[0] = 0; 317 bpf_percpu(values, 0) = 0;
302 assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) == -1 && 318 assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) == -1 &&
303 errno == EEXIST); 319 errno == EEXIST);
304 320
305 /* Check that key=1 can be found. */ 321 /* Check that key=1 can be found. */
306 assert(bpf_map_lookup_elem(fd, &key, values) == 0 && values[0] == 100); 322 assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
323 bpf_percpu(values, 0) == 100);
307 324
308 key = 0; 325 key = 0;
309 /* Check that key=0 is also found and zero initialized. */ 326 /* Check that key=0 is also found and zero initialized. */
310 assert(bpf_map_lookup_elem(fd, &key, values) == 0 && 327 assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
311 values[0] == 0 && values[nr_cpus - 1] == 0); 328 bpf_percpu(values, 0) == 0 &&
329 bpf_percpu(values, nr_cpus - 1) == 0);
312 330
313 /* Check that key=2 cannot be inserted due to max_entries limit. */ 331 /* Check that key=2 cannot be inserted due to max_entries limit. */
314 key = 2; 332 key = 2;
@@ -319,6 +337,8 @@ static void test_arraymap_percpu(int task, void *data)
319 assert(bpf_map_lookup_elem(fd, &key, values) == -1 && errno == ENOENT); 337 assert(bpf_map_lookup_elem(fd, &key, values) == -1 && errno == ENOENT);
320 338
321 /* Iterate over two elements. */ 339 /* Iterate over two elements. */
340 assert(bpf_map_get_next_key(fd, NULL, &next_key) == 0 &&
341 next_key == 0);
322 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 && 342 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
323 next_key == 0); 343 next_key == 0);
324 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 && 344 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
@@ -336,15 +356,15 @@ static void test_arraymap_percpu(int task, void *data)
336static void test_arraymap_percpu_many_keys(void) 356static void test_arraymap_percpu_many_keys(void)
337{ 357{
338 unsigned int nr_cpus = bpf_num_possible_cpus(); 358 unsigned int nr_cpus = bpf_num_possible_cpus();
359 BPF_DECLARE_PERCPU(long, values);
339 /* nr_keys is not too large otherwise the test stresses percpu 360 /* nr_keys is not too large otherwise the test stresses percpu
340 * allocator more than anything else 361 * allocator more than anything else
341 */ 362 */
342 unsigned int nr_keys = 2000; 363 unsigned int nr_keys = 2000;
343 long values[nr_cpus];
344 int key, fd, i; 364 int key, fd, i;
345 365
346 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), 366 fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
347 sizeof(values[0]), nr_keys, 0); 367 sizeof(bpf_percpu(values, 0)), nr_keys, 0);
348 if (fd < 0) { 368 if (fd < 0) {
349 printf("Failed to create per-cpu arraymap '%s'!\n", 369 printf("Failed to create per-cpu arraymap '%s'!\n",
350 strerror(errno)); 370 strerror(errno));
@@ -352,19 +372,19 @@ static void test_arraymap_percpu_many_keys(void)
352 } 372 }
353 373
354 for (i = 0; i < nr_cpus; i++) 374 for (i = 0; i < nr_cpus; i++)
355 values[i] = i + 10; 375 bpf_percpu(values, i) = i + 10;
356 376
357 for (key = 0; key < nr_keys; key++) 377 for (key = 0; key < nr_keys; key++)
358 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); 378 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
359 379
360 for (key = 0; key < nr_keys; key++) { 380 for (key = 0; key < nr_keys; key++) {
361 for (i = 0; i < nr_cpus; i++) 381 for (i = 0; i < nr_cpus; i++)
362 values[i] = 0; 382 bpf_percpu(values, i) = 0;
363 383
364 assert(bpf_map_lookup_elem(fd, &key, values) == 0); 384 assert(bpf_map_lookup_elem(fd, &key, values) == 0);
365 385
366 for (i = 0; i < nr_cpus; i++) 386 for (i = 0; i < nr_cpus; i++)
367 assert(values[i] == i + 10); 387 assert(bpf_percpu(values, i) == i + 10);
368 } 388 }
369 389
370 close(fd); 390 close(fd);
@@ -400,6 +420,8 @@ static void test_map_large(void)
400 errno == E2BIG); 420 errno == E2BIG);
401 421
402 /* Iterate through all elements. */ 422 /* Iterate through all elements. */
423 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
424 key.c = -1;
403 for (i = 0; i < MAP_SIZE; i++) 425 for (i = 0; i < MAP_SIZE; i++)
404 assert(bpf_map_get_next_key(fd, &key, &key) == 0); 426 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
405 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT); 427 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
@@ -499,6 +521,7 @@ static void test_map_parallel(void)
499 errno == EEXIST); 521 errno == EEXIST);
500 522
501 /* Check that all elements were inserted. */ 523 /* Check that all elements were inserted. */
524 assert(bpf_map_get_next_key(fd, NULL, &key) == 0);
502 key = -1; 525 key = -1;
503 for (i = 0; i < MAP_SIZE; i++) 526 for (i = 0; i < MAP_SIZE; i++)
504 assert(bpf_map_get_next_key(fd, &key, &key) == 0); 527 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
@@ -518,6 +541,7 @@ static void test_map_parallel(void)
518 541
519 /* Nothing should be left. */ 542 /* Nothing should be left. */
520 key = -1; 543 key = -1;
544 assert(bpf_map_get_next_key(fd, NULL, &key) == -1 && errno == ENOENT);
521 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT); 545 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
522} 546}
523 547
diff --git a/tools/testing/selftests/bpf/test_pkt_access.c b/tools/testing/selftests/bpf/test_pkt_access.c
new file mode 100644
index 000000000000..6e11ba11709e
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_pkt_access.c
@@ -0,0 +1,65 @@
1/* Copyright (c) 2017 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <stddef.h>
8#include <string.h>
9#include <linux/bpf.h>
10#include <linux/if_ether.h>
11#include <linux/if_packet.h>
12#include <linux/ip.h>
13#include <linux/ipv6.h>
14#include <linux/in.h>
15#include <linux/tcp.h>
16#include <linux/pkt_cls.h>
17#include "bpf_helpers.h"
18#include "bpf_endian.h"
19
20#define barrier() __asm__ __volatile__("": : :"memory")
21int _version SEC("version") = 1;
22
23SEC("test1")
24int process(struct __sk_buff *skb)
25{
26 void *data_end = (void *)(long)skb->data_end;
27 void *data = (void *)(long)skb->data;
28 struct ethhdr *eth = (struct ethhdr *)(data);
29 struct tcphdr *tcp = NULL;
30 __u8 proto = 255;
31 __u64 ihl_len;
32
33 if (eth + 1 > data_end)
34 return TC_ACT_SHOT;
35
36 if (eth->h_proto == bpf_htons(ETH_P_IP)) {
37 struct iphdr *iph = (struct iphdr *)(eth + 1);
38
39 if (iph + 1 > data_end)
40 return TC_ACT_SHOT;
41 ihl_len = iph->ihl * 4;
42 proto = iph->protocol;
43 tcp = (struct tcphdr *)((void *)(iph) + ihl_len);
44 } else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) {
45 struct ipv6hdr *ip6h = (struct ipv6hdr *)(eth + 1);
46
47 if (ip6h + 1 > data_end)
48 return TC_ACT_SHOT;
49 ihl_len = sizeof(*ip6h);
50 proto = ip6h->nexthdr;
51 tcp = (struct tcphdr *)((void *)(ip6h) + ihl_len);
52 }
53
54 if (tcp) {
55 if (((void *)(tcp) + 20) > data_end || proto != 6)
56 return TC_ACT_SHOT;
57 barrier(); /* to force ordering of checks */
58 if (((void *)(tcp) + 18) > data_end)
59 return TC_ACT_SHOT;
60 if (tcp->urg_ptr == 123)
61 return TC_ACT_OK;
62 }
63
64 return TC_ACT_UNSPEC;
65}
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
new file mode 100644
index 000000000000..b59f5ed4ae40
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -0,0 +1,299 @@
1/* Copyright (c) 2017 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <stdio.h>
8#include <unistd.h>
9#include <errno.h>
10#include <string.h>
11#include <assert.h>
12#include <stdlib.h>
13
14#include <linux/types.h>
15typedef __u16 __sum16;
16#include <arpa/inet.h>
17#include <linux/if_ether.h>
18#include <linux/if_packet.h>
19#include <linux/ip.h>
20#include <linux/ipv6.h>
21#include <linux/tcp.h>
22
23#include <sys/wait.h>
24#include <sys/resource.h>
25
26#include <linux/bpf.h>
27#include <linux/err.h>
28#include <bpf/bpf.h>
29#include <bpf/libbpf.h>
30#include "test_iptunnel_common.h"
31#include "bpf_util.h"
32#include "bpf_endian.h"
33
34static int error_cnt, pass_cnt;
35
36#define MAGIC_BYTES 123
37
38/* ipv4 test vector */
39static struct {
40 struct ethhdr eth;
41 struct iphdr iph;
42 struct tcphdr tcp;
43} __packed pkt_v4 = {
44 .eth.h_proto = bpf_htons(ETH_P_IP),
45 .iph.ihl = 5,
46 .iph.protocol = 6,
47 .iph.tot_len = bpf_htons(MAGIC_BYTES),
48 .tcp.urg_ptr = 123,
49};
50
51/* ipv6 test vector */
52static struct {
53 struct ethhdr eth;
54 struct ipv6hdr iph;
55 struct tcphdr tcp;
56} __packed pkt_v6 = {
57 .eth.h_proto = bpf_htons(ETH_P_IPV6),
58 .iph.nexthdr = 6,
59 .iph.payload_len = bpf_htons(MAGIC_BYTES),
60 .tcp.urg_ptr = 123,
61};
62
63#define CHECK(condition, tag, format...) ({ \
64 int __ret = !!(condition); \
65 if (__ret) { \
66 error_cnt++; \
67 printf("%s:FAIL:%s ", __func__, tag); \
68 printf(format); \
69 } else { \
70 pass_cnt++; \
71 printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\
72 } \
73})
74
75static int bpf_prog_load(const char *file, enum bpf_prog_type type,
76 struct bpf_object **pobj, int *prog_fd)
77{
78 struct bpf_program *prog;
79 struct bpf_object *obj;
80 int err;
81
82 obj = bpf_object__open(file);
83 if (IS_ERR(obj)) {
84 error_cnt++;
85 return -ENOENT;
86 }
87
88 prog = bpf_program__next(NULL, obj);
89 if (!prog) {
90 bpf_object__close(obj);
91 error_cnt++;
92 return -ENOENT;
93 }
94
95 bpf_program__set_type(prog, type);
96 err = bpf_object__load(obj);
97 if (err) {
98 bpf_object__close(obj);
99 error_cnt++;
100 return -EINVAL;
101 }
102
103 *pobj = obj;
104 *prog_fd = bpf_program__fd(prog);
105 return 0;
106}
107
108static int bpf_find_map(const char *test, struct bpf_object *obj,
109 const char *name)
110{
111 struct bpf_map *map;
112
113 map = bpf_object__find_map_by_name(obj, name);
114 if (!map) {
115 printf("%s:FAIL:map '%s' not found\n", test, name);
116 error_cnt++;
117 return -1;
118 }
119 return bpf_map__fd(map);
120}
121
122static void test_pkt_access(void)
123{
124 const char *file = "./test_pkt_access.o";
125 struct bpf_object *obj;
126 __u32 duration, retval;
127 int err, prog_fd;
128
129 err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
130 if (err)
131 return;
132
133 err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
134 NULL, NULL, &retval, &duration);
135 CHECK(err || errno || retval, "ipv4",
136 "err %d errno %d retval %d duration %d\n",
137 err, errno, retval, duration);
138
139 err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6),
140 NULL, NULL, &retval, &duration);
141 CHECK(err || errno || retval, "ipv6",
142 "err %d errno %d retval %d duration %d\n",
143 err, errno, retval, duration);
144 bpf_object__close(obj);
145}
146
147static void test_xdp(void)
148{
149 struct vip key4 = {.protocol = 6, .family = AF_INET};
150 struct vip key6 = {.protocol = 6, .family = AF_INET6};
151 struct iptnl_info value4 = {.family = AF_INET};
152 struct iptnl_info value6 = {.family = AF_INET6};
153 const char *file = "./test_xdp.o";
154 struct bpf_object *obj;
155 char buf[128];
156 struct ipv6hdr *iph6 = (void *)buf + sizeof(struct ethhdr);
157 struct iphdr *iph = (void *)buf + sizeof(struct ethhdr);
158 __u32 duration, retval, size;
159 int err, prog_fd, map_fd;
160
161 err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
162 if (err)
163 return;
164
165 map_fd = bpf_find_map(__func__, obj, "vip2tnl");
166 if (map_fd < 0)
167 goto out;
168 bpf_map_update_elem(map_fd, &key4, &value4, 0);
169 bpf_map_update_elem(map_fd, &key6, &value6, 0);
170
171 err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
172 buf, &size, &retval, &duration);
173
174 CHECK(err || errno || retval != XDP_TX || size != 74 ||
175 iph->protocol != IPPROTO_IPIP, "ipv4",
176 "err %d errno %d retval %d size %d\n",
177 err, errno, retval, size);
178
179 err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6),
180 buf, &size, &retval, &duration);
181 CHECK(err || errno || retval != XDP_TX || size != 114 ||
182 iph6->nexthdr != IPPROTO_IPV6, "ipv6",
183 "err %d errno %d retval %d size %d\n",
184 err, errno, retval, size);
185out:
186 bpf_object__close(obj);
187}
188
189#define MAGIC_VAL 0x1234
190#define NUM_ITER 100000
191#define VIP_NUM 5
192
193static void test_l4lb(void)
194{
195 unsigned int nr_cpus = bpf_num_possible_cpus();
196 const char *file = "./test_l4lb.o";
197 struct vip key = {.protocol = 6};
198 struct vip_meta {
199 __u32 flags;
200 __u32 vip_num;
201 } value = {.vip_num = VIP_NUM};
202 __u32 stats_key = VIP_NUM;
203 struct vip_stats {
204 __u64 bytes;
205 __u64 pkts;
206 } stats[nr_cpus];
207 struct real_definition {
208 union {
209 __be32 dst;
210 __be32 dstv6[4];
211 };
212 __u8 flags;
213 } real_def = {.dst = MAGIC_VAL};
214 __u32 ch_key = 11, real_num = 3;
215 __u32 duration, retval, size;
216 int err, i, prog_fd, map_fd;
217 __u64 bytes = 0, pkts = 0;
218 struct bpf_object *obj;
219 char buf[128];
220 u32 *magic = (u32 *)buf;
221
222 err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
223 if (err)
224 return;
225
226 map_fd = bpf_find_map(__func__, obj, "vip_map");
227 if (map_fd < 0)
228 goto out;
229 bpf_map_update_elem(map_fd, &key, &value, 0);
230
231 map_fd = bpf_find_map(__func__, obj, "ch_rings");
232 if (map_fd < 0)
233 goto out;
234 bpf_map_update_elem(map_fd, &ch_key, &real_num, 0);
235
236 map_fd = bpf_find_map(__func__, obj, "reals");
237 if (map_fd < 0)
238 goto out;
239 bpf_map_update_elem(map_fd, &real_num, &real_def, 0);
240
241 err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4),
242 buf, &size, &retval, &duration);
243 CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 ||
244 *magic != MAGIC_VAL, "ipv4",
245 "err %d errno %d retval %d size %d magic %x\n",
246 err, errno, retval, size, *magic);
247
248 err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6),
249 buf, &size, &retval, &duration);
250 CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 ||
251 *magic != MAGIC_VAL, "ipv6",
252 "err %d errno %d retval %d size %d magic %x\n",
253 err, errno, retval, size, *magic);
254
255 map_fd = bpf_find_map(__func__, obj, "stats");
256 if (map_fd < 0)
257 goto out;
258 bpf_map_lookup_elem(map_fd, &stats_key, stats);
259 for (i = 0; i < nr_cpus; i++) {
260 bytes += stats[i].bytes;
261 pkts += stats[i].pkts;
262 }
263 if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
264 error_cnt++;
265 printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
266 }
267out:
268 bpf_object__close(obj);
269}
270
271static void test_tcp_estats(void)
272{
273 const char *file = "./test_tcp_estats.o";
274 int err, prog_fd;
275 struct bpf_object *obj;
276 __u32 duration = 0;
277
278 err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
279 CHECK(err, "", "err %d errno %d\n", err, errno);
280 if (err)
281 return;
282
283 bpf_object__close(obj);
284}
285
286int main(void)
287{
288 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
289
290 setrlimit(RLIMIT_MEMLOCK, &rinf);
291
292 test_pkt_access();
293 test_xdp();
294 test_l4lb();
295 test_tcp_estats();
296
297 printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
298 return 0;
299}
diff --git a/tools/testing/selftests/bpf/test_tcp_estats.c b/tools/testing/selftests/bpf/test_tcp_estats.c
new file mode 100644
index 000000000000..bee3bbecc0c4
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_tcp_estats.c
@@ -0,0 +1,258 @@
1/* Copyright (c) 2017 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7
8/* This program shows clang/llvm is able to generate code pattern
9 * like:
10 * _tcp_send_active_reset:
11 * 0: bf 16 00 00 00 00 00 00 r6 = r1
12 * ......
13 * 335: b7 01 00 00 0f 00 00 00 r1 = 15
14 * 336: 05 00 48 00 00 00 00 00 goto 72
15 *
16 * LBB0_3:
17 * 337: b7 01 00 00 01 00 00 00 r1 = 1
18 * 338: 63 1a d0 ff 00 00 00 00 *(u32 *)(r10 - 48) = r1
19 * 408: b7 01 00 00 03 00 00 00 r1 = 3
20 *
21 * LBB0_4:
22 * 409: 71 a2 fe ff 00 00 00 00 r2 = *(u8 *)(r10 - 2)
23 * 410: bf a7 00 00 00 00 00 00 r7 = r10
24 * 411: 07 07 00 00 b8 ff ff ff r7 += -72
25 * 412: bf 73 00 00 00 00 00 00 r3 = r7
26 * 413: 0f 13 00 00 00 00 00 00 r3 += r1
27 * 414: 73 23 2d 00 00 00 00 00 *(u8 *)(r3 + 45) = r2
28 *
29 * From the above code snippet, the code generated by the compiler
30 * is reasonable. The "r1" is assigned to different values in basic
31 * blocks "_tcp_send_active_reset" and "LBB0_3", and used in "LBB0_4".
32 * The verifier should be able to handle such code patterns.
33 */
34#include <string.h>
35#include <linux/bpf.h>
36#include <linux/ipv6.h>
37#include <linux/version.h>
38#include <sys/socket.h>
39#include "bpf_helpers.h"
40
41#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
42#define TCP_ESTATS_MAGIC 0xBAADBEEF
43
44/* This test case needs "sock" and "pt_regs" data structure.
45 * Recursively, "sock" needs "sock_common" and "inet_sock".
46 * However, this is a unit test case only for
47 * verifier purpose without bpf program execution.
48 * We can safely mock much simpler data structures, basically
49 * only taking the necessary fields from kernel headers.
50 */
51typedef __u32 __bitwise __portpair;
52typedef __u64 __bitwise __addrpair;
53
54struct sock_common {
55 unsigned short skc_family;
56 union {
57 __addrpair skc_addrpair;
58 struct {
59 __be32 skc_daddr;
60 __be32 skc_rcv_saddr;
61 };
62 };
63 union {
64 __portpair skc_portpair;
65 struct {
66 __be16 skc_dport;
67 __u16 skc_num;
68 };
69 };
70 struct in6_addr skc_v6_daddr;
71 struct in6_addr skc_v6_rcv_saddr;
72};
73
74struct sock {
75 struct sock_common __sk_common;
76#define sk_family __sk_common.skc_family
77#define sk_v6_daddr __sk_common.skc_v6_daddr
78#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr
79};
80
81struct inet_sock {
82 struct sock sk;
83#define inet_daddr sk.__sk_common.skc_daddr
84#define inet_dport sk.__sk_common.skc_dport
85 __be32 inet_saddr;
86 __be16 inet_sport;
87};
88
89struct pt_regs {
90 long di;
91};
92
93static inline struct inet_sock *inet_sk(const struct sock *sk)
94{
95 return (struct inet_sock *)sk;
96}
97
98/* Define various data structures for state recording.
99 * Some fields are not used due to test simplification.
100 */
101enum tcp_estats_addrtype {
102 TCP_ESTATS_ADDRTYPE_IPV4 = 1,
103 TCP_ESTATS_ADDRTYPE_IPV6 = 2
104};
105
106enum tcp_estats_event_type {
107 TCP_ESTATS_ESTABLISH,
108 TCP_ESTATS_PERIODIC,
109 TCP_ESTATS_TIMEOUT,
110 TCP_ESTATS_RETRANSMIT_TIMEOUT,
111 TCP_ESTATS_RETRANSMIT_OTHER,
112 TCP_ESTATS_SYN_RETRANSMIT,
113 TCP_ESTATS_SYNACK_RETRANSMIT,
114 TCP_ESTATS_TERM,
115 TCP_ESTATS_TX_RESET,
116 TCP_ESTATS_RX_RESET,
117 TCP_ESTATS_WRITE_TIMEOUT,
118 TCP_ESTATS_CONN_TIMEOUT,
119 TCP_ESTATS_ACK_LATENCY,
120 TCP_ESTATS_NEVENTS,
121};
122
123struct tcp_estats_event {
124 int pid;
125 int cpu;
126 unsigned long ts;
127 unsigned int magic;
128 enum tcp_estats_event_type event_type;
129};
130
131/* The below data structure is packed in order for
132 * llvm compiler to generate expected code.
133 */
134struct tcp_estats_conn_id {
135 unsigned int localaddressType;
136 struct {
137 unsigned char data[16];
138 } localaddress;
139 struct {
140 unsigned char data[16];
141 } remaddress;
142 unsigned short localport;
143 unsigned short remport;
144} __attribute__((__packed__));
145
146struct tcp_estats_basic_event {
147 struct tcp_estats_event event;
148 struct tcp_estats_conn_id conn_id;
149};
150
151struct bpf_map_def SEC("maps") ev_record_map = {
152 .type = BPF_MAP_TYPE_HASH,
153 .key_size = sizeof(__u32),
154 .value_size = sizeof(struct tcp_estats_basic_event),
155 .max_entries = 1024,
156};
157
158struct dummy_tracepoint_args {
159 unsigned long long pad;
160 struct sock *sock;
161};
162
163static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event,
164 enum tcp_estats_event_type type)
165{
166 event->magic = TCP_ESTATS_MAGIC;
167 event->ts = bpf_ktime_get_ns();
168 event->event_type = type;
169}
170
171static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from)
172{
173 to[0] = _(from[0]);
174 to[1] = _(from[1]);
175 to[2] = _(from[2]);
176 to[3] = _(from[3]);
177}
178
179static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id,
180 __be32 *saddr, __be32 *daddr)
181{
182 conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4;
183
184 unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
185 unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr);
186}
187
188static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id,
189 __be32 *saddr, __be32 *daddr)
190{
191 conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6;
192
193 unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
194 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32),
195 (__u8 *)(saddr + 1));
196 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2,
197 (__u8 *)(saddr + 2));
198 unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3,
199 (__u8 *)(saddr + 3));
200
201 unaligned_u32_set(conn_id->remaddress.data,
202 (__u8 *)(daddr));
203 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32),
204 (__u8 *)(daddr + 1));
205 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2,
206 (__u8 *)(daddr + 2));
207 unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3,
208 (__u8 *)(daddr + 3));
209}
210
211static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id,
212 struct sock *sk)
213{
214 conn_id->localport = _(inet_sk(sk)->inet_sport);
215 conn_id->remport = _(inet_sk(sk)->inet_dport);
216
217 if (_(sk->sk_family) == AF_INET6)
218 conn_id_ipv6_init(conn_id,
219 sk->sk_v6_rcv_saddr.s6_addr32,
220 sk->sk_v6_daddr.s6_addr32);
221 else
222 conn_id_ipv4_init(conn_id,
223 &inet_sk(sk)->inet_saddr,
224 &inet_sk(sk)->inet_daddr);
225}
226
227static __always_inline void tcp_estats_init(struct sock *sk,
228 struct tcp_estats_event *event,
229 struct tcp_estats_conn_id *conn_id,
230 enum tcp_estats_event_type type)
231{
232 tcp_estats_ev_init(event, type);
233 tcp_estats_conn_id_init(conn_id, sk);
234}
235
236static __always_inline void send_basic_event(struct sock *sk,
237 enum tcp_estats_event_type type)
238{
239 struct tcp_estats_basic_event ev;
240 __u32 key = bpf_get_prandom_u32();
241
242 memset(&ev, 0, sizeof(ev));
243 tcp_estats_init(sk, &ev.event, &ev.conn_id, type);
244 bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY);
245}
246
247SEC("dummy_tracepoint")
248int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
249{
250 if (!arg->sock)
251 return 0;
252
253 send_basic_event(arg->sock, TCP_ESTATS_TX_RESET);
254 return 0;
255}
256
257char _license[] SEC("license") = "GPL";
258__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index d1555e4240c0..3773562056da 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -30,6 +30,14 @@
30 30
31#include <bpf/bpf.h> 31#include <bpf/bpf.h>
32 32
33#ifdef HAVE_GENHDR
34# include "autoconf.h"
35#else
36# if defined(__i386) || defined(__x86_64) || defined(__s390x__) || defined(__aarch64__)
37# define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1
38# endif
39#endif
40
33#include "../../../include/linux/filter.h" 41#include "../../../include/linux/filter.h"
34 42
35#ifndef ARRAY_SIZE 43#ifndef ARRAY_SIZE
@@ -38,6 +46,9 @@
38 46
39#define MAX_INSNS 512 47#define MAX_INSNS 512
40#define MAX_FIXUPS 8 48#define MAX_FIXUPS 8
49#define MAX_NR_MAPS 4
50
51#define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0)
41 52
42struct bpf_test { 53struct bpf_test {
43 const char *descr; 54 const char *descr;
@@ -45,6 +56,7 @@ struct bpf_test {
45 int fixup_map1[MAX_FIXUPS]; 56 int fixup_map1[MAX_FIXUPS];
46 int fixup_map2[MAX_FIXUPS]; 57 int fixup_map2[MAX_FIXUPS];
47 int fixup_prog[MAX_FIXUPS]; 58 int fixup_prog[MAX_FIXUPS];
59 int fixup_map_in_map[MAX_FIXUPS];
48 const char *errstr; 60 const char *errstr;
49 const char *errstr_unpriv; 61 const char *errstr_unpriv;
50 enum { 62 enum {
@@ -53,6 +65,7 @@ struct bpf_test {
53 REJECT 65 REJECT
54 } result, result_unpriv; 66 } result, result_unpriv;
55 enum bpf_prog_type prog_type; 67 enum bpf_prog_type prog_type;
68 uint8_t flags;
56}; 69};
57 70
58/* Note we want this to be 64 bit aligned so that the end of our array is 71/* Note we want this to be 64 bit aligned so that the end of our array is
@@ -178,6 +191,86 @@ static struct bpf_test tests[] = {
178 .result = REJECT, 191 .result = REJECT,
179 }, 192 },
180 { 193 {
194 "test6 ld_imm64",
195 .insns = {
196 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0),
197 BPF_RAW_INSN(0, 0, 0, 0, 0),
198 BPF_EXIT_INSN(),
199 },
200 .result = ACCEPT,
201 },
202 {
203 "test7 ld_imm64",
204 .insns = {
205 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 1),
206 BPF_RAW_INSN(0, 0, 0, 0, 1),
207 BPF_EXIT_INSN(),
208 },
209 .result = ACCEPT,
210 },
211 {
212 "test8 ld_imm64",
213 .insns = {
214 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 1, 1),
215 BPF_RAW_INSN(0, 0, 0, 0, 1),
216 BPF_EXIT_INSN(),
217 },
218 .errstr = "uses reserved fields",
219 .result = REJECT,
220 },
221 {
222 "test9 ld_imm64",
223 .insns = {
224 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 1),
225 BPF_RAW_INSN(0, 0, 0, 1, 1),
226 BPF_EXIT_INSN(),
227 },
228 .errstr = "invalid bpf_ld_imm64 insn",
229 .result = REJECT,
230 },
231 {
232 "test10 ld_imm64",
233 .insns = {
234 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 1),
235 BPF_RAW_INSN(0, BPF_REG_1, 0, 0, 1),
236 BPF_EXIT_INSN(),
237 },
238 .errstr = "invalid bpf_ld_imm64 insn",
239 .result = REJECT,
240 },
241 {
242 "test11 ld_imm64",
243 .insns = {
244 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 1),
245 BPF_RAW_INSN(0, 0, BPF_REG_1, 0, 1),
246 BPF_EXIT_INSN(),
247 },
248 .errstr = "invalid bpf_ld_imm64 insn",
249 .result = REJECT,
250 },
251 {
252 "test12 ld_imm64",
253 .insns = {
254 BPF_MOV64_IMM(BPF_REG_1, 0),
255 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, BPF_REG_1, 0, 1),
256 BPF_RAW_INSN(0, 0, 0, 0, 1),
257 BPF_EXIT_INSN(),
258 },
259 .errstr = "not pointing to valid bpf_map",
260 .result = REJECT,
261 },
262 {
263 "test13 ld_imm64",
264 .insns = {
265 BPF_MOV64_IMM(BPF_REG_1, 0),
266 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, BPF_REG_1, 0, 1),
267 BPF_RAW_INSN(0, 0, BPF_REG_1, 0, 1),
268 BPF_EXIT_INSN(),
269 },
270 .errstr = "invalid bpf_ld_imm64 insn",
271 .result = REJECT,
272 },
273 {
181 "no bpf_exit", 274 "no bpf_exit",
182 .insns = { 275 .insns = {
183 BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_2), 276 BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_2),
@@ -318,6 +411,30 @@ static struct bpf_test tests[] = {
318 .result = REJECT, 411 .result = REJECT,
319 }, 412 },
320 { 413 {
414 "invalid fp arithmetic",
415 /* If this gets ever changed, make sure JITs can deal with it. */
416 .insns = {
417 BPF_MOV64_IMM(BPF_REG_0, 0),
418 BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
419 BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 8),
420 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
421 BPF_EXIT_INSN(),
422 },
423 .errstr_unpriv = "R1 pointer arithmetic",
424 .result_unpriv = REJECT,
425 .errstr = "R1 invalid mem access",
426 .result = REJECT,
427 },
428 {
429 "non-invalid fp arithmetic",
430 .insns = {
431 BPF_MOV64_IMM(BPF_REG_0, 0),
432 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
433 BPF_EXIT_INSN(),
434 },
435 .result = ACCEPT,
436 },
437 {
321 "invalid argument register", 438 "invalid argument register",
322 .insns = { 439 .insns = {
323 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 440 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
@@ -759,6 +876,9 @@ static struct bpf_test tests[] = {
759 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 876 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
760 offsetof(struct __sk_buff, vlan_tci)), 877 offsetof(struct __sk_buff, vlan_tci)),
761 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), 878 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
879 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
880 offsetof(struct __sk_buff, napi_id)),
881 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0),
762 BPF_EXIT_INSN(), 882 BPF_EXIT_INSN(),
763 }, 883 },
764 .result = ACCEPT, 884 .result = ACCEPT,
@@ -1785,6 +1905,20 @@ static struct bpf_test tests[] = {
1785 .result = ACCEPT, 1905 .result = ACCEPT,
1786 }, 1906 },
1787 { 1907 {
1908 "unpriv: adding of fp",
1909 .insns = {
1910 BPF_MOV64_IMM(BPF_REG_0, 0),
1911 BPF_MOV64_IMM(BPF_REG_1, 0),
1912 BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_10),
1913 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, -8),
1914 BPF_EXIT_INSN(),
1915 },
1916 .errstr_unpriv = "pointer arithmetic prohibited",
1917 .result_unpriv = REJECT,
1918 .errstr = "R1 invalid mem access",
1919 .result = REJECT,
1920 },
1921 {
1788 "unpriv: cmp of stack pointer", 1922 "unpriv: cmp of stack pointer",
1789 .insns = { 1923 .insns = {
1790 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 1924 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
@@ -1798,16 +1932,22 @@ static struct bpf_test tests[] = {
1798 .result = ACCEPT, 1932 .result = ACCEPT,
1799 }, 1933 },
1800 { 1934 {
1801 "unpriv: obfuscate stack pointer", 1935 "stack pointer arithmetic",
1802 .insns = { 1936 .insns = {
1803 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 1937 BPF_MOV64_IMM(BPF_REG_1, 4),
1804 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 1938 BPF_JMP_IMM(BPF_JA, 0, 0, 0),
1805 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 1939 BPF_MOV64_REG(BPF_REG_7, BPF_REG_10),
1940 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -10),
1941 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, -10),
1942 BPF_MOV64_REG(BPF_REG_2, BPF_REG_7),
1943 BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1),
1944 BPF_ST_MEM(0, BPF_REG_2, 4, 0),
1945 BPF_MOV64_REG(BPF_REG_2, BPF_REG_7),
1946 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 8),
1947 BPF_ST_MEM(0, BPF_REG_2, 4, 0),
1806 BPF_MOV64_IMM(BPF_REG_0, 0), 1948 BPF_MOV64_IMM(BPF_REG_0, 0),
1807 BPF_EXIT_INSN(), 1949 BPF_EXIT_INSN(),
1808 }, 1950 },
1809 .errstr_unpriv = "R2 pointer arithmetic",
1810 .result_unpriv = REJECT,
1811 .result = ACCEPT, 1951 .result = ACCEPT,
1812 }, 1952 },
1813 { 1953 {
@@ -2432,6 +2572,49 @@ static struct bpf_test tests[] = {
2432 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 2572 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
2433 }, 2573 },
2434 { 2574 {
2575 "direct packet access: test15 (spill with xadd)",
2576 .insns = {
2577 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
2578 offsetof(struct __sk_buff, data)),
2579 BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
2580 offsetof(struct __sk_buff, data_end)),
2581 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
2582 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
2583 BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 8),
2584 BPF_MOV64_IMM(BPF_REG_5, 4096),
2585 BPF_MOV64_REG(BPF_REG_4, BPF_REG_10),
2586 BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -8),
2587 BPF_STX_MEM(BPF_DW, BPF_REG_4, BPF_REG_2, 0),
2588 BPF_STX_XADD(BPF_DW, BPF_REG_4, BPF_REG_5, 0),
2589 BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_4, 0),
2590 BPF_STX_MEM(BPF_W, BPF_REG_2, BPF_REG_5, 0),
2591 BPF_MOV64_IMM(BPF_REG_0, 0),
2592 BPF_EXIT_INSN(),
2593 },
2594 .errstr = "R2 invalid mem access 'inv'",
2595 .result = REJECT,
2596 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
2597 },
2598 {
2599 "direct packet access: test16 (arith on data_end)",
2600 .insns = {
2601 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
2602 offsetof(struct __sk_buff, data)),
2603 BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
2604 offsetof(struct __sk_buff, data_end)),
2605 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
2606 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
2607 BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 16),
2608 BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1),
2609 BPF_STX_MEM(BPF_B, BPF_REG_2, BPF_REG_2, 0),
2610 BPF_MOV64_IMM(BPF_REG_0, 0),
2611 BPF_EXIT_INSN(),
2612 },
2613 .errstr = "invalid access to packet",
2614 .result = REJECT,
2615 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
2616 },
2617 {
2435 "helper access to packet: test1, valid packet_ptr range", 2618 "helper access to packet: test1, valid packet_ptr range",
2436 .insns = { 2619 .insns = {
2437 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 2620 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
@@ -2934,6 +3117,7 @@ static struct bpf_test tests[] = {
2934 .errstr_unpriv = "R0 pointer arithmetic prohibited", 3117 .errstr_unpriv = "R0 pointer arithmetic prohibited",
2935 .result_unpriv = REJECT, 3118 .result_unpriv = REJECT,
2936 .result = ACCEPT, 3119 .result = ACCEPT,
3120 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
2937 }, 3121 },
2938 { 3122 {
2939 "valid map access into an array with a variable", 3123 "valid map access into an array with a variable",
@@ -2957,6 +3141,7 @@ static struct bpf_test tests[] = {
2957 .errstr_unpriv = "R0 pointer arithmetic prohibited", 3141 .errstr_unpriv = "R0 pointer arithmetic prohibited",
2958 .result_unpriv = REJECT, 3142 .result_unpriv = REJECT,
2959 .result = ACCEPT, 3143 .result = ACCEPT,
3144 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
2960 }, 3145 },
2961 { 3146 {
2962 "valid map access into an array with a signed variable", 3147 "valid map access into an array with a signed variable",
@@ -2984,6 +3169,7 @@ static struct bpf_test tests[] = {
2984 .errstr_unpriv = "R0 pointer arithmetic prohibited", 3169 .errstr_unpriv = "R0 pointer arithmetic prohibited",
2985 .result_unpriv = REJECT, 3170 .result_unpriv = REJECT,
2986 .result = ACCEPT, 3171 .result = ACCEPT,
3172 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
2987 }, 3173 },
2988 { 3174 {
2989 "invalid map access into an array with a constant", 3175 "invalid map access into an array with a constant",
@@ -3025,6 +3211,7 @@ static struct bpf_test tests[] = {
3025 .errstr = "R0 min value is outside of the array range", 3211 .errstr = "R0 min value is outside of the array range",
3026 .result_unpriv = REJECT, 3212 .result_unpriv = REJECT,
3027 .result = REJECT, 3213 .result = REJECT,
3214 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
3028 }, 3215 },
3029 { 3216 {
3030 "invalid map access into an array with a variable", 3217 "invalid map access into an array with a variable",
@@ -3048,6 +3235,7 @@ static struct bpf_test tests[] = {
3048 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", 3235 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
3049 .result_unpriv = REJECT, 3236 .result_unpriv = REJECT,
3050 .result = REJECT, 3237 .result = REJECT,
3238 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
3051 }, 3239 },
3052 { 3240 {
3053 "invalid map access into an array with no floor check", 3241 "invalid map access into an array with no floor check",
@@ -3074,6 +3262,7 @@ static struct bpf_test tests[] = {
3074 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", 3262 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
3075 .result_unpriv = REJECT, 3263 .result_unpriv = REJECT,
3076 .result = REJECT, 3264 .result = REJECT,
3265 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
3077 }, 3266 },
3078 { 3267 {
3079 "invalid map access into an array with a invalid max check", 3268 "invalid map access into an array with a invalid max check",
@@ -3100,6 +3289,7 @@ static struct bpf_test tests[] = {
3100 .errstr = "invalid access to map value, value_size=48 off=44 size=8", 3289 .errstr = "invalid access to map value, value_size=48 off=44 size=8",
3101 .result_unpriv = REJECT, 3290 .result_unpriv = REJECT,
3102 .result = REJECT, 3291 .result = REJECT,
3292 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
3103 }, 3293 },
3104 { 3294 {
3105 "invalid map access into an array with a invalid max check", 3295 "invalid map access into an array with a invalid max check",
@@ -3129,6 +3319,7 @@ static struct bpf_test tests[] = {
3129 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", 3319 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
3130 .result_unpriv = REJECT, 3320 .result_unpriv = REJECT,
3131 .result = REJECT, 3321 .result = REJECT,
3322 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
3132 }, 3323 },
3133 { 3324 {
3134 "multiple registers share map_lookup_elem result", 3325 "multiple registers share map_lookup_elem result",
@@ -3252,6 +3443,7 @@ static struct bpf_test tests[] = {
3252 .result = REJECT, 3443 .result = REJECT,
3253 .errstr_unpriv = "R0 pointer arithmetic prohibited", 3444 .errstr_unpriv = "R0 pointer arithmetic prohibited",
3254 .result_unpriv = REJECT, 3445 .result_unpriv = REJECT,
3446 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
3255 }, 3447 },
3256 { 3448 {
3257 "constant register |= constant should keep constant type", 3449 "constant register |= constant should keep constant type",
@@ -3418,6 +3610,26 @@ static struct bpf_test tests[] = {
3418 .prog_type = BPF_PROG_TYPE_LWT_XMIT, 3610 .prog_type = BPF_PROG_TYPE_LWT_XMIT,
3419 }, 3611 },
3420 { 3612 {
3613 "overlapping checks for direct packet access",
3614 .insns = {
3615 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
3616 offsetof(struct __sk_buff, data)),
3617 BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
3618 offsetof(struct __sk_buff, data_end)),
3619 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
3620 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
3621 BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 4),
3622 BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
3623 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6),
3624 BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1),
3625 BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_2, 6),
3626 BPF_MOV64_IMM(BPF_REG_0, 0),
3627 BPF_EXIT_INSN(),
3628 },
3629 .result = ACCEPT,
3630 .prog_type = BPF_PROG_TYPE_LWT_XMIT,
3631 },
3632 {
3421 "invalid access of tc_classid for LWT_IN", 3633 "invalid access of tc_classid for LWT_IN",
3422 .insns = { 3634 .insns = {
3423 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 3635 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
@@ -3961,7 +4173,208 @@ static struct bpf_test tests[] = {
3961 .result_unpriv = REJECT, 4173 .result_unpriv = REJECT,
3962 }, 4174 },
3963 { 4175 {
3964 "map element value (adjusted) is preserved across register spilling", 4176 "map element value or null is marked on register spilling",
4177 .insns = {
4178 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4179 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4180 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4181 BPF_LD_MAP_FD(BPF_REG_1, 0),
4182 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4183 BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
4184 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -152),
4185 BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
4186 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
4187 BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, 0),
4188 BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, 42),
4189 BPF_EXIT_INSN(),
4190 },
4191 .fixup_map2 = { 3 },
4192 .errstr_unpriv = "R0 leaks addr",
4193 .result = ACCEPT,
4194 .result_unpriv = REJECT,
4195 },
4196 {
4197 "map element value store of cleared call register",
4198 .insns = {
4199 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4200 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4201 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4202 BPF_LD_MAP_FD(BPF_REG_1, 0),
4203 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4204 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
4205 BPF_STX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 0),
4206 BPF_EXIT_INSN(),
4207 },
4208 .fixup_map2 = { 3 },
4209 .errstr_unpriv = "R1 !read_ok",
4210 .errstr = "R1 !read_ok",
4211 .result = REJECT,
4212 .result_unpriv = REJECT,
4213 },
4214 {
4215 "map element value with unaligned store",
4216 .insns = {
4217 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4218 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4219 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4220 BPF_LD_MAP_FD(BPF_REG_1, 0),
4221 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4222 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 17),
4223 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 3),
4224 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 42),
4225 BPF_ST_MEM(BPF_DW, BPF_REG_0, 2, 43),
4226 BPF_ST_MEM(BPF_DW, BPF_REG_0, -2, 44),
4227 BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
4228 BPF_ST_MEM(BPF_DW, BPF_REG_8, 0, 32),
4229 BPF_ST_MEM(BPF_DW, BPF_REG_8, 2, 33),
4230 BPF_ST_MEM(BPF_DW, BPF_REG_8, -2, 34),
4231 BPF_ALU64_IMM(BPF_ADD, BPF_REG_8, 5),
4232 BPF_ST_MEM(BPF_DW, BPF_REG_8, 0, 22),
4233 BPF_ST_MEM(BPF_DW, BPF_REG_8, 4, 23),
4234 BPF_ST_MEM(BPF_DW, BPF_REG_8, -7, 24),
4235 BPF_MOV64_REG(BPF_REG_7, BPF_REG_8),
4236 BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 3),
4237 BPF_ST_MEM(BPF_DW, BPF_REG_7, 0, 22),
4238 BPF_ST_MEM(BPF_DW, BPF_REG_7, 4, 23),
4239 BPF_ST_MEM(BPF_DW, BPF_REG_7, -4, 24),
4240 BPF_EXIT_INSN(),
4241 },
4242 .fixup_map2 = { 3 },
4243 .errstr_unpriv = "R0 pointer arithmetic prohibited",
4244 .result = ACCEPT,
4245 .result_unpriv = REJECT,
4246 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
4247 },
4248 {
4249 "map element value with unaligned load",
4250 .insns = {
4251 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4252 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4253 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4254 BPF_LD_MAP_FD(BPF_REG_1, 0),
4255 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4256 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 11),
4257 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
4258 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, MAX_ENTRIES, 9),
4259 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 3),
4260 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0),
4261 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 2),
4262 BPF_MOV64_REG(BPF_REG_8, BPF_REG_0),
4263 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_8, 0),
4264 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_8, 2),
4265 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 5),
4266 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 0),
4267 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_0, 4),
4268 BPF_EXIT_INSN(),
4269 },
4270 .fixup_map2 = { 3 },
4271 .errstr_unpriv = "R0 pointer arithmetic prohibited",
4272 .result = ACCEPT,
4273 .result_unpriv = REJECT,
4274 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
4275 },
4276 {
4277 "map element value illegal alu op, 1",
4278 .insns = {
4279 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4280 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4281 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4282 BPF_LD_MAP_FD(BPF_REG_1, 0),
4283 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4284 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
4285 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 8),
4286 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22),
4287 BPF_EXIT_INSN(),
4288 },
4289 .fixup_map2 = { 3 },
4290 .errstr_unpriv = "R0 pointer arithmetic prohibited",
4291 .errstr = "invalid mem access 'inv'",
4292 .result = REJECT,
4293 .result_unpriv = REJECT,
4294 },
4295 {
4296 "map element value illegal alu op, 2",
4297 .insns = {
4298 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4299 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4300 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4301 BPF_LD_MAP_FD(BPF_REG_1, 0),
4302 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4303 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
4304 BPF_ALU32_IMM(BPF_ADD, BPF_REG_0, 0),
4305 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22),
4306 BPF_EXIT_INSN(),
4307 },
4308 .fixup_map2 = { 3 },
4309 .errstr_unpriv = "R0 pointer arithmetic prohibited",
4310 .errstr = "invalid mem access 'inv'",
4311 .result = REJECT,
4312 .result_unpriv = REJECT,
4313 },
4314 {
4315 "map element value illegal alu op, 3",
4316 .insns = {
4317 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4318 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4319 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4320 BPF_LD_MAP_FD(BPF_REG_1, 0),
4321 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4322 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
4323 BPF_ALU64_IMM(BPF_DIV, BPF_REG_0, 42),
4324 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22),
4325 BPF_EXIT_INSN(),
4326 },
4327 .fixup_map2 = { 3 },
4328 .errstr_unpriv = "R0 pointer arithmetic prohibited",
4329 .errstr = "invalid mem access 'inv'",
4330 .result = REJECT,
4331 .result_unpriv = REJECT,
4332 },
4333 {
4334 "map element value illegal alu op, 4",
4335 .insns = {
4336 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4337 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4338 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4339 BPF_LD_MAP_FD(BPF_REG_1, 0),
4340 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4341 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
4342 BPF_ENDIAN(BPF_FROM_BE, BPF_REG_0, 64),
4343 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22),
4344 BPF_EXIT_INSN(),
4345 },
4346 .fixup_map2 = { 3 },
4347 .errstr_unpriv = "R0 pointer arithmetic prohibited",
4348 .errstr = "invalid mem access 'inv'",
4349 .result = REJECT,
4350 .result_unpriv = REJECT,
4351 },
4352 {
4353 "map element value illegal alu op, 5",
4354 .insns = {
4355 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4356 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4357 BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
4358 BPF_LD_MAP_FD(BPF_REG_1, 0),
4359 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
4360 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 7),
4361 BPF_MOV64_IMM(BPF_REG_3, 4096),
4362 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4363 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
4364 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0),
4365 BPF_STX_XADD(BPF_DW, BPF_REG_2, BPF_REG_3, 0),
4366 BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0),
4367 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 22),
4368 BPF_EXIT_INSN(),
4369 },
4370 .fixup_map2 = { 3 },
4371 .errstr_unpriv = "R0 invalid mem access 'inv'",
4372 .errstr = "R0 invalid mem access 'inv'",
4373 .result = REJECT,
4374 .result_unpriv = REJECT,
4375 },
4376 {
4377 "map element value is preserved across register spilling",
3965 .insns = { 4378 .insns = {
3966 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 4379 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
3967 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 4380 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
@@ -3983,6 +4396,7 @@ static struct bpf_test tests[] = {
3983 .errstr_unpriv = "R0 pointer arithmetic prohibited", 4396 .errstr_unpriv = "R0 pointer arithmetic prohibited",
3984 .result = ACCEPT, 4397 .result = ACCEPT,
3985 .result_unpriv = REJECT, 4398 .result_unpriv = REJECT,
4399 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
3986 }, 4400 },
3987 { 4401 {
3988 "helper access to variable memory: stack, bitwise AND + JMP, correct bounds", 4402 "helper access to variable memory: stack, bitwise AND + JMP, correct bounds",
@@ -4421,6 +4835,7 @@ static struct bpf_test tests[] = {
4421 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", 4835 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
4422 .result = REJECT, 4836 .result = REJECT,
4423 .result_unpriv = REJECT, 4837 .result_unpriv = REJECT,
4838 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
4424 }, 4839 },
4425 { 4840 {
4426 "invalid range check", 4841 "invalid range check",
@@ -4452,6 +4867,76 @@ static struct bpf_test tests[] = {
4452 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.", 4867 .errstr = "R0 min value is negative, either use unsigned index or do a if (index >=0) check.",
4453 .result = REJECT, 4868 .result = REJECT,
4454 .result_unpriv = REJECT, 4869 .result_unpriv = REJECT,
4870 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
4871 },
4872 {
4873 "map in map access",
4874 .insns = {
4875 BPF_ST_MEM(0, BPF_REG_10, -4, 0),
4876 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4877 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
4878 BPF_LD_MAP_FD(BPF_REG_1, 0),
4879 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4880 BPF_FUNC_map_lookup_elem),
4881 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
4882 BPF_ST_MEM(0, BPF_REG_10, -4, 0),
4883 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4884 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
4885 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
4886 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4887 BPF_FUNC_map_lookup_elem),
4888 BPF_MOV64_REG(BPF_REG_0, 0),
4889 BPF_EXIT_INSN(),
4890 },
4891 .fixup_map_in_map = { 3 },
4892 .result = ACCEPT,
4893 },
4894 {
4895 "invalid inner map pointer",
4896 .insns = {
4897 BPF_ST_MEM(0, BPF_REG_10, -4, 0),
4898 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4899 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
4900 BPF_LD_MAP_FD(BPF_REG_1, 0),
4901 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4902 BPF_FUNC_map_lookup_elem),
4903 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 6),
4904 BPF_ST_MEM(0, BPF_REG_10, -4, 0),
4905 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4906 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
4907 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
4908 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
4909 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4910 BPF_FUNC_map_lookup_elem),
4911 BPF_MOV64_REG(BPF_REG_0, 0),
4912 BPF_EXIT_INSN(),
4913 },
4914 .fixup_map_in_map = { 3 },
4915 .errstr = "R1 type=inv expected=map_ptr",
4916 .errstr_unpriv = "R1 pointer arithmetic prohibited",
4917 .result = REJECT,
4918 },
4919 {
4920 "forgot null checking on the inner map pointer",
4921 .insns = {
4922 BPF_ST_MEM(0, BPF_REG_10, -4, 0),
4923 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4924 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
4925 BPF_LD_MAP_FD(BPF_REG_1, 0),
4926 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4927 BPF_FUNC_map_lookup_elem),
4928 BPF_ST_MEM(0, BPF_REG_10, -4, 0),
4929 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
4930 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
4931 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
4932 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4933 BPF_FUNC_map_lookup_elem),
4934 BPF_MOV64_REG(BPF_REG_0, 0),
4935 BPF_EXIT_INSN(),
4936 },
4937 .fixup_map_in_map = { 3 },
4938 .errstr = "R1 type=map_value_or_null expected=map_ptr",
4939 .result = REJECT,
4455 } 4940 }
4456}; 4941};
4457 4942
@@ -4489,55 +4974,90 @@ static int create_prog_array(void)
4489 return fd; 4974 return fd;
4490} 4975}
4491 4976
4977static int create_map_in_map(void)
4978{
4979 int inner_map_fd, outer_map_fd;
4980
4981 inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int),
4982 sizeof(int), 1, 0);
4983 if (inner_map_fd < 0) {
4984 printf("Failed to create array '%s'!\n", strerror(errno));
4985 return inner_map_fd;
4986 }
4987
4988 outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS,
4989 sizeof(int), inner_map_fd, 1, 0);
4990 if (outer_map_fd < 0)
4991 printf("Failed to create array of maps '%s'!\n",
4992 strerror(errno));
4993
4994 close(inner_map_fd);
4995
4996 return outer_map_fd;
4997}
4998
4492static char bpf_vlog[32768]; 4999static char bpf_vlog[32768];
4493 5000
4494static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, 5001static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
4495 int *fd_f1, int *fd_f2, int *fd_f3) 5002 int *map_fds)
4496{ 5003{
4497 int *fixup_map1 = test->fixup_map1; 5004 int *fixup_map1 = test->fixup_map1;
4498 int *fixup_map2 = test->fixup_map2; 5005 int *fixup_map2 = test->fixup_map2;
4499 int *fixup_prog = test->fixup_prog; 5006 int *fixup_prog = test->fixup_prog;
5007 int *fixup_map_in_map = test->fixup_map_in_map;
4500 5008
4501 /* Allocating HTs with 1 elem is fine here, since we only test 5009 /* Allocating HTs with 1 elem is fine here, since we only test
4502 * for verifier and not do a runtime lookup, so the only thing 5010 * for verifier and not do a runtime lookup, so the only thing
4503 * that really matters is value size in this case. 5011 * that really matters is value size in this case.
4504 */ 5012 */
4505 if (*fixup_map1) { 5013 if (*fixup_map1) {
4506 *fd_f1 = create_map(sizeof(long long), 1); 5014 map_fds[0] = create_map(sizeof(long long), 1);
4507 do { 5015 do {
4508 prog[*fixup_map1].imm = *fd_f1; 5016 prog[*fixup_map1].imm = map_fds[0];
4509 fixup_map1++; 5017 fixup_map1++;
4510 } while (*fixup_map1); 5018 } while (*fixup_map1);
4511 } 5019 }
4512 5020
4513 if (*fixup_map2) { 5021 if (*fixup_map2) {
4514 *fd_f2 = create_map(sizeof(struct test_val), 1); 5022 map_fds[1] = create_map(sizeof(struct test_val), 1);
4515 do { 5023 do {
4516 prog[*fixup_map2].imm = *fd_f2; 5024 prog[*fixup_map2].imm = map_fds[1];
4517 fixup_map2++; 5025 fixup_map2++;
4518 } while (*fixup_map2); 5026 } while (*fixup_map2);
4519 } 5027 }
4520 5028
4521 if (*fixup_prog) { 5029 if (*fixup_prog) {
4522 *fd_f3 = create_prog_array(); 5030 map_fds[2] = create_prog_array();
4523 do { 5031 do {
4524 prog[*fixup_prog].imm = *fd_f3; 5032 prog[*fixup_prog].imm = map_fds[2];
4525 fixup_prog++; 5033 fixup_prog++;
4526 } while (*fixup_prog); 5034 } while (*fixup_prog);
4527 } 5035 }
5036
5037 if (*fixup_map_in_map) {
5038 map_fds[3] = create_map_in_map();
5039 do {
5040 prog[*fixup_map_in_map].imm = map_fds[3];
5041 fixup_map_in_map++;
5042 } while (*fixup_map_in_map);
5043 }
4528} 5044}
4529 5045
4530static void do_test_single(struct bpf_test *test, bool unpriv, 5046static void do_test_single(struct bpf_test *test, bool unpriv,
4531 int *passes, int *errors) 5047 int *passes, int *errors)
4532{ 5048{
5049 int fd_prog, expected_ret, reject_from_alignment;
4533 struct bpf_insn *prog = test->insns; 5050 struct bpf_insn *prog = test->insns;
4534 int prog_len = probe_filter_length(prog); 5051 int prog_len = probe_filter_length(prog);
4535 int prog_type = test->prog_type; 5052 int prog_type = test->prog_type;
4536 int fd_f1 = -1, fd_f2 = -1, fd_f3 = -1; 5053 int map_fds[MAX_NR_MAPS];
4537 int fd_prog, expected_ret;
4538 const char *expected_err; 5054 const char *expected_err;
5055 int i;
5056
5057 for (i = 0; i < MAX_NR_MAPS; i++)
5058 map_fds[i] = -1;
4539 5059
4540 do_test_fixup(test, prog, &fd_f1, &fd_f2, &fd_f3); 5060 do_test_fixup(test, prog, map_fds);
4541 5061
4542 fd_prog = bpf_load_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER, 5062 fd_prog = bpf_load_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
4543 prog, prog_len, "GPL", 0, bpf_vlog, 5063 prog, prog_len, "GPL", 0, bpf_vlog,
@@ -4547,8 +5067,19 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
4547 test->result_unpriv : test->result; 5067 test->result_unpriv : test->result;
4548 expected_err = unpriv && test->errstr_unpriv ? 5068 expected_err = unpriv && test->errstr_unpriv ?
4549 test->errstr_unpriv : test->errstr; 5069 test->errstr_unpriv : test->errstr;
5070
5071 reject_from_alignment = fd_prog < 0 &&
5072 (test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) &&
5073 strstr(bpf_vlog, "Unknown alignment.");
5074#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
5075 if (reject_from_alignment) {
5076 printf("FAIL\nFailed due to alignment despite having efficient unaligned access: '%s'!\n",
5077 strerror(errno));
5078 goto fail_log;
5079 }
5080#endif
4550 if (expected_ret == ACCEPT) { 5081 if (expected_ret == ACCEPT) {
4551 if (fd_prog < 0) { 5082 if (fd_prog < 0 && !reject_from_alignment) {
4552 printf("FAIL\nFailed to load prog '%s'!\n", 5083 printf("FAIL\nFailed to load prog '%s'!\n",
4553 strerror(errno)); 5084 strerror(errno));
4554 goto fail_log; 5085 goto fail_log;
@@ -4558,19 +5089,19 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
4558 printf("FAIL\nUnexpected success to load!\n"); 5089 printf("FAIL\nUnexpected success to load!\n");
4559 goto fail_log; 5090 goto fail_log;
4560 } 5091 }
4561 if (!strstr(bpf_vlog, expected_err)) { 5092 if (!strstr(bpf_vlog, expected_err) && !reject_from_alignment) {
4562 printf("FAIL\nUnexpected error message!\n"); 5093 printf("FAIL\nUnexpected error message!\n");
4563 goto fail_log; 5094 goto fail_log;
4564 } 5095 }
4565 } 5096 }
4566 5097
4567 (*passes)++; 5098 (*passes)++;
4568 printf("OK\n"); 5099 printf("OK%s\n", reject_from_alignment ?
5100 " (NOTE: reject due to unknown alignment)" : "");
4569close_fds: 5101close_fds:
4570 close(fd_prog); 5102 close(fd_prog);
4571 close(fd_f1); 5103 for (i = 0; i < MAX_NR_MAPS; i++)
4572 close(fd_f2); 5104 close(map_fds[i]);
4573 close(fd_f3);
4574 sched_yield(); 5105 sched_yield();
4575 return; 5106 return;
4576fail_log: 5107fail_log:
diff --git a/tools/testing/selftests/bpf/test_xdp.c b/tools/testing/selftests/bpf/test_xdp.c
new file mode 100644
index 000000000000..5e7df8bb5b5d
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_xdp.c
@@ -0,0 +1,235 @@
1/* Copyright (c) 2016,2017 Facebook
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 */
7#include <stddef.h>
8#include <string.h>
9#include <linux/bpf.h>
10#include <linux/if_ether.h>
11#include <linux/if_packet.h>
12#include <linux/ip.h>
13#include <linux/ipv6.h>
14#include <linux/in.h>
15#include <linux/udp.h>
16#include <linux/tcp.h>
17#include <linux/pkt_cls.h>
18#include <sys/socket.h>
19#include "bpf_helpers.h"
20#include "bpf_endian.h"
21#include "test_iptunnel_common.h"
22
23int _version SEC("version") = 1;
24
25struct bpf_map_def SEC("maps") rxcnt = {
26 .type = BPF_MAP_TYPE_PERCPU_ARRAY,
27 .key_size = sizeof(__u32),
28 .value_size = sizeof(__u64),
29 .max_entries = 256,
30};
31
32struct bpf_map_def SEC("maps") vip2tnl = {
33 .type = BPF_MAP_TYPE_HASH,
34 .key_size = sizeof(struct vip),
35 .value_size = sizeof(struct iptnl_info),
36 .max_entries = MAX_IPTNL_ENTRIES,
37};
38
39static __always_inline void count_tx(__u32 protocol)
40{
41 __u64 *rxcnt_count;
42
43 rxcnt_count = bpf_map_lookup_elem(&rxcnt, &protocol);
44 if (rxcnt_count)
45 *rxcnt_count += 1;
46}
47
48static __always_inline int get_dport(void *trans_data, void *data_end,
49 __u8 protocol)
50{
51 struct tcphdr *th;
52 struct udphdr *uh;
53
54 switch (protocol) {
55 case IPPROTO_TCP:
56 th = (struct tcphdr *)trans_data;
57 if (th + 1 > data_end)
58 return -1;
59 return th->dest;
60 case IPPROTO_UDP:
61 uh = (struct udphdr *)trans_data;
62 if (uh + 1 > data_end)
63 return -1;
64 return uh->dest;
65 default:
66 return 0;
67 }
68}
69
70static __always_inline void set_ethhdr(struct ethhdr *new_eth,
71 const struct ethhdr *old_eth,
72 const struct iptnl_info *tnl,
73 __be16 h_proto)
74{
75 memcpy(new_eth->h_source, old_eth->h_dest, sizeof(new_eth->h_source));
76 memcpy(new_eth->h_dest, tnl->dmac, sizeof(new_eth->h_dest));
77 new_eth->h_proto = h_proto;
78}
79
80static __always_inline int handle_ipv4(struct xdp_md *xdp)
81{
82 void *data_end = (void *)(long)xdp->data_end;
83 void *data = (void *)(long)xdp->data;
84 struct iptnl_info *tnl;
85 struct ethhdr *new_eth;
86 struct ethhdr *old_eth;
87 struct iphdr *iph = data + sizeof(struct ethhdr);
88 __u16 *next_iph;
89 __u16 payload_len;
90 struct vip vip = {};
91 int dport;
92 __u32 csum = 0;
93 int i;
94
95 if (iph + 1 > data_end)
96 return XDP_DROP;
97
98 dport = get_dport(iph + 1, data_end, iph->protocol);
99 if (dport == -1)
100 return XDP_DROP;
101
102 vip.protocol = iph->protocol;
103 vip.family = AF_INET;
104 vip.daddr.v4 = iph->daddr;
105 vip.dport = dport;
106 payload_len = bpf_ntohs(iph->tot_len);
107
108 tnl = bpf_map_lookup_elem(&vip2tnl, &vip);
109 /* It only does v4-in-v4 */
110 if (!tnl || tnl->family != AF_INET)
111 return XDP_PASS;
112
113 if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct iphdr)))
114 return XDP_DROP;
115
116 data = (void *)(long)xdp->data;
117 data_end = (void *)(long)xdp->data_end;
118
119 new_eth = data;
120 iph = data + sizeof(*new_eth);
121 old_eth = data + sizeof(*iph);
122
123 if (new_eth + 1 > data_end ||
124 old_eth + 1 > data_end ||
125 iph + 1 > data_end)
126 return XDP_DROP;
127
128 set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IP));
129
130 iph->version = 4;
131 iph->ihl = sizeof(*iph) >> 2;
132 iph->frag_off = 0;
133 iph->protocol = IPPROTO_IPIP;
134 iph->check = 0;
135 iph->tos = 0;
136 iph->tot_len = bpf_htons(payload_len + sizeof(*iph));
137 iph->daddr = tnl->daddr.v4;
138 iph->saddr = tnl->saddr.v4;
139 iph->ttl = 8;
140
141 next_iph = (__u16 *)iph;
142#pragma clang loop unroll(full)
143 for (i = 0; i < sizeof(*iph) >> 1; i++)
144 csum += *next_iph++;
145
146 iph->check = ~((csum & 0xffff) + (csum >> 16));
147
148 count_tx(vip.protocol);
149
150 return XDP_TX;
151}
152
153static __always_inline int handle_ipv6(struct xdp_md *xdp)
154{
155 void *data_end = (void *)(long)xdp->data_end;
156 void *data = (void *)(long)xdp->data;
157 struct iptnl_info *tnl;
158 struct ethhdr *new_eth;
159 struct ethhdr *old_eth;
160 struct ipv6hdr *ip6h = data + sizeof(struct ethhdr);
161 __u16 payload_len;
162 struct vip vip = {};
163 int dport;
164
165 if (ip6h + 1 > data_end)
166 return XDP_DROP;
167
168 dport = get_dport(ip6h + 1, data_end, ip6h->nexthdr);
169 if (dport == -1)
170 return XDP_DROP;
171
172 vip.protocol = ip6h->nexthdr;
173 vip.family = AF_INET6;
174 memcpy(vip.daddr.v6, ip6h->daddr.s6_addr32, sizeof(vip.daddr));
175 vip.dport = dport;
176 payload_len = ip6h->payload_len;
177
178 tnl = bpf_map_lookup_elem(&vip2tnl, &vip);
179 /* It only does v6-in-v6 */
180 if (!tnl || tnl->family != AF_INET6)
181 return XDP_PASS;
182
183 if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(struct ipv6hdr)))
184 return XDP_DROP;
185
186 data = (void *)(long)xdp->data;
187 data_end = (void *)(long)xdp->data_end;
188
189 new_eth = data;
190 ip6h = data + sizeof(*new_eth);
191 old_eth = data + sizeof(*ip6h);
192
193 if (new_eth + 1 > data_end || old_eth + 1 > data_end ||
194 ip6h + 1 > data_end)
195 return XDP_DROP;
196
197 set_ethhdr(new_eth, old_eth, tnl, bpf_htons(ETH_P_IPV6));
198
199 ip6h->version = 6;
200 ip6h->priority = 0;
201 memset(ip6h->flow_lbl, 0, sizeof(ip6h->flow_lbl));
202 ip6h->payload_len = bpf_htons(bpf_ntohs(payload_len) + sizeof(*ip6h));
203 ip6h->nexthdr = IPPROTO_IPV6;
204 ip6h->hop_limit = 8;
205 memcpy(ip6h->saddr.s6_addr32, tnl->saddr.v6, sizeof(tnl->saddr.v6));
206 memcpy(ip6h->daddr.s6_addr32, tnl->daddr.v6, sizeof(tnl->daddr.v6));
207
208 count_tx(vip.protocol);
209
210 return XDP_TX;
211}
212
213SEC("xdp_tx_iptunnel")
214int _xdp_tx_iptunnel(struct xdp_md *xdp)
215{
216 void *data_end = (void *)(long)xdp->data_end;
217 void *data = (void *)(long)xdp->data;
218 struct ethhdr *eth = data;
219 __u16 h_proto;
220
221 if (eth + 1 > data_end)
222 return XDP_DROP;
223
224 h_proto = eth->h_proto;
225
226 if (h_proto == bpf_htons(ETH_P_IP))
227 return handle_ipv4(xdp);
228 else if (h_proto == bpf_htons(ETH_P_IPV6))
229
230 return handle_ipv6(xdp);
231 else
232 return XDP_DROP;
233}
234
235char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
index 72aa103e4141..6b214b7b10fb 100644
--- a/tools/testing/selftests/breakpoints/Makefile
+++ b/tools/testing/selftests/breakpoints/Makefile
@@ -5,7 +5,7 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
5ifeq ($(ARCH),x86) 5ifeq ($(ARCH),x86)
6TEST_GEN_PROGS := breakpoint_test 6TEST_GEN_PROGS := breakpoint_test
7endif 7endif
8ifeq ($(ARCH),aarch64) 8ifneq (,$(filter $(ARCH),aarch64 arm64))
9TEST_GEN_PROGS := breakpoint_test_arm64 9TEST_GEN_PROGS := breakpoint_test_arm64
10endif 10endif
11 11
diff --git a/tools/testing/selftests/cpufreq/config b/tools/testing/selftests/cpufreq/config
new file mode 100644
index 000000000000..27ff72ebd0f5
--- /dev/null
+++ b/tools/testing/selftests/cpufreq/config
@@ -0,0 +1,15 @@
1CONFIG_CPU_FREQ=y
2CONFIG_CPU_FREQ_STAT=y
3CONFIG_CPU_FREQ_GOV_POWERSAVE=y
4CONFIG_CPU_FREQ_GOV_USERSPACE=y
5CONFIG_CPU_FREQ_GOV_ONDEMAND=y
6CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
7CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
8CONFIG_DEBUG_RT_MUTEXES=y
9CONFIG_DEBUG_PI_LIST=y
10CONFIG_DEBUG_SPINLOCK=y
11CONFIG_DEBUG_MUTEXES=y
12CONFIG_DEBUG_LOCK_ALLOC=y
13CONFIG_PROVE_LOCKING=y
14CONFIG_LOCKDEP=y
15CONFIG_DEBUG_ATOMIC_SLEEP=y
diff --git a/tools/testing/selftests/drivers/gpu/i915.sh b/tools/testing/selftests/drivers/gpu/i915.sh
index d407f0fa1e3a..c06d6e8a8dcc 100755
--- a/tools/testing/selftests/drivers/gpu/i915.sh
+++ b/tools/testing/selftests/drivers/gpu/i915.sh
@@ -7,6 +7,7 @@ if ! /sbin/modprobe -q -r i915; then
7fi 7fi
8 8
9if /sbin/modprobe -q i915 mock_selftests=-1; then 9if /sbin/modprobe -q i915 mock_selftests=-1; then
10 /sbin/modprobe -q -r i915
10 echo "drivers/gpu/i915: ok" 11 echo "drivers/gpu/i915: ok"
11else 12else
12 echo "drivers/gpu/i915: [FAIL]" 13 echo "drivers/gpu/i915: [FAIL]"
diff --git a/tools/testing/selftests/ftrace/config b/tools/testing/selftests/ftrace/config
index ef8214661612..8a1c9f949fe0 100644
--- a/tools/testing/selftests/ftrace/config
+++ b/tools/testing/selftests/ftrace/config
@@ -1 +1,2 @@
1CONFIG_KPROBES=y
1CONFIG_FTRACE=y 2CONFIG_FTRACE=y
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
index 52e3c4df28d6..717581145cfc 100755
--- a/tools/testing/selftests/ftrace/ftracetest
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -16,6 +16,7 @@ echo " -k|--keep Keep passed test logs"
16echo " -v|--verbose Increase verbosity of test messages" 16echo " -v|--verbose Increase verbosity of test messages"
17echo " -vv Alias of -v -v (Show all results in stdout)" 17echo " -vv Alias of -v -v (Show all results in stdout)"
18echo " -d|--debug Debug mode (trace all shell commands)" 18echo " -d|--debug Debug mode (trace all shell commands)"
19echo " -l|--logdir <dir> Save logs on the <dir>"
19exit $1 20exit $1
20} 21}
21 22
@@ -57,13 +58,17 @@ parse_opts() { # opts
57 ;; 58 ;;
58 --verbose|-v|-vv) 59 --verbose|-v|-vv)
59 VERBOSE=$((VERBOSE + 1)) 60 VERBOSE=$((VERBOSE + 1))
60 [ $1 == '-vv' ] && VERBOSE=$((VERBOSE + 1)) 61 [ $1 = '-vv' ] && VERBOSE=$((VERBOSE + 1))
61 shift 1 62 shift 1
62 ;; 63 ;;
63 --debug|-d) 64 --debug|-d)
64 DEBUG=1 65 DEBUG=1
65 shift 1 66 shift 1
66 ;; 67 ;;
68 --logdir|-l)
69 LOG_DIR=$2
70 shift 2
71 ;;
67 *.tc) 72 *.tc)
68 if [ -f "$1" ]; then 73 if [ -f "$1" ]; then
69 OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`" 74 OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`"
@@ -145,11 +150,16 @@ XFAILED_CASES=
145UNDEFINED_CASES= 150UNDEFINED_CASES=
146TOTAL_RESULT=0 151TOTAL_RESULT=0
147 152
153INSTANCE=
148CASENO=0 154CASENO=0
149testcase() { # testfile 155testcase() { # testfile
150 CASENO=$((CASENO+1)) 156 CASENO=$((CASENO+1))
151 desc=`grep "^#[ \t]*description:" $1 | cut -f2 -d:` 157 desc=`grep "^#[ \t]*description:" $1 | cut -f2 -d:`
152 prlog -n "[$CASENO]$desc" 158 prlog -n "[$CASENO]$INSTANCE$desc"
159}
160
161test_on_instance() { # testfile
162 grep -q "^#[ \t]*flags:.*instance" $1
153} 163}
154 164
155eval_result() { # sigval 165eval_result() { # sigval
@@ -266,6 +276,17 @@ for t in $TEST_CASES; do
266 run_test $t 276 run_test $t
267done 277done
268 278
279# Test on instance loop
280INSTANCE=" (instance) "
281for t in $TEST_CASES; do
282 test_on_instance $t || continue
283 SAVED_TRACING_DIR=$TRACING_DIR
284 export TRACING_DIR=`mktemp -d $TRACING_DIR/instances/ftracetest.XXXXXX`
285 run_test $t
286 rmdir $TRACING_DIR
287 TRACING_DIR=$SAVED_TRACING_DIR
288done
289
269prlog "" 290prlog ""
270prlog "# of passed: " `echo $PASSED_CASES | wc -w` 291prlog "# of passed: " `echo $PASSED_CASES | wc -w`
271prlog "# of failed: " `echo $FAILED_CASES | wc -w` 292prlog "# of failed: " `echo $FAILED_CASES | wc -w`
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
index bf9a7b037924..ebfce83f35b4 100644
--- a/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: Basic test for tracers 2# description: Basic test for tracers
3# flags: instance
3test -f available_tracers 4test -f available_tracers
4for t in `cat available_tracers`; do 5for t in `cat available_tracers`; do
5 echo $t > current_tracer 6 echo $t > current_tracer
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
index bde6625d9785..9e33f841812f 100644
--- a/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: Basic trace clock test 2# description: Basic trace clock test
3# flags: instance
3test -f trace_clock 4test -f trace_clock
4for c in `cat trace_clock | tr -d \[\]`; do 5for c in `cat trace_clock | tr -d \[\]`; do
5 echo $c > trace_clock 6 echo $c > trace_clock
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-enable.tc b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
index 87eb9d6dd4ca..283b45ecb199 100644
--- a/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
+++ b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event tracing - enable/disable with event level files 2# description: event tracing - enable/disable with event level files
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 echo > set_event 6 echo > set_event
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc
index d4ab27b522f8..96c1a95be4f7 100644
--- a/tools/testing/selftests/ftrace/test.d/event/event-pid.tc
+++ b/tools/testing/selftests/ftrace/test.d/event/event-pid.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event tracing - restricts events based on pid 2# description: event tracing - restricts events based on pid
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 echo > set_event 6 echo > set_event
diff --git a/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
index ced27ef0638f..b8fe2e5b9e67 100644
--- a/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
+++ b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event tracing - enable/disable with subsystem level files 2# description: event tracing - enable/disable with subsystem level files
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 echo > set_event 6 echo > set_event
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc
new file mode 100644
index 000000000000..bab5ff7c607e
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-pid.tc
@@ -0,0 +1,117 @@
1#!/bin/sh
2# description: ftrace - function pid filters
3
4# Make sure that function pid matching filter works.
5# Also test it on an instance directory
6
7if ! grep -q function available_tracers; then
8 echo "no function tracer configured"
9 exit_unsupported
10fi
11
12if [ ! -f set_ftrace_pid ]; then
13 echo "set_ftrace_pid not found? Is function tracer not set?"
14 exit_unsupported
15fi
16
17if [ ! -f set_ftrace_filter ]; then
18 echo "set_ftrace_filter not found? Is function tracer not set?"
19 exit_unsupported
20fi
21
22do_function_fork=1
23
24if [ ! -f options/function-fork ]; then
25 do_function_fork=0
26 echo "no option for function-fork found. Option will not be tested."
27fi
28
29read PID _ < /proc/self/stat
30
31if [ $do_function_fork -eq 1 ]; then
32 # default value of function-fork option
33 orig_value=`grep function-fork trace_options`
34fi
35
36do_reset() {
37 reset_tracer
38 clear_trace
39 enable_tracing
40 echo > set_ftrace_filter
41 echo > set_ftrace_pid
42
43 if [ $do_function_fork -eq 0 ]; then
44 return
45 fi
46
47 echo $orig_value > trace_options
48}
49
50fail() { # msg
51 do_reset
52 echo $1
53 exit $FAIL
54}
55
56yield() {
57 ping localhost -c 1 || sleep .001 || usleep 1 || sleep 1
58}
59
60do_test() {
61 disable_tracing
62
63 echo do_execve* > set_ftrace_filter
64 echo *do_fork >> set_ftrace_filter
65
66 echo $PID > set_ftrace_pid
67 echo function > current_tracer
68
69 if [ $do_function_fork -eq 1 ]; then
70 # don't allow children to be traced
71 echo nofunction-fork > trace_options
72 fi
73
74 enable_tracing
75 yield
76
77 count_pid=`cat trace | grep -v ^# | grep $PID | wc -l`
78 count_other=`cat trace | grep -v ^# | grep -v $PID | wc -l`
79
80 # count_other should be 0
81 if [ $count_pid -eq 0 -o $count_other -ne 0 ]; then
82 fail "PID filtering not working?"
83 fi
84
85 disable_tracing
86 clear_trace
87
88 if [ $do_function_fork -eq 0 ]; then
89 return
90 fi
91
92 # allow children to be traced
93 echo function-fork > trace_options
94
95 enable_tracing
96 yield
97
98 count_pid=`cat trace | grep -v ^# | grep $PID | wc -l`
99 count_other=`cat trace | grep -v ^# | grep -v $PID | wc -l`
100
101 # count_other should NOT be 0
102 if [ $count_pid -eq 0 -o $count_other -eq 0 ]; then
103 fail "PID filtering not following fork?"
104 fi
105}
106
107do_test
108
109mkdir instances/foo
110cd instances/foo
111do_test
112cd ../../
113rmdir instances/foo
114
115do_reset
116
117exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
new file mode 100644
index 000000000000..aa31368851c9
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_event_triggers.tc
@@ -0,0 +1,114 @@
1#!/bin/sh
2# description: ftrace - test for function event triggers
3# flags: instance
4#
5# Ftrace allows to add triggers to functions, such as enabling or disabling
6# tracing, enabling or disabling trace events, or recording a stack trace
7# within the ring buffer.
8#
9# This test is designed to test event triggers
10#
11
12# The triggers are set within the set_ftrace_filter file
13if [ ! -f set_ftrace_filter ]; then
14 echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
15 exit_unsupported
16fi
17
18do_reset() {
19 reset_ftrace_filter
20 reset_tracer
21 disable_events
22 clear_trace
23 enable_tracing
24}
25
26fail() { # mesg
27 do_reset
28 echo $1
29 exit $FAIL
30}
31
32SLEEP_TIME=".1"
33
34do_reset
35
36echo "Testing function probes with events:"
37
38EVENT="sched:sched_switch"
39EVENT_ENABLE="events/sched/sched_switch/enable"
40
41cnt_trace() {
42 grep -v '^#' trace | wc -l
43}
44
45test_event_enabled() {
46 val=$1
47
48 e=`cat $EVENT_ENABLE`
49 if [ "$e" != $val ]; then
50 echo "Expected $val but found $e"
51 exit 1
52 fi
53}
54
55run_enable_disable() {
56 enable=$1 # enable
57 Enable=$2 # Enable
58 check_disable=$3 # 0
59 check_enable_star=$4 # 1*
60 check_disable_star=$5 # 0*
61
62 cnt=`cnt_trace`
63 if [ $cnt -ne 0 ]; then
64 fail "Found junk in trace file"
65 fi
66
67 echo "$Enable event all the time"
68
69 echo $check_disable > $EVENT_ENABLE
70 sleep $SLEEP_TIME
71
72 test_event_enabled $check_disable
73
74 echo "schedule:${enable}_event:$EVENT" > set_ftrace_filter
75
76 echo " make sure it works 5 times"
77
78 for i in `seq 5`; do
79 sleep $SLEEP_TIME
80 echo " test $i"
81 test_event_enabled $check_enable_star
82
83 echo $check_disable > $EVENT_ENABLE
84 done
85 sleep $SLEEP_TIME
86 echo " make sure it's still works"
87 test_event_enabled $check_enable_star
88
89 reset_ftrace_filter
90
91 echo " make sure it only works 3 times"
92
93 echo $check_disable > $EVENT_ENABLE
94 sleep $SLEEP_TIME
95
96 echo "schedule:${enable}_event:$EVENT:3" > set_ftrace_filter
97
98 for i in `seq 3`; do
99 sleep $SLEEP_TIME
100 echo " test $i"
101 test_event_enabled $check_enable_star
102
103 echo $check_disable > $EVENT_ENABLE
104 done
105
106 sleep $SLEEP_TIME
107 echo " make sure it stop working"
108 test_event_enabled $check_disable_star
109
110 do_reset
111}
112
113run_enable_disable enable Enable 0 "1*" "0*"
114run_enable_disable disable Disable 1 "0*" "1*"
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
new file mode 100644
index 000000000000..113b4d9bc733
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_set_ftrace_file.tc
@@ -0,0 +1,132 @@
1#!/bin/sh
2# description: ftrace - test reading of set_ftrace_filter
3#
4# The set_ftrace_filter file of ftrace is used to list functions as well as
5# triggers (probes) attached to functions. The code to read this file is not
6# straight forward and has had various bugs in the past. This test is designed
7# to add functions and triggers to that file in various ways and read that
8# file in various ways (cat vs dd).
9#
10
11# The triggers are set within the set_ftrace_filter file
12if [ ! -f set_ftrace_filter ]; then
13 echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
14 exit_unsupported
15fi
16
17do_reset() {
18 reset_tracer
19 reset_ftrace_filter
20 disable_events
21 clear_trace
22 enable_tracing
23}
24
25fail() { # mesg
26 do_reset
27 echo $1
28 exit $FAIL
29}
30
31do_reset
32
33FILTER=set_ftrace_filter
34FUNC1="schedule"
35FUNC2="do_IRQ"
36
37ALL_FUNCS="#### all functions enabled ####"
38
39test_func() {
40 if ! echo "$1" | grep -q "^$2\$"; then
41 return 0
42 fi
43 echo "$1" | grep -v "^$2\$"
44 return 1
45}
46
47check_set_ftrace_filter() {
48 cat=`cat $FILTER`
49 dd1=`dd if=$FILTER bs=1 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`
50 dd100=`dd if=$FILTER bs=100 | grep -v -e 'records in' -e 'records out' -e 'bytes copied'`
51
52 echo "Testing '$@'"
53
54 while [ $# -gt 0 ]; do
55 echo "test $1"
56 if cat=`test_func "$cat" "$1"`; then
57 return 0
58 fi
59 if dd1=`test_func "$dd1" "$1"`; then
60 return 0
61 fi
62 if dd100=`test_func "$dd100" "$1"`; then
63 return 0
64 fi
65 shift
66 done
67
68 if [ -n "$cat" ]; then
69 return 0
70 fi
71 if [ -n "$dd1" ]; then
72 return 0
73 fi
74 if [ -n "$dd100" ]; then
75 return 0
76 fi
77 return 1;
78}
79
80if check_set_ftrace_filter "$ALL_FUNCS"; then
81 fail "Expected only $ALL_FUNCS"
82fi
83
84echo "$FUNC1:traceoff" > set_ftrace_filter
85if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited"; then
86 fail "Expected $ALL_FUNCS and $FUNC1:traceoff:unlimited"
87fi
88
89echo "$FUNC1" > set_ftrace_filter
90if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited"; then
91 fail "Expected $FUNC1 and $FUNC1:traceoff:unlimited"
92fi
93
94echo "$FUNC2" >> set_ftrace_filter
95if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited"; then
96 fail "Expected $FUNC1 $FUNC2 and $FUNC1:traceoff:unlimited"
97fi
98
99echo "$FUNC2:traceoff" >> set_ftrace_filter
100if check_set_ftrace_filter "$FUNC1" "$FUNC2" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
101 fail "Expected $FUNC1 $FUNC2 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
102fi
103
104echo "$FUNC1" > set_ftrace_filter
105if check_set_ftrace_filter "$FUNC1" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
106 fail "Expected $FUNC1 $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
107fi
108
109echo > set_ftrace_filter
110if check_set_ftrace_filter "$ALL_FUNCS" "$FUNC1:traceoff:unlimited" "$FUNC2:traceoff:unlimited"; then
111 fail "Expected $ALL_FUNCS $FUNC1:traceoff:unlimited and $FUNC2:traceoff:unlimited"
112fi
113
114reset_ftrace_filter
115
116if check_set_ftrace_filter "$ALL_FUNCS"; then
117 fail "Expected $ALL_FUNCS"
118fi
119
120echo "$FUNC1" > set_ftrace_filter
121if check_set_ftrace_filter "$FUNC1" ; then
122 fail "Expected $FUNC1"
123fi
124
125echo "$FUNC2" >> set_ftrace_filter
126if check_set_ftrace_filter "$FUNC1" "$FUNC2" ; then
127 fail "Expected $FUNC1 and $FUNC2"
128fi
129
130do_reset
131
132exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
new file mode 100644
index 000000000000..c8e02ec01eaf
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_traceonoff_triggers.tc
@@ -0,0 +1,172 @@
1#!/bin/sh
2# description: ftrace - test for function traceon/off triggers
3# flags: instance
4#
5# Ftrace allows to add triggers to functions, such as enabling or disabling
6# tracing, enabling or disabling trace events, or recording a stack trace
7# within the ring buffer.
8#
9# This test is designed to test enabling and disabling tracing triggers
10#
11
12# The triggers are set within the set_ftrace_filter file
13if [ ! -f set_ftrace_filter ]; then
14 echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
15 exit_unsupported
16fi
17
18do_reset() {
19 reset_ftrace_filter
20 reset_tracer
21 disable_events
22 clear_trace
23 enable_tracing
24}
25
26fail() { # mesg
27 do_reset
28 echo $1
29 exit $FAIL
30}
31
32SLEEP_TIME=".1"
33
34do_reset
35
36echo "Testing function probes with enabling disabling tracing:"
37
38cnt_trace() {
39 grep -v '^#' trace | wc -l
40}
41
42echo '** DISABLE TRACING'
43disable_tracing
44clear_trace
45
46cnt=`cnt_trace`
47if [ $cnt -ne 0 ]; then
48 fail "Found junk in trace"
49fi
50
51
52echo '** ENABLE EVENTS'
53
54echo 1 > events/enable
55
56echo '** ENABLE TRACING'
57enable_tracing
58
59cnt=`cnt_trace`
60if [ $cnt -eq 0 ]; then
61 fail "Nothing found in trace"
62fi
63
64# powerpc uses .schedule
65func="schedule"
66x=`grep '^\.schedule$' available_filter_functions | wc -l`
67if [ "$x" -eq 1 ]; then
68 func=".schedule"
69fi
70
71echo '** SET TRACEOFF'
72
73echo "$func:traceoff" > set_ftrace_filter
74
75cnt=`grep schedule set_ftrace_filter | wc -l`
76if [ $cnt -ne 1 ]; then
77 fail "Did not find traceoff trigger"
78fi
79
80cnt=`cnt_trace`
81sleep $SLEEP_TIME
82cnt2=`cnt_trace`
83
84if [ $cnt -ne $cnt2 ]; then
85 fail "Tracing is not stopped"
86fi
87
88on=`cat tracing_on`
89if [ $on != "0" ]; then
90 fail "Tracing is not off"
91fi
92
93line1=`cat trace | tail -1`
94sleep $SLEEP_TIME
95line2=`cat trace | tail -1`
96
97if [ "$line1" != "$line2" ]; then
98 fail "Tracing file is still changing"
99fi
100
101clear_trace
102
103cnt=`cnt_trace`
104if [ $cnt -ne 0 ]; then
105 fail "Tracing is still happeing"
106fi
107
108echo "!$func:traceoff" >> set_ftrace_filter
109
110cnt=`grep schedule set_ftrace_filter | wc -l`
111if [ $cnt -ne 0 ]; then
112 fail "traceoff trigger still exists"
113fi
114
115on=`cat tracing_on`
116if [ $on != "0" ]; then
117 fail "Tracing is started again"
118fi
119
120echo "$func:traceon" > set_ftrace_filter
121
122cnt=`grep schedule set_ftrace_filter | wc -l`
123if [ $cnt -ne 1 ]; then
124 fail "traceon trigger not found"
125fi
126
127cnt=`cnt_trace`
128if [ $cnt -eq 0 ]; then
129 fail "Tracing did not start"
130fi
131
132on=`cat tracing_on`
133if [ $on != "1" ]; then
134 fail "Tracing was not enabled"
135fi
136
137
138echo "!$func:traceon" >> set_ftrace_filter
139
140cnt=`grep schedule set_ftrace_filter | wc -l`
141if [ $cnt -ne 0 ]; then
142 fail "traceon trigger still exists"
143fi
144
145check_sleep() {
146 val=$1
147 sleep $SLEEP_TIME
148 cat set_ftrace_filter
149 on=`cat tracing_on`
150 if [ $on != "$val" ]; then
151 fail "Expected tracing_on to be $val, but it was $on"
152 fi
153}
154
155
156echo "$func:traceoff:3" > set_ftrace_filter
157check_sleep "0"
158echo 1 > tracing_on
159check_sleep "0"
160echo 1 > tracing_on
161check_sleep "0"
162echo 1 > tracing_on
163check_sleep "1"
164echo "!$func:traceoff:0" > set_ftrace_filter
165
166if grep -e traceon -e traceoff set_ftrace_filter; then
167 fail "Tracing on and off triggers still exist"
168fi
169
170disable_events
171
172exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
index 91de1a8e4f19..f2019b37370d 100644
--- a/tools/testing/selftests/ftrace/test.d/functions
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -30,6 +30,27 @@ reset_events_filter() { # reset all current setting filters
30 done 30 done
31} 31}
32 32
33reset_ftrace_filter() { # reset all triggers in set_ftrace_filter
34 echo > set_ftrace_filter
35 grep -v '^#' set_ftrace_filter | while read t; do
36 tr=`echo $t | cut -d: -f2`
37 if [ "$tr" = "" ]; then
38 continue
39 fi
40 if [ $tr = "enable_event" -o $tr = "disable_event" ]; then
41 tr=`echo $t | cut -d: -f1-4`
42 limit=`echo $t | cut -d: -f5`
43 else
44 tr=`echo $t | cut -d: -f1-2`
45 limit=`echo $t | cut -d: -f3`
46 fi
47 if [ "$limit" != "unlimited" ]; then
48 tr="$tr:$limit"
49 fi
50 echo "!$tr" > set_ftrace_filter
51 done
52}
53
33disable_events() { 54disable_events() {
34 echo 0 > events/enable 55 echo 0 > events/enable
35} 56}
diff --git a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc
index 4c5a061a5b4e..c73db7863adb 100644
--- a/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc
+++ b/tools/testing/selftests/ftrace/test.d/instances/instance-event.tc
@@ -75,9 +75,13 @@ rmdir foo
75if [ -d foo ]; then 75if [ -d foo ]; then
76 fail "foo still exists" 76 fail "foo still exists"
77fi 77fi
78exit 0
79
80 78
79mkdir foo
80echo "schedule:enable_event:sched:sched_switch" > foo/set_ftrace_filter
81rmdir foo
82if [ -d foo ]; then
83 fail "foo still exists"
84fi
81 85
82 86
83instance_slam() { 87instance_slam() {
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc
index 0a78705b43b2..c75faefb4fff 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_type.tc
@@ -26,7 +26,7 @@ check_types() {
26 test $X2 = $X3 26 test $X2 = $X3
27 test 0x$X3 = $3 27 test 0x$X3 = $3
28 28
29 B4=`printf "%x" $4` 29 B4=`printf "%02x" $4`
30 B3=`echo -n $X3 | tail -c 3 | head -c 2` 30 B3=`echo -n $X3 | tail -c 3 | head -c 2`
31 test $B3 = $B4 31 test $B3 = $B4
32} 32}
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_maxactive.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_maxactive.tc
new file mode 100644
index 000000000000..57abdf1caabf
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_maxactive.tc
@@ -0,0 +1,39 @@
1#!/bin/sh
2# description: Kretprobe dynamic event with maxactive
3
4[ -f kprobe_events ] || exit_unsupported # this is configurable
5
6echo > kprobe_events
7
8# Test if we successfully reject unknown messages
9if echo 'a:myprobeaccept inet_csk_accept' > kprobe_events; then false; else true; fi
10
11# Test if we successfully reject too big maxactive
12if echo 'r1000000:myprobeaccept inet_csk_accept' > kprobe_events; then false; else true; fi
13
14# Test if we successfully reject unparsable numbers for maxactive
15if echo 'r10fuzz:myprobeaccept inet_csk_accept' > kprobe_events; then false; else true; fi
16
17# Test for kretprobe with event name without maxactive
18echo 'r:myprobeaccept inet_csk_accept' > kprobe_events
19grep myprobeaccept kprobe_events
20test -d events/kprobes/myprobeaccept
21echo '-:myprobeaccept' >> kprobe_events
22
23# Test for kretprobe with event name with a small maxactive
24echo 'r10:myprobeaccept inet_csk_accept' > kprobe_events
25grep myprobeaccept kprobe_events
26test -d events/kprobes/myprobeaccept
27echo '-:myprobeaccept' >> kprobe_events
28
29# Test for kretprobe without event name without maxactive
30echo 'r inet_csk_accept' > kprobe_events
31grep inet_csk_accept kprobe_events
32echo > kprobe_events
33
34# Test for kretprobe without event name with a small maxactive
35echo 'r10 inet_csk_accept' > kprobe_events
36grep inet_csk_accept kprobe_events
37echo > kprobe_events
38
39clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc
index 1a9445021bf1..c5435adfdd93 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-eventonoff.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event trigger - test event enable/disable trigger 2# description: event trigger - test event enable/disable trigger
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 reset_trigger 6 reset_trigger
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc
index 514e466e198b..48849a8d577f 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-filter.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event trigger - test trigger filter 2# description: event trigger - test trigger filter
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 reset_trigger 6 reset_trigger
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc
index 400e98b64948..b7f86d10b549 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist-mod.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event trigger - test histogram modifiers 2# description: event trigger - test histogram modifiers
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 reset_trigger 6 reset_trigger
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc
index a00184cd9c95..fb66f7d9339d 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-hist.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event trigger - test histogram trigger 2# description: event trigger - test histogram trigger
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 reset_trigger 6 reset_trigger
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc
index 3478b00ead57..f9153087dd7c 100644
--- a/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-multihist.tc
@@ -1,5 +1,6 @@
1#!/bin/sh 1#!/bin/sh
2# description: event trigger - test multiple histogram triggers 2# description: event trigger - test multiple histogram triggers
3# flags: instance
3 4
4do_reset() { 5do_reset() {
5 reset_trigger 6 reset_trigger
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile
index 653c5cd9e44d..e2fbb890aef9 100644
--- a/tools/testing/selftests/futex/Makefile
+++ b/tools/testing/selftests/futex/Makefile
@@ -8,7 +8,7 @@ include ../lib.mk
8 8
9all: 9all:
10 for DIR in $(SUBDIRS); do \ 10 for DIR in $(SUBDIRS); do \
11 BUILD_TARGET=$$OUTPUT/$$DIR; \ 11 BUILD_TARGET=$(OUTPUT)/$$DIR; \
12 mkdir $$BUILD_TARGET -p; \ 12 mkdir $$BUILD_TARGET -p; \
13 make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ 13 make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
14 done 14 done
@@ -22,7 +22,7 @@ override define INSTALL_RULE
22 install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) 22 install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)
23 23
24 @for SUBDIR in $(SUBDIRS); do \ 24 @for SUBDIR in $(SUBDIRS); do \
25 BUILD_TARGET=$$OUTPUT/$$SUBDIR; \ 25 BUILD_TARGET=$(OUTPUT)/$$SUBDIR; \
26 mkdir $$BUILD_TARGET -p; \ 26 mkdir $$BUILD_TARGET -p; \
27 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \ 27 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \
28 done; 28 done;
@@ -32,9 +32,10 @@ override define EMIT_TESTS
32 echo "./run.sh" 32 echo "./run.sh"
33endef 33endef
34 34
35clean: 35override define CLEAN
36 for DIR in $(SUBDIRS); do \ 36 for DIR in $(SUBDIRS); do \
37 BUILD_TARGET=$$OUTPUT/$$DIR; \ 37 BUILD_TARGET=$(OUTPUT)/$$DIR; \
38 mkdir $$BUILD_TARGET -p; \ 38 mkdir $$BUILD_TARGET -p; \
39 make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ 39 make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
40 done 40 done
41endef
diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile
index 205e4d10e085..298929df97e6 100644
--- a/tools/testing/selftests/gpio/Makefile
+++ b/tools/testing/selftests/gpio/Makefile
@@ -2,13 +2,20 @@
2TEST_PROGS := gpio-mockup.sh 2TEST_PROGS := gpio-mockup.sh
3TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES) 3TEST_FILES := gpio-mockup-sysfs.sh $(BINARIES)
4BINARIES := gpio-mockup-chardev 4BINARIES := gpio-mockup-chardev
5EXTRA_PROGS := ../gpiogpio-event-mon ../gpiogpio-hammer ../gpiolsgpio
6EXTRA_DIRS := ../gpioinclude/
7EXTRA_OBJS := ../gpiogpio-event-mon-in.o ../gpiogpio-event-mon.o
8EXTRA_OBJS += ../gpiogpio-hammer-in.o ../gpiogpio-utils.o ../gpiolsgpio-in.o
9EXTRA_OBJS += ../gpiolsgpio.o
5 10
6include ../lib.mk 11include ../lib.mk
7 12
8all: $(BINARIES) 13all: $(BINARIES)
9 14
10clean: 15override define CLEAN
11 $(RM) $(BINARIES) 16 $(RM) $(BINARIES) $(EXTRA_PROGS) $(EXTRA_OBJS)
17 $(RM) -r $(EXTRA_DIRS)
18endef
12 19
13CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/ 20CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/
14LDLIBS += -lmount -I/usr/include/libmount 21LDLIBS += -lmount -I/usr/include/libmount
diff --git a/tools/testing/selftests/gpio/config b/tools/testing/selftests/gpio/config
new file mode 100644
index 000000000000..abaa6902b7b6
--- /dev/null
+++ b/tools/testing/selftests/gpio/config
@@ -0,0 +1,2 @@
1CONFIG_GPIOLIB=y
2CONFIG_GPIO_MOCKUP=m
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index 775c589ac3c0..959273c3a52e 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -51,8 +51,12 @@ endef
51emit_tests: 51emit_tests:
52 $(EMIT_TESTS) 52 $(EMIT_TESTS)
53 53
54clean: 54define CLEAN
55 $(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN) 55 $(RM) -r $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) $(EXTRA_CLEAN)
56endef
57
58clean:
59 $(CLEAN)
56 60
57$(OUTPUT)/%:%.c 61$(OUTPUT)/%:%.c
58 $(LINK.c) $^ $(LDLIBS) -o $@ 62 $(LINK.c) $^ $(LDLIBS) -o $@
diff --git a/tools/testing/selftests/lib/config b/tools/testing/selftests/lib/config
new file mode 100644
index 000000000000..126933bcc950
--- /dev/null
+++ b/tools/testing/selftests/lib/config
@@ -0,0 +1,3 @@
1CONFIG_TEST_PRINTF=m
2CONFIG_TEST_BITMAP=m
3CONFIG_PRIME_NUMBERS=m
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index fbfe5d0d5c2e..35cbb4cba410 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -5,7 +5,7 @@ CFLAGS += -I../../../../usr/include/
5 5
6reuseport_bpf_numa: LDFLAGS += -lnuma 6reuseport_bpf_numa: LDFLAGS += -lnuma
7 7
8TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh 8TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh
9TEST_GEN_FILES = socket 9TEST_GEN_FILES = socket
10TEST_GEN_FILES += psock_fanout psock_tpacket 10TEST_GEN_FILES += psock_fanout psock_tpacket
11TEST_GEN_FILES += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa 11TEST_GEN_FILES += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
diff --git a/tools/testing/selftests/net/netdevice.sh b/tools/testing/selftests/net/netdevice.sh
new file mode 100755
index 000000000000..4e00568d70c2
--- /dev/null
+++ b/tools/testing/selftests/net/netdevice.sh
@@ -0,0 +1,200 @@
1#!/bin/sh
2#
3# This test is for checking network interface
4# For the moment it tests only ethernet interface (but wifi could be easily added)
5#
6# We assume that all network driver are loaded
7# if not they probably have failed earlier in the boot process and their logged error will be catched by another test
8#
9
10# this function will try to up the interface
11# if already up, nothing done
12# arg1: network interface name
13kci_net_start()
14{
15 netdev=$1
16
17 ip link show "$netdev" |grep -q UP
18 if [ $? -eq 0 ];then
19 echo "SKIP: $netdev: interface already up"
20 return 0
21 fi
22
23 ip link set "$netdev" up
24 if [ $? -ne 0 ];then
25 echo "FAIL: $netdev: Fail to up interface"
26 return 1
27 else
28 echo "PASS: $netdev: set interface up"
29 NETDEV_STARTED=1
30 fi
31 return 0
32}
33
34# this function will try to setup an IP and MAC address on a network interface
35# Doing nothing if the interface was already up
36# arg1: network interface name
37kci_net_setup()
38{
39 netdev=$1
40
41 # do nothing if the interface was already up
42 if [ $NETDEV_STARTED -eq 0 ];then
43 return 0
44 fi
45
46 MACADDR='02:03:04:05:06:07'
47 ip link set dev $netdev address "$MACADDR"
48 if [ $? -ne 0 ];then
49 echo "FAIL: $netdev: Cannot set MAC address"
50 else
51 ip link show $netdev |grep -q "$MACADDR"
52 if [ $? -eq 0 ];then
53 echo "PASS: $netdev: set MAC address"
54 else
55 echo "FAIL: $netdev: Cannot set MAC address"
56 fi
57 fi
58
59 #check that the interface did not already have an IP
60 ip address show "$netdev" |grep '^[[:space:]]*inet'
61 if [ $? -eq 0 ];then
62 echo "SKIP: $netdev: already have an IP"
63 return 0
64 fi
65
66 # TODO what ipaddr to set ? DHCP ?
67 echo "SKIP: $netdev: set IP address"
68 return 0
69}
70
71# test an ethtool command
72# arg1: return code for not supported (see ethtool code source)
73# arg2: summary of the command
74# arg3: command to execute
75kci_netdev_ethtool_test()
76{
77 if [ $# -le 2 ];then
78 echo "SKIP: $netdev: ethtool: invalid number of arguments"
79 return 1
80 fi
81 $3 >/dev/null
82 ret=$?
83 if [ $ret -ne 0 ];then
84 if [ $ret -eq "$1" ];then
85 echo "SKIP: $netdev: ethtool $2 not supported"
86 else
87 echo "FAIL: $netdev: ethtool $2"
88 return 1
89 fi
90 else
91 echo "PASS: $netdev: ethtool $2"
92 fi
93 return 0
94}
95
96# test ethtool commands
97# arg1: network interface name
98kci_netdev_ethtool()
99{
100 netdev=$1
101
102 #check presence of ethtool
103 ethtool --version 2>/dev/null >/dev/null
104 if [ $? -ne 0 ];then
105 echo "SKIP: ethtool not present"
106 return 1
107 fi
108
109 TMP_ETHTOOL_FEATURES="$(mktemp)"
110 if [ ! -e "$TMP_ETHTOOL_FEATURES" ];then
111 echo "SKIP: Cannot create a tmp file"
112 return 1
113 fi
114
115 ethtool -k "$netdev" > "$TMP_ETHTOOL_FEATURES"
116 if [ $? -ne 0 ];then
117 echo "FAIL: $netdev: ethtool list features"
118 rm "$TMP_ETHTOOL_FEATURES"
119 return 1
120 fi
121 echo "PASS: $netdev: ethtool list features"
122 #TODO for each non fixed features, try to turn them on/off
123 rm "$TMP_ETHTOOL_FEATURES"
124
125 kci_netdev_ethtool_test 74 'dump' "ethtool -d $netdev"
126 kci_netdev_ethtool_test 94 'stats' "ethtool -S $netdev"
127 return 0
128}
129
130# stop a netdev
131# arg1: network interface name
132kci_netdev_stop()
133{
134 netdev=$1
135
136 if [ $NETDEV_STARTED -eq 0 ];then
137 echo "SKIP: $netdev: interface kept up"
138 return 0
139 fi
140
141 ip link set "$netdev" down
142 if [ $? -ne 0 ];then
143 echo "FAIL: $netdev: stop interface"
144 return 1
145 fi
146 echo "PASS: $netdev: stop interface"
147 return 0
148}
149
150# run all test on a netdev
151# arg1: network interface name
152kci_test_netdev()
153{
154 NETDEV_STARTED=0
155 IFACE_TO_UPDOWN="$1"
156 IFACE_TO_TEST="$1"
157 #check for VLAN interface
158 MASTER_IFACE="$(echo $1 | cut -d@ -f2)"
159 if [ ! -z "$MASTER_IFACE" ];then
160 IFACE_TO_UPDOWN="$MASTER_IFACE"
161 IFACE_TO_TEST="$(echo $1 | cut -d@ -f1)"
162 fi
163
164 NETDEV_STARTED=0
165 kci_net_start "$IFACE_TO_UPDOWN"
166
167 kci_net_setup "$IFACE_TO_TEST"
168
169 kci_netdev_ethtool "$IFACE_TO_TEST"
170
171 kci_netdev_stop "$IFACE_TO_UPDOWN"
172 return 0
173}
174
175#check for needed privileges
176if [ "$(id -u)" -ne 0 ];then
177 echo "SKIP: Need root privileges"
178 exit 0
179fi
180
181ip -Version 2>/dev/null >/dev/null
182if [ $? -ne 0 ];then
183 echo "SKIP: Could not run test without the ip tool"
184 exit 0
185fi
186
187TMP_LIST_NETDEV="$(mktemp)"
188if [ ! -e "$TMP_LIST_NETDEV" ];then
189 echo "FAIL: Cannot create a tmp file"
190 exit 1
191fi
192
193ip link show |grep '^[0-9]' | grep -oE '[[:space:]].*eth[0-9]*:|[[:space:]].*enp[0-9]s[0-9]:' | cut -d\ -f2 | cut -d: -f1> "$TMP_LIST_NETDEV"
194while read netdev
195do
196 kci_test_netdev "$netdev"
197done < "$TMP_LIST_NETDEV"
198
199rm "$TMP_LIST_NETDEV"
200exit 0
diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c
index 412459369686..989f917068d1 100644
--- a/tools/testing/selftests/net/psock_fanout.c
+++ b/tools/testing/selftests/net/psock_fanout.c
@@ -71,18 +71,17 @@
71 71
72/* Open a socket in a given fanout mode. 72/* Open a socket in a given fanout mode.
73 * @return -1 if mode is bad, a valid socket otherwise */ 73 * @return -1 if mode is bad, a valid socket otherwise */
74static int sock_fanout_open(uint16_t typeflags, int num_packets) 74static int sock_fanout_open(uint16_t typeflags, uint16_t group_id)
75{ 75{
76 int fd, val; 76 int fd, val;
77 77
78 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 78 fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
79 if (fd < 0) { 79 if (fd < 0) {
80 perror("socket packet"); 80 perror("socket packet");
81 exit(1); 81 exit(1);
82 } 82 }
83 83
84 /* fanout group ID is always 0: tests whether old groups are deleted */ 84 val = (((int) typeflags) << 16) | group_id;
85 val = ((int) typeflags) << 16;
86 if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) { 85 if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) {
87 if (close(fd)) { 86 if (close(fd)) {
88 perror("close packet"); 87 perror("close packet");
@@ -95,6 +94,38 @@ static int sock_fanout_open(uint16_t typeflags, int num_packets)
95 return fd; 94 return fd;
96} 95}
97 96
97static void sock_fanout_set_cbpf(int fd)
98{
99 struct sock_filter bpf_filter[] = {
100 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 80), /* ldb [80] */
101 BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
102 };
103 struct sock_fprog bpf_prog;
104
105 bpf_prog.filter = bpf_filter;
106 bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter);
107
108 if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT_DATA, &bpf_prog,
109 sizeof(bpf_prog))) {
110 perror("fanout data cbpf");
111 exit(1);
112 }
113}
114
115static void sock_fanout_getopts(int fd, uint16_t *typeflags, uint16_t *group_id)
116{
117 int sockopt;
118 socklen_t sockopt_len = sizeof(sockopt);
119
120 if (getsockopt(fd, SOL_PACKET, PACKET_FANOUT,
121 &sockopt, &sockopt_len)) {
122 perror("failed to getsockopt");
123 exit(1);
124 }
125 *typeflags = sockopt >> 16;
126 *group_id = sockopt & 0xfffff;
127}
128
98static void sock_fanout_set_ebpf(int fd) 129static void sock_fanout_set_ebpf(int fd)
99{ 130{
100 const int len_off = __builtin_offsetof(struct __sk_buff, len); 131 const int len_off = __builtin_offsetof(struct __sk_buff, len);
@@ -223,26 +254,26 @@ static void test_control_group(void)
223 254
224 fprintf(stderr, "test: control multiple sockets\n"); 255 fprintf(stderr, "test: control multiple sockets\n");
225 256
226 fds[0] = sock_fanout_open(PACKET_FANOUT_HASH, 20); 257 fds[0] = sock_fanout_open(PACKET_FANOUT_HASH, 0);
227 if (fds[0] == -1) { 258 if (fds[0] == -1) {
228 fprintf(stderr, "ERROR: failed to open HASH socket\n"); 259 fprintf(stderr, "ERROR: failed to open HASH socket\n");
229 exit(1); 260 exit(1);
230 } 261 }
231 if (sock_fanout_open(PACKET_FANOUT_HASH | 262 if (sock_fanout_open(PACKET_FANOUT_HASH |
232 PACKET_FANOUT_FLAG_DEFRAG, 10) != -1) { 263 PACKET_FANOUT_FLAG_DEFRAG, 0) != -1) {
233 fprintf(stderr, "ERROR: joined group with wrong flag defrag\n"); 264 fprintf(stderr, "ERROR: joined group with wrong flag defrag\n");
234 exit(1); 265 exit(1);
235 } 266 }
236 if (sock_fanout_open(PACKET_FANOUT_HASH | 267 if (sock_fanout_open(PACKET_FANOUT_HASH |
237 PACKET_FANOUT_FLAG_ROLLOVER, 10) != -1) { 268 PACKET_FANOUT_FLAG_ROLLOVER, 0) != -1) {
238 fprintf(stderr, "ERROR: joined group with wrong flag ro\n"); 269 fprintf(stderr, "ERROR: joined group with wrong flag ro\n");
239 exit(1); 270 exit(1);
240 } 271 }
241 if (sock_fanout_open(PACKET_FANOUT_CPU, 10) != -1) { 272 if (sock_fanout_open(PACKET_FANOUT_CPU, 0) != -1) {
242 fprintf(stderr, "ERROR: joined group with wrong mode\n"); 273 fprintf(stderr, "ERROR: joined group with wrong mode\n");
243 exit(1); 274 exit(1);
244 } 275 }
245 fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, 20); 276 fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, 0);
246 if (fds[1] == -1) { 277 if (fds[1] == -1) {
247 fprintf(stderr, "ERROR: failed to join group\n"); 278 fprintf(stderr, "ERROR: failed to join group\n");
248 exit(1); 279 exit(1);
@@ -253,6 +284,61 @@ static void test_control_group(void)
253 } 284 }
254} 285}
255 286
287/* Test creating a unique fanout group ids */
288static void test_unique_fanout_group_ids(void)
289{
290 int fds[3];
291 uint16_t typeflags, first_group_id, second_group_id;
292
293 fprintf(stderr, "test: unique ids\n");
294
295 fds[0] = sock_fanout_open(PACKET_FANOUT_HASH |
296 PACKET_FANOUT_FLAG_UNIQUEID, 0);
297 if (fds[0] == -1) {
298 fprintf(stderr, "ERROR: failed to create a unique id group.\n");
299 exit(1);
300 }
301
302 sock_fanout_getopts(fds[0], &typeflags, &first_group_id);
303 if (typeflags != PACKET_FANOUT_HASH) {
304 fprintf(stderr, "ERROR: unexpected typeflags %x\n", typeflags);
305 exit(1);
306 }
307
308 if (sock_fanout_open(PACKET_FANOUT_CPU, first_group_id) != -1) {
309 fprintf(stderr, "ERROR: joined group with wrong type.\n");
310 exit(1);
311 }
312
313 fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, first_group_id);
314 if (fds[1] == -1) {
315 fprintf(stderr,
316 "ERROR: failed to join previously created group.\n");
317 exit(1);
318 }
319
320 fds[2] = sock_fanout_open(PACKET_FANOUT_HASH |
321 PACKET_FANOUT_FLAG_UNIQUEID, 0);
322 if (fds[2] == -1) {
323 fprintf(stderr,
324 "ERROR: failed to create a second unique id group.\n");
325 exit(1);
326 }
327
328 sock_fanout_getopts(fds[2], &typeflags, &second_group_id);
329 if (sock_fanout_open(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_UNIQUEID,
330 second_group_id) != -1) {
331 fprintf(stderr,
332 "ERROR: specified a group id when requesting unique id\n");
333 exit(1);
334 }
335
336 if (close(fds[0]) || close(fds[1]) || close(fds[2])) {
337 fprintf(stderr, "ERROR: closing sockets\n");
338 exit(1);
339 }
340}
341
256static int test_datapath(uint16_t typeflags, int port_off, 342static int test_datapath(uint16_t typeflags, int port_off,
257 const int expect1[], const int expect2[]) 343 const int expect1[], const int expect2[])
258{ 344{
@@ -263,14 +349,14 @@ static int test_datapath(uint16_t typeflags, int port_off,
263 349
264 fprintf(stderr, "test: datapath 0x%hx\n", typeflags); 350 fprintf(stderr, "test: datapath 0x%hx\n", typeflags);
265 351
266 fds[0] = sock_fanout_open(typeflags, 20); 352 fds[0] = sock_fanout_open(typeflags, 0);
267 fds[1] = sock_fanout_open(typeflags, 20); 353 fds[1] = sock_fanout_open(typeflags, 0);
268 if (fds[0] == -1 || fds[1] == -1) { 354 if (fds[0] == -1 || fds[1] == -1) {
269 fprintf(stderr, "ERROR: failed open\n"); 355 fprintf(stderr, "ERROR: failed open\n");
270 exit(1); 356 exit(1);
271 } 357 }
272 if (type == PACKET_FANOUT_CBPF) 358 if (type == PACKET_FANOUT_CBPF)
273 sock_setfilter(fds[0], SOL_PACKET, PACKET_FANOUT_DATA); 359 sock_fanout_set_cbpf(fds[0]);
274 else if (type == PACKET_FANOUT_EBPF) 360 else if (type == PACKET_FANOUT_EBPF)
275 sock_fanout_set_ebpf(fds[0]); 361 sock_fanout_set_ebpf(fds[0]);
276 362
@@ -331,10 +417,12 @@ int main(int argc, char **argv)
331 const int expect_cpu0[2][2] = { { 20, 0 }, { 20, 0 } }; 417 const int expect_cpu0[2][2] = { { 20, 0 }, { 20, 0 } };
332 const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } }; 418 const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } };
333 const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } }; 419 const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } };
420 const int expect_uniqueid[2][2] = { { 20, 20}, { 20, 20 } };
334 int port_off = 2, tries = 5, ret; 421 int port_off = 2, tries = 5, ret;
335 422
336 test_control_single(); 423 test_control_single();
337 test_control_group(); 424 test_control_group();
425 test_unique_fanout_group_ids();
338 426
339 /* find a set of ports that do not collide onto the same socket */ 427 /* find a set of ports that do not collide onto the same socket */
340 ret = test_datapath(PACKET_FANOUT_HASH, port_off, 428 ret = test_datapath(PACKET_FANOUT_HASH, port_off,
@@ -365,6 +453,9 @@ int main(int argc, char **argv)
365 ret |= test_datapath(PACKET_FANOUT_CPU, port_off, 453 ret |= test_datapath(PACKET_FANOUT_CPU, port_off,
366 expect_cpu1[0], expect_cpu1[1]); 454 expect_cpu1[0], expect_cpu1[1]);
367 455
456 ret |= test_datapath(PACKET_FANOUT_FLAG_UNIQUEID, port_off,
457 expect_uniqueid[0], expect_uniqueid[1]);
458
368 if (ret) 459 if (ret)
369 return 1; 460 return 1;
370 461
diff --git a/tools/testing/selftests/net/psock_lib.h b/tools/testing/selftests/net/psock_lib.h
index a77da88bf946..7d990d6c861b 100644
--- a/tools/testing/selftests/net/psock_lib.h
+++ b/tools/testing/selftests/net/psock_lib.h
@@ -38,7 +38,7 @@
38# define __maybe_unused __attribute__ ((__unused__)) 38# define __maybe_unused __attribute__ ((__unused__))
39#endif 39#endif
40 40
41static __maybe_unused void sock_setfilter(int fd, int lvl, int optnum) 41static __maybe_unused void pair_udp_setfilter(int fd)
42{ 42{
43 /* the filter below checks for all of the following conditions that 43 /* the filter below checks for all of the following conditions that
44 * are based on the contents of create_payload() 44 * are based on the contents of create_payload()
@@ -76,23 +76,16 @@ static __maybe_unused void sock_setfilter(int fd, int lvl, int optnum)
76 }; 76 };
77 struct sock_fprog bpf_prog; 77 struct sock_fprog bpf_prog;
78 78
79 if (lvl == SOL_PACKET && optnum == PACKET_FANOUT_DATA)
80 bpf_filter[5].code = 0x16; /* RET A */
81
82 bpf_prog.filter = bpf_filter; 79 bpf_prog.filter = bpf_filter;
83 bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter); 80 bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter);
84 if (setsockopt(fd, lvl, optnum, &bpf_prog, 81
82 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf_prog,
85 sizeof(bpf_prog))) { 83 sizeof(bpf_prog))) {
86 perror("setsockopt SO_ATTACH_FILTER"); 84 perror("setsockopt SO_ATTACH_FILTER");
87 exit(1); 85 exit(1);
88 } 86 }
89} 87}
90 88
91static __maybe_unused void pair_udp_setfilter(int fd)
92{
93 sock_setfilter(fd, SOL_SOCKET, SO_ATTACH_FILTER);
94}
95
96static __maybe_unused void pair_udp_open(int fds[], uint16_t port) 89static __maybe_unused void pair_udp_open(int fds[], uint16_t port)
97{ 90{
98 struct sockaddr_in saddr, daddr; 91 struct sockaddr_in saddr, daddr;
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 1c5d0575802e..72c3ac2323e1 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -8,12 +8,13 @@ ifeq ($(ARCH),powerpc)
8 8
9GIT_VERSION = $(shell git describe --always --long --dirty || echo "unknown") 9GIT_VERSION = $(shell git describe --always --long --dirty || echo "unknown")
10 10
11CFLAGS := -std=gnu99 -Wall -O2 -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR)/include $(CFLAGS) 11CFLAGS := -std=gnu99 -O2 -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR)/include $(CFLAGS)
12 12
13export CFLAGS 13export CFLAGS
14 14
15SUB_DIRS = alignment \ 15SUB_DIRS = alignment \
16 benchmarks \ 16 benchmarks \
17 cache_shape \
17 copyloops \ 18 copyloops \
18 context_switch \ 19 context_switch \
19 dscr \ 20 dscr \
@@ -34,37 +35,38 @@ endif
34all: $(SUB_DIRS) 35all: $(SUB_DIRS)
35 36
36$(SUB_DIRS): 37$(SUB_DIRS):
37 BUILD_TARGET=$$OUTPUT/$@; mkdir -p $$BUILD_TARGET; $(MAKE) OUTPUT=$$BUILD_TARGET -k -C $@ all 38 BUILD_TARGET=$(OUTPUT)/$@; mkdir -p $$BUILD_TARGET; $(MAKE) OUTPUT=$$BUILD_TARGET -k -C $@ all
38 39
39include ../lib.mk 40include ../lib.mk
40 41
41override define RUN_TESTS 42override define RUN_TESTS
42 @for TARGET in $(SUB_DIRS); do \ 43 @for TARGET in $(SUB_DIRS); do \
43 BUILD_TARGET=$$OUTPUT/$$TARGET; \ 44 BUILD_TARGET=$(OUTPUT)/$$TARGET; \
44 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests;\ 45 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET run_tests;\
45 done; 46 done;
46endef 47endef
47 48
48override define INSTALL_RULE 49override define INSTALL_RULE
49 @for TARGET in $(SUB_DIRS); do \ 50 @for TARGET in $(SUB_DIRS); do \
50 BUILD_TARGET=$$OUTPUT/$$TARGET; \ 51 BUILD_TARGET=$(OUTPUT)/$$TARGET; \
51 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET install;\ 52 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET install;\
52 done; 53 done;
53endef 54endef
54 55
55override define EMIT_TESTS 56override define EMIT_TESTS
56 @for TARGET in $(SUB_DIRS); do \ 57 @for TARGET in $(SUB_DIRS); do \
57 BUILD_TARGET=$$OUTPUT/$$TARGET; \ 58 BUILD_TARGET=$(OUTPUT)/$$TARGET; \
58 $(MAKE) OUTPUT=$$BUILD_TARGET -s -C $$TARGET emit_tests;\ 59 $(MAKE) OUTPUT=$$BUILD_TARGET -s -C $$TARGET emit_tests;\
59 done; 60 done;
60endef 61endef
61 62
62clean: 63override define CLEAN
63 @for TARGET in $(SUB_DIRS); do \ 64 @for TARGET in $(SUB_DIRS); do \
64 BUILD_TARGET=$$OUTPUT/$$TARGET; \ 65 BUILD_TARGET=$(OUTPUT)/$$TARGET; \
65 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET clean; \ 66 $(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET clean; \
66 done; 67 done;
67 rm -f tags 68 rm -f tags
69endef
68 70
69tags: 71tags:
70 find . -name '*.c' -o -name '*.h' | xargs ctags 72 find . -name '*.c' -o -name '*.h' | xargs ctags
diff --git a/tools/testing/selftests/powerpc/cache_shape/.gitignore b/tools/testing/selftests/powerpc/cache_shape/.gitignore
new file mode 100644
index 000000000000..ec1848434be5
--- /dev/null
+++ b/tools/testing/selftests/powerpc/cache_shape/.gitignore
@@ -0,0 +1 @@
cache_shape
diff --git a/tools/testing/selftests/powerpc/cache_shape/Makefile b/tools/testing/selftests/powerpc/cache_shape/Makefile
new file mode 100644
index 000000000000..b24485ab30e2
--- /dev/null
+++ b/tools/testing/selftests/powerpc/cache_shape/Makefile
@@ -0,0 +1,10 @@
1TEST_PROGS := cache_shape
2
3all: $(TEST_PROGS)
4
5$(TEST_PROGS): ../harness.c ../utils.c
6
7include ../../lib.mk
8
9clean:
10 rm -f $(TEST_PROGS) *.o
diff --git a/tools/testing/selftests/powerpc/cache_shape/cache_shape.c b/tools/testing/selftests/powerpc/cache_shape/cache_shape.c
new file mode 100644
index 000000000000..29ec07eba7f9
--- /dev/null
+++ b/tools/testing/selftests/powerpc/cache_shape/cache_shape.c
@@ -0,0 +1,125 @@
1/*
2 * Copyright 2017, Michael Ellerman, IBM Corp.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <elf.h>
11#include <errno.h>
12#include <fcntl.h>
13#include <link.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/stat.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20#include <unistd.h>
21
22#include "utils.h"
23
24#ifndef AT_L1I_CACHESIZE
25#define AT_L1I_CACHESIZE 40
26#define AT_L1I_CACHEGEOMETRY 41
27#define AT_L1D_CACHESIZE 42
28#define AT_L1D_CACHEGEOMETRY 43
29#define AT_L2_CACHESIZE 44
30#define AT_L2_CACHEGEOMETRY 45
31#define AT_L3_CACHESIZE 46
32#define AT_L3_CACHEGEOMETRY 47
33#endif
34
35static void print_size(const char *label, uint32_t val)
36{
37 printf("%s cache size: %#10x %10dB %10dK\n", label, val, val, val / 1024);
38}
39
40static void print_geo(const char *label, uint32_t val)
41{
42 uint16_t assoc;
43
44 printf("%s line size: %#10x ", label, val & 0xFFFF);
45
46 assoc = val >> 16;
47 if (assoc)
48 printf("%u-way", assoc);
49 else
50 printf("fully");
51
52 printf(" associative\n");
53}
54
55static int test_cache_shape()
56{
57 static char buffer[4096];
58 ElfW(auxv_t) *p;
59 int found;
60
61 FAIL_IF(read_auxv(buffer, sizeof(buffer)));
62
63 found = 0;
64
65 p = find_auxv_entry(AT_L1I_CACHESIZE, buffer);
66 if (p) {
67 found++;
68 print_size("L1I ", (uint32_t)p->a_un.a_val);
69 }
70
71 p = find_auxv_entry(AT_L1I_CACHEGEOMETRY, buffer);
72 if (p) {
73 found++;
74 print_geo("L1I ", (uint32_t)p->a_un.a_val);
75 }
76
77 p = find_auxv_entry(AT_L1D_CACHESIZE, buffer);
78 if (p) {
79 found++;
80 print_size("L1D ", (uint32_t)p->a_un.a_val);
81 }
82
83 p = find_auxv_entry(AT_L1D_CACHEGEOMETRY, buffer);
84 if (p) {
85 found++;
86 print_geo("L1D ", (uint32_t)p->a_un.a_val);
87 }
88
89 p = find_auxv_entry(AT_L2_CACHESIZE, buffer);
90 if (p) {
91 found++;
92 print_size("L2 ", (uint32_t)p->a_un.a_val);
93 }
94
95 p = find_auxv_entry(AT_L2_CACHEGEOMETRY, buffer);
96 if (p) {
97 found++;
98 print_geo("L2 ", (uint32_t)p->a_un.a_val);
99 }
100
101 p = find_auxv_entry(AT_L3_CACHESIZE, buffer);
102 if (p) {
103 found++;
104 print_size("L3 ", (uint32_t)p->a_un.a_val);
105 }
106
107 p = find_auxv_entry(AT_L3_CACHEGEOMETRY, buffer);
108 if (p) {
109 found++;
110 print_geo("L3 ", (uint32_t)p->a_un.a_val);
111 }
112
113 /* If we found none we're probably on a system where they don't exist */
114 SKIP_IF(found == 0);
115
116 /* But if we found any, we expect to find them all */
117 FAIL_IF(found != 8);
118
119 return 0;
120}
121
122int main(void)
123{
124 return test_harness(test_cache_shape, "cache_shape");
125}
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h
index 53405e8a52ab..735815b3ad7f 100644
--- a/tools/testing/selftests/powerpc/include/utils.h
+++ b/tools/testing/selftests/powerpc/include/utils.h
@@ -24,7 +24,11 @@ typedef uint8_t u8;
24 24
25void test_harness_set_timeout(uint64_t time); 25void test_harness_set_timeout(uint64_t time);
26int test_harness(int (test_function)(void), char *name); 26int test_harness(int (test_function)(void), char *name);
27extern void *get_auxv_entry(int type); 27
28int read_auxv(char *buf, ssize_t buf_size);
29void *find_auxv_entry(int type, char *auxv);
30void *get_auxv_entry(int type);
31
28int pick_online_cpu(void); 32int pick_online_cpu(void);
29 33
30static inline bool have_hwcap(unsigned long ftr) 34static inline bool have_hwcap(unsigned long ftr)
diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore
index 427621792229..2f1f7b013293 100644
--- a/tools/testing/selftests/powerpc/tm/.gitignore
+++ b/tools/testing/selftests/powerpc/tm/.gitignore
@@ -11,3 +11,4 @@ tm-signal-context-chk-fpu
11tm-signal-context-chk-gpr 11tm-signal-context-chk-gpr
12tm-signal-context-chk-vmx 12tm-signal-context-chk-vmx
13tm-signal-context-chk-vsx 13tm-signal-context-chk-vsx
14tm-vmx-unavail
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
index 5576ee6a51f2..958c11c14acd 100644
--- a/tools/testing/selftests/powerpc/tm/Makefile
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -2,7 +2,8 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu
2 tm-signal-context-chk-vmx tm-signal-context-chk-vsx 2 tm-signal-context-chk-vmx tm-signal-context-chk-vsx
3 3
4TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ 4TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \
5 tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS) 5 tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail \
6 $(SIGNAL_CONTEXT_CHK_TESTS)
6 7
7include ../../lib.mk 8include ../../lib.mk
8 9
@@ -13,6 +14,7 @@ CFLAGS += -mhtm
13$(OUTPUT)/tm-syscall: tm-syscall-asm.S 14$(OUTPUT)/tm-syscall: tm-syscall-asm.S
14$(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include 15$(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include
15$(OUTPUT)/tm-tmspr: CFLAGS += -pthread 16$(OUTPUT)/tm-tmspr: CFLAGS += -pthread
17$(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64
16 18
17SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) 19SIGNAL_CONTEXT_CHK_TESTS := $(patsubst %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS))
18$(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S 20$(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S
diff --git a/tools/testing/selftests/powerpc/tm/tm-vmx-unavail.c b/tools/testing/selftests/powerpc/tm/tm-vmx-unavail.c
new file mode 100644
index 000000000000..137185ba4937
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-vmx-unavail.c
@@ -0,0 +1,118 @@
1/*
2 * Copyright 2017, Michael Neuling, IBM Corp.
3 * Licensed under GPLv2.
4 * Original: Breno Leitao <brenohl@br.ibm.com> &
5 * Gustavo Bueno Romero <gromero@br.ibm.com>
6 * Edited: Michael Neuling
7 *
8 * Force VMX unavailable during a transaction and see if it corrupts
9 * the checkpointed VMX register state after the abort.
10 */
11
12#include <inttypes.h>
13#include <htmintrin.h>
14#include <string.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <pthread.h>
18#include <sys/mman.h>
19#include <unistd.h>
20#include <pthread.h>
21
22#include "tm.h"
23#include "utils.h"
24
25int passed;
26
27void *worker(void *unused)
28{
29 __int128 vmx0;
30 uint64_t texasr;
31
32 asm goto (
33 "li 3, 1;" /* Stick non-zero value in VMX0 */
34 "std 3, 0(%[vmx0_ptr]);"
35 "lvx 0, 0, %[vmx0_ptr];"
36
37 /* Wait here a bit so we get scheduled out 255 times */
38 "lis 3, 0x3fff;"
39 "1: ;"
40 "addi 3, 3, -1;"
41 "cmpdi 3, 0;"
42 "bne 1b;"
43
44 /* Kernel will hopefully turn VMX off now */
45
46 "tbegin. ;"
47 "beq failure;"
48
49 /* Cause VMX unavail. Any VMX instruction */
50 "vaddcuw 0,0,0;"
51
52 "tend. ;"
53 "b %l[success];"
54
55 /* Check VMX0 sanity after abort */
56 "failure: ;"
57 "lvx 1, 0, %[vmx0_ptr];"
58 "vcmpequb. 2, 0, 1;"
59 "bc 4, 24, %l[value_mismatch];"
60 "b %l[value_match];"
61 :
62 : [vmx0_ptr] "r"(&vmx0)
63 : "r3"
64 : success, value_match, value_mismatch
65 );
66
67 /* HTM aborted and VMX0 is corrupted */
68value_mismatch:
69 texasr = __builtin_get_texasr();
70
71 printf("\n\n==============\n\n");
72 printf("Failure with error: %lx\n", _TEXASR_FAILURE_CODE(texasr));
73 printf("Summary error : %lx\n", _TEXASR_FAILURE_SUMMARY(texasr));
74 printf("TFIAR exact : %lx\n\n", _TEXASR_TFIAR_EXACT(texasr));
75
76 passed = 0;
77 return NULL;
78
79 /* HTM aborted but VMX0 is correct */
80value_match:
81// printf("!");
82 return NULL;
83
84success:
85// printf(".");
86 return NULL;
87}
88
89int tm_vmx_unavail_test()
90{
91 int threads;
92 pthread_t *thread;
93
94 SKIP_IF(!have_htm());
95
96 passed = 1;
97
98 threads = sysconf(_SC_NPROCESSORS_ONLN) * 4;
99 thread = malloc(sizeof(pthread_t)*threads);
100 if (!thread)
101 return EXIT_FAILURE;
102
103 for (uint64_t i = 0; i < threads; i++)
104 pthread_create(&thread[i], NULL, &worker, NULL);
105
106 for (uint64_t i = 0; i < threads; i++)
107 pthread_join(thread[i], NULL);
108
109 free(thread);
110
111 return passed ? EXIT_SUCCESS : EXIT_FAILURE;
112}
113
114
115int main(int argc, char **argv)
116{
117 return test_harness(tm_vmx_unavail_test, "tm_vmx_unavail_test");
118}
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
index dcf74184bfd0..d46916867a6f 100644
--- a/tools/testing/selftests/powerpc/utils.c
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -19,45 +19,64 @@
19 19
20static char auxv[4096]; 20static char auxv[4096];
21 21
22void *get_auxv_entry(int type) 22int read_auxv(char *buf, ssize_t buf_size)
23{ 23{
24 ElfW(auxv_t) *p;
25 void *result;
26 ssize_t num; 24 ssize_t num;
27 int fd; 25 int rc, fd;
28 26
29 fd = open("/proc/self/auxv", O_RDONLY); 27 fd = open("/proc/self/auxv", O_RDONLY);
30 if (fd == -1) { 28 if (fd == -1) {
31 perror("open"); 29 perror("open");
32 return NULL; 30 return -errno;
33 } 31 }
34 32
35 result = NULL; 33 num = read(fd, buf, buf_size);
36
37 num = read(fd, auxv, sizeof(auxv));
38 if (num < 0) { 34 if (num < 0) {
39 perror("read"); 35 perror("read");
36 rc = -EIO;
40 goto out; 37 goto out;
41 } 38 }
42 39
43 if (num > sizeof(auxv)) { 40 if (num > buf_size) {
44 printf("Overflowed auxv buffer\n"); 41 printf("overflowed auxv buffer\n");
42 rc = -EOVERFLOW;
45 goto out; 43 goto out;
46 } 44 }
47 45
46 rc = 0;
47out:
48 close(fd);
49 return rc;
50}
51
52void *find_auxv_entry(int type, char *auxv)
53{
54 ElfW(auxv_t) *p;
55
48 p = (ElfW(auxv_t) *)auxv; 56 p = (ElfW(auxv_t) *)auxv;
49 57
50 while (p->a_type != AT_NULL) { 58 while (p->a_type != AT_NULL) {
51 if (p->a_type == type) { 59 if (p->a_type == type)
52 result = (void *)p->a_un.a_val; 60 return p;
53 break;
54 }
55 61
56 p++; 62 p++;
57 } 63 }
58out: 64
59 close(fd); 65 return NULL;
60 return result; 66}
67
68void *get_auxv_entry(int type)
69{
70 ElfW(auxv_t) *p;
71
72 if (read_auxv(auxv, sizeof(auxv)))
73 return NULL;
74
75 p = find_auxv_entry(type, auxv);
76 if (p)
77 return (void *)p->a_un.a_val;
78
79 return NULL;
61} 80}
62 81
63int pick_online_cpu(void) 82int pick_online_cpu(void)
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index ea6e373edc27..93eede4e8fbe 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -170,7 +170,7 @@ qemu_append="`identify_qemu_append "$QEMU"`"
170# Pull in Kconfig-fragment boot parameters 170# Pull in Kconfig-fragment boot parameters
171boot_args="`configfrag_boot_params "$boot_args" "$config_template"`" 171boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
172# Generate kernel-version-specific boot parameters 172# Generate kernel-version-specific boot parameters
173boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`" 173boot_args="`per_version_boot_params "$boot_args" $resdir/.config $seconds`"
174 174
175if test -n "$TORTURE_BUILDONLY" 175if test -n "$TORTURE_BUILDONLY"
176then 176then
diff --git a/tools/testing/selftests/splice/Makefile b/tools/testing/selftests/splice/Makefile
index de51f439d4a6..9fc78e5e5451 100644
--- a/tools/testing/selftests/splice/Makefile
+++ b/tools/testing/selftests/splice/Makefile
@@ -4,5 +4,4 @@ all: $(TEST_PROGS) $(EXTRA)
4 4
5include ../lib.mk 5include ../lib.mk
6 6
7clean: 7EXTRA_CLEAN := $(EXTRA)
8 rm -fr $(TEST_PROGS) $(EXTRA)
diff --git a/tools/testing/selftests/sync/Makefile b/tools/testing/selftests/sync/Makefile
index 87ac400507c0..4981c6b6d050 100644
--- a/tools/testing/selftests/sync/Makefile
+++ b/tools/testing/selftests/sync/Makefile
@@ -20,5 +20,4 @@ TESTS += sync_stress_merge.o
20 20
21sync_test: $(OBJS) $(TESTS) 21sync_test: $(OBJS) $(TESTS)
22 22
23clean: 23EXTRA_CLEAN := sync_test $(OBJS) $(TESTS)
24 $(RM) sync_test $(OBJS) $(TESTS)
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile
index b90e50c36f9f..5fa1d7e9a915 100644
--- a/tools/testing/selftests/timers/Makefile
+++ b/tools/testing/selftests/timers/Makefile
@@ -3,7 +3,7 @@ CFLAGS += -O3 -Wl,-no-as-needed -Wall $(BUILD_FLAGS)
3LDFLAGS += -lrt -lpthread 3LDFLAGS += -lrt -lpthread
4 4
5# these are all "safe" tests that don't modify 5# these are all "safe" tests that don't modify
6# system time or require escalated privledges 6# system time or require escalated privileges
7TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \ 7TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \
8 inconsistency-check raw_skew threadtest rtctest 8 inconsistency-check raw_skew threadtest rtctest
9 9
@@ -14,7 +14,7 @@ TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew
14 14
15include ../lib.mk 15include ../lib.mk
16 16
17# these tests require escalated privledges 17# these tests require escalated privileges
18# and may modify the system time or trigger 18# and may modify the system time or trigger
19# other behavior like suspend 19# other behavior like suspend
20run_destructive_tests: run_tests 20run_destructive_tests: run_tests
diff --git a/tools/testing/selftests/timers/clocksource-switch.c b/tools/testing/selftests/timers/clocksource-switch.c
index fd88e3025bed..5ff165373f8b 100644
--- a/tools/testing/selftests/timers/clocksource-switch.c
+++ b/tools/testing/selftests/timers/clocksource-switch.c
@@ -159,7 +159,7 @@ int main(int argv, char **argc)
159 } 159 }
160 160
161 161
162 printf("Running Asyncrhonous Switching Tests...\n"); 162 printf("Running Asynchronous Switching Tests...\n");
163 pid = fork(); 163 pid = fork();
164 if (!pid) 164 if (!pid)
165 return run_tests(60); 165 return run_tests(60);
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index 41642ba5e318..cbb29e41ef2b 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -15,21 +15,15 @@ TEST_GEN_FILES += on-fault-limit
15TEST_GEN_FILES += thuge-gen 15TEST_GEN_FILES += thuge-gen
16TEST_GEN_FILES += transhuge-stress 16TEST_GEN_FILES += transhuge-stress
17TEST_GEN_FILES += userfaultfd 17TEST_GEN_FILES += userfaultfd
18TEST_GEN_FILES += userfaultfd_hugetlb
19TEST_GEN_FILES += userfaultfd_shmem
20TEST_GEN_FILES += mlock-random-test 18TEST_GEN_FILES += mlock-random-test
19TEST_GEN_FILES += virtual_address_range
21 20
22TEST_PROGS := run_vmtests 21TEST_PROGS := run_vmtests
23 22
24include ../lib.mk 23include ../lib.mk
25 24
26$(OUTPUT)/userfaultfd: LDLIBS += -lpthread ../../../../usr/include/linux/kernel.h 25$(OUTPUT)/userfaultfd: ../../../../usr/include/linux/kernel.h
27 26$(OUTPUT)/userfaultfd: LDLIBS += -lpthread
28$(OUTPUT)/userfaultfd_hugetlb: userfaultfd.c ../../../../usr/include/linux/kernel.h
29 $(CC) $(CFLAGS) -DHUGETLB_TEST -O2 -o $@ $< -lpthread
30
31$(OUTPUT)/userfaultfd_shmem: userfaultfd.c ../../../../usr/include/linux/kernel.h
32 $(CC) $(CFLAGS) -DSHMEM_TEST -O2 -o $@ $< -lpthread
33 27
34$(OUTPUT)/mlock-random-test: LDLIBS += -lcap 28$(OUTPUT)/mlock-random-test: LDLIBS += -lcap
35 29
diff --git a/tools/testing/selftests/vm/config b/tools/testing/selftests/vm/config
index 698c7ed28a26..1c0d76cb5adf 100644
--- a/tools/testing/selftests/vm/config
+++ b/tools/testing/selftests/vm/config
@@ -1 +1,2 @@
1CONFIG_SYSVIPC=y
1CONFIG_USERFAULTFD=y 2CONFIG_USERFAULTFD=y
diff --git a/tools/testing/selftests/vm/map_hugetlb.c b/tools/testing/selftests/vm/map_hugetlb.c
index addcd6fc1ecc..77687ab59f77 100644
--- a/tools/testing/selftests/vm/map_hugetlb.c
+++ b/tools/testing/selftests/vm/map_hugetlb.c
@@ -62,7 +62,7 @@ int main(void)
62 void *addr; 62 void *addr;
63 int ret; 63 int ret;
64 64
65 addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0); 65 addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, -1, 0);
66 if (addr == MAP_FAILED) { 66 if (addr == MAP_FAILED) {
67 perror("mmap"); 67 perror("mmap");
68 exit(1); 68 exit(1);
diff --git a/tools/testing/selftests/vm/mlock2-tests.c b/tools/testing/selftests/vm/mlock2-tests.c
index ff0cda2b19c9..e5dbc87b4297 100644
--- a/tools/testing/selftests/vm/mlock2-tests.c
+++ b/tools/testing/selftests/vm/mlock2-tests.c
@@ -293,7 +293,7 @@ static int test_mlock_lock()
293 unsigned long page_size = getpagesize(); 293 unsigned long page_size = getpagesize();
294 294
295 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, 295 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
296 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 296 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
297 if (map == MAP_FAILED) { 297 if (map == MAP_FAILED) {
298 perror("test_mlock_locked mmap"); 298 perror("test_mlock_locked mmap");
299 goto out; 299 goto out;
@@ -402,7 +402,7 @@ static int test_mlock_onfault()
402 unsigned long page_size = getpagesize(); 402 unsigned long page_size = getpagesize();
403 403
404 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, 404 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
405 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 405 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
406 if (map == MAP_FAILED) { 406 if (map == MAP_FAILED) {
407 perror("test_mlock_locked mmap"); 407 perror("test_mlock_locked mmap");
408 goto out; 408 goto out;
@@ -445,7 +445,7 @@ static int test_lock_onfault_of_present()
445 uint64_t page1_flags, page2_flags; 445 uint64_t page1_flags, page2_flags;
446 446
447 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, 447 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
448 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 448 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
449 if (map == MAP_FAILED) { 449 if (map == MAP_FAILED) {
450 perror("test_mlock_locked mmap"); 450 perror("test_mlock_locked mmap");
451 goto out; 451 goto out;
@@ -492,7 +492,7 @@ static int test_munlockall()
492 unsigned long page_size = getpagesize(); 492 unsigned long page_size = getpagesize();
493 493
494 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, 494 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
495 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 495 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
496 496
497 if (map == MAP_FAILED) { 497 if (map == MAP_FAILED) {
498 perror("test_munlockall mmap"); 498 perror("test_munlockall mmap");
@@ -518,7 +518,7 @@ static int test_munlockall()
518 munmap(map, 2 * page_size); 518 munmap(map, 2 * page_size);
519 519
520 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE, 520 map = mmap(NULL, 2 * page_size, PROT_READ | PROT_WRITE,
521 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 521 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
522 522
523 if (map == MAP_FAILED) { 523 if (map == MAP_FAILED) {
524 perror("test_munlockall second mmap"); 524 perror("test_munlockall second mmap");
@@ -573,7 +573,7 @@ static int test_vma_management(bool call_mlock)
573 struct vm_boundaries page3; 573 struct vm_boundaries page3;
574 574
575 map = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE, 575 map = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE,
576 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 576 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
577 if (map == MAP_FAILED) { 577 if (map == MAP_FAILED) {
578 perror("mmap()"); 578 perror("mmap()");
579 return ret; 579 return ret;
diff --git a/tools/testing/selftests/vm/on-fault-limit.c b/tools/testing/selftests/vm/on-fault-limit.c
index 0ae458f32fdb..7f96a5c2e292 100644
--- a/tools/testing/selftests/vm/on-fault-limit.c
+++ b/tools/testing/selftests/vm/on-fault-limit.c
@@ -26,7 +26,7 @@ static int test_limit(void)
26 } 26 }
27 27
28 map = mmap(NULL, 2 * lims.rlim_max, PROT_READ | PROT_WRITE, 28 map = mmap(NULL, 2 * lims.rlim_max, PROT_READ | PROT_WRITE,
29 MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, 0, 0); 29 MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
30 if (map != MAP_FAILED) 30 if (map != MAP_FAILED)
31 printf("mmap should have failed, but didn't\n"); 31 printf("mmap should have failed, but didn't\n");
32 else { 32 else {
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
index c92f6cf31d0a..07548a1fa901 100755
--- a/tools/testing/selftests/vm/run_vmtests
+++ b/tools/testing/selftests/vm/run_vmtests
@@ -49,9 +49,9 @@ fi
49mkdir $mnt 49mkdir $mnt
50mount -t hugetlbfs none $mnt 50mount -t hugetlbfs none $mnt
51 51
52echo "--------------------" 52echo "---------------------"
53echo "running hugepage-mmap" 53echo "running hugepage-mmap"
54echo "--------------------" 54echo "---------------------"
55./hugepage-mmap 55./hugepage-mmap
56if [ $? -ne 0 ]; then 56if [ $? -ne 0 ]; then
57 echo "[FAIL]" 57 echo "[FAIL]"
@@ -77,9 +77,9 @@ fi
77echo $shmmax > /proc/sys/kernel/shmmax 77echo $shmmax > /proc/sys/kernel/shmmax
78echo $shmall > /proc/sys/kernel/shmall 78echo $shmall > /proc/sys/kernel/shmall
79 79
80echo "--------------------" 80echo "-------------------"
81echo "running map_hugetlb" 81echo "running map_hugetlb"
82echo "--------------------" 82echo "-------------------"
83./map_hugetlb 83./map_hugetlb
84if [ $? -ne 0 ]; then 84if [ $? -ne 0 ]; then
85 echo "[FAIL]" 85 echo "[FAIL]"
@@ -92,10 +92,10 @@ echo "NOTE: The above hugetlb tests provide minimal coverage. Use"
92echo " https://github.com/libhugetlbfs/libhugetlbfs.git for" 92echo " https://github.com/libhugetlbfs/libhugetlbfs.git for"
93echo " hugetlb regression testing." 93echo " hugetlb regression testing."
94 94
95echo "--------------------" 95echo "-------------------"
96echo "running userfaultfd" 96echo "running userfaultfd"
97echo "--------------------" 97echo "-------------------"
98./userfaultfd 128 32 98./userfaultfd anon 128 32
99if [ $? -ne 0 ]; then 99if [ $? -ne 0 ]; then
100 echo "[FAIL]" 100 echo "[FAIL]"
101 exitcode=1 101 exitcode=1
@@ -103,11 +103,11 @@ else
103 echo "[PASS]" 103 echo "[PASS]"
104fi 104fi
105 105
106echo "----------------------------" 106echo "---------------------------"
107echo "running userfaultfd_hugetlb" 107echo "running userfaultfd_hugetlb"
108echo "----------------------------" 108echo "---------------------------"
109# 258MB total huge pages == 128MB src and 128MB dst 109# 256MB total huge pages == 128MB src and 128MB dst
110./userfaultfd_hugetlb 128 32 $mnt/ufd_test_file 110./userfaultfd hugetlb 128 32 $mnt/ufd_test_file
111if [ $? -ne 0 ]; then 111if [ $? -ne 0 ]; then
112 echo "[FAIL]" 112 echo "[FAIL]"
113 exitcode=1 113 exitcode=1
@@ -116,10 +116,10 @@ else
116fi 116fi
117rm -f $mnt/ufd_test_file 117rm -f $mnt/ufd_test_file
118 118
119echo "----------------------------" 119echo "-------------------------"
120echo "running userfaultfd_shmem" 120echo "running userfaultfd_shmem"
121echo "----------------------------" 121echo "-------------------------"
122./userfaultfd_shmem 128 32 122./userfaultfd shmem 128 32
123if [ $? -ne 0 ]; then 123if [ $? -ne 0 ]; then
124 echo "[FAIL]" 124 echo "[FAIL]"
125 exitcode=1 125 exitcode=1
@@ -143,9 +143,9 @@ else
143 echo "[PASS]" 143 echo "[PASS]"
144fi 144fi
145 145
146echo "--------------------" 146echo "----------------------"
147echo "running on-fault-limit" 147echo "running on-fault-limit"
148echo "--------------------" 148echo "----------------------"
149sudo -u nobody ./on-fault-limit 149sudo -u nobody ./on-fault-limit
150if [ $? -ne 0 ]; then 150if [ $? -ne 0 ]; then
151 echo "[FAIL]" 151 echo "[FAIL]"
@@ -165,4 +165,15 @@ else
165 echo "[PASS]" 165 echo "[PASS]"
166fi 166fi
167 167
168echo "-----------------------------"
169echo "running virtual_address_range"
170echo "-----------------------------"
171./virtual_address_range
172if [ $? -ne 0 ]; then
173 echo "[FAIL]"
174 exitcode=1
175else
176 echo "[PASS]"
177fi
178
168exit $exitcode 179exit $exitcode
diff --git a/tools/testing/selftests/vm/thuge-gen.c b/tools/testing/selftests/vm/thuge-gen.c
index 0bc737a75150..88a2ab535e01 100644
--- a/tools/testing/selftests/vm/thuge-gen.c
+++ b/tools/testing/selftests/vm/thuge-gen.c
@@ -146,7 +146,7 @@ void test_mmap(unsigned long size, unsigned flags)
146 146
147 before = read_free(size); 147 before = read_free(size);
148 map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE, 148 map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE,
149 MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, 0, 0); 149 MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, -1, 0);
150 150
151 if (map == (char *)-1) err("mmap"); 151 if (map == (char *)-1) err("mmap");
152 memset(map, 0xff, size*NUM_PAGES); 152 memset(map, 0xff, size*NUM_PAGES);
diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
index e9449c801888..1eae79ae5b4e 100644
--- a/tools/testing/selftests/vm/userfaultfd.c
+++ b/tools/testing/selftests/vm/userfaultfd.c
@@ -77,10 +77,13 @@ static unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size;
77#define BOUNCE_POLL (1<<3) 77#define BOUNCE_POLL (1<<3)
78static int bounces; 78static int bounces;
79 79
80#ifdef HUGETLB_TEST 80#define TEST_ANON 1
81#define TEST_HUGETLB 2
82#define TEST_SHMEM 3
83static int test_type;
84
81static int huge_fd; 85static int huge_fd;
82static char *huge_fd_off0; 86static char *huge_fd_off0;
83#endif
84static unsigned long long *count_verify; 87static unsigned long long *count_verify;
85static int uffd, uffd_flags, finished, *pipefd; 88static int uffd, uffd_flags, finished, *pipefd;
86static char *area_src, *area_dst; 89static char *area_src, *area_dst;
@@ -102,14 +105,7 @@ pthread_attr_t attr;
102 ~(unsigned long)(sizeof(unsigned long long) \ 105 ~(unsigned long)(sizeof(unsigned long long) \
103 - 1))) 106 - 1)))
104 107
105#if !defined(HUGETLB_TEST) && !defined(SHMEM_TEST) 108static int anon_release_pages(char *rel_area)
106
107/* Anonymous memory */
108#define EXPECTED_IOCTLS ((1 << _UFFDIO_WAKE) | \
109 (1 << _UFFDIO_COPY) | \
110 (1 << _UFFDIO_ZEROPAGE))
111
112static int release_pages(char *rel_area)
113{ 109{
114 int ret = 0; 110 int ret = 0;
115 111
@@ -121,7 +117,7 @@ static int release_pages(char *rel_area)
121 return ret; 117 return ret;
122} 118}
123 119
124static void allocate_area(void **alloc_area) 120static void anon_allocate_area(void **alloc_area)
125{ 121{
126 if (posix_memalign(alloc_area, page_size, nr_pages * page_size)) { 122 if (posix_memalign(alloc_area, page_size, nr_pages * page_size)) {
127 fprintf(stderr, "out of memory\n"); 123 fprintf(stderr, "out of memory\n");
@@ -129,14 +125,9 @@ static void allocate_area(void **alloc_area)
129 } 125 }
130} 126}
131 127
132#else /* HUGETLB_TEST or SHMEM_TEST */
133
134#define EXPECTED_IOCTLS UFFD_API_RANGE_IOCTLS_BASIC
135
136#ifdef HUGETLB_TEST
137 128
138/* HugeTLB memory */ 129/* HugeTLB memory */
139static int release_pages(char *rel_area) 130static int hugetlb_release_pages(char *rel_area)
140{ 131{
141 int ret = 0; 132 int ret = 0;
142 133
@@ -152,7 +143,7 @@ static int release_pages(char *rel_area)
152} 143}
153 144
154 145
155static void allocate_area(void **alloc_area) 146static void hugetlb_allocate_area(void **alloc_area)
156{ 147{
157 *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, 148 *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
158 MAP_PRIVATE | MAP_HUGETLB, huge_fd, 149 MAP_PRIVATE | MAP_HUGETLB, huge_fd,
@@ -167,10 +158,8 @@ static void allocate_area(void **alloc_area)
167 huge_fd_off0 = *alloc_area; 158 huge_fd_off0 = *alloc_area;
168} 159}
169 160
170#elif defined(SHMEM_TEST)
171
172/* Shared memory */ 161/* Shared memory */
173static int release_pages(char *rel_area) 162static int shmem_release_pages(char *rel_area)
174{ 163{
175 int ret = 0; 164 int ret = 0;
176 165
@@ -182,7 +171,7 @@ static int release_pages(char *rel_area)
182 return ret; 171 return ret;
183} 172}
184 173
185static void allocate_area(void **alloc_area) 174static void shmem_allocate_area(void **alloc_area)
186{ 175{
187 *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE, 176 *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
188 MAP_ANONYMOUS | MAP_SHARED, -1, 0); 177 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
@@ -192,11 +181,35 @@ static void allocate_area(void **alloc_area)
192 } 181 }
193} 182}
194 183
195#else /* SHMEM_TEST */ 184struct uffd_test_ops {
196#error "Undefined test type" 185 unsigned long expected_ioctls;
197#endif /* HUGETLB_TEST */ 186 void (*allocate_area)(void **alloc_area);
198 187 int (*release_pages)(char *rel_area);
199#endif /* !defined(HUGETLB_TEST) && !defined(SHMEM_TEST) */ 188};
189
190#define ANON_EXPECTED_IOCTLS ((1 << _UFFDIO_WAKE) | \
191 (1 << _UFFDIO_COPY) | \
192 (1 << _UFFDIO_ZEROPAGE))
193
194static struct uffd_test_ops anon_uffd_test_ops = {
195 .expected_ioctls = ANON_EXPECTED_IOCTLS,
196 .allocate_area = anon_allocate_area,
197 .release_pages = anon_release_pages,
198};
199
200static struct uffd_test_ops shmem_uffd_test_ops = {
201 .expected_ioctls = UFFD_API_RANGE_IOCTLS_BASIC,
202 .allocate_area = shmem_allocate_area,
203 .release_pages = shmem_release_pages,
204};
205
206static struct uffd_test_ops hugetlb_uffd_test_ops = {
207 .expected_ioctls = UFFD_API_RANGE_IOCTLS_BASIC,
208 .allocate_area = hugetlb_allocate_area,
209 .release_pages = hugetlb_release_pages,
210};
211
212static struct uffd_test_ops *uffd_test_ops;
200 213
201static int my_bcmp(char *str1, char *str2, size_t n) 214static int my_bcmp(char *str1, char *str2, size_t n)
202{ 215{
@@ -505,7 +518,7 @@ static int stress(unsigned long *userfaults)
505 * UFFDIO_COPY without writing zero pages into area_dst 518 * UFFDIO_COPY without writing zero pages into area_dst
506 * because the background threads already completed). 519 * because the background threads already completed).
507 */ 520 */
508 if (release_pages(area_src)) 521 if (uffd_test_ops->release_pages(area_src))
509 return 1; 522 return 1;
510 523
511 for (cpu = 0; cpu < nr_cpus; cpu++) { 524 for (cpu = 0; cpu < nr_cpus; cpu++) {
@@ -577,12 +590,12 @@ static int faulting_process(void)
577{ 590{
578 unsigned long nr; 591 unsigned long nr;
579 unsigned long long count; 592 unsigned long long count;
593 unsigned long split_nr_pages;
580 594
581#ifndef HUGETLB_TEST 595 if (test_type != TEST_HUGETLB)
582 unsigned long split_nr_pages = (nr_pages + 1) / 2; 596 split_nr_pages = (nr_pages + 1) / 2;
583#else 597 else
584 unsigned long split_nr_pages = nr_pages; 598 split_nr_pages = nr_pages;
585#endif
586 599
587 for (nr = 0; nr < split_nr_pages; nr++) { 600 for (nr = 0; nr < split_nr_pages; nr++) {
588 count = *area_count(area_dst, nr); 601 count = *area_count(area_dst, nr);
@@ -594,7 +607,9 @@ static int faulting_process(void)
594 } 607 }
595 } 608 }
596 609
597#ifndef HUGETLB_TEST 610 if (test_type == TEST_HUGETLB)
611 return 0;
612
598 area_dst = mremap(area_dst, nr_pages * page_size, nr_pages * page_size, 613 area_dst = mremap(area_dst, nr_pages * page_size, nr_pages * page_size,
599 MREMAP_MAYMOVE | MREMAP_FIXED, area_src); 614 MREMAP_MAYMOVE | MREMAP_FIXED, area_src);
600 if (area_dst == MAP_FAILED) 615 if (area_dst == MAP_FAILED)
@@ -610,7 +625,7 @@ static int faulting_process(void)
610 } 625 }
611 } 626 }
612 627
613 if (release_pages(area_dst)) 628 if (uffd_test_ops->release_pages(area_dst))
614 return 1; 629 return 1;
615 630
616 for (nr = 0; nr < nr_pages; nr++) { 631 for (nr = 0; nr < nr_pages; nr++) {
@@ -618,8 +633,6 @@ static int faulting_process(void)
618 fprintf(stderr, "nr %lu is not zero\n", nr), exit(1); 633 fprintf(stderr, "nr %lu is not zero\n", nr), exit(1);
619 } 634 }
620 635
621#endif /* HUGETLB_TEST */
622
623 return 0; 636 return 0;
624} 637}
625 638
@@ -627,7 +640,9 @@ static int uffdio_zeropage(int ufd, unsigned long offset)
627{ 640{
628 struct uffdio_zeropage uffdio_zeropage; 641 struct uffdio_zeropage uffdio_zeropage;
629 int ret; 642 int ret;
630 unsigned long has_zeropage = EXPECTED_IOCTLS & (1 << _UFFDIO_ZEROPAGE); 643 unsigned long has_zeropage;
644
645 has_zeropage = uffd_test_ops->expected_ioctls & (1 << _UFFDIO_ZEROPAGE);
631 646
632 if (offset >= nr_pages * page_size) 647 if (offset >= nr_pages * page_size)
633 fprintf(stderr, "unexpected offset %lu\n", 648 fprintf(stderr, "unexpected offset %lu\n",
@@ -675,7 +690,7 @@ static int userfaultfd_zeropage_test(void)
675 printf("testing UFFDIO_ZEROPAGE: "); 690 printf("testing UFFDIO_ZEROPAGE: ");
676 fflush(stdout); 691 fflush(stdout);
677 692
678 if (release_pages(area_dst)) 693 if (uffd_test_ops->release_pages(area_dst))
679 return 1; 694 return 1;
680 695
681 if (userfaultfd_open(0) < 0) 696 if (userfaultfd_open(0) < 0)
@@ -686,7 +701,7 @@ static int userfaultfd_zeropage_test(void)
686 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) 701 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
687 fprintf(stderr, "register failure\n"), exit(1); 702 fprintf(stderr, "register failure\n"), exit(1);
688 703
689 expected_ioctls = EXPECTED_IOCTLS; 704 expected_ioctls = uffd_test_ops->expected_ioctls;
690 if ((uffdio_register.ioctls & expected_ioctls) != 705 if ((uffdio_register.ioctls & expected_ioctls) !=
691 expected_ioctls) 706 expected_ioctls)
692 fprintf(stderr, 707 fprintf(stderr,
@@ -716,7 +731,7 @@ static int userfaultfd_events_test(void)
716 printf("testing events (fork, remap, remove): "); 731 printf("testing events (fork, remap, remove): ");
717 fflush(stdout); 732 fflush(stdout);
718 733
719 if (release_pages(area_dst)) 734 if (uffd_test_ops->release_pages(area_dst))
720 return 1; 735 return 1;
721 736
722 features = UFFD_FEATURE_EVENT_FORK | UFFD_FEATURE_EVENT_REMAP | 737 features = UFFD_FEATURE_EVENT_FORK | UFFD_FEATURE_EVENT_REMAP |
@@ -731,7 +746,7 @@ static int userfaultfd_events_test(void)
731 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) 746 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
732 fprintf(stderr, "register failure\n"), exit(1); 747 fprintf(stderr, "register failure\n"), exit(1);
733 748
734 expected_ioctls = EXPECTED_IOCTLS; 749 expected_ioctls = uffd_test_ops->expected_ioctls;
735 if ((uffdio_register.ioctls & expected_ioctls) != 750 if ((uffdio_register.ioctls & expected_ioctls) !=
736 expected_ioctls) 751 expected_ioctls)
737 fprintf(stderr, 752 fprintf(stderr,
@@ -773,10 +788,10 @@ static int userfaultfd_stress(void)
773 int err; 788 int err;
774 unsigned long userfaults[nr_cpus]; 789 unsigned long userfaults[nr_cpus];
775 790
776 allocate_area((void **)&area_src); 791 uffd_test_ops->allocate_area((void **)&area_src);
777 if (!area_src) 792 if (!area_src)
778 return 1; 793 return 1;
779 allocate_area((void **)&area_dst); 794 uffd_test_ops->allocate_area((void **)&area_dst);
780 if (!area_dst) 795 if (!area_dst)
781 return 1; 796 return 1;
782 797
@@ -856,7 +871,7 @@ static int userfaultfd_stress(void)
856 fprintf(stderr, "register failure\n"); 871 fprintf(stderr, "register failure\n");
857 return 1; 872 return 1;
858 } 873 }
859 expected_ioctls = EXPECTED_IOCTLS; 874 expected_ioctls = uffd_test_ops->expected_ioctls;
860 if ((uffdio_register.ioctls & expected_ioctls) != 875 if ((uffdio_register.ioctls & expected_ioctls) !=
861 expected_ioctls) { 876 expected_ioctls) {
862 fprintf(stderr, 877 fprintf(stderr,
@@ -888,7 +903,7 @@ static int userfaultfd_stress(void)
888 * MADV_DONTNEED only after the UFFDIO_REGISTER, so it's 903 * MADV_DONTNEED only after the UFFDIO_REGISTER, so it's
889 * required to MADV_DONTNEED here. 904 * required to MADV_DONTNEED here.
890 */ 905 */
891 if (release_pages(area_dst)) 906 if (uffd_test_ops->release_pages(area_dst))
892 return 1; 907 return 1;
893 908
894 /* bounce pass */ 909 /* bounce pass */
@@ -934,36 +949,6 @@ static int userfaultfd_stress(void)
934 return userfaultfd_zeropage_test() || userfaultfd_events_test(); 949 return userfaultfd_zeropage_test() || userfaultfd_events_test();
935} 950}
936 951
937#ifndef HUGETLB_TEST
938
939int main(int argc, char **argv)
940{
941 if (argc < 3)
942 fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1);
943 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
944 page_size = sysconf(_SC_PAGE_SIZE);
945 if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2
946 > page_size)
947 fprintf(stderr, "Impossible to run this test\n"), exit(2);
948 nr_pages_per_cpu = atol(argv[1]) * 1024*1024 / page_size /
949 nr_cpus;
950 if (!nr_pages_per_cpu) {
951 fprintf(stderr, "invalid MiB\n");
952 fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1);
953 }
954 bounces = atoi(argv[2]);
955 if (bounces <= 0) {
956 fprintf(stderr, "invalid bounces\n");
957 fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1);
958 }
959 nr_pages = nr_pages_per_cpu * nr_cpus;
960 printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
961 nr_pages, nr_pages_per_cpu);
962 return userfaultfd_stress();
963}
964
965#else /* HUGETLB_TEST */
966
967/* 952/*
968 * Copied from mlock2-tests.c 953 * Copied from mlock2-tests.c
969 */ 954 */
@@ -988,48 +973,78 @@ unsigned long default_huge_page_size(void)
988 return hps; 973 return hps;
989} 974}
990 975
991int main(int argc, char **argv) 976static void set_test_type(const char *type)
992{ 977{
993 if (argc < 4) 978 if (!strcmp(type, "anon")) {
994 fprintf(stderr, "Usage: <MiB> <bounces> <hugetlbfs_file>\n"), 979 test_type = TEST_ANON;
995 exit(1); 980 uffd_test_ops = &anon_uffd_test_ops;
996 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 981 } else if (!strcmp(type, "hugetlb")) {
997 page_size = default_huge_page_size(); 982 test_type = TEST_HUGETLB;
983 uffd_test_ops = &hugetlb_uffd_test_ops;
984 } else if (!strcmp(type, "shmem")) {
985 test_type = TEST_SHMEM;
986 uffd_test_ops = &shmem_uffd_test_ops;
987 } else {
988 fprintf(stderr, "Unknown test type: %s\n", type), exit(1);
989 }
990
991 if (test_type == TEST_HUGETLB)
992 page_size = default_huge_page_size();
993 else
994 page_size = sysconf(_SC_PAGE_SIZE);
995
998 if (!page_size) 996 if (!page_size)
999 fprintf(stderr, "Unable to determine huge page size\n"), 997 fprintf(stderr, "Unable to determine page size\n"),
1000 exit(2); 998 exit(2);
1001 if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2 999 if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) * 2
1002 > page_size) 1000 > page_size)
1003 fprintf(stderr, "Impossible to run this test\n"), exit(2); 1001 fprintf(stderr, "Impossible to run this test\n"), exit(2);
1004 nr_pages_per_cpu = atol(argv[1]) * 1024*1024 / page_size / 1002}
1003
1004int main(int argc, char **argv)
1005{
1006 if (argc < 4)
1007 fprintf(stderr, "Usage: <test type> <MiB> <bounces> [hugetlbfs_file]\n"),
1008 exit(1);
1009
1010 set_test_type(argv[1]);
1011
1012 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
1013 nr_pages_per_cpu = atol(argv[2]) * 1024*1024 / page_size /
1005 nr_cpus; 1014 nr_cpus;
1006 if (!nr_pages_per_cpu) { 1015 if (!nr_pages_per_cpu) {
1007 fprintf(stderr, "invalid MiB\n"); 1016 fprintf(stderr, "invalid MiB\n");
1008 fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1); 1017 fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1);
1009 } 1018 }
1010 bounces = atoi(argv[2]); 1019
1020 bounces = atoi(argv[3]);
1011 if (bounces <= 0) { 1021 if (bounces <= 0) {
1012 fprintf(stderr, "invalid bounces\n"); 1022 fprintf(stderr, "invalid bounces\n");
1013 fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1); 1023 fprintf(stderr, "Usage: <MiB> <bounces>\n"), exit(1);
1014 } 1024 }
1015 nr_pages = nr_pages_per_cpu * nr_cpus; 1025 nr_pages = nr_pages_per_cpu * nr_cpus;
1016 huge_fd = open(argv[3], O_CREAT | O_RDWR, 0755); 1026
1017 if (huge_fd < 0) { 1027 if (test_type == TEST_HUGETLB) {
1018 fprintf(stderr, "Open of %s failed", argv[3]); 1028 if (argc < 5)
1019 perror("open"); 1029 fprintf(stderr, "Usage: hugetlb <MiB> <bounces> <hugetlbfs_file>\n"),
1020 exit(1); 1030 exit(1);
1021 } 1031 huge_fd = open(argv[4], O_CREAT | O_RDWR, 0755);
1022 if (ftruncate(huge_fd, 0)) { 1032 if (huge_fd < 0) {
1023 fprintf(stderr, "ftruncate %s to size 0 failed", argv[3]); 1033 fprintf(stderr, "Open of %s failed", argv[3]);
1024 perror("ftruncate"); 1034 perror("open");
1025 exit(1); 1035 exit(1);
1036 }
1037 if (ftruncate(huge_fd, 0)) {
1038 fprintf(stderr, "ftruncate %s to size 0 failed", argv[3]);
1039 perror("ftruncate");
1040 exit(1);
1041 }
1026 } 1042 }
1027 printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n", 1043 printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
1028 nr_pages, nr_pages_per_cpu); 1044 nr_pages, nr_pages_per_cpu);
1029 return userfaultfd_stress(); 1045 return userfaultfd_stress();
1030} 1046}
1031 1047
1032#endif
1033#else /* __NR_userfaultfd */ 1048#else /* __NR_userfaultfd */
1034 1049
1035#warning "missing __NR_userfaultfd definition" 1050#warning "missing __NR_userfaultfd definition"
diff --git a/tools/testing/selftests/vm/virtual_address_range.c b/tools/testing/selftests/vm/virtual_address_range.c
new file mode 100644
index 000000000000..3b02aa6eb9da
--- /dev/null
+++ b/tools/testing/selftests/vm/virtual_address_range.c
@@ -0,0 +1,122 @@
1/*
2 * Copyright 2017, Anshuman Khandual, IBM Corp.
3 * Licensed under GPLv2.
4 *
5 * Works on architectures which support 128TB virtual
6 * address range and beyond.
7 */
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12#include <errno.h>
13#include <numaif.h>
14#include <sys/mman.h>
15#include <sys/time.h>
16
17/*
18 * Maximum address range mapped with a single mmap()
19 * call is little bit more than 16GB. Hence 16GB is
20 * chosen as the single chunk size for address space
21 * mapping.
22 */
23#define MAP_CHUNK_SIZE 17179869184UL /* 16GB */
24
25/*
26 * Address space till 128TB is mapped without any hint
27 * and is enabled by default. Address space beyond 128TB
28 * till 512TB is obtained by passing hint address as the
29 * first argument into mmap() system call.
30 *
31 * The process heap address space is divided into two
32 * different areas one below 128TB and one above 128TB
33 * till it reaches 512TB. One with size 128TB and the
34 * other being 384TB.
35 */
36#define NR_CHUNKS_128TB 8192UL /* Number of 16GB chunks for 128TB */
37#define NR_CHUNKS_384TB 24576UL /* Number of 16GB chunks for 384TB */
38
39#define ADDR_MARK_128TB (1UL << 47) /* First address beyond 128TB */
40
41static char *hind_addr(void)
42{
43 int bits = 48 + rand() % 15;
44
45 return (char *) (1UL << bits);
46}
47
48static int validate_addr(char *ptr, int high_addr)
49{
50 unsigned long addr = (unsigned long) ptr;
51
52 if (high_addr) {
53 if (addr < ADDR_MARK_128TB) {
54 printf("Bad address %lx\n", addr);
55 return 1;
56 }
57 return 0;
58 }
59
60 if (addr > ADDR_MARK_128TB) {
61 printf("Bad address %lx\n", addr);
62 return 1;
63 }
64 return 0;
65}
66
67static int validate_lower_address_hint(void)
68{
69 char *ptr;
70
71 ptr = mmap((void *) (1UL << 45), MAP_CHUNK_SIZE, PROT_READ |
72 PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
73
74 if (ptr == MAP_FAILED)
75 return 0;
76
77 return 1;
78}
79
80int main(int argc, char *argv[])
81{
82 char *ptr[NR_CHUNKS_128TB];
83 char *hptr[NR_CHUNKS_384TB];
84 char *hint;
85 unsigned long i, lchunks, hchunks;
86
87 for (i = 0; i < NR_CHUNKS_128TB; i++) {
88 ptr[i] = mmap(NULL, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
89 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
90
91 if (ptr[i] == MAP_FAILED) {
92 if (validate_lower_address_hint())
93 return 1;
94 break;
95 }
96
97 if (validate_addr(ptr[i], 0))
98 return 1;
99 }
100 lchunks = i;
101
102 for (i = 0; i < NR_CHUNKS_384TB; i++) {
103 hint = hind_addr();
104 hptr[i] = mmap(hint, MAP_CHUNK_SIZE, PROT_READ | PROT_WRITE,
105 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
106
107 if (hptr[i] == MAP_FAILED)
108 break;
109
110 if (validate_addr(hptr[i], 1))
111 return 1;
112 }
113 hchunks = i;
114
115 for (i = 0; i < lchunks; i++)
116 munmap(ptr[i], MAP_CHUNK_SIZE);
117
118 for (i = 0; i < hchunks; i++)
119 munmap(hptr[i], MAP_CHUNK_SIZE);
120
121 return 0;
122}
diff --git a/tools/testing/selftests/watchdog/watchdog-test.c b/tools/testing/selftests/watchdog/watchdog-test.c
index 6983d05097e2..a74c9d739d07 100644
--- a/tools/testing/selftests/watchdog/watchdog-test.c
+++ b/tools/testing/selftests/watchdog/watchdog-test.c
@@ -24,9 +24,11 @@ const char v = 'V';
24static void keep_alive(void) 24static void keep_alive(void)
25{ 25{
26 int dummy; 26 int dummy;
27 int ret;
27 28
28 printf("."); 29 ret = ioctl(fd, WDIOC_KEEPALIVE, &dummy);
29 ioctl(fd, WDIOC_KEEPALIVE, &dummy); 30 if (!ret)
31 printf(".");
30} 32}
31 33
32/* 34/*
@@ -51,6 +53,7 @@ int main(int argc, char *argv[])
51 int flags; 53 int flags;
52 unsigned int ping_rate = 1; 54 unsigned int ping_rate = 1;
53 int ret; 55 int ret;
56 int i;
54 57
55 setbuf(stdout, NULL); 58 setbuf(stdout, NULL);
56 59
@@ -61,31 +64,35 @@ int main(int argc, char *argv[])
61 exit(-1); 64 exit(-1);
62 } 65 }
63 66
64 if (argc > 1) { 67 for (i = 1; i < argc; i++) {
65 if (!strncasecmp(argv[1], "-d", 2)) { 68 if (!strncasecmp(argv[i], "-d", 2)) {
66 flags = WDIOS_DISABLECARD; 69 flags = WDIOS_DISABLECARD;
67 ioctl(fd, WDIOC_SETOPTIONS, &flags); 70 ret = ioctl(fd, WDIOC_SETOPTIONS, &flags);
68 printf("Watchdog card disabled.\n"); 71 if (!ret)
69 goto end; 72 printf("Watchdog card disabled.\n");
70 } else if (!strncasecmp(argv[1], "-e", 2)) { 73 } else if (!strncasecmp(argv[i], "-e", 2)) {
71 flags = WDIOS_ENABLECARD; 74 flags = WDIOS_ENABLECARD;
72 ioctl(fd, WDIOC_SETOPTIONS, &flags); 75 ret = ioctl(fd, WDIOC_SETOPTIONS, &flags);
73 printf("Watchdog card enabled.\n"); 76 if (!ret)
74 goto end; 77 printf("Watchdog card enabled.\n");
75 } else if (!strncasecmp(argv[1], "-t", 2) && argv[2]) { 78 } else if (!strncasecmp(argv[i], "-t", 2) && argv[2]) {
76 flags = atoi(argv[2]); 79 flags = atoi(argv[i + 1]);
77 ioctl(fd, WDIOC_SETTIMEOUT, &flags); 80 ret = ioctl(fd, WDIOC_SETTIMEOUT, &flags);
78 printf("Watchdog timeout set to %u seconds.\n", flags); 81 if (!ret)
79 goto end; 82 printf("Watchdog timeout set to %u seconds.\n", flags);
80 } else if (!strncasecmp(argv[1], "-p", 2) && argv[2]) { 83 i++;
81 ping_rate = strtoul(argv[2], NULL, 0); 84 } else if (!strncasecmp(argv[i], "-p", 2) && argv[2]) {
82 printf("Watchdog ping rate set to %u seconds.\n", ping_rate); 85 ping_rate = strtoul(argv[i + 1], NULL, 0);
83 } else { 86 printf("Watchdog ping rate set to %u seconds.\n", ping_rate);
84 printf("-d to disable, -e to enable, -t <n> to set " \ 87 i++;
85 "the timeout,\n-p <n> to set the ping rate, and \n"); 88 } else {
86 printf("run by itself to tick the card.\n"); 89 printf("-d to disable, -e to enable, -t <n> to set "
87 goto end; 90 "the timeout,\n-p <n> to set the ping rate, and ");
88 } 91 printf("run by itself to tick the card.\n");
92 printf("Parameters are parsed left-to-right in real-time.\n");
93 printf("Example: %s -d -t 10 -p 5 -e\n", argv[0]);
94 goto end;
95 }
89 } 96 }
90 97
91 printf("Watchdog Ticking Away!\n"); 98 printf("Watchdog Ticking Away!\n");
diff --git a/tools/testing/selftests/x86/.gitignore b/tools/testing/selftests/x86/.gitignore
index 15034fef9698..7757f73ff9a3 100644
--- a/tools/testing/selftests/x86/.gitignore
+++ b/tools/testing/selftests/x86/.gitignore
@@ -1,2 +1,15 @@
1*_32 1*_32
2*_64 2*_64
3single_step_syscall
4sysret_ss_attrs
5syscall_nt
6ptrace_syscall
7test_mremap_vdso
8check_initial_reg_state
9sigreturn
10ldt_gdt
11iopl
12mpx-mini-test
13ioperm
14protection_keys
15test_vdso
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index 38e0a9ca5d71..97f187e2663f 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -40,8 +40,7 @@ all_32: $(BINARIES_32)
40 40
41all_64: $(BINARIES_64) 41all_64: $(BINARIES_64)
42 42
43clean: 43EXTRA_CLEAN := $(BINARIES_32) $(BINARIES_64)
44 $(RM) $(BINARIES_32) $(BINARIES_64)
45 44
46$(BINARIES_32): $(OUTPUT)/%_32: %.c 45$(BINARIES_32): $(OUTPUT)/%_32: %.c
47 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm 46 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm
diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
index f6121612e769..b9a22f18566a 100644
--- a/tools/testing/selftests/x86/ldt_gdt.c
+++ b/tools/testing/selftests/x86/ldt_gdt.c
@@ -409,6 +409,51 @@ static void *threadproc(void *ctx)
409 } 409 }
410} 410}
411 411
412#ifdef __i386__
413
414#ifndef SA_RESTORE
415#define SA_RESTORER 0x04000000
416#endif
417
418/*
419 * The UAPI header calls this 'struct sigaction', which conflicts with
420 * glibc. Sigh.
421 */
422struct fake_ksigaction {
423 void *handler; /* the real type is nasty */
424 unsigned long sa_flags;
425 void (*sa_restorer)(void);
426 unsigned char sigset[8];
427};
428
429static void fix_sa_restorer(int sig)
430{
431 struct fake_ksigaction ksa;
432
433 if (syscall(SYS_rt_sigaction, sig, NULL, &ksa, 8) == 0) {
434 /*
435 * glibc has a nasty bug: it sometimes writes garbage to
436 * sa_restorer. This interacts quite badly with anything
437 * that fiddles with SS because it can trigger legacy
438 * stack switching. Patch it up. See:
439 *
440 * https://sourceware.org/bugzilla/show_bug.cgi?id=21269
441 */
442 if (!(ksa.sa_flags & SA_RESTORER) && ksa.sa_restorer) {
443 ksa.sa_restorer = NULL;
444 if (syscall(SYS_rt_sigaction, sig, &ksa, NULL,
445 sizeof(ksa.sigset)) != 0)
446 err(1, "rt_sigaction");
447 }
448 }
449}
450#else
451static void fix_sa_restorer(int sig)
452{
453 /* 64-bit glibc works fine. */
454}
455#endif
456
412static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 457static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
413 int flags) 458 int flags)
414{ 459{
@@ -420,6 +465,7 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
420 if (sigaction(sig, &sa, 0)) 465 if (sigaction(sig, &sa, 0))
421 err(1, "sigaction"); 466 err(1, "sigaction");
422 467
468 fix_sa_restorer(sig);
423} 469}
424 470
425static jmp_buf jmpbuf; 471static jmp_buf jmpbuf;
diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c
index 616ee9673339..a8df159a8924 100644
--- a/tools/testing/selftests/x86/mpx-mini-test.c
+++ b/tools/testing/selftests/x86/mpx-mini-test.c
@@ -404,8 +404,6 @@ void handler(int signum, siginfo_t *si, void *vucontext)
404 dprintf2("info->si_lower: %p\n", __si_bounds_lower(si)); 404 dprintf2("info->si_lower: %p\n", __si_bounds_lower(si));
405 dprintf2("info->si_upper: %p\n", __si_bounds_upper(si)); 405 dprintf2("info->si_upper: %p\n", __si_bounds_upper(si));
406 406
407 check_siginfo_vs_shadow(si);
408
409 for (i = 0; i < 8; i++) 407 for (i = 0; i < 8; i++)
410 dprintf3("[%d]: %p\n", i, si_addr_ptr[i]); 408 dprintf3("[%d]: %p\n", i, si_addr_ptr[i]);
411 switch (br_reason) { 409 switch (br_reason) {
@@ -416,6 +414,9 @@ void handler(int signum, siginfo_t *si, void *vucontext)
416 exit(5); 414 exit(5);
417 case 1: /* #BR MPX bounds exception */ 415 case 1: /* #BR MPX bounds exception */
418 /* these are normal and we expect to see them */ 416 /* these are normal and we expect to see them */
417
418 check_siginfo_vs_shadow(si);
419
419 dprintf1("bounds exception (normal): status 0x%jx at %p si_addr: %p\n", 420 dprintf1("bounds exception (normal): status 0x%jx at %p si_addr: %p\n",
420 status, (void *)ip, si->si_addr); 421 status, (void *)ip, si->si_addr);
421 num_bnd_chk++; 422 num_bnd_chk++;
diff --git a/tools/usb/.gitignore b/tools/usb/.gitignore
new file mode 100644
index 000000000000..1b7448981435
--- /dev/null
+++ b/tools/usb/.gitignore
@@ -0,0 +1,2 @@
1ffs-test
2testusb
diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README
index 5eb2b6c7722b..7844490fc603 100644
--- a/tools/usb/usbip/README
+++ b/tools/usb/usbip/README
@@ -244,7 +244,7 @@ Detach the imported device:
244 - See 'Debug Tips' on the project wiki. 244 - See 'Debug Tips' on the project wiki.
245 - http://usbip.wiki.sourceforge.net/how-to-debug-usbip 245 - http://usbip.wiki.sourceforge.net/how-to-debug-usbip
246 - usbip-host.ko must be bound to the target device. 246 - usbip-host.ko must be bound to the target device.
247 - See /proc/bus/usb/devices and find "Driver=..." lines of the device. 247 - See /sys/kernel/debug/usb/devices and find "Driver=..." lines of the device.
248 - Target USB gadget must be bound to vudc 248 - Target USB gadget must be bound to vudc
249 (using USB gadget susbsys, not usbip bind command) 249 (using USB gadget susbsys, not usbip bind command)
250 - Shutdown firewall. 250 - Shutdown firewall.
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
index ac73710473de..1517a232ab18 100644
--- a/tools/usb/usbip/libsrc/usbip_common.c
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -215,9 +215,16 @@ int read_usb_interface(struct usbip_usb_device *udev, int i,
215 struct usbip_usb_interface *uinf) 215 struct usbip_usb_interface *uinf)
216{ 216{
217 char busid[SYSFS_BUS_ID_SIZE]; 217 char busid[SYSFS_BUS_ID_SIZE];
218 int size;
218 struct udev_device *sif; 219 struct udev_device *sif;
219 220
220 sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); 221 size = snprintf(busid, sizeof(busid), "%s:%d.%d",
222 udev->busid, udev->bConfigurationValue, i);
223 if (size < 0 || (unsigned int)size >= sizeof(busid)) {
224 err("busid length %i >= %lu or < 0", size,
225 (long unsigned)sizeof(busid));
226 return -1;
227 }
221 228
222 sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); 229 sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
223 if (!sif) { 230 if (!sif) {
diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c
index 9d415228883d..6ff7b601f854 100644
--- a/tools/usb/usbip/libsrc/usbip_host_common.c
+++ b/tools/usb/usbip/libsrc/usbip_host_common.c
@@ -40,13 +40,20 @@ struct udev *udev_context;
40static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) 40static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
41{ 41{
42 char status_attr_path[SYSFS_PATH_MAX]; 42 char status_attr_path[SYSFS_PATH_MAX];
43 int size;
43 int fd; 44 int fd;
44 int length; 45 int length;
45 char status; 46 char status;
46 int value = 0; 47 int value = 0;
47 48
48 snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", 49 size = snprintf(status_attr_path, sizeof(status_attr_path),
49 udev->path); 50 "%s/usbip_status", udev->path);
51 if (size < 0 || (unsigned int)size >= sizeof(status_attr_path)) {
52 err("usbip_status path length %i >= %lu or < 0", size,
53 (long unsigned)sizeof(status_attr_path));
54 return -1;
55 }
56
50 57
51 fd = open(status_attr_path, O_RDONLY); 58 fd = open(status_attr_path, O_RDONLY);
52 if (fd < 0) { 59 if (fd < 0) {
@@ -218,6 +225,7 @@ int usbip_export_device(struct usbip_exported_device *edev, int sockfd)
218{ 225{
219 char attr_name[] = "usbip_sockfd"; 226 char attr_name[] = "usbip_sockfd";
220 char sockfd_attr_path[SYSFS_PATH_MAX]; 227 char sockfd_attr_path[SYSFS_PATH_MAX];
228 int size;
221 char sockfd_buff[30]; 229 char sockfd_buff[30];
222 int ret; 230 int ret;
223 231
@@ -237,10 +245,20 @@ int usbip_export_device(struct usbip_exported_device *edev, int sockfd)
237 } 245 }
238 246
239 /* only the first interface is true */ 247 /* only the first interface is true */
240 snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", 248 size = snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
241 edev->udev.path, attr_name); 249 edev->udev.path, attr_name);
250 if (size < 0 || (unsigned int)size >= sizeof(sockfd_attr_path)) {
251 err("exported device path length %i >= %lu or < 0", size,
252 (long unsigned)sizeof(sockfd_attr_path));
253 return -1;
254 }
242 255
243 snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); 256 size = snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
257 if (size < 0 || (unsigned int)size >= sizeof(sockfd_buff)) {
258 err("socket length %i >= %lu or < 0", size,
259 (long unsigned)sizeof(sockfd_buff));
260 return -1;
261 }
244 262
245 ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, 263 ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
246 strlen(sockfd_buff)); 264 strlen(sockfd_buff));
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index ad9204773533..f659c146cdc8 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -123,33 +123,15 @@ static int refresh_imported_device_list(void)
123 123
124static int get_nports(void) 124static int get_nports(void)
125{ 125{
126 char *c; 126 const char *attr_nports;
127 int nports = 0;
128 const char *attr_status;
129 127
130 attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, 128 attr_nports = udev_device_get_sysattr_value(vhci_driver->hc_device, "nports");
131 "status"); 129 if (!attr_nports) {
132 if (!attr_status) { 130 err("udev_device_get_sysattr_value nports failed");
133 err("udev_device_get_sysattr_value failed");
134 return -1; 131 return -1;
135 } 132 }
136 133
137 /* skip a header line */ 134 return (int)strtoul(attr_nports, NULL, 10);
138 c = strchr(attr_status, '\n');
139 if (!c)
140 return 0;
141 c++;
142
143 while (*c != '\0') {
144 /* go to the next line */
145 c = strchr(c, '\n');
146 if (!c)
147 return nports;
148 c++;
149 nports += 1;
150 }
151
152 return nports;
153} 135}
154 136
155/* 137/*
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
index d7599d943529..73d8eee8130b 100644
--- a/tools/usb/usbip/src/usbip.c
+++ b/tools/usb/usbip/src/usbip.c
@@ -176,6 +176,8 @@ int main(int argc, char *argv[])
176 break; 176 break;
177 case '?': 177 case '?':
178 printf("usbip: invalid option\n"); 178 printf("usbip: invalid option\n");
179 /* Terminate after printing error */
180 /* FALLTHRU */
179 default: 181 default:
180 usbip_usage(); 182 usbip_usage();
181 goto out; 183 goto out;
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index 9377c8b4ac16..d8f534025b7f 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -57,6 +57,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
57 unsigned int vring_align, 57 unsigned int vring_align,
58 struct virtio_device *vdev, 58 struct virtio_device *vdev,
59 bool weak_barriers, 59 bool weak_barriers,
60 bool ctx,
60 void *pages, 61 void *pages,
61 bool (*notify)(struct virtqueue *vq), 62 bool (*notify)(struct virtqueue *vq),
62 void (*callback)(struct virtqueue *vq), 63 void (*callback)(struct virtqueue *vq),
diff --git a/tools/virtio/ringtest/main.c b/tools/virtio/ringtest/main.c
index f31353fac541..453ca3c21193 100644
--- a/tools/virtio/ringtest/main.c
+++ b/tools/virtio/ringtest/main.c
@@ -20,6 +20,7 @@
20int runcycles = 10000000; 20int runcycles = 10000000;
21int max_outstanding = INT_MAX; 21int max_outstanding = INT_MAX;
22int batch = 1; 22int batch = 1;
23int param = 0;
23 24
24bool do_sleep = false; 25bool do_sleep = false;
25bool do_relax = false; 26bool do_relax = false;
@@ -86,7 +87,7 @@ void set_affinity(const char *arg)
86 cpu = strtol(arg, &endptr, 0); 87 cpu = strtol(arg, &endptr, 0);
87 assert(!*endptr); 88 assert(!*endptr);
88 89
89 assert(cpu >= 0 || cpu < CPU_SETSIZE); 90 assert(cpu >= 0 && cpu < CPU_SETSIZE);
90 91
91 self = pthread_self(); 92 self = pthread_self();
92 CPU_ZERO(&cpuset); 93 CPU_ZERO(&cpuset);
@@ -247,6 +248,11 @@ static const struct option longopts[] = {
247 .val = 'b', 248 .val = 'b',
248 }, 249 },
249 { 250 {
251 .name = "param",
252 .has_arg = required_argument,
253 .val = 'p',
254 },
255 {
250 .name = "sleep", 256 .name = "sleep",
251 .has_arg = no_argument, 257 .has_arg = no_argument,
252 .val = 's', 258 .val = 's',
@@ -274,6 +280,7 @@ static void help(void)
274 " [--run-cycles C (default: %d)]" 280 " [--run-cycles C (default: %d)]"
275 " [--batch b]" 281 " [--batch b]"
276 " [--outstanding o]" 282 " [--outstanding o]"
283 " [--param p]"
277 " [--sleep]" 284 " [--sleep]"
278 " [--relax]" 285 " [--relax]"
279 " [--exit]" 286 " [--exit]"
@@ -328,6 +335,12 @@ int main(int argc, char **argv)
328 assert(c > 0 && c < INT_MAX); 335 assert(c > 0 && c < INT_MAX);
329 max_outstanding = c; 336 max_outstanding = c;
330 break; 337 break;
338 case 'p':
339 c = strtol(optarg, &endptr, 0);
340 assert(!*endptr);
341 assert(c > 0 && c < INT_MAX);
342 param = c;
343 break;
331 case 'b': 344 case 'b':
332 c = strtol(optarg, &endptr, 0); 345 c = strtol(optarg, &endptr, 0);
333 assert(!*endptr); 346 assert(!*endptr);
diff --git a/tools/virtio/ringtest/main.h b/tools/virtio/ringtest/main.h
index 14142faf040b..90b0133004e1 100644
--- a/tools/virtio/ringtest/main.h
+++ b/tools/virtio/ringtest/main.h
@@ -10,6 +10,8 @@
10 10
11#include <stdbool.h> 11#include <stdbool.h>
12 12
13extern int param;
14
13extern bool do_exit; 15extern bool do_exit;
14 16
15#if defined(__x86_64__) || defined(__i386__) 17#if defined(__x86_64__) || defined(__i386__)
diff --git a/tools/virtio/ringtest/ptr_ring.c b/tools/virtio/ringtest/ptr_ring.c
index 635b07b4fdd3..7b22f1b20652 100644
--- a/tools/virtio/ringtest/ptr_ring.c
+++ b/tools/virtio/ringtest/ptr_ring.c
@@ -97,6 +97,9 @@ void alloc_ring(void)
97{ 97{
98 int ret = ptr_ring_init(&array, ring_size, 0); 98 int ret = ptr_ring_init(&array, ring_size, 0);
99 assert(!ret); 99 assert(!ret);
100 /* Hacky way to poke at ring internals. Useful for testing though. */
101 if (param)
102 array.batch = param;
100} 103}
101 104
102/* guest side */ 105/* guest side */
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index e0445898f08f..0fecaec90d0d 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -100,7 +100,7 @@ static void vq_info_add(struct vdev_info *dev, int num)
100 vring_init(&info->vring, num, info->ring, 4096); 100 vring_init(&info->vring, num, info->ring, 4096);
101 info->vq = vring_new_virtqueue(info->idx, 101 info->vq = vring_new_virtqueue(info->idx,
102 info->vring.num, 4096, &dev->vdev, 102 info->vring.num, 4096, &dev->vdev,
103 true, info->ring, 103 true, false, info->ring,
104 vq_notify, vq_callback, "test"); 104 vq_notify, vq_callback, "test");
105 assert(info->vq); 105 assert(info->vq);
106 info->vq->priv = info; 106 info->vq->priv = info;
@@ -202,7 +202,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
202 test = 0; 202 test = 0;
203 r = ioctl(dev->control, VHOST_TEST_RUN, &test); 203 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
204 assert(r >= 0); 204 assert(r >= 0);
205 fprintf(stderr, "spurious wakeus: 0x%llx\n", spurious); 205 fprintf(stderr, "spurious wakeups: 0x%llx\n", spurious);
206} 206}
207 207
208const char optstring[] = "h"; 208const char optstring[] = "h";
diff --git a/tools/virtio/vringh_test.c b/tools/virtio/vringh_test.c
index 5f94f5105678..9476c616d064 100644
--- a/tools/virtio/vringh_test.c
+++ b/tools/virtio/vringh_test.c
@@ -314,7 +314,8 @@ static int parallel_test(u64 features,
314 err(1, "Could not set affinity to cpu %u", first_cpu); 314 err(1, "Could not set affinity to cpu %u", first_cpu);
315 315
316 vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &gvdev.vdev, true, 316 vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &gvdev.vdev, true,
317 guest_map, fast_vringh ? no_notify_host 317 false, guest_map,
318 fast_vringh ? no_notify_host
318 : parallel_notify_host, 319 : parallel_notify_host,
319 never_callback_guest, "guest vq"); 320 never_callback_guest, "guest vq");
320 321
@@ -479,7 +480,7 @@ int main(int argc, char *argv[])
479 memset(__user_addr_min, 0, vring_size(RINGSIZE, ALIGN)); 480 memset(__user_addr_min, 0, vring_size(RINGSIZE, ALIGN));
480 481
481 /* Set up guest side. */ 482 /* Set up guest side. */
482 vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true, 483 vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true, false,
483 __user_addr_min, 484 __user_addr_min,
484 never_notify_host, never_callback_guest, 485 never_notify_host, never_callback_guest,
485 "guest vq"); 486 "guest vq");
@@ -663,7 +664,7 @@ int main(int argc, char *argv[])
663 /* Force creation of direct, which we modify. */ 664 /* Force creation of direct, which we modify. */
664 __virtio_clear_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC); 665 __virtio_clear_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC);
665 vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true, 666 vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true,
666 __user_addr_min, 667 false, __user_addr_min,
667 never_notify_host, 668 never_notify_host,
668 never_callback_guest, 669 never_callback_guest,
669 "guest vq"); 670 "guest vq");