aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /tools
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile77
-rw-r--r--tools/firewire/nosy-dump.c4
-rwxr-xr-xtools/hv/hv_get_dhcp_info.sh28
-rwxr-xr-xtools/hv/hv_get_dns_info.sh13
-rw-r--r--tools/hv/hv_kvp_daemon.c1696
-rwxr-xr-xtools/hv/hv_set_ifconfig.sh68
-rw-r--r--tools/include/tools/be_byteshift.h70
-rw-r--r--tools/include/tools/le_byteshift.h70
-rw-r--r--tools/lguest/Makefile8
-rw-r--r--tools/lguest/extract58
-rw-r--r--tools/lguest/lguest.c2052
-rw-r--r--tools/lguest/lguest.txt129
-rw-r--r--tools/lib/traceevent/Makefile319
-rw-r--r--tools/lib/traceevent/event-parse.c5617
-rw-r--r--tools/lib/traceevent/event-parse.h845
-rw-r--r--tools/lib/traceevent/event-utils.h86
-rw-r--r--tools/lib/traceevent/parse-filter.c2304
-rw-r--r--tools/lib/traceevent/parse-utils.c110
-rw-r--r--tools/lib/traceevent/trace-seq.c200
-rwxr-xr-xtools/nfsd/inject_fault.sh49
-rw-r--r--tools/perf/Documentation/Makefile121
-rw-r--r--tools/perf/Documentation/android.txt78
-rw-r--r--tools/perf/Documentation/examples.txt34
-rw-r--r--tools/perf/Documentation/jit-interface.txt15
-rw-r--r--tools/perf/Documentation/perf-annotate.txt20
-rw-r--r--tools/perf/Documentation/perf-bench.txt78
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt8
-rw-r--r--tools/perf/Documentation/perf-diff.txt63
-rw-r--r--tools/perf/Documentation/perf-evlist.txt10
-rw-r--r--tools/perf/Documentation/perf-inject.txt11
-rw-r--r--tools/perf/Documentation/perf-kmem.txt2
-rw-r--r--tools/perf/Documentation/perf-kvm.txt30
-rw-r--r--tools/perf/Documentation/perf-list.txt46
-rw-r--r--tools/perf/Documentation/perf-lock.txt22
-rw-r--r--tools/perf/Documentation/perf-probe.txt19
-rw-r--r--tools/perf/Documentation/perf-record.txt40
-rw-r--r--tools/perf/Documentation/perf-report.txt51
-rw-r--r--tools/perf/Documentation/perf-sched.txt8
-rw-r--r--tools/perf/Documentation/perf-script-perl.txt4
-rw-r--r--tools/perf/Documentation/perf-script-python.txt10
-rw-r--r--tools/perf/Documentation/perf-script.txt21
-rw-r--r--tools/perf/Documentation/perf-stat.txt25
-rw-r--r--tools/perf/Documentation/perf-test.txt8
-rw-r--r--tools/perf/Documentation/perf-timechart.txt2
-rw-r--r--tools/perf/Documentation/perf-top.txt56
-rw-r--r--tools/perf/Documentation/perf-trace.txt59
-rw-r--r--tools/perf/Documentation/perfconfig.example29
-rw-r--r--tools/perf/MANIFEST8
-rw-r--r--tools/perf/Makefile575
-rw-r--r--tools/perf/arch/common.c211
-rw-r--r--tools/perf/arch/common.h10
-rw-r--r--tools/perf/arch/powerpc/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c3
-rw-r--r--tools/perf/arch/powerpc/util/header.c36
-rw-r--r--tools/perf/arch/x86/Makefile4
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h80
-rw-r--r--tools/perf/arch/x86/util/header.c59
-rw-r--r--tools/perf/arch/x86/util/unwind.c111
-rw-r--r--tools/perf/bash_completion62
-rw-r--r--tools/perf/bench/bench.h4
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm-def.h8
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm.S12
-rw-r--r--tools/perf/bench/mem-memcpy.c98
-rw-r--r--tools/perf/bench/mem-memset-arch.h12
-rw-r--r--tools/perf/bench/mem-memset-x86-64-asm-def.h12
-rw-r--r--tools/perf/bench/mem-memset-x86-64-asm.S13
-rw-r--r--tools/perf/bench/mem-memset.c297
-rw-r--r--tools/perf/bench/sched-messaging.c2
-rw-r--r--tools/perf/bench/sched-pipe.c10
-rw-r--r--tools/perf/builtin-annotate.c161
-rw-r--r--tools/perf/builtin-bench.c9
-rw-r--r--tools/perf/builtin-buildid-cache.c61
-rw-r--r--tools/perf/builtin-buildid-list.c87
-rw-r--r--tools/perf/builtin-diff.c532
-rw-r--r--tools/perf/builtin-evlist.c111
-rw-r--r--tools/perf/builtin-help.c86
-rw-r--r--tools/perf/builtin-inject.c377
-rw-r--r--tools/perf/builtin-kmem.c293
-rw-r--r--tools/perf/builtin-kvm.c982
-rw-r--r--tools/perf/builtin-list.c16
-rw-r--r--tools/perf/builtin-lock.c508
-rw-r--r--tools/perf/builtin-probe.c143
-rw-r--r--tools/perf/builtin-record.c1080
-rw-r--r--tools/perf/builtin-report.c505
-rw-r--r--tools/perf/builtin-sched.c1561
-rw-r--r--tools/perf/builtin-script.c562
-rw-r--r--tools/perf/builtin-stat.c900
-rw-r--r--tools/perf/builtin-timechart.c179
-rw-r--r--tools/perf/builtin-top.c1078
-rw-r--r--tools/perf/builtin-trace.c685
-rw-r--r--tools/perf/builtin.h3
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/config/feature-tests.mak101
-rw-r--r--tools/perf/config/utilities.mak10
-rw-r--r--tools/perf/design.txt7
-rw-r--r--tools/perf/perf-archive.sh9
-rw-r--r--tools/perf/perf.c144
-rw-r--r--tools/perf/perf.h107
-rwxr-xr-xtools/perf/python/twatch.py2
-rwxr-xr-xtools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py94
-rw-r--r--tools/perf/scripts/python/bin/event_analyzing_sample-record8
-rw-r--r--tools/perf/scripts/python/bin/event_analyzing_sample-report3
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-record2
-rwxr-xr-xtools/perf/scripts/python/bin/net_dropmonitor-report4
-rw-r--r--tools/perf/scripts/python/event_analyzing_sample.py189
-rwxr-xr-xtools/perf/scripts/python/net_dropmonitor.py72
-rw-r--r--tools/perf/tests/attr.c175
-rw-r--r--tools/perf/tests/attr.py322
-rw-r--r--tools/perf/tests/attr/README64
-rw-r--r--tools/perf/tests/attr/base-record39
-rw-r--r--tools/perf/tests/attr/base-stat39
-rw-r--r--tools/perf/tests/attr/test-record-basic5
-rw-r--r--tools/perf/tests/attr/test-record-branch-any8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any_call8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any_ret8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-hv8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-ind_call8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-k8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-u8
-rw-r--r--tools/perf/tests/attr/test-record-count8
-rw-r--r--tools/perf/tests/attr/test-record-data8
-rw-r--r--tools/perf/tests/attr/test-record-freq6
-rw-r--r--tools/perf/tests/attr/test-record-graph-default6
-rw-r--r--tools/perf/tests/attr/test-record-graph-dwarf10
-rw-r--r--tools/perf/tests/attr/test-record-graph-fp6
-rw-r--r--tools/perf/tests/attr/test-record-group18
-rw-r--r--tools/perf/tests/attr/test-record-group119
-rw-r--r--tools/perf/tests/attr/test-record-no-delay9
-rw-r--r--tools/perf/tests/attr/test-record-no-inherit7
-rw-r--r--tools/perf/tests/attr/test-record-no-samples6
-rw-r--r--tools/perf/tests/attr/test-record-period7
-rw-r--r--tools/perf/tests/attr/test-record-raw7
-rw-r--r--tools/perf/tests/attr/test-stat-basic6
-rw-r--r--tools/perf/tests/attr/test-stat-default64
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-1101
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-2155
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-3173
-rw-r--r--tools/perf/tests/attr/test-stat-group15
-rw-r--r--tools/perf/tests/attr/test-stat-group115
-rw-r--r--tools/perf/tests/attr/test-stat-no-inherit7
-rw-r--r--tools/perf/tests/builtin-test.c173
-rw-r--r--tools/perf/tests/dso-data.c159
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c114
-rw-r--r--tools/perf/tests/evsel-tp-sched.c84
-rw-r--r--tools/perf/tests/mmap-basic.c162
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c120
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c117
-rw-r--r--tools/perf/tests/open-syscall.c66
-rw-r--r--tools/perf/tests/parse-events.c1117
-rw-r--r--tools/perf/tests/perf-record.c312
-rw-r--r--tools/perf/tests/pmu.c178
-rw-r--r--tools/perf/tests/rdpmc.c175
-rw-r--r--tools/perf/tests/tests.h22
-rw-r--r--tools/perf/tests/util.c30
-rw-r--r--tools/perf/ui/browser.c714
-rw-r--r--tools/perf/ui/browser.h73
-rw-r--r--tools/perf/ui/browsers/annotate.c970
-rw-r--r--tools/perf/ui/browsers/hists.c1651
-rw-r--r--tools/perf/ui/browsers/map.c154
-rw-r--r--tools/perf/ui/browsers/map.h6
-rw-r--r--tools/perf/ui/browsers/scripts.c189
-rw-r--r--tools/perf/ui/gtk/browser.c312
-rw-r--r--tools/perf/ui/gtk/gtk.h43
-rw-r--r--tools/perf/ui/gtk/helpline.c56
-rw-r--r--tools/perf/ui/gtk/progress.c59
-rw-r--r--tools/perf/ui/gtk/setup.c23
-rw-r--r--tools/perf/ui/gtk/util.c113
-rw-r--r--tools/perf/ui/helpline.c61
-rw-r--r--tools/perf/ui/helpline.h47
-rw-r--r--tools/perf/ui/hist.c527
-rw-r--r--tools/perf/ui/keysyms.h27
-rw-r--r--tools/perf/ui/libslang.h29
-rw-r--r--tools/perf/ui/progress.c26
-rw-r--r--tools/perf/ui/progress.h18
-rw-r--r--tools/perf/ui/setup.c52
-rw-r--r--tools/perf/ui/stdio/hist.c485
-rw-r--r--tools/perf/ui/tui/helpline.c57
-rw-r--r--tools/perf/ui/tui/progress.c42
-rw-r--r--tools/perf/ui/tui/setup.c149
-rw-r--r--tools/perf/ui/tui/util.c243
-rw-r--r--tools/perf/ui/ui.h39
-rw-r--r--tools/perf/ui/util.c85
-rw-r--r--tools/perf/ui/util.h21
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN14
-rw-r--r--tools/perf/util/alias.c3
-rw-r--r--tools/perf/util/annotate.c729
-rw-r--r--tools/perf/util/annotate.h92
-rw-r--r--tools/perf/util/bitmap.c10
-rw-r--r--tools/perf/util/build-id.c52
-rw-r--r--tools/perf/util/build-id.h13
-rw-r--r--tools/perf/util/cache.h17
-rw-r--r--tools/perf/util/callchain.c8
-rw-r--r--tools/perf/util/callchain.h7
-rw-r--r--tools/perf/util/cgroup.c19
-rw-r--r--tools/perf/util/color.c11
-rw-r--r--tools/perf/util/config.c17
-rw-r--r--tools/perf/util/cpumap.c33
-rw-r--r--tools/perf/util/cpumap.h15
-rw-r--r--tools/perf/util/ctype.c2
-rw-r--r--tools/perf/util/debug.c14
-rw-r--r--tools/perf/util/debug.h41
-rw-r--r--tools/perf/util/debugfs.c160
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/dso.c595
-rw-r--r--tools/perf/util/dso.h148
-rw-r--r--tools/perf/util/dwarf-aux.c2
-rw-r--r--tools/perf/util/event.c594
-rw-r--r--tools/perf/util/event.h93
-rw-r--r--tools/perf/util/evlist.c423
-rw-r--r--tools/perf/util/evlist.h83
-rw-r--r--tools/perf/util/evsel.c799
-rw-r--r--tools/perf/util/evsel.h89
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh15
-rw-r--r--tools/perf/util/header.c2471
-rw-r--r--tools/perf/util/header.h111
-rw-r--r--tools/perf/util/help.c4
-rw-r--r--tools/perf/util/hist.c1145
-rw-r--r--tools/perf/util/hist.h165
-rw-r--r--tools/perf/util/include/asm/byteorder.h2
-rw-r--r--tools/perf/util/include/asm/dwarf2.h4
-rw-r--r--tools/perf/util/include/asm/unistd_32.h1
-rw-r--r--tools/perf/util/include/asm/unistd_64.h1
-rw-r--r--tools/perf/util/include/linux/bitmap.h11
-rw-r--r--tools/perf/util/include/linux/bitops.h124
-rw-r--r--tools/perf/util/include/linux/compiler.h9
-rw-r--r--tools/perf/util/include/linux/const.h2
-rw-r--r--tools/perf/util/include/linux/export.h6
-rw-r--r--tools/perf/util/include/linux/kernel.h27
-rw-r--r--tools/perf/util/include/linux/magic.h12
-rw-r--r--tools/perf/util/include/linux/rbtree.h1
-rw-r--r--tools/perf/util/include/linux/rbtree_augmented.h2
-rw-r--r--tools/perf/util/include/linux/string.h2
-rw-r--r--tools/perf/util/include/linux/types.h8
-rw-r--r--tools/perf/util/intlist.c101
-rw-r--r--tools/perf/util/intlist.h75
-rw-r--r--tools/perf/util/machine.c464
-rw-r--r--tools/perf/util/machine.h148
-rw-r--r--tools/perf/util/map.c297
-rw-r--r--tools/perf/util/map.h126
-rw-r--r--tools/perf/util/pager.c4
-rw-r--r--tools/perf/util/parse-events.c1274
-rw-r--r--tools/perf/util/parse-events.h81
-rw-r--r--tools/perf/util/parse-events.l215
-rw-r--r--tools/perf/util/parse-events.y415
-rw-r--r--tools/perf/util/parse-options.c14
-rw-r--r--tools/perf/util/parse-options.h1
-rw-r--r--tools/perf/util/path.c2
-rw-r--r--tools/perf/util/perf_regs.h14
-rw-r--r--tools/perf/util/pmu.c554
-rw-r--r--tools/perf/util/pmu.h57
-rw-r--r--tools/perf/util/pmu.l43
-rw-r--r--tools/perf/util/pmu.y93
-rw-r--r--tools/perf/util/probe-event.c510
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/probe-finder.c45
-rw-r--r--tools/perf/util/probe-finder.h1
-rw-r--r--tools/perf/util/pstack.c46
-rw-r--r--tools/perf/util/python-ext-sources21
-rw-r--r--tools/perf/util/python.c60
-rw-r--r--tools/perf/util/rblist.c107
-rw-r--r--tools/perf/util/rblist.h47
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c119
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c138
-rw-r--r--tools/perf/util/session.c962
-rw-r--r--tools/perf/util/session.h100
-rw-r--r--tools/perf/util/setup.py9
-rw-r--r--tools/perf/util/sort.c358
-rw-r--r--tools/perf/util/sort.h81
-rw-r--r--tools/perf/util/stat.c57
-rw-r--r--tools/perf/util/stat.h16
-rw-r--r--tools/perf/util/strbuf.c3
-rw-r--r--tools/perf/util/string.c58
-rw-r--r--tools/perf/util/strlist.c130
-rw-r--r--tools/perf/util/strlist.h11
-rw-r--r--tools/perf/util/symbol-elf.c841
-rw-r--r--tools/perf/util/symbol-minimal.c307
-rw-r--r--tools/perf/util/symbol.c1304
-rw-r--r--tools/perf/util/symbol.h190
-rw-r--r--tools/perf/util/sysfs.c60
-rw-r--r--tools/perf/util/sysfs.h6
-rw-r--r--tools/perf/util/target.c151
-rw-r--r--tools/perf/util/target.h65
-rw-r--r--tools/perf/util/thread.c46
-rw-r--r--tools/perf/util/thread.h18
-rw-r--r--tools/perf/util/thread_map.c236
-rw-r--r--tools/perf/util/thread_map.h13
-rw-r--r--tools/perf/util/tool.h50
-rw-r--r--tools/perf/util/top.c166
-rw-r--r--tools/perf/util/top.h62
-rw-r--r--tools/perf/util/trace-event-info.c143
-rw-r--r--tools/perf/util/trace-event-parse.c3139
-rw-r--r--tools/perf/util/trace-event-read.c116
-rw-r--r--tools/perf/util/trace-event-scripting.c32
-rw-r--r--tools/perf/util/trace-event.h298
-rw-r--r--tools/perf/util/types.h5
-rw-r--r--tools/perf/util/unwind.c571
-rw-r--r--tools/perf/util/unwind.h35
-rw-r--r--tools/perf/util/usage.c6
-rw-r--r--tools/perf/util/util.c87
-rw-r--r--tools/perf/util/util.h42
-rw-r--r--tools/perf/util/values.c1
-rw-r--r--tools/perf/util/vdso.c111
-rw-r--r--tools/perf/util/vdso.h18
-rw-r--r--tools/perf/util/wrapper.c3
-rw-r--r--tools/power/acpi/Makefile18
-rw-r--r--tools/power/acpi/acpidump.859
-rw-r--r--tools/power/acpi/acpidump.c559
-rw-r--r--tools/power/cpupower/Makefile96
-rw-r--r--tools/power/cpupower/bench/Makefile23
-rw-r--r--tools/power/cpupower/debug/i386/Makefile43
-rw-r--r--tools/power/cpupower/debug/x86_64/Makefile26
-rw-r--r--tools/power/cpupower/man/cpupower-frequency-info.14
-rw-r--r--tools/power/cpupower/man/cpupower-frequency-set.14
-rw-r--r--tools/power/cpupower/man/cpupower-idle-info.190
-rw-r--r--tools/power/cpupower/man/cpupower-monitor.117
-rw-r--r--tools/power/cpupower/man/cpupower-set.19
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c12
-rw-r--r--tools/power/cpupower/utils/helpers/amd.c4
-rw-r--r--tools/power/cpupower/utils/helpers/cpuid.c2
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h29
-rw-r--r--tools/power/cpupower/utils/helpers/pci.c35
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c54
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c53
-rw-r--r--tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c25
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c21
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h17
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c10
-rw-r--r--tools/power/x86/turbostat/Makefile22
-rw-r--r--tools/power/x86/turbostat/turbostat.8210
-rw-r--r--tools/power/x86/turbostat/turbostat.c2201
-rw-r--r--tools/power/x86/x86_energy_perf_policy/Makefile6
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c2
-rw-r--r--tools/scripts/Makefile.include77
-rw-r--r--tools/testing/fault-injection/failcmd.sh219
-rwxr-xr-xtools/testing/ktest/compare-ktest-sample.pl4
-rw-r--r--tools/testing/ktest/examples/README32
-rw-r--r--tools/testing/ktest/examples/crosstests.conf260
-rw-r--r--tools/testing/ktest/examples/include/bisect.conf90
-rw-r--r--tools/testing/ktest/examples/include/defaults.conf157
-rw-r--r--tools/testing/ktest/examples/include/min-config.conf60
-rw-r--r--tools/testing/ktest/examples/include/patchcheck.conf74
-rw-r--r--tools/testing/ktest/examples/include/tests.conf74
-rw-r--r--tools/testing/ktest/examples/kvm.conf88
-rw-r--r--tools/testing/ktest/examples/snowball.conf53
-rw-r--r--tools/testing/ktest/examples/test.conf62
-rwxr-xr-xtools/testing/ktest/ktest.pl1591
-rw-r--r--tools/testing/ktest/sample.conf363
-rw-r--r--tools/testing/selftests/Makefile16
-rw-r--r--tools/testing/selftests/breakpoints/Makefile23
-rw-r--r--tools/testing/selftests/breakpoints/breakpoint_test.c394
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile6
-rw-r--r--tools/testing/selftests/cpu-hotplug/on-off-test.sh221
-rw-r--r--tools/testing/selftests/ipc/Makefile25
-rw-r--r--tools/testing/selftests/ipc/msgque.c246
-rw-r--r--tools/testing/selftests/kcmp/Makefile29
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c96
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile6
-rw-r--r--tools/testing/selftests/memory-hotplug/on-off-test.sh230
-rw-r--r--tools/testing/selftests/mqueue/Makefile10
-rw-r--r--tools/testing/selftests/mqueue/mq_open_tests.c492
-rw-r--r--tools/testing/selftests/mqueue/mq_perf_tests.c741
-rw-r--r--tools/testing/selftests/vm/Makefile14
-rw-r--r--tools/testing/selftests/vm/hugepage-mmap.c92
-rw-r--r--tools/testing/selftests/vm/hugepage-shm.c100
-rw-r--r--tools/testing/selftests/vm/map_hugetlb.c79
-rw-r--r--tools/testing/selftests/vm/run_vmtests77
-rw-r--r--tools/testing/selftests/vm/thuge-gen.c254
-rw-r--r--tools/usb/Makefile2
-rw-r--r--tools/usb/ffs-test.c33
-rw-r--r--tools/usb/testusb.c51
-rw-r--r--tools/virtio/linux/virtio.h26
-rw-r--r--tools/virtio/virtio-trace/Makefile13
-rw-r--r--tools/virtio/virtio-trace/README118
-rw-r--r--tools/virtio/virtio-trace/trace-agent-ctl.c137
-rw-r--r--tools/virtio/virtio-trace/trace-agent-rw.c192
-rw-r--r--tools/virtio/virtio-trace/trace-agent.c270
-rw-r--r--tools/virtio/virtio-trace/trace-agent.h75
-rw-r--r--tools/virtio/virtio_test.c38
-rw-r--r--tools/vm/Makefile11
-rw-r--r--tools/vm/page-types.c1076
-rw-r--r--tools/vm/slabinfo.c1393
382 files changed, 13240 insertions, 60859 deletions
diff --git a/tools/Makefile b/tools/Makefile
deleted file mode 100644
index 1f9a529fe54..00000000000
--- a/tools/Makefile
+++ /dev/null
@@ -1,77 +0,0 @@
1include scripts/Makefile.include
2
3help:
4 @echo 'Possible targets:'
5 @echo ''
6 @echo ' cpupower - a tool for all things x86 CPU power'
7 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
8 @echo ' lguest - a minimal 32-bit x86 hypervisor'
9 @echo ' perf - Linux performance measurement and analysis tool'
10 @echo ' selftests - various kernel selftests'
11 @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
12 @echo ' usb - USB testing tools'
13 @echo ' virtio - vhost test module'
14 @echo ' vm - misc vm tools'
15 @echo ' x86_energy_perf_policy - Intel energy policy tool'
16 @echo ''
17 @echo 'You can do:'
18 @echo ' $$ make -C tools/<tool>_install'
19 @echo ''
20 @echo ' from the kernel command line to build and install one of'
21 @echo ' the tools above'
22 @echo ''
23 @echo ' $$ make tools/install'
24 @echo ''
25 @echo ' installs all tools.'
26 @echo ''
27 @echo 'Cleaning targets:'
28 @echo ''
29 @echo ' all of the above with the "_clean" string appended cleans'
30 @echo ' the respective build directory.'
31 @echo ' clean: a summary clean target to clean _all_ folders'
32
33cpupower: FORCE
34 $(call descend,power/$@)
35
36firewire lguest perf usb virtio vm: FORCE
37 $(call descend,$@)
38
39selftests: FORCE
40 $(call descend,testing/$@)
41
42turbostat x86_energy_perf_policy: FORCE
43 $(call descend,power/x86/$@)
44
45cpupower_install:
46 $(call descend,power/$(@:_install=),install)
47
48firewire_install lguest_install perf_install usb_install virtio_install vm_install:
49 $(call descend,$(@:_install=),install)
50
51selftests_install:
52 $(call descend,testing/$(@:_clean=),install)
53
54turbostat_install x86_energy_perf_policy_install:
55 $(call descend,power/x86/$(@:_install=),install)
56
57install: cpupower_install firewire_install lguest_install perf_install \
58 selftests_install turbostat_install usb_install virtio_install \
59 vm_install x86_energy_perf_policy_install
60
61cpupower_clean:
62 $(call descend,power/cpupower,clean)
63
64firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
65 $(call descend,$(@:_clean=),clean)
66
67selftests_clean:
68 $(call descend,testing/$(@:_clean=),clean)
69
70turbostat_clean x86_energy_perf_policy_clean:
71 $(call descend,power/x86/$(@:_clean=),clean)
72
73clean: cpupower_clean firewire_clean lguest_clean perf_clean selftests_clean \
74 turbostat_clean usb_clean virtio_clean vm_clean \
75 x86_energy_perf_policy_clean
76
77.PHONY: FORCE
diff --git a/tools/firewire/nosy-dump.c b/tools/firewire/nosy-dump.c
index 3179c711bd6..f93b776370b 100644
--- a/tools/firewire/nosy-dump.c
+++ b/tools/firewire/nosy-dump.c
@@ -150,8 +150,6 @@ subaction_create(uint32_t *data, size_t length)
150 150
151 /* we put the ack in the subaction struct for easy access. */ 151 /* we put the ack in the subaction struct for easy access. */
152 sa = malloc(sizeof *sa - sizeof sa->packet + length); 152 sa = malloc(sizeof *sa - sizeof sa->packet + length);
153 if (!sa)
154 exit(EXIT_FAILURE);
155 sa->ack = data[length / 4 - 1]; 153 sa->ack = data[length / 4 - 1];
156 sa->length = length; 154 sa->length = length;
157 memcpy(&sa->packet, data, length); 155 memcpy(&sa->packet, data, length);
@@ -182,8 +180,6 @@ link_transaction_lookup(int request_node, int response_node, int tlabel)
182 } 180 }
183 181
184 t = malloc(sizeof *t); 182 t = malloc(sizeof *t);
185 if (!t)
186 exit(EXIT_FAILURE);
187 t->request_node = request_node; 183 t->request_node = request_node;
188 t->response_node = response_node; 184 t->response_node = response_node;
189 t->tlabel = tlabel; 185 t->tlabel = tlabel;
diff --git a/tools/hv/hv_get_dhcp_info.sh b/tools/hv/hv_get_dhcp_info.sh
deleted file mode 100755
index ccd3e953276..00000000000
--- a/tools/hv/hv_get_dhcp_info.sh
+++ /dev/null
@@ -1,28 +0,0 @@
1#!/bin/bash
2
3# This example script retrieves the DHCP state of a given interface.
4# In the interest of keeping the KVP daemon code free of distro specific
5# information; the kvp daemon code invokes this external script to gather
6# DHCP setting for the specific interface.
7#
8# Input: Name of the interface
9#
10# Output: The script prints the string "Enabled" to stdout to indicate
11# that DHCP is enabled on the interface. If DHCP is not enabled,
12# the script prints the string "Disabled" to stdout.
13#
14# Each Distro is expected to implement this script in a distro specific
15# fashion. For instance on Distros that ship with Network Manager enabled,
16# this script can be based on the Network Manager APIs for retrieving DHCP
17# information.
18
19if_file="/etc/sysconfig/network-scripts/ifcfg-"$1
20
21dhcp=$(grep "dhcp" $if_file 2>/dev/null)
22
23if [ "$dhcp" != "" ];
24then
25echo "Enabled"
26else
27echo "Disabled"
28fi
diff --git a/tools/hv/hv_get_dns_info.sh b/tools/hv/hv_get_dns_info.sh
deleted file mode 100755
index 058c17b46ff..00000000000
--- a/tools/hv/hv_get_dns_info.sh
+++ /dev/null
@@ -1,13 +0,0 @@
1#!/bin/bash
2
3# This example script parses /etc/resolv.conf to retrive DNS information.
4# In the interest of keeping the KVP daemon code free of distro specific
5# information; the kvp daemon code invokes this external script to gather
6# DNS information.
7# This script is expected to print the nameserver values to stdout.
8# Each Distro is expected to implement this script in a distro specific
9# fashion. For instance on Distros that ship with Network Manager enabled,
10# this script can be based on the Network Manager APIs for retrieving DNS
11# entries.
12
13cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }'
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
deleted file mode 100644
index d25a46925e6..00000000000
--- a/tools/hv/hv_kvp_daemon.c
+++ /dev/null
@@ -1,1696 +0,0 @@
1/*
2 * An implementation of key value pair (KVP) functionality for Linux.
3 *
4 *
5 * Copyright (C) 2010, Novell, Inc.
6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT. See the GNU General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/poll.h>
28#include <sys/utsname.h>
29#include <linux/types.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <string.h>
34#include <ctype.h>
35#include <errno.h>
36#include <arpa/inet.h>
37#include <linux/connector.h>
38#include <linux/hyperv.h>
39#include <linux/netlink.h>
40#include <ifaddrs.h>
41#include <netdb.h>
42#include <syslog.h>
43#include <sys/stat.h>
44#include <fcntl.h>
45#include <dirent.h>
46#include <net/if.h>
47
48/*
49 * KVP protocol: The user mode component first registers with the
50 * the kernel component. Subsequently, the kernel component requests, data
51 * for the specified keys. In response to this message the user mode component
52 * fills in the value corresponding to the specified key. We overload the
53 * sequence field in the cn_msg header to define our KVP message types.
54 *
55 * We use this infrastructure for also supporting queries from user mode
56 * application for state that may be maintained in the KVP kernel component.
57 *
58 */
59
60
61enum key_index {
62 FullyQualifiedDomainName = 0,
63 IntegrationServicesVersion, /*This key is serviced in the kernel*/
64 NetworkAddressIPv4,
65 NetworkAddressIPv6,
66 OSBuildNumber,
67 OSName,
68 OSMajorVersion,
69 OSMinorVersion,
70 OSVersion,
71 ProcessorArchitecture
72};
73
74
75enum {
76 IPADDR = 0,
77 NETMASK,
78 GATEWAY,
79 DNS
80};
81
82static char kvp_send_buffer[4096];
83static char kvp_recv_buffer[4096 * 2];
84static struct sockaddr_nl addr;
85static int in_hand_shake = 1;
86
87static char *os_name = "";
88static char *os_major = "";
89static char *os_minor = "";
90static char *processor_arch;
91static char *os_build;
92static char *os_version;
93static char *lic_version = "Unknown version";
94static struct utsname uts_buf;
95
96/*
97 * The location of the interface configuration file.
98 */
99
100#define KVP_CONFIG_LOC "/var/opt/"
101
102#define MAX_FILE_NAME 100
103#define ENTRIES_PER_BLOCK 50
104
105struct kvp_record {
106 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
107 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
108};
109
110struct kvp_file_state {
111 int fd;
112 int num_blocks;
113 struct kvp_record *records;
114 int num_records;
115 char fname[MAX_FILE_NAME];
116};
117
118static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
119
120static void kvp_acquire_lock(int pool)
121{
122 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
123 fl.l_pid = getpid();
124
125 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
126 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
127 exit(EXIT_FAILURE);
128 }
129}
130
131static void kvp_release_lock(int pool)
132{
133 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
134 fl.l_pid = getpid();
135
136 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
137 perror("fcntl");
138 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
139 exit(EXIT_FAILURE);
140 }
141}
142
143static void kvp_update_file(int pool)
144{
145 FILE *filep;
146 size_t bytes_written;
147
148 /*
149 * We are going to write our in-memory registry out to
150 * disk; acquire the lock first.
151 */
152 kvp_acquire_lock(pool);
153
154 filep = fopen(kvp_file_info[pool].fname, "w");
155 if (!filep) {
156 kvp_release_lock(pool);
157 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
158 exit(EXIT_FAILURE);
159 }
160
161 bytes_written = fwrite(kvp_file_info[pool].records,
162 sizeof(struct kvp_record),
163 kvp_file_info[pool].num_records, filep);
164
165 if (ferror(filep) || fclose(filep)) {
166 kvp_release_lock(pool);
167 syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
168 exit(EXIT_FAILURE);
169 }
170
171 kvp_release_lock(pool);
172}
173
174static void kvp_update_mem_state(int pool)
175{
176 FILE *filep;
177 size_t records_read = 0;
178 struct kvp_record *record = kvp_file_info[pool].records;
179 struct kvp_record *readp;
180 int num_blocks = kvp_file_info[pool].num_blocks;
181 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
182
183 kvp_acquire_lock(pool);
184
185 filep = fopen(kvp_file_info[pool].fname, "r");
186 if (!filep) {
187 kvp_release_lock(pool);
188 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
189 exit(EXIT_FAILURE);
190 }
191 for (;;) {
192 readp = &record[records_read];
193 records_read += fread(readp, sizeof(struct kvp_record),
194 ENTRIES_PER_BLOCK * num_blocks,
195 filep);
196
197 if (ferror(filep)) {
198 syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
199 exit(EXIT_FAILURE);
200 }
201
202 if (!feof(filep)) {
203 /*
204 * We have more data to read.
205 */
206 num_blocks++;
207 record = realloc(record, alloc_unit * num_blocks);
208
209 if (record == NULL) {
210 syslog(LOG_ERR, "malloc failed");
211 exit(EXIT_FAILURE);
212 }
213 continue;
214 }
215 break;
216 }
217
218 kvp_file_info[pool].num_blocks = num_blocks;
219 kvp_file_info[pool].records = record;
220 kvp_file_info[pool].num_records = records_read;
221
222 fclose(filep);
223 kvp_release_lock(pool);
224}
225static int kvp_file_init(void)
226{
227 int fd;
228 FILE *filep;
229 size_t records_read;
230 char *fname;
231 struct kvp_record *record;
232 struct kvp_record *readp;
233 int num_blocks;
234 int i;
235 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
236
237 if (access("/var/opt/hyperv", F_OK)) {
238 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
239 syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
240 exit(EXIT_FAILURE);
241 }
242 }
243
244 for (i = 0; i < KVP_POOL_COUNT; i++) {
245 fname = kvp_file_info[i].fname;
246 records_read = 0;
247 num_blocks = 1;
248 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
249 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
250
251 if (fd == -1)
252 return 1;
253
254
255 filep = fopen(fname, "r");
256 if (!filep)
257 return 1;
258
259 record = malloc(alloc_unit * num_blocks);
260 if (record == NULL) {
261 fclose(filep);
262 return 1;
263 }
264 for (;;) {
265 readp = &record[records_read];
266 records_read += fread(readp, sizeof(struct kvp_record),
267 ENTRIES_PER_BLOCK,
268 filep);
269
270 if (ferror(filep)) {
271 syslog(LOG_ERR, "Failed to read file, pool: %d",
272 i);
273 exit(EXIT_FAILURE);
274 }
275
276 if (!feof(filep)) {
277 /*
278 * We have more data to read.
279 */
280 num_blocks++;
281 record = realloc(record, alloc_unit *
282 num_blocks);
283 if (record == NULL) {
284 fclose(filep);
285 return 1;
286 }
287 continue;
288 }
289 break;
290 }
291 kvp_file_info[i].fd = fd;
292 kvp_file_info[i].num_blocks = num_blocks;
293 kvp_file_info[i].records = record;
294 kvp_file_info[i].num_records = records_read;
295 fclose(filep);
296
297 }
298
299 return 0;
300}
301
302static int kvp_key_delete(int pool, const char *key, int key_size)
303{
304 int i;
305 int j, k;
306 int num_records;
307 struct kvp_record *record;
308
309 /*
310 * First update the in-memory state.
311 */
312 kvp_update_mem_state(pool);
313
314 num_records = kvp_file_info[pool].num_records;
315 record = kvp_file_info[pool].records;
316
317 for (i = 0; i < num_records; i++) {
318 if (memcmp(key, record[i].key, key_size))
319 continue;
320 /*
321 * Found a match; just move the remaining
322 * entries up.
323 */
324 if (i == num_records) {
325 kvp_file_info[pool].num_records--;
326 kvp_update_file(pool);
327 return 0;
328 }
329
330 j = i;
331 k = j + 1;
332 for (; k < num_records; k++) {
333 strcpy(record[j].key, record[k].key);
334 strcpy(record[j].value, record[k].value);
335 j++;
336 }
337
338 kvp_file_info[pool].num_records--;
339 kvp_update_file(pool);
340 return 0;
341 }
342 return 1;
343}
344
345static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value,
346 int value_size)
347{
348 int i;
349 int num_records;
350 struct kvp_record *record;
351 int num_blocks;
352
353 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
354 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
355 return 1;
356
357 /*
358 * First update the in-memory state.
359 */
360 kvp_update_mem_state(pool);
361
362 num_records = kvp_file_info[pool].num_records;
363 record = kvp_file_info[pool].records;
364 num_blocks = kvp_file_info[pool].num_blocks;
365
366 for (i = 0; i < num_records; i++) {
367 if (memcmp(key, record[i].key, key_size))
368 continue;
369 /*
370 * Found a match; just update the value -
371 * this is the modify case.
372 */
373 memcpy(record[i].value, value, value_size);
374 kvp_update_file(pool);
375 return 0;
376 }
377
378 /*
379 * Need to add a new entry;
380 */
381 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
382 /* Need to allocate a larger array for reg entries. */
383 record = realloc(record, sizeof(struct kvp_record) *
384 ENTRIES_PER_BLOCK * (num_blocks + 1));
385
386 if (record == NULL)
387 return 1;
388 kvp_file_info[pool].num_blocks++;
389
390 }
391 memcpy(record[i].value, value, value_size);
392 memcpy(record[i].key, key, key_size);
393 kvp_file_info[pool].records = record;
394 kvp_file_info[pool].num_records++;
395 kvp_update_file(pool);
396 return 0;
397}
398
399static int kvp_get_value(int pool, const char *key, int key_size, char *value,
400 int value_size)
401{
402 int i;
403 int num_records;
404 struct kvp_record *record;
405
406 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
407 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
408 return 1;
409
410 /*
411 * First update the in-memory state.
412 */
413 kvp_update_mem_state(pool);
414
415 num_records = kvp_file_info[pool].num_records;
416 record = kvp_file_info[pool].records;
417
418 for (i = 0; i < num_records; i++) {
419 if (memcmp(key, record[i].key, key_size))
420 continue;
421 /*
422 * Found a match; just copy the value out.
423 */
424 memcpy(value, record[i].value, value_size);
425 return 0;
426 }
427
428 return 1;
429}
430
431static int kvp_pool_enumerate(int pool, int index, char *key, int key_size,
432 char *value, int value_size)
433{
434 struct kvp_record *record;
435
436 /*
437 * First update our in-memory database.
438 */
439 kvp_update_mem_state(pool);
440 record = kvp_file_info[pool].records;
441
442 if (index >= kvp_file_info[pool].num_records) {
443 return 1;
444 }
445
446 memcpy(key, record[index].key, key_size);
447 memcpy(value, record[index].value, value_size);
448 return 0;
449}
450
451
452void kvp_get_os_info(void)
453{
454 FILE *file;
455 char *p, buf[512];
456
457 uname(&uts_buf);
458 os_version = uts_buf.release;
459 os_build = strdup(uts_buf.release);
460
461 os_name = uts_buf.sysname;
462 processor_arch = uts_buf.machine;
463
464 /*
465 * The current windows host (win7) expects the build
466 * string to be of the form: x.y.z
467 * Strip additional information we may have.
468 */
469 p = strchr(os_version, '-');
470 if (p)
471 *p = '\0';
472
473 /*
474 * Parse the /etc/os-release file if present:
475 * http://www.freedesktop.org/software/systemd/man/os-release.html
476 */
477 file = fopen("/etc/os-release", "r");
478 if (file != NULL) {
479 while (fgets(buf, sizeof(buf), file)) {
480 char *value, *q;
481
482 /* Ignore comments */
483 if (buf[0] == '#')
484 continue;
485
486 /* Split into name=value */
487 p = strchr(buf, '=');
488 if (!p)
489 continue;
490 *p++ = 0;
491
492 /* Remove quotes and newline; un-escape */
493 value = p;
494 q = p;
495 while (*p) {
496 if (*p == '\\') {
497 ++p;
498 if (!*p)
499 break;
500 *q++ = *p++;
501 } else if (*p == '\'' || *p == '"' ||
502 *p == '\n') {
503 ++p;
504 } else {
505 *q++ = *p++;
506 }
507 }
508 *q = 0;
509
510 if (!strcmp(buf, "NAME")) {
511 p = strdup(value);
512 if (!p)
513 break;
514 os_name = p;
515 } else if (!strcmp(buf, "VERSION_ID")) {
516 p = strdup(value);
517 if (!p)
518 break;
519 os_major = p;
520 }
521 }
522 fclose(file);
523 return;
524 }
525
526 /* Fallback for older RH/SUSE releases */
527 file = fopen("/etc/SuSE-release", "r");
528 if (file != NULL)
529 goto kvp_osinfo_found;
530 file = fopen("/etc/redhat-release", "r");
531 if (file != NULL)
532 goto kvp_osinfo_found;
533
534 /*
535 * We don't have information about the os.
536 */
537 return;
538
539kvp_osinfo_found:
540 /* up to three lines */
541 p = fgets(buf, sizeof(buf), file);
542 if (p) {
543 p = strchr(buf, '\n');
544 if (p)
545 *p = '\0';
546 p = strdup(buf);
547 if (!p)
548 goto done;
549 os_name = p;
550
551 /* second line */
552 p = fgets(buf, sizeof(buf), file);
553 if (p) {
554 p = strchr(buf, '\n');
555 if (p)
556 *p = '\0';
557 p = strdup(buf);
558 if (!p)
559 goto done;
560 os_major = p;
561
562 /* third line */
563 p = fgets(buf, sizeof(buf), file);
564 if (p) {
565 p = strchr(buf, '\n');
566 if (p)
567 *p = '\0';
568 p = strdup(buf);
569 if (p)
570 os_minor = p;
571 }
572 }
573 }
574
575done:
576 fclose(file);
577 return;
578}
579
580
581
582/*
583 * Retrieve an interface name corresponding to the specified guid.
584 * If there is a match, the function returns a pointer
585 * to the interface name and if not, a NULL is returned.
586 * If a match is found, the caller is responsible for
587 * freeing the memory.
588 */
589
590static char *kvp_get_if_name(char *guid)
591{
592 DIR *dir;
593 struct dirent *entry;
594 FILE *file;
595 char *p, *q, *x;
596 char *if_name = NULL;
597 char buf[256];
598 char *kvp_net_dir = "/sys/class/net/";
599 char dev_id[256];
600
601 dir = opendir(kvp_net_dir);
602 if (dir == NULL)
603 return NULL;
604
605 snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
606 q = dev_id + strlen(kvp_net_dir);
607
608 while ((entry = readdir(dir)) != NULL) {
609 /*
610 * Set the state for the next pass.
611 */
612 *q = '\0';
613 strcat(dev_id, entry->d_name);
614 strcat(dev_id, "/device/device_id");
615
616 file = fopen(dev_id, "r");
617 if (file == NULL)
618 continue;
619
620 p = fgets(buf, sizeof(buf), file);
621 if (p) {
622 x = strchr(p, '\n');
623 if (x)
624 *x = '\0';
625
626 if (!strcmp(p, guid)) {
627 /*
628 * Found the guid match; return the interface
629 * name. The caller will free the memory.
630 */
631 if_name = strdup(entry->d_name);
632 fclose(file);
633 break;
634 }
635 }
636 fclose(file);
637 }
638
639 closedir(dir);
640 return if_name;
641}
642
643/*
644 * Retrieve the MAC address given the interface name.
645 */
646
647static char *kvp_if_name_to_mac(char *if_name)
648{
649 FILE *file;
650 char *p, *x;
651 char buf[256];
652 char addr_file[256];
653 int i;
654 char *mac_addr = NULL;
655
656 snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
657 if_name, "/address");
658
659 file = fopen(addr_file, "r");
660 if (file == NULL)
661 return NULL;
662
663 p = fgets(buf, sizeof(buf), file);
664 if (p) {
665 x = strchr(p, '\n');
666 if (x)
667 *x = '\0';
668 for (i = 0; i < strlen(p); i++)
669 p[i] = toupper(p[i]);
670 mac_addr = strdup(p);
671 }
672
673 fclose(file);
674 return mac_addr;
675}
676
677
678/*
679 * Retrieve the interface name given tha MAC address.
680 */
681
682static char *kvp_mac_to_if_name(char *mac)
683{
684 DIR *dir;
685 struct dirent *entry;
686 FILE *file;
687 char *p, *q, *x;
688 char *if_name = NULL;
689 char buf[256];
690 char *kvp_net_dir = "/sys/class/net/";
691 char dev_id[256];
692 int i;
693
694 dir = opendir(kvp_net_dir);
695 if (dir == NULL)
696 return NULL;
697
698 snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
699 q = dev_id + strlen(kvp_net_dir);
700
701 while ((entry = readdir(dir)) != NULL) {
702 /*
703 * Set the state for the next pass.
704 */
705 *q = '\0';
706
707 strcat(dev_id, entry->d_name);
708 strcat(dev_id, "/address");
709
710 file = fopen(dev_id, "r");
711 if (file == NULL)
712 continue;
713
714 p = fgets(buf, sizeof(buf), file);
715 if (p) {
716 x = strchr(p, '\n');
717 if (x)
718 *x = '\0';
719
720 for (i = 0; i < strlen(p); i++)
721 p[i] = toupper(p[i]);
722
723 if (!strcmp(p, mac)) {
724 /*
725 * Found the MAC match; return the interface
726 * name. The caller will free the memory.
727 */
728 if_name = strdup(entry->d_name);
729 fclose(file);
730 break;
731 }
732 }
733 fclose(file);
734 }
735
736 closedir(dir);
737 return if_name;
738}
739
740
741static void kvp_process_ipconfig_file(char *cmd,
742 char *config_buf, int len,
743 int element_size, int offset)
744{
745 char buf[256];
746 char *p;
747 char *x;
748 FILE *file;
749
750 /*
751 * First execute the command.
752 */
753 file = popen(cmd, "r");
754 if (file == NULL)
755 return;
756
757 if (offset == 0)
758 memset(config_buf, 0, len);
759 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
760 if ((len - strlen(config_buf)) < (element_size + 1))
761 break;
762
763 x = strchr(p, '\n');
764 *x = '\0';
765 strcat(config_buf, p);
766 strcat(config_buf, ";");
767 }
768 pclose(file);
769}
770
771static void kvp_get_ipconfig_info(char *if_name,
772 struct hv_kvp_ipaddr_value *buffer)
773{
774 char cmd[512];
775 char dhcp_info[128];
776 char *p;
777 FILE *file;
778
779 /*
780 * Get the address of default gateway (ipv4).
781 */
782 sprintf(cmd, "%s %s", "ip route show dev", if_name);
783 strcat(cmd, " | awk '/default/ {print $3 }'");
784
785 /*
786 * Execute the command to gather gateway info.
787 */
788 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
789 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
790
791 /*
792 * Get the address of default gateway (ipv6).
793 */
794 sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name);
795 strcat(cmd, " | awk '/default/ {print $3 }'");
796
797 /*
798 * Execute the command to gather gateway info (ipv6).
799 */
800 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
801 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
802
803
804 /*
805 * Gather the DNS state.
806 * Since there is no standard way to get this information
807 * across various distributions of interest; we just invoke
808 * an external script that needs to be ported across distros
809 * of interest.
810 *
811 * Following is the expected format of the information from the script:
812 *
813 * ipaddr1 (nameserver1)
814 * ipaddr2 (nameserver2)
815 * .
816 * .
817 */
818
819 sprintf(cmd, "%s", "hv_get_dns_info");
820
821 /*
822 * Execute the command to gather DNS info.
823 */
824 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
825 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
826
827 /*
828 * Gather the DHCP state.
829 * We will gather this state by invoking an external script.
830 * The parameter to the script is the interface name.
831 * Here is the expected output:
832 *
833 * Enabled: DHCP enabled.
834 */
835
836 sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
837
838 file = popen(cmd, "r");
839 if (file == NULL)
840 return;
841
842 p = fgets(dhcp_info, sizeof(dhcp_info), file);
843 if (p == NULL) {
844 pclose(file);
845 return;
846 }
847
848 if (!strncmp(p, "Enabled", 7))
849 buffer->dhcp_enabled = 1;
850 else
851 buffer->dhcp_enabled = 0;
852
853 pclose(file);
854}
855
856
857static unsigned int hweight32(unsigned int *w)
858{
859 unsigned int res = *w - ((*w >> 1) & 0x55555555);
860 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
861 res = (res + (res >> 4)) & 0x0F0F0F0F;
862 res = res + (res >> 8);
863 return (res + (res >> 16)) & 0x000000FF;
864}
865
866static int kvp_process_ip_address(void *addrp,
867 int family, char *buffer,
868 int length, int *offset)
869{
870 struct sockaddr_in *addr;
871 struct sockaddr_in6 *addr6;
872 int addr_length;
873 char tmp[50];
874 const char *str;
875
876 if (family == AF_INET) {
877 addr = (struct sockaddr_in *)addrp;
878 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
879 addr_length = INET_ADDRSTRLEN;
880 } else {
881 addr6 = (struct sockaddr_in6 *)addrp;
882 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
883 addr_length = INET6_ADDRSTRLEN;
884 }
885
886 if ((length - *offset) < addr_length + 2)
887 return HV_E_FAIL;
888 if (str == NULL) {
889 strcpy(buffer, "inet_ntop failed\n");
890 return HV_E_FAIL;
891 }
892 if (*offset == 0)
893 strcpy(buffer, tmp);
894 else {
895 strcat(buffer, ";");
896 strcat(buffer, tmp);
897 }
898
899 *offset += strlen(str) + 1;
900
901 return 0;
902}
903
904static int
905kvp_get_ip_info(int family, char *if_name, int op,
906 void *out_buffer, int length)
907{
908 struct ifaddrs *ifap;
909 struct ifaddrs *curp;
910 int offset = 0;
911 int sn_offset = 0;
912 int error = 0;
913 char *buffer;
914 struct hv_kvp_ipaddr_value *ip_buffer;
915 char cidr_mask[5]; /* /xyz */
916 int weight;
917 int i;
918 unsigned int *w;
919 char *sn_str;
920 struct sockaddr_in6 *addr6;
921
922 if (op == KVP_OP_ENUMERATE) {
923 buffer = out_buffer;
924 } else {
925 ip_buffer = out_buffer;
926 buffer = (char *)ip_buffer->ip_addr;
927 ip_buffer->addr_family = 0;
928 }
929 /*
930 * On entry into this function, the buffer is capable of holding the
931 * maximum key value.
932 */
933
934 if (getifaddrs(&ifap)) {
935 strcpy(buffer, "getifaddrs failed\n");
936 return HV_E_FAIL;
937 }
938
939 curp = ifap;
940 while (curp != NULL) {
941 if (curp->ifa_addr == NULL) {
942 curp = curp->ifa_next;
943 continue;
944 }
945
946 if ((if_name != NULL) &&
947 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
948 /*
949 * We want info about a specific interface;
950 * just continue.
951 */
952 curp = curp->ifa_next;
953 continue;
954 }
955
956 /*
957 * We only support two address families: AF_INET and AF_INET6.
958 * If a family value of 0 is specified, we collect both
959 * supported address families; if not we gather info on
960 * the specified address family.
961 */
962 if ((((family != 0) &&
963 (curp->ifa_addr->sa_family != family))) ||
964 (curp->ifa_flags & IFF_LOOPBACK)) {
965 curp = curp->ifa_next;
966 continue;
967 }
968 if ((curp->ifa_addr->sa_family != AF_INET) &&
969 (curp->ifa_addr->sa_family != AF_INET6)) {
970 curp = curp->ifa_next;
971 continue;
972 }
973
974 if (op == KVP_OP_GET_IP_INFO) {
975 /*
976 * Gather info other than the IP address.
977 * IP address info will be gathered later.
978 */
979 if (curp->ifa_addr->sa_family == AF_INET) {
980 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
981 /*
982 * Get subnet info.
983 */
984 error = kvp_process_ip_address(
985 curp->ifa_netmask,
986 AF_INET,
987 (char *)
988 ip_buffer->sub_net,
989 length,
990 &sn_offset);
991 if (error)
992 goto gather_ipaddr;
993 } else {
994 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
995
996 /*
997 * Get subnet info in CIDR format.
998 */
999 weight = 0;
1000 sn_str = (char *)ip_buffer->sub_net;
1001 addr6 = (struct sockaddr_in6 *)
1002 curp->ifa_netmask;
1003 w = addr6->sin6_addr.s6_addr32;
1004
1005 for (i = 0; i < 4; i++)
1006 weight += hweight32(&w[i]);
1007
1008 sprintf(cidr_mask, "/%d", weight);
1009 if ((length - sn_offset) <
1010 (strlen(cidr_mask) + 1))
1011 goto gather_ipaddr;
1012
1013 if (sn_offset == 0)
1014 strcpy(sn_str, cidr_mask);
1015 else
1016 strcat(sn_str, cidr_mask);
1017 strcat((char *)ip_buffer->sub_net, ";");
1018 sn_offset += strlen(sn_str) + 1;
1019 }
1020
1021 /*
1022 * Collect other ip related configuration info.
1023 */
1024
1025 kvp_get_ipconfig_info(if_name, ip_buffer);
1026 }
1027
1028gather_ipaddr:
1029 error = kvp_process_ip_address(curp->ifa_addr,
1030 curp->ifa_addr->sa_family,
1031 buffer,
1032 length, &offset);
1033 if (error)
1034 goto getaddr_done;
1035
1036 curp = curp->ifa_next;
1037 }
1038
1039getaddr_done:
1040 freeifaddrs(ifap);
1041 return error;
1042}
1043
1044
1045static int expand_ipv6(char *addr, int type)
1046{
1047 int ret;
1048 struct in6_addr v6_addr;
1049
1050 ret = inet_pton(AF_INET6, addr, &v6_addr);
1051
1052 if (ret != 1) {
1053 if (type == NETMASK)
1054 return 1;
1055 return 0;
1056 }
1057
1058 sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1059 "%02x%02x:%02x%02x:%02x%02x",
1060 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1061 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1062 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1063 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1064 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1065 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1066 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1067 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1068
1069 return 1;
1070
1071}
1072
1073static int is_ipv4(char *addr)
1074{
1075 int ret;
1076 struct in_addr ipv4_addr;
1077
1078 ret = inet_pton(AF_INET, addr, &ipv4_addr);
1079
1080 if (ret == 1)
1081 return 1;
1082 return 0;
1083}
1084
1085static int parse_ip_val_buffer(char *in_buf, int *offset,
1086 char *out_buf, int out_len)
1087{
1088 char *x;
1089 char *start;
1090
1091 /*
1092 * in_buf has sequence of characters that are seperated by
1093 * the character ';'. The last sequence does not have the
1094 * terminating ";" character.
1095 */
1096 start = in_buf + *offset;
1097
1098 x = strchr(start, ';');
1099 if (x)
1100 *x = 0;
1101 else
1102 x = start + strlen(start);
1103
1104 if (strlen(start) != 0) {
1105 int i = 0;
1106 /*
1107 * Get rid of leading spaces.
1108 */
1109 while (start[i] == ' ')
1110 i++;
1111
1112 if ((x - start) <= out_len) {
1113 strcpy(out_buf, (start + i));
1114 *offset += (x - start) + 1;
1115 return 1;
1116 }
1117 }
1118 return 0;
1119}
1120
1121static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1122{
1123 int ret;
1124
1125 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1126
1127 if (ret < 0)
1128 return HV_E_FAIL;
1129
1130 return 0;
1131}
1132
1133
1134static int process_ip_string(FILE *f, char *ip_string, int type)
1135{
1136 int error = 0;
1137 char addr[INET6_ADDRSTRLEN];
1138 int i = 0;
1139 int j = 0;
1140 char str[256];
1141 char sub_str[10];
1142 int offset = 0;
1143
1144 memset(addr, 0, sizeof(addr));
1145
1146 while (parse_ip_val_buffer(ip_string, &offset, addr,
1147 (MAX_IP_ADDR_SIZE * 2))) {
1148
1149 sub_str[0] = 0;
1150 if (is_ipv4(addr)) {
1151 switch (type) {
1152 case IPADDR:
1153 snprintf(str, sizeof(str), "%s", "IPADDR");
1154 break;
1155 case NETMASK:
1156 snprintf(str, sizeof(str), "%s", "NETMASK");
1157 break;
1158 case GATEWAY:
1159 snprintf(str, sizeof(str), "%s", "GATEWAY");
1160 break;
1161 case DNS:
1162 snprintf(str, sizeof(str), "%s", "DNS");
1163 break;
1164 }
1165 if (i != 0) {
1166 if (type != DNS) {
1167 snprintf(sub_str, sizeof(sub_str),
1168 "_%d", i++);
1169 } else {
1170 snprintf(sub_str, sizeof(sub_str),
1171 "%d", ++i);
1172 }
1173 } else if (type == DNS) {
1174 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1175 }
1176
1177
1178 } else if (expand_ipv6(addr, type)) {
1179 switch (type) {
1180 case IPADDR:
1181 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1182 break;
1183 case NETMASK:
1184 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1185 break;
1186 case GATEWAY:
1187 snprintf(str, sizeof(str), "%s",
1188 "IPV6_DEFAULTGW");
1189 break;
1190 case DNS:
1191 snprintf(str, sizeof(str), "%s", "DNS");
1192 break;
1193 }
1194 if ((j != 0) || (type == DNS)) {
1195 if (type != DNS) {
1196 snprintf(sub_str, sizeof(sub_str),
1197 "_%d", j++);
1198 } else {
1199 snprintf(sub_str, sizeof(sub_str),
1200 "%d", ++i);
1201 }
1202 } else if (type == DNS) {
1203 snprintf(sub_str, sizeof(sub_str),
1204 "%d", ++i);
1205 }
1206 } else {
1207 return HV_INVALIDARG;
1208 }
1209
1210 error = kvp_write_file(f, str, sub_str, addr);
1211 if (error)
1212 return error;
1213 memset(addr, 0, sizeof(addr));
1214 }
1215
1216 return 0;
1217}
1218
1219static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1220{
1221 int error = 0;
1222 char if_file[128];
1223 FILE *file;
1224 char cmd[512];
1225 char *mac_addr;
1226
1227 /*
1228 * Set the configuration for the specified interface with
1229 * the information provided. Since there is no standard
1230 * way to configure an interface, we will have an external
1231 * script that does the job of configuring the interface and
1232 * flushing the configuration.
1233 *
1234 * The parameters passed to this external script are:
1235 * 1. A configuration file that has the specified configuration.
1236 *
1237 * We will embed the name of the interface in the configuration
1238 * file: ifcfg-ethx (where ethx is the interface name).
1239 *
1240 * The information provided here may be more than what is needed
1241 * in a given distro to configure the interface and so are free
1242 * ignore information that may not be relevant.
1243 *
1244 * Here is the format of the ip configuration file:
1245 *
1246 * HWADDR=macaddr
1247 * IF_NAME=interface name
1248 * DHCP=yes (This is optional; if yes, DHCP is configured)
1249 *
1250 * IPADDR=ipaddr1
1251 * IPADDR_1=ipaddr2
1252 * IPADDR_x=ipaddry (where y = x + 1)
1253 *
1254 * NETMASK=netmask1
1255 * NETMASK_x=netmasky (where y = x + 1)
1256 *
1257 * GATEWAY=ipaddr1
1258 * GATEWAY_x=ipaddry (where y = x + 1)
1259 *
1260 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1261 *
1262 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1263 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1264 * IPV6NETMASK.
1265 *
1266 * The host can specify multiple ipv4 and ipv6 addresses to be
1267 * configured for the interface. Furthermore, the configuration
1268 * needs to be persistent. A subsequent GET call on the interface
1269 * is expected to return the configuration that is set via the SET
1270 * call.
1271 */
1272
1273 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1274 "hyperv/ifcfg-", if_name);
1275
1276 file = fopen(if_file, "w");
1277
1278 if (file == NULL) {
1279 syslog(LOG_ERR, "Failed to open config file");
1280 return HV_E_FAIL;
1281 }
1282
1283 /*
1284 * First write out the MAC address.
1285 */
1286
1287 mac_addr = kvp_if_name_to_mac(if_name);
1288 if (mac_addr == NULL) {
1289 error = HV_E_FAIL;
1290 goto setval_error;
1291 }
1292
1293 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1294 if (error)
1295 goto setval_error;
1296
1297 error = kvp_write_file(file, "IF_NAME", "", if_name);
1298 if (error)
1299 goto setval_error;
1300
1301 if (new_val->dhcp_enabled) {
1302 error = kvp_write_file(file, "DHCP", "", "yes");
1303 if (error)
1304 goto setval_error;
1305
1306 /*
1307 * We are done!.
1308 */
1309 goto setval_done;
1310 }
1311
1312 /*
1313 * Write the configuration for ipaddress, netmask, gateway and
1314 * name servers.
1315 */
1316
1317 error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1318 if (error)
1319 goto setval_error;
1320
1321 error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1322 if (error)
1323 goto setval_error;
1324
1325 error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1326 if (error)
1327 goto setval_error;
1328
1329 error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1330 if (error)
1331 goto setval_error;
1332
1333setval_done:
1334 free(mac_addr);
1335 fclose(file);
1336
1337 /*
1338 * Now that we have populated the configuration file,
1339 * invoke the external script to do its magic.
1340 */
1341
1342 snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1343 system(cmd);
1344 return 0;
1345
1346setval_error:
1347 syslog(LOG_ERR, "Failed to write config file");
1348 free(mac_addr);
1349 fclose(file);
1350 return error;
1351}
1352
1353
1354static int
1355kvp_get_domain_name(char *buffer, int length)
1356{
1357 struct addrinfo hints, *info ;
1358 int error = 0;
1359
1360 gethostname(buffer, length);
1361 memset(&hints, 0, sizeof(hints));
1362 hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1363 hints.ai_socktype = SOCK_STREAM;
1364 hints.ai_flags = AI_CANONNAME;
1365
1366 error = getaddrinfo(buffer, NULL, &hints, &info);
1367 if (error != 0) {
1368 strcpy(buffer, "getaddrinfo failed\n");
1369 return error;
1370 }
1371 strcpy(buffer, info->ai_canonname);
1372 freeaddrinfo(info);
1373 return error;
1374}
1375
1376static int
1377netlink_send(int fd, struct cn_msg *msg)
1378{
1379 struct nlmsghdr *nlh;
1380 unsigned int size;
1381 struct msghdr message;
1382 char buffer[64];
1383 struct iovec iov[2];
1384
1385 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
1386
1387 nlh = (struct nlmsghdr *)buffer;
1388 nlh->nlmsg_seq = 0;
1389 nlh->nlmsg_pid = getpid();
1390 nlh->nlmsg_type = NLMSG_DONE;
1391 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
1392 nlh->nlmsg_flags = 0;
1393
1394 iov[0].iov_base = nlh;
1395 iov[0].iov_len = sizeof(*nlh);
1396
1397 iov[1].iov_base = msg;
1398 iov[1].iov_len = size;
1399
1400 memset(&message, 0, sizeof(message));
1401 message.msg_name = &addr;
1402 message.msg_namelen = sizeof(addr);
1403 message.msg_iov = iov;
1404 message.msg_iovlen = 2;
1405
1406 return sendmsg(fd, &message, 0);
1407}
1408
1409int main(void)
1410{
1411 int fd, len, sock_opt;
1412 int error;
1413 struct cn_msg *message;
1414 struct pollfd pfd;
1415 struct nlmsghdr *incoming_msg;
1416 struct cn_msg *incoming_cn_msg;
1417 struct hv_kvp_msg *hv_msg;
1418 char *p;
1419 char *key_value;
1420 char *key_name;
1421 int op;
1422 int pool;
1423 char *if_name;
1424 struct hv_kvp_ipaddr_value *kvp_ip_val;
1425
1426 daemon(1, 0);
1427 openlog("KVP", 0, LOG_USER);
1428 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1429 /*
1430 * Retrieve OS release information.
1431 */
1432 kvp_get_os_info();
1433
1434 if (kvp_file_init()) {
1435 syslog(LOG_ERR, "Failed to initialize the pools");
1436 exit(EXIT_FAILURE);
1437 }
1438
1439 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
1440 if (fd < 0) {
1441 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
1442 exit(EXIT_FAILURE);
1443 }
1444 addr.nl_family = AF_NETLINK;
1445 addr.nl_pad = 0;
1446 addr.nl_pid = 0;
1447 addr.nl_groups = CN_KVP_IDX;
1448
1449
1450 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
1451 if (error < 0) {
1452 syslog(LOG_ERR, "bind failed; error:%d", error);
1453 close(fd);
1454 exit(EXIT_FAILURE);
1455 }
1456 sock_opt = addr.nl_groups;
1457 setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
1458 /*
1459 * Register ourselves with the kernel.
1460 */
1461 message = (struct cn_msg *)kvp_send_buffer;
1462 message->id.idx = CN_KVP_IDX;
1463 message->id.val = CN_KVP_VAL;
1464
1465 hv_msg = (struct hv_kvp_msg *)message->data;
1466 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1467 message->ack = 0;
1468 message->len = sizeof(struct hv_kvp_msg);
1469
1470 len = netlink_send(fd, message);
1471 if (len < 0) {
1472 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
1473 close(fd);
1474 exit(EXIT_FAILURE);
1475 }
1476
1477 pfd.fd = fd;
1478
1479 while (1) {
1480 struct sockaddr *addr_p = (struct sockaddr *) &addr;
1481 socklen_t addr_l = sizeof(addr);
1482 pfd.events = POLLIN;
1483 pfd.revents = 0;
1484 poll(&pfd, 1, -1);
1485
1486 len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
1487 addr_p, &addr_l);
1488
1489 if (len < 0) {
1490 syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
1491 addr.nl_pid, errno, strerror(errno));
1492 close(fd);
1493 return -1;
1494 }
1495
1496 if (addr.nl_pid) {
1497 syslog(LOG_WARNING, "Received packet from untrusted pid:%u",
1498 addr.nl_pid);
1499 continue;
1500 }
1501
1502 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
1503 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
1504 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1505
1506 /*
1507 * We will use the KVP header information to pass back
1508 * the error from this daemon. So, first copy the state
1509 * and set the error code to success.
1510 */
1511 op = hv_msg->kvp_hdr.operation;
1512 pool = hv_msg->kvp_hdr.pool;
1513 hv_msg->error = HV_S_OK;
1514
1515 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1516 /*
1517 * Driver is registering with us; stash away the version
1518 * information.
1519 */
1520 in_hand_shake = 0;
1521 p = (char *)hv_msg->body.kvp_register.version;
1522 lic_version = malloc(strlen(p) + 1);
1523 if (lic_version) {
1524 strcpy(lic_version, p);
1525 syslog(LOG_INFO, "KVP LIC Version: %s",
1526 lic_version);
1527 } else {
1528 syslog(LOG_ERR, "malloc failed");
1529 }
1530 continue;
1531 }
1532
1533 switch (op) {
1534 case KVP_OP_GET_IP_INFO:
1535 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1536 if_name =
1537 kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
1538
1539 if (if_name == NULL) {
1540 /*
1541 * We could not map the mac address to an
1542 * interface name; return error.
1543 */
1544 hv_msg->error = HV_E_FAIL;
1545 break;
1546 }
1547 error = kvp_get_ip_info(
1548 0, if_name, KVP_OP_GET_IP_INFO,
1549 kvp_ip_val,
1550 (MAX_IP_ADDR_SIZE * 2));
1551
1552 if (error)
1553 hv_msg->error = error;
1554
1555 free(if_name);
1556 break;
1557
1558 case KVP_OP_SET_IP_INFO:
1559 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1560 if_name = kvp_get_if_name(
1561 (char *)kvp_ip_val->adapter_id);
1562 if (if_name == NULL) {
1563 /*
1564 * We could not map the guid to an
1565 * interface name; return error.
1566 */
1567 hv_msg->error = HV_GUID_NOTFOUND;
1568 break;
1569 }
1570 error = kvp_set_ip_info(if_name, kvp_ip_val);
1571 if (error)
1572 hv_msg->error = error;
1573
1574 free(if_name);
1575 break;
1576
1577 case KVP_OP_SET:
1578 if (kvp_key_add_or_modify(pool,
1579 hv_msg->body.kvp_set.data.key,
1580 hv_msg->body.kvp_set.data.key_size,
1581 hv_msg->body.kvp_set.data.value,
1582 hv_msg->body.kvp_set.data.value_size))
1583 hv_msg->error = HV_S_CONT;
1584 break;
1585
1586 case KVP_OP_GET:
1587 if (kvp_get_value(pool,
1588 hv_msg->body.kvp_set.data.key,
1589 hv_msg->body.kvp_set.data.key_size,
1590 hv_msg->body.kvp_set.data.value,
1591 hv_msg->body.kvp_set.data.value_size))
1592 hv_msg->error = HV_S_CONT;
1593 break;
1594
1595 case KVP_OP_DELETE:
1596 if (kvp_key_delete(pool,
1597 hv_msg->body.kvp_delete.key,
1598 hv_msg->body.kvp_delete.key_size))
1599 hv_msg->error = HV_S_CONT;
1600 break;
1601
1602 default:
1603 break;
1604 }
1605
1606 if (op != KVP_OP_ENUMERATE)
1607 goto kvp_done;
1608
1609 /*
1610 * If the pool is KVP_POOL_AUTO, dynamically generate
1611 * both the key and the value; if not read from the
1612 * appropriate pool.
1613 */
1614 if (pool != KVP_POOL_AUTO) {
1615 if (kvp_pool_enumerate(pool,
1616 hv_msg->body.kvp_enum_data.index,
1617 hv_msg->body.kvp_enum_data.data.key,
1618 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1619 hv_msg->body.kvp_enum_data.data.value,
1620 HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1621 hv_msg->error = HV_S_CONT;
1622 goto kvp_done;
1623 }
1624
1625 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
1626 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1627 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1628
1629 switch (hv_msg->body.kvp_enum_data.index) {
1630 case FullyQualifiedDomainName:
1631 kvp_get_domain_name(key_value,
1632 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1633 strcpy(key_name, "FullyQualifiedDomainName");
1634 break;
1635 case IntegrationServicesVersion:
1636 strcpy(key_name, "IntegrationServicesVersion");
1637 strcpy(key_value, lic_version);
1638 break;
1639 case NetworkAddressIPv4:
1640 kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1641 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1642 strcpy(key_name, "NetworkAddressIPv4");
1643 break;
1644 case NetworkAddressIPv6:
1645 kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1646 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1647 strcpy(key_name, "NetworkAddressIPv6");
1648 break;
1649 case OSBuildNumber:
1650 strcpy(key_value, os_build);
1651 strcpy(key_name, "OSBuildNumber");
1652 break;
1653 case OSName:
1654 strcpy(key_value, os_name);
1655 strcpy(key_name, "OSName");
1656 break;
1657 case OSMajorVersion:
1658 strcpy(key_value, os_major);
1659 strcpy(key_name, "OSMajorVersion");
1660 break;
1661 case OSMinorVersion:
1662 strcpy(key_value, os_minor);
1663 strcpy(key_name, "OSMinorVersion");
1664 break;
1665 case OSVersion:
1666 strcpy(key_value, os_version);
1667 strcpy(key_name, "OSVersion");
1668 break;
1669 case ProcessorArchitecture:
1670 strcpy(key_value, processor_arch);
1671 strcpy(key_name, "ProcessorArchitecture");
1672 break;
1673 default:
1674 hv_msg->error = HV_S_CONT;
1675 break;
1676 }
1677 /*
1678 * Send the value back to the kernel. The response is
1679 * already in the receive buffer. Update the cn_msg header to
1680 * reflect the key value that has been added to the message
1681 */
1682kvp_done:
1683
1684 incoming_cn_msg->id.idx = CN_KVP_IDX;
1685 incoming_cn_msg->id.val = CN_KVP_VAL;
1686 incoming_cn_msg->ack = 0;
1687 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
1688
1689 len = netlink_send(fd, incoming_cn_msg);
1690 if (len < 0) {
1691 syslog(LOG_ERR, "net_link send failed; error:%d", len);
1692 exit(EXIT_FAILURE);
1693 }
1694 }
1695
1696}
diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh
deleted file mode 100755
index 3e9427e08d8..00000000000
--- a/tools/hv/hv_set_ifconfig.sh
+++ /dev/null
@@ -1,68 +0,0 @@
1#!/bin/bash
2
3# This example script activates an interface based on the specified
4# configuration.
5#
6# In the interest of keeping the KVP daemon code free of distro specific
7# information; the kvp daemon code invokes this external script to configure
8# the interface.
9#
10# The only argument to this script is the configuration file that is to
11# be used to configure the interface.
12#
13# Each Distro is expected to implement this script in a distro specific
14# fashion. For instance on Distros that ship with Network Manager enabled,
15# this script can be based on the Network Manager APIs for configuring the
16# interface.
17#
18# This example script is based on a RHEL environment.
19#
20# Here is the format of the ip configuration file:
21#
22# HWADDR=macaddr
23# IF_NAME=interface name
24# DHCP=yes (This is optional; if yes, DHCP is configured)
25#
26# IPADDR=ipaddr1
27# IPADDR_1=ipaddr2
28# IPADDR_x=ipaddry (where y = x + 1)
29#
30# NETMASK=netmask1
31# NETMASK_x=netmasky (where y = x + 1)
32#
33# GATEWAY=ipaddr1
34# GATEWAY_x=ipaddry (where y = x + 1)
35#
36# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
37#
38# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
39# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
40# IPV6NETMASK.
41#
42# The host can specify multiple ipv4 and ipv6 addresses to be
43# configured for the interface. Furthermore, the configuration
44# needs to be persistent. A subsequent GET call on the interface
45# is expected to return the configuration that is set via the SET
46# call.
47#
48
49
50
51echo "IPV6INIT=yes" >> $1
52echo "NM_CONTROLLED=no" >> $1
53echo "PEERDNS=yes" >> $1
54echo "ONBOOT=yes" >> $1
55
56dhcp=$(grep "DHCP" $1 2>/dev/null)
57if [ "$dhcp" != "" ];
58then
59echo "BOOTPROTO=dhcp" >> $1;
60fi
61
62cp $1 /etc/sysconfig/network-scripts/
63
64
65interface=$(echo $1 | awk -F - '{ print $2 }')
66
67/sbin/ifdown $interface 2>/dev/null
68/sbin/ifup $interfac 2>/dev/null
diff --git a/tools/include/tools/be_byteshift.h b/tools/include/tools/be_byteshift.h
deleted file mode 100644
index f4912e2668b..00000000000
--- a/tools/include/tools/be_byteshift.h
+++ /dev/null
@@ -1,70 +0,0 @@
1#ifndef _TOOLS_BE_BYTESHIFT_H
2#define _TOOLS_BE_BYTESHIFT_H
3
4#include <linux/types.h>
5
6static inline __u16 __get_unaligned_be16(const __u8 *p)
7{
8 return p[0] << 8 | p[1];
9}
10
11static inline __u32 __get_unaligned_be32(const __u8 *p)
12{
13 return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
14}
15
16static inline __u64 __get_unaligned_be64(const __u8 *p)
17{
18 return (__u64)__get_unaligned_be32(p) << 32 |
19 __get_unaligned_be32(p + 4);
20}
21
22static inline void __put_unaligned_be16(__u16 val, __u8 *p)
23{
24 *p++ = val >> 8;
25 *p++ = val;
26}
27
28static inline void __put_unaligned_be32(__u32 val, __u8 *p)
29{
30 __put_unaligned_be16(val >> 16, p);
31 __put_unaligned_be16(val, p + 2);
32}
33
34static inline void __put_unaligned_be64(__u64 val, __u8 *p)
35{
36 __put_unaligned_be32(val >> 32, p);
37 __put_unaligned_be32(val, p + 4);
38}
39
40static inline __u16 get_unaligned_be16(const void *p)
41{
42 return __get_unaligned_be16((const __u8 *)p);
43}
44
45static inline __u32 get_unaligned_be32(const void *p)
46{
47 return __get_unaligned_be32((const __u8 *)p);
48}
49
50static inline __u64 get_unaligned_be64(const void *p)
51{
52 return __get_unaligned_be64((const __u8 *)p);
53}
54
55static inline void put_unaligned_be16(__u16 val, void *p)
56{
57 __put_unaligned_be16(val, p);
58}
59
60static inline void put_unaligned_be32(__u32 val, void *p)
61{
62 __put_unaligned_be32(val, p);
63}
64
65static inline void put_unaligned_be64(__u64 val, void *p)
66{
67 __put_unaligned_be64(val, p);
68}
69
70#endif /* _TOOLS_BE_BYTESHIFT_H */
diff --git a/tools/include/tools/le_byteshift.h b/tools/include/tools/le_byteshift.h
deleted file mode 100644
index c99d45a68bd..00000000000
--- a/tools/include/tools/le_byteshift.h
+++ /dev/null
@@ -1,70 +0,0 @@
1#ifndef _TOOLS_LE_BYTESHIFT_H
2#define _TOOLS_LE_BYTESHIFT_H
3
4#include <linux/types.h>
5
6static inline __u16 __get_unaligned_le16(const __u8 *p)
7{
8 return p[0] | p[1] << 8;
9}
10
11static inline __u32 __get_unaligned_le32(const __u8 *p)
12{
13 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
14}
15
16static inline __u64 __get_unaligned_le64(const __u8 *p)
17{
18 return (__u64)__get_unaligned_le32(p + 4) << 32 |
19 __get_unaligned_le32(p);
20}
21
22static inline void __put_unaligned_le16(__u16 val, __u8 *p)
23{
24 *p++ = val;
25 *p++ = val >> 8;
26}
27
28static inline void __put_unaligned_le32(__u32 val, __u8 *p)
29{
30 __put_unaligned_le16(val >> 16, p + 2);
31 __put_unaligned_le16(val, p);
32}
33
34static inline void __put_unaligned_le64(__u64 val, __u8 *p)
35{
36 __put_unaligned_le32(val >> 32, p + 4);
37 __put_unaligned_le32(val, p);
38}
39
40static inline __u16 get_unaligned_le16(const void *p)
41{
42 return __get_unaligned_le16((const __u8 *)p);
43}
44
45static inline __u32 get_unaligned_le32(const void *p)
46{
47 return __get_unaligned_le32((const __u8 *)p);
48}
49
50static inline __u64 get_unaligned_le64(const void *p)
51{
52 return __get_unaligned_le64((const __u8 *)p);
53}
54
55static inline void put_unaligned_le16(__u16 val, void *p)
56{
57 __put_unaligned_le16(val, p);
58}
59
60static inline void put_unaligned_le32(__u32 val, void *p)
61{
62 __put_unaligned_le32(val, p);
63}
64
65static inline void put_unaligned_le64(__u64 val, void *p)
66{
67 __put_unaligned_le64(val, p);
68}
69
70#endif /* _TOOLS_LE_BYTESHIFT_H */
diff --git a/tools/lguest/Makefile b/tools/lguest/Makefile
deleted file mode 100644
index 0ac34206f7a..00000000000
--- a/tools/lguest/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
1# This creates the demonstration utility "lguest" which runs a Linux guest.
2# Missing headers? Add "-I../../../include -I../../../arch/x86/include"
3CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE
4
5all: lguest
6
7clean:
8 rm -f lguest
diff --git a/tools/lguest/extract b/tools/lguest/extract
deleted file mode 100644
index 7730bb6e4b9..00000000000
--- a/tools/lguest/extract
+++ /dev/null
@@ -1,58 +0,0 @@
1#! /bin/sh
2
3set -e
4
5PREFIX=$1
6shift
7
8trap 'rm -r $TMPDIR' 0
9TMPDIR=`mktemp -d`
10
11exec 3>/dev/null
12for f; do
13 while IFS="
14" read -r LINE; do
15 case "$LINE" in
16 *$PREFIX:[0-9]*:\**)
17 NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
18 if [ -f $TMPDIR/$NUM ]; then
19 echo "$TMPDIR/$NUM already exits prior to $f"
20 exit 1
21 fi
22 exec 3>>$TMPDIR/$NUM
23 echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
24 /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3
25 ;;
26 *$PREFIX:[0-9]*)
27 NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
28 if [ -f $TMPDIR/$NUM ]; then
29 echo "$TMPDIR/$NUM already exits prior to $f"
30 exit 1
31 fi
32 exec 3>>$TMPDIR/$NUM
33 echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
34 /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3
35 ;;
36 *:\**)
37 /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3
38 echo >&3
39 exec 3>/dev/null
40 ;;
41 *)
42 /bin/echo "$LINE" >&3
43 ;;
44 esac
45 done < $f
46 echo >&3
47 exec 3>/dev/null
48done
49
50LASTFILE=""
51for f in $TMPDIR/*; do
52 if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then
53 LASTFILE=$(cat $TMPDIR/.$(basename $f) )
54 echo "[ $LASTFILE ]"
55 fi
56 cat $f
57done
58
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
deleted file mode 100644
index 07a03452c22..00000000000
--- a/tools/lguest/lguest.c
+++ /dev/null
@@ -1,2052 +0,0 @@
1/*P:100
2 * This is the Launcher code, a simple program which lays out the "physical"
3 * memory for the new Guest by mapping the kernel image and the virtual
4 * devices, then opens /dev/lguest to tell the kernel about the Guest and
5 * control it.
6:*/
7#define _LARGEFILE64_SOURCE
8#define _GNU_SOURCE
9#include <stdio.h>
10#include <string.h>
11#include <unistd.h>
12#include <err.h>
13#include <stdint.h>
14#include <stdlib.h>
15#include <elf.h>
16#include <sys/mman.h>
17#include <sys/param.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/wait.h>
21#include <sys/eventfd.h>
22#include <fcntl.h>
23#include <stdbool.h>
24#include <errno.h>
25#include <ctype.h>
26#include <sys/socket.h>
27#include <sys/ioctl.h>
28#include <sys/time.h>
29#include <time.h>
30#include <netinet/in.h>
31#include <net/if.h>
32#include <linux/sockios.h>
33#include <linux/if_tun.h>
34#include <sys/uio.h>
35#include <termios.h>
36#include <getopt.h>
37#include <assert.h>
38#include <sched.h>
39#include <limits.h>
40#include <stddef.h>
41#include <signal.h>
42#include <pwd.h>
43#include <grp.h>
44
45#include <linux/virtio_config.h>
46#include <linux/virtio_net.h>
47#include <linux/virtio_blk.h>
48#include <linux/virtio_console.h>
49#include <linux/virtio_rng.h>
50#include <linux/virtio_ring.h>
51#include <asm/bootparam.h>
52#include "../../include/linux/lguest_launcher.h"
53/*L:110
54 * We can ignore the 43 include files we need for this program, but I do want
55 * to draw attention to the use of kernel-style types.
56 *
57 * As Linus said, "C is a Spartan language, and so should your naming be." I
58 * like these abbreviations, so we define them here. Note that u64 is always
59 * unsigned long long, which works on all Linux systems: this means that we can
60 * use %llu in printf for any u64.
61 */
62typedef unsigned long long u64;
63typedef uint32_t u32;
64typedef uint16_t u16;
65typedef uint8_t u8;
66/*:*/
67
68#define BRIDGE_PFX "bridge:"
69#ifndef SIOCBRADDIF
70#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
71#endif
72/* We can have up to 256 pages for devices. */
73#define DEVICE_PAGES 256
74/* This will occupy 3 pages: it must be a power of 2. */
75#define VIRTQUEUE_NUM 256
76
77/*L:120
78 * verbose is both a global flag and a macro. The C preprocessor allows
79 * this, and although I wouldn't recommend it, it works quite nicely here.
80 */
81static bool verbose;
82#define verbose(args...) \
83 do { if (verbose) printf(args); } while(0)
84/*:*/
85
86/* The pointer to the start of guest memory. */
87static void *guest_base;
88/* The maximum guest physical address allowed, and maximum possible. */
89static unsigned long guest_limit, guest_max;
90/* The /dev/lguest file descriptor. */
91static int lguest_fd;
92
93/* a per-cpu variable indicating whose vcpu is currently running */
94static unsigned int __thread cpu_id;
95
96/* This is our list of devices. */
97struct device_list {
98 /* Counter to assign interrupt numbers. */
99 unsigned int next_irq;
100
101 /* Counter to print out convenient device numbers. */
102 unsigned int device_num;
103
104 /* The descriptor page for the devices. */
105 u8 *descpage;
106
107 /* A single linked list of devices. */
108 struct device *dev;
109 /* And a pointer to the last device for easy append. */
110 struct device *lastdev;
111};
112
113/* The list of Guest devices, based on command line arguments. */
114static struct device_list devices;
115
116/* The device structure describes a single device. */
117struct device {
118 /* The linked-list pointer. */
119 struct device *next;
120
121 /* The device's descriptor, as mapped into the Guest. */
122 struct lguest_device_desc *desc;
123
124 /* We can't trust desc values once Guest has booted: we use these. */
125 unsigned int feature_len;
126 unsigned int num_vq;
127
128 /* The name of this device, for --verbose. */
129 const char *name;
130
131 /* Any queues attached to this device */
132 struct virtqueue *vq;
133
134 /* Is it operational */
135 bool running;
136
137 /* Device-specific data. */
138 void *priv;
139};
140
141/* The virtqueue structure describes a queue attached to a device. */
142struct virtqueue {
143 struct virtqueue *next;
144
145 /* Which device owns me. */
146 struct device *dev;
147
148 /* The configuration for this queue. */
149 struct lguest_vqconfig config;
150
151 /* The actual ring of buffers. */
152 struct vring vring;
153
154 /* Last available index we saw. */
155 u16 last_avail_idx;
156
157 /* How many are used since we sent last irq? */
158 unsigned int pending_used;
159
160 /* Eventfd where Guest notifications arrive. */
161 int eventfd;
162
163 /* Function for the thread which is servicing this virtqueue. */
164 void (*service)(struct virtqueue *vq);
165 pid_t thread;
166};
167
168/* Remember the arguments to the program so we can "reboot" */
169static char **main_args;
170
171/* The original tty settings to restore on exit. */
172static struct termios orig_term;
173
174/*
175 * We have to be careful with barriers: our devices are all run in separate
176 * threads and so we need to make sure that changes visible to the Guest happen
177 * in precise order.
178 */
179#define wmb() __asm__ __volatile__("" : : : "memory")
180#define mb() __asm__ __volatile__("" : : : "memory")
181
182/* Wrapper for the last available index. Makes it easier to change. */
183#define lg_last_avail(vq) ((vq)->last_avail_idx)
184
185/*
186 * The virtio configuration space is defined to be little-endian. x86 is
187 * little-endian too, but it's nice to be explicit so we have these helpers.
188 */
189#define cpu_to_le16(v16) (v16)
190#define cpu_to_le32(v32) (v32)
191#define cpu_to_le64(v64) (v64)
192#define le16_to_cpu(v16) (v16)
193#define le32_to_cpu(v32) (v32)
194#define le64_to_cpu(v64) (v64)
195
196/* Is this iovec empty? */
197static bool iov_empty(const struct iovec iov[], unsigned int num_iov)
198{
199 unsigned int i;
200
201 for (i = 0; i < num_iov; i++)
202 if (iov[i].iov_len)
203 return false;
204 return true;
205}
206
207/* Take len bytes from the front of this iovec. */
208static void iov_consume(struct iovec iov[], unsigned num_iov,
209 void *dest, unsigned len)
210{
211 unsigned int i;
212
213 for (i = 0; i < num_iov; i++) {
214 unsigned int used;
215
216 used = iov[i].iov_len < len ? iov[i].iov_len : len;
217 if (dest) {
218 memcpy(dest, iov[i].iov_base, used);
219 dest += used;
220 }
221 iov[i].iov_base += used;
222 iov[i].iov_len -= used;
223 len -= used;
224 }
225 if (len != 0)
226 errx(1, "iovec too short!");
227}
228
229/* The device virtqueue descriptors are followed by feature bitmasks. */
230static u8 *get_feature_bits(struct device *dev)
231{
232 return (u8 *)(dev->desc + 1)
233 + dev->num_vq * sizeof(struct lguest_vqconfig);
234}
235
236/*L:100
237 * The Launcher code itself takes us out into userspace, that scary place where
238 * pointers run wild and free! Unfortunately, like most userspace programs,
239 * it's quite boring (which is why everyone likes to hack on the kernel!).
240 * Perhaps if you make up an Lguest Drinking Game at this point, it will get
241 * you through this section. Or, maybe not.
242 *
243 * The Launcher sets up a big chunk of memory to be the Guest's "physical"
244 * memory and stores it in "guest_base". In other words, Guest physical ==
245 * Launcher virtual with an offset.
246 *
247 * This can be tough to get your head around, but usually it just means that we
248 * use these trivial conversion functions when the Guest gives us its
249 * "physical" addresses:
250 */
251static void *from_guest_phys(unsigned long addr)
252{
253 return guest_base + addr;
254}
255
256static unsigned long to_guest_phys(const void *addr)
257{
258 return (addr - guest_base);
259}
260
261/*L:130
262 * Loading the Kernel.
263 *
264 * We start with couple of simple helper routines. open_or_die() avoids
265 * error-checking code cluttering the callers:
266 */
267static int open_or_die(const char *name, int flags)
268{
269 int fd = open(name, flags);
270 if (fd < 0)
271 err(1, "Failed to open %s", name);
272 return fd;
273}
274
275/* map_zeroed_pages() takes a number of pages. */
276static void *map_zeroed_pages(unsigned int num)
277{
278 int fd = open_or_die("/dev/zero", O_RDONLY);
279 void *addr;
280
281 /*
282 * We use a private mapping (ie. if we write to the page, it will be
283 * copied). We allocate an extra two pages PROT_NONE to act as guard
284 * pages against read/write attempts that exceed allocated space.
285 */
286 addr = mmap(NULL, getpagesize() * (num+2),
287 PROT_NONE, MAP_PRIVATE, fd, 0);
288
289 if (addr == MAP_FAILED)
290 err(1, "Mmapping %u pages of /dev/zero", num);
291
292 if (mprotect(addr + getpagesize(), getpagesize() * num,
293 PROT_READ|PROT_WRITE) == -1)
294 err(1, "mprotect rw %u pages failed", num);
295
296 /*
297 * One neat mmap feature is that you can close the fd, and it
298 * stays mapped.
299 */
300 close(fd);
301
302 /* Return address after PROT_NONE page */
303 return addr + getpagesize();
304}
305
306/* Get some more pages for a device. */
307static void *get_pages(unsigned int num)
308{
309 void *addr = from_guest_phys(guest_limit);
310
311 guest_limit += num * getpagesize();
312 if (guest_limit > guest_max)
313 errx(1, "Not enough memory for devices");
314 return addr;
315}
316
317/*
318 * This routine is used to load the kernel or initrd. It tries mmap, but if
319 * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries),
320 * it falls back to reading the memory in.
321 */
322static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
323{
324 ssize_t r;
325
326 /*
327 * We map writable even though for some segments are marked read-only.
328 * The kernel really wants to be writable: it patches its own
329 * instructions.
330 *
331 * MAP_PRIVATE means that the page won't be copied until a write is
332 * done to it. This allows us to share untouched memory between
333 * Guests.
334 */
335 if (mmap(addr, len, PROT_READ|PROT_WRITE,
336 MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
337 return;
338
339 /* pread does a seek and a read in one shot: saves a few lines. */
340 r = pread(fd, addr, len, offset);
341 if (r != len)
342 err(1, "Reading offset %lu len %lu gave %zi", offset, len, r);
343}
344
345/*
346 * This routine takes an open vmlinux image, which is in ELF, and maps it into
347 * the Guest memory. ELF = Embedded Linking Format, which is the format used
348 * by all modern binaries on Linux including the kernel.
349 *
350 * The ELF headers give *two* addresses: a physical address, and a virtual
351 * address. We use the physical address; the Guest will map itself to the
352 * virtual address.
353 *
354 * We return the starting address.
355 */
356static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
357{
358 Elf32_Phdr phdr[ehdr->e_phnum];
359 unsigned int i;
360
361 /*
362 * Sanity checks on the main ELF header: an x86 executable with a
363 * reasonable number of correctly-sized program headers.
364 */
365 if (ehdr->e_type != ET_EXEC
366 || ehdr->e_machine != EM_386
367 || ehdr->e_phentsize != sizeof(Elf32_Phdr)
368 || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
369 errx(1, "Malformed elf header");
370
371 /*
372 * An ELF executable contains an ELF header and a number of "program"
373 * headers which indicate which parts ("segments") of the program to
374 * load where.
375 */
376
377 /* We read in all the program headers at once: */
378 if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
379 err(1, "Seeking to program headers");
380 if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
381 err(1, "Reading program headers");
382
383 /*
384 * Try all the headers: there are usually only three. A read-only one,
385 * a read-write one, and a "note" section which we don't load.
386 */
387 for (i = 0; i < ehdr->e_phnum; i++) {
388 /* If this isn't a loadable segment, we ignore it */
389 if (phdr[i].p_type != PT_LOAD)
390 continue;
391
392 verbose("Section %i: size %i addr %p\n",
393 i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
394
395 /* We map this section of the file at its physical address. */
396 map_at(elf_fd, from_guest_phys(phdr[i].p_paddr),
397 phdr[i].p_offset, phdr[i].p_filesz);
398 }
399
400 /* The entry point is given in the ELF header. */
401 return ehdr->e_entry;
402}
403
404/*L:150
405 * A bzImage, unlike an ELF file, is not meant to be loaded. You're supposed
406 * to jump into it and it will unpack itself. We used to have to perform some
407 * hairy magic because the unpacking code scared me.
408 *
409 * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote
410 * a small patch to jump over the tricky bits in the Guest, so now we just read
411 * the funky header so we know where in the file to load, and away we go!
412 */
413static unsigned long load_bzimage(int fd)
414{
415 struct boot_params boot;
416 int r;
417 /* Modern bzImages get loaded at 1M. */
418 void *p = from_guest_phys(0x100000);
419
420 /*
421 * Go back to the start of the file and read the header. It should be
422 * a Linux boot header (see Documentation/x86/boot.txt)
423 */
424 lseek(fd, 0, SEEK_SET);
425 read(fd, &boot, sizeof(boot));
426
427 /* Inside the setup_hdr, we expect the magic "HdrS" */
428 if (memcmp(&boot.hdr.header, "HdrS", 4) != 0)
429 errx(1, "This doesn't look like a bzImage to me");
430
431 /* Skip over the extra sectors of the header. */
432 lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET);
433
434 /* Now read everything into memory. in nice big chunks. */
435 while ((r = read(fd, p, 65536)) > 0)
436 p += r;
437
438 /* Finally, code32_start tells us where to enter the kernel. */
439 return boot.hdr.code32_start;
440}
441
442/*L:140
443 * Loading the kernel is easy when it's a "vmlinux", but most kernels
444 * come wrapped up in the self-decompressing "bzImage" format. With a little
445 * work, we can load those, too.
446 */
447static unsigned long load_kernel(int fd)
448{
449 Elf32_Ehdr hdr;
450
451 /* Read in the first few bytes. */
452 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
453 err(1, "Reading kernel");
454
455 /* If it's an ELF file, it starts with "\177ELF" */
456 if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
457 return map_elf(fd, &hdr);
458
459 /* Otherwise we assume it's a bzImage, and try to load it. */
460 return load_bzimage(fd);
461}
462
463/*
464 * This is a trivial little helper to align pages. Andi Kleen hated it because
465 * it calls getpagesize() twice: "it's dumb code."
466 *
467 * Kernel guys get really het up about optimization, even when it's not
468 * necessary. I leave this code as a reaction against that.
469 */
470static inline unsigned long page_align(unsigned long addr)
471{
472 /* Add upwards and truncate downwards. */
473 return ((addr + getpagesize()-1) & ~(getpagesize()-1));
474}
475
476/*L:180
477 * An "initial ram disk" is a disk image loaded into memory along with the
478 * kernel which the kernel can use to boot from without needing any drivers.
479 * Most distributions now use this as standard: the initrd contains the code to
480 * load the appropriate driver modules for the current machine.
481 *
482 * Importantly, James Morris works for RedHat, and Fedora uses initrds for its
483 * kernels. He sent me this (and tells me when I break it).
484 */
485static unsigned long load_initrd(const char *name, unsigned long mem)
486{
487 int ifd;
488 struct stat st;
489 unsigned long len;
490
491 ifd = open_or_die(name, O_RDONLY);
492 /* fstat() is needed to get the file size. */
493 if (fstat(ifd, &st) < 0)
494 err(1, "fstat() on initrd '%s'", name);
495
496 /*
497 * We map the initrd at the top of memory, but mmap wants it to be
498 * page-aligned, so we round the size up for that.
499 */
500 len = page_align(st.st_size);
501 map_at(ifd, from_guest_phys(mem - len), 0, st.st_size);
502 /*
503 * Once a file is mapped, you can close the file descriptor. It's a
504 * little odd, but quite useful.
505 */
506 close(ifd);
507 verbose("mapped initrd %s size=%lu @ %p\n", name, len, (void*)mem-len);
508
509 /* We return the initrd size. */
510 return len;
511}
512/*:*/
513
514/*
515 * Simple routine to roll all the commandline arguments together with spaces
516 * between them.
517 */
518static void concat(char *dst, char *args[])
519{
520 unsigned int i, len = 0;
521
522 for (i = 0; args[i]; i++) {
523 if (i) {
524 strcat(dst+len, " ");
525 len++;
526 }
527 strcpy(dst+len, args[i]);
528 len += strlen(args[i]);
529 }
530 /* In case it's empty. */
531 dst[len] = '\0';
532}
533
534/*L:185
535 * This is where we actually tell the kernel to initialize the Guest. We
536 * saw the arguments it expects when we looked at initialize() in lguest_user.c:
537 * the base of Guest "physical" memory, the top physical page to allow and the
538 * entry point for the Guest.
539 */
540static void tell_kernel(unsigned long start)
541{
542 unsigned long args[] = { LHREQ_INITIALIZE,
543 (unsigned long)guest_base,
544 guest_limit / getpagesize(), start };
545 verbose("Guest: %p - %p (%#lx)\n",
546 guest_base, guest_base + guest_limit, guest_limit);
547 lguest_fd = open_or_die("/dev/lguest", O_RDWR);
548 if (write(lguest_fd, args, sizeof(args)) < 0)
549 err(1, "Writing to /dev/lguest");
550}
551/*:*/
552
553/*L:200
554 * Device Handling.
555 *
556 * When the Guest gives us a buffer, it sends an array of addresses and sizes.
557 * We need to make sure it's not trying to reach into the Launcher itself, so
558 * we have a convenient routine which checks it and exits with an error message
559 * if something funny is going on:
560 */
561static void *_check_pointer(unsigned long addr, unsigned int size,
562 unsigned int line)
563{
564 /*
565 * Check if the requested address and size exceeds the allocated memory,
566 * or addr + size wraps around.
567 */
568 if ((addr + size) > guest_limit || (addr + size) < addr)
569 errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
570 /*
571 * We return a pointer for the caller's convenience, now we know it's
572 * safe to use.
573 */
574 return from_guest_phys(addr);
575}
576/* A macro which transparently hands the line number to the real function. */
577#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
578
579/*
580 * Each buffer in the virtqueues is actually a chain of descriptors. This
581 * function returns the next descriptor in the chain, or vq->vring.num if we're
582 * at the end.
583 */
584static unsigned next_desc(struct vring_desc *desc,
585 unsigned int i, unsigned int max)
586{
587 unsigned int next;
588
589 /* If this descriptor says it doesn't chain, we're done. */
590 if (!(desc[i].flags & VRING_DESC_F_NEXT))
591 return max;
592
593 /* Check they're not leading us off end of descriptors. */
594 next = desc[i].next;
595 /* Make sure compiler knows to grab that: we don't want it changing! */
596 wmb();
597
598 if (next >= max)
599 errx(1, "Desc next is %u", next);
600
601 return next;
602}
603
604/*
605 * This actually sends the interrupt for this virtqueue, if we've used a
606 * buffer.
607 */
608static void trigger_irq(struct virtqueue *vq)
609{
610 unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
611
612 /* Don't inform them if nothing used. */
613 if (!vq->pending_used)
614 return;
615 vq->pending_used = 0;
616
617 /* If they don't want an interrupt, don't send one... */
618 if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) {
619 return;
620 }
621
622 /* Send the Guest an interrupt tell them we used something up. */
623 if (write(lguest_fd, buf, sizeof(buf)) != 0)
624 err(1, "Triggering irq %i", vq->config.irq);
625}
626
627/*
628 * This looks in the virtqueue for the first available buffer, and converts
629 * it to an iovec for convenient access. Since descriptors consist of some
630 * number of output then some number of input descriptors, it's actually two
631 * iovecs, but we pack them into one and note how many of each there were.
632 *
633 * This function waits if necessary, and returns the descriptor number found.
634 */
635static unsigned wait_for_vq_desc(struct virtqueue *vq,
636 struct iovec iov[],
637 unsigned int *out_num, unsigned int *in_num)
638{
639 unsigned int i, head, max;
640 struct vring_desc *desc;
641 u16 last_avail = lg_last_avail(vq);
642
643 /* There's nothing available? */
644 while (last_avail == vq->vring.avail->idx) {
645 u64 event;
646
647 /*
648 * Since we're about to sleep, now is a good time to tell the
649 * Guest about what we've used up to now.
650 */
651 trigger_irq(vq);
652
653 /* OK, now we need to know about added descriptors. */
654 vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
655
656 /*
657 * They could have slipped one in as we were doing that: make
658 * sure it's written, then check again.
659 */
660 mb();
661 if (last_avail != vq->vring.avail->idx) {
662 vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
663 break;
664 }
665
666 /* Nothing new? Wait for eventfd to tell us they refilled. */
667 if (read(vq->eventfd, &event, sizeof(event)) != sizeof(event))
668 errx(1, "Event read failed?");
669
670 /* We don't need to be notified again. */
671 vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
672 }
673
674 /* Check it isn't doing very strange things with descriptor numbers. */
675 if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num)
676 errx(1, "Guest moved used index from %u to %u",
677 last_avail, vq->vring.avail->idx);
678
679 /*
680 * Grab the next descriptor number they're advertising, and increment
681 * the index we've seen.
682 */
683 head = vq->vring.avail->ring[last_avail % vq->vring.num];
684 lg_last_avail(vq)++;
685
686 /* If their number is silly, that's a fatal mistake. */
687 if (head >= vq->vring.num)
688 errx(1, "Guest says index %u is available", head);
689
690 /* When we start there are none of either input nor output. */
691 *out_num = *in_num = 0;
692
693 max = vq->vring.num;
694 desc = vq->vring.desc;
695 i = head;
696
697 /*
698 * If this is an indirect entry, then this buffer contains a descriptor
699 * table which we handle as if it's any normal descriptor chain.
700 */
701 if (desc[i].flags & VRING_DESC_F_INDIRECT) {
702 if (desc[i].len % sizeof(struct vring_desc))
703 errx(1, "Invalid size for indirect buffer table");
704
705 max = desc[i].len / sizeof(struct vring_desc);
706 desc = check_pointer(desc[i].addr, desc[i].len);
707 i = 0;
708 }
709
710 do {
711 /* Grab the first descriptor, and check it's OK. */
712 iov[*out_num + *in_num].iov_len = desc[i].len;
713 iov[*out_num + *in_num].iov_base
714 = check_pointer(desc[i].addr, desc[i].len);
715 /* If this is an input descriptor, increment that count. */
716 if (desc[i].flags & VRING_DESC_F_WRITE)
717 (*in_num)++;
718 else {
719 /*
720 * If it's an output descriptor, they're all supposed
721 * to come before any input descriptors.
722 */
723 if (*in_num)
724 errx(1, "Descriptor has out after in");
725 (*out_num)++;
726 }
727
728 /* If we've got too many, that implies a descriptor loop. */
729 if (*out_num + *in_num > max)
730 errx(1, "Looped descriptor");
731 } while ((i = next_desc(desc, i, max)) != max);
732
733 return head;
734}
735
736/*
737 * After we've used one of their buffers, we tell the Guest about it. Sometime
738 * later we'll want to send them an interrupt using trigger_irq(); note that
739 * wait_for_vq_desc() does that for us if it has to wait.
740 */
741static void add_used(struct virtqueue *vq, unsigned int head, int len)
742{
743 struct vring_used_elem *used;
744
745 /*
746 * The virtqueue contains a ring of used buffers. Get a pointer to the
747 * next entry in that used ring.
748 */
749 used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
750 used->id = head;
751 used->len = len;
752 /* Make sure buffer is written before we update index. */
753 wmb();
754 vq->vring.used->idx++;
755 vq->pending_used++;
756}
757
758/* And here's the combo meal deal. Supersize me! */
759static void add_used_and_trigger(struct virtqueue *vq, unsigned head, int len)
760{
761 add_used(vq, head, len);
762 trigger_irq(vq);
763}
764
765/*
766 * The Console
767 *
768 * We associate some data with the console for our exit hack.
769 */
770struct console_abort {
771 /* How many times have they hit ^C? */
772 int count;
773 /* When did they start? */
774 struct timeval start;
775};
776
777/* This is the routine which handles console input (ie. stdin). */
778static void console_input(struct virtqueue *vq)
779{
780 int len;
781 unsigned int head, in_num, out_num;
782 struct console_abort *abort = vq->dev->priv;
783 struct iovec iov[vq->vring.num];
784
785 /* Make sure there's a descriptor available. */
786 head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
787 if (out_num)
788 errx(1, "Output buffers in console in queue?");
789
790 /* Read into it. This is where we usually wait. */
791 len = readv(STDIN_FILENO, iov, in_num);
792 if (len <= 0) {
793 /* Ran out of input? */
794 warnx("Failed to get console input, ignoring console.");
795 /*
796 * For simplicity, dying threads kill the whole Launcher. So
797 * just nap here.
798 */
799 for (;;)
800 pause();
801 }
802
803 /* Tell the Guest we used a buffer. */
804 add_used_and_trigger(vq, head, len);
805
806 /*
807 * Three ^C within one second? Exit.
808 *
809 * This is such a hack, but works surprisingly well. Each ^C has to
810 * be in a buffer by itself, so they can't be too fast. But we check
811 * that we get three within about a second, so they can't be too
812 * slow.
813 */
814 if (len != 1 || ((char *)iov[0].iov_base)[0] != 3) {
815 abort->count = 0;
816 return;
817 }
818
819 abort->count++;
820 if (abort->count == 1)
821 gettimeofday(&abort->start, NULL);
822 else if (abort->count == 3) {
823 struct timeval now;
824 gettimeofday(&now, NULL);
825 /* Kill all Launcher processes with SIGINT, like normal ^C */
826 if (now.tv_sec <= abort->start.tv_sec+1)
827 kill(0, SIGINT);
828 abort->count = 0;
829 }
830}
831
832/* This is the routine which handles console output (ie. stdout). */
833static void console_output(struct virtqueue *vq)
834{
835 unsigned int head, out, in;
836 struct iovec iov[vq->vring.num];
837
838 /* We usually wait in here, for the Guest to give us something. */
839 head = wait_for_vq_desc(vq, iov, &out, &in);
840 if (in)
841 errx(1, "Input buffers in console output queue?");
842
843 /* writev can return a partial write, so we loop here. */
844 while (!iov_empty(iov, out)) {
845 int len = writev(STDOUT_FILENO, iov, out);
846 if (len <= 0) {
847 warn("Write to stdout gave %i (%d)", len, errno);
848 break;
849 }
850 iov_consume(iov, out, NULL, len);
851 }
852
853 /*
854 * We're finished with that buffer: if we're going to sleep,
855 * wait_for_vq_desc() will prod the Guest with an interrupt.
856 */
857 add_used(vq, head, 0);
858}
859
860/*
861 * The Network
862 *
863 * Handling output for network is also simple: we get all the output buffers
864 * and write them to /dev/net/tun.
865 */
866struct net_info {
867 int tunfd;
868};
869
870static void net_output(struct virtqueue *vq)
871{
872 struct net_info *net_info = vq->dev->priv;
873 unsigned int head, out, in;
874 struct iovec iov[vq->vring.num];
875
876 /* We usually wait in here for the Guest to give us a packet. */
877 head = wait_for_vq_desc(vq, iov, &out, &in);
878 if (in)
879 errx(1, "Input buffers in net output queue?");
880 /*
881 * Send the whole thing through to /dev/net/tun. It expects the exact
882 * same format: what a coincidence!
883 */
884 if (writev(net_info->tunfd, iov, out) < 0)
885 warnx("Write to tun failed (%d)?", errno);
886
887 /*
888 * Done with that one; wait_for_vq_desc() will send the interrupt if
889 * all packets are processed.
890 */
891 add_used(vq, head, 0);
892}
893
894/*
895 * Handling network input is a bit trickier, because I've tried to optimize it.
896 *
897 * First we have a helper routine which tells is if from this file descriptor
898 * (ie. the /dev/net/tun device) will block:
899 */
900static bool will_block(int fd)
901{
902 fd_set fdset;
903 struct timeval zero = { 0, 0 };
904 FD_ZERO(&fdset);
905 FD_SET(fd, &fdset);
906 return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
907}
908
909/*
910 * This handles packets coming in from the tun device to our Guest. Like all
911 * service routines, it gets called again as soon as it returns, so you don't
912 * see a while(1) loop here.
913 */
914static void net_input(struct virtqueue *vq)
915{
916 int len;
917 unsigned int head, out, in;
918 struct iovec iov[vq->vring.num];
919 struct net_info *net_info = vq->dev->priv;
920
921 /*
922 * Get a descriptor to write an incoming packet into. This will also
923 * send an interrupt if they're out of descriptors.
924 */
925 head = wait_for_vq_desc(vq, iov, &out, &in);
926 if (out)
927 errx(1, "Output buffers in net input queue?");
928
929 /*
930 * If it looks like we'll block reading from the tun device, send them
931 * an interrupt.
932 */
933 if (vq->pending_used && will_block(net_info->tunfd))
934 trigger_irq(vq);
935
936 /*
937 * Read in the packet. This is where we normally wait (when there's no
938 * incoming network traffic).
939 */
940 len = readv(net_info->tunfd, iov, in);
941 if (len <= 0)
942 warn("Failed to read from tun (%d).", errno);
943
944 /*
945 * Mark that packet buffer as used, but don't interrupt here. We want
946 * to wait until we've done as much work as we can.
947 */
948 add_used(vq, head, len);
949}
950/*:*/
951
952/* This is the helper to create threads: run the service routine in a loop. */
953static int do_thread(void *_vq)
954{
955 struct virtqueue *vq = _vq;
956
957 for (;;)
958 vq->service(vq);
959 return 0;
960}
961
962/*
963 * When a child dies, we kill our entire process group with SIGTERM. This
964 * also has the side effect that the shell restores the console for us!
965 */
966static void kill_launcher(int signal)
967{
968 kill(0, SIGTERM);
969}
970
971static void reset_device(struct device *dev)
972{
973 struct virtqueue *vq;
974
975 verbose("Resetting device %s\n", dev->name);
976
977 /* Clear any features they've acked. */
978 memset(get_feature_bits(dev) + dev->feature_len, 0, dev->feature_len);
979
980 /* We're going to be explicitly killing threads, so ignore them. */
981 signal(SIGCHLD, SIG_IGN);
982
983 /* Zero out the virtqueues, get rid of their threads */
984 for (vq = dev->vq; vq; vq = vq->next) {
985 if (vq->thread != (pid_t)-1) {
986 kill(vq->thread, SIGTERM);
987 waitpid(vq->thread, NULL, 0);
988 vq->thread = (pid_t)-1;
989 }
990 memset(vq->vring.desc, 0,
991 vring_size(vq->config.num, LGUEST_VRING_ALIGN));
992 lg_last_avail(vq) = 0;
993 }
994 dev->running = false;
995
996 /* Now we care if threads die. */
997 signal(SIGCHLD, (void *)kill_launcher);
998}
999
1000/*L:216
1001 * This actually creates the thread which services the virtqueue for a device.
1002 */
1003static void create_thread(struct virtqueue *vq)
1004{
1005 /*
1006 * Create stack for thread. Since the stack grows upwards, we point
1007 * the stack pointer to the end of this region.
1008 */
1009 char *stack = malloc(32768);
1010 unsigned long args[] = { LHREQ_EVENTFD,
1011 vq->config.pfn*getpagesize(), 0 };
1012
1013 /* Create a zero-initialized eventfd. */
1014 vq->eventfd = eventfd(0, 0);
1015 if (vq->eventfd < 0)
1016 err(1, "Creating eventfd");
1017 args[2] = vq->eventfd;
1018
1019 /*
1020 * Attach an eventfd to this virtqueue: it will go off when the Guest
1021 * does an LHCALL_NOTIFY for this vq.
1022 */
1023 if (write(lguest_fd, &args, sizeof(args)) != 0)
1024 err(1, "Attaching eventfd");
1025
1026 /*
1027 * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so
1028 * we get a signal if it dies.
1029 */
1030 vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq);
1031 if (vq->thread == (pid_t)-1)
1032 err(1, "Creating clone");
1033
1034 /* We close our local copy now the child has it. */
1035 close(vq->eventfd);
1036}
1037
1038static void start_device(struct device *dev)
1039{
1040 unsigned int i;
1041 struct virtqueue *vq;
1042
1043 verbose("Device %s OK: offered", dev->name);
1044 for (i = 0; i < dev->feature_len; i++)
1045 verbose(" %02x", get_feature_bits(dev)[i]);
1046 verbose(", accepted");
1047 for (i = 0; i < dev->feature_len; i++)
1048 verbose(" %02x", get_feature_bits(dev)
1049 [dev->feature_len+i]);
1050
1051 for (vq = dev->vq; vq; vq = vq->next) {
1052 if (vq->service)
1053 create_thread(vq);
1054 }
1055 dev->running = true;
1056}
1057
1058static void cleanup_devices(void)
1059{
1060 struct device *dev;
1061
1062 for (dev = devices.dev; dev; dev = dev->next)
1063 reset_device(dev);
1064
1065 /* If we saved off the original terminal settings, restore them now. */
1066 if (orig_term.c_lflag & (ISIG|ICANON|ECHO))
1067 tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
1068}
1069
1070/* When the Guest tells us they updated the status field, we handle it. */
1071static void update_device_status(struct device *dev)
1072{
1073 /* A zero status is a reset, otherwise it's a set of flags. */
1074 if (dev->desc->status == 0)
1075 reset_device(dev);
1076 else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
1077 warnx("Device %s configuration FAILED", dev->name);
1078 if (dev->running)
1079 reset_device(dev);
1080 } else {
1081 if (dev->running)
1082 err(1, "Device %s features finalized twice", dev->name);
1083 start_device(dev);
1084 }
1085}
1086
1087/*L:215
1088 * This is the generic routine we call when the Guest uses LHCALL_NOTIFY. In
1089 * particular, it's used to notify us of device status changes during boot.
1090 */
1091static void handle_output(unsigned long addr)
1092{
1093 struct device *i;
1094
1095 /* Check each device. */
1096 for (i = devices.dev; i; i = i->next) {
1097 struct virtqueue *vq;
1098
1099 /*
1100 * Notifications to device descriptors mean they updated the
1101 * device status.
1102 */
1103 if (from_guest_phys(addr) == i->desc) {
1104 update_device_status(i);
1105 return;
1106 }
1107
1108 /* Devices should not be used before features are finalized. */
1109 for (vq = i->vq; vq; vq = vq->next) {
1110 if (addr != vq->config.pfn*getpagesize())
1111 continue;
1112 errx(1, "Notification on %s before setup!", i->name);
1113 }
1114 }
1115
1116 /*
1117 * Early console write is done using notify on a nul-terminated string
1118 * in Guest memory. It's also great for hacking debugging messages
1119 * into a Guest.
1120 */
1121 if (addr >= guest_limit)
1122 errx(1, "Bad NOTIFY %#lx", addr);
1123
1124 write(STDOUT_FILENO, from_guest_phys(addr),
1125 strnlen(from_guest_phys(addr), guest_limit - addr));
1126}
1127
1128/*L:190
1129 * Device Setup
1130 *
1131 * All devices need a descriptor so the Guest knows it exists, and a "struct
1132 * device" so the Launcher can keep track of it. We have common helper
1133 * routines to allocate and manage them.
1134 */
1135
1136/*
1137 * The layout of the device page is a "struct lguest_device_desc" followed by a
1138 * number of virtqueue descriptors, then two sets of feature bits, then an
1139 * array of configuration bytes. This routine returns the configuration
1140 * pointer.
1141 */
1142static u8 *device_config(const struct device *dev)
1143{
1144 return (void *)(dev->desc + 1)
1145 + dev->num_vq * sizeof(struct lguest_vqconfig)
1146 + dev->feature_len * 2;
1147}
1148
1149/*
1150 * This routine allocates a new "struct lguest_device_desc" from descriptor
1151 * table page just above the Guest's normal memory. It returns a pointer to
1152 * that descriptor.
1153 */
1154static struct lguest_device_desc *new_dev_desc(u16 type)
1155{
1156 struct lguest_device_desc d = { .type = type };
1157 void *p;
1158
1159 /* Figure out where the next device config is, based on the last one. */
1160 if (devices.lastdev)
1161 p = device_config(devices.lastdev)
1162 + devices.lastdev->desc->config_len;
1163 else
1164 p = devices.descpage;
1165
1166 /* We only have one page for all the descriptors. */
1167 if (p + sizeof(d) > (void *)devices.descpage + getpagesize())
1168 errx(1, "Too many devices");
1169
1170 /* p might not be aligned, so we memcpy in. */
1171 return memcpy(p, &d, sizeof(d));
1172}
1173
1174/*
1175 * Each device descriptor is followed by the description of its virtqueues. We
1176 * specify how many descriptors the virtqueue is to have.
1177 */
1178static void add_virtqueue(struct device *dev, unsigned int num_descs,
1179 void (*service)(struct virtqueue *))
1180{
1181 unsigned int pages;
1182 struct virtqueue **i, *vq = malloc(sizeof(*vq));
1183 void *p;
1184
1185 /* First we need some memory for this virtqueue. */
1186 pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1)
1187 / getpagesize();
1188 p = get_pages(pages);
1189
1190 /* Initialize the virtqueue */
1191 vq->next = NULL;
1192 vq->last_avail_idx = 0;
1193 vq->dev = dev;
1194
1195 /*
1196 * This is the routine the service thread will run, and its Process ID
1197 * once it's running.
1198 */
1199 vq->service = service;
1200 vq->thread = (pid_t)-1;
1201
1202 /* Initialize the configuration. */
1203 vq->config.num = num_descs;
1204 vq->config.irq = devices.next_irq++;
1205 vq->config.pfn = to_guest_phys(p) / getpagesize();
1206
1207 /* Initialize the vring. */
1208 vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN);
1209
1210 /*
1211 * Append virtqueue to this device's descriptor. We use
1212 * device_config() to get the end of the device's current virtqueues;
1213 * we check that we haven't added any config or feature information
1214 * yet, otherwise we'd be overwriting them.
1215 */
1216 assert(dev->desc->config_len == 0 && dev->desc->feature_len == 0);
1217 memcpy(device_config(dev), &vq->config, sizeof(vq->config));
1218 dev->num_vq++;
1219 dev->desc->num_vq++;
1220
1221 verbose("Virtqueue page %#lx\n", to_guest_phys(p));
1222
1223 /*
1224 * Add to tail of list, so dev->vq is first vq, dev->vq->next is
1225 * second.
1226 */
1227 for (i = &dev->vq; *i; i = &(*i)->next);
1228 *i = vq;
1229}
1230
1231/*
1232 * The first half of the feature bitmask is for us to advertise features. The
1233 * second half is for the Guest to accept features.
1234 */
1235static void add_feature(struct device *dev, unsigned bit)
1236{
1237 u8 *features = get_feature_bits(dev);
1238
1239 /* We can't extend the feature bits once we've added config bytes */
1240 if (dev->desc->feature_len <= bit / CHAR_BIT) {
1241 assert(dev->desc->config_len == 0);
1242 dev->feature_len = dev->desc->feature_len = (bit/CHAR_BIT) + 1;
1243 }
1244
1245 features[bit / CHAR_BIT] |= (1 << (bit % CHAR_BIT));
1246}
1247
1248/*
1249 * This routine sets the configuration fields for an existing device's
1250 * descriptor. It only works for the last device, but that's OK because that's
1251 * how we use it.
1252 */
1253static void set_config(struct device *dev, unsigned len, const void *conf)
1254{
1255 /* Check we haven't overflowed our single page. */
1256 if (device_config(dev) + len > devices.descpage + getpagesize())
1257 errx(1, "Too many devices");
1258
1259 /* Copy in the config information, and store the length. */
1260 memcpy(device_config(dev), conf, len);
1261 dev->desc->config_len = len;
1262
1263 /* Size must fit in config_len field (8 bits)! */
1264 assert(dev->desc->config_len == len);
1265}
1266
1267/*
1268 * This routine does all the creation and setup of a new device, including
1269 * calling new_dev_desc() to allocate the descriptor and device memory. We
1270 * don't actually start the service threads until later.
1271 *
1272 * See what I mean about userspace being boring?
1273 */
1274static struct device *new_device(const char *name, u16 type)
1275{
1276 struct device *dev = malloc(sizeof(*dev));
1277
1278 /* Now we populate the fields one at a time. */
1279 dev->desc = new_dev_desc(type);
1280 dev->name = name;
1281 dev->vq = NULL;
1282 dev->feature_len = 0;
1283 dev->num_vq = 0;
1284 dev->running = false;
1285 dev->next = NULL;
1286
1287 /*
1288 * Append to device list. Prepending to a single-linked list is
1289 * easier, but the user expects the devices to be arranged on the bus
1290 * in command-line order. The first network device on the command line
1291 * is eth0, the first block device /dev/vda, etc.
1292 */
1293 if (devices.lastdev)
1294 devices.lastdev->next = dev;
1295 else
1296 devices.dev = dev;
1297 devices.lastdev = dev;
1298
1299 return dev;
1300}
1301
1302/*
1303 * Our first setup routine is the console. It's a fairly simple device, but
1304 * UNIX tty handling makes it uglier than it could be.
1305 */
1306static void setup_console(void)
1307{
1308 struct device *dev;
1309
1310 /* If we can save the initial standard input settings... */
1311 if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
1312 struct termios term = orig_term;
1313 /*
1314 * Then we turn off echo, line buffering and ^C etc: We want a
1315 * raw input stream to the Guest.
1316 */
1317 term.c_lflag &= ~(ISIG|ICANON|ECHO);
1318 tcsetattr(STDIN_FILENO, TCSANOW, &term);
1319 }
1320
1321 dev = new_device("console", VIRTIO_ID_CONSOLE);
1322
1323 /* We store the console state in dev->priv, and initialize it. */
1324 dev->priv = malloc(sizeof(struct console_abort));
1325 ((struct console_abort *)dev->priv)->count = 0;
1326
1327 /*
1328 * The console needs two virtqueues: the input then the output. When
1329 * they put something the input queue, we make sure we're listening to
1330 * stdin. When they put something in the output queue, we write it to
1331 * stdout.
1332 */
1333 add_virtqueue(dev, VIRTQUEUE_NUM, console_input);
1334 add_virtqueue(dev, VIRTQUEUE_NUM, console_output);
1335
1336 verbose("device %u: console\n", ++devices.device_num);
1337}
1338/*:*/
1339
1340/*M:010
1341 * Inter-guest networking is an interesting area. Simplest is to have a
1342 * --sharenet=<name> option which opens or creates a named pipe. This can be
1343 * used to send packets to another guest in a 1:1 manner.
1344 *
1345 * More sophisticated is to use one of the tools developed for project like UML
1346 * to do networking.
1347 *
1348 * Faster is to do virtio bonding in kernel. Doing this 1:1 would be
1349 * completely generic ("here's my vring, attach to your vring") and would work
1350 * for any traffic. Of course, namespace and permissions issues need to be
1351 * dealt with. A more sophisticated "multi-channel" virtio_net.c could hide
1352 * multiple inter-guest channels behind one interface, although it would
1353 * require some manner of hotplugging new virtio channels.
1354 *
1355 * Finally, we could use a virtio network switch in the kernel, ie. vhost.
1356:*/
1357
1358static u32 str2ip(const char *ipaddr)
1359{
1360 unsigned int b[4];
1361
1362 if (sscanf(ipaddr, "%u.%u.%u.%u", &b[0], &b[1], &b[2], &b[3]) != 4)
1363 errx(1, "Failed to parse IP address '%s'", ipaddr);
1364 return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
1365}
1366
1367static void str2mac(const char *macaddr, unsigned char mac[6])
1368{
1369 unsigned int m[6];
1370 if (sscanf(macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
1371 &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]) != 6)
1372 errx(1, "Failed to parse mac address '%s'", macaddr);
1373 mac[0] = m[0];
1374 mac[1] = m[1];
1375 mac[2] = m[2];
1376 mac[3] = m[3];
1377 mac[4] = m[4];
1378 mac[5] = m[5];
1379}
1380
1381/*
1382 * This code is "adapted" from libbridge: it attaches the Host end of the
1383 * network device to the bridge device specified by the command line.
1384 *
1385 * This is yet another James Morris contribution (I'm an IP-level guy, so I
1386 * dislike bridging), and I just try not to break it.
1387 */
1388static void add_to_bridge(int fd, const char *if_name, const char *br_name)
1389{
1390 int ifidx;
1391 struct ifreq ifr;
1392
1393 if (!*br_name)
1394 errx(1, "must specify bridge name");
1395
1396 ifidx = if_nametoindex(if_name);
1397 if (!ifidx)
1398 errx(1, "interface %s does not exist!", if_name);
1399
1400 strncpy(ifr.ifr_name, br_name, IFNAMSIZ);
1401 ifr.ifr_name[IFNAMSIZ-1] = '\0';
1402 ifr.ifr_ifindex = ifidx;
1403 if (ioctl(fd, SIOCBRADDIF, &ifr) < 0)
1404 err(1, "can't add %s to bridge %s", if_name, br_name);
1405}
1406
1407/*
1408 * This sets up the Host end of the network device with an IP address, brings
1409 * it up so packets will flow, the copies the MAC address into the hwaddr
1410 * pointer.
1411 */
1412static void configure_device(int fd, const char *tapif, u32 ipaddr)
1413{
1414 struct ifreq ifr;
1415 struct sockaddr_in sin;
1416
1417 memset(&ifr, 0, sizeof(ifr));
1418 strcpy(ifr.ifr_name, tapif);
1419
1420 /* Don't read these incantations. Just cut & paste them like I did! */
1421 sin.sin_family = AF_INET;
1422 sin.sin_addr.s_addr = htonl(ipaddr);
1423 memcpy(&ifr.ifr_addr, &sin, sizeof(sin));
1424 if (ioctl(fd, SIOCSIFADDR, &ifr) != 0)
1425 err(1, "Setting %s interface address", tapif);
1426 ifr.ifr_flags = IFF_UP;
1427 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0)
1428 err(1, "Bringing interface %s up", tapif);
1429}
1430
1431static int get_tun_device(char tapif[IFNAMSIZ])
1432{
1433 struct ifreq ifr;
1434 int netfd;
1435
1436 /* Start with this zeroed. Messy but sure. */
1437 memset(&ifr, 0, sizeof(ifr));
1438
1439 /*
1440 * We open the /dev/net/tun device and tell it we want a tap device. A
1441 * tap device is like a tun device, only somehow different. To tell
1442 * the truth, I completely blundered my way through this code, but it
1443 * works now!
1444 */
1445 netfd = open_or_die("/dev/net/tun", O_RDWR);
1446 ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
1447 strcpy(ifr.ifr_name, "tap%d");
1448 if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
1449 err(1, "configuring /dev/net/tun");
1450
1451 if (ioctl(netfd, TUNSETOFFLOAD,
1452 TUN_F_CSUM|TUN_F_TSO4|TUN_F_TSO6|TUN_F_TSO_ECN) != 0)
1453 err(1, "Could not set features for tun device");
1454
1455 /*
1456 * We don't need checksums calculated for packets coming in this
1457 * device: trust us!
1458 */
1459 ioctl(netfd, TUNSETNOCSUM, 1);
1460
1461 memcpy(tapif, ifr.ifr_name, IFNAMSIZ);
1462 return netfd;
1463}
1464
1465/*L:195
1466 * Our network is a Host<->Guest network. This can either use bridging or
1467 * routing, but the principle is the same: it uses the "tun" device to inject
1468 * packets into the Host as if they came in from a normal network card. We
1469 * just shunt packets between the Guest and the tun device.
1470 */
1471static void setup_tun_net(char *arg)
1472{
1473 struct device *dev;
1474 struct net_info *net_info = malloc(sizeof(*net_info));
1475 int ipfd;
1476 u32 ip = INADDR_ANY;
1477 bool bridging = false;
1478 char tapif[IFNAMSIZ], *p;
1479 struct virtio_net_config conf;
1480
1481 net_info->tunfd = get_tun_device(tapif);
1482
1483 /* First we create a new network device. */
1484 dev = new_device("net", VIRTIO_ID_NET);
1485 dev->priv = net_info;
1486
1487 /* Network devices need a recv and a send queue, just like console. */
1488 add_virtqueue(dev, VIRTQUEUE_NUM, net_input);
1489 add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
1490
1491 /*
1492 * We need a socket to perform the magic network ioctls to bring up the
1493 * tap interface, connect to the bridge etc. Any socket will do!
1494 */
1495 ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
1496 if (ipfd < 0)
1497 err(1, "opening IP socket");
1498
1499 /* If the command line was --tunnet=bridge:<name> do bridging. */
1500 if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
1501 arg += strlen(BRIDGE_PFX);
1502 bridging = true;
1503 }
1504
1505 /* A mac address may follow the bridge name or IP address */
1506 p = strchr(arg, ':');
1507 if (p) {
1508 str2mac(p+1, conf.mac);
1509 add_feature(dev, VIRTIO_NET_F_MAC);
1510 *p = '\0';
1511 }
1512
1513 /* arg is now either an IP address or a bridge name */
1514 if (bridging)
1515 add_to_bridge(ipfd, tapif, arg);
1516 else
1517 ip = str2ip(arg);
1518
1519 /* Set up the tun device. */
1520 configure_device(ipfd, tapif, ip);
1521
1522 /* Expect Guest to handle everything except UFO */
1523 add_feature(dev, VIRTIO_NET_F_CSUM);
1524 add_feature(dev, VIRTIO_NET_F_GUEST_CSUM);
1525 add_feature(dev, VIRTIO_NET_F_GUEST_TSO4);
1526 add_feature(dev, VIRTIO_NET_F_GUEST_TSO6);
1527 add_feature(dev, VIRTIO_NET_F_GUEST_ECN);
1528 add_feature(dev, VIRTIO_NET_F_HOST_TSO4);
1529 add_feature(dev, VIRTIO_NET_F_HOST_TSO6);
1530 add_feature(dev, VIRTIO_NET_F_HOST_ECN);
1531 /* We handle indirect ring entries */
1532 add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
1533 set_config(dev, sizeof(conf), &conf);
1534
1535 /* We don't need the socket any more; setup is done. */
1536 close(ipfd);
1537
1538 devices.device_num++;
1539
1540 if (bridging)
1541 verbose("device %u: tun %s attached to bridge: %s\n",
1542 devices.device_num, tapif, arg);
1543 else
1544 verbose("device %u: tun %s: %s\n",
1545 devices.device_num, tapif, arg);
1546}
1547/*:*/
1548
1549/* This hangs off device->priv. */
1550struct vblk_info {
1551 /* The size of the file. */
1552 off64_t len;
1553
1554 /* The file descriptor for the file. */
1555 int fd;
1556
1557};
1558
1559/*L:210
1560 * The Disk
1561 *
1562 * The disk only has one virtqueue, so it only has one thread. It is really
1563 * simple: the Guest asks for a block number and we read or write that position
1564 * in the file.
1565 *
1566 * Before we serviced each virtqueue in a separate thread, that was unacceptably
1567 * slow: the Guest waits until the read is finished before running anything
1568 * else, even if it could have been doing useful work.
1569 *
1570 * We could have used async I/O, except it's reputed to suck so hard that
1571 * characters actually go missing from your code when you try to use it.
1572 */
1573static void blk_request(struct virtqueue *vq)
1574{
1575 struct vblk_info *vblk = vq->dev->priv;
1576 unsigned int head, out_num, in_num, wlen;
1577 int ret, i;
1578 u8 *in;
1579 struct virtio_blk_outhdr out;
1580 struct iovec iov[vq->vring.num];
1581 off64_t off;
1582
1583 /*
1584 * Get the next request, where we normally wait. It triggers the
1585 * interrupt to acknowledge previously serviced requests (if any).
1586 */
1587 head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
1588
1589 /* Copy the output header from the front of the iov (adjusts iov) */
1590 iov_consume(iov, out_num, &out, sizeof(out));
1591
1592 /* Find and trim end of iov input array, for our status byte. */
1593 in = NULL;
1594 for (i = out_num + in_num - 1; i >= out_num; i--) {
1595 if (iov[i].iov_len > 0) {
1596 in = iov[i].iov_base + iov[i].iov_len - 1;
1597 iov[i].iov_len--;
1598 break;
1599 }
1600 }
1601 if (!in)
1602 errx(1, "Bad virtblk cmd with no room for status");
1603
1604 /*
1605 * For historical reasons, block operations are expressed in 512 byte
1606 * "sectors".
1607 */
1608 off = out.sector * 512;
1609
1610 /*
1611 * In general the virtio block driver is allowed to try SCSI commands.
1612 * It'd be nice if we supported eject, for example, but we don't.
1613 */
1614 if (out.type & VIRTIO_BLK_T_SCSI_CMD) {
1615 fprintf(stderr, "Scsi commands unsupported\n");
1616 *in = VIRTIO_BLK_S_UNSUPP;
1617 wlen = sizeof(*in);
1618 } else if (out.type & VIRTIO_BLK_T_OUT) {
1619 /*
1620 * Write
1621 *
1622 * Move to the right location in the block file. This can fail
1623 * if they try to write past end.
1624 */
1625 if (lseek64(vblk->fd, off, SEEK_SET) != off)
1626 err(1, "Bad seek to sector %llu", out.sector);
1627
1628 ret = writev(vblk->fd, iov, out_num);
1629 verbose("WRITE to sector %llu: %i\n", out.sector, ret);
1630
1631 /*
1632 * Grr... Now we know how long the descriptor they sent was, we
1633 * make sure they didn't try to write over the end of the block
1634 * file (possibly extending it).
1635 */
1636 if (ret > 0 && off + ret > vblk->len) {
1637 /* Trim it back to the correct length */
1638 ftruncate64(vblk->fd, vblk->len);
1639 /* Die, bad Guest, die. */
1640 errx(1, "Write past end %llu+%u", off, ret);
1641 }
1642
1643 wlen = sizeof(*in);
1644 *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
1645 } else if (out.type & VIRTIO_BLK_T_FLUSH) {
1646 /* Flush */
1647 ret = fdatasync(vblk->fd);
1648 verbose("FLUSH fdatasync: %i\n", ret);
1649 wlen = sizeof(*in);
1650 *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
1651 } else {
1652 /*
1653 * Read
1654 *
1655 * Move to the right location in the block file. This can fail
1656 * if they try to read past end.
1657 */
1658 if (lseek64(vblk->fd, off, SEEK_SET) != off)
1659 err(1, "Bad seek to sector %llu", out.sector);
1660
1661 ret = readv(vblk->fd, iov + out_num, in_num);
1662 if (ret >= 0) {
1663 wlen = sizeof(*in) + ret;
1664 *in = VIRTIO_BLK_S_OK;
1665 } else {
1666 wlen = sizeof(*in);
1667 *in = VIRTIO_BLK_S_IOERR;
1668 }
1669 }
1670
1671 /* Finished that request. */
1672 add_used(vq, head, wlen);
1673}
1674
1675/*L:198 This actually sets up a virtual block device. */
1676static void setup_block_file(const char *filename)
1677{
1678 struct device *dev;
1679 struct vblk_info *vblk;
1680 struct virtio_blk_config conf;
1681
1682 /* Creat the device. */
1683 dev = new_device("block", VIRTIO_ID_BLOCK);
1684
1685 /* The device has one virtqueue, where the Guest places requests. */
1686 add_virtqueue(dev, VIRTQUEUE_NUM, blk_request);
1687
1688 /* Allocate the room for our own bookkeeping */
1689 vblk = dev->priv = malloc(sizeof(*vblk));
1690
1691 /* First we open the file and store the length. */
1692 vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
1693 vblk->len = lseek64(vblk->fd, 0, SEEK_END);
1694
1695 /* We support FLUSH. */
1696 add_feature(dev, VIRTIO_BLK_F_FLUSH);
1697
1698 /* Tell Guest how many sectors this device has. */
1699 conf.capacity = cpu_to_le64(vblk->len / 512);
1700
1701 /*
1702 * Tell Guest not to put in too many descriptors at once: two are used
1703 * for the in and out elements.
1704 */
1705 add_feature(dev, VIRTIO_BLK_F_SEG_MAX);
1706 conf.seg_max = cpu_to_le32(VIRTQUEUE_NUM - 2);
1707
1708 /* Don't try to put whole struct: we have 8 bit limit. */
1709 set_config(dev, offsetof(struct virtio_blk_config, geometry), &conf);
1710
1711 verbose("device %u: virtblock %llu sectors\n",
1712 ++devices.device_num, le64_to_cpu(conf.capacity));
1713}
1714
1715/*L:211
1716 * Our random number generator device reads from /dev/random into the Guest's
1717 * input buffers. The usual case is that the Guest doesn't want random numbers
1718 * and so has no buffers although /dev/random is still readable, whereas
1719 * console is the reverse.
1720 *
1721 * The same logic applies, however.
1722 */
1723struct rng_info {
1724 int rfd;
1725};
1726
1727static void rng_input(struct virtqueue *vq)
1728{
1729 int len;
1730 unsigned int head, in_num, out_num, totlen = 0;
1731 struct rng_info *rng_info = vq->dev->priv;
1732 struct iovec iov[vq->vring.num];
1733
1734 /* First we need a buffer from the Guests's virtqueue. */
1735 head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
1736 if (out_num)
1737 errx(1, "Output buffers in rng?");
1738
1739 /*
1740 * Just like the console write, we loop to cover the whole iovec.
1741 * In this case, short reads actually happen quite a bit.
1742 */
1743 while (!iov_empty(iov, in_num)) {
1744 len = readv(rng_info->rfd, iov, in_num);
1745 if (len <= 0)
1746 err(1, "Read from /dev/random gave %i", len);
1747 iov_consume(iov, in_num, NULL, len);
1748 totlen += len;
1749 }
1750
1751 /* Tell the Guest about the new input. */
1752 add_used(vq, head, totlen);
1753}
1754
1755/*L:199
1756 * This creates a "hardware" random number device for the Guest.
1757 */
1758static void setup_rng(void)
1759{
1760 struct device *dev;
1761 struct rng_info *rng_info = malloc(sizeof(*rng_info));
1762
1763 /* Our device's privat info simply contains the /dev/random fd. */
1764 rng_info->rfd = open_or_die("/dev/random", O_RDONLY);
1765
1766 /* Create the new device. */
1767 dev = new_device("rng", VIRTIO_ID_RNG);
1768 dev->priv = rng_info;
1769
1770 /* The device has one virtqueue, where the Guest places inbufs. */
1771 add_virtqueue(dev, VIRTQUEUE_NUM, rng_input);
1772
1773 verbose("device %u: rng\n", devices.device_num++);
1774}
1775/* That's the end of device setup. */
1776
1777/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */
1778static void __attribute__((noreturn)) restart_guest(void)
1779{
1780 unsigned int i;
1781
1782 /*
1783 * Since we don't track all open fds, we simply close everything beyond
1784 * stderr.
1785 */
1786 for (i = 3; i < FD_SETSIZE; i++)
1787 close(i);
1788
1789 /* Reset all the devices (kills all threads). */
1790 cleanup_devices();
1791
1792 execv(main_args[0], main_args);
1793 err(1, "Could not exec %s", main_args[0]);
1794}
1795
1796/*L:220
1797 * Finally we reach the core of the Launcher which runs the Guest, serves
1798 * its input and output, and finally, lays it to rest.
1799 */
1800static void __attribute__((noreturn)) run_guest(void)
1801{
1802 for (;;) {
1803 unsigned long notify_addr;
1804 int readval;
1805
1806 /* We read from the /dev/lguest device to run the Guest. */
1807 readval = pread(lguest_fd, &notify_addr,
1808 sizeof(notify_addr), cpu_id);
1809
1810 /* One unsigned long means the Guest did HCALL_NOTIFY */
1811 if (readval == sizeof(notify_addr)) {
1812 verbose("Notify on address %#lx\n", notify_addr);
1813 handle_output(notify_addr);
1814 /* ENOENT means the Guest died. Reading tells us why. */
1815 } else if (errno == ENOENT) {
1816 char reason[1024] = { 0 };
1817 pread(lguest_fd, reason, sizeof(reason)-1, cpu_id);
1818 errx(1, "%s", reason);
1819 /* ERESTART means that we need to reboot the guest */
1820 } else if (errno == ERESTART) {
1821 restart_guest();
1822 /* Anything else means a bug or incompatible change. */
1823 } else
1824 err(1, "Running guest failed");
1825 }
1826}
1827/*L:240
1828 * This is the end of the Launcher. The good news: we are over halfway
1829 * through! The bad news: the most fiendish part of the code still lies ahead
1830 * of us.
1831 *
1832 * Are you ready? Take a deep breath and join me in the core of the Host, in
1833 * "make Host".
1834:*/
1835
1836static struct option opts[] = {
1837 { "verbose", 0, NULL, 'v' },
1838 { "tunnet", 1, NULL, 't' },
1839 { "block", 1, NULL, 'b' },
1840 { "rng", 0, NULL, 'r' },
1841 { "initrd", 1, NULL, 'i' },
1842 { "username", 1, NULL, 'u' },
1843 { "chroot", 1, NULL, 'c' },
1844 { NULL },
1845};
1846static void usage(void)
1847{
1848 errx(1, "Usage: lguest [--verbose] "
1849 "[--tunnet=(<ipaddr>:<macaddr>|bridge:<bridgename>:<macaddr>)\n"
1850 "|--block=<filename>|--initrd=<filename>]...\n"
1851 "<mem-in-mb> vmlinux [args...]");
1852}
1853
1854/*L:105 The main routine is where the real work begins: */
1855int main(int argc, char *argv[])
1856{
1857 /* Memory, code startpoint and size of the (optional) initrd. */
1858 unsigned long mem = 0, start, initrd_size = 0;
1859 /* Two temporaries. */
1860 int i, c;
1861 /* The boot information for the Guest. */
1862 struct boot_params *boot;
1863 /* If they specify an initrd file to load. */
1864 const char *initrd_name = NULL;
1865
1866 /* Password structure for initgroups/setres[gu]id */
1867 struct passwd *user_details = NULL;
1868
1869 /* Directory to chroot to */
1870 char *chroot_path = NULL;
1871
1872 /* Save the args: we "reboot" by execing ourselves again. */
1873 main_args = argv;
1874
1875 /*
1876 * First we initialize the device list. We keep a pointer to the last
1877 * device, and the next interrupt number to use for devices (1:
1878 * remember that 0 is used by the timer).
1879 */
1880 devices.lastdev = NULL;
1881 devices.next_irq = 1;
1882
1883 /* We're CPU 0. In fact, that's the only CPU possible right now. */
1884 cpu_id = 0;
1885
1886 /*
1887 * We need to know how much memory so we can set up the device
1888 * descriptor and memory pages for the devices as we parse the command
1889 * line. So we quickly look through the arguments to find the amount
1890 * of memory now.
1891 */
1892 for (i = 1; i < argc; i++) {
1893 if (argv[i][0] != '-') {
1894 mem = atoi(argv[i]) * 1024 * 1024;
1895 /*
1896 * We start by mapping anonymous pages over all of
1897 * guest-physical memory range. This fills it with 0,
1898 * and ensures that the Guest won't be killed when it
1899 * tries to access it.
1900 */
1901 guest_base = map_zeroed_pages(mem / getpagesize()
1902 + DEVICE_PAGES);
1903 guest_limit = mem;
1904 guest_max = mem + DEVICE_PAGES*getpagesize();
1905 devices.descpage = get_pages(1);
1906 break;
1907 }
1908 }
1909
1910 /* The options are fairly straight-forward */
1911 while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) {
1912 switch (c) {
1913 case 'v':
1914 verbose = true;
1915 break;
1916 case 't':
1917 setup_tun_net(optarg);
1918 break;
1919 case 'b':
1920 setup_block_file(optarg);
1921 break;
1922 case 'r':
1923 setup_rng();
1924 break;
1925 case 'i':
1926 initrd_name = optarg;
1927 break;
1928 case 'u':
1929 user_details = getpwnam(optarg);
1930 if (!user_details)
1931 err(1, "getpwnam failed, incorrect username?");
1932 break;
1933 case 'c':
1934 chroot_path = optarg;
1935 break;
1936 default:
1937 warnx("Unknown argument %s", argv[optind]);
1938 usage();
1939 }
1940 }
1941 /*
1942 * After the other arguments we expect memory and kernel image name,
1943 * followed by command line arguments for the kernel.
1944 */
1945 if (optind + 2 > argc)
1946 usage();
1947
1948 verbose("Guest base is at %p\n", guest_base);
1949
1950 /* We always have a console device */
1951 setup_console();
1952
1953 /* Now we load the kernel */
1954 start = load_kernel(open_or_die(argv[optind+1], O_RDONLY));
1955
1956 /* Boot information is stashed at physical address 0 */
1957 boot = from_guest_phys(0);
1958
1959 /* Map the initrd image if requested (at top of physical memory) */
1960 if (initrd_name) {
1961 initrd_size = load_initrd(initrd_name, mem);
1962 /*
1963 * These are the location in the Linux boot header where the
1964 * start and size of the initrd are expected to be found.
1965 */
1966 boot->hdr.ramdisk_image = mem - initrd_size;
1967 boot->hdr.ramdisk_size = initrd_size;
1968 /* The bootloader type 0xFF means "unknown"; that's OK. */
1969 boot->hdr.type_of_loader = 0xFF;
1970 }
1971
1972 /*
1973 * The Linux boot header contains an "E820" memory map: ours is a
1974 * simple, single region.
1975 */
1976 boot->e820_entries = 1;
1977 boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM });
1978 /*
1979 * The boot header contains a command line pointer: we put the command
1980 * line after the boot header.
1981 */
1982 boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1);
1983 /* We use a simple helper to copy the arguments separated by spaces. */
1984 concat((char *)(boot + 1), argv+optind+2);
1985
1986 /* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */
1987 boot->hdr.kernel_alignment = 0x1000000;
1988
1989 /* Boot protocol version: 2.07 supports the fields for lguest. */
1990 boot->hdr.version = 0x207;
1991
1992 /* The hardware_subarch value of "1" tells the Guest it's an lguest. */
1993 boot->hdr.hardware_subarch = 1;
1994
1995 /* Tell the entry path not to try to reload segment registers. */
1996 boot->hdr.loadflags |= KEEP_SEGMENTS;
1997
1998 /* We tell the kernel to initialize the Guest. */
1999 tell_kernel(start);
2000
2001 /* Ensure that we terminate if a device-servicing child dies. */
2002 signal(SIGCHLD, kill_launcher);
2003
2004 /* If we exit via err(), this kills all the threads, restores tty. */
2005 atexit(cleanup_devices);
2006
2007 /* If requested, chroot to a directory */
2008 if (chroot_path) {
2009 if (chroot(chroot_path) != 0)
2010 err(1, "chroot(\"%s\") failed", chroot_path);
2011
2012 if (chdir("/") != 0)
2013 err(1, "chdir(\"/\") failed");
2014
2015 verbose("chroot done\n");
2016 }
2017
2018 /* If requested, drop privileges */
2019 if (user_details) {
2020 uid_t u;
2021 gid_t g;
2022
2023 u = user_details->pw_uid;
2024 g = user_details->pw_gid;
2025
2026 if (initgroups(user_details->pw_name, g) != 0)
2027 err(1, "initgroups failed");
2028
2029 if (setresgid(g, g, g) != 0)
2030 err(1, "setresgid failed");
2031
2032 if (setresuid(u, u, u) != 0)
2033 err(1, "setresuid failed");
2034
2035 verbose("Dropping privileges completed\n");
2036 }
2037
2038 /* Finally, run the Guest. This doesn't return. */
2039 run_guest();
2040}
2041/*:*/
2042
2043/*M:999
2044 * Mastery is done: you now know everything I do.
2045 *
2046 * But surely you have seen code, features and bugs in your wanderings which
2047 * you now yearn to attack? That is the real game, and I look forward to you
2048 * patching and forking lguest into the Your-Name-Here-visor.
2049 *
2050 * Farewell, and good coding!
2051 * Rusty Russell.
2052 */
diff --git a/tools/lguest/lguest.txt b/tools/lguest/lguest.txt
deleted file mode 100644
index bff0c554485..00000000000
--- a/tools/lguest/lguest.txt
+++ /dev/null
@@ -1,129 +0,0 @@
1 __
2 (___()'`; Rusty's Remarkably Unreliable Guide to Lguest
3 /, /` - or, A Young Coder's Illustrated Hypervisor
4 \\"--\\ http://lguest.ozlabs.org
5
6Lguest is designed to be a minimal 32-bit x86 hypervisor for the Linux kernel,
7for Linux developers and users to experiment with virtualization with the
8minimum of complexity. Nonetheless, it should have sufficient features to
9make it useful for specific tasks, and, of course, you are encouraged to fork
10and enhance it (see drivers/lguest/README).
11
12Features:
13
14- Kernel module which runs in a normal kernel.
15- Simple I/O model for communication.
16- Simple program to create new guests.
17- Logo contains cute puppies: http://lguest.ozlabs.org
18
19Developer features:
20
21- Fun to hack on.
22- No ABI: being tied to a specific kernel anyway, you can change anything.
23- Many opportunities for improvement or feature implementation.
24
25Running Lguest:
26
27- The easiest way to run lguest is to use same kernel as guest and host.
28 You can configure them differently, but usually it's easiest not to.
29
30 You will need to configure your kernel with the following options:
31
32 "General setup":
33 "Prompt for development and/or incomplete code/drivers" = Y
34 (CONFIG_EXPERIMENTAL=y)
35
36 "Processor type and features":
37 "Paravirtualized guest support" = Y
38 "Lguest guest support" = Y
39 "High Memory Support" = off/4GB
40 "Alignment value to which kernel should be aligned" = 0x100000
41 (CONFIG_PARAVIRT=y, CONFIG_LGUEST_GUEST=y, CONFIG_HIGHMEM64G=n and
42 CONFIG_PHYSICAL_ALIGN=0x100000)
43
44 "Device Drivers":
45 "Block devices"
46 "Virtio block driver (EXPERIMENTAL)" = M/Y
47 "Network device support"
48 "Universal TUN/TAP device driver support" = M/Y
49 "Virtio network driver (EXPERIMENTAL)" = M/Y
50 (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m)
51
52 "Virtualization"
53 "Linux hypervisor example code" = M/Y
54 (CONFIG_LGUEST=m)
55
56- A tool called "lguest" is available in this directory: type "make"
57 to build it. If you didn't build your kernel in-tree, use "make
58 O=<builddir>".
59
60- Create or find a root disk image. There are several useful ones
61 around, such as the xm-test tiny root image at
62 http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img
63
64 For more serious work, I usually use a distribution ISO image and
65 install it under qemu, then make multiple copies:
66
67 dd if=/dev/zero of=rootfile bs=1M count=2048
68 qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d
69
70 Make sure that you install a getty on /dev/hvc0 if you want to log in on the
71 console!
72
73- "modprobe lg" if you built it as a module.
74
75- Run an lguest as root:
76
77 Documentation/virtual/lguest/lguest 64 vmlinux --tunnet=192.168.19.1 \
78 --block=rootfile root=/dev/vda
79
80 Explanation:
81 64: the amount of memory to use, in MB.
82
83 vmlinux: the kernel image found in the top of your build directory. You
84 can also use a standard bzImage.
85
86 --tunnet=192.168.19.1: configures a "tap" device for networking with this
87 IP address.
88
89 --block=rootfile: a file or block device which becomes /dev/vda
90 inside the guest.
91
92 root=/dev/vda: this (and anything else on the command line) are
93 kernel boot parameters.
94
95- Configuring networking. I usually have the host masquerade, using
96 "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 >
97 /proc/sys/net/ipv4/ip_forward". In this example, I would configure
98 eth0 inside the guest at 192.168.19.2.
99
100 Another method is to bridge the tap device to an external interface
101 using --tunnet=bridge:<bridgename>, and perhaps run dhcp on the guest
102 to obtain an IP address. The bridge needs to be configured first:
103 this option simply adds the tap interface to it.
104
105 A simple example on my system:
106
107 ifconfig eth0 0.0.0.0
108 brctl addbr lg0
109 ifconfig lg0 up
110 brctl addif lg0 eth0
111 dhclient lg0
112
113 Then use --tunnet=bridge:lg0 when launching the guest.
114
115 See:
116
117 http://www.linuxfoundation.org/collaborate/workgroups/networking/bridge
118
119 for general information on how to get bridging to work.
120
121- Random number generation. Using the --rng option will provide a
122 /dev/hwrng in the guest that will read from the host's /dev/random.
123 Use this option in conjunction with rng-tools (see ../hw_random.txt)
124 to provide entropy to the guest kernel's /dev/random.
125
126There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest
127
128Good luck!
129Rusty Russell rusty@rustcorp.com.au.
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
deleted file mode 100644
index a20e3203343..00000000000
--- a/tools/lib/traceevent/Makefile
+++ /dev/null
@@ -1,319 +0,0 @@
1# trace-cmd version
2EP_VERSION = 1
3EP_PATCHLEVEL = 1
4EP_EXTRAVERSION = 0
5
6# file format version
7FILE_VERSION = 6
8
9MAKEFLAGS += --no-print-directory
10
11
12# Makefiles suck: This macro sets a default value of $(2) for the
13# variable named by $(1), unless the variable has been set by
14# environment or command line. This is necessary for CC and AR
15# because make sets default values, so the simpler ?= approach
16# won't work as expected.
17define allow-override
18 $(if $(or $(findstring environment,$(origin $(1))),\
19 $(findstring command line,$(origin $(1)))),,\
20 $(eval $(1) = $(2)))
21endef
22
23# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
24$(call allow-override,CC,$(CROSS_COMPILE)gcc)
25$(call allow-override,AR,$(CROSS_COMPILE)ar)
26
27EXT = -std=gnu99
28INSTALL = install
29
30# Use DESTDIR for installing into a different root directory.
31# This is useful for building a package. The program will be
32# installed in this directory as if it was the root directory.
33# Then the build tool can move it later.
34DESTDIR ?=
35DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
36
37prefix ?= /usr/local
38bindir_relative = bin
39bindir = $(prefix)/$(bindir_relative)
40man_dir = $(prefix)/share/man
41man_dir_SQ = '$(subst ','\'',$(man_dir))'
42html_install = $(prefix)/share/kernelshark/html
43html_install_SQ = '$(subst ','\'',$(html_install))'
44img_install = $(prefix)/share/kernelshark/html/images
45img_install_SQ = '$(subst ','\'',$(img_install))'
46
47export man_dir man_dir_SQ html_install html_install_SQ INSTALL
48export img_install img_install_SQ
49export DESTDIR DESTDIR_SQ
50
51# copy a bit from Linux kbuild
52
53ifeq ("$(origin V)", "command line")
54 VERBOSE = $(V)
55endif
56ifndef VERBOSE
57 VERBOSE = 0
58endif
59
60ifeq ("$(origin O)", "command line")
61 BUILD_OUTPUT := $(O)
62endif
63
64ifeq ($(BUILD_SRC),)
65ifneq ($(BUILD_OUTPUT),)
66
67define build_output
68 $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \
69 BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
70endef
71
72saved-output := $(BUILD_OUTPUT)
73BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
74$(if $(BUILD_OUTPUT),, \
75 $(error output directory "$(saved-output)" does not exist))
76
77all: sub-make
78
79gui: force
80 $(call build_output, all_cmd)
81
82$(filter-out gui,$(MAKECMDGOALS)): sub-make
83
84sub-make: force
85 $(call build_output, $(MAKECMDGOALS))
86
87
88# Leave processing to above invocation of make
89skip-makefile := 1
90
91endif # BUILD_OUTPUT
92endif # BUILD_SRC
93
94# We process the rest of the Makefile if this is the final invocation of make
95ifeq ($(skip-makefile),)
96
97srctree := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
98objtree := $(CURDIR)
99src := $(srctree)
100obj := $(objtree)
101
102export prefix bindir src obj
103
104# Shell quotes
105bindir_SQ = $(subst ','\'',$(bindir))
106bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
107
108LIB_FILE = libtraceevent.a libtraceevent.so
109
110CONFIG_INCLUDES =
111CONFIG_LIBS =
112CONFIG_FLAGS =
113
114VERSION = $(EP_VERSION)
115PATCHLEVEL = $(EP_PATCHLEVEL)
116EXTRAVERSION = $(EP_EXTRAVERSION)
117
118OBJ = $@
119N =
120
121export Q VERBOSE
122
123EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
124
125INCLUDES = -I. -I/usr/local/include $(CONFIG_INCLUDES)
126
127# Set compile option CFLAGS if not set elsewhere
128CFLAGS ?= -g -Wall
129
130# Append required CFLAGS
131override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
132override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
133
134ifeq ($(VERBOSE),1)
135 Q =
136 print_compile =
137 print_app_build =
138 print_fpic_compile =
139 print_shared_lib_compile =
140 print_plugin_obj_compile =
141 print_plugin_build =
142 print_install =
143else
144 Q = @
145 print_compile = echo ' CC '$(OBJ);
146 print_app_build = echo ' BUILD '$(OBJ);
147 print_fpic_compile = echo ' CC FPIC '$(OBJ);
148 print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
149 print_plugin_obj_compile = echo ' CC PLUGIN OBJ '$(OBJ);
150 print_plugin_build = echo ' CC PLUGI '$(OBJ);
151 print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
152 print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
153endif
154
155do_fpic_compile = \
156 ($(print_fpic_compile) \
157 $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
158
159do_app_build = \
160 ($(print_app_build) \
161 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
162
163do_compile_shared_library = \
164 ($(print_shared_lib_compile) \
165 $(CC) --shared $^ -o $@)
166
167do_compile_plugin_obj = \
168 ($(print_plugin_obj_compile) \
169 $(CC) -c $(CFLAGS) -fPIC -o $@ $<)
170
171do_plugin_build = \
172 ($(print_plugin_build) \
173 $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
174
175do_build_static_lib = \
176 ($(print_static_lib_build) \
177 $(RM) $@; $(AR) rcs $@ $^)
178
179
180define do_compile
181 $(print_compile) \
182 $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
183endef
184
185$(obj)/%.o: $(src)/%.c
186 $(Q)$(call do_compile)
187
188%.o: $(src)/%.c
189 $(Q)$(call do_compile)
190
191PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
192
193ALL_OBJS = $(PEVENT_LIB_OBJS)
194
195CMD_TARGETS = $(LIB_FILE)
196
197TARGETS = $(CMD_TARGETS)
198
199
200all: all_cmd
201
202all_cmd: $(CMD_TARGETS)
203
204libtraceevent.so: $(PEVENT_LIB_OBJS)
205 $(Q)$(do_compile_shared_library)
206
207libtraceevent.a: $(PEVENT_LIB_OBJS)
208 $(Q)$(do_build_static_lib)
209
210$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
211 $(Q)$(do_fpic_compile)
212
213define make_version.h
214 (echo '/* This file is automatically generated. Do not modify. */'; \
215 echo \#define VERSION_CODE $(shell \
216 expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
217 echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
218 echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
219 echo '#define FILE_VERSION '$(FILE_VERSION); \
220 ) > $1
221endef
222
223define update_version.h
224 ($(call make_version.h, $@.tmp); \
225 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
226 rm -f $@.tmp; \
227 else \
228 echo ' UPDATE $@'; \
229 mv -f $@.tmp $@; \
230 fi);
231endef
232
233ep_version.h: force
234 $(Q)$(N)$(call update_version.h)
235
236VERSION_FILES = ep_version.h
237
238define update_dir
239 (echo $1 > $@.tmp; \
240 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
241 rm -f $@.tmp; \
242 else \
243 echo ' UPDATE $@'; \
244 mv -f $@.tmp $@; \
245 fi);
246endef
247
248## make deps
249
250all_objs := $(sort $(ALL_OBJS))
251all_deps := $(all_objs:%.o=.%.d)
252
253# let .d file also depends on the source and header files
254define check_deps
255 @set -e; $(RM) $@; \
256 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
257 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
258 $(RM) $@.$$$$
259endef
260
261$(gui_deps): ks_version.h
262$(non_gui_deps): tc_version.h
263
264$(all_deps): .%.d: $(src)/%.c
265 $(Q)$(call check_deps)
266
267$(all_objs) : %.o : .%.d
268
269dep_includes := $(wildcard $(all_deps))
270
271ifneq ($(dep_includes),)
272 include $(dep_includes)
273endif
274
275### Detect environment changes
276TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
277
278TRACEEVENT-CFLAGS: force
279 @FLAGS='$(TRACK_CFLAGS)'; \
280 if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
281 echo 1>&2 " * new build flags or cross compiler"; \
282 echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
283 fi
284
285tags: force
286 $(RM) tags
287 find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
288 --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
289
290TAGS: force
291 $(RM) TAGS
292 find . -name '*.[ch]' | xargs etags \
293 --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
294
295define do_install
296 $(print_install) \
297 if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
298 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
299 fi; \
300 $(INSTALL) $1 '$(DESTDIR_SQ)$2'
301endef
302
303install_lib: all_cmd install_plugins install_python
304 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
305
306install: install_lib
307
308clean:
309 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
310 $(RM) TRACEEVENT-CFLAGS tags TAGS
311
312endif # skip-makefile
313
314PHONY += force
315force:
316
317# Declare the contents of the .PHONY variable as phony. We keep that
318# information in a variable so we can use it in if_changed and friends.
319.PHONY: $(PHONY)
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
deleted file mode 100644
index 5a824e355d0..00000000000
--- a/tools/lib/traceevent/event-parse.c
+++ /dev/null
@@ -1,5617 +0,0 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by
23 * - Copyright (C) 2009 Frederic Weisbecker,
24 * Frederic Weisbecker gave his permission to relicense the code to
25 * the Lesser General Public License.
26 */
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <stdarg.h>
31#include <ctype.h>
32#include <errno.h>
33#include <stdint.h>
34#include <limits.h>
35
36#include "event-parse.h"
37#include "event-utils.h"
38
39static const char *input_buf;
40static unsigned long long input_buf_ptr;
41static unsigned long long input_buf_siz;
42
43static int is_flag_field;
44static int is_symbolic_field;
45
46static int show_warning = 1;
47
48#define do_warning(fmt, ...) \
49 do { \
50 if (show_warning) \
51 warning(fmt, ##__VA_ARGS__); \
52 } while (0)
53
54static void init_input_buf(const char *buf, unsigned long long size)
55{
56 input_buf = buf;
57 input_buf_siz = size;
58 input_buf_ptr = 0;
59}
60
61const char *pevent_get_input_buf(void)
62{
63 return input_buf;
64}
65
66unsigned long long pevent_get_input_buf_ptr(void)
67{
68 return input_buf_ptr;
69}
70
71struct event_handler {
72 struct event_handler *next;
73 int id;
74 const char *sys_name;
75 const char *event_name;
76 pevent_event_handler_func func;
77 void *context;
78};
79
80struct pevent_func_params {
81 struct pevent_func_params *next;
82 enum pevent_func_arg_type type;
83};
84
85struct pevent_function_handler {
86 struct pevent_function_handler *next;
87 enum pevent_func_arg_type ret_type;
88 char *name;
89 pevent_func_handler func;
90 struct pevent_func_params *params;
91 int nr_args;
92};
93
94static unsigned long long
95process_defined_func(struct trace_seq *s, void *data, int size,
96 struct event_format *event, struct print_arg *arg);
97
98static void free_func_handle(struct pevent_function_handler *func);
99
100/**
101 * pevent_buffer_init - init buffer for parsing
102 * @buf: buffer to parse
103 * @size: the size of the buffer
104 *
105 * For use with pevent_read_token(), this initializes the internal
106 * buffer that pevent_read_token() will parse.
107 */
108void pevent_buffer_init(const char *buf, unsigned long long size)
109{
110 init_input_buf(buf, size);
111}
112
113void breakpoint(void)
114{
115 static int x;
116 x++;
117}
118
119struct print_arg *alloc_arg(void)
120{
121 return calloc(1, sizeof(struct print_arg));
122}
123
124struct cmdline {
125 char *comm;
126 int pid;
127};
128
129static int cmdline_cmp(const void *a, const void *b)
130{
131 const struct cmdline *ca = a;
132 const struct cmdline *cb = b;
133
134 if (ca->pid < cb->pid)
135 return -1;
136 if (ca->pid > cb->pid)
137 return 1;
138
139 return 0;
140}
141
142struct cmdline_list {
143 struct cmdline_list *next;
144 char *comm;
145 int pid;
146};
147
148static int cmdline_init(struct pevent *pevent)
149{
150 struct cmdline_list *cmdlist = pevent->cmdlist;
151 struct cmdline_list *item;
152 struct cmdline *cmdlines;
153 int i;
154
155 cmdlines = malloc(sizeof(*cmdlines) * pevent->cmdline_count);
156 if (!cmdlines)
157 return -1;
158
159 i = 0;
160 while (cmdlist) {
161 cmdlines[i].pid = cmdlist->pid;
162 cmdlines[i].comm = cmdlist->comm;
163 i++;
164 item = cmdlist;
165 cmdlist = cmdlist->next;
166 free(item);
167 }
168
169 qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
170
171 pevent->cmdlines = cmdlines;
172 pevent->cmdlist = NULL;
173
174 return 0;
175}
176
177static const char *find_cmdline(struct pevent *pevent, int pid)
178{
179 const struct cmdline *comm;
180 struct cmdline key;
181
182 if (!pid)
183 return "<idle>";
184
185 if (!pevent->cmdlines && cmdline_init(pevent))
186 return "<not enough memory for cmdlines!>";
187
188 key.pid = pid;
189
190 comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
191 sizeof(*pevent->cmdlines), cmdline_cmp);
192
193 if (comm)
194 return comm->comm;
195 return "<...>";
196}
197
198/**
199 * pevent_pid_is_registered - return if a pid has a cmdline registered
200 * @pevent: handle for the pevent
201 * @pid: The pid to check if it has a cmdline registered with.
202 *
203 * Returns 1 if the pid has a cmdline mapped to it
204 * 0 otherwise.
205 */
206int pevent_pid_is_registered(struct pevent *pevent, int pid)
207{
208 const struct cmdline *comm;
209 struct cmdline key;
210
211 if (!pid)
212 return 1;
213
214 if (!pevent->cmdlines && cmdline_init(pevent))
215 return 0;
216
217 key.pid = pid;
218
219 comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
220 sizeof(*pevent->cmdlines), cmdline_cmp);
221
222 if (comm)
223 return 1;
224 return 0;
225}
226
227/*
228 * If the command lines have been converted to an array, then
229 * we must add this pid. This is much slower than when cmdlines
230 * are added before the array is initialized.
231 */
232static int add_new_comm(struct pevent *pevent, const char *comm, int pid)
233{
234 struct cmdline *cmdlines = pevent->cmdlines;
235 const struct cmdline *cmdline;
236 struct cmdline key;
237
238 if (!pid)
239 return 0;
240
241 /* avoid duplicates */
242 key.pid = pid;
243
244 cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
245 sizeof(*pevent->cmdlines), cmdline_cmp);
246 if (cmdline) {
247 errno = EEXIST;
248 return -1;
249 }
250
251 cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1));
252 if (!cmdlines) {
253 errno = ENOMEM;
254 return -1;
255 }
256
257 cmdlines[pevent->cmdline_count].comm = strdup(comm);
258 if (!cmdlines[pevent->cmdline_count].comm) {
259 free(cmdlines);
260 errno = ENOMEM;
261 return -1;
262 }
263
264 cmdlines[pevent->cmdline_count].pid = pid;
265
266 if (cmdlines[pevent->cmdline_count].comm)
267 pevent->cmdline_count++;
268
269 qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
270 pevent->cmdlines = cmdlines;
271
272 return 0;
273}
274
275/**
276 * pevent_register_comm - register a pid / comm mapping
277 * @pevent: handle for the pevent
278 * @comm: the command line to register
279 * @pid: the pid to map the command line to
280 *
281 * This adds a mapping to search for command line names with
282 * a given pid. The comm is duplicated.
283 */
284int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
285{
286 struct cmdline_list *item;
287
288 if (pevent->cmdlines)
289 return add_new_comm(pevent, comm, pid);
290
291 item = malloc(sizeof(*item));
292 if (!item)
293 return -1;
294
295 item->comm = strdup(comm);
296 if (!item->comm) {
297 free(item);
298 return -1;
299 }
300 item->pid = pid;
301 item->next = pevent->cmdlist;
302
303 pevent->cmdlist = item;
304 pevent->cmdline_count++;
305
306 return 0;
307}
308
309struct func_map {
310 unsigned long long addr;
311 char *func;
312 char *mod;
313};
314
315struct func_list {
316 struct func_list *next;
317 unsigned long long addr;
318 char *func;
319 char *mod;
320};
321
322static int func_cmp(const void *a, const void *b)
323{
324 const struct func_map *fa = a;
325 const struct func_map *fb = b;
326
327 if (fa->addr < fb->addr)
328 return -1;
329 if (fa->addr > fb->addr)
330 return 1;
331
332 return 0;
333}
334
335/*
336 * We are searching for a record in between, not an exact
337 * match.
338 */
339static int func_bcmp(const void *a, const void *b)
340{
341 const struct func_map *fa = a;
342 const struct func_map *fb = b;
343
344 if ((fa->addr == fb->addr) ||
345
346 (fa->addr > fb->addr &&
347 fa->addr < (fb+1)->addr))
348 return 0;
349
350 if (fa->addr < fb->addr)
351 return -1;
352
353 return 1;
354}
355
356static int func_map_init(struct pevent *pevent)
357{
358 struct func_list *funclist;
359 struct func_list *item;
360 struct func_map *func_map;
361 int i;
362
363 func_map = malloc(sizeof(*func_map) * (pevent->func_count + 1));
364 if (!func_map)
365 return -1;
366
367 funclist = pevent->funclist;
368
369 i = 0;
370 while (funclist) {
371 func_map[i].func = funclist->func;
372 func_map[i].addr = funclist->addr;
373 func_map[i].mod = funclist->mod;
374 i++;
375 item = funclist;
376 funclist = funclist->next;
377 free(item);
378 }
379
380 qsort(func_map, pevent->func_count, sizeof(*func_map), func_cmp);
381
382 /*
383 * Add a special record at the end.
384 */
385 func_map[pevent->func_count].func = NULL;
386 func_map[pevent->func_count].addr = 0;
387 func_map[pevent->func_count].mod = NULL;
388
389 pevent->func_map = func_map;
390 pevent->funclist = NULL;
391
392 return 0;
393}
394
395static struct func_map *
396find_func(struct pevent *pevent, unsigned long long addr)
397{
398 struct func_map *func;
399 struct func_map key;
400
401 if (!pevent->func_map)
402 func_map_init(pevent);
403
404 key.addr = addr;
405
406 func = bsearch(&key, pevent->func_map, pevent->func_count,
407 sizeof(*pevent->func_map), func_bcmp);
408
409 return func;
410}
411
412/**
413 * pevent_find_function - find a function by a given address
414 * @pevent: handle for the pevent
415 * @addr: the address to find the function with
416 *
417 * Returns a pointer to the function stored that has the given
418 * address. Note, the address does not have to be exact, it
419 * will select the function that would contain the address.
420 */
421const char *pevent_find_function(struct pevent *pevent, unsigned long long addr)
422{
423 struct func_map *map;
424
425 map = find_func(pevent, addr);
426 if (!map)
427 return NULL;
428
429 return map->func;
430}
431
432/**
433 * pevent_find_function_address - find a function address by a given address
434 * @pevent: handle for the pevent
435 * @addr: the address to find the function with
436 *
437 * Returns the address the function starts at. This can be used in
438 * conjunction with pevent_find_function to print both the function
439 * name and the function offset.
440 */
441unsigned long long
442pevent_find_function_address(struct pevent *pevent, unsigned long long addr)
443{
444 struct func_map *map;
445
446 map = find_func(pevent, addr);
447 if (!map)
448 return 0;
449
450 return map->addr;
451}
452
453/**
454 * pevent_register_function - register a function with a given address
455 * @pevent: handle for the pevent
456 * @function: the function name to register
457 * @addr: the address the function starts at
458 * @mod: the kernel module the function may be in (NULL for none)
459 *
460 * This registers a function name with an address and module.
461 * The @func passed in is duplicated.
462 */
463int pevent_register_function(struct pevent *pevent, char *func,
464 unsigned long long addr, char *mod)
465{
466 struct func_list *item = malloc(sizeof(*item));
467
468 if (!item)
469 return -1;
470
471 item->next = pevent->funclist;
472 item->func = strdup(func);
473 if (!item->func)
474 goto out_free;
475
476 if (mod) {
477 item->mod = strdup(mod);
478 if (!item->mod)
479 goto out_free_func;
480 } else
481 item->mod = NULL;
482 item->addr = addr;
483
484 pevent->funclist = item;
485 pevent->func_count++;
486
487 return 0;
488
489out_free_func:
490 free(item->func);
491 item->func = NULL;
492out_free:
493 free(item);
494 errno = ENOMEM;
495 return -1;
496}
497
498/**
499 * pevent_print_funcs - print out the stored functions
500 * @pevent: handle for the pevent
501 *
502 * This prints out the stored functions.
503 */
504void pevent_print_funcs(struct pevent *pevent)
505{
506 int i;
507
508 if (!pevent->func_map)
509 func_map_init(pevent);
510
511 for (i = 0; i < (int)pevent->func_count; i++) {
512 printf("%016llx %s",
513 pevent->func_map[i].addr,
514 pevent->func_map[i].func);
515 if (pevent->func_map[i].mod)
516 printf(" [%s]\n", pevent->func_map[i].mod);
517 else
518 printf("\n");
519 }
520}
521
522struct printk_map {
523 unsigned long long addr;
524 char *printk;
525};
526
527struct printk_list {
528 struct printk_list *next;
529 unsigned long long addr;
530 char *printk;
531};
532
533static int printk_cmp(const void *a, const void *b)
534{
535 const struct printk_map *pa = a;
536 const struct printk_map *pb = b;
537
538 if (pa->addr < pb->addr)
539 return -1;
540 if (pa->addr > pb->addr)
541 return 1;
542
543 return 0;
544}
545
546static int printk_map_init(struct pevent *pevent)
547{
548 struct printk_list *printklist;
549 struct printk_list *item;
550 struct printk_map *printk_map;
551 int i;
552
553 printk_map = malloc(sizeof(*printk_map) * (pevent->printk_count + 1));
554 if (!printk_map)
555 return -1;
556
557 printklist = pevent->printklist;
558
559 i = 0;
560 while (printklist) {
561 printk_map[i].printk = printklist->printk;
562 printk_map[i].addr = printklist->addr;
563 i++;
564 item = printklist;
565 printklist = printklist->next;
566 free(item);
567 }
568
569 qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp);
570
571 pevent->printk_map = printk_map;
572 pevent->printklist = NULL;
573
574 return 0;
575}
576
577static struct printk_map *
578find_printk(struct pevent *pevent, unsigned long long addr)
579{
580 struct printk_map *printk;
581 struct printk_map key;
582
583 if (!pevent->printk_map && printk_map_init(pevent))
584 return NULL;
585
586 key.addr = addr;
587
588 printk = bsearch(&key, pevent->printk_map, pevent->printk_count,
589 sizeof(*pevent->printk_map), printk_cmp);
590
591 return printk;
592}
593
594/**
595 * pevent_register_print_string - register a string by its address
596 * @pevent: handle for the pevent
597 * @fmt: the string format to register
598 * @addr: the address the string was located at
599 *
600 * This registers a string by the address it was stored in the kernel.
601 * The @fmt passed in is duplicated.
602 */
603int pevent_register_print_string(struct pevent *pevent, char *fmt,
604 unsigned long long addr)
605{
606 struct printk_list *item = malloc(sizeof(*item));
607
608 if (!item)
609 return -1;
610
611 item->next = pevent->printklist;
612 item->addr = addr;
613
614 item->printk = strdup(fmt);
615 if (!item->printk)
616 goto out_free;
617
618 pevent->printklist = item;
619 pevent->printk_count++;
620
621 return 0;
622
623out_free:
624 free(item);
625 errno = ENOMEM;
626 return -1;
627}
628
629/**
630 * pevent_print_printk - print out the stored strings
631 * @pevent: handle for the pevent
632 *
633 * This prints the string formats that were stored.
634 */
635void pevent_print_printk(struct pevent *pevent)
636{
637 int i;
638
639 if (!pevent->printk_map)
640 printk_map_init(pevent);
641
642 for (i = 0; i < (int)pevent->printk_count; i++) {
643 printf("%016llx %s\n",
644 pevent->printk_map[i].addr,
645 pevent->printk_map[i].printk);
646 }
647}
648
649static struct event_format *alloc_event(void)
650{
651 return calloc(1, sizeof(struct event_format));
652}
653
654static int add_event(struct pevent *pevent, struct event_format *event)
655{
656 int i;
657 struct event_format **events = realloc(pevent->events, sizeof(event) *
658 (pevent->nr_events + 1));
659 if (!events)
660 return -1;
661
662 pevent->events = events;
663
664 for (i = 0; i < pevent->nr_events; i++) {
665 if (pevent->events[i]->id > event->id)
666 break;
667 }
668 if (i < pevent->nr_events)
669 memmove(&pevent->events[i + 1],
670 &pevent->events[i],
671 sizeof(event) * (pevent->nr_events - i));
672
673 pevent->events[i] = event;
674 pevent->nr_events++;
675
676 event->pevent = pevent;
677
678 return 0;
679}
680
681static int event_item_type(enum event_type type)
682{
683 switch (type) {
684 case EVENT_ITEM ... EVENT_SQUOTE:
685 return 1;
686 case EVENT_ERROR ... EVENT_DELIM:
687 default:
688 return 0;
689 }
690}
691
692static void free_flag_sym(struct print_flag_sym *fsym)
693{
694 struct print_flag_sym *next;
695
696 while (fsym) {
697 next = fsym->next;
698 free(fsym->value);
699 free(fsym->str);
700 free(fsym);
701 fsym = next;
702 }
703}
704
705static void free_arg(struct print_arg *arg)
706{
707 struct print_arg *farg;
708
709 if (!arg)
710 return;
711
712 switch (arg->type) {
713 case PRINT_ATOM:
714 free(arg->atom.atom);
715 break;
716 case PRINT_FIELD:
717 free(arg->field.name);
718 break;
719 case PRINT_FLAGS:
720 free_arg(arg->flags.field);
721 free(arg->flags.delim);
722 free_flag_sym(arg->flags.flags);
723 break;
724 case PRINT_SYMBOL:
725 free_arg(arg->symbol.field);
726 free_flag_sym(arg->symbol.symbols);
727 break;
728 case PRINT_HEX:
729 free_arg(arg->hex.field);
730 free_arg(arg->hex.size);
731 break;
732 case PRINT_TYPE:
733 free(arg->typecast.type);
734 free_arg(arg->typecast.item);
735 break;
736 case PRINT_STRING:
737 case PRINT_BSTRING:
738 free(arg->string.string);
739 break;
740 case PRINT_DYNAMIC_ARRAY:
741 free(arg->dynarray.index);
742 break;
743 case PRINT_OP:
744 free(arg->op.op);
745 free_arg(arg->op.left);
746 free_arg(arg->op.right);
747 break;
748 case PRINT_FUNC:
749 while (arg->func.args) {
750 farg = arg->func.args;
751 arg->func.args = farg->next;
752 free_arg(farg);
753 }
754 break;
755
756 case PRINT_NULL:
757 default:
758 break;
759 }
760
761 free(arg);
762}
763
764static enum event_type get_type(int ch)
765{
766 if (ch == '\n')
767 return EVENT_NEWLINE;
768 if (isspace(ch))
769 return EVENT_SPACE;
770 if (isalnum(ch) || ch == '_')
771 return EVENT_ITEM;
772 if (ch == '\'')
773 return EVENT_SQUOTE;
774 if (ch == '"')
775 return EVENT_DQUOTE;
776 if (!isprint(ch))
777 return EVENT_NONE;
778 if (ch == '(' || ch == ')' || ch == ',')
779 return EVENT_DELIM;
780
781 return EVENT_OP;
782}
783
784static int __read_char(void)
785{
786 if (input_buf_ptr >= input_buf_siz)
787 return -1;
788
789 return input_buf[input_buf_ptr++];
790}
791
792static int __peek_char(void)
793{
794 if (input_buf_ptr >= input_buf_siz)
795 return -1;
796
797 return input_buf[input_buf_ptr];
798}
799
800/**
801 * pevent_peek_char - peek at the next character that will be read
802 *
803 * Returns the next character read, or -1 if end of buffer.
804 */
805int pevent_peek_char(void)
806{
807 return __peek_char();
808}
809
810static int extend_token(char **tok, char *buf, int size)
811{
812 char *newtok = realloc(*tok, size);
813
814 if (!newtok) {
815 free(*tok);
816 *tok = NULL;
817 return -1;
818 }
819
820 if (!*tok)
821 strcpy(newtok, buf);
822 else
823 strcat(newtok, buf);
824 *tok = newtok;
825
826 return 0;
827}
828
829static enum event_type force_token(const char *str, char **tok);
830
831static enum event_type __read_token(char **tok)
832{
833 char buf[BUFSIZ];
834 int ch, last_ch, quote_ch, next_ch;
835 int i = 0;
836 int tok_size = 0;
837 enum event_type type;
838
839 *tok = NULL;
840
841
842 ch = __read_char();
843 if (ch < 0)
844 return EVENT_NONE;
845
846 type = get_type(ch);
847 if (type == EVENT_NONE)
848 return type;
849
850 buf[i++] = ch;
851
852 switch (type) {
853 case EVENT_NEWLINE:
854 case EVENT_DELIM:
855 if (asprintf(tok, "%c", ch) < 0)
856 return EVENT_ERROR;
857
858 return type;
859
860 case EVENT_OP:
861 switch (ch) {
862 case '-':
863 next_ch = __peek_char();
864 if (next_ch == '>') {
865 buf[i++] = __read_char();
866 break;
867 }
868 /* fall through */
869 case '+':
870 case '|':
871 case '&':
872 case '>':
873 case '<':
874 last_ch = ch;
875 ch = __peek_char();
876 if (ch != last_ch)
877 goto test_equal;
878 buf[i++] = __read_char();
879 switch (last_ch) {
880 case '>':
881 case '<':
882 goto test_equal;
883 default:
884 break;
885 }
886 break;
887 case '!':
888 case '=':
889 goto test_equal;
890 default: /* what should we do instead? */
891 break;
892 }
893 buf[i] = 0;
894 *tok = strdup(buf);
895 return type;
896
897 test_equal:
898 ch = __peek_char();
899 if (ch == '=')
900 buf[i++] = __read_char();
901 goto out;
902
903 case EVENT_DQUOTE:
904 case EVENT_SQUOTE:
905 /* don't keep quotes */
906 i--;
907 quote_ch = ch;
908 last_ch = 0;
909 concat:
910 do {
911 if (i == (BUFSIZ - 1)) {
912 buf[i] = 0;
913 tok_size += BUFSIZ;
914
915 if (extend_token(tok, buf, tok_size) < 0)
916 return EVENT_NONE;
917 i = 0;
918 }
919 last_ch = ch;
920 ch = __read_char();
921 buf[i++] = ch;
922 /* the '\' '\' will cancel itself */
923 if (ch == '\\' && last_ch == '\\')
924 last_ch = 0;
925 } while (ch != quote_ch || last_ch == '\\');
926 /* remove the last quote */
927 i--;
928
929 /*
930 * For strings (double quotes) check the next token.
931 * If it is another string, concatinate the two.
932 */
933 if (type == EVENT_DQUOTE) {
934 unsigned long long save_input_buf_ptr = input_buf_ptr;
935
936 do {
937 ch = __read_char();
938 } while (isspace(ch));
939 if (ch == '"')
940 goto concat;
941 input_buf_ptr = save_input_buf_ptr;
942 }
943
944 goto out;
945
946 case EVENT_ERROR ... EVENT_SPACE:
947 case EVENT_ITEM:
948 default:
949 break;
950 }
951
952 while (get_type(__peek_char()) == type) {
953 if (i == (BUFSIZ - 1)) {
954 buf[i] = 0;
955 tok_size += BUFSIZ;
956
957 if (extend_token(tok, buf, tok_size) < 0)
958 return EVENT_NONE;
959 i = 0;
960 }
961 ch = __read_char();
962 buf[i++] = ch;
963 }
964
965 out:
966 buf[i] = 0;
967 if (extend_token(tok, buf, tok_size + i + 1) < 0)
968 return EVENT_NONE;
969
970 if (type == EVENT_ITEM) {
971 /*
972 * Older versions of the kernel has a bug that
973 * creates invalid symbols and will break the mac80211
974 * parsing. This is a work around to that bug.
975 *
976 * See Linux kernel commit:
977 * 811cb50baf63461ce0bdb234927046131fc7fa8b
978 */
979 if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
980 free(*tok);
981 *tok = NULL;
982 return force_token("\"\%s\" ", tok);
983 } else if (strcmp(*tok, "STA_PR_FMT") == 0) {
984 free(*tok);
985 *tok = NULL;
986 return force_token("\" sta:%pM\" ", tok);
987 } else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
988 free(*tok);
989 *tok = NULL;
990 return force_token("\" vif:%p(%d)\" ", tok);
991 }
992 }
993
994 return type;
995}
996
997static enum event_type force_token(const char *str, char **tok)
998{
999 const char *save_input_buf;
1000 unsigned long long save_input_buf_ptr;
1001 unsigned long long save_input_buf_siz;
1002 enum event_type type;
1003
1004 /* save off the current input pointers */
1005 save_input_buf = input_buf;
1006 save_input_buf_ptr = input_buf_ptr;
1007 save_input_buf_siz = input_buf_siz;
1008
1009 init_input_buf(str, strlen(str));
1010
1011 type = __read_token(tok);
1012
1013 /* reset back to original token */
1014 input_buf = save_input_buf;
1015 input_buf_ptr = save_input_buf_ptr;
1016 input_buf_siz = save_input_buf_siz;
1017
1018 return type;
1019}
1020
1021static void free_token(char *tok)
1022{
1023 if (tok)
1024 free(tok);
1025}
1026
1027static enum event_type read_token(char **tok)
1028{
1029 enum event_type type;
1030
1031 for (;;) {
1032 type = __read_token(tok);
1033 if (type != EVENT_SPACE)
1034 return type;
1035
1036 free_token(*tok);
1037 }
1038
1039 /* not reached */
1040 *tok = NULL;
1041 return EVENT_NONE;
1042}
1043
1044/**
1045 * pevent_read_token - access to utilites to use the pevent parser
1046 * @tok: The token to return
1047 *
1048 * This will parse tokens from the string given by
1049 * pevent_init_data().
1050 *
1051 * Returns the token type.
1052 */
1053enum event_type pevent_read_token(char **tok)
1054{
1055 return read_token(tok);
1056}
1057
1058/**
1059 * pevent_free_token - free a token returned by pevent_read_token
1060 * @token: the token to free
1061 */
1062void pevent_free_token(char *token)
1063{
1064 free_token(token);
1065}
1066
1067/* no newline */
1068static enum event_type read_token_item(char **tok)
1069{
1070 enum event_type type;
1071
1072 for (;;) {
1073 type = __read_token(tok);
1074 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
1075 return type;
1076 free_token(*tok);
1077 *tok = NULL;
1078 }
1079
1080 /* not reached */
1081 *tok = NULL;
1082 return EVENT_NONE;
1083}
1084
1085static int test_type(enum event_type type, enum event_type expect)
1086{
1087 if (type != expect) {
1088 do_warning("Error: expected type %d but read %d",
1089 expect, type);
1090 return -1;
1091 }
1092 return 0;
1093}
1094
1095static int test_type_token(enum event_type type, const char *token,
1096 enum event_type expect, const char *expect_tok)
1097{
1098 if (type != expect) {
1099 do_warning("Error: expected type %d but read %d",
1100 expect, type);
1101 return -1;
1102 }
1103
1104 if (strcmp(token, expect_tok) != 0) {
1105 do_warning("Error: expected '%s' but read '%s'",
1106 expect_tok, token);
1107 return -1;
1108 }
1109 return 0;
1110}
1111
1112static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
1113{
1114 enum event_type type;
1115
1116 if (newline_ok)
1117 type = read_token(tok);
1118 else
1119 type = read_token_item(tok);
1120 return test_type(type, expect);
1121}
1122
1123static int read_expect_type(enum event_type expect, char **tok)
1124{
1125 return __read_expect_type(expect, tok, 1);
1126}
1127
1128static int __read_expected(enum event_type expect, const char *str,
1129 int newline_ok)
1130{
1131 enum event_type type;
1132 char *token;
1133 int ret;
1134
1135 if (newline_ok)
1136 type = read_token(&token);
1137 else
1138 type = read_token_item(&token);
1139
1140 ret = test_type_token(type, token, expect, str);
1141
1142 free_token(token);
1143
1144 return ret;
1145}
1146
1147static int read_expected(enum event_type expect, const char *str)
1148{
1149 return __read_expected(expect, str, 1);
1150}
1151
1152static int read_expected_item(enum event_type expect, const char *str)
1153{
1154 return __read_expected(expect, str, 0);
1155}
1156
1157static char *event_read_name(void)
1158{
1159 char *token;
1160
1161 if (read_expected(EVENT_ITEM, "name") < 0)
1162 return NULL;
1163
1164 if (read_expected(EVENT_OP, ":") < 0)
1165 return NULL;
1166
1167 if (read_expect_type(EVENT_ITEM, &token) < 0)
1168 goto fail;
1169
1170 return token;
1171
1172 fail:
1173 free_token(token);
1174 return NULL;
1175}
1176
1177static int event_read_id(void)
1178{
1179 char *token;
1180 int id;
1181
1182 if (read_expected_item(EVENT_ITEM, "ID") < 0)
1183 return -1;
1184
1185 if (read_expected(EVENT_OP, ":") < 0)
1186 return -1;
1187
1188 if (read_expect_type(EVENT_ITEM, &token) < 0)
1189 goto fail;
1190
1191 id = strtoul(token, NULL, 0);
1192 free_token(token);
1193 return id;
1194
1195 fail:
1196 free_token(token);
1197 return -1;
1198}
1199
1200static int field_is_string(struct format_field *field)
1201{
1202 if ((field->flags & FIELD_IS_ARRAY) &&
1203 (strstr(field->type, "char") || strstr(field->type, "u8") ||
1204 strstr(field->type, "s8")))
1205 return 1;
1206
1207 return 0;
1208}
1209
1210static int field_is_dynamic(struct format_field *field)
1211{
1212 if (strncmp(field->type, "__data_loc", 10) == 0)
1213 return 1;
1214
1215 return 0;
1216}
1217
1218static int field_is_long(struct format_field *field)
1219{
1220 /* includes long long */
1221 if (strstr(field->type, "long"))
1222 return 1;
1223
1224 return 0;
1225}
1226
1227static int event_read_fields(struct event_format *event, struct format_field **fields)
1228{
1229 struct format_field *field = NULL;
1230 enum event_type type;
1231 char *token;
1232 char *last_token;
1233 int count = 0;
1234
1235 do {
1236 type = read_token(&token);
1237 if (type == EVENT_NEWLINE) {
1238 free_token(token);
1239 return count;
1240 }
1241
1242 count++;
1243
1244 if (test_type_token(type, token, EVENT_ITEM, "field"))
1245 goto fail;
1246 free_token(token);
1247
1248 type = read_token(&token);
1249 /*
1250 * The ftrace fields may still use the "special" name.
1251 * Just ignore it.
1252 */
1253 if (event->flags & EVENT_FL_ISFTRACE &&
1254 type == EVENT_ITEM && strcmp(token, "special") == 0) {
1255 free_token(token);
1256 type = read_token(&token);
1257 }
1258
1259 if (test_type_token(type, token, EVENT_OP, ":") < 0)
1260 goto fail;
1261
1262 free_token(token);
1263 if (read_expect_type(EVENT_ITEM, &token) < 0)
1264 goto fail;
1265
1266 last_token = token;
1267
1268 field = calloc(1, sizeof(*field));
1269 if (!field)
1270 goto fail;
1271
1272 field->event = event;
1273
1274 /* read the rest of the type */
1275 for (;;) {
1276 type = read_token(&token);
1277 if (type == EVENT_ITEM ||
1278 (type == EVENT_OP && strcmp(token, "*") == 0) ||
1279 /*
1280 * Some of the ftrace fields are broken and have
1281 * an illegal "." in them.
1282 */
1283 (event->flags & EVENT_FL_ISFTRACE &&
1284 type == EVENT_OP && strcmp(token, ".") == 0)) {
1285
1286 if (strcmp(token, "*") == 0)
1287 field->flags |= FIELD_IS_POINTER;
1288
1289 if (field->type) {
1290 char *new_type;
1291 new_type = realloc(field->type,
1292 strlen(field->type) +
1293 strlen(last_token) + 2);
1294 if (!new_type) {
1295 free(last_token);
1296 goto fail;
1297 }
1298 field->type = new_type;
1299 strcat(field->type, " ");
1300 strcat(field->type, last_token);
1301 free(last_token);
1302 } else
1303 field->type = last_token;
1304 last_token = token;
1305 continue;
1306 }
1307
1308 break;
1309 }
1310
1311 if (!field->type) {
1312 do_warning("%s: no type found", __func__);
1313 goto fail;
1314 }
1315 field->name = last_token;
1316
1317 if (test_type(type, EVENT_OP))
1318 goto fail;
1319
1320 if (strcmp(token, "[") == 0) {
1321 enum event_type last_type = type;
1322 char *brackets = token;
1323 char *new_brackets;
1324 int len;
1325
1326 field->flags |= FIELD_IS_ARRAY;
1327
1328 type = read_token(&token);
1329
1330 if (type == EVENT_ITEM)
1331 field->arraylen = strtoul(token, NULL, 0);
1332 else
1333 field->arraylen = 0;
1334
1335 while (strcmp(token, "]") != 0) {
1336 if (last_type == EVENT_ITEM &&
1337 type == EVENT_ITEM)
1338 len = 2;
1339 else
1340 len = 1;
1341 last_type = type;
1342
1343 new_brackets = realloc(brackets,
1344 strlen(brackets) +
1345 strlen(token) + len);
1346 if (!new_brackets) {
1347 free(brackets);
1348 goto fail;
1349 }
1350 brackets = new_brackets;
1351 if (len == 2)
1352 strcat(brackets, " ");
1353 strcat(brackets, token);
1354 /* We only care about the last token */
1355 field->arraylen = strtoul(token, NULL, 0);
1356 free_token(token);
1357 type = read_token(&token);
1358 if (type == EVENT_NONE) {
1359 do_warning("failed to find token");
1360 goto fail;
1361 }
1362 }
1363
1364 free_token(token);
1365
1366 new_brackets = realloc(brackets, strlen(brackets) + 2);
1367 if (!new_brackets) {
1368 free(brackets);
1369 goto fail;
1370 }
1371 brackets = new_brackets;
1372 strcat(brackets, "]");
1373
1374 /* add brackets to type */
1375
1376 type = read_token(&token);
1377 /*
1378 * If the next token is not an OP, then it is of
1379 * the format: type [] item;
1380 */
1381 if (type == EVENT_ITEM) {
1382 char *new_type;
1383 new_type = realloc(field->type,
1384 strlen(field->type) +
1385 strlen(field->name) +
1386 strlen(brackets) + 2);
1387 if (!new_type) {
1388 free(brackets);
1389 goto fail;
1390 }
1391 field->type = new_type;
1392 strcat(field->type, " ");
1393 strcat(field->type, field->name);
1394 free_token(field->name);
1395 strcat(field->type, brackets);
1396 field->name = token;
1397 type = read_token(&token);
1398 } else {
1399 char *new_type;
1400 new_type = realloc(field->type,
1401 strlen(field->type) +
1402 strlen(brackets) + 1);
1403 if (!new_type) {
1404 free(brackets);
1405 goto fail;
1406 }
1407 field->type = new_type;
1408 strcat(field->type, brackets);
1409 }
1410 free(brackets);
1411 }
1412
1413 if (field_is_string(field))
1414 field->flags |= FIELD_IS_STRING;
1415 if (field_is_dynamic(field))
1416 field->flags |= FIELD_IS_DYNAMIC;
1417 if (field_is_long(field))
1418 field->flags |= FIELD_IS_LONG;
1419
1420 if (test_type_token(type, token, EVENT_OP, ";"))
1421 goto fail;
1422 free_token(token);
1423
1424 if (read_expected(EVENT_ITEM, "offset") < 0)
1425 goto fail_expect;
1426
1427 if (read_expected(EVENT_OP, ":") < 0)
1428 goto fail_expect;
1429
1430 if (read_expect_type(EVENT_ITEM, &token))
1431 goto fail;
1432 field->offset = strtoul(token, NULL, 0);
1433 free_token(token);
1434
1435 if (read_expected(EVENT_OP, ";") < 0)
1436 goto fail_expect;
1437
1438 if (read_expected(EVENT_ITEM, "size") < 0)
1439 goto fail_expect;
1440
1441 if (read_expected(EVENT_OP, ":") < 0)
1442 goto fail_expect;
1443
1444 if (read_expect_type(EVENT_ITEM, &token))
1445 goto fail;
1446 field->size = strtoul(token, NULL, 0);
1447 free_token(token);
1448
1449 if (read_expected(EVENT_OP, ";") < 0)
1450 goto fail_expect;
1451
1452 type = read_token(&token);
1453 if (type != EVENT_NEWLINE) {
1454 /* newer versions of the kernel have a "signed" type */
1455 if (test_type_token(type, token, EVENT_ITEM, "signed"))
1456 goto fail;
1457
1458 free_token(token);
1459
1460 if (read_expected(EVENT_OP, ":") < 0)
1461 goto fail_expect;
1462
1463 if (read_expect_type(EVENT_ITEM, &token))
1464 goto fail;
1465
1466 /* add signed type */
1467
1468 free_token(token);
1469 if (read_expected(EVENT_OP, ";") < 0)
1470 goto fail_expect;
1471
1472 if (read_expect_type(EVENT_NEWLINE, &token))
1473 goto fail;
1474 }
1475
1476 free_token(token);
1477
1478 if (field->flags & FIELD_IS_ARRAY) {
1479 if (field->arraylen)
1480 field->elementsize = field->size / field->arraylen;
1481 else if (field->flags & FIELD_IS_STRING)
1482 field->elementsize = 1;
1483 else
1484 field->elementsize = event->pevent->long_size;
1485 } else
1486 field->elementsize = field->size;
1487
1488 *fields = field;
1489 fields = &field->next;
1490
1491 } while (1);
1492
1493 return 0;
1494
1495fail:
1496 free_token(token);
1497fail_expect:
1498 if (field) {
1499 free(field->type);
1500 free(field->name);
1501 free(field);
1502 }
1503 return -1;
1504}
1505
1506static int event_read_format(struct event_format *event)
1507{
1508 char *token;
1509 int ret;
1510
1511 if (read_expected_item(EVENT_ITEM, "format") < 0)
1512 return -1;
1513
1514 if (read_expected(EVENT_OP, ":") < 0)
1515 return -1;
1516
1517 if (read_expect_type(EVENT_NEWLINE, &token))
1518 goto fail;
1519 free_token(token);
1520
1521 ret = event_read_fields(event, &event->format.common_fields);
1522 if (ret < 0)
1523 return ret;
1524 event->format.nr_common = ret;
1525
1526 ret = event_read_fields(event, &event->format.fields);
1527 if (ret < 0)
1528 return ret;
1529 event->format.nr_fields = ret;
1530
1531 return 0;
1532
1533 fail:
1534 free_token(token);
1535 return -1;
1536}
1537
1538static enum event_type
1539process_arg_token(struct event_format *event, struct print_arg *arg,
1540 char **tok, enum event_type type);
1541
1542static enum event_type
1543process_arg(struct event_format *event, struct print_arg *arg, char **tok)
1544{
1545 enum event_type type;
1546 char *token;
1547
1548 type = read_token(&token);
1549 *tok = token;
1550
1551 return process_arg_token(event, arg, tok, type);
1552}
1553
1554static enum event_type
1555process_op(struct event_format *event, struct print_arg *arg, char **tok);
1556
1557static enum event_type
1558process_cond(struct event_format *event, struct print_arg *top, char **tok)
1559{
1560 struct print_arg *arg, *left, *right;
1561 enum event_type type;
1562 char *token = NULL;
1563
1564 arg = alloc_arg();
1565 left = alloc_arg();
1566 right = alloc_arg();
1567
1568 if (!arg || !left || !right) {
1569 do_warning("%s: not enough memory!", __func__);
1570 /* arg will be freed at out_free */
1571 free_arg(left);
1572 free_arg(right);
1573 goto out_free;
1574 }
1575
1576 arg->type = PRINT_OP;
1577 arg->op.left = left;
1578 arg->op.right = right;
1579
1580 *tok = NULL;
1581 type = process_arg(event, left, &token);
1582
1583 again:
1584 /* Handle other operations in the arguments */
1585 if (type == EVENT_OP && strcmp(token, ":") != 0) {
1586 type = process_op(event, left, &token);
1587 goto again;
1588 }
1589
1590 if (test_type_token(type, token, EVENT_OP, ":"))
1591 goto out_free;
1592
1593 arg->op.op = token;
1594
1595 type = process_arg(event, right, &token);
1596
1597 top->op.right = arg;
1598
1599 *tok = token;
1600 return type;
1601
1602out_free:
1603 /* Top may point to itself */
1604 top->op.right = NULL;
1605 free_token(token);
1606 free_arg(arg);
1607 return EVENT_ERROR;
1608}
1609
1610static enum event_type
1611process_array(struct event_format *event, struct print_arg *top, char **tok)
1612{
1613 struct print_arg *arg;
1614 enum event_type type;
1615 char *token = NULL;
1616
1617 arg = alloc_arg();
1618 if (!arg) {
1619 do_warning("%s: not enough memory!", __func__);
1620 /* '*tok' is set to top->op.op. No need to free. */
1621 *tok = NULL;
1622 return EVENT_ERROR;
1623 }
1624
1625 *tok = NULL;
1626 type = process_arg(event, arg, &token);
1627 if (test_type_token(type, token, EVENT_OP, "]"))
1628 goto out_free;
1629
1630 top->op.right = arg;
1631
1632 free_token(token);
1633 type = read_token_item(&token);
1634 *tok = token;
1635
1636 return type;
1637
1638out_free:
1639 free_token(token);
1640 free_arg(arg);
1641 return EVENT_ERROR;
1642}
1643
1644static int get_op_prio(char *op)
1645{
1646 if (!op[1]) {
1647 switch (op[0]) {
1648 case '~':
1649 case '!':
1650 return 4;
1651 case '*':
1652 case '/':
1653 case '%':
1654 return 6;
1655 case '+':
1656 case '-':
1657 return 7;
1658 /* '>>' and '<<' are 8 */
1659 case '<':
1660 case '>':
1661 return 9;
1662 /* '==' and '!=' are 10 */
1663 case '&':
1664 return 11;
1665 case '^':
1666 return 12;
1667 case '|':
1668 return 13;
1669 case '?':
1670 return 16;
1671 default:
1672 do_warning("unknown op '%c'", op[0]);
1673 return -1;
1674 }
1675 } else {
1676 if (strcmp(op, "++") == 0 ||
1677 strcmp(op, "--") == 0) {
1678 return 3;
1679 } else if (strcmp(op, ">>") == 0 ||
1680 strcmp(op, "<<") == 0) {
1681 return 8;
1682 } else if (strcmp(op, ">=") == 0 ||
1683 strcmp(op, "<=") == 0) {
1684 return 9;
1685 } else if (strcmp(op, "==") == 0 ||
1686 strcmp(op, "!=") == 0) {
1687 return 10;
1688 } else if (strcmp(op, "&&") == 0) {
1689 return 14;
1690 } else if (strcmp(op, "||") == 0) {
1691 return 15;
1692 } else {
1693 do_warning("unknown op '%s'", op);
1694 return -1;
1695 }
1696 }
1697}
1698
1699static int set_op_prio(struct print_arg *arg)
1700{
1701
1702 /* single ops are the greatest */
1703 if (!arg->op.left || arg->op.left->type == PRINT_NULL)
1704 arg->op.prio = 0;
1705 else
1706 arg->op.prio = get_op_prio(arg->op.op);
1707
1708 return arg->op.prio;
1709}
1710
1711/* Note, *tok does not get freed, but will most likely be saved */
1712static enum event_type
1713process_op(struct event_format *event, struct print_arg *arg, char **tok)
1714{
1715 struct print_arg *left, *right = NULL;
1716 enum event_type type;
1717 char *token;
1718
1719 /* the op is passed in via tok */
1720 token = *tok;
1721
1722 if (arg->type == PRINT_OP && !arg->op.left) {
1723 /* handle single op */
1724 if (token[1]) {
1725 do_warning("bad op token %s", token);
1726 goto out_free;
1727 }
1728 switch (token[0]) {
1729 case '~':
1730 case '!':
1731 case '+':
1732 case '-':
1733 break;
1734 default:
1735 do_warning("bad op token %s", token);
1736 goto out_free;
1737
1738 }
1739
1740 /* make an empty left */
1741 left = alloc_arg();
1742 if (!left)
1743 goto out_warn_free;
1744
1745 left->type = PRINT_NULL;
1746 arg->op.left = left;
1747
1748 right = alloc_arg();
1749 if (!right)
1750 goto out_warn_free;
1751
1752 arg->op.right = right;
1753
1754 /* do not free the token, it belongs to an op */
1755 *tok = NULL;
1756 type = process_arg(event, right, tok);
1757
1758 } else if (strcmp(token, "?") == 0) {
1759
1760 left = alloc_arg();
1761 if (!left)
1762 goto out_warn_free;
1763
1764 /* copy the top arg to the left */
1765 *left = *arg;
1766
1767 arg->type = PRINT_OP;
1768 arg->op.op = token;
1769 arg->op.left = left;
1770 arg->op.prio = 0;
1771
1772 /* it will set arg->op.right */
1773 type = process_cond(event, arg, tok);
1774
1775 } else if (strcmp(token, ">>") == 0 ||
1776 strcmp(token, "<<") == 0 ||
1777 strcmp(token, "&") == 0 ||
1778 strcmp(token, "|") == 0 ||
1779 strcmp(token, "&&") == 0 ||
1780 strcmp(token, "||") == 0 ||
1781 strcmp(token, "-") == 0 ||
1782 strcmp(token, "+") == 0 ||
1783 strcmp(token, "*") == 0 ||
1784 strcmp(token, "^") == 0 ||
1785 strcmp(token, "/") == 0 ||
1786 strcmp(token, "<") == 0 ||
1787 strcmp(token, ">") == 0 ||
1788 strcmp(token, "==") == 0 ||
1789 strcmp(token, "!=") == 0) {
1790
1791 left = alloc_arg();
1792 if (!left)
1793 goto out_warn_free;
1794
1795 /* copy the top arg to the left */
1796 *left = *arg;
1797
1798 arg->type = PRINT_OP;
1799 arg->op.op = token;
1800 arg->op.left = left;
1801 arg->op.right = NULL;
1802
1803 if (set_op_prio(arg) == -1) {
1804 event->flags |= EVENT_FL_FAILED;
1805 /* arg->op.op (= token) will be freed at out_free */
1806 arg->op.op = NULL;
1807 goto out_free;
1808 }
1809
1810 type = read_token_item(&token);
1811 *tok = token;
1812
1813 /* could just be a type pointer */
1814 if ((strcmp(arg->op.op, "*") == 0) &&
1815 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1816 char *new_atom;
1817
1818 if (left->type != PRINT_ATOM) {
1819 do_warning("bad pointer type");
1820 goto out_free;
1821 }
1822 new_atom = realloc(left->atom.atom,
1823 strlen(left->atom.atom) + 3);
1824 if (!new_atom)
1825 goto out_warn_free;
1826
1827 left->atom.atom = new_atom;
1828 strcat(left->atom.atom, " *");
1829 free(arg->op.op);
1830 *arg = *left;
1831 free(left);
1832
1833 return type;
1834 }
1835
1836 right = alloc_arg();
1837 if (!right)
1838 goto out_warn_free;
1839
1840 type = process_arg_token(event, right, tok, type);
1841 arg->op.right = right;
1842
1843 } else if (strcmp(token, "[") == 0) {
1844
1845 left = alloc_arg();
1846 if (!left)
1847 goto out_warn_free;
1848
1849 *left = *arg;
1850
1851 arg->type = PRINT_OP;
1852 arg->op.op = token;
1853 arg->op.left = left;
1854
1855 arg->op.prio = 0;
1856
1857 /* it will set arg->op.right */
1858 type = process_array(event, arg, tok);
1859
1860 } else {
1861 do_warning("unknown op '%s'", token);
1862 event->flags |= EVENT_FL_FAILED;
1863 /* the arg is now the left side */
1864 goto out_free;
1865 }
1866
1867 if (type == EVENT_OP && strcmp(*tok, ":") != 0) {
1868 int prio;
1869
1870 /* higher prios need to be closer to the root */
1871 prio = get_op_prio(*tok);
1872
1873 if (prio > arg->op.prio)
1874 return process_op(event, arg, tok);
1875
1876 return process_op(event, right, tok);
1877 }
1878
1879 return type;
1880
1881out_warn_free:
1882 do_warning("%s: not enough memory!", __func__);
1883out_free:
1884 free_token(token);
1885 *tok = NULL;
1886 return EVENT_ERROR;
1887}
1888
1889static enum event_type
1890process_entry(struct event_format *event __maybe_unused, struct print_arg *arg,
1891 char **tok)
1892{
1893 enum event_type type;
1894 char *field;
1895 char *token;
1896
1897 if (read_expected(EVENT_OP, "->") < 0)
1898 goto out_err;
1899
1900 if (read_expect_type(EVENT_ITEM, &token) < 0)
1901 goto out_free;
1902 field = token;
1903
1904 arg->type = PRINT_FIELD;
1905 arg->field.name = field;
1906
1907 if (is_flag_field) {
1908 arg->field.field = pevent_find_any_field(event, arg->field.name);
1909 arg->field.field->flags |= FIELD_IS_FLAG;
1910 is_flag_field = 0;
1911 } else if (is_symbolic_field) {
1912 arg->field.field = pevent_find_any_field(event, arg->field.name);
1913 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1914 is_symbolic_field = 0;
1915 }
1916
1917 type = read_token(&token);
1918 *tok = token;
1919
1920 return type;
1921
1922 out_free:
1923 free_token(token);
1924 out_err:
1925 *tok = NULL;
1926 return EVENT_ERROR;
1927}
1928
1929static char *arg_eval (struct print_arg *arg);
1930
1931static unsigned long long
1932eval_type_str(unsigned long long val, const char *type, int pointer)
1933{
1934 int sign = 0;
1935 char *ref;
1936 int len;
1937
1938 len = strlen(type);
1939
1940 if (pointer) {
1941
1942 if (type[len-1] != '*') {
1943 do_warning("pointer expected with non pointer type");
1944 return val;
1945 }
1946
1947 ref = malloc(len);
1948 if (!ref) {
1949 do_warning("%s: not enough memory!", __func__);
1950 return val;
1951 }
1952 memcpy(ref, type, len);
1953
1954 /* chop off the " *" */
1955 ref[len - 2] = 0;
1956
1957 val = eval_type_str(val, ref, 0);
1958 free(ref);
1959 return val;
1960 }
1961
1962 /* check if this is a pointer */
1963 if (type[len - 1] == '*')
1964 return val;
1965
1966 /* Try to figure out the arg size*/
1967 if (strncmp(type, "struct", 6) == 0)
1968 /* all bets off */
1969 return val;
1970
1971 if (strcmp(type, "u8") == 0)
1972 return val & 0xff;
1973
1974 if (strcmp(type, "u16") == 0)
1975 return val & 0xffff;
1976
1977 if (strcmp(type, "u32") == 0)
1978 return val & 0xffffffff;
1979
1980 if (strcmp(type, "u64") == 0 ||
1981 strcmp(type, "s64"))
1982 return val;
1983
1984 if (strcmp(type, "s8") == 0)
1985 return (unsigned long long)(char)val & 0xff;
1986
1987 if (strcmp(type, "s16") == 0)
1988 return (unsigned long long)(short)val & 0xffff;
1989
1990 if (strcmp(type, "s32") == 0)
1991 return (unsigned long long)(int)val & 0xffffffff;
1992
1993 if (strncmp(type, "unsigned ", 9) == 0) {
1994 sign = 0;
1995 type += 9;
1996 }
1997
1998 if (strcmp(type, "char") == 0) {
1999 if (sign)
2000 return (unsigned long long)(char)val & 0xff;
2001 else
2002 return val & 0xff;
2003 }
2004
2005 if (strcmp(type, "short") == 0) {
2006 if (sign)
2007 return (unsigned long long)(short)val & 0xffff;
2008 else
2009 return val & 0xffff;
2010 }
2011
2012 if (strcmp(type, "int") == 0) {
2013 if (sign)
2014 return (unsigned long long)(int)val & 0xffffffff;
2015 else
2016 return val & 0xffffffff;
2017 }
2018
2019 return val;
2020}
2021
2022/*
2023 * Try to figure out the type.
2024 */
2025static unsigned long long
2026eval_type(unsigned long long val, struct print_arg *arg, int pointer)
2027{
2028 if (arg->type != PRINT_TYPE) {
2029 do_warning("expected type argument");
2030 return 0;
2031 }
2032
2033 return eval_type_str(val, arg->typecast.type, pointer);
2034}
2035
2036static int arg_num_eval(struct print_arg *arg, long long *val)
2037{
2038 long long left, right;
2039 int ret = 1;
2040
2041 switch (arg->type) {
2042 case PRINT_ATOM:
2043 *val = strtoll(arg->atom.atom, NULL, 0);
2044 break;
2045 case PRINT_TYPE:
2046 ret = arg_num_eval(arg->typecast.item, val);
2047 if (!ret)
2048 break;
2049 *val = eval_type(*val, arg, 0);
2050 break;
2051 case PRINT_OP:
2052 switch (arg->op.op[0]) {
2053 case '|':
2054 ret = arg_num_eval(arg->op.left, &left);
2055 if (!ret)
2056 break;
2057 ret = arg_num_eval(arg->op.right, &right);
2058 if (!ret)
2059 break;
2060 if (arg->op.op[1])
2061 *val = left || right;
2062 else
2063 *val = left | right;
2064 break;
2065 case '&':
2066 ret = arg_num_eval(arg->op.left, &left);
2067 if (!ret)
2068 break;
2069 ret = arg_num_eval(arg->op.right, &right);
2070 if (!ret)
2071 break;
2072 if (arg->op.op[1])
2073 *val = left && right;
2074 else
2075 *val = left & right;
2076 break;
2077 case '<':
2078 ret = arg_num_eval(arg->op.left, &left);
2079 if (!ret)
2080 break;
2081 ret = arg_num_eval(arg->op.right, &right);
2082 if (!ret)
2083 break;
2084 switch (arg->op.op[1]) {
2085 case 0:
2086 *val = left < right;
2087 break;
2088 case '<':
2089 *val = left << right;
2090 break;
2091 case '=':
2092 *val = left <= right;
2093 break;
2094 default:
2095 do_warning("unknown op '%s'", arg->op.op);
2096 ret = 0;
2097 }
2098 break;
2099 case '>':
2100 ret = arg_num_eval(arg->op.left, &left);
2101 if (!ret)
2102 break;
2103 ret = arg_num_eval(arg->op.right, &right);
2104 if (!ret)
2105 break;
2106 switch (arg->op.op[1]) {
2107 case 0:
2108 *val = left > right;
2109 break;
2110 case '>':
2111 *val = left >> right;
2112 break;
2113 case '=':
2114 *val = left >= right;
2115 break;
2116 default:
2117 do_warning("unknown op '%s'", arg->op.op);
2118 ret = 0;
2119 }
2120 break;
2121 case '=':
2122 ret = arg_num_eval(arg->op.left, &left);
2123 if (!ret)
2124 break;
2125 ret = arg_num_eval(arg->op.right, &right);
2126 if (!ret)
2127 break;
2128
2129 if (arg->op.op[1] != '=') {
2130 do_warning("unknown op '%s'", arg->op.op);
2131 ret = 0;
2132 } else
2133 *val = left == right;
2134 break;
2135 case '!':
2136 ret = arg_num_eval(arg->op.left, &left);
2137 if (!ret)
2138 break;
2139 ret = arg_num_eval(arg->op.right, &right);
2140 if (!ret)
2141 break;
2142
2143 switch (arg->op.op[1]) {
2144 case '=':
2145 *val = left != right;
2146 break;
2147 default:
2148 do_warning("unknown op '%s'", arg->op.op);
2149 ret = 0;
2150 }
2151 break;
2152 case '-':
2153 /* check for negative */
2154 if (arg->op.left->type == PRINT_NULL)
2155 left = 0;
2156 else
2157 ret = arg_num_eval(arg->op.left, &left);
2158 if (!ret)
2159 break;
2160 ret = arg_num_eval(arg->op.right, &right);
2161 if (!ret)
2162 break;
2163 *val = left - right;
2164 break;
2165 case '+':
2166 if (arg->op.left->type == PRINT_NULL)
2167 left = 0;
2168 else
2169 ret = arg_num_eval(arg->op.left, &left);
2170 if (!ret)
2171 break;
2172 ret = arg_num_eval(arg->op.right, &right);
2173 if (!ret)
2174 break;
2175 *val = left + right;
2176 break;
2177 default:
2178 do_warning("unknown op '%s'", arg->op.op);
2179 ret = 0;
2180 }
2181 break;
2182
2183 case PRINT_NULL:
2184 case PRINT_FIELD ... PRINT_SYMBOL:
2185 case PRINT_STRING:
2186 case PRINT_BSTRING:
2187 default:
2188 do_warning("invalid eval type %d", arg->type);
2189 ret = 0;
2190
2191 }
2192 return ret;
2193}
2194
2195static char *arg_eval (struct print_arg *arg)
2196{
2197 long long val;
2198 static char buf[20];
2199
2200 switch (arg->type) {
2201 case PRINT_ATOM:
2202 return arg->atom.atom;
2203 case PRINT_TYPE:
2204 return arg_eval(arg->typecast.item);
2205 case PRINT_OP:
2206 if (!arg_num_eval(arg, &val))
2207 break;
2208 sprintf(buf, "%lld", val);
2209 return buf;
2210
2211 case PRINT_NULL:
2212 case PRINT_FIELD ... PRINT_SYMBOL:
2213 case PRINT_STRING:
2214 case PRINT_BSTRING:
2215 default:
2216 do_warning("invalid eval type %d", arg->type);
2217 break;
2218 }
2219
2220 return NULL;
2221}
2222
2223static enum event_type
2224process_fields(struct event_format *event, struct print_flag_sym **list, char **tok)
2225{
2226 enum event_type type;
2227 struct print_arg *arg = NULL;
2228 struct print_flag_sym *field;
2229 char *token = *tok;
2230 char *value;
2231
2232 do {
2233 free_token(token);
2234 type = read_token_item(&token);
2235 if (test_type_token(type, token, EVENT_OP, "{"))
2236 break;
2237
2238 arg = alloc_arg();
2239 if (!arg)
2240 goto out_free;
2241
2242 free_token(token);
2243 type = process_arg(event, arg, &token);
2244
2245 if (type == EVENT_OP)
2246 type = process_op(event, arg, &token);
2247
2248 if (type == EVENT_ERROR)
2249 goto out_free;
2250
2251 if (test_type_token(type, token, EVENT_DELIM, ","))
2252 goto out_free;
2253
2254 field = calloc(1, sizeof(*field));
2255 if (!field)
2256 goto out_free;
2257
2258 value = arg_eval(arg);
2259 if (value == NULL)
2260 goto out_free_field;
2261 field->value = strdup(value);
2262 if (field->value == NULL)
2263 goto out_free_field;
2264
2265 free_arg(arg);
2266 arg = alloc_arg();
2267 if (!arg)
2268 goto out_free;
2269
2270 free_token(token);
2271 type = process_arg(event, arg, &token);
2272 if (test_type_token(type, token, EVENT_OP, "}"))
2273 goto out_free_field;
2274
2275 value = arg_eval(arg);
2276 if (value == NULL)
2277 goto out_free_field;
2278 field->str = strdup(value);
2279 if (field->str == NULL)
2280 goto out_free_field;
2281 free_arg(arg);
2282 arg = NULL;
2283
2284 *list = field;
2285 list = &field->next;
2286
2287 free_token(token);
2288 type = read_token_item(&token);
2289 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
2290
2291 *tok = token;
2292 return type;
2293
2294out_free_field:
2295 free_flag_sym(field);
2296out_free:
2297 free_arg(arg);
2298 free_token(token);
2299 *tok = NULL;
2300
2301 return EVENT_ERROR;
2302}
2303
2304static enum event_type
2305process_flags(struct event_format *event, struct print_arg *arg, char **tok)
2306{
2307 struct print_arg *field;
2308 enum event_type type;
2309 char *token;
2310
2311 memset(arg, 0, sizeof(*arg));
2312 arg->type = PRINT_FLAGS;
2313
2314 field = alloc_arg();
2315 if (!field) {
2316 do_warning("%s: not enough memory!", __func__);
2317 goto out_free;
2318 }
2319
2320 type = process_arg(event, field, &token);
2321
2322 /* Handle operations in the first argument */
2323 while (type == EVENT_OP)
2324 type = process_op(event, field, &token);
2325
2326 if (test_type_token(type, token, EVENT_DELIM, ","))
2327 goto out_free_field;
2328 free_token(token);
2329
2330 arg->flags.field = field;
2331
2332 type = read_token_item(&token);
2333 if (event_item_type(type)) {
2334 arg->flags.delim = token;
2335 type = read_token_item(&token);
2336 }
2337
2338 if (test_type_token(type, token, EVENT_DELIM, ","))
2339 goto out_free;
2340
2341 type = process_fields(event, &arg->flags.flags, &token);
2342 if (test_type_token(type, token, EVENT_DELIM, ")"))
2343 goto out_free;
2344
2345 free_token(token);
2346 type = read_token_item(tok);
2347 return type;
2348
2349out_free_field:
2350 free_arg(field);
2351out_free:
2352 free_token(token);
2353 *tok = NULL;
2354 return EVENT_ERROR;
2355}
2356
2357static enum event_type
2358process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
2359{
2360 struct print_arg *field;
2361 enum event_type type;
2362 char *token;
2363
2364 memset(arg, 0, sizeof(*arg));
2365 arg->type = PRINT_SYMBOL;
2366
2367 field = alloc_arg();
2368 if (!field) {
2369 do_warning("%s: not enough memory!", __func__);
2370 goto out_free;
2371 }
2372
2373 type = process_arg(event, field, &token);
2374 if (test_type_token(type, token, EVENT_DELIM, ","))
2375 goto out_free_field;
2376
2377 arg->symbol.field = field;
2378
2379 type = process_fields(event, &arg->symbol.symbols, &token);
2380 if (test_type_token(type, token, EVENT_DELIM, ")"))
2381 goto out_free;
2382
2383 free_token(token);
2384 type = read_token_item(tok);
2385 return type;
2386
2387out_free_field:
2388 free_arg(field);
2389out_free:
2390 free_token(token);
2391 *tok = NULL;
2392 return EVENT_ERROR;
2393}
2394
2395static enum event_type
2396process_hex(struct event_format *event, struct print_arg *arg, char **tok)
2397{
2398 struct print_arg *field;
2399 enum event_type type;
2400 char *token;
2401
2402 memset(arg, 0, sizeof(*arg));
2403 arg->type = PRINT_HEX;
2404
2405 field = alloc_arg();
2406 if (!field) {
2407 do_warning("%s: not enough memory!", __func__);
2408 goto out_free;
2409 }
2410
2411 type = process_arg(event, field, &token);
2412
2413 if (test_type_token(type, token, EVENT_DELIM, ","))
2414 goto out_free;
2415
2416 arg->hex.field = field;
2417
2418 free_token(token);
2419
2420 field = alloc_arg();
2421 if (!field) {
2422 do_warning("%s: not enough memory!", __func__);
2423 *tok = NULL;
2424 return EVENT_ERROR;
2425 }
2426
2427 type = process_arg(event, field, &token);
2428
2429 if (test_type_token(type, token, EVENT_DELIM, ")"))
2430 goto out_free;
2431
2432 arg->hex.size = field;
2433
2434 free_token(token);
2435 type = read_token_item(tok);
2436 return type;
2437
2438 out_free:
2439 free_arg(field);
2440 free_token(token);
2441 *tok = NULL;
2442 return EVENT_ERROR;
2443}
2444
2445static enum event_type
2446process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
2447{
2448 struct format_field *field;
2449 enum event_type type;
2450 char *token;
2451
2452 memset(arg, 0, sizeof(*arg));
2453 arg->type = PRINT_DYNAMIC_ARRAY;
2454
2455 /*
2456 * The item within the parenthesis is another field that holds
2457 * the index into where the array starts.
2458 */
2459 type = read_token(&token);
2460 *tok = token;
2461 if (type != EVENT_ITEM)
2462 goto out_free;
2463
2464 /* Find the field */
2465
2466 field = pevent_find_field(event, token);
2467 if (!field)
2468 goto out_free;
2469
2470 arg->dynarray.field = field;
2471 arg->dynarray.index = 0;
2472
2473 if (read_expected(EVENT_DELIM, ")") < 0)
2474 goto out_free;
2475
2476 free_token(token);
2477 type = read_token_item(&token);
2478 *tok = token;
2479 if (type != EVENT_OP || strcmp(token, "[") != 0)
2480 return type;
2481
2482 free_token(token);
2483 arg = alloc_arg();
2484 if (!field) {
2485 do_warning("%s: not enough memory!", __func__);
2486 *tok = NULL;
2487 return EVENT_ERROR;
2488 }
2489
2490 type = process_arg(event, arg, &token);
2491 if (type == EVENT_ERROR)
2492 goto out_free_arg;
2493
2494 if (!test_type_token(type, token, EVENT_OP, "]"))
2495 goto out_free_arg;
2496
2497 free_token(token);
2498 type = read_token_item(tok);
2499 return type;
2500
2501 out_free_arg:
2502 free_arg(arg);
2503 out_free:
2504 free_token(token);
2505 *tok = NULL;
2506 return EVENT_ERROR;
2507}
2508
2509static enum event_type
2510process_paren(struct event_format *event, struct print_arg *arg, char **tok)
2511{
2512 struct print_arg *item_arg;
2513 enum event_type type;
2514 char *token;
2515
2516 type = process_arg(event, arg, &token);
2517
2518 if (type == EVENT_ERROR)
2519 goto out_free;
2520
2521 if (type == EVENT_OP)
2522 type = process_op(event, arg, &token);
2523
2524 if (type == EVENT_ERROR)
2525 goto out_free;
2526
2527 if (test_type_token(type, token, EVENT_DELIM, ")"))
2528 goto out_free;
2529
2530 free_token(token);
2531 type = read_token_item(&token);
2532
2533 /*
2534 * If the next token is an item or another open paren, then
2535 * this was a typecast.
2536 */
2537 if (event_item_type(type) ||
2538 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
2539
2540 /* make this a typecast and contine */
2541
2542 /* prevous must be an atom */
2543 if (arg->type != PRINT_ATOM) {
2544 do_warning("previous needed to be PRINT_ATOM");
2545 goto out_free;
2546 }
2547
2548 item_arg = alloc_arg();
2549 if (!item_arg) {
2550 do_warning("%s: not enough memory!", __func__);
2551 goto out_free;
2552 }
2553
2554 arg->type = PRINT_TYPE;
2555 arg->typecast.type = arg->atom.atom;
2556 arg->typecast.item = item_arg;
2557 type = process_arg_token(event, item_arg, &token, type);
2558
2559 }
2560
2561 *tok = token;
2562 return type;
2563
2564 out_free:
2565 free_token(token);
2566 *tok = NULL;
2567 return EVENT_ERROR;
2568}
2569
2570
2571static enum event_type
2572process_str(struct event_format *event __maybe_unused, struct print_arg *arg,
2573 char **tok)
2574{
2575 enum event_type type;
2576 char *token;
2577
2578 if (read_expect_type(EVENT_ITEM, &token) < 0)
2579 goto out_free;
2580
2581 arg->type = PRINT_STRING;
2582 arg->string.string = token;
2583 arg->string.offset = -1;
2584
2585 if (read_expected(EVENT_DELIM, ")") < 0)
2586 goto out_err;
2587
2588 type = read_token(&token);
2589 *tok = token;
2590
2591 return type;
2592
2593 out_free:
2594 free_token(token);
2595 out_err:
2596 *tok = NULL;
2597 return EVENT_ERROR;
2598}
2599
2600static struct pevent_function_handler *
2601find_func_handler(struct pevent *pevent, char *func_name)
2602{
2603 struct pevent_function_handler *func;
2604
2605 if (!pevent)
2606 return NULL;
2607
2608 for (func = pevent->func_handlers; func; func = func->next) {
2609 if (strcmp(func->name, func_name) == 0)
2610 break;
2611 }
2612
2613 return func;
2614}
2615
2616static void remove_func_handler(struct pevent *pevent, char *func_name)
2617{
2618 struct pevent_function_handler *func;
2619 struct pevent_function_handler **next;
2620
2621 next = &pevent->func_handlers;
2622 while ((func = *next)) {
2623 if (strcmp(func->name, func_name) == 0) {
2624 *next = func->next;
2625 free_func_handle(func);
2626 break;
2627 }
2628 next = &func->next;
2629 }
2630}
2631
2632static enum event_type
2633process_func_handler(struct event_format *event, struct pevent_function_handler *func,
2634 struct print_arg *arg, char **tok)
2635{
2636 struct print_arg **next_arg;
2637 struct print_arg *farg;
2638 enum event_type type;
2639 char *token;
2640 const char *test;
2641 int i;
2642
2643 arg->type = PRINT_FUNC;
2644 arg->func.func = func;
2645
2646 *tok = NULL;
2647
2648 next_arg = &(arg->func.args);
2649 for (i = 0; i < func->nr_args; i++) {
2650 farg = alloc_arg();
2651 if (!farg) {
2652 do_warning("%s: not enough memory!", __func__);
2653 return EVENT_ERROR;
2654 }
2655
2656 type = process_arg(event, farg, &token);
2657 if (i < (func->nr_args - 1))
2658 test = ",";
2659 else
2660 test = ")";
2661
2662 if (test_type_token(type, token, EVENT_DELIM, test)) {
2663 free_arg(farg);
2664 free_token(token);
2665 return EVENT_ERROR;
2666 }
2667
2668 *next_arg = farg;
2669 next_arg = &(farg->next);
2670 free_token(token);
2671 }
2672
2673 type = read_token(&token);
2674 *tok = token;
2675
2676 return type;
2677}
2678
2679static enum event_type
2680process_function(struct event_format *event, struct print_arg *arg,
2681 char *token, char **tok)
2682{
2683 struct pevent_function_handler *func;
2684
2685 if (strcmp(token, "__print_flags") == 0) {
2686 free_token(token);
2687 is_flag_field = 1;
2688 return process_flags(event, arg, tok);
2689 }
2690 if (strcmp(token, "__print_symbolic") == 0) {
2691 free_token(token);
2692 is_symbolic_field = 1;
2693 return process_symbols(event, arg, tok);
2694 }
2695 if (strcmp(token, "__print_hex") == 0) {
2696 free_token(token);
2697 return process_hex(event, arg, tok);
2698 }
2699 if (strcmp(token, "__get_str") == 0) {
2700 free_token(token);
2701 return process_str(event, arg, tok);
2702 }
2703 if (strcmp(token, "__get_dynamic_array") == 0) {
2704 free_token(token);
2705 return process_dynamic_array(event, arg, tok);
2706 }
2707
2708 func = find_func_handler(event->pevent, token);
2709 if (func) {
2710 free_token(token);
2711 return process_func_handler(event, func, arg, tok);
2712 }
2713
2714 do_warning("function %s not defined", token);
2715 free_token(token);
2716 return EVENT_ERROR;
2717}
2718
2719static enum event_type
2720process_arg_token(struct event_format *event, struct print_arg *arg,
2721 char **tok, enum event_type type)
2722{
2723 char *token;
2724 char *atom;
2725
2726 token = *tok;
2727
2728 switch (type) {
2729 case EVENT_ITEM:
2730 if (strcmp(token, "REC") == 0) {
2731 free_token(token);
2732 type = process_entry(event, arg, &token);
2733 break;
2734 }
2735 atom = token;
2736 /* test the next token */
2737 type = read_token_item(&token);
2738
2739 /*
2740 * If the next token is a parenthesis, then this
2741 * is a function.
2742 */
2743 if (type == EVENT_DELIM && strcmp(token, "(") == 0) {
2744 free_token(token);
2745 token = NULL;
2746 /* this will free atom. */
2747 type = process_function(event, arg, atom, &token);
2748 break;
2749 }
2750 /* atoms can be more than one token long */
2751 while (type == EVENT_ITEM) {
2752 char *new_atom;
2753 new_atom = realloc(atom,
2754 strlen(atom) + strlen(token) + 2);
2755 if (!new_atom) {
2756 free(atom);
2757 *tok = NULL;
2758 free_token(token);
2759 return EVENT_ERROR;
2760 }
2761 atom = new_atom;
2762 strcat(atom, " ");
2763 strcat(atom, token);
2764 free_token(token);
2765 type = read_token_item(&token);
2766 }
2767
2768 arg->type = PRINT_ATOM;
2769 arg->atom.atom = atom;
2770 break;
2771
2772 case EVENT_DQUOTE:
2773 case EVENT_SQUOTE:
2774 arg->type = PRINT_ATOM;
2775 arg->atom.atom = token;
2776 type = read_token_item(&token);
2777 break;
2778 case EVENT_DELIM:
2779 if (strcmp(token, "(") == 0) {
2780 free_token(token);
2781 type = process_paren(event, arg, &token);
2782 break;
2783 }
2784 case EVENT_OP:
2785 /* handle single ops */
2786 arg->type = PRINT_OP;
2787 arg->op.op = token;
2788 arg->op.left = NULL;
2789 type = process_op(event, arg, &token);
2790
2791 /* On error, the op is freed */
2792 if (type == EVENT_ERROR)
2793 arg->op.op = NULL;
2794
2795 /* return error type if errored */
2796 break;
2797
2798 case EVENT_ERROR ... EVENT_NEWLINE:
2799 default:
2800 do_warning("unexpected type %d", type);
2801 return EVENT_ERROR;
2802 }
2803 *tok = token;
2804
2805 return type;
2806}
2807
2808static int event_read_print_args(struct event_format *event, struct print_arg **list)
2809{
2810 enum event_type type = EVENT_ERROR;
2811 struct print_arg *arg;
2812 char *token;
2813 int args = 0;
2814
2815 do {
2816 if (type == EVENT_NEWLINE) {
2817 type = read_token_item(&token);
2818 continue;
2819 }
2820
2821 arg = alloc_arg();
2822 if (!arg) {
2823 do_warning("%s: not enough memory!", __func__);
2824 return -1;
2825 }
2826
2827 type = process_arg(event, arg, &token);
2828
2829 if (type == EVENT_ERROR) {
2830 free_token(token);
2831 free_arg(arg);
2832 return -1;
2833 }
2834
2835 *list = arg;
2836 args++;
2837
2838 if (type == EVENT_OP) {
2839 type = process_op(event, arg, &token);
2840 free_token(token);
2841 if (type == EVENT_ERROR) {
2842 *list = NULL;
2843 free_arg(arg);
2844 return -1;
2845 }
2846 list = &arg->next;
2847 continue;
2848 }
2849
2850 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
2851 free_token(token);
2852 *list = arg;
2853 list = &arg->next;
2854 continue;
2855 }
2856 break;
2857 } while (type != EVENT_NONE);
2858
2859 if (type != EVENT_NONE && type != EVENT_ERROR)
2860 free_token(token);
2861
2862 return args;
2863}
2864
2865static int event_read_print(struct event_format *event)
2866{
2867 enum event_type type;
2868 char *token;
2869 int ret;
2870
2871 if (read_expected_item(EVENT_ITEM, "print") < 0)
2872 return -1;
2873
2874 if (read_expected(EVENT_ITEM, "fmt") < 0)
2875 return -1;
2876
2877 if (read_expected(EVENT_OP, ":") < 0)
2878 return -1;
2879
2880 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
2881 goto fail;
2882
2883 concat:
2884 event->print_fmt.format = token;
2885 event->print_fmt.args = NULL;
2886
2887 /* ok to have no arg */
2888 type = read_token_item(&token);
2889
2890 if (type == EVENT_NONE)
2891 return 0;
2892
2893 /* Handle concatenation of print lines */
2894 if (type == EVENT_DQUOTE) {
2895 char *cat;
2896
2897 if (asprintf(&cat, "%s%s", event->print_fmt.format, token) < 0)
2898 goto fail;
2899 free_token(token);
2900 free_token(event->print_fmt.format);
2901 event->print_fmt.format = NULL;
2902 token = cat;
2903 goto concat;
2904 }
2905
2906 if (test_type_token(type, token, EVENT_DELIM, ","))
2907 goto fail;
2908
2909 free_token(token);
2910
2911 ret = event_read_print_args(event, &event->print_fmt.args);
2912 if (ret < 0)
2913 return -1;
2914
2915 return ret;
2916
2917 fail:
2918 free_token(token);
2919 return -1;
2920}
2921
2922/**
2923 * pevent_find_common_field - return a common field by event
2924 * @event: handle for the event
2925 * @name: the name of the common field to return
2926 *
2927 * Returns a common field from the event by the given @name.
2928 * This only searchs the common fields and not all field.
2929 */
2930struct format_field *
2931pevent_find_common_field(struct event_format *event, const char *name)
2932{
2933 struct format_field *format;
2934
2935 for (format = event->format.common_fields;
2936 format; format = format->next) {
2937 if (strcmp(format->name, name) == 0)
2938 break;
2939 }
2940
2941 return format;
2942}
2943
2944/**
2945 * pevent_find_field - find a non-common field
2946 * @event: handle for the event
2947 * @name: the name of the non-common field
2948 *
2949 * Returns a non-common field by the given @name.
2950 * This does not search common fields.
2951 */
2952struct format_field *
2953pevent_find_field(struct event_format *event, const char *name)
2954{
2955 struct format_field *format;
2956
2957 for (format = event->format.fields;
2958 format; format = format->next) {
2959 if (strcmp(format->name, name) == 0)
2960 break;
2961 }
2962
2963 return format;
2964}
2965
2966/**
2967 * pevent_find_any_field - find any field by name
2968 * @event: handle for the event
2969 * @name: the name of the field
2970 *
2971 * Returns a field by the given @name.
2972 * This searchs the common field names first, then
2973 * the non-common ones if a common one was not found.
2974 */
2975struct format_field *
2976pevent_find_any_field(struct event_format *event, const char *name)
2977{
2978 struct format_field *format;
2979
2980 format = pevent_find_common_field(event, name);
2981 if (format)
2982 return format;
2983 return pevent_find_field(event, name);
2984}
2985
2986/**
2987 * pevent_read_number - read a number from data
2988 * @pevent: handle for the pevent
2989 * @ptr: the raw data
2990 * @size: the size of the data that holds the number
2991 *
2992 * Returns the number (converted to host) from the
2993 * raw data.
2994 */
2995unsigned long long pevent_read_number(struct pevent *pevent,
2996 const void *ptr, int size)
2997{
2998 switch (size) {
2999 case 1:
3000 return *(unsigned char *)ptr;
3001 case 2:
3002 return data2host2(pevent, ptr);
3003 case 4:
3004 return data2host4(pevent, ptr);
3005 case 8:
3006 return data2host8(pevent, ptr);
3007 default:
3008 /* BUG! */
3009 return 0;
3010 }
3011}
3012
3013/**
3014 * pevent_read_number_field - read a number from data
3015 * @field: a handle to the field
3016 * @data: the raw data to read
3017 * @value: the value to place the number in
3018 *
3019 * Reads raw data according to a field offset and size,
3020 * and translates it into @value.
3021 *
3022 * Returns 0 on success, -1 otherwise.
3023 */
3024int pevent_read_number_field(struct format_field *field, const void *data,
3025 unsigned long long *value)
3026{
3027 if (!field)
3028 return -1;
3029 switch (field->size) {
3030 case 1:
3031 case 2:
3032 case 4:
3033 case 8:
3034 *value = pevent_read_number(field->event->pevent,
3035 data + field->offset, field->size);
3036 return 0;
3037 default:
3038 return -1;
3039 }
3040}
3041
3042static int get_common_info(struct pevent *pevent,
3043 const char *type, int *offset, int *size)
3044{
3045 struct event_format *event;
3046 struct format_field *field;
3047
3048 /*
3049 * All events should have the same common elements.
3050 * Pick any event to find where the type is;
3051 */
3052 if (!pevent->events) {
3053 do_warning("no event_list!");
3054 return -1;
3055 }
3056
3057 event = pevent->events[0];
3058 field = pevent_find_common_field(event, type);
3059 if (!field)
3060 return -1;
3061
3062 *offset = field->offset;
3063 *size = field->size;
3064
3065 return 0;
3066}
3067
3068static int __parse_common(struct pevent *pevent, void *data,
3069 int *size, int *offset, const char *name)
3070{
3071 int ret;
3072
3073 if (!*size) {
3074 ret = get_common_info(pevent, name, offset, size);
3075 if (ret < 0)
3076 return ret;
3077 }
3078 return pevent_read_number(pevent, data + *offset, *size);
3079}
3080
3081static int trace_parse_common_type(struct pevent *pevent, void *data)
3082{
3083 return __parse_common(pevent, data,
3084 &pevent->type_size, &pevent->type_offset,
3085 "common_type");
3086}
3087
3088static int parse_common_pid(struct pevent *pevent, void *data)
3089{
3090 return __parse_common(pevent, data,
3091 &pevent->pid_size, &pevent->pid_offset,
3092 "common_pid");
3093}
3094
3095static int parse_common_pc(struct pevent *pevent, void *data)
3096{
3097 return __parse_common(pevent, data,
3098 &pevent->pc_size, &pevent->pc_offset,
3099 "common_preempt_count");
3100}
3101
3102static int parse_common_flags(struct pevent *pevent, void *data)
3103{
3104 return __parse_common(pevent, data,
3105 &pevent->flags_size, &pevent->flags_offset,
3106 "common_flags");
3107}
3108
3109static int parse_common_lock_depth(struct pevent *pevent, void *data)
3110{
3111 return __parse_common(pevent, data,
3112 &pevent->ld_size, &pevent->ld_offset,
3113 "common_lock_depth");
3114}
3115
3116static int parse_common_migrate_disable(struct pevent *pevent, void *data)
3117{
3118 return __parse_common(pevent, data,
3119 &pevent->ld_size, &pevent->ld_offset,
3120 "common_migrate_disable");
3121}
3122
3123static int events_id_cmp(const void *a, const void *b);
3124
3125/**
3126 * pevent_find_event - find an event by given id
3127 * @pevent: a handle to the pevent
3128 * @id: the id of the event
3129 *
3130 * Returns an event that has a given @id.
3131 */
3132struct event_format *pevent_find_event(struct pevent *pevent, int id)
3133{
3134 struct event_format **eventptr;
3135 struct event_format key;
3136 struct event_format *pkey = &key;
3137
3138 /* Check cache first */
3139 if (pevent->last_event && pevent->last_event->id == id)
3140 return pevent->last_event;
3141
3142 key.id = id;
3143
3144 eventptr = bsearch(&pkey, pevent->events, pevent->nr_events,
3145 sizeof(*pevent->events), events_id_cmp);
3146
3147 if (eventptr) {
3148 pevent->last_event = *eventptr;
3149 return *eventptr;
3150 }
3151
3152 return NULL;
3153}
3154
3155/**
3156 * pevent_find_event_by_name - find an event by given name
3157 * @pevent: a handle to the pevent
3158 * @sys: the system name to search for
3159 * @name: the name of the event to search for
3160 *
3161 * This returns an event with a given @name and under the system
3162 * @sys. If @sys is NULL the first event with @name is returned.
3163 */
3164struct event_format *
3165pevent_find_event_by_name(struct pevent *pevent,
3166 const char *sys, const char *name)
3167{
3168 struct event_format *event;
3169 int i;
3170
3171 if (pevent->last_event &&
3172 strcmp(pevent->last_event->name, name) == 0 &&
3173 (!sys || strcmp(pevent->last_event->system, sys) == 0))
3174 return pevent->last_event;
3175
3176 for (i = 0; i < pevent->nr_events; i++) {
3177 event = pevent->events[i];
3178 if (strcmp(event->name, name) == 0) {
3179 if (!sys)
3180 break;
3181 if (strcmp(event->system, sys) == 0)
3182 break;
3183 }
3184 }
3185 if (i == pevent->nr_events)
3186 event = NULL;
3187
3188 pevent->last_event = event;
3189 return event;
3190}
3191
3192static unsigned long long
3193eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg)
3194{
3195 struct pevent *pevent = event->pevent;
3196 unsigned long long val = 0;
3197 unsigned long long left, right;
3198 struct print_arg *typearg = NULL;
3199 struct print_arg *larg;
3200 unsigned long offset;
3201 unsigned int field_size;
3202
3203 switch (arg->type) {
3204 case PRINT_NULL:
3205 /* ?? */
3206 return 0;
3207 case PRINT_ATOM:
3208 return strtoull(arg->atom.atom, NULL, 0);
3209 case PRINT_FIELD:
3210 if (!arg->field.field) {
3211 arg->field.field = pevent_find_any_field(event, arg->field.name);
3212 if (!arg->field.field)
3213 goto out_warning_field;
3214
3215 }
3216 /* must be a number */
3217 val = pevent_read_number(pevent, data + arg->field.field->offset,
3218 arg->field.field->size);
3219 break;
3220 case PRINT_FLAGS:
3221 case PRINT_SYMBOL:
3222 case PRINT_HEX:
3223 break;
3224 case PRINT_TYPE:
3225 val = eval_num_arg(data, size, event, arg->typecast.item);
3226 return eval_type(val, arg, 0);
3227 case PRINT_STRING:
3228 case PRINT_BSTRING:
3229 return 0;
3230 case PRINT_FUNC: {
3231 struct trace_seq s;
3232 trace_seq_init(&s);
3233 val = process_defined_func(&s, data, size, event, arg);
3234 trace_seq_destroy(&s);
3235 return val;
3236 }
3237 case PRINT_OP:
3238 if (strcmp(arg->op.op, "[") == 0) {
3239 /*
3240 * Arrays are special, since we don't want
3241 * to read the arg as is.
3242 */
3243 right = eval_num_arg(data, size, event, arg->op.right);
3244
3245 /* handle typecasts */
3246 larg = arg->op.left;
3247 while (larg->type == PRINT_TYPE) {
3248 if (!typearg)
3249 typearg = larg;
3250 larg = larg->typecast.item;
3251 }
3252
3253 /* Default to long size */
3254 field_size = pevent->long_size;
3255
3256 switch (larg->type) {
3257 case PRINT_DYNAMIC_ARRAY:
3258 offset = pevent_read_number(pevent,
3259 data + larg->dynarray.field->offset,
3260 larg->dynarray.field->size);
3261 if (larg->dynarray.field->elementsize)
3262 field_size = larg->dynarray.field->elementsize;
3263 /*
3264 * The actual length of the dynamic array is stored
3265 * in the top half of the field, and the offset
3266 * is in the bottom half of the 32 bit field.
3267 */
3268 offset &= 0xffff;
3269 offset += right;
3270 break;
3271 case PRINT_FIELD:
3272 if (!larg->field.field) {
3273 larg->field.field =
3274 pevent_find_any_field(event, larg->field.name);
3275 if (!larg->field.field) {
3276 arg = larg;
3277 goto out_warning_field;
3278 }
3279 }
3280 field_size = larg->field.field->elementsize;
3281 offset = larg->field.field->offset +
3282 right * larg->field.field->elementsize;
3283 break;
3284 default:
3285 goto default_op; /* oops, all bets off */
3286 }
3287 val = pevent_read_number(pevent,
3288 data + offset, field_size);
3289 if (typearg)
3290 val = eval_type(val, typearg, 1);
3291 break;
3292 } else if (strcmp(arg->op.op, "?") == 0) {
3293 left = eval_num_arg(data, size, event, arg->op.left);
3294 arg = arg->op.right;
3295 if (left)
3296 val = eval_num_arg(data, size, event, arg->op.left);
3297 else
3298 val = eval_num_arg(data, size, event, arg->op.right);
3299 break;
3300 }
3301 default_op:
3302 left = eval_num_arg(data, size, event, arg->op.left);
3303 right = eval_num_arg(data, size, event, arg->op.right);
3304 switch (arg->op.op[0]) {
3305 case '!':
3306 switch (arg->op.op[1]) {
3307 case 0:
3308 val = !right;
3309 break;
3310 case '=':
3311 val = left != right;
3312 break;
3313 default:
3314 goto out_warning_op;
3315 }
3316 break;
3317 case '~':
3318 val = ~right;
3319 break;
3320 case '|':
3321 if (arg->op.op[1])
3322 val = left || right;
3323 else
3324 val = left | right;
3325 break;
3326 case '&':
3327 if (arg->op.op[1])
3328 val = left && right;
3329 else
3330 val = left & right;
3331 break;
3332 case '<':
3333 switch (arg->op.op[1]) {
3334 case 0:
3335 val = left < right;
3336 break;
3337 case '<':
3338 val = left << right;
3339 break;
3340 case '=':
3341 val = left <= right;
3342 break;
3343 default:
3344 goto out_warning_op;
3345 }
3346 break;
3347 case '>':
3348 switch (arg->op.op[1]) {
3349 case 0:
3350 val = left > right;
3351 break;
3352 case '>':
3353 val = left >> right;
3354 break;
3355 case '=':
3356 val = left >= right;
3357 break;
3358 default:
3359 goto out_warning_op;
3360 }
3361 break;
3362 case '=':
3363 if (arg->op.op[1] != '=')
3364 goto out_warning_op;
3365
3366 val = left == right;
3367 break;
3368 case '-':
3369 val = left - right;
3370 break;
3371 case '+':
3372 val = left + right;
3373 break;
3374 case '/':
3375 val = left / right;
3376 break;
3377 case '*':
3378 val = left * right;
3379 break;
3380 default:
3381 goto out_warning_op;
3382 }
3383 break;
3384 default: /* not sure what to do there */
3385 return 0;
3386 }
3387 return val;
3388
3389out_warning_op:
3390 do_warning("%s: unknown op '%s'", __func__, arg->op.op);
3391 return 0;
3392
3393out_warning_field:
3394 do_warning("%s: field %s not found", __func__, arg->field.name);
3395 return 0;
3396}
3397
3398struct flag {
3399 const char *name;
3400 unsigned long long value;
3401};
3402
3403static const struct flag flags[] = {
3404 { "HI_SOFTIRQ", 0 },
3405 { "TIMER_SOFTIRQ", 1 },
3406 { "NET_TX_SOFTIRQ", 2 },
3407 { "NET_RX_SOFTIRQ", 3 },
3408 { "BLOCK_SOFTIRQ", 4 },
3409 { "BLOCK_IOPOLL_SOFTIRQ", 5 },
3410 { "TASKLET_SOFTIRQ", 6 },
3411 { "SCHED_SOFTIRQ", 7 },
3412 { "HRTIMER_SOFTIRQ", 8 },
3413 { "RCU_SOFTIRQ", 9 },
3414
3415 { "HRTIMER_NORESTART", 0 },
3416 { "HRTIMER_RESTART", 1 },
3417};
3418
3419static unsigned long long eval_flag(const char *flag)
3420{
3421 int i;
3422
3423 /*
3424 * Some flags in the format files do not get converted.
3425 * If the flag is not numeric, see if it is something that
3426 * we already know about.
3427 */
3428 if (isdigit(flag[0]))
3429 return strtoull(flag, NULL, 0);
3430
3431 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
3432 if (strcmp(flags[i].name, flag) == 0)
3433 return flags[i].value;
3434
3435 return 0;
3436}
3437
3438static void print_str_to_seq(struct trace_seq *s, const char *format,
3439 int len_arg, const char *str)
3440{
3441 if (len_arg >= 0)
3442 trace_seq_printf(s, format, len_arg, str);
3443 else
3444 trace_seq_printf(s, format, str);
3445}
3446
3447static void print_str_arg(struct trace_seq *s, void *data, int size,
3448 struct event_format *event, const char *format,
3449 int len_arg, struct print_arg *arg)
3450{
3451 struct pevent *pevent = event->pevent;
3452 struct print_flag_sym *flag;
3453 struct format_field *field;
3454 unsigned long long val, fval;
3455 unsigned long addr;
3456 char *str;
3457 unsigned char *hex;
3458 int print;
3459 int i, len;
3460
3461 switch (arg->type) {
3462 case PRINT_NULL:
3463 /* ?? */
3464 return;
3465 case PRINT_ATOM:
3466 print_str_to_seq(s, format, len_arg, arg->atom.atom);
3467 return;
3468 case PRINT_FIELD:
3469 field = arg->field.field;
3470 if (!field) {
3471 field = pevent_find_any_field(event, arg->field.name);
3472 if (!field) {
3473 str = arg->field.name;
3474 goto out_warning_field;
3475 }
3476 arg->field.field = field;
3477 }
3478 /* Zero sized fields, mean the rest of the data */
3479 len = field->size ? : size - field->offset;
3480
3481 /*
3482 * Some events pass in pointers. If this is not an array
3483 * and the size is the same as long_size, assume that it
3484 * is a pointer.
3485 */
3486 if (!(field->flags & FIELD_IS_ARRAY) &&
3487 field->size == pevent->long_size) {
3488 addr = *(unsigned long *)(data + field->offset);
3489 trace_seq_printf(s, "%lx", addr);
3490 break;
3491 }
3492 str = malloc(len + 1);
3493 if (!str) {
3494 do_warning("%s: not enough memory!", __func__);
3495 return;
3496 }
3497 memcpy(str, data + field->offset, len);
3498 str[len] = 0;
3499 print_str_to_seq(s, format, len_arg, str);
3500 free(str);
3501 break;
3502 case PRINT_FLAGS:
3503 val = eval_num_arg(data, size, event, arg->flags.field);
3504 print = 0;
3505 for (flag = arg->flags.flags; flag; flag = flag->next) {
3506 fval = eval_flag(flag->value);
3507 if (!val && !fval) {
3508 print_str_to_seq(s, format, len_arg, flag->str);
3509 break;
3510 }
3511 if (fval && (val & fval) == fval) {
3512 if (print && arg->flags.delim)
3513 trace_seq_puts(s, arg->flags.delim);
3514 print_str_to_seq(s, format, len_arg, flag->str);
3515 print = 1;
3516 val &= ~fval;
3517 }
3518 }
3519 break;
3520 case PRINT_SYMBOL:
3521 val = eval_num_arg(data, size, event, arg->symbol.field);
3522 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
3523 fval = eval_flag(flag->value);
3524 if (val == fval) {
3525 print_str_to_seq(s, format, len_arg, flag->str);
3526 break;
3527 }
3528 }
3529 break;
3530 case PRINT_HEX:
3531 field = arg->hex.field->field.field;
3532 if (!field) {
3533 str = arg->hex.field->field.name;
3534 field = pevent_find_any_field(event, str);
3535 if (!field)
3536 goto out_warning_field;
3537 arg->hex.field->field.field = field;
3538 }
3539 hex = data + field->offset;
3540 len = eval_num_arg(data, size, event, arg->hex.size);
3541 for (i = 0; i < len; i++) {
3542 if (i)
3543 trace_seq_putc(s, ' ');
3544 trace_seq_printf(s, "%02x", hex[i]);
3545 }
3546 break;
3547
3548 case PRINT_TYPE:
3549 break;
3550 case PRINT_STRING: {
3551 int str_offset;
3552
3553 if (arg->string.offset == -1) {
3554 struct format_field *f;
3555
3556 f = pevent_find_any_field(event, arg->string.string);
3557 arg->string.offset = f->offset;
3558 }
3559 str_offset = data2host4(pevent, data + arg->string.offset);
3560 str_offset &= 0xffff;
3561 print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset);
3562 break;
3563 }
3564 case PRINT_BSTRING:
3565 print_str_to_seq(s, format, len_arg, arg->string.string);
3566 break;
3567 case PRINT_OP:
3568 /*
3569 * The only op for string should be ? :
3570 */
3571 if (arg->op.op[0] != '?')
3572 return;
3573 val = eval_num_arg(data, size, event, arg->op.left);
3574 if (val)
3575 print_str_arg(s, data, size, event,
3576 format, len_arg, arg->op.right->op.left);
3577 else
3578 print_str_arg(s, data, size, event,
3579 format, len_arg, arg->op.right->op.right);
3580 break;
3581 case PRINT_FUNC:
3582 process_defined_func(s, data, size, event, arg);
3583 break;
3584 default:
3585 /* well... */
3586 break;
3587 }
3588
3589 return;
3590
3591out_warning_field:
3592 do_warning("%s: field %s not found", __func__, arg->field.name);
3593}
3594
3595static unsigned long long
3596process_defined_func(struct trace_seq *s, void *data, int size,
3597 struct event_format *event, struct print_arg *arg)
3598{
3599 struct pevent_function_handler *func_handle = arg->func.func;
3600 struct pevent_func_params *param;
3601 unsigned long long *args;
3602 unsigned long long ret;
3603 struct print_arg *farg;
3604 struct trace_seq str;
3605 struct save_str {
3606 struct save_str *next;
3607 char *str;
3608 } *strings = NULL, *string;
3609 int i;
3610
3611 if (!func_handle->nr_args) {
3612 ret = (*func_handle->func)(s, NULL);
3613 goto out;
3614 }
3615
3616 farg = arg->func.args;
3617 param = func_handle->params;
3618
3619 ret = ULLONG_MAX;
3620 args = malloc(sizeof(*args) * func_handle->nr_args);
3621 if (!args)
3622 goto out;
3623
3624 for (i = 0; i < func_handle->nr_args; i++) {
3625 switch (param->type) {
3626 case PEVENT_FUNC_ARG_INT:
3627 case PEVENT_FUNC_ARG_LONG:
3628 case PEVENT_FUNC_ARG_PTR:
3629 args[i] = eval_num_arg(data, size, event, farg);
3630 break;
3631 case PEVENT_FUNC_ARG_STRING:
3632 trace_seq_init(&str);
3633 print_str_arg(&str, data, size, event, "%s", -1, farg);
3634 trace_seq_terminate(&str);
3635 string = malloc(sizeof(*string));
3636 if (!string) {
3637 do_warning("%s(%d): malloc str", __func__, __LINE__);
3638 goto out_free;
3639 }
3640 string->next = strings;
3641 string->str = strdup(str.buffer);
3642 if (!string->str) {
3643 free(string);
3644 do_warning("%s(%d): malloc str", __func__, __LINE__);
3645 goto out_free;
3646 }
3647 args[i] = (uintptr_t)string->str;
3648 strings = string;
3649 trace_seq_destroy(&str);
3650 break;
3651 default:
3652 /*
3653 * Something went totally wrong, this is not
3654 * an input error, something in this code broke.
3655 */
3656 do_warning("Unexpected end of arguments\n");
3657 goto out_free;
3658 }
3659 farg = farg->next;
3660 param = param->next;
3661 }
3662
3663 ret = (*func_handle->func)(s, args);
3664out_free:
3665 free(args);
3666 while (strings) {
3667 string = strings;
3668 strings = string->next;
3669 free(string->str);
3670 free(string);
3671 }
3672
3673 out:
3674 /* TBD : handle return type here */
3675 return ret;
3676}
3677
3678static void free_args(struct print_arg *args)
3679{
3680 struct print_arg *next;
3681
3682 while (args) {
3683 next = args->next;
3684
3685 free_arg(args);
3686 args = next;
3687 }
3688}
3689
3690static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event)
3691{
3692 struct pevent *pevent = event->pevent;
3693 struct format_field *field, *ip_field;
3694 struct print_arg *args, *arg, **next;
3695 unsigned long long ip, val;
3696 char *ptr;
3697 void *bptr;
3698 int vsize;
3699
3700 field = pevent->bprint_buf_field;
3701 ip_field = pevent->bprint_ip_field;
3702
3703 if (!field) {
3704 field = pevent_find_field(event, "buf");
3705 if (!field) {
3706 do_warning("can't find buffer field for binary printk");
3707 return NULL;
3708 }
3709 ip_field = pevent_find_field(event, "ip");
3710 if (!ip_field) {
3711 do_warning("can't find ip field for binary printk");
3712 return NULL;
3713 }
3714 pevent->bprint_buf_field = field;
3715 pevent->bprint_ip_field = ip_field;
3716 }
3717
3718 ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size);
3719
3720 /*
3721 * The first arg is the IP pointer.
3722 */
3723 args = alloc_arg();
3724 if (!args) {
3725 do_warning("%s(%d): not enough memory!", __func__, __LINE__);
3726 return NULL;
3727 }
3728 arg = args;
3729 arg->next = NULL;
3730 next = &arg->next;
3731
3732 arg->type = PRINT_ATOM;
3733
3734 if (asprintf(&arg->atom.atom, "%lld", ip) < 0)
3735 goto out_free;
3736
3737 /* skip the first "%pf : " */
3738 for (ptr = fmt + 6, bptr = data + field->offset;
3739 bptr < data + size && *ptr; ptr++) {
3740 int ls = 0;
3741
3742 if (*ptr == '%') {
3743 process_again:
3744 ptr++;
3745 switch (*ptr) {
3746 case '%':
3747 break;
3748 case 'l':
3749 ls++;
3750 goto process_again;
3751 case 'L':
3752 ls = 2;
3753 goto process_again;
3754 case '0' ... '9':
3755 goto process_again;
3756 case '.':
3757 goto process_again;
3758 case 'p':
3759 ls = 1;
3760 /* fall through */
3761 case 'd':
3762 case 'u':
3763 case 'x':
3764 case 'i':
3765 switch (ls) {
3766 case 0:
3767 vsize = 4;
3768 break;
3769 case 1:
3770 vsize = pevent->long_size;
3771 break;
3772 case 2:
3773 vsize = 8;
3774 break;
3775 default:
3776 vsize = ls; /* ? */
3777 break;
3778 }
3779 /* fall through */
3780 case '*':
3781 if (*ptr == '*')
3782 vsize = 4;
3783
3784 /* the pointers are always 4 bytes aligned */
3785 bptr = (void *)(((unsigned long)bptr + 3) &
3786 ~3);
3787 val = pevent_read_number(pevent, bptr, vsize);
3788 bptr += vsize;
3789 arg = alloc_arg();
3790 if (!arg) {
3791 do_warning("%s(%d): not enough memory!",
3792 __func__, __LINE__);
3793 goto out_free;
3794 }
3795 arg->next = NULL;
3796 arg->type = PRINT_ATOM;
3797 if (asprintf(&arg->atom.atom, "%lld", val) < 0) {
3798 free(arg);
3799 goto out_free;
3800 }
3801 *next = arg;
3802 next = &arg->next;
3803 /*
3804 * The '*' case means that an arg is used as the length.
3805 * We need to continue to figure out for what.
3806 */
3807 if (*ptr == '*')
3808 goto process_again;
3809
3810 break;
3811 case 's':
3812 arg = alloc_arg();
3813 if (!arg) {
3814 do_warning("%s(%d): not enough memory!",
3815 __func__, __LINE__);
3816 goto out_free;
3817 }
3818 arg->next = NULL;
3819 arg->type = PRINT_BSTRING;
3820 arg->string.string = strdup(bptr);
3821 if (!arg->string.string)
3822 goto out_free;
3823 bptr += strlen(bptr) + 1;
3824 *next = arg;
3825 next = &arg->next;
3826 default:
3827 break;
3828 }
3829 }
3830 }
3831
3832 return args;
3833
3834out_free:
3835 free_args(args);
3836 return NULL;
3837}
3838
3839static char *
3840get_bprint_format(void *data, int size __maybe_unused,
3841 struct event_format *event)
3842{
3843 struct pevent *pevent = event->pevent;
3844 unsigned long long addr;
3845 struct format_field *field;
3846 struct printk_map *printk;
3847 char *format;
3848 char *p;
3849
3850 field = pevent->bprint_fmt_field;
3851
3852 if (!field) {
3853 field = pevent_find_field(event, "fmt");
3854 if (!field) {
3855 do_warning("can't find format field for binary printk");
3856 return NULL;
3857 }
3858 pevent->bprint_fmt_field = field;
3859 }
3860
3861 addr = pevent_read_number(pevent, data + field->offset, field->size);
3862
3863 printk = find_printk(pevent, addr);
3864 if (!printk) {
3865 if (asprintf(&format, "%%pf : (NO FORMAT FOUND at %llx)\n", addr) < 0)
3866 return NULL;
3867 return format;
3868 }
3869
3870 p = printk->printk;
3871 /* Remove any quotes. */
3872 if (*p == '"')
3873 p++;
3874 if (asprintf(&format, "%s : %s", "%pf", p) < 0)
3875 return NULL;
3876 /* remove ending quotes and new line since we will add one too */
3877 p = format + strlen(format) - 1;
3878 if (*p == '"')
3879 *p = 0;
3880
3881 p -= 2;
3882 if (strcmp(p, "\\n") == 0)
3883 *p = 0;
3884
3885 return format;
3886}
3887
3888static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
3889 struct event_format *event, struct print_arg *arg)
3890{
3891 unsigned char *buf;
3892 const char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
3893
3894 if (arg->type == PRINT_FUNC) {
3895 process_defined_func(s, data, size, event, arg);
3896 return;
3897 }
3898
3899 if (arg->type != PRINT_FIELD) {
3900 trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",
3901 arg->type);
3902 return;
3903 }
3904
3905 if (mac == 'm')
3906 fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
3907 if (!arg->field.field) {
3908 arg->field.field =
3909 pevent_find_any_field(event, arg->field.name);
3910 if (!arg->field.field) {
3911 do_warning("%s: field %s not found",
3912 __func__, arg->field.name);
3913 return;
3914 }
3915 }
3916 if (arg->field.field->size != 6) {
3917 trace_seq_printf(s, "INVALIDMAC");
3918 return;
3919 }
3920 buf = data + arg->field.field->offset;
3921 trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
3922}
3923
3924static int is_printable_array(char *p, unsigned int len)
3925{
3926 unsigned int i;
3927
3928 for (i = 0; i < len && p[i]; i++)
3929 if (!isprint(p[i]))
3930 return 0;
3931 return 1;
3932}
3933
3934static void print_event_fields(struct trace_seq *s, void *data,
3935 int size __maybe_unused,
3936 struct event_format *event)
3937{
3938 struct format_field *field;
3939 unsigned long long val;
3940 unsigned int offset, len, i;
3941
3942 field = event->format.fields;
3943 while (field) {
3944 trace_seq_printf(s, " %s=", field->name);
3945 if (field->flags & FIELD_IS_ARRAY) {
3946 offset = field->offset;
3947 len = field->size;
3948 if (field->flags & FIELD_IS_DYNAMIC) {
3949 val = pevent_read_number(event->pevent, data + offset, len);
3950 offset = val;
3951 len = offset >> 16;
3952 offset &= 0xffff;
3953 }
3954 if (field->flags & FIELD_IS_STRING &&
3955 is_printable_array(data + offset, len)) {
3956 trace_seq_printf(s, "%s", (char *)data + offset);
3957 } else {
3958 trace_seq_puts(s, "ARRAY[");
3959 for (i = 0; i < len; i++) {
3960 if (i)
3961 trace_seq_puts(s, ", ");
3962 trace_seq_printf(s, "%02x",
3963 *((unsigned char *)data + offset + i));
3964 }
3965 trace_seq_putc(s, ']');
3966 field->flags &= ~FIELD_IS_STRING;
3967 }
3968 } else {
3969 val = pevent_read_number(event->pevent, data + field->offset,
3970 field->size);
3971 if (field->flags & FIELD_IS_POINTER) {
3972 trace_seq_printf(s, "0x%llx", val);
3973 } else if (field->flags & FIELD_IS_SIGNED) {
3974 switch (field->size) {
3975 case 4:
3976 /*
3977 * If field is long then print it in hex.
3978 * A long usually stores pointers.
3979 */
3980 if (field->flags & FIELD_IS_LONG)
3981 trace_seq_printf(s, "0x%x", (int)val);
3982 else
3983 trace_seq_printf(s, "%d", (int)val);
3984 break;
3985 case 2:
3986 trace_seq_printf(s, "%2d", (short)val);
3987 break;
3988 case 1:
3989 trace_seq_printf(s, "%1d", (char)val);
3990 break;
3991 default:
3992 trace_seq_printf(s, "%lld", val);
3993 }
3994 } else {
3995 if (field->flags & FIELD_IS_LONG)
3996 trace_seq_printf(s, "0x%llx", val);
3997 else
3998 trace_seq_printf(s, "%llu", val);
3999 }
4000 }
4001 field = field->next;
4002 }
4003}
4004
4005static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event)
4006{
4007 struct pevent *pevent = event->pevent;
4008 struct print_fmt *print_fmt = &event->print_fmt;
4009 struct print_arg *arg = print_fmt->args;
4010 struct print_arg *args = NULL;
4011 const char *ptr = print_fmt->format;
4012 unsigned long long val;
4013 struct func_map *func;
4014 const char *saveptr;
4015 char *bprint_fmt = NULL;
4016 char format[32];
4017 int show_func;
4018 int len_as_arg;
4019 int len_arg;
4020 int len;
4021 int ls;
4022
4023 if (event->flags & EVENT_FL_FAILED) {
4024 trace_seq_printf(s, "[FAILED TO PARSE]");
4025 print_event_fields(s, data, size, event);
4026 return;
4027 }
4028
4029 if (event->flags & EVENT_FL_ISBPRINT) {
4030 bprint_fmt = get_bprint_format(data, size, event);
4031 args = make_bprint_args(bprint_fmt, data, size, event);
4032 arg = args;
4033 ptr = bprint_fmt;
4034 }
4035
4036 for (; *ptr; ptr++) {
4037 ls = 0;
4038 if (*ptr == '\\') {
4039 ptr++;
4040 switch (*ptr) {
4041 case 'n':
4042 trace_seq_putc(s, '\n');
4043 break;
4044 case 't':
4045 trace_seq_putc(s, '\t');
4046 break;
4047 case 'r':
4048 trace_seq_putc(s, '\r');
4049 break;
4050 case '\\':
4051 trace_seq_putc(s, '\\');
4052 break;
4053 default:
4054 trace_seq_putc(s, *ptr);
4055 break;
4056 }
4057
4058 } else if (*ptr == '%') {
4059 saveptr = ptr;
4060 show_func = 0;
4061 len_as_arg = 0;
4062 cont_process:
4063 ptr++;
4064 switch (*ptr) {
4065 case '%':
4066 trace_seq_putc(s, '%');
4067 break;
4068 case '#':
4069 /* FIXME: need to handle properly */
4070 goto cont_process;
4071 case 'h':
4072 ls--;
4073 goto cont_process;
4074 case 'l':
4075 ls++;
4076 goto cont_process;
4077 case 'L':
4078 ls = 2;
4079 goto cont_process;
4080 case '*':
4081 /* The argument is the length. */
4082 if (!arg) {
4083 do_warning("no argument match");
4084 event->flags |= EVENT_FL_FAILED;
4085 goto out_failed;
4086 }
4087 len_arg = eval_num_arg(data, size, event, arg);
4088 len_as_arg = 1;
4089 arg = arg->next;
4090 goto cont_process;
4091 case '.':
4092 case 'z':
4093 case 'Z':
4094 case '0' ... '9':
4095 goto cont_process;
4096 case 'p':
4097 if (pevent->long_size == 4)
4098 ls = 1;
4099 else
4100 ls = 2;
4101
4102 if (*(ptr+1) == 'F' ||
4103 *(ptr+1) == 'f') {
4104 ptr++;
4105 show_func = *ptr;
4106 } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
4107 print_mac_arg(s, *(ptr+1), data, size, event, arg);
4108 ptr++;
4109 arg = arg->next;
4110 break;
4111 }
4112
4113 /* fall through */
4114 case 'd':
4115 case 'i':
4116 case 'x':
4117 case 'X':
4118 case 'u':
4119 if (!arg) {
4120 do_warning("no argument match");
4121 event->flags |= EVENT_FL_FAILED;
4122 goto out_failed;
4123 }
4124
4125 len = ((unsigned long)ptr + 1) -
4126 (unsigned long)saveptr;
4127
4128 /* should never happen */
4129 if (len > 31) {
4130 do_warning("bad format!");
4131 event->flags |= EVENT_FL_FAILED;
4132 len = 31;
4133 }
4134
4135 memcpy(format, saveptr, len);
4136 format[len] = 0;
4137
4138 val = eval_num_arg(data, size, event, arg);
4139 arg = arg->next;
4140
4141 if (show_func) {
4142 func = find_func(pevent, val);
4143 if (func) {
4144 trace_seq_puts(s, func->func);
4145 if (show_func == 'F')
4146 trace_seq_printf(s,
4147 "+0x%llx",
4148 val - func->addr);
4149 break;
4150 }
4151 }
4152 if (pevent->long_size == 8 && ls &&
4153 sizeof(long) != 8) {
4154 char *p;
4155
4156 ls = 2;
4157 /* make %l into %ll */
4158 p = strchr(format, 'l');
4159 if (p)
4160 memmove(p+1, p, strlen(p)+1);
4161 else if (strcmp(format, "%p") == 0)
4162 strcpy(format, "0x%llx");
4163 }
4164 switch (ls) {
4165 case -2:
4166 if (len_as_arg)
4167 trace_seq_printf(s, format, len_arg, (char)val);
4168 else
4169 trace_seq_printf(s, format, (char)val);
4170 break;
4171 case -1:
4172 if (len_as_arg)
4173 trace_seq_printf(s, format, len_arg, (short)val);
4174 else
4175 trace_seq_printf(s, format, (short)val);
4176 break;
4177 case 0:
4178 if (len_as_arg)
4179 trace_seq_printf(s, format, len_arg, (int)val);
4180 else
4181 trace_seq_printf(s, format, (int)val);
4182 break;
4183 case 1:
4184 if (len_as_arg)
4185 trace_seq_printf(s, format, len_arg, (long)val);
4186 else
4187 trace_seq_printf(s, format, (long)val);
4188 break;
4189 case 2:
4190 if (len_as_arg)
4191 trace_seq_printf(s, format, len_arg,
4192 (long long)val);
4193 else
4194 trace_seq_printf(s, format, (long long)val);
4195 break;
4196 default:
4197 do_warning("bad count (%d)", ls);
4198 event->flags |= EVENT_FL_FAILED;
4199 }
4200 break;
4201 case 's':
4202 if (!arg) {
4203 do_warning("no matching argument");
4204 event->flags |= EVENT_FL_FAILED;
4205 goto out_failed;
4206 }
4207
4208 len = ((unsigned long)ptr + 1) -
4209 (unsigned long)saveptr;
4210
4211 /* should never happen */
4212 if (len > 31) {
4213 do_warning("bad format!");
4214 event->flags |= EVENT_FL_FAILED;
4215 len = 31;
4216 }
4217
4218 memcpy(format, saveptr, len);
4219 format[len] = 0;
4220 if (!len_as_arg)
4221 len_arg = -1;
4222 print_str_arg(s, data, size, event,
4223 format, len_arg, arg);
4224 arg = arg->next;
4225 break;
4226 default:
4227 trace_seq_printf(s, ">%c<", *ptr);
4228
4229 }
4230 } else
4231 trace_seq_putc(s, *ptr);
4232 }
4233
4234 if (event->flags & EVENT_FL_FAILED) {
4235out_failed:
4236 trace_seq_printf(s, "[FAILED TO PARSE]");
4237 }
4238
4239 if (args) {
4240 free_args(args);
4241 free(bprint_fmt);
4242 }
4243}
4244
4245/**
4246 * pevent_data_lat_fmt - parse the data for the latency format
4247 * @pevent: a handle to the pevent
4248 * @s: the trace_seq to write to
4249 * @record: the record to read from
4250 *
4251 * This parses out the Latency format (interrupts disabled,
4252 * need rescheduling, in hard/soft interrupt, preempt count
4253 * and lock depth) and places it into the trace_seq.
4254 */
4255void pevent_data_lat_fmt(struct pevent *pevent,
4256 struct trace_seq *s, struct pevent_record *record)
4257{
4258 static int check_lock_depth = 1;
4259 static int check_migrate_disable = 1;
4260 static int lock_depth_exists;
4261 static int migrate_disable_exists;
4262 unsigned int lat_flags;
4263 unsigned int pc;
4264 int lock_depth;
4265 int migrate_disable;
4266 int hardirq;
4267 int softirq;
4268 void *data = record->data;
4269
4270 lat_flags = parse_common_flags(pevent, data);
4271 pc = parse_common_pc(pevent, data);
4272 /* lock_depth may not always exist */
4273 if (lock_depth_exists)
4274 lock_depth = parse_common_lock_depth(pevent, data);
4275 else if (check_lock_depth) {
4276 lock_depth = parse_common_lock_depth(pevent, data);
4277 if (lock_depth < 0)
4278 check_lock_depth = 0;
4279 else
4280 lock_depth_exists = 1;
4281 }
4282
4283 /* migrate_disable may not always exist */
4284 if (migrate_disable_exists)
4285 migrate_disable = parse_common_migrate_disable(pevent, data);
4286 else if (check_migrate_disable) {
4287 migrate_disable = parse_common_migrate_disable(pevent, data);
4288 if (migrate_disable < 0)
4289 check_migrate_disable = 0;
4290 else
4291 migrate_disable_exists = 1;
4292 }
4293
4294 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
4295 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
4296
4297 trace_seq_printf(s, "%c%c%c",
4298 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
4299 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
4300 'X' : '.',
4301 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
4302 'N' : '.',
4303 (hardirq && softirq) ? 'H' :
4304 hardirq ? 'h' : softirq ? 's' : '.');
4305
4306 if (pc)
4307 trace_seq_printf(s, "%x", pc);
4308 else
4309 trace_seq_putc(s, '.');
4310
4311 if (migrate_disable_exists) {
4312 if (migrate_disable < 0)
4313 trace_seq_putc(s, '.');
4314 else
4315 trace_seq_printf(s, "%d", migrate_disable);
4316 }
4317
4318 if (lock_depth_exists) {
4319 if (lock_depth < 0)
4320 trace_seq_putc(s, '.');
4321 else
4322 trace_seq_printf(s, "%d", lock_depth);
4323 }
4324
4325 trace_seq_terminate(s);
4326}
4327
4328/**
4329 * pevent_data_type - parse out the given event type
4330 * @pevent: a handle to the pevent
4331 * @rec: the record to read from
4332 *
4333 * This returns the event id from the @rec.
4334 */
4335int pevent_data_type(struct pevent *pevent, struct pevent_record *rec)
4336{
4337 return trace_parse_common_type(pevent, rec->data);
4338}
4339
4340/**
4341 * pevent_data_event_from_type - find the event by a given type
4342 * @pevent: a handle to the pevent
4343 * @type: the type of the event.
4344 *
4345 * This returns the event form a given @type;
4346 */
4347struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type)
4348{
4349 return pevent_find_event(pevent, type);
4350}
4351
4352/**
4353 * pevent_data_pid - parse the PID from raw data
4354 * @pevent: a handle to the pevent
4355 * @rec: the record to parse
4356 *
4357 * This returns the PID from a raw data.
4358 */
4359int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec)
4360{
4361 return parse_common_pid(pevent, rec->data);
4362}
4363
4364/**
4365 * pevent_data_comm_from_pid - return the command line from PID
4366 * @pevent: a handle to the pevent
4367 * @pid: the PID of the task to search for
4368 *
4369 * This returns a pointer to the command line that has the given
4370 * @pid.
4371 */
4372const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
4373{
4374 const char *comm;
4375
4376 comm = find_cmdline(pevent, pid);
4377 return comm;
4378}
4379
4380/**
4381 * pevent_data_comm_from_pid - parse the data into the print format
4382 * @s: the trace_seq to write to
4383 * @event: the handle to the event
4384 * @record: the record to read from
4385 *
4386 * This parses the raw @data using the given @event information and
4387 * writes the print format into the trace_seq.
4388 */
4389void pevent_event_info(struct trace_seq *s, struct event_format *event,
4390 struct pevent_record *record)
4391{
4392 int print_pretty = 1;
4393
4394 if (event->pevent->print_raw)
4395 print_event_fields(s, record->data, record->size, event);
4396 else {
4397
4398 if (event->handler)
4399 print_pretty = event->handler(s, record, event,
4400 event->context);
4401
4402 if (print_pretty)
4403 pretty_print(s, record->data, record->size, event);
4404 }
4405
4406 trace_seq_terminate(s);
4407}
4408
4409void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
4410 struct pevent_record *record)
4411{
4412 static const char *spaces = " "; /* 20 spaces */
4413 struct event_format *event;
4414 unsigned long secs;
4415 unsigned long usecs;
4416 unsigned long nsecs;
4417 const char *comm;
4418 void *data = record->data;
4419 int type;
4420 int pid;
4421 int len;
4422 int p;
4423
4424 secs = record->ts / NSECS_PER_SEC;
4425 nsecs = record->ts - secs * NSECS_PER_SEC;
4426
4427 if (record->size < 0) {
4428 do_warning("ug! negative record size %d", record->size);
4429 return;
4430 }
4431
4432 type = trace_parse_common_type(pevent, data);
4433
4434 event = pevent_find_event(pevent, type);
4435 if (!event) {
4436 do_warning("ug! no event found for type %d", type);
4437 return;
4438 }
4439
4440 pid = parse_common_pid(pevent, data);
4441 comm = find_cmdline(pevent, pid);
4442
4443 if (pevent->latency_format) {
4444 trace_seq_printf(s, "%8.8s-%-5d %3d",
4445 comm, pid, record->cpu);
4446 pevent_data_lat_fmt(pevent, s, record);
4447 } else
4448 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
4449
4450 if (pevent->flags & PEVENT_NSEC_OUTPUT) {
4451 usecs = nsecs;
4452 p = 9;
4453 } else {
4454 usecs = (nsecs + 500) / NSECS_PER_USEC;
4455 p = 6;
4456 }
4457
4458 trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name);
4459
4460 /* Space out the event names evenly. */
4461 len = strlen(event->name);
4462 if (len < 20)
4463 trace_seq_printf(s, "%.*s", 20 - len, spaces);
4464
4465 pevent_event_info(s, event, record);
4466}
4467
4468static int events_id_cmp(const void *a, const void *b)
4469{
4470 struct event_format * const * ea = a;
4471 struct event_format * const * eb = b;
4472
4473 if ((*ea)->id < (*eb)->id)
4474 return -1;
4475
4476 if ((*ea)->id > (*eb)->id)
4477 return 1;
4478
4479 return 0;
4480}
4481
4482static int events_name_cmp(const void *a, const void *b)
4483{
4484 struct event_format * const * ea = a;
4485 struct event_format * const * eb = b;
4486 int res;
4487
4488 res = strcmp((*ea)->name, (*eb)->name);
4489 if (res)
4490 return res;
4491
4492 res = strcmp((*ea)->system, (*eb)->system);
4493 if (res)
4494 return res;
4495
4496 return events_id_cmp(a, b);
4497}
4498
4499static int events_system_cmp(const void *a, const void *b)
4500{
4501 struct event_format * const * ea = a;
4502 struct event_format * const * eb = b;
4503 int res;
4504
4505 res = strcmp((*ea)->system, (*eb)->system);
4506 if (res)
4507 return res;
4508
4509 res = strcmp((*ea)->name, (*eb)->name);
4510 if (res)
4511 return res;
4512
4513 return events_id_cmp(a, b);
4514}
4515
4516struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type)
4517{
4518 struct event_format **events;
4519 int (*sort)(const void *a, const void *b);
4520
4521 events = pevent->sort_events;
4522
4523 if (events && pevent->last_type == sort_type)
4524 return events;
4525
4526 if (!events) {
4527 events = malloc(sizeof(*events) * (pevent->nr_events + 1));
4528 if (!events)
4529 return NULL;
4530
4531 memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events);
4532 events[pevent->nr_events] = NULL;
4533
4534 pevent->sort_events = events;
4535
4536 /* the internal events are sorted by id */
4537 if (sort_type == EVENT_SORT_ID) {
4538 pevent->last_type = sort_type;
4539 return events;
4540 }
4541 }
4542
4543 switch (sort_type) {
4544 case EVENT_SORT_ID:
4545 sort = events_id_cmp;
4546 break;
4547 case EVENT_SORT_NAME:
4548 sort = events_name_cmp;
4549 break;
4550 case EVENT_SORT_SYSTEM:
4551 sort = events_system_cmp;
4552 break;
4553 default:
4554 return events;
4555 }
4556
4557 qsort(events, pevent->nr_events, sizeof(*events), sort);
4558 pevent->last_type = sort_type;
4559
4560 return events;
4561}
4562
4563static struct format_field **
4564get_event_fields(const char *type, const char *name,
4565 int count, struct format_field *list)
4566{
4567 struct format_field **fields;
4568 struct format_field *field;
4569 int i = 0;
4570
4571 fields = malloc(sizeof(*fields) * (count + 1));
4572 if (!fields)
4573 return NULL;
4574
4575 for (field = list; field; field = field->next) {
4576 fields[i++] = field;
4577 if (i == count + 1) {
4578 do_warning("event %s has more %s fields than specified",
4579 name, type);
4580 i--;
4581 break;
4582 }
4583 }
4584
4585 if (i != count)
4586 do_warning("event %s has less %s fields than specified",
4587 name, type);
4588
4589 fields[i] = NULL;
4590
4591 return fields;
4592}
4593
4594/**
4595 * pevent_event_common_fields - return a list of common fields for an event
4596 * @event: the event to return the common fields of.
4597 *
4598 * Returns an allocated array of fields. The last item in the array is NULL.
4599 * The array must be freed with free().
4600 */
4601struct format_field **pevent_event_common_fields(struct event_format *event)
4602{
4603 return get_event_fields("common", event->name,
4604 event->format.nr_common,
4605 event->format.common_fields);
4606}
4607
4608/**
4609 * pevent_event_fields - return a list of event specific fields for an event
4610 * @event: the event to return the fields of.
4611 *
4612 * Returns an allocated array of fields. The last item in the array is NULL.
4613 * The array must be freed with free().
4614 */
4615struct format_field **pevent_event_fields(struct event_format *event)
4616{
4617 return get_event_fields("event", event->name,
4618 event->format.nr_fields,
4619 event->format.fields);
4620}
4621
4622static void print_fields(struct trace_seq *s, struct print_flag_sym *field)
4623{
4624 trace_seq_printf(s, "{ %s, %s }", field->value, field->str);
4625 if (field->next) {
4626 trace_seq_puts(s, ", ");
4627 print_fields(s, field->next);
4628 }
4629}
4630
4631/* for debugging */
4632static void print_args(struct print_arg *args)
4633{
4634 int print_paren = 1;
4635 struct trace_seq s;
4636
4637 switch (args->type) {
4638 case PRINT_NULL:
4639 printf("null");
4640 break;
4641 case PRINT_ATOM:
4642 printf("%s", args->atom.atom);
4643 break;
4644 case PRINT_FIELD:
4645 printf("REC->%s", args->field.name);
4646 break;
4647 case PRINT_FLAGS:
4648 printf("__print_flags(");
4649 print_args(args->flags.field);
4650 printf(", %s, ", args->flags.delim);
4651 trace_seq_init(&s);
4652 print_fields(&s, args->flags.flags);
4653 trace_seq_do_printf(&s);
4654 trace_seq_destroy(&s);
4655 printf(")");
4656 break;
4657 case PRINT_SYMBOL:
4658 printf("__print_symbolic(");
4659 print_args(args->symbol.field);
4660 printf(", ");
4661 trace_seq_init(&s);
4662 print_fields(&s, args->symbol.symbols);
4663 trace_seq_do_printf(&s);
4664 trace_seq_destroy(&s);
4665 printf(")");
4666 break;
4667 case PRINT_HEX:
4668 printf("__print_hex(");
4669 print_args(args->hex.field);
4670 printf(", ");
4671 print_args(args->hex.size);
4672 printf(")");
4673 break;
4674 case PRINT_STRING:
4675 case PRINT_BSTRING:
4676 printf("__get_str(%s)", args->string.string);
4677 break;
4678 case PRINT_TYPE:
4679 printf("(%s)", args->typecast.type);
4680 print_args(args->typecast.item);
4681 break;
4682 case PRINT_OP:
4683 if (strcmp(args->op.op, ":") == 0)
4684 print_paren = 0;
4685 if (print_paren)
4686 printf("(");
4687 print_args(args->op.left);
4688 printf(" %s ", args->op.op);
4689 print_args(args->op.right);
4690 if (print_paren)
4691 printf(")");
4692 break;
4693 default:
4694 /* we should warn... */
4695 return;
4696 }
4697 if (args->next) {
4698 printf("\n");
4699 print_args(args->next);
4700 }
4701}
4702
4703static void parse_header_field(const char *field,
4704 int *offset, int *size, int mandatory)
4705{
4706 unsigned long long save_input_buf_ptr;
4707 unsigned long long save_input_buf_siz;
4708 char *token;
4709 int type;
4710
4711 save_input_buf_ptr = input_buf_ptr;
4712 save_input_buf_siz = input_buf_siz;
4713
4714 if (read_expected(EVENT_ITEM, "field") < 0)
4715 return;
4716 if (read_expected(EVENT_OP, ":") < 0)
4717 return;
4718
4719 /* type */
4720 if (read_expect_type(EVENT_ITEM, &token) < 0)
4721 goto fail;
4722 free_token(token);
4723
4724 /*
4725 * If this is not a mandatory field, then test it first.
4726 */
4727 if (mandatory) {
4728 if (read_expected(EVENT_ITEM, field) < 0)
4729 return;
4730 } else {
4731 if (read_expect_type(EVENT_ITEM, &token) < 0)
4732 goto fail;
4733 if (strcmp(token, field) != 0)
4734 goto discard;
4735 free_token(token);
4736 }
4737
4738 if (read_expected(EVENT_OP, ";") < 0)
4739 return;
4740 if (read_expected(EVENT_ITEM, "offset") < 0)
4741 return;
4742 if (read_expected(EVENT_OP, ":") < 0)
4743 return;
4744 if (read_expect_type(EVENT_ITEM, &token) < 0)
4745 goto fail;
4746 *offset = atoi(token);
4747 free_token(token);
4748 if (read_expected(EVENT_OP, ";") < 0)
4749 return;
4750 if (read_expected(EVENT_ITEM, "size") < 0)
4751 return;
4752 if (read_expected(EVENT_OP, ":") < 0)
4753 return;
4754 if (read_expect_type(EVENT_ITEM, &token) < 0)
4755 goto fail;
4756 *size = atoi(token);
4757 free_token(token);
4758 if (read_expected(EVENT_OP, ";") < 0)
4759 return;
4760 type = read_token(&token);
4761 if (type != EVENT_NEWLINE) {
4762 /* newer versions of the kernel have a "signed" type */
4763 if (type != EVENT_ITEM)
4764 goto fail;
4765
4766 if (strcmp(token, "signed") != 0)
4767 goto fail;
4768
4769 free_token(token);
4770
4771 if (read_expected(EVENT_OP, ":") < 0)
4772 return;
4773
4774 if (read_expect_type(EVENT_ITEM, &token))
4775 goto fail;
4776
4777 free_token(token);
4778 if (read_expected(EVENT_OP, ";") < 0)
4779 return;
4780
4781 if (read_expect_type(EVENT_NEWLINE, &token))
4782 goto fail;
4783 }
4784 fail:
4785 free_token(token);
4786 return;
4787
4788 discard:
4789 input_buf_ptr = save_input_buf_ptr;
4790 input_buf_siz = save_input_buf_siz;
4791 *offset = 0;
4792 *size = 0;
4793 free_token(token);
4794}
4795
4796/**
4797 * pevent_parse_header_page - parse the data stored in the header page
4798 * @pevent: the handle to the pevent
4799 * @buf: the buffer storing the header page format string
4800 * @size: the size of @buf
4801 * @long_size: the long size to use if there is no header
4802 *
4803 * This parses the header page format for information on the
4804 * ring buffer used. The @buf should be copied from
4805 *
4806 * /sys/kernel/debug/tracing/events/header_page
4807 */
4808int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
4809 int long_size)
4810{
4811 int ignore;
4812
4813 if (!size) {
4814 /*
4815 * Old kernels did not have header page info.
4816 * Sorry but we just use what we find here in user space.
4817 */
4818 pevent->header_page_ts_size = sizeof(long long);
4819 pevent->header_page_size_size = long_size;
4820 pevent->header_page_data_offset = sizeof(long long) + long_size;
4821 pevent->old_format = 1;
4822 return -1;
4823 }
4824 init_input_buf(buf, size);
4825
4826 parse_header_field("timestamp", &pevent->header_page_ts_offset,
4827 &pevent->header_page_ts_size, 1);
4828 parse_header_field("commit", &pevent->header_page_size_offset,
4829 &pevent->header_page_size_size, 1);
4830 parse_header_field("overwrite", &pevent->header_page_overwrite,
4831 &ignore, 0);
4832 parse_header_field("data", &pevent->header_page_data_offset,
4833 &pevent->header_page_data_size, 1);
4834
4835 return 0;
4836}
4837
4838static int event_matches(struct event_format *event,
4839 int id, const char *sys_name,
4840 const char *event_name)
4841{
4842 if (id >= 0 && id != event->id)
4843 return 0;
4844
4845 if (event_name && (strcmp(event_name, event->name) != 0))
4846 return 0;
4847
4848 if (sys_name && (strcmp(sys_name, event->system) != 0))
4849 return 0;
4850
4851 return 1;
4852}
4853
4854static void free_handler(struct event_handler *handle)
4855{
4856 free((void *)handle->sys_name);
4857 free((void *)handle->event_name);
4858 free(handle);
4859}
4860
4861static int find_event_handle(struct pevent *pevent, struct event_format *event)
4862{
4863 struct event_handler *handle, **next;
4864
4865 for (next = &pevent->handlers; *next;
4866 next = &(*next)->next) {
4867 handle = *next;
4868 if (event_matches(event, handle->id,
4869 handle->sys_name,
4870 handle->event_name))
4871 break;
4872 }
4873
4874 if (!(*next))
4875 return 0;
4876
4877 pr_stat("overriding event (%d) %s:%s with new print handler",
4878 event->id, event->system, event->name);
4879
4880 event->handler = handle->func;
4881 event->context = handle->context;
4882
4883 *next = handle->next;
4884 free_handler(handle);
4885
4886 return 1;
4887}
4888
4889/**
4890 * __pevent_parse_format - parse the event format
4891 * @buf: the buffer storing the event format string
4892 * @size: the size of @buf
4893 * @sys: the system the event belongs to
4894 *
4895 * This parses the event format and creates an event structure
4896 * to quickly parse raw data for a given event.
4897 *
4898 * These files currently come from:
4899 *
4900 * /sys/kernel/debug/tracing/events/.../.../format
4901 */
4902enum pevent_errno __pevent_parse_format(struct event_format **eventp,
4903 struct pevent *pevent, const char *buf,
4904 unsigned long size, const char *sys)
4905{
4906 struct event_format *event;
4907 int ret;
4908
4909 init_input_buf(buf, size);
4910
4911 *eventp = event = alloc_event();
4912 if (!event)
4913 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
4914
4915 event->name = event_read_name();
4916 if (!event->name) {
4917 /* Bad event? */
4918 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
4919 goto event_alloc_failed;
4920 }
4921
4922 if (strcmp(sys, "ftrace") == 0) {
4923 event->flags |= EVENT_FL_ISFTRACE;
4924
4925 if (strcmp(event->name, "bprint") == 0)
4926 event->flags |= EVENT_FL_ISBPRINT;
4927 }
4928
4929 event->id = event_read_id();
4930 if (event->id < 0) {
4931 ret = PEVENT_ERRNO__READ_ID_FAILED;
4932 /*
4933 * This isn't an allocation error actually.
4934 * But as the ID is critical, just bail out.
4935 */
4936 goto event_alloc_failed;
4937 }
4938
4939 event->system = strdup(sys);
4940 if (!event->system) {
4941 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
4942 goto event_alloc_failed;
4943 }
4944
4945 /* Add pevent to event so that it can be referenced */
4946 event->pevent = pevent;
4947
4948 ret = event_read_format(event);
4949 if (ret < 0) {
4950 ret = PEVENT_ERRNO__READ_FORMAT_FAILED;
4951 goto event_parse_failed;
4952 }
4953
4954 /*
4955 * If the event has an override, don't print warnings if the event
4956 * print format fails to parse.
4957 */
4958 if (pevent && find_event_handle(pevent, event))
4959 show_warning = 0;
4960
4961 ret = event_read_print(event);
4962 show_warning = 1;
4963
4964 if (ret < 0) {
4965 ret = PEVENT_ERRNO__READ_PRINT_FAILED;
4966 goto event_parse_failed;
4967 }
4968
4969 if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
4970 struct format_field *field;
4971 struct print_arg *arg, **list;
4972
4973 /* old ftrace had no args */
4974 list = &event->print_fmt.args;
4975 for (field = event->format.fields; field; field = field->next) {
4976 arg = alloc_arg();
4977 if (!arg) {
4978 event->flags |= EVENT_FL_FAILED;
4979 return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED;
4980 }
4981 arg->type = PRINT_FIELD;
4982 arg->field.name = strdup(field->name);
4983 if (!arg->field.name) {
4984 event->flags |= EVENT_FL_FAILED;
4985 free_arg(arg);
4986 return PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED;
4987 }
4988 arg->field.field = field;
4989 *list = arg;
4990 list = &arg->next;
4991 }
4992 return 0;
4993 }
4994
4995 return 0;
4996
4997 event_parse_failed:
4998 event->flags |= EVENT_FL_FAILED;
4999 return ret;
5000
5001 event_alloc_failed:
5002 free(event->system);
5003 free(event->name);
5004 free(event);
5005 *eventp = NULL;
5006 return ret;
5007}
5008
5009/**
5010 * pevent_parse_format - parse the event format
5011 * @buf: the buffer storing the event format string
5012 * @size: the size of @buf
5013 * @sys: the system the event belongs to
5014 *
5015 * This parses the event format and creates an event structure
5016 * to quickly parse raw data for a given event.
5017 *
5018 * These files currently come from:
5019 *
5020 * /sys/kernel/debug/tracing/events/.../.../format
5021 */
5022enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
5023 unsigned long size, const char *sys)
5024{
5025 return __pevent_parse_format(eventp, NULL, buf, size, sys);
5026}
5027
5028/**
5029 * pevent_parse_event - parse the event format
5030 * @pevent: the handle to the pevent
5031 * @buf: the buffer storing the event format string
5032 * @size: the size of @buf
5033 * @sys: the system the event belongs to
5034 *
5035 * This parses the event format and creates an event structure
5036 * to quickly parse raw data for a given event.
5037 *
5038 * These files currently come from:
5039 *
5040 * /sys/kernel/debug/tracing/events/.../.../format
5041 */
5042enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
5043 unsigned long size, const char *sys)
5044{
5045 struct event_format *event = NULL;
5046 int ret = __pevent_parse_format(&event, pevent, buf, size, sys);
5047
5048 if (event == NULL)
5049 return ret;
5050
5051 if (add_event(pevent, event)) {
5052 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
5053 goto event_add_failed;
5054 }
5055
5056#define PRINT_ARGS 0
5057 if (PRINT_ARGS && event->print_fmt.args)
5058 print_args(event->print_fmt.args);
5059
5060 return 0;
5061
5062event_add_failed:
5063 pevent_free_format(event);
5064 return ret;
5065}
5066
5067#undef _PE
5068#define _PE(code, str) str
5069static const char * const pevent_error_str[] = {
5070 PEVENT_ERRORS
5071};
5072#undef _PE
5073
5074int pevent_strerror(struct pevent *pevent __maybe_unused,
5075 enum pevent_errno errnum, char *buf, size_t buflen)
5076{
5077 int idx;
5078 const char *msg;
5079
5080 if (errnum >= 0) {
5081 msg = strerror_r(errnum, buf, buflen);
5082 if (msg != buf) {
5083 size_t len = strlen(msg);
5084 memcpy(buf, msg, min(buflen - 1, len));
5085 *(buf + min(buflen - 1, len)) = '\0';
5086 }
5087 return 0;
5088 }
5089
5090 if (errnum <= __PEVENT_ERRNO__START ||
5091 errnum >= __PEVENT_ERRNO__END)
5092 return -1;
5093
5094 idx = errnum - __PEVENT_ERRNO__START - 1;
5095 msg = pevent_error_str[idx];
5096
5097 switch (errnum) {
5098 case PEVENT_ERRNO__MEM_ALLOC_FAILED:
5099 case PEVENT_ERRNO__PARSE_EVENT_FAILED:
5100 case PEVENT_ERRNO__READ_ID_FAILED:
5101 case PEVENT_ERRNO__READ_FORMAT_FAILED:
5102 case PEVENT_ERRNO__READ_PRINT_FAILED:
5103 case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED:
5104 case PEVENT_ERRNO__INVALID_ARG_TYPE:
5105 snprintf(buf, buflen, "%s", msg);
5106 break;
5107
5108 default:
5109 /* cannot reach here */
5110 break;
5111 }
5112
5113 return 0;
5114}
5115
5116int get_field_val(struct trace_seq *s, struct format_field *field,
5117 const char *name, struct pevent_record *record,
5118 unsigned long long *val, int err)
5119{
5120 if (!field) {
5121 if (err)
5122 trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
5123 return -1;
5124 }
5125
5126 if (pevent_read_number_field(field, record->data, val)) {
5127 if (err)
5128 trace_seq_printf(s, " %s=INVALID", name);
5129 return -1;
5130 }
5131
5132 return 0;
5133}
5134
5135/**
5136 * pevent_get_field_raw - return the raw pointer into the data field
5137 * @s: The seq to print to on error
5138 * @event: the event that the field is for
5139 * @name: The name of the field
5140 * @record: The record with the field name.
5141 * @len: place to store the field length.
5142 * @err: print default error if failed.
5143 *
5144 * Returns a pointer into record->data of the field and places
5145 * the length of the field in @len.
5146 *
5147 * On failure, it returns NULL.
5148 */
5149void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
5150 const char *name, struct pevent_record *record,
5151 int *len, int err)
5152{
5153 struct format_field *field;
5154 void *data = record->data;
5155 unsigned offset;
5156 int dummy;
5157
5158 if (!event)
5159 return NULL;
5160
5161 field = pevent_find_field(event, name);
5162
5163 if (!field) {
5164 if (err)
5165 trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
5166 return NULL;
5167 }
5168
5169 /* Allow @len to be NULL */
5170 if (!len)
5171 len = &dummy;
5172
5173 offset = field->offset;
5174 if (field->flags & FIELD_IS_DYNAMIC) {
5175 offset = pevent_read_number(event->pevent,
5176 data + offset, field->size);
5177 *len = offset >> 16;
5178 offset &= 0xffff;
5179 } else
5180 *len = field->size;
5181
5182 return data + offset;
5183}
5184
5185/**
5186 * pevent_get_field_val - find a field and return its value
5187 * @s: The seq to print to on error
5188 * @event: the event that the field is for
5189 * @name: The name of the field
5190 * @record: The record with the field name.
5191 * @val: place to store the value of the field.
5192 * @err: print default error if failed.
5193 *
5194 * Returns 0 on success -1 on field not found.
5195 */
5196int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
5197 const char *name, struct pevent_record *record,
5198 unsigned long long *val, int err)
5199{
5200 struct format_field *field;
5201
5202 if (!event)
5203 return -1;
5204
5205 field = pevent_find_field(event, name);
5206
5207 return get_field_val(s, field, name, record, val, err);
5208}
5209
5210/**
5211 * pevent_get_common_field_val - find a common field and return its value
5212 * @s: The seq to print to on error
5213 * @event: the event that the field is for
5214 * @name: The name of the field
5215 * @record: The record with the field name.
5216 * @val: place to store the value of the field.
5217 * @err: print default error if failed.
5218 *
5219 * Returns 0 on success -1 on field not found.
5220 */
5221int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
5222 const char *name, struct pevent_record *record,
5223 unsigned long long *val, int err)
5224{
5225 struct format_field *field;
5226
5227 if (!event)
5228 return -1;
5229
5230 field = pevent_find_common_field(event, name);
5231
5232 return get_field_val(s, field, name, record, val, err);
5233}
5234
5235/**
5236 * pevent_get_any_field_val - find a any field and return its value
5237 * @s: The seq to print to on error
5238 * @event: the event that the field is for
5239 * @name: The name of the field
5240 * @record: The record with the field name.
5241 * @val: place to store the value of the field.
5242 * @err: print default error if failed.
5243 *
5244 * Returns 0 on success -1 on field not found.
5245 */
5246int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
5247 const char *name, struct pevent_record *record,
5248 unsigned long long *val, int err)
5249{
5250 struct format_field *field;
5251
5252 if (!event)
5253 return -1;
5254
5255 field = pevent_find_any_field(event, name);
5256
5257 return get_field_val(s, field, name, record, val, err);
5258}
5259
5260/**
5261 * pevent_print_num_field - print a field and a format
5262 * @s: The seq to print to
5263 * @fmt: The printf format to print the field with.
5264 * @event: the event that the field is for
5265 * @name: The name of the field
5266 * @record: The record with the field name.
5267 * @err: print default error if failed.
5268 *
5269 * Returns: 0 on success, -1 field not found, or 1 if buffer is full.
5270 */
5271int pevent_print_num_field(struct trace_seq *s, const char *fmt,
5272 struct event_format *event, const char *name,
5273 struct pevent_record *record, int err)
5274{
5275 struct format_field *field = pevent_find_field(event, name);
5276 unsigned long long val;
5277
5278 if (!field)
5279 goto failed;
5280
5281 if (pevent_read_number_field(field, record->data, &val))
5282 goto failed;
5283
5284 return trace_seq_printf(s, fmt, val);
5285
5286 failed:
5287 if (err)
5288 trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
5289 return -1;
5290}
5291
5292static void free_func_handle(struct pevent_function_handler *func)
5293{
5294 struct pevent_func_params *params;
5295
5296 free(func->name);
5297
5298 while (func->params) {
5299 params = func->params;
5300 func->params = params->next;
5301 free(params);
5302 }
5303
5304 free(func);
5305}
5306
5307/**
5308 * pevent_register_print_function - register a helper function
5309 * @pevent: the handle to the pevent
5310 * @func: the function to process the helper function
5311 * @ret_type: the return type of the helper function
5312 * @name: the name of the helper function
5313 * @parameters: A list of enum pevent_func_arg_type
5314 *
5315 * Some events may have helper functions in the print format arguments.
5316 * This allows a plugin to dynamically create a way to process one
5317 * of these functions.
5318 *
5319 * The @parameters is a variable list of pevent_func_arg_type enums that
5320 * must end with PEVENT_FUNC_ARG_VOID.
5321 */
5322int pevent_register_print_function(struct pevent *pevent,
5323 pevent_func_handler func,
5324 enum pevent_func_arg_type ret_type,
5325 char *name, ...)
5326{
5327 struct pevent_function_handler *func_handle;
5328 struct pevent_func_params **next_param;
5329 struct pevent_func_params *param;
5330 enum pevent_func_arg_type type;
5331 va_list ap;
5332 int ret;
5333
5334 func_handle = find_func_handler(pevent, name);
5335 if (func_handle) {
5336 /*
5337 * This is most like caused by the users own
5338 * plugins updating the function. This overrides the
5339 * system defaults.
5340 */
5341 pr_stat("override of function helper '%s'", name);
5342 remove_func_handler(pevent, name);
5343 }
5344
5345 func_handle = calloc(1, sizeof(*func_handle));
5346 if (!func_handle) {
5347 do_warning("Failed to allocate function handler");
5348 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
5349 }
5350
5351 func_handle->ret_type = ret_type;
5352 func_handle->name = strdup(name);
5353 func_handle->func = func;
5354 if (!func_handle->name) {
5355 do_warning("Failed to allocate function name");
5356 free(func_handle);
5357 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
5358 }
5359
5360 next_param = &(func_handle->params);
5361 va_start(ap, name);
5362 for (;;) {
5363 type = va_arg(ap, enum pevent_func_arg_type);
5364 if (type == PEVENT_FUNC_ARG_VOID)
5365 break;
5366
5367 if (type >= PEVENT_FUNC_ARG_MAX_TYPES) {
5368 do_warning("Invalid argument type %d", type);
5369 ret = PEVENT_ERRNO__INVALID_ARG_TYPE;
5370 goto out_free;
5371 }
5372
5373 param = malloc(sizeof(*param));
5374 if (!param) {
5375 do_warning("Failed to allocate function param");
5376 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
5377 goto out_free;
5378 }
5379 param->type = type;
5380 param->next = NULL;
5381
5382 *next_param = param;
5383 next_param = &(param->next);
5384
5385 func_handle->nr_args++;
5386 }
5387 va_end(ap);
5388
5389 func_handle->next = pevent->func_handlers;
5390 pevent->func_handlers = func_handle;
5391
5392 return 0;
5393 out_free:
5394 va_end(ap);
5395 free_func_handle(func_handle);
5396 return ret;
5397}
5398
5399/**
5400 * pevent_register_event_handler - register a way to parse an event
5401 * @pevent: the handle to the pevent
5402 * @id: the id of the event to register
5403 * @sys_name: the system name the event belongs to
5404 * @event_name: the name of the event
5405 * @func: the function to call to parse the event information
5406 * @context: the data to be passed to @func
5407 *
5408 * This function allows a developer to override the parsing of
5409 * a given event. If for some reason the default print format
5410 * is not sufficient, this function will register a function
5411 * for an event to be used to parse the data instead.
5412 *
5413 * If @id is >= 0, then it is used to find the event.
5414 * else @sys_name and @event_name are used.
5415 */
5416int pevent_register_event_handler(struct pevent *pevent,
5417 int id, char *sys_name, char *event_name,
5418 pevent_event_handler_func func,
5419 void *context)
5420{
5421 struct event_format *event;
5422 struct event_handler *handle;
5423
5424 if (id >= 0) {
5425 /* search by id */
5426 event = pevent_find_event(pevent, id);
5427 if (!event)
5428 goto not_found;
5429 if (event_name && (strcmp(event_name, event->name) != 0))
5430 goto not_found;
5431 if (sys_name && (strcmp(sys_name, event->system) != 0))
5432 goto not_found;
5433 } else {
5434 event = pevent_find_event_by_name(pevent, sys_name, event_name);
5435 if (!event)
5436 goto not_found;
5437 }
5438
5439 pr_stat("overriding event (%d) %s:%s with new print handler",
5440 event->id, event->system, event->name);
5441
5442 event->handler = func;
5443 event->context = context;
5444 return 0;
5445
5446 not_found:
5447 /* Save for later use. */
5448 handle = calloc(1, sizeof(*handle));
5449 if (!handle) {
5450 do_warning("Failed to allocate event handler");
5451 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
5452 }
5453
5454 handle->id = id;
5455 if (event_name)
5456 handle->event_name = strdup(event_name);
5457 if (sys_name)
5458 handle->sys_name = strdup(sys_name);
5459
5460 if ((event_name && !handle->event_name) ||
5461 (sys_name && !handle->sys_name)) {
5462 do_warning("Failed to allocate event/sys name");
5463 free((void *)handle->event_name);
5464 free((void *)handle->sys_name);
5465 free(handle);
5466 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
5467 }
5468
5469 handle->func = func;
5470 handle->next = pevent->handlers;
5471 pevent->handlers = handle;
5472 handle->context = context;
5473
5474 return -1;
5475}
5476
5477/**
5478 * pevent_alloc - create a pevent handle
5479 */
5480struct pevent *pevent_alloc(void)
5481{
5482 struct pevent *pevent = calloc(1, sizeof(*pevent));
5483
5484 if (pevent)
5485 pevent->ref_count = 1;
5486
5487 return pevent;
5488}
5489
5490void pevent_ref(struct pevent *pevent)
5491{
5492 pevent->ref_count++;
5493}
5494
5495static void free_format_fields(struct format_field *field)
5496{
5497 struct format_field *next;
5498
5499 while (field) {
5500 next = field->next;
5501 free(field->type);
5502 free(field->name);
5503 free(field);
5504 field = next;
5505 }
5506}
5507
5508static void free_formats(struct format *format)
5509{
5510 free_format_fields(format->common_fields);
5511 free_format_fields(format->fields);
5512}
5513
5514void pevent_free_format(struct event_format *event)
5515{
5516 free(event->name);
5517 free(event->system);
5518
5519 free_formats(&event->format);
5520
5521 free(event->print_fmt.format);
5522 free_args(event->print_fmt.args);
5523
5524 free(event);
5525}
5526
5527/**
5528 * pevent_free - free a pevent handle
5529 * @pevent: the pevent handle to free
5530 */
5531void pevent_free(struct pevent *pevent)
5532{
5533 struct cmdline_list *cmdlist, *cmdnext;
5534 struct func_list *funclist, *funcnext;
5535 struct printk_list *printklist, *printknext;
5536 struct pevent_function_handler *func_handler;
5537 struct event_handler *handle;
5538 int i;
5539
5540 if (!pevent)
5541 return;
5542
5543 cmdlist = pevent->cmdlist;
5544 funclist = pevent->funclist;
5545 printklist = pevent->printklist;
5546
5547 pevent->ref_count--;
5548 if (pevent->ref_count)
5549 return;
5550
5551 if (pevent->cmdlines) {
5552 for (i = 0; i < pevent->cmdline_count; i++)
5553 free(pevent->cmdlines[i].comm);
5554 free(pevent->cmdlines);
5555 }
5556
5557 while (cmdlist) {
5558 cmdnext = cmdlist->next;
5559 free(cmdlist->comm);
5560 free(cmdlist);
5561 cmdlist = cmdnext;
5562 }
5563
5564 if (pevent->func_map) {
5565 for (i = 0; i < (int)pevent->func_count; i++) {
5566 free(pevent->func_map[i].func);
5567 free(pevent->func_map[i].mod);
5568 }
5569 free(pevent->func_map);
5570 }
5571
5572 while (funclist) {
5573 funcnext = funclist->next;
5574 free(funclist->func);
5575 free(funclist->mod);
5576 free(funclist);
5577 funclist = funcnext;
5578 }
5579
5580 while (pevent->func_handlers) {
5581 func_handler = pevent->func_handlers;
5582 pevent->func_handlers = func_handler->next;
5583 free_func_handle(func_handler);
5584 }
5585
5586 if (pevent->printk_map) {
5587 for (i = 0; i < (int)pevent->printk_count; i++)
5588 free(pevent->printk_map[i].printk);
5589 free(pevent->printk_map);
5590 }
5591
5592 while (printklist) {
5593 printknext = printklist->next;
5594 free(printklist->printk);
5595 free(printklist);
5596 printklist = printknext;
5597 }
5598
5599 for (i = 0; i < pevent->nr_events; i++)
5600 pevent_free_format(pevent->events[i]);
5601
5602 while (pevent->handlers) {
5603 handle = pevent->handlers;
5604 pevent->handlers = handle->next;
5605 free_handler(handle);
5606 }
5607
5608 free(pevent->events);
5609 free(pevent->sort_events);
5610
5611 free(pevent);
5612}
5613
5614void pevent_unref(struct pevent *pevent)
5615{
5616 pevent_free(pevent);
5617}
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
deleted file mode 100644
index 24a4bbabc5d..00000000000
--- a/tools/lib/traceevent/event-parse.h
+++ /dev/null
@@ -1,845 +0,0 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#ifndef _PARSE_EVENTS_H
22#define _PARSE_EVENTS_H
23
24#include <stdarg.h>
25#include <regex.h>
26
27#ifndef __maybe_unused
28#define __maybe_unused __attribute__((unused))
29#endif
30
31/* ----------------------- trace_seq ----------------------- */
32
33
34#ifndef TRACE_SEQ_BUF_SIZE
35#define TRACE_SEQ_BUF_SIZE 4096
36#endif
37
38#ifndef DEBUG_RECORD
39#define DEBUG_RECORD 0
40#endif
41
42struct pevent_record {
43 unsigned long long ts;
44 unsigned long long offset;
45 long long missed_events; /* buffer dropped events before */
46 int record_size; /* size of binary record */
47 int size; /* size of data */
48 void *data;
49 int cpu;
50 int ref_count;
51 int locked; /* Do not free, even if ref_count is zero */
52 void *priv;
53#if DEBUG_RECORD
54 struct pevent_record *prev;
55 struct pevent_record *next;
56 long alloc_addr;
57#endif
58};
59
60/*
61 * Trace sequences are used to allow a function to call several other functions
62 * to create a string of data to use (up to a max of PAGE_SIZE).
63 */
64
65struct trace_seq {
66 char *buffer;
67 unsigned int buffer_size;
68 unsigned int len;
69 unsigned int readpos;
70};
71
72void trace_seq_init(struct trace_seq *s);
73void trace_seq_destroy(struct trace_seq *s);
74
75extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
76 __attribute__ ((format (printf, 2, 3)));
77extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
78 __attribute__ ((format (printf, 2, 0)));
79
80extern int trace_seq_puts(struct trace_seq *s, const char *str);
81extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
82
83extern void trace_seq_terminate(struct trace_seq *s);
84
85extern int trace_seq_do_printf(struct trace_seq *s);
86
87
88/* ----------------------- pevent ----------------------- */
89
90struct pevent;
91struct event_format;
92
93typedef int (*pevent_event_handler_func)(struct trace_seq *s,
94 struct pevent_record *record,
95 struct event_format *event,
96 void *context);
97
98typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
99typedef int (*pevent_plugin_unload_func)(void);
100
101struct plugin_option {
102 struct plugin_option *next;
103 void *handle;
104 char *file;
105 char *name;
106 char *plugin_alias;
107 char *description;
108 char *value;
109 void *priv;
110 int set;
111};
112
113/*
114 * Plugin hooks that can be called:
115 *
116 * PEVENT_PLUGIN_LOADER: (required)
117 * The function name to initialized the plugin.
118 *
119 * int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
120 *
121 * PEVENT_PLUGIN_UNLOADER: (optional)
122 * The function called just before unloading
123 *
124 * int PEVENT_PLUGIN_UNLOADER(void)
125 *
126 * PEVENT_PLUGIN_OPTIONS: (optional)
127 * Plugin options that can be set before loading
128 *
129 * struct plugin_option PEVENT_PLUGIN_OPTIONS[] = {
130 * {
131 * .name = "option-name",
132 * .plugin_alias = "overide-file-name", (optional)
133 * .description = "description of option to show users",
134 * },
135 * {
136 * .name = NULL,
137 * },
138 * };
139 *
140 * Array must end with .name = NULL;
141 *
142 *
143 * .plugin_alias is used to give a shorter name to access
144 * the vairable. Useful if a plugin handles more than one event.
145 *
146 * PEVENT_PLUGIN_ALIAS: (optional)
147 * The name to use for finding options (uses filename if not defined)
148 */
149#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
150#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
151#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options
152#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias
153#define _MAKE_STR(x) #x
154#define MAKE_STR(x) _MAKE_STR(x)
155#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
156#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)
157#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
158#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
159
160#define NSECS_PER_SEC 1000000000ULL
161#define NSECS_PER_USEC 1000ULL
162
163enum format_flags {
164 FIELD_IS_ARRAY = 1,
165 FIELD_IS_POINTER = 2,
166 FIELD_IS_SIGNED = 4,
167 FIELD_IS_STRING = 8,
168 FIELD_IS_DYNAMIC = 16,
169 FIELD_IS_LONG = 32,
170 FIELD_IS_FLAG = 64,
171 FIELD_IS_SYMBOLIC = 128,
172};
173
174struct format_field {
175 struct format_field *next;
176 struct event_format *event;
177 char *type;
178 char *name;
179 int offset;
180 int size;
181 unsigned int arraylen;
182 unsigned int elementsize;
183 unsigned long flags;
184};
185
186struct format {
187 int nr_common;
188 int nr_fields;
189 struct format_field *common_fields;
190 struct format_field *fields;
191};
192
193struct print_arg_atom {
194 char *atom;
195};
196
197struct print_arg_string {
198 char *string;
199 int offset;
200};
201
202struct print_arg_field {
203 char *name;
204 struct format_field *field;
205};
206
207struct print_flag_sym {
208 struct print_flag_sym *next;
209 char *value;
210 char *str;
211};
212
213struct print_arg_typecast {
214 char *type;
215 struct print_arg *item;
216};
217
218struct print_arg_flags {
219 struct print_arg *field;
220 char *delim;
221 struct print_flag_sym *flags;
222};
223
224struct print_arg_symbol {
225 struct print_arg *field;
226 struct print_flag_sym *symbols;
227};
228
229struct print_arg_hex {
230 struct print_arg *field;
231 struct print_arg *size;
232};
233
234struct print_arg_dynarray {
235 struct format_field *field;
236 struct print_arg *index;
237};
238
239struct print_arg;
240
241struct print_arg_op {
242 char *op;
243 int prio;
244 struct print_arg *left;
245 struct print_arg *right;
246};
247
248struct pevent_function_handler;
249
250struct print_arg_func {
251 struct pevent_function_handler *func;
252 struct print_arg *args;
253};
254
255enum print_arg_type {
256 PRINT_NULL,
257 PRINT_ATOM,
258 PRINT_FIELD,
259 PRINT_FLAGS,
260 PRINT_SYMBOL,
261 PRINT_HEX,
262 PRINT_TYPE,
263 PRINT_STRING,
264 PRINT_BSTRING,
265 PRINT_DYNAMIC_ARRAY,
266 PRINT_OP,
267 PRINT_FUNC,
268};
269
270struct print_arg {
271 struct print_arg *next;
272 enum print_arg_type type;
273 union {
274 struct print_arg_atom atom;
275 struct print_arg_field field;
276 struct print_arg_typecast typecast;
277 struct print_arg_flags flags;
278 struct print_arg_symbol symbol;
279 struct print_arg_hex hex;
280 struct print_arg_func func;
281 struct print_arg_string string;
282 struct print_arg_op op;
283 struct print_arg_dynarray dynarray;
284 };
285};
286
287struct print_fmt {
288 char *format;
289 struct print_arg *args;
290};
291
292struct event_format {
293 struct pevent *pevent;
294 char *name;
295 int id;
296 int flags;
297 struct format format;
298 struct print_fmt print_fmt;
299 char *system;
300 pevent_event_handler_func handler;
301 void *context;
302};
303
304enum {
305 EVENT_FL_ISFTRACE = 0x01,
306 EVENT_FL_ISPRINT = 0x02,
307 EVENT_FL_ISBPRINT = 0x04,
308 EVENT_FL_ISFUNCENT = 0x10,
309 EVENT_FL_ISFUNCRET = 0x20,
310
311 EVENT_FL_FAILED = 0x80000000
312};
313
314enum event_sort_type {
315 EVENT_SORT_ID,
316 EVENT_SORT_NAME,
317 EVENT_SORT_SYSTEM,
318};
319
320enum event_type {
321 EVENT_ERROR,
322 EVENT_NONE,
323 EVENT_SPACE,
324 EVENT_NEWLINE,
325 EVENT_OP,
326 EVENT_DELIM,
327 EVENT_ITEM,
328 EVENT_DQUOTE,
329 EVENT_SQUOTE,
330};
331
332typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
333 unsigned long long *args);
334
335enum pevent_func_arg_type {
336 PEVENT_FUNC_ARG_VOID,
337 PEVENT_FUNC_ARG_INT,
338 PEVENT_FUNC_ARG_LONG,
339 PEVENT_FUNC_ARG_STRING,
340 PEVENT_FUNC_ARG_PTR,
341 PEVENT_FUNC_ARG_MAX_TYPES
342};
343
344enum pevent_flag {
345 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */
346};
347
348#define PEVENT_ERRORS \
349 _PE(MEM_ALLOC_FAILED, "failed to allocate memory"), \
350 _PE(PARSE_EVENT_FAILED, "failed to parse event"), \
351 _PE(READ_ID_FAILED, "failed to read event id"), \
352 _PE(READ_FORMAT_FAILED, "failed to read event format"), \
353 _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \
354 _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\
355 _PE(INVALID_ARG_TYPE, "invalid argument type")
356
357#undef _PE
358#define _PE(__code, __str) PEVENT_ERRNO__ ## __code
359enum pevent_errno {
360 PEVENT_ERRNO__SUCCESS = 0,
361
362 /*
363 * Choose an arbitrary negative big number not to clash with standard
364 * errno since SUS requires the errno has distinct positive values.
365 * See 'Issue 6' in the link below.
366 *
367 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
368 */
369 __PEVENT_ERRNO__START = -100000,
370
371 PEVENT_ERRORS,
372
373 __PEVENT_ERRNO__END,
374};
375#undef _PE
376
377struct cmdline;
378struct cmdline_list;
379struct func_map;
380struct func_list;
381struct event_handler;
382
383struct pevent {
384 int ref_count;
385
386 int header_page_ts_offset;
387 int header_page_ts_size;
388 int header_page_size_offset;
389 int header_page_size_size;
390 int header_page_data_offset;
391 int header_page_data_size;
392 int header_page_overwrite;
393
394 int file_bigendian;
395 int host_bigendian;
396
397 int latency_format;
398
399 int old_format;
400
401 int cpus;
402 int long_size;
403
404 struct cmdline *cmdlines;
405 struct cmdline_list *cmdlist;
406 int cmdline_count;
407
408 struct func_map *func_map;
409 struct func_list *funclist;
410 unsigned int func_count;
411
412 struct printk_map *printk_map;
413 struct printk_list *printklist;
414 unsigned int printk_count;
415
416
417 struct event_format **events;
418 int nr_events;
419 struct event_format **sort_events;
420 enum event_sort_type last_type;
421
422 int type_offset;
423 int type_size;
424
425 int pid_offset;
426 int pid_size;
427
428 int pc_offset;
429 int pc_size;
430
431 int flags_offset;
432 int flags_size;
433
434 int ld_offset;
435 int ld_size;
436
437 int print_raw;
438
439 int test_filters;
440
441 int flags;
442
443 struct format_field *bprint_ip_field;
444 struct format_field *bprint_fmt_field;
445 struct format_field *bprint_buf_field;
446
447 struct event_handler *handlers;
448 struct pevent_function_handler *func_handlers;
449
450 /* cache */
451 struct event_format *last_event;
452};
453
454static inline void pevent_set_flag(struct pevent *pevent, int flag)
455{
456 pevent->flags |= flag;
457}
458
459static inline unsigned short
460__data2host2(struct pevent *pevent, unsigned short data)
461{
462 unsigned short swap;
463
464 if (pevent->host_bigendian == pevent->file_bigendian)
465 return data;
466
467 swap = ((data & 0xffULL) << 8) |
468 ((data & (0xffULL << 8)) >> 8);
469
470 return swap;
471}
472
473static inline unsigned int
474__data2host4(struct pevent *pevent, unsigned int data)
475{
476 unsigned int swap;
477
478 if (pevent->host_bigendian == pevent->file_bigendian)
479 return data;
480
481 swap = ((data & 0xffULL) << 24) |
482 ((data & (0xffULL << 8)) << 8) |
483 ((data & (0xffULL << 16)) >> 8) |
484 ((data & (0xffULL << 24)) >> 24);
485
486 return swap;
487}
488
489static inline unsigned long long
490__data2host8(struct pevent *pevent, unsigned long long data)
491{
492 unsigned long long swap;
493
494 if (pevent->host_bigendian == pevent->file_bigendian)
495 return data;
496
497 swap = ((data & 0xffULL) << 56) |
498 ((data & (0xffULL << 8)) << 40) |
499 ((data & (0xffULL << 16)) << 24) |
500 ((data & (0xffULL << 24)) << 8) |
501 ((data & (0xffULL << 32)) >> 8) |
502 ((data & (0xffULL << 40)) >> 24) |
503 ((data & (0xffULL << 48)) >> 40) |
504 ((data & (0xffULL << 56)) >> 56);
505
506 return swap;
507}
508
509#define data2host2(pevent, ptr) __data2host2(pevent, *(unsigned short *)(ptr))
510#define data2host4(pevent, ptr) __data2host4(pevent, *(unsigned int *)(ptr))
511#define data2host8(pevent, ptr) \
512({ \
513 unsigned long long __val; \
514 \
515 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
516 __data2host8(pevent, __val); \
517})
518
519/* taken from kernel/trace/trace.h */
520enum trace_flag_type {
521 TRACE_FLAG_IRQS_OFF = 0x01,
522 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
523 TRACE_FLAG_NEED_RESCHED = 0x04,
524 TRACE_FLAG_HARDIRQ = 0x08,
525 TRACE_FLAG_SOFTIRQ = 0x10,
526};
527
528int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
529int pevent_register_function(struct pevent *pevent, char *name,
530 unsigned long long addr, char *mod);
531int pevent_register_print_string(struct pevent *pevent, char *fmt,
532 unsigned long long addr);
533int pevent_pid_is_registered(struct pevent *pevent, int pid);
534
535void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
536 struct pevent_record *record);
537
538int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
539 int long_size);
540
541enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
542 unsigned long size, const char *sys);
543enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
544 unsigned long size, const char *sys);
545void pevent_free_format(struct event_format *event);
546
547void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
548 const char *name, struct pevent_record *record,
549 int *len, int err);
550
551int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
552 const char *name, struct pevent_record *record,
553 unsigned long long *val, int err);
554int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
555 const char *name, struct pevent_record *record,
556 unsigned long long *val, int err);
557int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
558 const char *name, struct pevent_record *record,
559 unsigned long long *val, int err);
560
561int pevent_print_num_field(struct trace_seq *s, const char *fmt,
562 struct event_format *event, const char *name,
563 struct pevent_record *record, int err);
564
565int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
566 pevent_event_handler_func func, void *context);
567int pevent_register_print_function(struct pevent *pevent,
568 pevent_func_handler func,
569 enum pevent_func_arg_type ret_type,
570 char *name, ...);
571
572struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
573struct format_field *pevent_find_field(struct event_format *event, const char *name);
574struct format_field *pevent_find_any_field(struct event_format *event, const char *name);
575
576const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
577unsigned long long
578pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
579unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
580int pevent_read_number_field(struct format_field *field, const void *data,
581 unsigned long long *value);
582
583struct event_format *pevent_find_event(struct pevent *pevent, int id);
584
585struct event_format *
586pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
587
588void pevent_data_lat_fmt(struct pevent *pevent,
589 struct trace_seq *s, struct pevent_record *record);
590int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
591struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
592int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
593const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
594void pevent_event_info(struct trace_seq *s, struct event_format *event,
595 struct pevent_record *record);
596int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
597 char *buf, size_t buflen);
598
599struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
600struct format_field **pevent_event_common_fields(struct event_format *event);
601struct format_field **pevent_event_fields(struct event_format *event);
602
603static inline int pevent_get_cpus(struct pevent *pevent)
604{
605 return pevent->cpus;
606}
607
608static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
609{
610 pevent->cpus = cpus;
611}
612
613static inline int pevent_get_long_size(struct pevent *pevent)
614{
615 return pevent->long_size;
616}
617
618static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
619{
620 pevent->long_size = long_size;
621}
622
623static inline int pevent_is_file_bigendian(struct pevent *pevent)
624{
625 return pevent->file_bigendian;
626}
627
628static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
629{
630 pevent->file_bigendian = endian;
631}
632
633static inline int pevent_is_host_bigendian(struct pevent *pevent)
634{
635 return pevent->host_bigendian;
636}
637
638static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
639{
640 pevent->host_bigendian = endian;
641}
642
643static inline int pevent_is_latency_format(struct pevent *pevent)
644{
645 return pevent->latency_format;
646}
647
648static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
649{
650 pevent->latency_format = lat;
651}
652
653struct pevent *pevent_alloc(void);
654void pevent_free(struct pevent *pevent);
655void pevent_ref(struct pevent *pevent);
656void pevent_unref(struct pevent *pevent);
657
658/* access to the internal parser */
659void pevent_buffer_init(const char *buf, unsigned long long size);
660enum event_type pevent_read_token(char **tok);
661void pevent_free_token(char *token);
662int pevent_peek_char(void);
663const char *pevent_get_input_buf(void);
664unsigned long long pevent_get_input_buf_ptr(void);
665
666/* for debugging */
667void pevent_print_funcs(struct pevent *pevent);
668void pevent_print_printk(struct pevent *pevent);
669
670/* ----------------------- filtering ----------------------- */
671
672enum filter_boolean_type {
673 FILTER_FALSE,
674 FILTER_TRUE,
675};
676
677enum filter_op_type {
678 FILTER_OP_AND = 1,
679 FILTER_OP_OR,
680 FILTER_OP_NOT,
681};
682
683enum filter_cmp_type {
684 FILTER_CMP_NONE,
685 FILTER_CMP_EQ,
686 FILTER_CMP_NE,
687 FILTER_CMP_GT,
688 FILTER_CMP_LT,
689 FILTER_CMP_GE,
690 FILTER_CMP_LE,
691 FILTER_CMP_MATCH,
692 FILTER_CMP_NOT_MATCH,
693 FILTER_CMP_REGEX,
694 FILTER_CMP_NOT_REGEX,
695};
696
697enum filter_exp_type {
698 FILTER_EXP_NONE,
699 FILTER_EXP_ADD,
700 FILTER_EXP_SUB,
701 FILTER_EXP_MUL,
702 FILTER_EXP_DIV,
703 FILTER_EXP_MOD,
704 FILTER_EXP_RSHIFT,
705 FILTER_EXP_LSHIFT,
706 FILTER_EXP_AND,
707 FILTER_EXP_OR,
708 FILTER_EXP_XOR,
709 FILTER_EXP_NOT,
710};
711
712enum filter_arg_type {
713 FILTER_ARG_NONE,
714 FILTER_ARG_BOOLEAN,
715 FILTER_ARG_VALUE,
716 FILTER_ARG_FIELD,
717 FILTER_ARG_EXP,
718 FILTER_ARG_OP,
719 FILTER_ARG_NUM,
720 FILTER_ARG_STR,
721};
722
723enum filter_value_type {
724 FILTER_NUMBER,
725 FILTER_STRING,
726 FILTER_CHAR
727};
728
729struct fliter_arg;
730
731struct filter_arg_boolean {
732 enum filter_boolean_type value;
733};
734
735struct filter_arg_field {
736 struct format_field *field;
737};
738
739struct filter_arg_value {
740 enum filter_value_type type;
741 union {
742 char *str;
743 unsigned long long val;
744 };
745};
746
747struct filter_arg_op {
748 enum filter_op_type type;
749 struct filter_arg *left;
750 struct filter_arg *right;
751};
752
753struct filter_arg_exp {
754 enum filter_exp_type type;
755 struct filter_arg *left;
756 struct filter_arg *right;
757};
758
759struct filter_arg_num {
760 enum filter_cmp_type type;
761 struct filter_arg *left;
762 struct filter_arg *right;
763};
764
765struct filter_arg_str {
766 enum filter_cmp_type type;
767 struct format_field *field;
768 char *val;
769 char *buffer;
770 regex_t reg;
771};
772
773struct filter_arg {
774 enum filter_arg_type type;
775 union {
776 struct filter_arg_boolean boolean;
777 struct filter_arg_field field;
778 struct filter_arg_value value;
779 struct filter_arg_op op;
780 struct filter_arg_exp exp;
781 struct filter_arg_num num;
782 struct filter_arg_str str;
783 };
784};
785
786struct filter_type {
787 int event_id;
788 struct event_format *event;
789 struct filter_arg *filter;
790};
791
792struct event_filter {
793 struct pevent *pevent;
794 int filters;
795 struct filter_type *event_filters;
796};
797
798struct event_filter *pevent_filter_alloc(struct pevent *pevent);
799
800#define FILTER_NONE -2
801#define FILTER_NOEXIST -1
802#define FILTER_MISS 0
803#define FILTER_MATCH 1
804
805enum filter_trivial_type {
806 FILTER_TRIVIAL_FALSE,
807 FILTER_TRIVIAL_TRUE,
808 FILTER_TRIVIAL_BOTH,
809};
810
811int pevent_filter_add_filter_str(struct event_filter *filter,
812 const char *filter_str,
813 char **error_str);
814
815
816int pevent_filter_match(struct event_filter *filter,
817 struct pevent_record *record);
818
819int pevent_event_filtered(struct event_filter *filter,
820 int event_id);
821
822void pevent_filter_reset(struct event_filter *filter);
823
824void pevent_filter_clear_trivial(struct event_filter *filter,
825 enum filter_trivial_type type);
826
827void pevent_filter_free(struct event_filter *filter);
828
829char *pevent_filter_make_string(struct event_filter *filter, int event_id);
830
831int pevent_filter_remove_event(struct event_filter *filter,
832 int event_id);
833
834int pevent_filter_event_has_trivial(struct event_filter *filter,
835 int event_id,
836 enum filter_trivial_type type);
837
838int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);
839
840int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
841 enum filter_trivial_type type);
842
843int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
844
845#endif /* _PARSE_EVENTS_H */
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
deleted file mode 100644
index bc075006966..00000000000
--- a/tools/lib/traceevent/event-utils.h
+++ /dev/null
@@ -1,86 +0,0 @@
1/*
2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#ifndef __UTIL_H
22#define __UTIL_H
23
24#include <ctype.h>
25
26/* Can be overridden */
27void die(const char *fmt, ...);
28void *malloc_or_die(unsigned int size);
29void warning(const char *fmt, ...);
30void pr_stat(const char *fmt, ...);
31void vpr_stat(const char *fmt, va_list ap);
32
33/* Always available */
34void __die(const char *fmt, ...);
35void __warning(const char *fmt, ...);
36void __pr_stat(const char *fmt, ...);
37
38void __vdie(const char *fmt, ...);
39void __vwarning(const char *fmt, ...);
40void __vpr_stat(const char *fmt, ...);
41
42#define min(x, y) ({ \
43 typeof(x) _min1 = (x); \
44 typeof(y) _min2 = (y); \
45 (void) (&_min1 == &_min2); \
46 _min1 < _min2 ? _min1 : _min2; })
47
48static inline char *strim(char *string)
49{
50 char *ret;
51
52 if (!string)
53 return NULL;
54 while (*string) {
55 if (!isspace(*string))
56 break;
57 string++;
58 }
59 ret = string;
60
61 string = ret + strlen(ret) - 1;
62 while (string > ret) {
63 if (!isspace(*string))
64 break;
65 string--;
66 }
67 string[1] = 0;
68
69 return ret;
70}
71
72static inline int has_text(const char *text)
73{
74 if (!text)
75 return 0;
76
77 while (*text) {
78 if (!isspace(*text))
79 return 1;
80 text++;
81 }
82
83 return 0;
84}
85
86#endif
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
deleted file mode 100644
index 5ea4326ad11..00000000000
--- a/tools/lib/traceevent/parse-filter.c
+++ /dev/null
@@ -1,2304 +0,0 @@
1/*
2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <errno.h>
26#include <sys/types.h>
27
28#include "event-parse.h"
29#include "event-utils.h"
30
31#define COMM "COMM"
32
33static struct format_field comm = {
34 .name = "COMM",
35};
36
37struct event_list {
38 struct event_list *next;
39 struct event_format *event;
40};
41
42#define MAX_ERR_STR_SIZE 256
43
44static void show_error(char **error_str, const char *fmt, ...)
45{
46 unsigned long long index;
47 const char *input;
48 char *error;
49 va_list ap;
50 int len;
51 int i;
52
53 if (!error_str)
54 return;
55
56 input = pevent_get_input_buf();
57 index = pevent_get_input_buf_ptr();
58 len = input ? strlen(input) : 0;
59
60 error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
61
62 if (len) {
63 strcpy(error, input);
64 error[len] = '\n';
65 for (i = 1; i < len && i < index; i++)
66 error[len+i] = ' ';
67 error[len + i] = '^';
68 error[len + i + 1] = '\n';
69 len += i+2;
70 }
71
72 va_start(ap, fmt);
73 vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);
74 va_end(ap);
75
76 *error_str = error;
77}
78
79static void free_token(char *token)
80{
81 pevent_free_token(token);
82}
83
84static enum event_type read_token(char **tok)
85{
86 enum event_type type;
87 char *token = NULL;
88
89 do {
90 free_token(token);
91 type = pevent_read_token(&token);
92 } while (type == EVENT_NEWLINE || type == EVENT_SPACE);
93
94 /* If token is = or ! check to see if the next char is ~ */
95 if (token &&
96 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
97 pevent_peek_char() == '~') {
98 /* append it */
99 *tok = malloc_or_die(3);
100 sprintf(*tok, "%c%c", *token, '~');
101 free_token(token);
102 /* Now remove the '~' from the buffer */
103 pevent_read_token(&token);
104 free_token(token);
105 } else
106 *tok = token;
107
108 return type;
109}
110
111static int filter_cmp(const void *a, const void *b)
112{
113 const struct filter_type *ea = a;
114 const struct filter_type *eb = b;
115
116 if (ea->event_id < eb->event_id)
117 return -1;
118
119 if (ea->event_id > eb->event_id)
120 return 1;
121
122 return 0;
123}
124
125static struct filter_type *
126find_filter_type(struct event_filter *filter, int id)
127{
128 struct filter_type *filter_type;
129 struct filter_type key;
130
131 key.event_id = id;
132
133 filter_type = bsearch(&key, filter->event_filters,
134 filter->filters,
135 sizeof(*filter->event_filters),
136 filter_cmp);
137
138 return filter_type;
139}
140
141static struct filter_type *
142add_filter_type(struct event_filter *filter, int id)
143{
144 struct filter_type *filter_type;
145 int i;
146
147 filter_type = find_filter_type(filter, id);
148 if (filter_type)
149 return filter_type;
150
151 filter->event_filters = realloc(filter->event_filters,
152 sizeof(*filter->event_filters) *
153 (filter->filters + 1));
154 if (!filter->event_filters)
155 die("Could not allocate filter");
156
157 for (i = 0; i < filter->filters; i++) {
158 if (filter->event_filters[i].event_id > id)
159 break;
160 }
161
162 if (i < filter->filters)
163 memmove(&filter->event_filters[i+1],
164 &filter->event_filters[i],
165 sizeof(*filter->event_filters) *
166 (filter->filters - i));
167
168 filter_type = &filter->event_filters[i];
169 filter_type->event_id = id;
170 filter_type->event = pevent_find_event(filter->pevent, id);
171 filter_type->filter = NULL;
172
173 filter->filters++;
174
175 return filter_type;
176}
177
178/**
179 * pevent_filter_alloc - create a new event filter
180 * @pevent: The pevent that this filter is associated with
181 */
182struct event_filter *pevent_filter_alloc(struct pevent *pevent)
183{
184 struct event_filter *filter;
185
186 filter = malloc_or_die(sizeof(*filter));
187 memset(filter, 0, sizeof(*filter));
188 filter->pevent = pevent;
189 pevent_ref(pevent);
190
191 return filter;
192}
193
194static struct filter_arg *allocate_arg(void)
195{
196 struct filter_arg *arg;
197
198 arg = malloc_or_die(sizeof(*arg));
199 memset(arg, 0, sizeof(*arg));
200
201 return arg;
202}
203
204static void free_arg(struct filter_arg *arg)
205{
206 if (!arg)
207 return;
208
209 switch (arg->type) {
210 case FILTER_ARG_NONE:
211 case FILTER_ARG_BOOLEAN:
212 break;
213
214 case FILTER_ARG_NUM:
215 free_arg(arg->num.left);
216 free_arg(arg->num.right);
217 break;
218
219 case FILTER_ARG_EXP:
220 free_arg(arg->exp.left);
221 free_arg(arg->exp.right);
222 break;
223
224 case FILTER_ARG_STR:
225 free(arg->str.val);
226 regfree(&arg->str.reg);
227 free(arg->str.buffer);
228 break;
229
230 case FILTER_ARG_VALUE:
231 if (arg->value.type == FILTER_STRING ||
232 arg->value.type == FILTER_CHAR)
233 free(arg->value.str);
234 break;
235
236 case FILTER_ARG_OP:
237 free_arg(arg->op.left);
238 free_arg(arg->op.right);
239 default:
240 break;
241 }
242
243 free(arg);
244}
245
246static void add_event(struct event_list **events,
247 struct event_format *event)
248{
249 struct event_list *list;
250
251 list = malloc_or_die(sizeof(*list));
252 list->next = *events;
253 *events = list;
254 list->event = event;
255}
256
257static int event_match(struct event_format *event,
258 regex_t *sreg, regex_t *ereg)
259{
260 if (sreg) {
261 return !regexec(sreg, event->system, 0, NULL, 0) &&
262 !regexec(ereg, event->name, 0, NULL, 0);
263 }
264
265 return !regexec(ereg, event->system, 0, NULL, 0) ||
266 !regexec(ereg, event->name, 0, NULL, 0);
267}
268
269static int
270find_event(struct pevent *pevent, struct event_list **events,
271 char *sys_name, char *event_name)
272{
273 struct event_format *event;
274 regex_t ereg;
275 regex_t sreg;
276 int match = 0;
277 char *reg;
278 int ret;
279 int i;
280
281 if (!event_name) {
282 /* if no name is given, then swap sys and name */
283 event_name = sys_name;
284 sys_name = NULL;
285 }
286
287 reg = malloc_or_die(strlen(event_name) + 3);
288 sprintf(reg, "^%s$", event_name);
289
290 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
291 free(reg);
292
293 if (ret)
294 return -1;
295
296 if (sys_name) {
297 reg = malloc_or_die(strlen(sys_name) + 3);
298 sprintf(reg, "^%s$", sys_name);
299 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
300 free(reg);
301 if (ret) {
302 regfree(&ereg);
303 return -1;
304 }
305 }
306
307 for (i = 0; i < pevent->nr_events; i++) {
308 event = pevent->events[i];
309 if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
310 match = 1;
311 add_event(events, event);
312 }
313 }
314
315 regfree(&ereg);
316 if (sys_name)
317 regfree(&sreg);
318
319 if (!match)
320 return -1;
321
322 return 0;
323}
324
325static void free_events(struct event_list *events)
326{
327 struct event_list *event;
328
329 while (events) {
330 event = events;
331 events = events->next;
332 free(event);
333 }
334}
335
336static struct filter_arg *
337create_arg_item(struct event_format *event, const char *token,
338 enum event_type type, char **error_str)
339{
340 struct format_field *field;
341 struct filter_arg *arg;
342
343 arg = allocate_arg();
344
345 switch (type) {
346
347 case EVENT_SQUOTE:
348 case EVENT_DQUOTE:
349 arg->type = FILTER_ARG_VALUE;
350 arg->value.type =
351 type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
352 arg->value.str = strdup(token);
353 if (!arg->value.str)
354 die("malloc string");
355 break;
356 case EVENT_ITEM:
357 /* if it is a number, then convert it */
358 if (isdigit(token[0])) {
359 arg->type = FILTER_ARG_VALUE;
360 arg->value.type = FILTER_NUMBER;
361 arg->value.val = strtoull(token, NULL, 0);
362 break;
363 }
364 /* Consider this a field */
365 field = pevent_find_any_field(event, token);
366 if (!field) {
367 if (strcmp(token, COMM) != 0) {
368 /* not a field, Make it false */
369 arg->type = FILTER_ARG_BOOLEAN;
370 arg->boolean.value = FILTER_FALSE;
371 break;
372 }
373 /* If token is 'COMM' then it is special */
374 field = &comm;
375 }
376 arg->type = FILTER_ARG_FIELD;
377 arg->field.field = field;
378 break;
379 default:
380 free_arg(arg);
381 show_error(error_str, "expected a value but found %s",
382 token);
383 return NULL;
384 }
385 return arg;
386}
387
388static struct filter_arg *
389create_arg_op(enum filter_op_type btype)
390{
391 struct filter_arg *arg;
392
393 arg = allocate_arg();
394 arg->type = FILTER_ARG_OP;
395 arg->op.type = btype;
396
397 return arg;
398}
399
400static struct filter_arg *
401create_arg_exp(enum filter_exp_type etype)
402{
403 struct filter_arg *arg;
404
405 arg = allocate_arg();
406 arg->type = FILTER_ARG_EXP;
407 arg->op.type = etype;
408
409 return arg;
410}
411
412static struct filter_arg *
413create_arg_cmp(enum filter_exp_type etype)
414{
415 struct filter_arg *arg;
416
417 arg = allocate_arg();
418 /* Use NUM and change if necessary */
419 arg->type = FILTER_ARG_NUM;
420 arg->op.type = etype;
421
422 return arg;
423}
424
425static int add_right(struct filter_arg *op, struct filter_arg *arg,
426 char **error_str)
427{
428 struct filter_arg *left;
429 char *str;
430 int op_type;
431 int ret;
432
433 switch (op->type) {
434 case FILTER_ARG_EXP:
435 if (op->exp.right)
436 goto out_fail;
437 op->exp.right = arg;
438 break;
439
440 case FILTER_ARG_OP:
441 if (op->op.right)
442 goto out_fail;
443 op->op.right = arg;
444 break;
445
446 case FILTER_ARG_NUM:
447 if (op->op.right)
448 goto out_fail;
449 /*
450 * The arg must be num, str, or field
451 */
452 switch (arg->type) {
453 case FILTER_ARG_VALUE:
454 case FILTER_ARG_FIELD:
455 break;
456 default:
457 show_error(error_str,
458 "Illegal rvalue");
459 return -1;
460 }
461
462 /*
463 * Depending on the type, we may need to
464 * convert this to a string or regex.
465 */
466 switch (arg->value.type) {
467 case FILTER_CHAR:
468 /*
469 * A char should be converted to number if
470 * the string is 1 byte, and the compare
471 * is not a REGEX.
472 */
473 if (strlen(arg->value.str) == 1 &&
474 op->num.type != FILTER_CMP_REGEX &&
475 op->num.type != FILTER_CMP_NOT_REGEX) {
476 arg->value.type = FILTER_NUMBER;
477 goto do_int;
478 }
479 /* fall through */
480 case FILTER_STRING:
481
482 /* convert op to a string arg */
483 op_type = op->num.type;
484 left = op->num.left;
485 str = arg->value.str;
486
487 /* reset the op for the new field */
488 memset(op, 0, sizeof(*op));
489
490 /*
491 * If left arg was a field not found then
492 * NULL the entire op.
493 */
494 if (left->type == FILTER_ARG_BOOLEAN) {
495 free_arg(left);
496 free_arg(arg);
497 op->type = FILTER_ARG_BOOLEAN;
498 op->boolean.value = FILTER_FALSE;
499 break;
500 }
501
502 /* Left arg must be a field */
503 if (left->type != FILTER_ARG_FIELD) {
504 show_error(error_str,
505 "Illegal lvalue for string comparison");
506 return -1;
507 }
508
509 /* Make sure this is a valid string compare */
510 switch (op_type) {
511 case FILTER_CMP_EQ:
512 op_type = FILTER_CMP_MATCH;
513 break;
514 case FILTER_CMP_NE:
515 op_type = FILTER_CMP_NOT_MATCH;
516 break;
517
518 case FILTER_CMP_REGEX:
519 case FILTER_CMP_NOT_REGEX:
520 ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
521 if (ret) {
522 show_error(error_str,
523 "RegEx '%s' did not compute",
524 str);
525 return -1;
526 }
527 break;
528 default:
529 show_error(error_str,
530 "Illegal comparison for string");
531 return -1;
532 }
533
534 op->type = FILTER_ARG_STR;
535 op->str.type = op_type;
536 op->str.field = left->field.field;
537 op->str.val = strdup(str);
538 if (!op->str.val)
539 die("malloc string");
540 /*
541 * Need a buffer to copy data for tests
542 */
543 op->str.buffer = malloc_or_die(op->str.field->size + 1);
544 /* Null terminate this buffer */
545 op->str.buffer[op->str.field->size] = 0;
546
547 /* We no longer have left or right args */
548 free_arg(arg);
549 free_arg(left);
550
551 break;
552
553 case FILTER_NUMBER:
554
555 do_int:
556 switch (op->num.type) {
557 case FILTER_CMP_REGEX:
558 case FILTER_CMP_NOT_REGEX:
559 show_error(error_str,
560 "Op not allowed with integers");
561 return -1;
562
563 default:
564 break;
565 }
566
567 /* numeric compare */
568 op->num.right = arg;
569 break;
570 default:
571 goto out_fail;
572 }
573 break;
574 default:
575 goto out_fail;
576 }
577
578 return 0;
579
580 out_fail:
581 show_error(error_str,
582 "Syntax error");
583 return -1;
584}
585
586static struct filter_arg *
587rotate_op_right(struct filter_arg *a, struct filter_arg *b)
588{
589 struct filter_arg *arg;
590
591 arg = a->op.right;
592 a->op.right = b;
593 return arg;
594}
595
596static int add_left(struct filter_arg *op, struct filter_arg *arg)
597{
598 switch (op->type) {
599 case FILTER_ARG_EXP:
600 if (arg->type == FILTER_ARG_OP)
601 arg = rotate_op_right(arg, op);
602 op->exp.left = arg;
603 break;
604
605 case FILTER_ARG_OP:
606 op->op.left = arg;
607 break;
608 case FILTER_ARG_NUM:
609 if (arg->type == FILTER_ARG_OP)
610 arg = rotate_op_right(arg, op);
611
612 /* left arg of compares must be a field */
613 if (arg->type != FILTER_ARG_FIELD &&
614 arg->type != FILTER_ARG_BOOLEAN)
615 return -1;
616 op->num.left = arg;
617 break;
618 default:
619 return -1;
620 }
621 return 0;
622}
623
624enum op_type {
625 OP_NONE,
626 OP_BOOL,
627 OP_NOT,
628 OP_EXP,
629 OP_CMP,
630};
631
632static enum op_type process_op(const char *token,
633 enum filter_op_type *btype,
634 enum filter_cmp_type *ctype,
635 enum filter_exp_type *etype)
636{
637 *btype = FILTER_OP_NOT;
638 *etype = FILTER_EXP_NONE;
639 *ctype = FILTER_CMP_NONE;
640
641 if (strcmp(token, "&&") == 0)
642 *btype = FILTER_OP_AND;
643 else if (strcmp(token, "||") == 0)
644 *btype = FILTER_OP_OR;
645 else if (strcmp(token, "!") == 0)
646 return OP_NOT;
647
648 if (*btype != FILTER_OP_NOT)
649 return OP_BOOL;
650
651 /* Check for value expressions */
652 if (strcmp(token, "+") == 0) {
653 *etype = FILTER_EXP_ADD;
654 } else if (strcmp(token, "-") == 0) {
655 *etype = FILTER_EXP_SUB;
656 } else if (strcmp(token, "*") == 0) {
657 *etype = FILTER_EXP_MUL;
658 } else if (strcmp(token, "/") == 0) {
659 *etype = FILTER_EXP_DIV;
660 } else if (strcmp(token, "%") == 0) {
661 *etype = FILTER_EXP_MOD;
662 } else if (strcmp(token, ">>") == 0) {
663 *etype = FILTER_EXP_RSHIFT;
664 } else if (strcmp(token, "<<") == 0) {
665 *etype = FILTER_EXP_LSHIFT;
666 } else if (strcmp(token, "&") == 0) {
667 *etype = FILTER_EXP_AND;
668 } else if (strcmp(token, "|") == 0) {
669 *etype = FILTER_EXP_OR;
670 } else if (strcmp(token, "^") == 0) {
671 *etype = FILTER_EXP_XOR;
672 } else if (strcmp(token, "~") == 0)
673 *etype = FILTER_EXP_NOT;
674
675 if (*etype != FILTER_EXP_NONE)
676 return OP_EXP;
677
678 /* Check for compares */
679 if (strcmp(token, "==") == 0)
680 *ctype = FILTER_CMP_EQ;
681 else if (strcmp(token, "!=") == 0)
682 *ctype = FILTER_CMP_NE;
683 else if (strcmp(token, "<") == 0)
684 *ctype = FILTER_CMP_LT;
685 else if (strcmp(token, ">") == 0)
686 *ctype = FILTER_CMP_GT;
687 else if (strcmp(token, "<=") == 0)
688 *ctype = FILTER_CMP_LE;
689 else if (strcmp(token, ">=") == 0)
690 *ctype = FILTER_CMP_GE;
691 else if (strcmp(token, "=~") == 0)
692 *ctype = FILTER_CMP_REGEX;
693 else if (strcmp(token, "!~") == 0)
694 *ctype = FILTER_CMP_NOT_REGEX;
695 else
696 return OP_NONE;
697
698 return OP_CMP;
699}
700
701static int check_op_done(struct filter_arg *arg)
702{
703 switch (arg->type) {
704 case FILTER_ARG_EXP:
705 return arg->exp.right != NULL;
706
707 case FILTER_ARG_OP:
708 return arg->op.right != NULL;
709
710 case FILTER_ARG_NUM:
711 return arg->num.right != NULL;
712
713 case FILTER_ARG_STR:
714 /* A string conversion is always done */
715 return 1;
716
717 case FILTER_ARG_BOOLEAN:
718 /* field not found, is ok */
719 return 1;
720
721 default:
722 return 0;
723 }
724}
725
726enum filter_vals {
727 FILTER_VAL_NORM,
728 FILTER_VAL_FALSE,
729 FILTER_VAL_TRUE,
730};
731
732void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
733 struct filter_arg *arg)
734{
735 struct filter_arg *other_child;
736 struct filter_arg **ptr;
737
738 if (parent->type != FILTER_ARG_OP &&
739 arg->type != FILTER_ARG_OP)
740 die("can not reparent other than OP");
741
742 /* Get the sibling */
743 if (old_child->op.right == arg) {
744 ptr = &old_child->op.right;
745 other_child = old_child->op.left;
746 } else if (old_child->op.left == arg) {
747 ptr = &old_child->op.left;
748 other_child = old_child->op.right;
749 } else
750 die("Error in reparent op, find other child");
751
752 /* Detach arg from old_child */
753 *ptr = NULL;
754
755 /* Check for root */
756 if (parent == old_child) {
757 free_arg(other_child);
758 *parent = *arg;
759 /* Free arg without recussion */
760 free(arg);
761 return;
762 }
763
764 if (parent->op.right == old_child)
765 ptr = &parent->op.right;
766 else if (parent->op.left == old_child)
767 ptr = &parent->op.left;
768 else
769 die("Error in reparent op");
770 *ptr = arg;
771
772 free_arg(old_child);
773}
774
775enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
776{
777 enum filter_vals lval, rval;
778
779 switch (arg->type) {
780
781 /* bad case */
782 case FILTER_ARG_BOOLEAN:
783 return FILTER_VAL_FALSE + arg->boolean.value;
784
785 /* good cases: */
786 case FILTER_ARG_STR:
787 case FILTER_ARG_VALUE:
788 case FILTER_ARG_FIELD:
789 return FILTER_VAL_NORM;
790
791 case FILTER_ARG_EXP:
792 lval = test_arg(arg, arg->exp.left);
793 if (lval != FILTER_VAL_NORM)
794 return lval;
795 rval = test_arg(arg, arg->exp.right);
796 if (rval != FILTER_VAL_NORM)
797 return rval;
798 return FILTER_VAL_NORM;
799
800 case FILTER_ARG_NUM:
801 lval = test_arg(arg, arg->num.left);
802 if (lval != FILTER_VAL_NORM)
803 return lval;
804 rval = test_arg(arg, arg->num.right);
805 if (rval != FILTER_VAL_NORM)
806 return rval;
807 return FILTER_VAL_NORM;
808
809 case FILTER_ARG_OP:
810 if (arg->op.type != FILTER_OP_NOT) {
811 lval = test_arg(arg, arg->op.left);
812 switch (lval) {
813 case FILTER_VAL_NORM:
814 break;
815 case FILTER_VAL_TRUE:
816 if (arg->op.type == FILTER_OP_OR)
817 return FILTER_VAL_TRUE;
818 rval = test_arg(arg, arg->op.right);
819 if (rval != FILTER_VAL_NORM)
820 return rval;
821
822 reparent_op_arg(parent, arg, arg->op.right);
823 return FILTER_VAL_NORM;
824
825 case FILTER_VAL_FALSE:
826 if (arg->op.type == FILTER_OP_AND)
827 return FILTER_VAL_FALSE;
828 rval = test_arg(arg, arg->op.right);
829 if (rval != FILTER_VAL_NORM)
830 return rval;
831
832 reparent_op_arg(parent, arg, arg->op.right);
833 return FILTER_VAL_NORM;
834 }
835 }
836
837 rval = test_arg(arg, arg->op.right);
838 switch (rval) {
839 case FILTER_VAL_NORM:
840 break;
841 case FILTER_VAL_TRUE:
842 if (arg->op.type == FILTER_OP_OR)
843 return FILTER_VAL_TRUE;
844 if (arg->op.type == FILTER_OP_NOT)
845 return FILTER_VAL_FALSE;
846
847 reparent_op_arg(parent, arg, arg->op.left);
848 return FILTER_VAL_NORM;
849
850 case FILTER_VAL_FALSE:
851 if (arg->op.type == FILTER_OP_AND)
852 return FILTER_VAL_FALSE;
853 if (arg->op.type == FILTER_OP_NOT)
854 return FILTER_VAL_TRUE;
855
856 reparent_op_arg(parent, arg, arg->op.left);
857 return FILTER_VAL_NORM;
858 }
859
860 return FILTER_VAL_NORM;
861 default:
862 die("bad arg in filter tree");
863 }
864 return FILTER_VAL_NORM;
865}
866
867/* Remove any unknown event fields */
868static struct filter_arg *collapse_tree(struct filter_arg *arg)
869{
870 enum filter_vals ret;
871
872 ret = test_arg(arg, arg);
873 switch (ret) {
874 case FILTER_VAL_NORM:
875 return arg;
876
877 case FILTER_VAL_TRUE:
878 case FILTER_VAL_FALSE:
879 free_arg(arg);
880 arg = allocate_arg();
881 arg->type = FILTER_ARG_BOOLEAN;
882 arg->boolean.value = ret == FILTER_VAL_TRUE;
883 }
884
885 return arg;
886}
887
888static int
889process_filter(struct event_format *event, struct filter_arg **parg,
890 char **error_str, int not)
891{
892 enum event_type type;
893 char *token = NULL;
894 struct filter_arg *current_op = NULL;
895 struct filter_arg *current_exp = NULL;
896 struct filter_arg *left_item = NULL;
897 struct filter_arg *arg = NULL;
898 enum op_type op_type;
899 enum filter_op_type btype;
900 enum filter_exp_type etype;
901 enum filter_cmp_type ctype;
902 int ret;
903
904 *parg = NULL;
905
906 do {
907 free(token);
908 type = read_token(&token);
909 switch (type) {
910 case EVENT_SQUOTE:
911 case EVENT_DQUOTE:
912 case EVENT_ITEM:
913 arg = create_arg_item(event, token, type, error_str);
914 if (!arg)
915 goto fail;
916 if (!left_item)
917 left_item = arg;
918 else if (current_exp) {
919 ret = add_right(current_exp, arg, error_str);
920 if (ret < 0)
921 goto fail;
922 left_item = NULL;
923 /* Not's only one one expression */
924 if (not) {
925 arg = NULL;
926 if (current_op)
927 goto fail_print;
928 free(token);
929 *parg = current_exp;
930 return 0;
931 }
932 } else
933 goto fail_print;
934 arg = NULL;
935 break;
936
937 case EVENT_DELIM:
938 if (*token == ',') {
939 show_error(error_str,
940 "Illegal token ','");
941 goto fail;
942 }
943
944 if (*token == '(') {
945 if (left_item) {
946 show_error(error_str,
947 "Open paren can not come after item");
948 goto fail;
949 }
950 if (current_exp) {
951 show_error(error_str,
952 "Open paren can not come after expression");
953 goto fail;
954 }
955
956 ret = process_filter(event, &arg, error_str, 0);
957 if (ret != 1) {
958 if (ret == 0)
959 show_error(error_str,
960 "Unbalanced number of '('");
961 goto fail;
962 }
963 ret = 0;
964
965 /* A not wants just one expression */
966 if (not) {
967 if (current_op)
968 goto fail_print;
969 *parg = arg;
970 return 0;
971 }
972
973 if (current_op)
974 ret = add_right(current_op, arg, error_str);
975 else
976 current_exp = arg;
977
978 if (ret < 0)
979 goto fail;
980
981 } else { /* ')' */
982 if (!current_op && !current_exp)
983 goto fail_print;
984
985 /* Make sure everything is finished at this level */
986 if (current_exp && !check_op_done(current_exp))
987 goto fail_print;
988 if (current_op && !check_op_done(current_op))
989 goto fail_print;
990
991 if (current_op)
992 *parg = current_op;
993 else
994 *parg = current_exp;
995 return 1;
996 }
997 break;
998
999 case EVENT_OP:
1000 op_type = process_op(token, &btype, &ctype, &etype);
1001
1002 /* All expect a left arg except for NOT */
1003 switch (op_type) {
1004 case OP_BOOL:
1005 /* Logic ops need a left expression */
1006 if (!current_exp && !current_op)
1007 goto fail_print;
1008 /* fall through */
1009 case OP_NOT:
1010 /* logic only processes ops and exp */
1011 if (left_item)
1012 goto fail_print;
1013 break;
1014 case OP_EXP:
1015 case OP_CMP:
1016 if (!left_item)
1017 goto fail_print;
1018 break;
1019 case OP_NONE:
1020 show_error(error_str,
1021 "Unknown op token %s", token);
1022 goto fail;
1023 }
1024
1025 ret = 0;
1026 switch (op_type) {
1027 case OP_BOOL:
1028 arg = create_arg_op(btype);
1029 if (current_op)
1030 ret = add_left(arg, current_op);
1031 else
1032 ret = add_left(arg, current_exp);
1033 current_op = arg;
1034 current_exp = NULL;
1035 break;
1036
1037 case OP_NOT:
1038 arg = create_arg_op(btype);
1039 if (current_op)
1040 ret = add_right(current_op, arg, error_str);
1041 if (ret < 0)
1042 goto fail;
1043 current_exp = arg;
1044 ret = process_filter(event, &arg, error_str, 1);
1045 if (ret < 0)
1046 goto fail;
1047 ret = add_right(current_exp, arg, error_str);
1048 if (ret < 0)
1049 goto fail;
1050 break;
1051
1052 case OP_EXP:
1053 case OP_CMP:
1054 if (op_type == OP_EXP)
1055 arg = create_arg_exp(etype);
1056 else
1057 arg = create_arg_cmp(ctype);
1058
1059 if (current_op)
1060 ret = add_right(current_op, arg, error_str);
1061 if (ret < 0)
1062 goto fail;
1063 ret = add_left(arg, left_item);
1064 if (ret < 0) {
1065 arg = NULL;
1066 goto fail_print;
1067 }
1068 current_exp = arg;
1069 break;
1070 default:
1071 break;
1072 }
1073 arg = NULL;
1074 if (ret < 0)
1075 goto fail_print;
1076 break;
1077 case EVENT_NONE:
1078 break;
1079 default:
1080 goto fail_print;
1081 }
1082 } while (type != EVENT_NONE);
1083
1084 if (!current_op && !current_exp)
1085 goto fail_print;
1086
1087 if (!current_op)
1088 current_op = current_exp;
1089
1090 current_op = collapse_tree(current_op);
1091
1092 *parg = current_op;
1093
1094 return 0;
1095
1096 fail_print:
1097 show_error(error_str, "Syntax error");
1098 fail:
1099 free_arg(current_op);
1100 free_arg(current_exp);
1101 free_arg(arg);
1102 free(token);
1103 return -1;
1104}
1105
1106static int
1107process_event(struct event_format *event, const char *filter_str,
1108 struct filter_arg **parg, char **error_str)
1109{
1110 int ret;
1111
1112 pevent_buffer_init(filter_str, strlen(filter_str));
1113
1114 ret = process_filter(event, parg, error_str, 0);
1115 if (ret == 1) {
1116 show_error(error_str,
1117 "Unbalanced number of ')'");
1118 return -1;
1119 }
1120 if (ret < 0)
1121 return ret;
1122
1123 /* If parg is NULL, then make it into FALSE */
1124 if (!*parg) {
1125 *parg = allocate_arg();
1126 (*parg)->type = FILTER_ARG_BOOLEAN;
1127 (*parg)->boolean.value = FILTER_FALSE;
1128 }
1129
1130 return 0;
1131}
1132
1133static int filter_event(struct event_filter *filter,
1134 struct event_format *event,
1135 const char *filter_str, char **error_str)
1136{
1137 struct filter_type *filter_type;
1138 struct filter_arg *arg;
1139 int ret;
1140
1141 if (filter_str) {
1142 ret = process_event(event, filter_str, &arg, error_str);
1143 if (ret < 0)
1144 return ret;
1145
1146 } else {
1147 /* just add a TRUE arg */
1148 arg = allocate_arg();
1149 arg->type = FILTER_ARG_BOOLEAN;
1150 arg->boolean.value = FILTER_TRUE;
1151 }
1152
1153 filter_type = add_filter_type(filter, event->id);
1154 if (filter_type->filter)
1155 free_arg(filter_type->filter);
1156 filter_type->filter = arg;
1157
1158 return 0;
1159}
1160
1161/**
1162 * pevent_filter_add_filter_str - add a new filter
1163 * @filter: the event filter to add to
1164 * @filter_str: the filter string that contains the filter
1165 * @error_str: string containing reason for failed filter
1166 *
1167 * Returns 0 if the filter was successfully added
1168 * -1 if there was an error.
1169 *
1170 * On error, if @error_str points to a string pointer,
1171 * it is set to the reason that the filter failed.
1172 * This string must be freed with "free".
1173 */
1174int pevent_filter_add_filter_str(struct event_filter *filter,
1175 const char *filter_str,
1176 char **error_str)
1177{
1178 struct pevent *pevent = filter->pevent;
1179 struct event_list *event;
1180 struct event_list *events = NULL;
1181 const char *filter_start;
1182 const char *next_event;
1183 char *this_event;
1184 char *event_name = NULL;
1185 char *sys_name = NULL;
1186 char *sp;
1187 int rtn = 0;
1188 int len;
1189 int ret;
1190
1191 /* clear buffer to reset show error */
1192 pevent_buffer_init("", 0);
1193
1194 if (error_str)
1195 *error_str = NULL;
1196
1197 filter_start = strchr(filter_str, ':');
1198 if (filter_start)
1199 len = filter_start - filter_str;
1200 else
1201 len = strlen(filter_str);
1202
1203
1204 do {
1205 next_event = strchr(filter_str, ',');
1206 if (next_event &&
1207 (!filter_start || next_event < filter_start))
1208 len = next_event - filter_str;
1209 else if (filter_start)
1210 len = filter_start - filter_str;
1211 else
1212 len = strlen(filter_str);
1213
1214 this_event = malloc_or_die(len + 1);
1215 memcpy(this_event, filter_str, len);
1216 this_event[len] = 0;
1217
1218 if (next_event)
1219 next_event++;
1220
1221 filter_str = next_event;
1222
1223 sys_name = strtok_r(this_event, "/", &sp);
1224 event_name = strtok_r(NULL, "/", &sp);
1225
1226 if (!sys_name) {
1227 show_error(error_str, "No filter found");
1228 /* This can only happen when events is NULL, but still */
1229 free_events(events);
1230 free(this_event);
1231 return -1;
1232 }
1233
1234 /* Find this event */
1235 ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
1236 if (ret < 0) {
1237 if (event_name)
1238 show_error(error_str,
1239 "No event found under '%s.%s'",
1240 sys_name, event_name);
1241 else
1242 show_error(error_str,
1243 "No event found under '%s'",
1244 sys_name);
1245 free_events(events);
1246 free(this_event);
1247 return -1;
1248 }
1249 free(this_event);
1250 } while (filter_str);
1251
1252 /* Skip the ':' */
1253 if (filter_start)
1254 filter_start++;
1255
1256 /* filter starts here */
1257 for (event = events; event; event = event->next) {
1258 ret = filter_event(filter, event->event, filter_start,
1259 error_str);
1260 /* Failures are returned if a parse error happened */
1261 if (ret < 0)
1262 rtn = ret;
1263
1264 if (ret >= 0 && pevent->test_filters) {
1265 char *test;
1266 test = pevent_filter_make_string(filter, event->event->id);
1267 printf(" '%s: %s'\n", event->event->name, test);
1268 free(test);
1269 }
1270 }
1271
1272 free_events(events);
1273
1274 if (rtn >= 0 && pevent->test_filters)
1275 exit(0);
1276
1277 return rtn;
1278}
1279
1280static void free_filter_type(struct filter_type *filter_type)
1281{
1282 free_arg(filter_type->filter);
1283}
1284
1285/**
1286 * pevent_filter_remove_event - remove a filter for an event
1287 * @filter: the event filter to remove from
1288 * @event_id: the event to remove a filter for
1289 *
1290 * Removes the filter saved for an event defined by @event_id
1291 * from the @filter.
1292 *
1293 * Returns 1: if an event was removed
1294 * 0: if the event was not found
1295 */
1296int pevent_filter_remove_event(struct event_filter *filter,
1297 int event_id)
1298{
1299 struct filter_type *filter_type;
1300 unsigned long len;
1301
1302 if (!filter->filters)
1303 return 0;
1304
1305 filter_type = find_filter_type(filter, event_id);
1306
1307 if (!filter_type)
1308 return 0;
1309
1310 free_filter_type(filter_type);
1311
1312 /* The filter_type points into the event_filters array */
1313 len = (unsigned long)(filter->event_filters + filter->filters) -
1314 (unsigned long)(filter_type + 1);
1315
1316 memmove(filter_type, filter_type + 1, len);
1317 filter->filters--;
1318
1319 memset(&filter->event_filters[filter->filters], 0,
1320 sizeof(*filter_type));
1321
1322 return 1;
1323}
1324
1325/**
1326 * pevent_filter_reset - clear all filters in a filter
1327 * @filter: the event filter to reset
1328 *
1329 * Removes all filters from a filter and resets it.
1330 */
1331void pevent_filter_reset(struct event_filter *filter)
1332{
1333 int i;
1334
1335 for (i = 0; i < filter->filters; i++)
1336 free_filter_type(&filter->event_filters[i]);
1337
1338 free(filter->event_filters);
1339 filter->filters = 0;
1340 filter->event_filters = NULL;
1341}
1342
1343void pevent_filter_free(struct event_filter *filter)
1344{
1345 pevent_unref(filter->pevent);
1346
1347 pevent_filter_reset(filter);
1348
1349 free(filter);
1350}
1351
1352static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg);
1353
1354static int copy_filter_type(struct event_filter *filter,
1355 struct event_filter *source,
1356 struct filter_type *filter_type)
1357{
1358 struct filter_arg *arg;
1359 struct event_format *event;
1360 const char *sys;
1361 const char *name;
1362 char *str;
1363
1364 /* Can't assume that the pevent's are the same */
1365 sys = filter_type->event->system;
1366 name = filter_type->event->name;
1367 event = pevent_find_event_by_name(filter->pevent, sys, name);
1368 if (!event)
1369 return -1;
1370
1371 str = arg_to_str(source, filter_type->filter);
1372 if (!str)
1373 return -1;
1374
1375 if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
1376 /* Add trivial event */
1377 arg = allocate_arg();
1378 arg->type = FILTER_ARG_BOOLEAN;
1379 if (strcmp(str, "TRUE") == 0)
1380 arg->boolean.value = 1;
1381 else
1382 arg->boolean.value = 0;
1383
1384 filter_type = add_filter_type(filter, event->id);
1385 filter_type->filter = arg;
1386
1387 free(str);
1388 return 0;
1389 }
1390
1391 filter_event(filter, event, str, NULL);
1392 free(str);
1393
1394 return 0;
1395}
1396
1397/**
1398 * pevent_filter_copy - copy a filter using another filter
1399 * @dest - the filter to copy to
1400 * @source - the filter to copy from
1401 *
1402 * Returns 0 on success and -1 if not all filters were copied
1403 */
1404int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
1405{
1406 int ret = 0;
1407 int i;
1408
1409 pevent_filter_reset(dest);
1410
1411 for (i = 0; i < source->filters; i++) {
1412 if (copy_filter_type(dest, source, &source->event_filters[i]))
1413 ret = -1;
1414 }
1415 return ret;
1416}
1417
1418
1419/**
1420 * pevent_update_trivial - update the trivial filters with the given filter
1421 * @dest - the filter to update
1422 * @source - the filter as the source of the update
1423 * @type - the type of trivial filter to update.
1424 *
1425 * Scan dest for trivial events matching @type to replace with the source.
1426 *
1427 * Returns 0 on success and -1 if there was a problem updating, but
1428 * events may have still been updated on error.
1429 */
1430int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
1431 enum filter_trivial_type type)
1432{
1433 struct pevent *src_pevent;
1434 struct pevent *dest_pevent;
1435 struct event_format *event;
1436 struct filter_type *filter_type;
1437 struct filter_arg *arg;
1438 char *str;
1439 int i;
1440
1441 src_pevent = source->pevent;
1442 dest_pevent = dest->pevent;
1443
1444 /* Do nothing if either of the filters has nothing to filter */
1445 if (!dest->filters || !source->filters)
1446 return 0;
1447
1448 for (i = 0; i < dest->filters; i++) {
1449 filter_type = &dest->event_filters[i];
1450 arg = filter_type->filter;
1451 if (arg->type != FILTER_ARG_BOOLEAN)
1452 continue;
1453 if ((arg->boolean.value && type == FILTER_TRIVIAL_FALSE) ||
1454 (!arg->boolean.value && type == FILTER_TRIVIAL_TRUE))
1455 continue;
1456
1457 event = filter_type->event;
1458
1459 if (src_pevent != dest_pevent) {
1460 /* do a look up */
1461 event = pevent_find_event_by_name(src_pevent,
1462 event->system,
1463 event->name);
1464 if (!event)
1465 return -1;
1466 }
1467
1468 str = pevent_filter_make_string(source, event->id);
1469 if (!str)
1470 continue;
1471
1472 /* Don't bother if the filter is trivial too */
1473 if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0)
1474 filter_event(dest, event, str, NULL);
1475 free(str);
1476 }
1477 return 0;
1478}
1479
1480/**
1481 * pevent_filter_clear_trivial - clear TRUE and FALSE filters
1482 * @filter: the filter to remove trivial filters from
1483 * @type: remove only true, false, or both
1484 *
1485 * Removes filters that only contain a TRUE or FALES boolean arg.
1486 */
1487void pevent_filter_clear_trivial(struct event_filter *filter,
1488 enum filter_trivial_type type)
1489{
1490 struct filter_type *filter_type;
1491 int count = 0;
1492 int *ids = NULL;
1493 int i;
1494
1495 if (!filter->filters)
1496 return;
1497
1498 /*
1499 * Two steps, first get all ids with trivial filters.
1500 * then remove those ids.
1501 */
1502 for (i = 0; i < filter->filters; i++) {
1503 filter_type = &filter->event_filters[i];
1504 if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
1505 continue;
1506 switch (type) {
1507 case FILTER_TRIVIAL_FALSE:
1508 if (filter_type->filter->boolean.value)
1509 continue;
1510 case FILTER_TRIVIAL_TRUE:
1511 if (!filter_type->filter->boolean.value)
1512 continue;
1513 default:
1514 break;
1515 }
1516
1517 ids = realloc(ids, sizeof(*ids) * (count + 1));
1518 if (!ids)
1519 die("Can't allocate ids");
1520 ids[count++] = filter_type->event_id;
1521 }
1522
1523 if (!count)
1524 return;
1525
1526 for (i = 0; i < count; i++)
1527 pevent_filter_remove_event(filter, ids[i]);
1528
1529 free(ids);
1530}
1531
1532/**
1533 * pevent_filter_event_has_trivial - return true event contains trivial filter
1534 * @filter: the filter with the information
1535 * @event_id: the id of the event to test
1536 * @type: trivial type to test for (TRUE, FALSE, EITHER)
1537 *
1538 * Returns 1 if the event contains a matching trivial type
1539 * otherwise 0.
1540 */
1541int pevent_filter_event_has_trivial(struct event_filter *filter,
1542 int event_id,
1543 enum filter_trivial_type type)
1544{
1545 struct filter_type *filter_type;
1546
1547 if (!filter->filters)
1548 return 0;
1549
1550 filter_type = find_filter_type(filter, event_id);
1551
1552 if (!filter_type)
1553 return 0;
1554
1555 if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
1556 return 0;
1557
1558 switch (type) {
1559 case FILTER_TRIVIAL_FALSE:
1560 return !filter_type->filter->boolean.value;
1561
1562 case FILTER_TRIVIAL_TRUE:
1563 return filter_type->filter->boolean.value;
1564 default:
1565 return 1;
1566 }
1567}
1568
1569static int test_filter(struct event_format *event,
1570 struct filter_arg *arg, struct pevent_record *record);
1571
1572static const char *
1573get_comm(struct event_format *event, struct pevent_record *record)
1574{
1575 const char *comm;
1576 int pid;
1577
1578 pid = pevent_data_pid(event->pevent, record);
1579 comm = pevent_data_comm_from_pid(event->pevent, pid);
1580 return comm;
1581}
1582
1583static unsigned long long
1584get_value(struct event_format *event,
1585 struct format_field *field, struct pevent_record *record)
1586{
1587 unsigned long long val;
1588
1589 /* Handle our dummy "comm" field */
1590 if (field == &comm) {
1591 const char *name;
1592
1593 name = get_comm(event, record);
1594 return (unsigned long)name;
1595 }
1596
1597 pevent_read_number_field(field, record->data, &val);
1598
1599 if (!(field->flags & FIELD_IS_SIGNED))
1600 return val;
1601
1602 switch (field->size) {
1603 case 1:
1604 return (char)val;
1605 case 2:
1606 return (short)val;
1607 case 4:
1608 return (int)val;
1609 case 8:
1610 return (long long)val;
1611 }
1612 return val;
1613}
1614
1615static unsigned long long
1616get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record);
1617
1618static unsigned long long
1619get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
1620{
1621 unsigned long long lval, rval;
1622
1623 lval = get_arg_value(event, arg->exp.left, record);
1624 rval = get_arg_value(event, arg->exp.right, record);
1625
1626 switch (arg->exp.type) {
1627 case FILTER_EXP_ADD:
1628 return lval + rval;
1629
1630 case FILTER_EXP_SUB:
1631 return lval - rval;
1632
1633 case FILTER_EXP_MUL:
1634 return lval * rval;
1635
1636 case FILTER_EXP_DIV:
1637 return lval / rval;
1638
1639 case FILTER_EXP_MOD:
1640 return lval % rval;
1641
1642 case FILTER_EXP_RSHIFT:
1643 return lval >> rval;
1644
1645 case FILTER_EXP_LSHIFT:
1646 return lval << rval;
1647
1648 case FILTER_EXP_AND:
1649 return lval & rval;
1650
1651 case FILTER_EXP_OR:
1652 return lval | rval;
1653
1654 case FILTER_EXP_XOR:
1655 return lval ^ rval;
1656
1657 case FILTER_EXP_NOT:
1658 default:
1659 die("error in exp");
1660 }
1661 return 0;
1662}
1663
1664static unsigned long long
1665get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
1666{
1667 switch (arg->type) {
1668 case FILTER_ARG_FIELD:
1669 return get_value(event, arg->field.field, record);
1670
1671 case FILTER_ARG_VALUE:
1672 if (arg->value.type != FILTER_NUMBER)
1673 die("must have number field!");
1674 return arg->value.val;
1675
1676 case FILTER_ARG_EXP:
1677 return get_exp_value(event, arg, record);
1678
1679 default:
1680 die("oops in filter");
1681 }
1682 return 0;
1683}
1684
1685static int test_num(struct event_format *event,
1686 struct filter_arg *arg, struct pevent_record *record)
1687{
1688 unsigned long long lval, rval;
1689
1690 lval = get_arg_value(event, arg->num.left, record);
1691 rval = get_arg_value(event, arg->num.right, record);
1692
1693 switch (arg->num.type) {
1694 case FILTER_CMP_EQ:
1695 return lval == rval;
1696
1697 case FILTER_CMP_NE:
1698 return lval != rval;
1699
1700 case FILTER_CMP_GT:
1701 return lval > rval;
1702
1703 case FILTER_CMP_LT:
1704 return lval < rval;
1705
1706 case FILTER_CMP_GE:
1707 return lval >= rval;
1708
1709 case FILTER_CMP_LE:
1710 return lval <= rval;
1711
1712 default:
1713 /* ?? */
1714 return 0;
1715 }
1716}
1717
1718static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
1719{
1720 struct event_format *event;
1721 struct pevent *pevent;
1722 unsigned long long addr;
1723 const char *val = NULL;
1724 char hex[64];
1725
1726 /* If the field is not a string convert it */
1727 if (arg->str.field->flags & FIELD_IS_STRING) {
1728 val = record->data + arg->str.field->offset;
1729
1730 /*
1731 * We need to copy the data since we can't be sure the field
1732 * is null terminated.
1733 */
1734 if (*(val + arg->str.field->size - 1)) {
1735 /* copy it */
1736 memcpy(arg->str.buffer, val, arg->str.field->size);
1737 /* the buffer is already NULL terminated */
1738 val = arg->str.buffer;
1739 }
1740
1741 } else {
1742 event = arg->str.field->event;
1743 pevent = event->pevent;
1744 addr = get_value(event, arg->str.field, record);
1745
1746 if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG))
1747 /* convert to a kernel symbol */
1748 val = pevent_find_function(pevent, addr);
1749
1750 if (val == NULL) {
1751 /* just use the hex of the string name */
1752 snprintf(hex, 64, "0x%llx", addr);
1753 val = hex;
1754 }
1755 }
1756
1757 return val;
1758}
1759
1760static int test_str(struct event_format *event,
1761 struct filter_arg *arg, struct pevent_record *record)
1762{
1763 const char *val;
1764
1765 if (arg->str.field == &comm)
1766 val = get_comm(event, record);
1767 else
1768 val = get_field_str(arg, record);
1769
1770 switch (arg->str.type) {
1771 case FILTER_CMP_MATCH:
1772 return strcmp(val, arg->str.val) == 0;
1773
1774 case FILTER_CMP_NOT_MATCH:
1775 return strcmp(val, arg->str.val) != 0;
1776
1777 case FILTER_CMP_REGEX:
1778 /* Returns zero on match */
1779 return !regexec(&arg->str.reg, val, 0, NULL, 0);
1780
1781 case FILTER_CMP_NOT_REGEX:
1782 return regexec(&arg->str.reg, val, 0, NULL, 0);
1783
1784 default:
1785 /* ?? */
1786 return 0;
1787 }
1788}
1789
1790static int test_op(struct event_format *event,
1791 struct filter_arg *arg, struct pevent_record *record)
1792{
1793 switch (arg->op.type) {
1794 case FILTER_OP_AND:
1795 return test_filter(event, arg->op.left, record) &&
1796 test_filter(event, arg->op.right, record);
1797
1798 case FILTER_OP_OR:
1799 return test_filter(event, arg->op.left, record) ||
1800 test_filter(event, arg->op.right, record);
1801
1802 case FILTER_OP_NOT:
1803 return !test_filter(event, arg->op.right, record);
1804
1805 default:
1806 /* ?? */
1807 return 0;
1808 }
1809}
1810
1811static int test_filter(struct event_format *event,
1812 struct filter_arg *arg, struct pevent_record *record)
1813{
1814 switch (arg->type) {
1815 case FILTER_ARG_BOOLEAN:
1816 /* easy case */
1817 return arg->boolean.value;
1818
1819 case FILTER_ARG_OP:
1820 return test_op(event, arg, record);
1821
1822 case FILTER_ARG_NUM:
1823 return test_num(event, arg, record);
1824
1825 case FILTER_ARG_STR:
1826 return test_str(event, arg, record);
1827
1828 case FILTER_ARG_EXP:
1829 case FILTER_ARG_VALUE:
1830 case FILTER_ARG_FIELD:
1831 /*
1832 * Expressions, fields and values evaluate
1833 * to true if they return non zero
1834 */
1835 return !!get_arg_value(event, arg, record);
1836
1837 default:
1838 die("oops!");
1839 /* ?? */
1840 return 0;
1841 }
1842}
1843
1844/**
1845 * pevent_event_filtered - return true if event has filter
1846 * @filter: filter struct with filter information
1847 * @event_id: event id to test if filter exists
1848 *
1849 * Returns 1 if filter found for @event_id
1850 * otherwise 0;
1851 */
1852int pevent_event_filtered(struct event_filter *filter,
1853 int event_id)
1854{
1855 struct filter_type *filter_type;
1856
1857 if (!filter->filters)
1858 return 0;
1859
1860 filter_type = find_filter_type(filter, event_id);
1861
1862 return filter_type ? 1 : 0;
1863}
1864
1865/**
1866 * pevent_filter_match - test if a record matches a filter
1867 * @filter: filter struct with filter information
1868 * @record: the record to test against the filter
1869 *
1870 * Returns:
1871 * 1 - filter found for event and @record matches
1872 * 0 - filter found for event and @record does not match
1873 * -1 - no filter found for @record's event
1874 * -2 - if no filters exist
1875 */
1876int pevent_filter_match(struct event_filter *filter,
1877 struct pevent_record *record)
1878{
1879 struct pevent *pevent = filter->pevent;
1880 struct filter_type *filter_type;
1881 int event_id;
1882
1883 if (!filter->filters)
1884 return FILTER_NONE;
1885
1886 event_id = pevent_data_type(pevent, record);
1887
1888 filter_type = find_filter_type(filter, event_id);
1889
1890 if (!filter_type)
1891 return FILTER_NOEXIST;
1892
1893 return test_filter(filter_type->event, filter_type->filter, record) ?
1894 FILTER_MATCH : FILTER_MISS;
1895}
1896
1897static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1898{
1899 char *str = NULL;
1900 char *left = NULL;
1901 char *right = NULL;
1902 char *op = NULL;
1903 int left_val = -1;
1904 int right_val = -1;
1905 int val;
1906 int len;
1907
1908 switch (arg->op.type) {
1909 case FILTER_OP_AND:
1910 op = "&&";
1911 /* fall through */
1912 case FILTER_OP_OR:
1913 if (!op)
1914 op = "||";
1915
1916 left = arg_to_str(filter, arg->op.left);
1917 right = arg_to_str(filter, arg->op.right);
1918 if (!left || !right)
1919 break;
1920
1921 /* Try to consolidate boolean values */
1922 if (strcmp(left, "TRUE") == 0)
1923 left_val = 1;
1924 else if (strcmp(left, "FALSE") == 0)
1925 left_val = 0;
1926
1927 if (strcmp(right, "TRUE") == 0)
1928 right_val = 1;
1929 else if (strcmp(right, "FALSE") == 0)
1930 right_val = 0;
1931
1932 if (left_val >= 0) {
1933 if ((arg->op.type == FILTER_OP_AND && !left_val) ||
1934 (arg->op.type == FILTER_OP_OR && left_val)) {
1935 /* Just return left value */
1936 str = left;
1937 left = NULL;
1938 break;
1939 }
1940 if (right_val >= 0) {
1941 /* just evaluate this. */
1942 val = 0;
1943 switch (arg->op.type) {
1944 case FILTER_OP_AND:
1945 val = left_val && right_val;
1946 break;
1947 case FILTER_OP_OR:
1948 val = left_val || right_val;
1949 break;
1950 default:
1951 break;
1952 }
1953 str = malloc_or_die(6);
1954 if (val)
1955 strcpy(str, "TRUE");
1956 else
1957 strcpy(str, "FALSE");
1958 break;
1959 }
1960 }
1961 if (right_val >= 0) {
1962 if ((arg->op.type == FILTER_OP_AND && !right_val) ||
1963 (arg->op.type == FILTER_OP_OR && right_val)) {
1964 /* Just return right value */
1965 str = right;
1966 right = NULL;
1967 break;
1968 }
1969 /* The right value is meaningless */
1970 str = left;
1971 left = NULL;
1972 break;
1973 }
1974
1975 len = strlen(left) + strlen(right) + strlen(op) + 10;
1976 str = malloc_or_die(len);
1977 snprintf(str, len, "(%s) %s (%s)",
1978 left, op, right);
1979 break;
1980
1981 case FILTER_OP_NOT:
1982 op = "!";
1983 right = arg_to_str(filter, arg->op.right);
1984 if (!right)
1985 break;
1986
1987 /* See if we can consolidate */
1988 if (strcmp(right, "TRUE") == 0)
1989 right_val = 1;
1990 else if (strcmp(right, "FALSE") == 0)
1991 right_val = 0;
1992 if (right_val >= 0) {
1993 /* just return the opposite */
1994 str = malloc_or_die(6);
1995 if (right_val)
1996 strcpy(str, "FALSE");
1997 else
1998 strcpy(str, "TRUE");
1999 break;
2000 }
2001 len = strlen(right) + strlen(op) + 3;
2002 str = malloc_or_die(len);
2003 snprintf(str, len, "%s(%s)", op, right);
2004 break;
2005
2006 default:
2007 /* ?? */
2008 break;
2009 }
2010 free(left);
2011 free(right);
2012 return str;
2013}
2014
2015static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
2016{
2017 char *str;
2018
2019 str = malloc_or_die(30);
2020
2021 snprintf(str, 30, "%lld", arg->value.val);
2022
2023 return str;
2024}
2025
2026static char *field_to_str(struct event_filter *filter, struct filter_arg *arg)
2027{
2028 return strdup(arg->field.field->name);
2029}
2030
2031static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
2032{
2033 char *lstr;
2034 char *rstr;
2035 char *op;
2036 char *str = NULL;
2037 int len;
2038
2039 lstr = arg_to_str(filter, arg->exp.left);
2040 rstr = arg_to_str(filter, arg->exp.right);
2041 if (!lstr || !rstr)
2042 goto out;
2043
2044 switch (arg->exp.type) {
2045 case FILTER_EXP_ADD:
2046 op = "+";
2047 break;
2048 case FILTER_EXP_SUB:
2049 op = "-";
2050 break;
2051 case FILTER_EXP_MUL:
2052 op = "*";
2053 break;
2054 case FILTER_EXP_DIV:
2055 op = "/";
2056 break;
2057 case FILTER_EXP_MOD:
2058 op = "%";
2059 break;
2060 case FILTER_EXP_RSHIFT:
2061 op = ">>";
2062 break;
2063 case FILTER_EXP_LSHIFT:
2064 op = "<<";
2065 break;
2066 case FILTER_EXP_AND:
2067 op = "&";
2068 break;
2069 case FILTER_EXP_OR:
2070 op = "|";
2071 break;
2072 case FILTER_EXP_XOR:
2073 op = "^";
2074 break;
2075 default:
2076 die("oops in exp");
2077 }
2078
2079 len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
2080 str = malloc_or_die(len);
2081 snprintf(str, len, "%s %s %s", lstr, op, rstr);
2082out:
2083 free(lstr);
2084 free(rstr);
2085
2086 return str;
2087}
2088
2089static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
2090{
2091 char *lstr;
2092 char *rstr;
2093 char *str = NULL;
2094 char *op = NULL;
2095 int len;
2096
2097 lstr = arg_to_str(filter, arg->num.left);
2098 rstr = arg_to_str(filter, arg->num.right);
2099 if (!lstr || !rstr)
2100 goto out;
2101
2102 switch (arg->num.type) {
2103 case FILTER_CMP_EQ:
2104 op = "==";
2105 /* fall through */
2106 case FILTER_CMP_NE:
2107 if (!op)
2108 op = "!=";
2109 /* fall through */
2110 case FILTER_CMP_GT:
2111 if (!op)
2112 op = ">";
2113 /* fall through */
2114 case FILTER_CMP_LT:
2115 if (!op)
2116 op = "<";
2117 /* fall through */
2118 case FILTER_CMP_GE:
2119 if (!op)
2120 op = ">=";
2121 /* fall through */
2122 case FILTER_CMP_LE:
2123 if (!op)
2124 op = "<=";
2125
2126 len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
2127 str = malloc_or_die(len);
2128 sprintf(str, "%s %s %s", lstr, op, rstr);
2129
2130 break;
2131
2132 default:
2133 /* ?? */
2134 break;
2135 }
2136
2137out:
2138 free(lstr);
2139 free(rstr);
2140 return str;
2141}
2142
2143static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2144{
2145 char *str = NULL;
2146 char *op = NULL;
2147 int len;
2148
2149 switch (arg->str.type) {
2150 case FILTER_CMP_MATCH:
2151 op = "==";
2152 /* fall through */
2153 case FILTER_CMP_NOT_MATCH:
2154 if (!op)
2155 op = "!=";
2156 /* fall through */
2157 case FILTER_CMP_REGEX:
2158 if (!op)
2159 op = "=~";
2160 /* fall through */
2161 case FILTER_CMP_NOT_REGEX:
2162 if (!op)
2163 op = "!~";
2164
2165 len = strlen(arg->str.field->name) + strlen(op) +
2166 strlen(arg->str.val) + 6;
2167 str = malloc_or_die(len);
2168 snprintf(str, len, "%s %s \"%s\"",
2169 arg->str.field->name,
2170 op, arg->str.val);
2171 break;
2172
2173 default:
2174 /* ?? */
2175 break;
2176 }
2177 return str;
2178}
2179
2180static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
2181{
2182 char *str;
2183
2184 switch (arg->type) {
2185 case FILTER_ARG_BOOLEAN:
2186 str = malloc_or_die(6);
2187 if (arg->boolean.value)
2188 strcpy(str, "TRUE");
2189 else
2190 strcpy(str, "FALSE");
2191 return str;
2192
2193 case FILTER_ARG_OP:
2194 return op_to_str(filter, arg);
2195
2196 case FILTER_ARG_NUM:
2197 return num_to_str(filter, arg);
2198
2199 case FILTER_ARG_STR:
2200 return str_to_str(filter, arg);
2201
2202 case FILTER_ARG_VALUE:
2203 return val_to_str(filter, arg);
2204
2205 case FILTER_ARG_FIELD:
2206 return field_to_str(filter, arg);
2207
2208 case FILTER_ARG_EXP:
2209 return exp_to_str(filter, arg);
2210
2211 default:
2212 /* ?? */
2213 return NULL;
2214 }
2215
2216}
2217
2218/**
2219 * pevent_filter_make_string - return a string showing the filter
2220 * @filter: filter struct with filter information
2221 * @event_id: the event id to return the filter string with
2222 *
2223 * Returns a string that displays the filter contents.
2224 * This string must be freed with free(str).
2225 * NULL is returned if no filter is found.
2226 */
2227char *
2228pevent_filter_make_string(struct event_filter *filter, int event_id)
2229{
2230 struct filter_type *filter_type;
2231
2232 if (!filter->filters)
2233 return NULL;
2234
2235 filter_type = find_filter_type(filter, event_id);
2236
2237 if (!filter_type)
2238 return NULL;
2239
2240 return arg_to_str(filter, filter_type->filter);
2241}
2242
2243/**
2244 * pevent_filter_compare - compare two filters and return if they are the same
2245 * @filter1: Filter to compare with @filter2
2246 * @filter2: Filter to compare with @filter1
2247 *
2248 * Returns:
2249 * 1 if the two filters hold the same content.
2250 * 0 if they do not.
2251 */
2252int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
2253{
2254 struct filter_type *filter_type1;
2255 struct filter_type *filter_type2;
2256 char *str1, *str2;
2257 int result;
2258 int i;
2259
2260 /* Do the easy checks first */
2261 if (filter1->filters != filter2->filters)
2262 return 0;
2263 if (!filter1->filters && !filter2->filters)
2264 return 1;
2265
2266 /*
2267 * Now take a look at each of the events to see if they have the same
2268 * filters to them.
2269 */
2270 for (i = 0; i < filter1->filters; i++) {
2271 filter_type1 = &filter1->event_filters[i];
2272 filter_type2 = find_filter_type(filter2, filter_type1->event_id);
2273 if (!filter_type2)
2274 break;
2275 if (filter_type1->filter->type != filter_type2->filter->type)
2276 break;
2277 switch (filter_type1->filter->type) {
2278 case FILTER_TRIVIAL_FALSE:
2279 case FILTER_TRIVIAL_TRUE:
2280 /* trivial types just need the type compared */
2281 continue;
2282 default:
2283 break;
2284 }
2285 /* The best way to compare complex filters is with strings */
2286 str1 = arg_to_str(filter1, filter_type1->filter);
2287 str2 = arg_to_str(filter2, filter_type2->filter);
2288 if (str1 && str2)
2289 result = strcmp(str1, str2) != 0;
2290 else
2291 /* bail out if allocation fails */
2292 result = 1;
2293
2294 free(str1);
2295 free(str2);
2296 if (result)
2297 break;
2298 }
2299
2300 if (i < filter1->filters)
2301 return 0;
2302 return 1;
2303}
2304
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c
deleted file mode 100644
index f023a133abb..00000000000
--- a/tools/lib/traceevent/parse-utils.c
+++ /dev/null
@@ -1,110 +0,0 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <stdarg.h>
5#include <errno.h>
6
7#define __weak __attribute__((weak))
8
9void __vdie(const char *fmt, va_list ap)
10{
11 int ret = errno;
12
13 if (errno)
14 perror("trace-cmd");
15 else
16 ret = -1;
17
18 fprintf(stderr, " ");
19 vfprintf(stderr, fmt, ap);
20
21 fprintf(stderr, "\n");
22 exit(ret);
23}
24
25void __die(const char *fmt, ...)
26{
27 va_list ap;
28
29 va_start(ap, fmt);
30 __vdie(fmt, ap);
31 va_end(ap);
32}
33
34void __weak die(const char *fmt, ...)
35{
36 va_list ap;
37
38 va_start(ap, fmt);
39 __vdie(fmt, ap);
40 va_end(ap);
41}
42
43void __vwarning(const char *fmt, va_list ap)
44{
45 if (errno)
46 perror("trace-cmd");
47 errno = 0;
48
49 fprintf(stderr, " ");
50 vfprintf(stderr, fmt, ap);
51
52 fprintf(stderr, "\n");
53}
54
55void __warning(const char *fmt, ...)
56{
57 va_list ap;
58
59 va_start(ap, fmt);
60 __vwarning(fmt, ap);
61 va_end(ap);
62}
63
64void __weak warning(const char *fmt, ...)
65{
66 va_list ap;
67
68 va_start(ap, fmt);
69 __vwarning(fmt, ap);
70 va_end(ap);
71}
72
73void __vpr_stat(const char *fmt, va_list ap)
74{
75 vprintf(fmt, ap);
76 printf("\n");
77}
78
79void __pr_stat(const char *fmt, ...)
80{
81 va_list ap;
82
83 va_start(ap, fmt);
84 __vpr_stat(fmt, ap);
85 va_end(ap);
86}
87
88void __weak vpr_stat(const char *fmt, va_list ap)
89{
90 __vpr_stat(fmt, ap);
91}
92
93void __weak pr_stat(const char *fmt, ...)
94{
95 va_list ap;
96
97 va_start(ap, fmt);
98 __vpr_stat(fmt, ap);
99 va_end(ap);
100}
101
102void __weak *malloc_or_die(unsigned int size)
103{
104 void *data;
105
106 data = malloc(size);
107 if (!data)
108 die("malloc");
109 return data;
110}
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
deleted file mode 100644
index b1ccc923e8a..00000000000
--- a/tools/lib/traceevent/trace-seq.c
+++ /dev/null
@@ -1,200 +0,0 @@
1/*
2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25
26#include "event-parse.h"
27#include "event-utils.h"
28
29/*
30 * The TRACE_SEQ_POISON is to catch the use of using
31 * a trace_seq structure after it was destroyed.
32 */
33#define TRACE_SEQ_POISON ((void *)0xdeadbeef)
34#define TRACE_SEQ_CHECK(s) \
35do { \
36 if ((s)->buffer == TRACE_SEQ_POISON) \
37 die("Usage of trace_seq after it was destroyed"); \
38} while (0)
39
40/**
41 * trace_seq_init - initialize the trace_seq structure
42 * @s: a pointer to the trace_seq structure to initialize
43 */
44void trace_seq_init(struct trace_seq *s)
45{
46 s->len = 0;
47 s->readpos = 0;
48 s->buffer_size = TRACE_SEQ_BUF_SIZE;
49 s->buffer = malloc_or_die(s->buffer_size);
50}
51
52/**
53 * trace_seq_destroy - free up memory of a trace_seq
54 * @s: a pointer to the trace_seq to free the buffer
55 *
56 * Only frees the buffer, not the trace_seq struct itself.
57 */
58void trace_seq_destroy(struct trace_seq *s)
59{
60 if (!s)
61 return;
62 TRACE_SEQ_CHECK(s);
63 free(s->buffer);
64 s->buffer = TRACE_SEQ_POISON;
65}
66
67static void expand_buffer(struct trace_seq *s)
68{
69 s->buffer_size += TRACE_SEQ_BUF_SIZE;
70 s->buffer = realloc(s->buffer, s->buffer_size);
71 if (!s->buffer)
72 die("Can't allocate trace_seq buffer memory");
73}
74
75/**
76 * trace_seq_printf - sequence printing of trace information
77 * @s: trace sequence descriptor
78 * @fmt: printf format string
79 *
80 * It returns 0 if the trace oversizes the buffer's free
81 * space, 1 otherwise.
82 *
83 * The tracer may use either sequence operations or its own
84 * copy to user routines. To simplify formating of a trace
85 * trace_seq_printf is used to store strings into a special
86 * buffer (@s). Then the output may be either used by
87 * the sequencer or pulled into another buffer.
88 */
89int
90trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
91{
92 va_list ap;
93 int len;
94 int ret;
95
96 TRACE_SEQ_CHECK(s);
97
98 try_again:
99 len = (s->buffer_size - 1) - s->len;
100
101 va_start(ap, fmt);
102 ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
103 va_end(ap);
104
105 if (ret >= len) {
106 expand_buffer(s);
107 goto try_again;
108 }
109
110 s->len += ret;
111
112 return 1;
113}
114
115/**
116 * trace_seq_vprintf - sequence printing of trace information
117 * @s: trace sequence descriptor
118 * @fmt: printf format string
119 *
120 * The tracer may use either sequence operations or its own
121 * copy to user routines. To simplify formating of a trace
122 * trace_seq_printf is used to store strings into a special
123 * buffer (@s). Then the output may be either used by
124 * the sequencer or pulled into another buffer.
125 */
126int
127trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
128{
129 int len;
130 int ret;
131
132 TRACE_SEQ_CHECK(s);
133
134 try_again:
135 len = (s->buffer_size - 1) - s->len;
136
137 ret = vsnprintf(s->buffer + s->len, len, fmt, args);
138
139 if (ret >= len) {
140 expand_buffer(s);
141 goto try_again;
142 }
143
144 s->len += ret;
145
146 return len;
147}
148
149/**
150 * trace_seq_puts - trace sequence printing of simple string
151 * @s: trace sequence descriptor
152 * @str: simple string to record
153 *
154 * The tracer may use either the sequence operations or its own
155 * copy to user routines. This function records a simple string
156 * into a special buffer (@s) for later retrieval by a sequencer
157 * or other mechanism.
158 */
159int trace_seq_puts(struct trace_seq *s, const char *str)
160{
161 int len;
162
163 TRACE_SEQ_CHECK(s);
164
165 len = strlen(str);
166
167 while (len > ((s->buffer_size - 1) - s->len))
168 expand_buffer(s);
169
170 memcpy(s->buffer + s->len, str, len);
171 s->len += len;
172
173 return len;
174}
175
176int trace_seq_putc(struct trace_seq *s, unsigned char c)
177{
178 TRACE_SEQ_CHECK(s);
179
180 while (s->len >= (s->buffer_size - 1))
181 expand_buffer(s);
182
183 s->buffer[s->len++] = c;
184
185 return 1;
186}
187
188void trace_seq_terminate(struct trace_seq *s)
189{
190 TRACE_SEQ_CHECK(s);
191
192 /* There's always one character left on the buffer */
193 s->buffer[s->len] = 0;
194}
195
196int trace_seq_do_printf(struct trace_seq *s)
197{
198 TRACE_SEQ_CHECK(s);
199 return printf("%.*s", s->len, s->buffer);
200}
diff --git a/tools/nfsd/inject_fault.sh b/tools/nfsd/inject_fault.sh
deleted file mode 100755
index 06a399ac8b2..00000000000
--- a/tools/nfsd/inject_fault.sh
+++ /dev/null
@@ -1,49 +0,0 @@
1#!/bin/bash
2#
3# Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
4#
5# Script for easier NFSD fault injection
6
7# Check that debugfs has been mounted
8DEBUGFS=`cat /proc/mounts | grep debugfs`
9if [ "$DEBUGFS" == "" ]; then
10 echo "debugfs does not appear to be mounted!"
11 echo "Please mount debugfs and try again"
12 exit 1
13fi
14
15# Check that the fault injection directory exists
16DEBUGDIR=`echo $DEBUGFS | awk '{print $2}'`/nfsd
17if [ ! -d "$DEBUGDIR" ]; then
18 echo "$DEBUGDIR does not exist"
19 echo "Check that your .config selects CONFIG_NFSD_FAULT_INJECTION"
20 exit 1
21fi
22
23function help()
24{
25 echo "Usage $0 injection_type [count]"
26 echo ""
27 echo "Injection types are:"
28 ls $DEBUGDIR
29 exit 1
30}
31
32if [ $# == 0 ]; then
33 help
34elif [ ! -f $DEBUGDIR/$1 ]; then
35 help
36elif [ $# != 2 ]; then
37 COUNT=0
38else
39 COUNT=$2
40fi
41
42BEFORE=`mktemp`
43AFTER=`mktemp`
44dmesg > $BEFORE
45echo $COUNT > $DEBUGDIR/$1
46dmesg > $AFTER
47# Capture lines that only exist in the $AFTER file
48diff $BEFORE $AFTER | grep ">"
49rm -f $BEFORE $AFTER
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index ef6d22e879e..4626a398836 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -1,12 +1,3 @@
1include ../config/utilities.mak
2
3OUTPUT := ./
4ifeq ("$(origin O)", "command line")
5 ifneq ($(O),)
6 OUTPUT := $(O)/
7 endif
8endif
9
10MAN1_TXT= \ 1MAN1_TXT= \
11 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \ 2 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
12 $(wildcard perf-*.txt)) \ 3 $(wildcard perf-*.txt)) \
@@ -15,11 +6,10 @@ MAN5_TXT=
15MAN7_TXT= 6MAN7_TXT=
16 7
17MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT) 8MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
18_MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT)) 9MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
19_MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT)) 10MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
20 11
21MAN_XML=$(addprefix $(OUTPUT),$(_MAN_XML)) 12DOC_HTML=$(MAN_HTML)
22MAN_HTML=$(addprefix $(OUTPUT),$(_MAN_HTML))
23 13
24ARTICLES = 14ARTICLES =
25# with their own formatting rules. 15# with their own formatting rules.
@@ -28,17 +18,11 @@ API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technica
28SP_ARTICLES += $(API_DOCS) 18SP_ARTICLES += $(API_DOCS)
29SP_ARTICLES += technical/api-index 19SP_ARTICLES += technical/api-index
30 20
31_DOC_HTML = $(_MAN_HTML) 21DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
32_DOC_HTML+=$(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
33DOC_HTML=$(addprefix $(OUTPUT),$(_DOC_HTML))
34
35_DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
36_DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
37_DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
38 22
39DOC_MAN1=$(addprefix $(OUTPUT),$(_DOC_MAN1)) 23DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
40DOC_MAN5=$(addprefix $(OUTPUT),$(_DOC_MAN5)) 24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
41DOC_MAN7=$(addprefix $(OUTPUT),$(_DOC_MAN7)) 25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
42 26
43# Make the path relative to DESTDIR, not prefix 27# Make the path relative to DESTDIR, not prefix
44ifndef DESTDIR 28ifndef DESTDIR
@@ -66,7 +50,6 @@ MAKEINFO=makeinfo
66INSTALL_INFO=install-info 50INSTALL_INFO=install-info
67DOCBOOK2X_TEXI=docbook2x-texi 51DOCBOOK2X_TEXI=docbook2x-texi
68DBLATEX=dblatex 52DBLATEX=dblatex
69XMLTO=xmlto
70ifndef PERL_PATH 53ifndef PERL_PATH
71 PERL_PATH = /usr/bin/perl 54 PERL_PATH = /usr/bin/perl
72endif 55endif
@@ -74,16 +57,6 @@ endif
74-include ../config.mak.autogen 57-include ../config.mak.autogen
75-include ../config.mak 58-include ../config.mak
76 59
77_tmp_tool_path := $(call get-executable,$(ASCIIDOC))
78ifeq ($(_tmp_tool_path),)
79 missing_tools = $(ASCIIDOC)
80endif
81
82_tmp_tool_path := $(call get-executable,$(XMLTO))
83ifeq ($(_tmp_tool_path),)
84 missing_tools += $(XMLTO)
85endif
86
87# 60#
88# For asciidoc ... 61# For asciidoc ...
89# -7.1.2, no extra settings are needed. 62# -7.1.2, no extra settings are needed.
@@ -177,18 +150,13 @@ man1: $(DOC_MAN1)
177man5: $(DOC_MAN5) 150man5: $(DOC_MAN5)
178man7: $(DOC_MAN7) 151man7: $(DOC_MAN7)
179 152
180info: $(OUTPUT)perf.info $(OUTPUT)perfman.info 153info: perf.info perfman.info
181 154
182pdf: $(OUTPUT)user-manual.pdf 155pdf: user-manual.pdf
183 156
184install: install-man 157install: install-man
185 158
186check-man-tools: 159install-man: man
187ifdef missing_tools
188 $(error "You need to install $(missing_tools) for man pages")
189endif
190
191do-install-man: man
192 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir) 160 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
193# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir) 161# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
194# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir) 162# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
@@ -196,18 +164,9 @@ do-install-man: man
196# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir) 164# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
197# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) 165# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
198 166
199install-man: check-man-tools man
200
201try-install-man:
202ifdef missing_tools
203 $(warning Please install $(missing_tools) to have the man pages installed)
204else
205 $(MAKE) do-install-man
206endif
207
208install-info: info 167install-info: info
209 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir) 168 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
210 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir) 169 $(INSTALL) -m 644 perf.info perfman.info $(DESTDIR)$(infodir)
211 if test -r $(DESTDIR)$(infodir)/dir; then \ 170 if test -r $(DESTDIR)$(infodir)/dir; then \
212 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\ 171 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
213 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\ 172 $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
@@ -217,27 +176,27 @@ install-info: info
217 176
218install-pdf: pdf 177install-pdf: pdf
219 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) 178 $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
220 $(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir) 179 $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
221 180
222#install-html: html 181#install-html: html
223# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 182# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
224 183
225$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 184../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
226 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE 185 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE
227 186
228-include $(OUTPUT)PERF-VERSION-FILE 187-include ../PERF-VERSION-FILE
229 188
230# 189#
231# Determine "include::" file references in asciidoc files. 190# Determine "include::" file references in asciidoc files.
232# 191#
233$(OUTPUT)doc.dep : $(wildcard *.txt) build-docdep.perl 192doc.dep : $(wildcard *.txt) build-docdep.perl
234 $(QUIET_GEN)$(RM) $@+ $@ && \ 193 $(QUIET_GEN)$(RM) $@+ $@ && \
235 $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \ 194 $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
236 mv $@+ $@ 195 mv $@+ $@
237 196
238-include $(OUPTUT)doc.dep 197-include doc.dep
239 198
240_cmds_txt = cmds-ancillaryinterrogators.txt \ 199cmds_txt = cmds-ancillaryinterrogators.txt \
241 cmds-ancillarymanipulators.txt \ 200 cmds-ancillarymanipulators.txt \
242 cmds-mainporcelain.txt \ 201 cmds-mainporcelain.txt \
243 cmds-plumbinginterrogators.txt \ 202 cmds-plumbinginterrogators.txt \
@@ -246,36 +205,32 @@ _cmds_txt = cmds-ancillaryinterrogators.txt \
246 cmds-synchelpers.txt \ 205 cmds-synchelpers.txt \
247 cmds-purehelpers.txt \ 206 cmds-purehelpers.txt \
248 cmds-foreignscminterface.txt 207 cmds-foreignscminterface.txt
249cmds_txt=$(addprefix $(OUTPUT),$(_cmds_txt))
250 208
251$(cmds_txt): $(OUTPUT)cmd-list.made 209$(cmds_txt): cmd-list.made
252 210
253$(OUTPUT)cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) 211cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
254 $(QUIET_GEN)$(RM) $@ && \ 212 $(QUIET_GEN)$(RM) $@ && \
255 $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \ 213 $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
256 date >$@ 214 date >$@
257 215
258clean: 216clean:
259 $(RM) $(MAN_XML) $(addsuffix +,$(MAN_XML)) 217 $(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
260 $(RM) $(MAN_HTML) $(addsuffix +,$(MAN_HTML)) 218 $(RM) *.texi *.texi+ *.texi++ perf.info perfman.info
261 $(RM) $(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7) 219 $(RM) howto-index.txt howto/*.html doc.dep
262 $(RM) $(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++ 220 $(RM) technical/api-*.html technical/api-index.txt
263 $(RM) $(OUTPUT)perf.info $(OUTPUT)perfman.info 221 $(RM) $(cmds_txt) *.made
264 $(RM) $(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep 222
265 $(RM) $(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt 223$(MAN_HTML): %.html : %.txt
266 $(RM) $(cmds_txt) $(OUTPUT)*.made
267
268$(MAN_HTML): $(OUTPUT)%.html : %.txt
269 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 224 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
270 $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \ 225 $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
271 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \ 226 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
272 mv $@+ $@ 227 mv $@+ $@
273 228
274$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml 229%.1 %.5 %.7 : %.xml
275 $(QUIET_XMLTO)$(RM) $@ && \ 230 $(QUIET_XMLTO)$(RM) $@ && \
276 $(XMLTO) -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< 231 xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
277 232
278$(OUTPUT)%.xml : %.txt 233%.xml : %.txt
279 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 234 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
280 $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ 235 $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
281 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \ 236 $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
@@ -284,25 +239,25 @@ $(OUTPUT)%.xml : %.txt
284XSLT = docbook.xsl 239XSLT = docbook.xsl
285XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css 240XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
286 241
287$(OUTPUT)user-manual.html: $(OUTPUT)user-manual.xml 242user-manual.html: user-manual.xml
288 $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $< 243 $(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
289 244
290$(OUTPUT)perf.info: $(OUTPUT)user-manual.texi 245perf.info: user-manual.texi
291 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ $(OUTPUT)user-manual.texi 246 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
292 247
293$(OUTPUT)user-manual.texi: $(OUTPUT)user-manual.xml 248user-manual.texi: user-manual.xml
294 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ 249 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
295 $(DOCBOOK2X_TEXI) $(OUTPUT)user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \ 250 $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
296 $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \ 251 $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
297 rm $@++ && \ 252 rm $@++ && \
298 mv $@+ $@ 253 mv $@+ $@
299 254
300$(OUTPUT)user-manual.pdf: $(OUTPUT)user-manual.xml 255user-manual.pdf: user-manual.xml
301 $(QUIET_DBLATEX)$(RM) $@+ $@ && \ 256 $(QUIET_DBLATEX)$(RM) $@+ $@ && \
302 $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \ 257 $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
303 mv $@+ $@ 258 mv $@+ $@
304 259
305$(OUTPUT)perfman.texi: $(MAN_XML) cat-texi.perl 260perfman.texi: $(MAN_XML) cat-texi.perl
306 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ 261 $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
307 ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \ 262 ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
308 --to-stdout $(xml) &&) true) > $@++ && \ 263 --to-stdout $(xml) &&) true) > $@++ && \
@@ -310,7 +265,7 @@ $(OUTPUT)perfman.texi: $(MAN_XML) cat-texi.perl
310 rm $@++ && \ 265 rm $@++ && \
311 mv $@+ $@ 266 mv $@+ $@
312 267
313$(OUTPUT)perfman.info: $(OUTPUT)perfman.texi 268perfman.info: perfman.texi
314 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi 269 $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
315 270
316$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml 271$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
diff --git a/tools/perf/Documentation/android.txt b/tools/perf/Documentation/android.txt
deleted file mode 100644
index 8484c3a04a6..00000000000
--- a/tools/perf/Documentation/android.txt
+++ /dev/null
@@ -1,78 +0,0 @@
1How to compile perf for Android
2=========================================
3
4I. Set the Android NDK environment
5------------------------------------------------
6
7(a). Use the Android NDK
8------------------------------------------------
91. You need to download and install the Android Native Development Kit (NDK).
10Set the NDK variable to point to the path where you installed the NDK:
11 export NDK=/path/to/android-ndk
12
132. Set cross-compiling environment variables for NDK toolchain and sysroot.
14For arm:
15 export NDK_TOOLCHAIN=${NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-
16 export NDK_SYSROOT=${NDK}/platforms/android-9/arch-arm
17For x86:
18 export NDK_TOOLCHAIN=${NDK}/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android-
19 export NDK_SYSROOT=${NDK}/platforms/android-9/arch-x86
20
21This method is not working for Android NDK versions up to Revision 8b.
22perf uses some bionic enhancements that are not included in these NDK versions.
23You can use method (b) described below instead.
24
25(b). Use the Android source tree
26-----------------------------------------------
271. Download the master branch of the Android source tree.
28Set the environment for the target you want using:
29 source build/envsetup.sh
30 lunch
31
322. Build your own NDK sysroot to contain latest bionic changes and set the
33NDK sysroot environment variable.
34 cd ${ANDROID_BUILD_TOP}/ndk
35For arm:
36 ./build/tools/build-ndk-sysroot.sh --abi=arm
37 export NDK_SYSROOT=${ANDROID_BUILD_TOP}/ndk/build/platforms/android-3/arch-arm
38For x86:
39 ./build/tools/build-ndk-sysroot.sh --abi=x86
40 export NDK_SYSROOT=${ANDROID_BUILD_TOP}/ndk/build/platforms/android-3/arch-x86
41
423. Set the NDK toolchain environment variable.
43For arm:
44 export NDK_TOOLCHAIN=${ANDROID_TOOLCHAIN}/arm-linux-androideabi-
45For x86:
46 export NDK_TOOLCHAIN=${ANDROID_TOOLCHAIN}/i686-linux-android-
47
48II. Compile perf for Android
49------------------------------------------------
50You need to run make with the NDK toolchain and sysroot defined above:
51For arm:
52 make ARCH=arm CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}"
53For x86:
54 make ARCH=x86 CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}"
55
56III. Install perf
57-----------------------------------------------
58You need to connect to your Android device/emulator using adb.
59Install perf using:
60 adb push perf /data/perf
61
62If you also want to use perf-archive you need busybox tools for Android.
63For installing perf-archive, you first need to replace #!/bin/bash with #!/system/bin/sh:
64 sed 's/#!\/bin\/bash/#!\/system\/bin\/sh/g' perf-archive >> /tmp/perf-archive
65 chmod +x /tmp/perf-archive
66 adb push /tmp/perf-archive /data/perf-archive
67
68IV. Environment settings for running perf
69------------------------------------------------
70Some perf features need environment variables to run properly.
71You need to set these before running perf on the target:
72 adb shell
73 # PERF_PAGER=cat
74
75IV. Run perf
76------------------------------------------------
77Run perf on your device/emulator to which you previously connected using adb:
78 # ./data/perf
diff --git a/tools/perf/Documentation/examples.txt b/tools/perf/Documentation/examples.txt
index 77f95276242..8eb6c489fb1 100644
--- a/tools/perf/Documentation/examples.txt
+++ b/tools/perf/Documentation/examples.txt
@@ -17,8 +17,8 @@ titan:~> perf list
17 kmem:kmem_cache_alloc_node [Tracepoint event] 17 kmem:kmem_cache_alloc_node [Tracepoint event]
18 kmem:kfree [Tracepoint event] 18 kmem:kfree [Tracepoint event]
19 kmem:kmem_cache_free [Tracepoint event] 19 kmem:kmem_cache_free [Tracepoint event]
20 kmem:mm_page_free [Tracepoint event] 20 kmem:mm_page_free_direct [Tracepoint event]
21 kmem:mm_page_free_batched [Tracepoint event] 21 kmem:mm_pagevec_free [Tracepoint event]
22 kmem:mm_page_alloc [Tracepoint event] 22 kmem:mm_page_alloc [Tracepoint event]
23 kmem:mm_page_alloc_zone_locked [Tracepoint event] 23 kmem:mm_page_alloc_zone_locked [Tracepoint event]
24 kmem:mm_page_pcpu_drain [Tracepoint event] 24 kmem:mm_page_pcpu_drain [Tracepoint event]
@@ -29,15 +29,15 @@ measured. For example the page alloc/free properties of a 'hackbench
29run' are: 29run' are:
30 30
31 titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc 31 titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc
32 -e kmem:mm_page_free_batched -e kmem:mm_page_free ./hackbench 10 32 -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10
33 Time: 0.575 33 Time: 0.575
34 34
35 Performance counter stats for './hackbench 10': 35 Performance counter stats for './hackbench 10':
36 36
37 13857 kmem:mm_page_pcpu_drain 37 13857 kmem:mm_page_pcpu_drain
38 27576 kmem:mm_page_alloc 38 27576 kmem:mm_page_alloc
39 6025 kmem:mm_page_free_batched 39 6025 kmem:mm_pagevec_free
40 20934 kmem:mm_page_free 40 20934 kmem:mm_page_free_direct
41 41
42 0.613972165 seconds time elapsed 42 0.613972165 seconds time elapsed
43 43
@@ -45,8 +45,8 @@ You can observe the statistical properties as well, by using the
45'repeat the workload N times' feature of perf stat: 45'repeat the workload N times' feature of perf stat:
46 46
47 titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e 47 titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e
48 kmem:mm_page_alloc -e kmem:mm_page_free_batched -e 48 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
49 kmem:mm_page_free ./hackbench 10 49 kmem:mm_page_free_direct ./hackbench 10
50 Time: 0.627 50 Time: 0.627
51 Time: 0.644 51 Time: 0.644
52 Time: 0.564 52 Time: 0.564
@@ -57,8 +57,8 @@ You can observe the statistical properties as well, by using the
57 57
58 12920 kmem:mm_page_pcpu_drain ( +- 3.359% ) 58 12920 kmem:mm_page_pcpu_drain ( +- 3.359% )
59 25035 kmem:mm_page_alloc ( +- 3.783% ) 59 25035 kmem:mm_page_alloc ( +- 3.783% )
60 6104 kmem:mm_page_free_batched ( +- 0.934% ) 60 6104 kmem:mm_pagevec_free ( +- 0.934% )
61 18376 kmem:mm_page_free ( +- 4.941% ) 61 18376 kmem:mm_page_free_direct ( +- 4.941% )
62 62
63 0.643954516 seconds time elapsed ( +- 2.363% ) 63 0.643954516 seconds time elapsed ( +- 2.363% )
64 64
@@ -158,15 +158,15 @@ Or you can observe the whole system's page allocations for 10
158seconds: 158seconds:
159 159
160titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e 160titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e
161kmem:mm_page_alloc -e kmem:mm_page_free_batched -e 161kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
162kmem:mm_page_free sleep 10 162kmem:mm_page_free_direct sleep 10
163 163
164 Performance counter stats for 'sleep 10': 164 Performance counter stats for 'sleep 10':
165 165
166 171585 kmem:mm_page_pcpu_drain 166 171585 kmem:mm_page_pcpu_drain
167 322114 kmem:mm_page_alloc 167 322114 kmem:mm_page_alloc
168 73623 kmem:mm_page_free_batched 168 73623 kmem:mm_pagevec_free
169 254115 kmem:mm_page_free 169 254115 kmem:mm_page_free_direct
170 170
171 10.000591410 seconds time elapsed 171 10.000591410 seconds time elapsed
172 172
@@ -174,15 +174,15 @@ Or observe how fluctuating the page allocations are, via statistical
174analysis done over ten 1-second intervals: 174analysis done over ten 1-second intervals:
175 175
176 titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e 176 titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e
177 kmem:mm_page_alloc -e kmem:mm_page_free_batched -e 177 kmem:mm_page_alloc -e kmem:mm_pagevec_free -e
178 kmem:mm_page_free sleep 1 178 kmem:mm_page_free_direct sleep 1
179 179
180 Performance counter stats for 'sleep 1' (10 runs): 180 Performance counter stats for 'sleep 1' (10 runs):
181 181
182 17254 kmem:mm_page_pcpu_drain ( +- 3.709% ) 182 17254 kmem:mm_page_pcpu_drain ( +- 3.709% )
183 34394 kmem:mm_page_alloc ( +- 4.617% ) 183 34394 kmem:mm_page_alloc ( +- 4.617% )
184 7509 kmem:mm_page_free_batched ( +- 4.820% ) 184 7509 kmem:mm_pagevec_free ( +- 4.820% )
185 25653 kmem:mm_page_free ( +- 3.672% ) 185 25653 kmem:mm_page_free_direct ( +- 3.672% )
186 186
187 1.058135029 seconds time elapsed ( +- 3.089% ) 187 1.058135029 seconds time elapsed ( +- 3.089% )
188 188
diff --git a/tools/perf/Documentation/jit-interface.txt b/tools/perf/Documentation/jit-interface.txt
deleted file mode 100644
index a8656f56491..00000000000
--- a/tools/perf/Documentation/jit-interface.txt
+++ /dev/null
@@ -1,15 +0,0 @@
1perf supports a simple JIT interface to resolve symbols for dynamic code generated
2by a JIT.
3
4The JIT has to write a /tmp/perf-%d.map (%d = pid of process) file
5
6This is a text file.
7
8Each line has the following format, fields separated with spaces:
9
10START SIZE symbolname
11
12START and SIZE are hex numbers without 0x.
13symbolname is the rest of the line, so it could contain special characters.
14
15The ownership of the file has to match the process.
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index c8ffd9fd5c6..85c5f026930 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -22,7 +22,7 @@ OPTIONS
22------- 22-------
23-i:: 23-i::
24--input=:: 24--input=::
25 Input file name. (default: perf.data unless stdin is a fifo) 25 Input file name. (default: perf.data)
26 26
27-d:: 27-d::
28--dsos=<dso[,dso...]>:: 28--dsos=<dso[,dso...]>::
@@ -66,28 +66,12 @@ OPTIONS
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69-C:: 69-c::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of 71 be provided as a comma-separated list with no space: 0,1. Ranges of
72 CPUs are specified with -: 0-2. Default is to report samples on all 72 CPUs are specified with -: 0-2. Default is to report samples on all
73 CPUs. 73 CPUs.
74 74
75--asm-raw::
76 Show raw instruction encoding of assembly instructions.
77
78--source::
79 Interleave source code with assembly code. Enabled by default,
80 disable with --no-source.
81
82--symfs=<directory>::
83 Look for files with symbols relative to this directory.
84
85-M::
86--disassembler-style=:: Set disassembler style for objdump.
87
88--objdump=<path>::
89 Path to objdump binary.
90
91SEE ALSO 75SEE ALSO
92-------- 76--------
93linkperf:perf-record[1], linkperf:perf-report[1] 77linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
index 7065cd6fbdf..a3dbadb26ef 100644
--- a/tools/perf/Documentation/perf-bench.txt
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This 'perf bench' command is a general framework for benchmark suites. 15This 'perf bench' command is general framework for benchmark suites.
16 16
17COMMON OPTIONS 17COMMON OPTIONS
18-------------- 18--------------
@@ -45,20 +45,14 @@ SUBSYSTEM
45'sched':: 45'sched'::
46 Scheduler and IPC mechanisms. 46 Scheduler and IPC mechanisms.
47 47
48'mem'::
49 Memory access performance.
50
51'all'::
52 All benchmark subsystems.
53
54SUITES FOR 'sched' 48SUITES FOR 'sched'
55~~~~~~~~~~~~~~~~~~ 49~~~~~~~~~~~~~~~~~~
56*messaging*:: 50*messaging*::
57Suite for evaluating performance of scheduler and IPC mechanisms. 51Suite for evaluating performance of scheduler and IPC mechanisms.
58Based on hackbench by Rusty Russell. 52Based on hackbench by Rusty Russell.
59 53
60Options of *messaging* 54Options of *pipe*
61^^^^^^^^^^^^^^^^^^^^^^ 55^^^^^^^^^^^^^^^^^
62-p:: 56-p::
63--pipe:: 57--pipe::
64Use pipe() instead of socketpair() 58Use pipe() instead of socketpair()
@@ -121,72 +115,6 @@ Example of *pipe*
121 59004 ops/sec 115 59004 ops/sec
122--------------------- 116---------------------
123 117
124SUITES FOR 'mem'
125~~~~~~~~~~~~~~~~
126*memcpy*::
127Suite for evaluating performance of simple memory copy in various ways.
128
129Options of *memcpy*
130^^^^^^^^^^^^^^^^^^^
131-l::
132--length::
133Specify length of memory to copy (default: 1MB).
134Available units are B, KB, MB, GB and TB (case insensitive).
135
136-r::
137--routine::
138Specify routine to copy (default: default).
139Available routines are depend on the architecture.
140On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported.
141
142-i::
143--iterations::
144Repeat memcpy invocation this number of times.
145
146-c::
147--cycle::
148Use perf's cpu-cycles event instead of gettimeofday syscall.
149
150-o::
151--only-prefault::
152Show only the result with page faults before memcpy.
153
154-n::
155--no-prefault::
156Show only the result without page faults before memcpy.
157
158*memset*::
159Suite for evaluating performance of simple memory set in various ways.
160
161Options of *memset*
162^^^^^^^^^^^^^^^^^^^
163-l::
164--length::
165Specify length of memory to set (default: 1MB).
166Available units are B, KB, MB, GB and TB (case insensitive).
167
168-r::
169--routine::
170Specify routine to set (default: default).
171Available routines are depend on the architecture.
172On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported.
173
174-i::
175--iterations::
176Repeat memset invocation this number of times.
177
178-c::
179--cycle::
180Use perf's cpu-cycles event instead of gettimeofday syscall.
181
182-o::
183--only-prefault::
184Show only the result with page faults before memset.
185
186-n::
187--no-prefault::
188Show only the result without page faults before memset.
189
190SEE ALSO 118SEE ALSO
191-------- 119--------
192linkperf:perf[1] 120linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
index 25c52efcc7f..5eaac6f26d5 100644
--- a/tools/perf/Documentation/perf-buildid-list.txt
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -16,9 +16,6 @@ This command displays the buildids found in a perf.data file, so that other
16tools can be used to fetch packages with matching symbol tables for use by 16tools can be used to fetch packages with matching symbol tables for use by
17perf report. 17perf report.
18 18
19It can also be used to show the build id of the running kernel or in an ELF
20file using -i/--input.
21
22OPTIONS 19OPTIONS
23------- 20-------
24-H:: 21-H::
@@ -26,13 +23,10 @@ OPTIONS
26 Show only DSOs with hits. 23 Show only DSOs with hits.
27-i:: 24-i::
28--input=:: 25--input=::
29 Input file name. (default: perf.data unless stdin is a fifo) 26 Input file name. (default: perf.data)
30-f:: 27-f::
31--force:: 28--force::
32 Don't do ownership validation. 29 Don't do ownership validation.
33-k::
34--kernel::
35 Show running kernel build id.
36-v:: 30-v::
37--verbose:: 31--verbose::
38 Be more verbose. 32 Be more verbose.
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 194f37d635d..74d7481ed7a 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -17,9 +17,6 @@ captured via perf record.
17 17
18If no parameters are passed it will assume perf.data.old and perf.data. 18If no parameters are passed it will assume perf.data.old and perf.data.
19 19
20The differential profile is displayed only for events matching both
21specified perf.data files.
22
23OPTIONS 20OPTIONS
24------- 21-------
25-M:: 22-M::
@@ -72,66 +69,6 @@ OPTIONS
72--symfs=<directory>:: 69--symfs=<directory>::
73 Look for files with symbols relative to this directory. 70 Look for files with symbols relative to this directory.
74 71
75-b::
76--baseline-only::
77 Show only items with match in baseline.
78
79-c::
80--compute::
81 Differential computation selection - delta,ratio,wdiff (default is delta).
82 If '+' is specified as a first character, the output is sorted based
83 on the computation results.
84 See COMPARISON METHODS section for more info.
85
86-p::
87--period::
88 Show period values for both compared hist entries.
89
90-F::
91--formula::
92 Show formula for given computation.
93
94COMPARISON METHODS
95------------------
96delta
97~~~~~
98If specified the 'Delta' column is displayed with value 'd' computed as:
99
100 d = A->period_percent - B->period_percent
101
102with:
103 - A/B being matching hist entry from first/second file specified
104 (or perf.data/perf.data.old) respectively.
105
106 - period_percent being the % of the hist entry period value within
107 single data file
108
109ratio
110~~~~~
111If specified the 'Ratio' column is displayed with value 'r' computed as:
112
113 r = A->period / B->period
114
115with:
116 - A/B being matching hist entry from first/second file specified
117 (or perf.data/perf.data.old) respectively.
118
119 - period being the hist entry period value
120
121wdiff
122~~~~~
123If specified the 'Weighted diff' column is displayed with value 'd' computed as:
124
125 d = B->period * WEIGHT-A - A->period * WEIGHT-B
126
127 - A/B being matching hist entry from first/second file specified
128 (or perf.data/perf.data.old) respectively.
129
130 - period being the hist entry period value
131
132 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
133 behind ':' separator like '-c wdiff:1,2'.
134
135SEE ALSO 72SEE ALSO
136-------- 73--------
137linkperf:perf-record[1] 74linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 15217345c2f..0cada9e053d 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -18,15 +18,7 @@ OPTIONS
18------- 18-------
19-i:: 19-i::
20--input=:: 20--input=::
21 Input file name. (default: perf.data unless stdin is a fifo) 21 Input file name. (default: perf.data)
22
23-F::
24--freq=::
25 Show just the sample frequency used for each event.
26
27-v::
28--verbose=::
29 Show all fields.
30 22
31SEE ALSO 23SEE ALSO
32-------- 24--------
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index a00a34276c5..025630d43cd 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -29,17 +29,6 @@ OPTIONS
29-v:: 29-v::
30--verbose:: 30--verbose::
31 Be more verbose. 31 Be more verbose.
32-i::
33--input=::
34 Input file name. (default: stdin)
35-o::
36--output=::
37 Output file name. (default: stdout)
38-s::
39--sched-stat::
40 Merge sched_stat and sched_switch for getting events where and how long
41 tasks slept. sched_switch contains a callchain where a task slept and
42 sched_stat contains a timeslice how long a task slept.
43 32
44SEE ALSO 33SEE ALSO
45-------- 34--------
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index 7c8fbbf3f61..a52fcde894c 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -23,7 +23,7 @@ OPTIONS
23------- 23-------
24-i <file>:: 24-i <file>::
25--input=<file>:: 25--input=<file>::
26 Select the input file (default: perf.data unless stdin is a fifo) 26 Select the input file (default: perf.data)
27 27
28--caller:: 28--caller::
29 Show per-callsite statistics 29 Show per-callsite statistics
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 326f2cb333c..dd84cb2f0a8 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] 12 [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
13 {top|record|report|diff|buildid-list} 13 {top|record|report|diff|buildid-list}
14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> 14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} 15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list}
16 16
17DESCRIPTION 17DESCRIPTION
18----------- 18-----------
@@ -38,18 +38,6 @@ There are a couple of variants of perf kvm:
38 so that other tools can be used to fetch packages with matching symbol tables 38 so that other tools can be used to fetch packages with matching symbol tables
39 for use by perf report. 39 for use by perf report.
40 40
41 'perf kvm stat <command>' to run a command and gather performance counter
42 statistics.
43 Especially, perf 'kvm stat record/report' generates a statistical analysis
44 of KVM events. Currently, vmexit, mmio and ioport events are supported.
45 'perf kvm stat record <command>' records kvm events and the events between
46 start and end <command>.
47 And this command produces a file which contains tracing results of kvm
48 events.
49
50 'perf kvm stat report' reports statistical data which includes events
51 handled time, samples, and so on.
52
53OPTIONS 41OPTIONS
54------- 42-------
55-i:: 43-i::
@@ -80,21 +68,7 @@ OPTIONS
80--guestvmlinux=<path>:: 68--guestvmlinux=<path>::
81 Guest os kernel vmlinux. 69 Guest os kernel vmlinux.
82 70
83STAT REPORT OPTIONS
84-------------------
85--vcpu=<value>::
86 analyze events which occures on this vcpu. (default: all vcpus)
87
88--events=<value>::
89 events to be analyzed. Possible values: vmexit, mmio, ioport.
90 (default: vmexit)
91-k::
92--key=<value>::
93 Sorting key. Possible values: sample (default, sort by samples
94 number), time (sort by average time).
95
96SEE ALSO 71SEE ALSO
97-------- 72--------
98linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1], 73linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1],
99linkperf:perf-diff[1], linkperf:perf-buildid-list[1], 74linkperf:perf-diff[1], linkperf:perf-buildid-list[1]
100linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index d1e39dc8c81..7a527f7e9da 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -15,43 +15,22 @@ DESCRIPTION
15This command displays the symbolic event types which can be selected in the 15This command displays the symbolic event types which can be selected in the
16various perf commands with the -e option. 16various perf commands with the -e option.
17 17
18[[EVENT_MODIFIERS]]
19EVENT MODIFIERS 18EVENT MODIFIERS
20--------------- 19---------------
21 20
22Events can optionally have a modifer by appending a colon and one or 21Events can optionally have a modifer by appending a colon and one or
23more modifiers. Modifiers allow the user to restrict the events to be 22more modifiers. Modifiers allow the user to restrict when events are
24counted. The following modifiers exist: 23counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
25
26 u - user-space counting
27 k - kernel counting
28 h - hypervisor counting
29 G - guest counting (in KVM guests)
30 H - host counting (not in KVM guests)
31 p - precise level
32 24
33The 'p' modifier can be used for specifying how precise the instruction 25The 'p' modifier can be used for specifying how precise the instruction
34address should be. The 'p' modifier can be specified multiple times: 26address should be. The 'p' modifier is currently only implemented for
35 27Intel PEBS and can be specified multiple times:
36 0 - SAMPLE_IP can have arbitrary skid 28 0 - SAMPLE_IP can have arbitrary skid
37 1 - SAMPLE_IP must have constant skid 29 1 - SAMPLE_IP must have constant skid
38 2 - SAMPLE_IP requested to have 0 skid 30 2 - SAMPLE_IP requested to have 0 skid
39 3 - SAMPLE_IP must have 0 skid 31 3 - SAMPLE_IP must have 0 skid
40
41For Intel systems precise event sampling is implemented with PEBS
42which supports up to precise-level 2.
43 32
44On AMD systems it is implemented using IBS (up to precise-level 2). 33The PEBS implementation now supports up to 2.
45The precise modifier works with event types 0x76 (cpu-cycles, CPU
46clocks not halted) and 0xC1 (micro-ops retired). Both events map to
47IBS execution sampling (IBS op) with the IBS Op Counter Control bit
48(IbsOpCntCtl) set respectively (see AMD64 Architecture Programmer’s
49Manual Volume 2: System Programming, 13.3 Instruction-Based
50Sampling). Examples to use IBS:
51
52 perf record -a -e cpu-cycles:p ... # use ibs op counting cycles
53 perf record -a -e r076:p ... # same as -e cpu-cycles:p
54 perf record -a -e r0C1:p ... # use ibs op counting micro-ops
55 34
56RAW HARDWARE EVENT DESCRIPTOR 35RAW HARDWARE EVENT DESCRIPTOR
57----------------------------- 36-----------------------------
@@ -63,11 +42,6 @@ layout of IA32_PERFEVTSELx MSRs (see [Intel® 64 and IA-32 Architectures Softwar
63of IA32_PERFEVTSELx MSRs) or AMD's PerfEvtSeln (see [AMD64 Architecture Programmer’s Manual Volume 2: System Programming], Page 344, 42of IA32_PERFEVTSELx MSRs) or AMD's PerfEvtSeln (see [AMD64 Architecture Programmer’s Manual Volume 2: System Programming], Page 344,
64Figure 13-7 Performance Event-Select Register (PerfEvtSeln)). 43Figure 13-7 Performance Event-Select Register (PerfEvtSeln)).
65 44
66Note: Only the following bit fields can be set in x86 counter
67registers: event, umask, edge, inv, cmask. Esp. guest/host only and
68OS/user mode flags must be setup using <<EVENT_MODIFIERS, EVENT
69MODIFIERS>>.
70
71Example: 45Example:
72 46
73If the Intel docs for a QM720 Core i7 describe an event as: 47If the Intel docs for a QM720 Core i7 describe an event as:
@@ -115,4 +89,4 @@ SEE ALSO
115linkperf:perf-stat[1], linkperf:perf-top[1], 89linkperf:perf-stat[1], linkperf:perf-top[1],
116linkperf:perf-record[1], 90linkperf:perf-record[1],
117http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide], 91http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide],
118http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming] 92http://support.amd.com/us/Processor_TechDocs/24593.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming]
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
index c7f5f55634a..4a26a2f3a6a 100644
--- a/tools/perf/Documentation/perf-lock.txt
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -8,7 +8,7 @@ perf-lock - Analyze lock events
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf lock' {record|report|script|info} 11'perf lock' {record|report|trace}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -20,19 +20,16 @@ and statistics with this 'perf lock' command.
20 produces the file "perf.data" which contains tracing 20 produces the file "perf.data" which contains tracing
21 results of lock events. 21 results of lock events.
22 22
23 'perf lock report' reports statistical data. 23 'perf lock trace' shows raw lock events.
24
25 'perf lock script' shows raw lock events.
26 24
27 'perf lock info' shows metadata like threads or addresses 25 'perf lock report' reports statistical data.
28 of lock instances.
29 26
30COMMON OPTIONS 27COMMON OPTIONS
31-------------- 28--------------
32 29
33-i:: 30-i::
34--input=<file>:: 31--input=<file>::
35 Input file name. (default: perf.data unless stdin is a fifo) 32 Input file name.
36 33
37-v:: 34-v::
38--verbose:: 35--verbose::
@@ -50,17 +47,6 @@ REPORT OPTIONS
50 Sorting key. Possible values: acquired (default), contended, 47 Sorting key. Possible values: acquired (default), contended,
51 wait_total, wait_max, wait_min. 48 wait_total, wait_max, wait_min.
52 49
53INFO OPTIONS
54------------
55
56-t::
57--threads::
58 dump thread list in perf.data
59
60-m::
61--map::
62 dump map of lock instances (address:name table)
63
64SEE ALSO 50SEE ALSO
65-------- 51--------
66linkperf:perf[1] 52linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index b715cb71592..2780d9ce48b 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -77,8 +77,7 @@ OPTIONS
77 77
78-F:: 78-F::
79--funcs:: 79--funcs::
80 Show available functions in given module or kernel. With -x/--exec, 80 Show available functions in given module or kernel.
81 can also list functions in a user space executable / shared library.
82 81
83--filter=FILTER:: 82--filter=FILTER::
84 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob 83 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -99,15 +98,6 @@ OPTIONS
99--max-probes:: 98--max-probes::
100 Set the maximum number of probe points for an event. Default is 128. 99 Set the maximum number of probe points for an event. Default is 128.
101 100
102-x::
103--exec=PATH::
104 Specify path to the executable or shared library file for user
105 space tracing. Can also be used with --funcs option.
106
107In absence of -m/-x options, perf probe checks if the first argument after
108the options is an absolute path name. If its an absolute path, perf probe
109uses it as a target module/target user space binary to probe.
110
111PROBE SYNTAX 101PROBE SYNTAX
112------------ 102------------
113Probe points are defined by following syntax. 103Probe points are defined by following syntax.
@@ -192,13 +182,6 @@ Delete all probes on schedule().
192 182
193 ./perf probe --del='schedule*' 183 ./perf probe --del='schedule*'
194 184
195Add probes at zfree() function on /bin/zsh
196
197 ./perf probe -x /bin/zsh zfree or ./perf probe /bin/zsh zfree
198
199Add probes at malloc() function on libc
200
201 ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc
202 185
203SEE ALSO 186SEE ALSO
204-------- 187--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 938e8904f64..5a520f82529 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -52,15 +52,11 @@ OPTIONS
52 52
53-p:: 53-p::
54--pid=:: 54--pid=::
55 Record events on existing process ID (comma separated list). 55 Record events on existing process ID.
56 56
57-t:: 57-t::
58--tid=:: 58--tid=::
59 Record events on existing thread ID (comma separated list). 59 Record events on existing thread ID.
60
61-u::
62--uid=::
63 Record events in threads owned by uid. Name or number.
64 60
65-r:: 61-r::
66--realtime=:: 62--realtime=::
@@ -93,7 +89,7 @@ OPTIONS
93 89
94-m:: 90-m::
95--mmap-pages=:: 91--mmap-pages=::
96 Number of mmap data pages. Must be a power of two. 92 Number of mmap data pages.
97 93
98-g:: 94-g::
99--call-graph:: 95--call-graph::
@@ -152,36 +148,6 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
152corresponding events, i.e., they always refer to events defined earlier on the command 148corresponding events, i.e., they always refer to events defined earlier on the command
153line. 149line.
154 150
155-b::
156--branch-any::
157Enable taken branch stack sampling. Any type of taken branch may be sampled.
158This is a shortcut for --branch-filter any. See --branch-filter for more infos.
159
160-j::
161--branch-filter::
162Enable taken branch stack sampling. Each sample captures a series of consecutive
163taken branches. The number of branches captured with each sample depends on the
164underlying hardware, the type of branches of interest, and the executed code.
165It is possible to select the types of branches captured by enabling filters. The
166following filters are defined:
167
168 - any: any type of branches
169 - any_call: any function call or system call
170 - any_ret: any function return or system call return
171 - ind_call: any indirect branch
172 - u: only when the branch target is at the user level
173 - k: only when the branch target is in the kernel
174 - hv: only when the target is at the hypervisor level
175
176+
177The option requires at least one branch type among any, any_call, any_ret, ind_call.
178The privilege levels may be omitted, in which case, the privilege levels of the associated
179event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
180levels are subject to permissions. When sampling on multiple events, branch stack sampling
181is enabled for all the sampling events. The sampled branch type is the same for all events.
182The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
183Note that this feature may not be available on all processors.
184
185SEE ALSO 151SEE ALSO
186-------- 152--------
187linkperf:perf-stat[1], linkperf:perf-list[1] 153linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index f4d91bebd59..04253c07d19 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -19,7 +19,7 @@ OPTIONS
19------- 19-------
20-i:: 20-i::
21--input=:: 21--input=::
22 Input file name. (default: perf.data unless stdin is a fifo) 22 Input file name. (default: perf.data)
23 23
24-v:: 24-v::
25--verbose:: 25--verbose::
@@ -39,7 +39,7 @@ OPTIONS
39-T:: 39-T::
40--threads:: 40--threads::
41 Show per-thread event counters 41 Show per-thread event counters
42-c:: 42-C::
43--comms=:: 43--comms=::
44 Only consider symbols in these comms. CSV that understands 44 Only consider symbols in these comms. CSV that understands
45 file://filename entries. 45 file://filename entries.
@@ -48,16 +48,13 @@ OPTIONS
48 Only consider these symbols. CSV that understands 48 Only consider these symbols. CSV that understands
49 file://filename entries. 49 file://filename entries.
50 50
51--symbol-filter=::
52 Only show symbols that match (partially) with this filter.
53
54-U:: 51-U::
55--hide-unresolved:: 52--hide-unresolved::
56 Only display entries resolved to a symbol. 53 Only display entries resolved to a symbol.
57 54
58-s:: 55-s::
59--sort=:: 56--sort=::
60 Sort by key(s): pid, comm, dso, symbol, parent, srcline. 57 Sort by key(s): pid, comm, dso, symbol, parent.
61 58
62-p:: 59-p::
63--parent=<regex>:: 60--parent=<regex>::
@@ -83,10 +80,9 @@ OPTIONS
83--dump-raw-trace:: 80--dump-raw-trace::
84 Dump raw trace in ASCII. 81 Dump raw trace in ASCII.
85 82
86-g [type,min[,limit],order]:: 83-g [type,min,order]::
87--call-graph:: 84--call-graph::
88 Display call chains using type, min percent threshold, optional print 85 Display call chains using type, min percent threshold and order.
89 limit and order.
90 type can be either: 86 type can be either:
91 - flat: single column, linear exposure of call chains. 87 - flat: single column, linear exposure of call chains.
92 - graph: use a graph tree, displaying absolute overhead rates. 88 - graph: use a graph tree, displaying absolute overhead rates.
@@ -113,8 +109,6 @@ OPTIONS
113 requires a tty, if one is not present, as when piping to other 109 requires a tty, if one is not present, as when piping to other
114 commands, the stdio interface is used. 110 commands, the stdio interface is used.
115 111
116--gtk:: Use the GTK2 interface.
117
118-k:: 112-k::
119--vmlinux=<file>:: 113--vmlinux=<file>::
120 vmlinux pathname 114 vmlinux pathname
@@ -134,43 +128,12 @@ OPTIONS
134--symfs=<directory>:: 128--symfs=<directory>::
135 Look for files with symbols relative to this directory. 129 Look for files with symbols relative to this directory.
136 130
137-C:: 131-c::
138--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 132--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
139 be provided as a comma-separated list with no space: 0,1. Ranges of 133 be provided as a comma-separated list with no space: 0,1. Ranges of
140 CPUs are specified with -: 0-2. Default is to report samples on all 134 CPUs are specified with -: 0-2. Default is to report samples on all
141 CPUs. 135 CPUs.
142 136
143-M::
144--disassembler-style=:: Set disassembler style for objdump.
145
146--source::
147 Interleave source code with assembly code. Enabled by default,
148 disable with --no-source.
149
150--asm-raw::
151 Show raw instruction encoding of assembly instructions.
152
153--show-total-period:: Show a column with the sum of periods.
154
155-I::
156--show-info::
157 Display extended information about the perf.data file. This adds
158 information which may be very large and thus may clutter the display.
159 It currently includes: cpu and numa topology of the host system.
160
161-b::
162--branch-stack::
163 Use the addresses of sampled taken branches instead of the instruction
164 address to build the histograms. To generate meaningful output, the
165 perf.data file must have been obtained using perf record -b or
166 perf record --branch-filter xxx where xxx is a branch filter option.
167 perf report is able to auto-detect whether a perf.data file contains
168 branch stacks and it will automatically switch to the branch view mode,
169 unless --no-branch-stack is used.
170
171--objdump=<path>::
172 Path to objdump binary.
173
174SEE ALSO 137SEE ALSO
175-------- 138--------
176linkperf:perf-stat[1], linkperf:perf-annotate[1] 139linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 8ff4df95695..46822d5fde1 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -8,7 +8,7 @@ perf-sched - Tool to trace/measure scheduler properties (latencies)
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf sched' {record|latency|map|replay|script} 11'perf sched' {record|latency|map|replay|trace}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -20,8 +20,8 @@ There are five variants of perf sched:
20 'perf sched latency' to report the per task scheduling latencies 20 'perf sched latency' to report the per task scheduling latencies
21 and other scheduling properties of the workload. 21 and other scheduling properties of the workload.
22 22
23 'perf sched script' to see a detailed trace of the workload that 23 'perf sched trace' to see a detailed trace of the workload that
24 was recorded (aliased to 'perf script' for now). 24 was recorded.
25 25
26 'perf sched replay' to simulate the workload that was recorded 26 'perf sched replay' to simulate the workload that was recorded
27 via perf sched record. (this is done by starting up mockup threads 27 via perf sched record. (this is done by starting up mockup threads
@@ -40,7 +40,7 @@ OPTIONS
40------- 40-------
41-i:: 41-i::
42--input=<file>:: 42--input=<file>::
43 Input file name. (default: perf.data unless stdin is a fifo) 43 Input file name. (default: perf.data)
44 44
45-v:: 45-v::
46--verbose:: 46--verbose::
diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
index d00bef23134..3152cca1550 100644
--- a/tools/perf/Documentation/perf-script-perl.txt
+++ b/tools/perf/Documentation/perf-script-perl.txt
@@ -116,8 +116,8 @@ search path and 'use'ing a few support modules (see module
116descriptions below): 116descriptions below):
117 117
118---- 118----
119 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; 119 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/perf-script-Util/lib";
120 use lib "./Perf-Trace-Util/lib"; 120 use lib "./perf-script-Util/lib";
121 use Perf::Trace::Core; 121 use Perf::Trace::Core;
122 use Perf::Trace::Context; 122 use Perf::Trace::Context;
123 use Perf::Trace::Util; 123 use Perf::Trace::Util;
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index a4027f221a5..47102206911 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -129,7 +129,7 @@ import os
129import sys 129import sys
130 130
131sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 131sys.path.append(os.environ['PERF_EXEC_PATH'] + \
132 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 132 '/scripts/python/perf-script-Util/lib/Perf/Trace')
133 133
134from perf_trace_context import * 134from perf_trace_context import *
135from Core import * 135from Core import *
@@ -216,7 +216,7 @@ import os
216import sys 216import sys
217 217
218sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 218sys.path.append(os.environ['PERF_EXEC_PATH'] + \
219 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 219 '/scripts/python/perf-script-Util/lib/Perf/Trace')
220 220
221from perf_trace_context import * 221from perf_trace_context import *
222from Core import * 222from Core import *
@@ -279,7 +279,7 @@ import os
279import sys 279import sys
280 280
281sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 281sys.path.append(os.environ['PERF_EXEC_PATH'] + \
282 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 282 '/scripts/python/perf-script-Util/lib/Perf/Trace')
283 283
284from perf_trace_context import * 284from perf_trace_context import *
285from Core import * 285from Core import *
@@ -391,7 +391,7 @@ drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
391drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 .. 391drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
392drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin 392drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
393-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py 393-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util 394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 perf-script-Util
395-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py 395-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
396---- 396----
397 397
@@ -518,7 +518,7 @@ descriptions below):
518 import sys 518 import sys
519 519
520 sys.path.append(os.environ['PERF_EXEC_PATH'] + \ 520 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
521 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 521 '/scripts/python/perf-script-Util/lib/Perf/Trace')
522 522
523 from perf_trace_context import * 523 from perf_trace_context import *
524 from Core import * 524 from Core import *
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index e9cbfcddfa3..db017867d9e 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -106,7 +106,7 @@ OPTIONS
106 106
107-i:: 107-i::
108--input=:: 108--input=::
109 Input file name. (default: perf.data unless stdin is a fifo) 109 Input file name.
110 110
111-d:: 111-d::
112--debug-mode:: 112--debug-mode::
@@ -115,7 +115,7 @@ OPTIONS
115-f:: 115-f::
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.
119 Field list can be prepended with the type, trace, sw or hw, 119 Field list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies. 120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace 121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
@@ -182,27 +182,12 @@ OPTIONS
182--hide-call-graph:: 182--hide-call-graph::
183 When printing symbols do not display call chain. 183 When printing symbols do not display call chain.
184 184
185-C:: 185-c::
186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
187 be provided as a comma-separated list with no space: 0,1. Ranges of 187 be provided as a comma-separated list with no space: 0,1. Ranges of
188 CPUs are specified with -: 0-2. Default is to report samples on all 188 CPUs are specified with -: 0-2. Default is to report samples on all
189 CPUs. 189 CPUs.
190 190
191-c::
192--comms=::
193 Only display events for these comms. CSV that understands
194 file://filename entries.
195
196-I::
197--show-info::
198 Display extended information about the perf.data file. This adds
199 information which may be very large and thus may clutter the display.
200 It currently includes: cpu and numa topology of the host system.
201 It can only be used with the perf script report mode.
202
203--show-kernel-path::
204 Try to resolve the path of [kernel.kallsyms]
205
206SEE ALSO 191SEE ALSO
207-------- 192--------
208linkperf:perf-record[1], linkperf:perf-script-perl[1], 193linkperf: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 cf0c3107e06..918cc38ee6d 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -35,11 +35,11 @@ OPTIONS
35 child tasks do not inherit counters 35 child tasks do not inherit counters
36-p:: 36-p::
37--pid=<pid>:: 37--pid=<pid>::
38 stat events on existing process id (comma separated list) 38 stat events on existing process id
39 39
40-t:: 40-t::
41--tid=<tid>:: 41--tid=<tid>::
42 stat events on existing thread id (comma separated list) 42 stat events on existing thread id
43 43
44 44
45-a:: 45-a::
@@ -94,27 +94,6 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
94corresponding events, i.e., they always refer to events defined earlier on the command 94corresponding events, i.e., they always refer to events defined earlier on the command
95line. 95line.
96 96
97-o file::
98--output file::
99Print the output into the designated file.
100
101--append::
102Append to the output file designated with the -o option. Ignored if -o is not specified.
103
104--log-fd::
105
106Log output to fd, instead of stderr. Complementary to --output, and mutually exclusive
107with it. --append may be used here. Examples:
108 3>results perf stat --log-fd 3 -- $cmd
109 3>>results perf stat --log-fd 3 --append -- $cmd
110
111--pre::
112--post::
113 Pre and post measurement hooks, e.g.:
114
115perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage
116
117
118EXAMPLES 97EXAMPLES
119-------- 98--------
120 99
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index b24ac40fcd5..2c3b462f64b 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -8,19 +8,13 @@ perf-test - Runs sanity tests.
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]' 11'perf test <options>'
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command does assorted sanity tests, initially through linked routines but 15This command does assorted sanity tests, initially through linked routines but
16also will look for a directory with more tests in the form of scripts. 16also will look for a directory with more tests in the form of scripts.
17 17
18To get a list of available tests use 'perf test list', specifying a test name
19fragment will show all tests that have it.
20
21To run just specific tests, inform test name fragments or the numbers obtained
22from 'perf test list'.
23
24OPTIONS 18OPTIONS
25------- 19-------
26-v:: 20-v::
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 1632b0efc75..d7b79e2ba2a 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -27,7 +27,7 @@ OPTIONS
27 Select the output file (default: output.svg) 27 Select the output file (default: output.svg)
28-i:: 28-i::
29--input=:: 29--input=::
30 Select the input file (default: perf.data unless stdin is a fifo) 30 Select the input file (default: perf.data)
31-w:: 31-w::
32--width=:: 32--width=::
33 Select the width of the SVG file (default: 1000) 33 Select the width of the SVG file (default: 1000)
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 5b80d84d6b4..f6eb1cdafb7 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -72,15 +72,11 @@ Default is to monitor all CPUS.
72 72
73-p <pid>:: 73-p <pid>::
74--pid=<pid>:: 74--pid=<pid>::
75 Profile events on existing Process ID (comma separated list). 75 Profile events on existing Process ID.
76 76
77-t <tid>:: 77-t <tid>::
78--tid=<tid>:: 78--tid=<tid>::
79 Profile events on existing thread ID (comma separated list). 79 Profile events on existing thread ID.
80
81-u::
82--uid=::
83 Record events in threads owned by uid. Name or number.
84 80
85-r <priority>:: 81-r <priority>::
86--realtime=<priority>:: 82--realtime=<priority>::
@@ -110,51 +106,6 @@ Default is to monitor all CPUS.
110--zero:: 106--zero::
111 Zero history across display updates. 107 Zero history across display updates.
112 108
113-s::
114--sort::
115 Sort by key(s): pid, comm, dso, symbol, parent, srcline.
116
117-n::
118--show-nr-samples::
119 Show a column with the number of samples.
120
121--show-total-period::
122 Show a column with the sum of periods.
123
124--dsos::
125 Only consider symbols in these dsos.
126
127--comms::
128 Only consider symbols in these comms.
129
130--symbols::
131 Only consider these symbols.
132
133-M::
134--disassembler-style=:: Set disassembler style for objdump.
135
136--source::
137 Interleave source code with assembly code. Enabled by default,
138 disable with --no-source.
139
140--asm-raw::
141 Show raw instruction encoding of assembly instructions.
142
143-G [type,min,order]::
144--call-graph::
145 Display call chains using type, min percent threshold and order.
146 type can be either:
147 - flat: single column, linear exposure of call chains.
148 - graph: use a graph tree, displaying absolute overhead rates.
149 - fractal: like graph, but displays relative rates. Each branch of
150 the tree is considered as a new profiled object.
151
152 order can be either:
153 - callee: callee based call graph.
154 - caller: inverted caller based call graph.
155
156 Default: fractal,0.5,callee.
157
158INTERACTIVE PROMPTING KEYS 109INTERACTIVE PROMPTING KEYS
159-------------------------- 110--------------------------
160 111
@@ -179,6 +130,9 @@ INTERACTIVE PROMPTING KEYS
179[S]:: 130[S]::
180 Stop annotation, return to full profile display. 131 Stop annotation, return to full profile display.
181 132
133[w]::
134 Toggle between weighted sum and individual count[E]r profile.
135
182[z]:: 136[z]::
183 Toggle event count zeroing across display updates. 137 Toggle event count zeroing across display updates.
184 138
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
deleted file mode 100644
index 68718ccdd17..00000000000
--- a/tools/perf/Documentation/perf-trace.txt
+++ /dev/null
@@ -1,59 +0,0 @@
1perf-trace(1)
2=============
3
4NAME
5----
6perf-trace - strace inspired tool
7
8SYNOPSIS
9--------
10[verse]
11'perf trace'
12
13DESCRIPTION
14-----------
15This command will show the events associated with the target, initially
16syscalls, but other system events like pagefaults, task lifetime events,
17scheduling events, etc.
18
19Initially this is a live mode only tool, but eventually will work with
20perf.data files like the other tools, allowing a detached 'record' from
21analysis phases.
22
23OPTIONS
24-------
25
26--all-cpus::
27 System-wide collection from all CPUs.
28
29-p::
30--pid=::
31 Record events on existing process ID (comma separated list).
32
33--tid=::
34 Record events on existing thread ID (comma separated list).
35
36--uid=::
37 Record events in threads owned by uid. Name or number.
38
39--no-inherit::
40 Child tasks do not inherit counters.
41
42--mmap-pages=::
43 Number of mmap data pages. Must be a power of two.
44
45--cpu::
46Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
47comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
48In per-thread mode with inheritance mode on (default), Events are captured only when
49the thread executes on the designated CPUs. Default is to monitor all CPUs.
50
51--duration:
52 Show only events that had a duration greater than N.M ms.
53
54--sched:
55 Accrue thread runtime and provide a summary at the end of the session.
56
57SEE ALSO
58--------
59linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
deleted file mode 100644
index 767ea2436e1..00000000000
--- a/tools/perf/Documentation/perfconfig.example
+++ /dev/null
@@ -1,29 +0,0 @@
1[colors]
2
3 # These were the old defaults
4 top = red, lightgray
5 medium = green, lightgray
6 normal = black, lightgray
7 selected = lightgray, magenta
8 code = blue, lightgray
9 addr = magenta, lightgray
10
11[tui]
12
13 # Defaults if linked with libslang
14 report = on
15 annotate = on
16 top = on
17
18[buildid]
19
20 # Default, disable using /dev/null
21 dir = /root/.debug
22
23[annotate]
24
25 # Defaults
26 hide_src_code = false
27 use_offset = true
28 jump_arrows = true
29 show_nr_jumps = false
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 80db3f4bcf7..c12659d8cb2 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,7 +1,4 @@
1tools/perf 1tools/perf
2tools/scripts
3tools/lib/traceevent
4include/linux/const.h
5include/linux/perf_event.h 2include/linux/perf_event.h
6include/linux/rbtree.h 3include/linux/rbtree.h
7include/linux/list.h 4include/linux/list.h
@@ -10,12 +7,7 @@ include/linux/stringify.h
10lib/rbtree.c 7lib/rbtree.c
11include/linux/swab.h 8include/linux/swab.h
12arch/*/include/asm/unistd*.h 9arch/*/include/asm/unistd*.h
13arch/*/include/asm/perf_regs.h
14arch/*/lib/memcpy*.S 10arch/*/lib/memcpy*.S
15arch/*/lib/memset*.S
16include/linux/poison.h 11include/linux/poison.h
17include/linux/magic.h 12include/linux/magic.h
18include/linux/hw_breakpoint.h 13include/linux/hw_breakpoint.h
19arch/x86/include/asm/svm.h
20arch/x86/include/asm/vmx.h
21arch/x86/include/asm/kvm_host.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 891bc77bdb2..e9d5c271db6 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,22 +1,20 @@
1include ../scripts/Makefile.include 1ifeq ("$(origin O)", "command line")
2 OUTPUT := $(O)/
3endif
2 4
3# The default target of this Makefile is... 5# The default target of this Makefile is...
4all: 6all:
5 7
6include config/utilities.mak 8include config/utilities.mak
7 9
10ifneq ($(OUTPUT),)
11# check that the output directory actually exists
12OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
13$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
14endif
15
8# Define V to have a more verbose compile. 16# Define V to have a more verbose compile.
9# 17#
10# Define O to save output files in a separate directory.
11#
12# Define ARCH as name of target architecture if you want cross-builds.
13#
14# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
15#
16# Define NO_LIBPERL to disable perl script extension.
17#
18# Define NO_LIBPYTHON to disable python script extension.
19#
20# Define PYTHON to point to the python binary if the default 18# Define PYTHON to point to the python binary if the default
21# `python' is not correct; for example: PYTHON=python2 19# `python' is not correct; for example: PYTHON=python2
22# 20#
@@ -34,19 +32,6 @@ include config/utilities.mak
34# Define NO_DWARF if you do not want debug-info analysis feature at all. 32# Define NO_DWARF if you do not want debug-info analysis feature at all.
35# 33#
36# Define WERROR=0 to disable treating any warnings as errors. 34# Define WERROR=0 to disable treating any warnings as errors.
37#
38# Define NO_NEWT if you do not want TUI support.
39#
40# Define NO_GTK2 if you do not want GTK+ GUI support.
41#
42# Define NO_DEMANGLE if you do not want C++ symbol demangling.
43#
44# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds)
45#
46# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf
47# backtrace post unwind.
48#
49# Define NO_BACKTRACE if you do not want stack backtrace debug feature
50 35
51$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 36$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
52 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 37 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@@ -59,30 +44,25 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
59 -e s/s390x/s390/ -e s/parisc64/parisc/ \ 44 -e s/s390x/s390/ -e s/parisc64/parisc/ \
60 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ 45 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
61 -e s/sh[234].*/sh/ ) 46 -e s/sh[234].*/sh/ )
62NO_PERF_REGS := 1
63 47
64CC = $(CROSS_COMPILE)gcc 48CC = $(CROSS_COMPILE)gcc
65AR = $(CROSS_COMPILE)ar 49AR = $(CROSS_COMPILE)ar
66 50
67# Additional ARCH settings for x86 51# Additional ARCH settings for x86
68ifeq ($(ARCH),i386) 52ifeq ($(ARCH),i386)
69 override ARCH := x86 53 ARCH := x86
70 NO_PERF_REGS := 0
71 LIBUNWIND_LIBS = -lunwind -lunwind-x86
72endif 54endif
73ifeq ($(ARCH),x86_64) 55ifeq ($(ARCH),x86_64)
74 override ARCH := x86 56 ARCH := x86
75 IS_X86_64 := 0 57 IS_X86_64 := 0
76 ifeq (, $(findstring m32,$(EXTRA_CFLAGS))) 58 ifeq (, $(findstring m32,$(EXTRA_CFLAGS)))
77 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) 59 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -xc - | tail -n 1)
78 endif 60 endif
79 ifeq (${IS_X86_64}, 1) 61 ifeq (${IS_X86_64}, 1)
80 RAW_ARCH := x86_64 62 RAW_ARCH := x86_64
81 ARCH_CFLAGS := -DARCH_X86_64 63 ARCH_CFLAGS := -DARCH_X86_64
82 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S 64 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
83 endif 65 endif
84 NO_PERF_REGS := 0
85 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
86endif 66endif
87 67
88# Treat warnings as errors unless directed not to 68# Treat warnings as errors unless directed not to
@@ -90,22 +70,41 @@ ifneq ($(WERROR),0)
90 CFLAGS_WERROR := -Werror 70 CFLAGS_WERROR := -Werror
91endif 71endif
92 72
73#
74# Include saner warnings here, which can catch bugs:
75#
76
77EXTRA_WARNINGS := -Wformat
78EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
79EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
80EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
81EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
82EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
83EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
84EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
85EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
86EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
87EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
88EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
89EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
90EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
91EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
92EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
93EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
94EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
95EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
96EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
97
93ifeq ("$(origin DEBUG)", "command line") 98ifeq ("$(origin DEBUG)", "command line")
94 PERF_DEBUG = $(DEBUG) 99 PERF_DEBUG = $(DEBUG)
95endif 100endif
96ifndef PERF_DEBUG 101ifndef PERF_DEBUG
97 CFLAGS_OPTIMIZE = -O6 -D_FORTIFY_SOURCE=2 102 CFLAGS_OPTIMIZE = -O6
98endif
99
100ifdef PARSER_DEBUG
101 PARSER_DEBUG_BISON := -t
102 PARSER_DEBUG_FLEX := -d
103 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
104endif 103endif
105 104
106CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS) 105CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
107EXTLIBS = -lpthread -lrt -lelf -lm 106EXTLIBS = -lpthread -lrt -lelf -lm
108ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 107ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
109ALL_LDFLAGS = $(LDFLAGS) 108ALL_LDFLAGS = $(LDFLAGS)
110STRIP ?= strip 109STRIP ?= strip
111 110
@@ -155,58 +154,26 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
155 154
156-include config/feature-tests.mak 155-include config/feature-tests.mak
157 156
158ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) 157ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
159 CFLAGS := $(CFLAGS) -fstack-protector-all 158 CFLAGS := $(CFLAGS) -fstack-protector-all
160endif 159endif
161 160
162ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y) 161ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y)
163 CFLAGS := $(CFLAGS) -Wstack-protector 162 CFLAGS := $(CFLAGS) -Wstack-protector
164endif 163endif
165 164
166ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y) 165ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y)
167 CFLAGS := $(CFLAGS) -Wvolatile-register-var 166 CFLAGS := $(CFLAGS) -Wvolatile-register-var
168endif 167endif
169 168
170### --- END CONFIGURATION SECTION --- 169### --- END CONFIGURATION SECTION ---
171 170
172ifeq ($(srctree),) 171# Those must not be GNU-specific; they are shared with perl/ which may
173srctree := $(patsubst %/,%,$(dir $(shell pwd))) 172# be built by a different compiler. (Note that this is an artifact now
174srctree := $(patsubst %/,%,$(dir $(srctree))) 173# but it still might be nice to keep that distinction.)
175#$(info Determined 'srctree' to be $(srctree)) 174BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include
176endif
177
178ifneq ($(objtree),)
179#$(info Determined 'objtree' to be $(objtree))
180endif
181
182ifneq ($(OUTPUT),)
183#$(info Determined 'OUTPUT' to be $(OUTPUT))
184endif
185
186BASIC_CFLAGS = \
187 -Iutil/include \
188 -Iarch/$(ARCH)/include \
189 $(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
190 -I$(srctree)/arch/$(ARCH)/include/uapi \
191 -I$(srctree)/arch/$(ARCH)/include \
192 $(if $(objtree),-I$(objtree)/include/generated/uapi) \
193 -I$(srctree)/include/uapi \
194 -I$(srctree)/include \
195 -I$(OUTPUT)util \
196 -Iutil \
197 -I. \
198 -I$(TRACE_EVENT_DIR) \
199 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
200
201BASIC_LDFLAGS = 175BASIC_LDFLAGS =
202 176
203ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
204 BIONIC := 1
205 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
206 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
207 BASIC_CFLAGS += -I.
208endif
209
210# Guard against environment variables 177# Guard against environment variables
211BUILTIN_OBJS = 178BUILTIN_OBJS =
212LIB_H = 179LIB_H =
@@ -219,23 +186,7 @@ SCRIPT_SH += perf-archive.sh
219grep-libs = $(filter -l%,$(1)) 186grep-libs = $(filter -l%,$(1))
220strip-libs = $(filter-out -l%,$(1)) 187strip-libs = $(filter-out -l%,$(1))
221 188
222TRACE_EVENT_DIR = ../lib/traceevent/ 189$(OUTPUT)python/perf.so: $(PYRF_OBJS)
223
224ifneq ($(OUTPUT),)
225 TE_PATH=$(OUTPUT)
226else
227 TE_PATH=$(TRACE_EVENT_DIR)
228endif
229
230LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
231TE_LIB := -L$(TE_PATH) -ltraceevent
232
233PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
234PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
235
236export LIBTRACEEVENT
237
238$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
239 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 190 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
240 --quiet build_ext; \ 191 --quiet build_ext; \
241 mkdir -p $(OUTPUT)python && \ 192 mkdir -p $(OUTPUT)python && \
@@ -269,30 +220,12 @@ endif
269 220
270export PERL_PATH 221export PERL_PATH
271 222
272FLEX = flex
273BISON= bison
274
275$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
276 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
277
278$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
279 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
280
281$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
282 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
283
284$(OUTPUT)util/pmu-bison.c: util/pmu.y
285 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c
286
287$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
288$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
289
290LIB_FILE=$(OUTPUT)libperf.a 223LIB_FILE=$(OUTPUT)libperf.a
291 224
292LIB_H += ../../include/uapi/linux/perf_event.h 225LIB_H += ../../include/linux/perf_event.h
293LIB_H += ../../include/linux/rbtree.h 226LIB_H += ../../include/linux/rbtree.h
294LIB_H += ../../include/linux/list.h 227LIB_H += ../../include/linux/list.h
295LIB_H += ../../include/uapi/linux/const.h 228LIB_H += ../../include/linux/const.h
296LIB_H += ../../include/linux/hash.h 229LIB_H += ../../include/linux/hash.h
297LIB_H += ../../include/linux/stringify.h 230LIB_H += ../../include/linux/stringify.h
298LIB_H += util/include/linux/bitmap.h 231LIB_H += util/include/linux/bitmap.h
@@ -302,12 +235,10 @@ LIB_H += util/include/linux/const.h
302LIB_H += util/include/linux/ctype.h 235LIB_H += util/include/linux/ctype.h
303LIB_H += util/include/linux/kernel.h 236LIB_H += util/include/linux/kernel.h
304LIB_H += util/include/linux/list.h 237LIB_H += util/include/linux/list.h
305LIB_H += util/include/linux/export.h 238LIB_H += util/include/linux/module.h
306LIB_H += util/include/linux/magic.h
307LIB_H += util/include/linux/poison.h 239LIB_H += util/include/linux/poison.h
308LIB_H += util/include/linux/prefetch.h 240LIB_H += util/include/linux/prefetch.h
309LIB_H += util/include/linux/rbtree.h 241LIB_H += util/include/linux/rbtree.h
310LIB_H += util/include/linux/rbtree_augmented.h
311LIB_H += util/include/linux/string.h 242LIB_H += util/include/linux/string.h
312LIB_H += util/include/linux/types.h 243LIB_H += util/include/linux/types.h
313LIB_H += util/include/linux/linkage.h 244LIB_H += util/include/linux/linkage.h
@@ -321,8 +252,6 @@ LIB_H += util/include/asm/uaccess.h
321LIB_H += util/include/dwarf-regs.h 252LIB_H += util/include/dwarf-regs.h
322LIB_H += util/include/asm/dwarf2.h 253LIB_H += util/include/asm/dwarf2.h
323LIB_H += util/include/asm/cpufeature.h 254LIB_H += util/include/asm/cpufeature.h
324LIB_H += util/include/asm/unistd_32.h
325LIB_H += util/include/asm/unistd_64.h
326LIB_H += perf.h 255LIB_H += perf.h
327LIB_H += util/annotate.h 256LIB_H += util/annotate.h
328LIB_H += util/cache.h 257LIB_H += util/cache.h
@@ -330,15 +259,12 @@ LIB_H += util/callchain.h
330LIB_H += util/build-id.h 259LIB_H += util/build-id.h
331LIB_H += util/debug.h 260LIB_H += util/debug.h
332LIB_H += util/debugfs.h 261LIB_H += util/debugfs.h
333LIB_H += util/sysfs.h
334LIB_H += util/pmu.h
335LIB_H += util/event.h 262LIB_H += util/event.h
336LIB_H += util/evsel.h 263LIB_H += util/evsel.h
337LIB_H += util/evlist.h 264LIB_H += util/evlist.h
338LIB_H += util/exec_cmd.h 265LIB_H += util/exec_cmd.h
339LIB_H += util/types.h 266LIB_H += util/types.h
340LIB_H += util/levenshtein.h 267LIB_H += util/levenshtein.h
341LIB_H += util/machine.h
342LIB_H += util/map.h 268LIB_H += util/map.h
343LIB_H += util/parse-options.h 269LIB_H += util/parse-options.h
344LIB_H += util/parse-events.h 270LIB_H += util/parse-events.h
@@ -352,10 +278,8 @@ LIB_H += util/strbuf.h
352LIB_H += util/strlist.h 278LIB_H += util/strlist.h
353LIB_H += util/strfilter.h 279LIB_H += util/strfilter.h
354LIB_H += util/svghelper.h 280LIB_H += util/svghelper.h
355LIB_H += util/tool.h
356LIB_H += util/run-command.h 281LIB_H += util/run-command.h
357LIB_H += util/sigchain.h 282LIB_H += util/sigchain.h
358LIB_H += util/dso.h
359LIB_H += util/symbol.h 283LIB_H += util/symbol.h
360LIB_H += util/color.h 284LIB_H += util/color.h
361LIB_H += util/values.h 285LIB_H += util/values.h
@@ -372,14 +296,6 @@ LIB_H += util/cpumap.h
372LIB_H += util/top.h 296LIB_H += util/top.h
373LIB_H += $(ARCH_INCLUDE) 297LIB_H += $(ARCH_INCLUDE)
374LIB_H += util/cgroup.h 298LIB_H += util/cgroup.h
375LIB_H += $(TRACE_EVENT_DIR)event-parse.h
376LIB_H += util/target.h
377LIB_H += util/rblist.h
378LIB_H += util/intlist.h
379LIB_H += util/perf_regs.h
380LIB_H += util/unwind.h
381LIB_H += ui/helpline.h
382LIB_H += util/vdso.h
383 299
384LIB_OBJS += $(OUTPUT)util/abspath.o 300LIB_OBJS += $(OUTPUT)util/abspath.o
385LIB_OBJS += $(OUTPUT)util/alias.o 301LIB_OBJS += $(OUTPUT)util/alias.o
@@ -388,8 +304,6 @@ LIB_OBJS += $(OUTPUT)util/build-id.o
388LIB_OBJS += $(OUTPUT)util/config.o 304LIB_OBJS += $(OUTPUT)util/config.o
389LIB_OBJS += $(OUTPUT)util/ctype.o 305LIB_OBJS += $(OUTPUT)util/ctype.o
390LIB_OBJS += $(OUTPUT)util/debugfs.o 306LIB_OBJS += $(OUTPUT)util/debugfs.o
391LIB_OBJS += $(OUTPUT)util/sysfs.o
392LIB_OBJS += $(OUTPUT)util/pmu.o
393LIB_OBJS += $(OUTPUT)util/environment.o 307LIB_OBJS += $(OUTPUT)util/environment.o
394LIB_OBJS += $(OUTPUT)util/event.o 308LIB_OBJS += $(OUTPUT)util/event.o
395LIB_OBJS += $(OUTPUT)util/evlist.o 309LIB_OBJS += $(OUTPUT)util/evlist.o
@@ -413,26 +327,19 @@ LIB_OBJS += $(OUTPUT)util/top.o
413LIB_OBJS += $(OUTPUT)util/usage.o 327LIB_OBJS += $(OUTPUT)util/usage.o
414LIB_OBJS += $(OUTPUT)util/wrapper.o 328LIB_OBJS += $(OUTPUT)util/wrapper.o
415LIB_OBJS += $(OUTPUT)util/sigchain.o 329LIB_OBJS += $(OUTPUT)util/sigchain.o
416LIB_OBJS += $(OUTPUT)util/dso.o
417LIB_OBJS += $(OUTPUT)util/symbol.o 330LIB_OBJS += $(OUTPUT)util/symbol.o
418LIB_OBJS += $(OUTPUT)util/symbol-elf.o
419LIB_OBJS += $(OUTPUT)util/color.o 331LIB_OBJS += $(OUTPUT)util/color.o
420LIB_OBJS += $(OUTPUT)util/pager.o 332LIB_OBJS += $(OUTPUT)util/pager.o
421LIB_OBJS += $(OUTPUT)util/header.o 333LIB_OBJS += $(OUTPUT)util/header.o
422LIB_OBJS += $(OUTPUT)util/callchain.o 334LIB_OBJS += $(OUTPUT)util/callchain.o
423LIB_OBJS += $(OUTPUT)util/values.o 335LIB_OBJS += $(OUTPUT)util/values.o
424LIB_OBJS += $(OUTPUT)util/debug.o 336LIB_OBJS += $(OUTPUT)util/debug.o
425LIB_OBJS += $(OUTPUT)util/machine.o
426LIB_OBJS += $(OUTPUT)util/map.o 337LIB_OBJS += $(OUTPUT)util/map.o
427LIB_OBJS += $(OUTPUT)util/pstack.o 338LIB_OBJS += $(OUTPUT)util/pstack.o
428LIB_OBJS += $(OUTPUT)util/session.o 339LIB_OBJS += $(OUTPUT)util/session.o
429LIB_OBJS += $(OUTPUT)util/thread.o 340LIB_OBJS += $(OUTPUT)util/thread.o
430LIB_OBJS += $(OUTPUT)util/thread_map.o 341LIB_OBJS += $(OUTPUT)util/thread_map.o
431LIB_OBJS += $(OUTPUT)util/trace-event-parse.o 342LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
432LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
433LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
434LIB_OBJS += $(OUTPUT)util/pmu-flex.o
435LIB_OBJS += $(OUTPUT)util/pmu-bison.o
436LIB_OBJS += $(OUTPUT)util/trace-event-read.o 343LIB_OBJS += $(OUTPUT)util/trace-event-read.o
437LIB_OBJS += $(OUTPUT)util/trace-event-info.o 344LIB_OBJS += $(OUTPUT)util/trace-event-info.o
438LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o 345LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
@@ -444,46 +351,18 @@ LIB_OBJS += $(OUTPUT)util/util.o
444LIB_OBJS += $(OUTPUT)util/xyarray.o 351LIB_OBJS += $(OUTPUT)util/xyarray.o
445LIB_OBJS += $(OUTPUT)util/cpumap.o 352LIB_OBJS += $(OUTPUT)util/cpumap.o
446LIB_OBJS += $(OUTPUT)util/cgroup.o 353LIB_OBJS += $(OUTPUT)util/cgroup.o
447LIB_OBJS += $(OUTPUT)util/target.o
448LIB_OBJS += $(OUTPUT)util/rblist.o
449LIB_OBJS += $(OUTPUT)util/intlist.o
450LIB_OBJS += $(OUTPUT)util/vdso.o
451LIB_OBJS += $(OUTPUT)util/stat.o
452
453LIB_OBJS += $(OUTPUT)ui/setup.o
454LIB_OBJS += $(OUTPUT)ui/helpline.o
455LIB_OBJS += $(OUTPUT)ui/progress.o
456LIB_OBJS += $(OUTPUT)ui/hist.o
457LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
458
459LIB_OBJS += $(OUTPUT)arch/common.o
460
461LIB_OBJS += $(OUTPUT)tests/parse-events.o
462LIB_OBJS += $(OUTPUT)tests/dso-data.o
463LIB_OBJS += $(OUTPUT)tests/attr.o
464LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
465LIB_OBJS += $(OUTPUT)tests/open-syscall.o
466LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
467LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
468LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
469LIB_OBJS += $(OUTPUT)tests/perf-record.o
470LIB_OBJS += $(OUTPUT)tests/rdpmc.o
471LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
472LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
473LIB_OBJS += $(OUTPUT)tests/pmu.o
474LIB_OBJS += $(OUTPUT)tests/util.o
475 354
476BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 355BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
356
477BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 357BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
358
478# Benchmark modules 359# Benchmark modules
479BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o 360BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
480BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o 361BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
481ifeq ($(RAW_ARCH),x86_64) 362ifeq ($(RAW_ARCH),x86_64)
482BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o 363BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
483BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
484endif 364endif
485BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o 365BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
486BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
487 366
488BUILTIN_OBJS += $(OUTPUT)builtin-diff.o 367BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
489BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o 368BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
@@ -502,10 +381,24 @@ BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
502BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o 381BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
503BUILTIN_OBJS += $(OUTPUT)builtin-lock.o 382BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
504BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o 383BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
384BUILTIN_OBJS += $(OUTPUT)builtin-test.o
505BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 385BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
506BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
507 386
508PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) 387PERFLIBS = $(LIB_FILE)
388
389# Files needed for the python binding, perf.so
390# pyrf is just an internal name needed for all those wrappers.
391# This has to be in sync with what is in the 'sources' variable in
392# tools/perf/util/setup.py
393
394PYRF_OBJS += $(OUTPUT)util/cpumap.o
395PYRF_OBJS += $(OUTPUT)util/ctype.o
396PYRF_OBJS += $(OUTPUT)util/evlist.o
397PYRF_OBJS += $(OUTPUT)util/evsel.o
398PYRF_OBJS += $(OUTPUT)util/python.o
399PYRF_OBJS += $(OUTPUT)util/thread_map.o
400PYRF_OBJS += $(OUTPUT)util/util.o
401PYRF_OBJS += $(OUTPUT)util/xyarray.o
509 402
510# 403#
511# Platform specific tweaks 404# Platform specific tweaks
@@ -518,59 +411,13 @@ PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
518-include config.mak.autogen 411-include config.mak.autogen
519-include config.mak 412-include config.mak
520 413
521ifdef NO_LIBELF 414ifndef NO_DWARF
415FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
416ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
417 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
522 NO_DWARF := 1 418 NO_DWARF := 1
523 NO_DEMANGLE := 1 419endif # Dwarf support
524 NO_LIBUNWIND := 1 420endif # NO_DWARF
525else
526FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
527ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
528 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
529 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
530 LIBC_SUPPORT := 1
531 endif
532 ifeq ($(BIONIC),1)
533 LIBC_SUPPORT := 1
534 endif
535 ifeq ($(LIBC_SUPPORT),1)
536 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
537
538 NO_LIBELF := 1
539 NO_DWARF := 1
540 NO_DEMANGLE := 1
541 else
542 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
543 endif
544else
545 # for linking with debug library, run like:
546 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
547 ifdef LIBDW_DIR
548 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
549 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
550 endif
551
552 FLAGS_DWARF=$(ALL_CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
553 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
554 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
555 NO_DWARF := 1
556 endif # Dwarf support
557endif # SOURCE_LIBELF
558endif # NO_LIBELF
559
560ifndef NO_LIBUNWIND
561# for linking with debug library, run like:
562# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
563ifdef LIBUNWIND_DIR
564 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
565 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
566endif
567
568FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
569ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
570 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
571 NO_LIBUNWIND := 1
572endif # Libunwind support
573endif # NO_LIBUNWIND
574 421
575-include arch/$(ARCH)/Makefile 422-include arch/$(ARCH)/Makefile
576 423
@@ -578,109 +425,58 @@ ifneq ($(OUTPUT),)
578 BASIC_CFLAGS += -I$(OUTPUT) 425 BASIC_CFLAGS += -I$(OUTPUT)
579endif 426endif
580 427
581ifdef NO_LIBELF
582EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
583
584# Remove ELF/DWARF dependent codes
585LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
586LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
587LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
588LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
589
590BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
591
592# Use minimal symbol handling
593LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
594
595else # NO_LIBELF
596BASIC_CFLAGS += -DLIBELF_SUPPORT
597
598FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) 428FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
599ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) 429ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
600 BASIC_CFLAGS += -DLIBELF_MMAP 430 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
431 ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
432 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
433 else
434 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
435 endif
436endif
437
438ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
439 BASIC_CFLAGS += -DLIBELF_NO_MMAP
601endif 440endif
602 441
603ifndef NO_DWARF 442ifndef NO_DWARF
604ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 443ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
605 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 444 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
606else 445else
607 BASIC_CFLAGS := -DDWARF_SUPPORT $(LIBDW_CFLAGS) $(BASIC_CFLAGS) 446 BASIC_CFLAGS += -DDWARF_SUPPORT
608 BASIC_LDFLAGS := $(LIBDW_LDFLAGS) $(BASIC_LDFLAGS)
609 EXTLIBS += -lelf -ldw 447 EXTLIBS += -lelf -ldw
610 LIB_OBJS += $(OUTPUT)util/probe-finder.o 448 LIB_OBJS += $(OUTPUT)util/probe-finder.o
611 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o 449 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
612endif # PERF_HAVE_DWARF_REGS 450endif # PERF_HAVE_DWARF_REGS
613endif # NO_DWARF 451endif # NO_DWARF
614endif # NO_LIBELF
615
616ifndef NO_LIBUNWIND
617 BASIC_CFLAGS += -DLIBUNWIND_SUPPORT
618 EXTLIBS += $(LIBUNWIND_LIBS)
619 BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
620 BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
621 LIB_OBJS += $(OUTPUT)util/unwind.o
622endif
623 452
624ifndef NO_LIBAUDIT 453ifdef NO_NEWT
625 FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit 454 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
626 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y) 455else
627 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
628 else
629 BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
630 BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
631 EXTLIBS += -laudit
632 endif
633endif
634
635ifndef NO_NEWT
636 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt 456 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
637 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y) 457 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y)
638 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 458 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
459 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
639 else 460 else
640 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 461 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
641 BASIC_CFLAGS += -I/usr/include/slang 462 BASIC_CFLAGS += -I/usr/include/slang
642 BASIC_CFLAGS += -DNEWT_SUPPORT
643 EXTLIBS += -lnewt -lslang 463 EXTLIBS += -lnewt -lslang
644 LIB_OBJS += $(OUTPUT)ui/browser.o 464 LIB_OBJS += $(OUTPUT)util/ui/setup.o
645 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o 465 LIB_OBJS += $(OUTPUT)util/ui/browser.o
646 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 466 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
647 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 467 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
648 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o 468 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
649 LIB_OBJS += $(OUTPUT)ui/util.o 469 LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
650 LIB_OBJS += $(OUTPUT)ui/tui/setup.o 470 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
651 LIB_OBJS += $(OUTPUT)ui/tui/util.o 471 LIB_OBJS += $(OUTPUT)util/ui/progress.o
652 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o 472 LIB_OBJS += $(OUTPUT)util/ui/util.o
653 LIB_OBJS += $(OUTPUT)ui/tui/progress.o 473 LIB_H += util/ui/browser.h
654 LIB_H += ui/browser.h 474 LIB_H += util/ui/browsers/map.h
655 LIB_H += ui/browsers/map.h 475 LIB_H += util/ui/helpline.h
656 LIB_H += ui/keysyms.h 476 LIB_H += util/ui/libslang.h
657 LIB_H += ui/libslang.h 477 LIB_H += util/ui/progress.h
658 LIB_H += ui/progress.h 478 LIB_H += util/ui/util.h
659 LIB_H += ui/util.h 479 LIB_H += util/ui/ui.h
660 LIB_H += ui/ui.h
661 endif
662endif
663
664ifndef NO_GTK2
665 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
666 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
667 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
668 else
669 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
670 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
671 endif
672 BASIC_CFLAGS += -DGTK2_SUPPORT
673 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
674 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
675 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
676 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
677 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
678 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
679 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
680 # Make sure that it'd be included only once.
681 ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),)
682 LIB_OBJS += $(OUTPUT)ui/util.o
683 endif
684 endif 480 endif
685endif 481endif
686 482
@@ -693,7 +489,7 @@ else
693 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 489 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
694 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 490 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
695 491
696 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y) 492 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
697 BASIC_CFLAGS += -DNO_LIBPERL 493 BASIC_CFLAGS += -DNO_LIBPERL
698 else 494 else
699 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS) 495 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
@@ -747,11 +543,11 @@ else
747 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 543 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
748 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 544 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
749 545
750 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y) 546 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
751 $(call disable-python,Python.h (for Python 2.x)) 547 $(call disable-python,Python.h (for Python 2.x))
752 else 548 else
753 549
754 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y) 550 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED)),y)
755 $(warning Python 3 is not yet supported; please set) 551 $(warning Python 3 is not yet supported; please set)
756 $(warning PYTHON and/or PYTHON_CONFIG appropriately.) 552 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
757 $(warning If you also have Python 2 installed, then) 553 $(warning If you also have Python 2 installed, then)
@@ -784,23 +580,23 @@ else
784 EXTLIBS += -liberty 580 EXTLIBS += -liberty
785 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 581 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
786 else 582 else
787 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd 583 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd
788 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd) 584 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
789 ifeq ($(has_bfd),y) 585 ifeq ($(has_bfd),y)
790 EXTLIBS += -lbfd 586 EXTLIBS += -lbfd
791 else 587 else
792 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty 588 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
793 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty) 589 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY))
794 ifeq ($(has_bfd_iberty),y) 590 ifeq ($(has_bfd_iberty),y)
795 EXTLIBS += -lbfd -liberty 591 EXTLIBS += -lbfd -liberty
796 else 592 else
797 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz 593 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
798 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz) 594 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z))
799 ifeq ($(has_bfd_iberty_z),y) 595 ifeq ($(has_bfd_iberty_z),y)
800 EXTLIBS += -lbfd -liberty -lz 596 EXTLIBS += -lbfd -liberty -lz
801 else 597 else
802 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty 598 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
803 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle) 599 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE))
804 ifeq ($(has_cplus_demangle),y) 600 ifeq ($(has_cplus_demangle),y)
805 EXTLIBS += -liberty 601 EXTLIBS += -liberty
806 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 602 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -814,29 +610,23 @@ else
814 endif 610 endif
815endif 611endif
816 612
817ifeq ($(NO_PERF_REGS),0)
818 ifeq ($(ARCH),x86)
819 LIB_H += arch/x86/include/perf_regs.h
820 endif
821 BASIC_CFLAGS += -DHAVE_PERF_REGS
822endif
823 613
824ifndef NO_STRLCPY 614ifdef NO_STRLCPY
825 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y) 615 BASIC_CFLAGS += -DNO_STRLCPY
826 BASIC_CFLAGS += -DHAVE_STRLCPY 616else
617 ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y)
618 BASIC_CFLAGS += -DNO_STRLCPY
827 endif 619 endif
828endif 620endif
829 621
830ifndef NO_ON_EXIT 622ifneq ($(findstring $(MAKEFLAGS),s),s)
831 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y) 623ifndef V
832 BASIC_CFLAGS += -DHAVE_ON_EXIT 624 QUIET_CC = @echo ' ' CC $@;
833 endif 625 QUIET_AR = @echo ' ' AR $@;
626 QUIET_LINK = @echo ' ' LINK $@;
627 QUIET_MKDIR = @echo ' ' MKDIR $@;
628 QUIET_GEN = @echo ' ' GEN $@;
834endif 629endif
835
836ifndef NO_BACKTRACE
837 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
838 BASIC_CFLAGS += -DBACKTRACE_SUPPORT
839 endif
840endif 630endif
841 631
842ifdef ASCIIDOC8 632ifdef ASCIIDOC8
@@ -856,7 +646,6 @@ perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
856template_dir_SQ = $(subst ','\'',$(template_dir)) 646template_dir_SQ = $(subst ','\'',$(template_dir))
857htmldir_SQ = $(subst ','\'',$(htmldir)) 647htmldir_SQ = $(subst ','\'',$(htmldir))
858prefix_SQ = $(subst ','\'',$(prefix)) 648prefix_SQ = $(subst ','\'',$(prefix))
859sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
860 649
861SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) 650SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
862 651
@@ -917,63 +706,40 @@ $(OUTPUT)perf.o perf.spec \
917 $(SCRIPTS) \ 706 $(SCRIPTS) \
918 : $(OUTPUT)PERF-VERSION-FILE 707 : $(OUTPUT)PERF-VERSION-FILE
919 708
920.SUFFIXES:
921.SUFFIXES: .o .c .S .s
922
923# These two need to be here so that when O= is not used they take precedence
924# over the general rule for .o
925
926$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
927 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -w $<
928
929$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
930 $(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
931
932$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS 709$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
933 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 710 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
934$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
935 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
936$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS 711$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
937 $(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $< 712 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
938$(OUTPUT)%.o: %.S 713$(OUTPUT)%.o: %.S
939 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 714 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
940$(OUTPUT)%.s: %.S
941 $(QUIET_CC)$(CC) -o $@ -E $(ALL_CFLAGS) $<
942 715
943$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 716$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
944 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 717 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
945 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ 718 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
719 '-DBINDIR="$(bindir_relative_SQ)"' \
946 '-DPREFIX="$(prefix_SQ)"' \ 720 '-DPREFIX="$(prefix_SQ)"' \
947 $< 721 $<
948 722
949$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
950 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
951 '-DBINDIR="$(bindir_SQ)"' \
952 $<
953
954$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 723$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
955 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 724 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
956 725
957$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS 726$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
958 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 727 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
959 728
960$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS 729$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
961 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 730 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
962 731
963$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS 732$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
964 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 733 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
965 734
966$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 735$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
967 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 736 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
968 737
969$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS 738$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
970 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 739 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
971 740
972$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 741$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
973 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 742 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
974
975$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
976 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $<
977 743
978$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS 744$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
979 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 745 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
@@ -1004,13 +770,6 @@ $(sort $(dir $(DIRECTORY_DEPS))):
1004$(LIB_FILE): $(LIB_OBJS) 770$(LIB_FILE): $(LIB_OBJS)
1005 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 771 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
1006 772
1007# libtraceevent.a
1008$(LIBTRACEEVENT):
1009 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a
1010
1011$(LIBTRACEEVENT)-clean:
1012 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
1013
1014help: 773help:
1015 @echo 'Perf make targets:' 774 @echo 'Perf make targets:'
1016 @echo ' doc - make *all* documentation (see below)' 775 @echo ' doc - make *all* documentation (see below)'
@@ -1038,17 +797,23 @@ help:
1038 @echo ' quick-install-html - install the html documentation quickly' 797 @echo ' quick-install-html - install the html documentation quickly'
1039 @echo '' 798 @echo ''
1040 @echo 'Perf maintainer targets:' 799 @echo 'Perf maintainer targets:'
800 @echo ' distclean - alias to clean'
1041 @echo ' clean - clean all binary objects and build output' 801 @echo ' clean - clean all binary objects and build output'
1042 802
803doc:
804 $(MAKE) -C Documentation all
805
806man:
807 $(MAKE) -C Documentation man
1043 808
1044DOC_TARGETS := doc man html info pdf 809html:
810 $(MAKE) -C Documentation html
1045 811
1046INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man 812info:
1047INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html 813 $(MAKE) -C Documentation info
1048 814
1049# 'make doc' should call 'make -C Documentation all' 815pdf:
1050$(DOC_TARGETS): 816 $(MAKE) -C Documentation pdf
1051 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
1052 817
1053TAGS: 818TAGS:
1054 $(RM) TAGS 819 $(RM) TAGS
@@ -1099,7 +864,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir)
1099endif 864endif
1100perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 865perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1101 866
1102install: all try-install-man 867install: all
1103 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 868 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1104 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' 869 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1105 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 870 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
@@ -1113,32 +878,44 @@ install: all try-install-man
1113 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace' 878 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1114 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' 879 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1115 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 880 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1116 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
1117 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
1118 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
1119 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
1120 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1121 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1122 881
1123install-python_ext: 882install-python_ext:
1124 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' 883 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
1125 884
1126# 'make install-doc' should call 'make -C Documentation install' 885install-doc:
1127$(INSTALL_DOC_TARGETS): 886 $(MAKE) -C Documentation install
1128 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=) 887
888install-man:
889 $(MAKE) -C Documentation install-man
890
891install-html:
892 $(MAKE) -C Documentation install-html
893
894install-info:
895 $(MAKE) -C Documentation install-info
896
897install-pdf:
898 $(MAKE) -C Documentation install-pdf
899
900quick-install-doc:
901 $(MAKE) -C Documentation quick-install
902
903quick-install-man:
904 $(MAKE) -C Documentation quick-install-man
905
906quick-install-html:
907 $(MAKE) -C Documentation quick-install-html
1129 908
1130### Cleaning rules 909### Cleaning rules
1131 910
1132clean: $(LIBTRACEEVENT)-clean 911clean:
1133 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) 912 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
1134 $(RM) $(ALL_PROGRAMS) perf 913 $(RM) $(ALL_PROGRAMS) perf
1135 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 914 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1136 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 915 $(MAKE) -C Documentation/ clean
1137 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS 916 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
1138 $(RM) $(OUTPUT)util/*-bison*
1139 $(RM) $(OUTPUT)util/*-flex*
1140 $(python-clean) 917 $(python-clean)
1141 918
1142.PHONY: all install clean strip $(LIBTRACEEVENT) 919.PHONY: all install clean strip
1143.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 920.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1144.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 921.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
deleted file mode 100644
index 3e975cb6232..00000000000
--- a/tools/perf/arch/common.c
+++ /dev/null
@@ -1,211 +0,0 @@
1#include <stdio.h>
2#include <sys/utsname.h>
3#include "common.h"
4#include "../util/debug.h"
5
6const char *const arm_triplets[] = {
7 "arm-eabi-",
8 "arm-linux-androideabi-",
9 "arm-unknown-linux-",
10 "arm-unknown-linux-gnu-",
11 "arm-unknown-linux-gnueabi-",
12 NULL
13};
14
15const char *const powerpc_triplets[] = {
16 "powerpc-unknown-linux-gnu-",
17 "powerpc64-unknown-linux-gnu-",
18 NULL
19};
20
21const char *const s390_triplets[] = {
22 "s390-ibm-linux-",
23 NULL
24};
25
26const char *const sh_triplets[] = {
27 "sh-unknown-linux-gnu-",
28 "sh64-unknown-linux-gnu-",
29 NULL
30};
31
32const char *const sparc_triplets[] = {
33 "sparc-unknown-linux-gnu-",
34 "sparc64-unknown-linux-gnu-",
35 NULL
36};
37
38const char *const x86_triplets[] = {
39 "x86_64-pc-linux-gnu-",
40 "x86_64-unknown-linux-gnu-",
41 "i686-pc-linux-gnu-",
42 "i586-pc-linux-gnu-",
43 "i486-pc-linux-gnu-",
44 "i386-pc-linux-gnu-",
45 "i686-linux-android-",
46 "i686-android-linux-",
47 NULL
48};
49
50const char *const mips_triplets[] = {
51 "mips-unknown-linux-gnu-",
52 "mipsel-linux-android-",
53 NULL
54};
55
56static bool lookup_path(char *name)
57{
58 bool found = false;
59 char *path, *tmp;
60 char buf[PATH_MAX];
61 char *env = getenv("PATH");
62
63 if (!env)
64 return false;
65
66 env = strdup(env);
67 if (!env)
68 return false;
69
70 path = strtok_r(env, ":", &tmp);
71 while (path) {
72 scnprintf(buf, sizeof(buf), "%s/%s", path, name);
73 if (access(buf, F_OK) == 0) {
74 found = true;
75 break;
76 }
77 path = strtok_r(NULL, ":", &tmp);
78 }
79 free(env);
80 return found;
81}
82
83static int lookup_triplets(const char *const *triplets, const char *name)
84{
85 int i;
86 char buf[PATH_MAX];
87
88 for (i = 0; triplets[i] != NULL; i++) {
89 scnprintf(buf, sizeof(buf), "%s%s", triplets[i], name);
90 if (lookup_path(buf))
91 return i;
92 }
93 return -1;
94}
95
96/*
97 * Return architecture name in a normalized form.
98 * The conversion logic comes from the Makefile.
99 */
100static const char *normalize_arch(char *arch)
101{
102 if (!strcmp(arch, "x86_64"))
103 return "x86";
104 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6')
105 return "x86";
106 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
107 return "sparc";
108 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
109 return "arm";
110 if (!strncmp(arch, "s390", 4))
111 return "s390";
112 if (!strncmp(arch, "parisc", 6))
113 return "parisc";
114 if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3))
115 return "powerpc";
116 if (!strncmp(arch, "mips", 4))
117 return "mips";
118 if (!strncmp(arch, "sh", 2) && isdigit(arch[2]))
119 return "sh";
120
121 return arch;
122}
123
124static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
125 const char *name,
126 const char **path)
127{
128 int idx;
129 const char *arch, *cross_env;
130 struct utsname uts;
131 const char *const *path_list;
132 char *buf = NULL;
133
134 arch = normalize_arch(env->arch);
135
136 if (uname(&uts) < 0)
137 goto out;
138
139 /*
140 * We don't need to try to find objdump path for native system.
141 * Just use default binutils path (e.g.: "objdump").
142 */
143 if (!strcmp(normalize_arch(uts.machine), arch))
144 goto out;
145
146 cross_env = getenv("CROSS_COMPILE");
147 if (cross_env) {
148 if (asprintf(&buf, "%s%s", cross_env, name) < 0)
149 goto out_error;
150 if (buf[0] == '/') {
151 if (access(buf, F_OK) == 0)
152 goto out;
153 goto out_error;
154 }
155 if (lookup_path(buf))
156 goto out;
157 free(buf);
158 }
159
160 if (!strcmp(arch, "arm"))
161 path_list = arm_triplets;
162 else if (!strcmp(arch, "powerpc"))
163 path_list = powerpc_triplets;
164 else if (!strcmp(arch, "sh"))
165 path_list = sh_triplets;
166 else if (!strcmp(arch, "s390"))
167 path_list = s390_triplets;
168 else if (!strcmp(arch, "sparc"))
169 path_list = sparc_triplets;
170 else if (!strcmp(arch, "x86"))
171 path_list = x86_triplets;
172 else if (!strcmp(arch, "mips"))
173 path_list = mips_triplets;
174 else {
175 ui__error("binutils for %s not supported.\n", arch);
176 goto out_error;
177 }
178
179 idx = lookup_triplets(path_list, name);
180 if (idx < 0) {
181 ui__error("Please install %s for %s.\n"
182 "You can add it to PATH, set CROSS_COMPILE or "
183 "override the default using --%s.\n",
184 name, arch, name);
185 goto out_error;
186 }
187
188 if (asprintf(&buf, "%s%s", path_list[idx], name) < 0)
189 goto out_error;
190
191out:
192 *path = buf;
193 return 0;
194out_error:
195 free(buf);
196 *path = NULL;
197 return -1;
198}
199
200int perf_session_env__lookup_objdump(struct perf_session_env *env)
201{
202 /*
203 * For live mode, env->arch will be NULL and we can use
204 * the native objdump tool.
205 */
206 if (env->arch == NULL)
207 return 0;
208
209 return perf_session_env__lookup_binutils_path(env, "objdump",
210 &objdump_path);
211}
diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h
deleted file mode 100644
index ede246eda9b..00000000000
--- a/tools/perf/arch/common.h
+++ /dev/null
@@ -1,10 +0,0 @@
1#ifndef ARCH_PERF_COMMON_H
2#define ARCH_PERF_COMMON_H
3
4#include "../util/session.h"
5
6extern const char *objdump_path;
7
8int perf_session_env__lookup_objdump(struct perf_session_env *env);
9
10#endif /* ARCH_PERF_COMMON_H */
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 744e629797b..15130b50dfe 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -2,4 +2,3 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
index 7cdd61d0e27..48ae0c5e3f7 100644
--- a/tools/perf/arch/powerpc/util/dwarf-regs.c
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -9,10 +9,7 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#include <stdlib.h>
13#ifndef __UCLIBC__
14#include <libio.h> 12#include <libio.h>
15#endif
16#include <dwarf-regs.h> 13#include <dwarf-regs.h>
17 14
18 15
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
deleted file mode 100644
index 2f7073d107f..00000000000
--- a/tools/perf/arch/powerpc/util/header.c
+++ /dev/null
@@ -1,36 +0,0 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11
12#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \
14 : "=r" (rval)); rval; })
15
16#define SPRN_PVR 0x11F /* Processor Version Register */
17#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
18#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
19
20int
21get_cpuid(char *buffer, size_t sz)
22{
23 unsigned long pvr;
24 int nb;
25
26 pvr = mfspr(SPRN_PVR);
27
28 nb = scnprintf(buffer, sz, "%lu,%lu$", PVR_VER(pvr), PVR_REV(pvr));
29
30 /* look for end marker to ensure the entire data fit */
31 if (strchr(buffer, '$')) {
32 buffer[nb-1] = '\0';
33 return 0;
34 }
35 return -1;
36}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 815841c04eb..15130b50dfe 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -2,7 +2,3 @@ ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
7endif
8LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
deleted file mode 100644
index 7fcdcdbee91..00000000000
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ /dev/null
@@ -1,80 +0,0 @@
1#ifndef ARCH_PERF_REGS_H
2#define ARCH_PERF_REGS_H
3
4#include <stdlib.h>
5#include "../../util/types.h"
6#include <asm/perf_regs.h>
7
8#ifndef ARCH_X86_64
9#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
10#else
11#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
12 (1ULL << PERF_REG_X86_ES) | \
13 (1ULL << PERF_REG_X86_FS) | \
14 (1ULL << PERF_REG_X86_GS))
15#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
16#endif
17#define PERF_REG_IP PERF_REG_X86_IP
18#define PERF_REG_SP PERF_REG_X86_SP
19
20static inline const char *perf_reg_name(int id)
21{
22 switch (id) {
23 case PERF_REG_X86_AX:
24 return "AX";
25 case PERF_REG_X86_BX:
26 return "BX";
27 case PERF_REG_X86_CX:
28 return "CX";
29 case PERF_REG_X86_DX:
30 return "DX";
31 case PERF_REG_X86_SI:
32 return "SI";
33 case PERF_REG_X86_DI:
34 return "DI";
35 case PERF_REG_X86_BP:
36 return "BP";
37 case PERF_REG_X86_SP:
38 return "SP";
39 case PERF_REG_X86_IP:
40 return "IP";
41 case PERF_REG_X86_FLAGS:
42 return "FLAGS";
43 case PERF_REG_X86_CS:
44 return "CS";
45 case PERF_REG_X86_SS:
46 return "SS";
47 case PERF_REG_X86_DS:
48 return "DS";
49 case PERF_REG_X86_ES:
50 return "ES";
51 case PERF_REG_X86_FS:
52 return "FS";
53 case PERF_REG_X86_GS:
54 return "GS";
55#ifdef ARCH_X86_64
56 case PERF_REG_X86_R8:
57 return "R8";
58 case PERF_REG_X86_R9:
59 return "R9";
60 case PERF_REG_X86_R10:
61 return "R10";
62 case PERF_REG_X86_R11:
63 return "R11";
64 case PERF_REG_X86_R12:
65 return "R12";
66 case PERF_REG_X86_R13:
67 return "R13";
68 case PERF_REG_X86_R14:
69 return "R14";
70 case PERF_REG_X86_R15:
71 return "R15";
72#endif /* ARCH_X86_64 */
73 default:
74 return NULL;
75 }
76
77 return NULL;
78}
79
80#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
deleted file mode 100644
index 146d12a1cec..00000000000
--- a/tools/perf/arch/x86/util/header.c
+++ /dev/null
@@ -1,59 +0,0 @@
1#include <sys/types.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#include "../../util/header.h"
8
9static inline void
10cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
11 unsigned int *d)
12{
13 __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t"
14 "movl %%ebx, %%esi\n\t.byte 0x5b"
15 : "=a" (*a),
16 "=S" (*b),
17 "=c" (*c),
18 "=d" (*d)
19 : "a" (op));
20}
21
22int
23get_cpuid(char *buffer, size_t sz)
24{
25 unsigned int a, b, c, d, lvl;
26 int family = -1, model = -1, step = -1;
27 int nb;
28 char vendor[16];
29
30 cpuid(0, &lvl, &b, &c, &d);
31 strncpy(&vendor[0], (char *)(&b), 4);
32 strncpy(&vendor[4], (char *)(&d), 4);
33 strncpy(&vendor[8], (char *)(&c), 4);
34 vendor[12] = '\0';
35
36 if (lvl >= 1) {
37 cpuid(1, &a, &b, &c, &d);
38
39 family = (a >> 8) & 0xf; /* bits 11 - 8 */
40 model = (a >> 4) & 0xf; /* Bits 7 - 4 */
41 step = a & 0xf;
42
43 /* extended family */
44 if (family == 0xf)
45 family += (a >> 20) & 0xff;
46
47 /* extended model */
48 if (family >= 0x6)
49 model += ((a >> 16) & 0xf) << 4;
50 }
51 nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
52
53 /* look for end marker to ensure the entire data fit */
54 if (strchr(buffer, '$')) {
55 buffer[nb-1] = '\0';
56 return 0;
57 }
58 return -1;
59}
diff --git a/tools/perf/arch/x86/util/unwind.c b/tools/perf/arch/x86/util/unwind.c
deleted file mode 100644
index 78d956eff96..00000000000
--- a/tools/perf/arch/x86/util/unwind.c
+++ /dev/null
@@ -1,111 +0,0 @@
1
2#include <errno.h>
3#include <libunwind.h>
4#include "perf_regs.h"
5#include "../../util/unwind.h"
6
7#ifdef ARCH_X86_64
8int unwind__arch_reg_id(int regnum)
9{
10 int id;
11
12 switch (regnum) {
13 case UNW_X86_64_RAX:
14 id = PERF_REG_X86_AX;
15 break;
16 case UNW_X86_64_RDX:
17 id = PERF_REG_X86_DX;
18 break;
19 case UNW_X86_64_RCX:
20 id = PERF_REG_X86_CX;
21 break;
22 case UNW_X86_64_RBX:
23 id = PERF_REG_X86_BX;
24 break;
25 case UNW_X86_64_RSI:
26 id = PERF_REG_X86_SI;
27 break;
28 case UNW_X86_64_RDI:
29 id = PERF_REG_X86_DI;
30 break;
31 case UNW_X86_64_RBP:
32 id = PERF_REG_X86_BP;
33 break;
34 case UNW_X86_64_RSP:
35 id = PERF_REG_X86_SP;
36 break;
37 case UNW_X86_64_R8:
38 id = PERF_REG_X86_R8;
39 break;
40 case UNW_X86_64_R9:
41 id = PERF_REG_X86_R9;
42 break;
43 case UNW_X86_64_R10:
44 id = PERF_REG_X86_R10;
45 break;
46 case UNW_X86_64_R11:
47 id = PERF_REG_X86_R11;
48 break;
49 case UNW_X86_64_R12:
50 id = PERF_REG_X86_R12;
51 break;
52 case UNW_X86_64_R13:
53 id = PERF_REG_X86_R13;
54 break;
55 case UNW_X86_64_R14:
56 id = PERF_REG_X86_R14;
57 break;
58 case UNW_X86_64_R15:
59 id = PERF_REG_X86_R15;
60 break;
61 case UNW_X86_64_RIP:
62 id = PERF_REG_X86_IP;
63 break;
64 default:
65 pr_err("unwind: invalid reg id %d\n", regnum);
66 return -EINVAL;
67 }
68
69 return id;
70}
71#else
72int unwind__arch_reg_id(int regnum)
73{
74 int id;
75
76 switch (regnum) {
77 case UNW_X86_EAX:
78 id = PERF_REG_X86_AX;
79 break;
80 case UNW_X86_EDX:
81 id = PERF_REG_X86_DX;
82 break;
83 case UNW_X86_ECX:
84 id = PERF_REG_X86_CX;
85 break;
86 case UNW_X86_EBX:
87 id = PERF_REG_X86_BX;
88 break;
89 case UNW_X86_ESI:
90 id = PERF_REG_X86_SI;
91 break;
92 case UNW_X86_EDI:
93 id = PERF_REG_X86_DI;
94 break;
95 case UNW_X86_EBP:
96 id = PERF_REG_X86_BP;
97 break;
98 case UNW_X86_ESP:
99 id = PERF_REG_X86_SP;
100 break;
101 case UNW_X86_EIP:
102 id = PERF_REG_X86_IP;
103 break;
104 default:
105 pr_err("unwind: invalid reg id %d\n", regnum);
106 return -EINVAL;
107 }
108
109 return id;
110}
111#endif /* ARCH_X86_64 */
diff --git a/tools/perf/bash_completion b/tools/perf/bash_completion
deleted file mode 100644
index 56e6a12aab5..00000000000
--- a/tools/perf/bash_completion
+++ /dev/null
@@ -1,62 +0,0 @@
1# perf completion
2
3function_exists()
4{
5 declare -F $1 > /dev/null
6 return $?
7}
8
9function_exists __ltrim_colon_completions ||
10__ltrim_colon_completions()
11{
12 if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
13 # Remove colon-word prefix from COMPREPLY items
14 local colon_word=${1%${1##*:}}
15 local i=${#COMPREPLY[*]}
16 while [[ $((--i)) -ge 0 ]]; do
17 COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
18 done
19 fi
20}
21
22have perf &&
23_perf()
24{
25 local cur prev cmd
26
27 COMPREPLY=()
28 if function_exists _get_comp_words_by_ref; then
29 _get_comp_words_by_ref -n : cur prev
30 else
31 cur=$(_get_cword :)
32 prev=${COMP_WORDS[COMP_CWORD-1]}
33 fi
34
35 cmd=${COMP_WORDS[0]}
36
37 # List perf subcommands or long options
38 if [ $COMP_CWORD -eq 1 ]; then
39 if [[ $cur == --* ]]; then
40 COMPREPLY=( $( compgen -W '--help --version \
41 --exec-path --html-path --paginate --no-pager \
42 --perf-dir --work-tree --debugfs-dir' -- "$cur" ) )
43 else
44 cmds=$($cmd --list-cmds)
45 COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
46 fi
47 # List possible events for -e option
48 elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then
49 evts=$($cmd list --raw-dump)
50 COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) )
51 __ltrim_colon_completions $cur
52 # List long option names
53 elif [[ $cur == --* ]]; then
54 subcmd=${COMP_WORDS[1]}
55 opts=$($cmd $subcmd --list-opts)
56 COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) )
57 # Fall down to list regular files
58 else
59 _filedir
60 fi
61} &&
62complete -F _perf perf
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index 8f89998eeaf..f7781c6267c 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -3,9 +3,7 @@
3 3
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); 4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); 5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, 6extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
7 const char *prefix __maybe_unused);
8extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
9 7
10#define BENCH_FORMAT_DEFAULT_STR "default" 8#define BENCH_FORMAT_DEFAULT_STR "default"
11#define BENCH_FORMAT_DEFAULT 0 9#define BENCH_FORMAT_DEFAULT 0
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
index d66ab799b35..d588b87696f 100644
--- a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
@@ -2,11 +2,3 @@
2MEMCPY_FN(__memcpy, 2MEMCPY_FN(__memcpy,
3 "x86-64-unrolled", 3 "x86-64-unrolled",
4 "unrolled memcpy() in arch/x86/lib/memcpy_64.S") 4 "unrolled memcpy() in arch/x86/lib/memcpy_64.S")
5
6MEMCPY_FN(memcpy_c,
7 "x86-64-movsq",
8 "movsq-based memcpy() in arch/x86/lib/memcpy_64.S")
9
10MEMCPY_FN(memcpy_c_e,
11 "x86-64-movsb",
12 "movsb-based memcpy() in arch/x86/lib/memcpy_64.S")
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S
index fcd9cf00600..a57b66e853c 100644
--- a/tools/perf/bench/mem-memcpy-x86-64-asm.S
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S
@@ -1,12 +1,2 @@
1#define memcpy MEMCPY /* don't hide glibc's memcpy() */ 1
2#define altinstr_replacement text
3#define globl p2align 4; .globl
4#define Lmemcpy_c globl memcpy_c; memcpy_c
5#define Lmemcpy_c_e globl memcpy_c_e; memcpy_c_e
6#include "../../../arch/x86/lib/memcpy_64.S" 2#include "../../../arch/x86/lib/memcpy_64.S"
7/*
8 * We need to provide note.GNU-stack section, saying that we want
9 * NOT executable stack. Otherwise the final linking will assume that
10 * the ELF stack should not be restricted at all and set it RWX.
11 */
12.section .note.GNU-stack,"",@progbits
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 93c83e3cb4a..db82021f4b9 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
7 */ 7 */
8#include <ctype.h>
8 9
9#include "../perf.h" 10#include "../perf.h"
10#include "../util/util.h" 11#include "../util/util.h"
@@ -23,22 +24,19 @@
23 24
24static const char *length_str = "1MB"; 25static const char *length_str = "1MB";
25static const char *routine = "default"; 26static const char *routine = "default";
26static int iterations = 1; 27static bool use_clock;
27static bool use_cycle; 28static int clock_fd;
28static int cycle_fd;
29static bool only_prefault; 29static bool only_prefault;
30static bool no_prefault; 30static bool no_prefault;
31 31
32static const struct option options[] = { 32static const struct option options[] = {
33 OPT_STRING('l', "length", &length_str, "1MB", 33 OPT_STRING('l', "length", &length_str, "1MB",
34 "Specify length of memory to copy. " 34 "Specify length of memory to copy. "
35 "Available units: B, KB, MB, GB and TB (upper and lower)"), 35 "available unit: B, MB, GB (upper and lower)"),
36 OPT_STRING('r', "routine", &routine, "default", 36 OPT_STRING('r', "routine", &routine, "default",
37 "Specify routine to copy"), 37 "Specify routine to copy"),
38 OPT_INTEGER('i', "iterations", &iterations, 38 OPT_BOOLEAN('c', "clock", &use_clock,
39 "repeat memcpy() invocation this number of times"), 39 "Use CPU clock for measuring"),
40 OPT_BOOLEAN('c', "cycle", &use_cycle,
41 "Use cycles event instead of gettimeofday() for measuring"),
42 OPT_BOOLEAN('o', "only-prefault", &only_prefault, 40 OPT_BOOLEAN('o', "only-prefault", &only_prefault,
43 "Show only the result with page faults before memcpy()"), 41 "Show only the result with page faults before memcpy()"),
44 OPT_BOOLEAN('n', "no-prefault", &no_prefault, 42 OPT_BOOLEAN('n', "no-prefault", &no_prefault,
@@ -76,27 +74,27 @@ static const char * const bench_mem_memcpy_usage[] = {
76 NULL 74 NULL
77}; 75};
78 76
79static struct perf_event_attr cycle_attr = { 77static struct perf_event_attr clock_attr = {
80 .type = PERF_TYPE_HARDWARE, 78 .type = PERF_TYPE_HARDWARE,
81 .config = PERF_COUNT_HW_CPU_CYCLES 79 .config = PERF_COUNT_HW_CPU_CYCLES
82}; 80};
83 81
84static void init_cycle(void) 82static void init_clock(void)
85{ 83{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); 84 clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
87 85
88 if (cycle_fd < 0 && errno == ENOSYS) 86 if (clock_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 87 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
90 else 88 else
91 BUG_ON(cycle_fd < 0); 89 BUG_ON(clock_fd < 0);
92} 90}
93 91
94static u64 get_cycle(void) 92static u64 get_clock(void)
95{ 93{
96 int ret; 94 int ret;
97 u64 clk; 95 u64 clk;
98 96
99 ret = read(cycle_fd, &clk, sizeof(u64)); 97 ret = read(clock_fd, &clk, sizeof(u64));
100 BUG_ON(ret != sizeof(u64)); 98 BUG_ON(ret != sizeof(u64));
101 99
102 return clk; 100 return clk;
@@ -119,32 +117,29 @@ static void alloc_mem(void **dst, void **src, size_t length)
119 die("memory allocation failed - maybe length is too large?\n"); 117 die("memory allocation failed - maybe length is too large?\n");
120} 118}
121 119
122static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault) 120static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
123{ 121{
124 u64 cycle_start = 0ULL, cycle_end = 0ULL; 122 u64 clock_start = 0ULL, clock_end = 0ULL;
125 void *src = NULL, *dst = NULL; 123 void *src = NULL, *dst = NULL;
126 int i;
127 124
128 alloc_mem(&src, &dst, len); 125 alloc_mem(&src, &dst, len);
129 126
130 if (prefault) 127 if (prefault)
131 fn(dst, src, len); 128 fn(dst, src, len);
132 129
133 cycle_start = get_cycle(); 130 clock_start = get_clock();
134 for (i = 0; i < iterations; ++i) 131 fn(dst, src, len);
135 fn(dst, src, len); 132 clock_end = get_clock();
136 cycle_end = get_cycle();
137 133
138 free(src); 134 free(src);
139 free(dst); 135 free(dst);
140 return cycle_end - cycle_start; 136 return clock_end - clock_start;
141} 137}
142 138
143static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault) 139static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
144{ 140{
145 struct timeval tv_start, tv_end, tv_diff; 141 struct timeval tv_start, tv_end, tv_diff;
146 void *src = NULL, *dst = NULL; 142 void *src = NULL, *dst = NULL;
147 int i;
148 143
149 alloc_mem(&src, &dst, len); 144 alloc_mem(&src, &dst, len);
150 145
@@ -152,8 +147,7 @@ static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
152 fn(dst, src, len); 147 fn(dst, src, len);
153 148
154 BUG_ON(gettimeofday(&tv_start, NULL)); 149 BUG_ON(gettimeofday(&tv_start, NULL));
155 for (i = 0; i < iterations; ++i) 150 fn(dst, src, len);
156 fn(dst, src, len);
157 BUG_ON(gettimeofday(&tv_end, NULL)); 151 BUG_ON(gettimeofday(&tv_end, NULL));
158 152
159 timersub(&tv_end, &tv_start, &tv_diff); 153 timersub(&tv_end, &tv_start, &tv_diff);
@@ -177,22 +171,22 @@ static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
177 } while (0) 171 } while (0)
178 172
179int bench_mem_memcpy(int argc, const char **argv, 173int bench_mem_memcpy(int argc, const char **argv,
180 const char *prefix __maybe_unused) 174 const char *prefix __used)
181{ 175{
182 int i; 176 int i;
183 size_t len; 177 size_t len;
184 double result_bps[2]; 178 double result_bps[2];
185 u64 result_cycle[2]; 179 u64 result_clock[2];
186 180
187 argc = parse_options(argc, argv, options, 181 argc = parse_options(argc, argv, options,
188 bench_mem_memcpy_usage, 0); 182 bench_mem_memcpy_usage, 0);
189 183
190 if (use_cycle) 184 if (use_clock)
191 init_cycle(); 185 init_clock();
192 186
193 len = (size_t)perf_atoll((char *)length_str); 187 len = (size_t)perf_atoll((char *)length_str);
194 188
195 result_cycle[0] = result_cycle[1] = 0ULL; 189 result_clock[0] = result_clock[1] = 0ULL;
196 result_bps[0] = result_bps[1] = 0.0; 190 result_bps[0] = result_bps[1] = 0.0;
197 191
198 if ((s64)len <= 0) { 192 if ((s64)len <= 0) {
@@ -223,11 +217,11 @@ int bench_mem_memcpy(int argc, const char **argv,
223 217
224 if (!only_prefault && !no_prefault) { 218 if (!only_prefault && !no_prefault) {
225 /* show both of results */ 219 /* show both of results */
226 if (use_cycle) { 220 if (use_clock) {
227 result_cycle[0] = 221 result_clock[0] =
228 do_memcpy_cycle(routines[i].fn, len, false); 222 do_memcpy_clock(routines[i].fn, len, false);
229 result_cycle[1] = 223 result_clock[1] =
230 do_memcpy_cycle(routines[i].fn, len, true); 224 do_memcpy_clock(routines[i].fn, len, true);
231 } else { 225 } else {
232 result_bps[0] = 226 result_bps[0] =
233 do_memcpy_gettimeofday(routines[i].fn, 227 do_memcpy_gettimeofday(routines[i].fn,
@@ -237,9 +231,9 @@ int bench_mem_memcpy(int argc, const char **argv,
237 len, true); 231 len, true);
238 } 232 }
239 } else { 233 } else {
240 if (use_cycle) { 234 if (use_clock) {
241 result_cycle[pf] = 235 result_clock[pf] =
242 do_memcpy_cycle(routines[i].fn, 236 do_memcpy_clock(routines[i].fn,
243 len, only_prefault); 237 len, only_prefault);
244 } else { 238 } else {
245 result_bps[pf] = 239 result_bps[pf] =
@@ -251,12 +245,12 @@ int bench_mem_memcpy(int argc, const char **argv,
251 switch (bench_format) { 245 switch (bench_format) {
252 case BENCH_FORMAT_DEFAULT: 246 case BENCH_FORMAT_DEFAULT:
253 if (!only_prefault && !no_prefault) { 247 if (!only_prefault && !no_prefault) {
254 if (use_cycle) { 248 if (use_clock) {
255 printf(" %14lf Cycle/Byte\n", 249 printf(" %14lf Clock/Byte\n",
256 (double)result_cycle[0] 250 (double)result_clock[0]
257 / (double)len); 251 / (double)len);
258 printf(" %14lf Cycle/Byte (with prefault)\n", 252 printf(" %14lf Clock/Byte (with prefault)\n",
259 (double)result_cycle[1] 253 (double)result_clock[1]
260 / (double)len); 254 / (double)len);
261 } else { 255 } else {
262 print_bps(result_bps[0]); 256 print_bps(result_bps[0]);
@@ -265,9 +259,9 @@ int bench_mem_memcpy(int argc, const char **argv,
265 printf(" (with prefault)\n"); 259 printf(" (with prefault)\n");
266 } 260 }
267 } else { 261 } else {
268 if (use_cycle) { 262 if (use_clock) {
269 printf(" %14lf Cycle/Byte", 263 printf(" %14lf Clock/Byte",
270 (double)result_cycle[pf] 264 (double)result_clock[pf]
271 / (double)len); 265 / (double)len);
272 } else 266 } else
273 print_bps(result_bps[pf]); 267 print_bps(result_bps[pf]);
@@ -277,17 +271,17 @@ int bench_mem_memcpy(int argc, const char **argv,
277 break; 271 break;
278 case BENCH_FORMAT_SIMPLE: 272 case BENCH_FORMAT_SIMPLE:
279 if (!only_prefault && !no_prefault) { 273 if (!only_prefault && !no_prefault) {
280 if (use_cycle) { 274 if (use_clock) {
281 printf("%lf %lf\n", 275 printf("%lf %lf\n",
282 (double)result_cycle[0] / (double)len, 276 (double)result_clock[0] / (double)len,
283 (double)result_cycle[1] / (double)len); 277 (double)result_clock[1] / (double)len);
284 } else { 278 } else {
285 printf("%lf %lf\n", 279 printf("%lf %lf\n",
286 result_bps[0], result_bps[1]); 280 result_bps[0], result_bps[1]);
287 } 281 }
288 } else { 282 } else {
289 if (use_cycle) { 283 if (use_clock) {
290 printf("%lf\n", (double)result_cycle[pf] 284 printf("%lf\n", (double)result_clock[pf]
291 / (double)len); 285 / (double)len);
292 } else 286 } else
293 printf("%lf\n", result_bps[pf]); 287 printf("%lf\n", result_bps[pf]);
diff --git a/tools/perf/bench/mem-memset-arch.h b/tools/perf/bench/mem-memset-arch.h
deleted file mode 100644
index a040fa77665..00000000000
--- a/tools/perf/bench/mem-memset-arch.h
+++ /dev/null
@@ -1,12 +0,0 @@
1
2#ifdef ARCH_X86_64
3
4#define MEMSET_FN(fn, name, desc) \
5 extern void *fn(void *, int, size_t);
6
7#include "mem-memset-x86-64-asm-def.h"
8
9#undef MEMSET_FN
10
11#endif
12
diff --git a/tools/perf/bench/mem-memset-x86-64-asm-def.h b/tools/perf/bench/mem-memset-x86-64-asm-def.h
deleted file mode 100644
index a71dff97c1f..00000000000
--- a/tools/perf/bench/mem-memset-x86-64-asm-def.h
+++ /dev/null
@@ -1,12 +0,0 @@
1
2MEMSET_FN(__memset,
3 "x86-64-unrolled",
4 "unrolled memset() in arch/x86/lib/memset_64.S")
5
6MEMSET_FN(memset_c,
7 "x86-64-stosq",
8 "movsq-based memset() in arch/x86/lib/memset_64.S")
9
10MEMSET_FN(memset_c_e,
11 "x86-64-stosb",
12 "movsb-based memset() in arch/x86/lib/memset_64.S")
diff --git a/tools/perf/bench/mem-memset-x86-64-asm.S b/tools/perf/bench/mem-memset-x86-64-asm.S
deleted file mode 100644
index 9e5af89ed13..00000000000
--- a/tools/perf/bench/mem-memset-x86-64-asm.S
+++ /dev/null
@@ -1,13 +0,0 @@
1#define memset MEMSET /* don't hide glibc's memset() */
2#define altinstr_replacement text
3#define globl p2align 4; .globl
4#define Lmemset_c globl memset_c; memset_c
5#define Lmemset_c_e globl memset_c_e; memset_c_e
6#include "../../../arch/x86/lib/memset_64.S"
7
8/*
9 * We need to provide note.GNU-stack section, saying that we want
10 * NOT executable stack. Otherwise the final linking will assume that
11 * the ELF stack should not be restricted at all and set it RWX.
12 */
13.section .note.GNU-stack,"",@progbits
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c
deleted file mode 100644
index c6e4bc52349..00000000000
--- a/tools/perf/bench/mem-memset.c
+++ /dev/null
@@ -1,297 +0,0 @@
1/*
2 * mem-memset.c
3 *
4 * memset: Simple memory set in various ways
5 *
6 * Trivial clone of mem-memcpy.c.
7 */
8
9#include "../perf.h"
10#include "../util/util.h"
11#include "../util/parse-options.h"
12#include "../util/header.h"
13#include "bench.h"
14#include "mem-memset-arch.h"
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/time.h>
20#include <errno.h>
21
22#define K 1024
23
24static const char *length_str = "1MB";
25static const char *routine = "default";
26static int iterations = 1;
27static bool use_cycle;
28static int cycle_fd;
29static bool only_prefault;
30static bool no_prefault;
31
32static const struct option options[] = {
33 OPT_STRING('l', "length", &length_str, "1MB",
34 "Specify length of memory to set. "
35 "Available units: B, KB, MB, GB and TB (upper and lower)"),
36 OPT_STRING('r', "routine", &routine, "default",
37 "Specify routine to set"),
38 OPT_INTEGER('i', "iterations", &iterations,
39 "repeat memset() invocation this number of times"),
40 OPT_BOOLEAN('c', "cycle", &use_cycle,
41 "Use cycles event instead of gettimeofday() for measuring"),
42 OPT_BOOLEAN('o', "only-prefault", &only_prefault,
43 "Show only the result with page faults before memset()"),
44 OPT_BOOLEAN('n', "no-prefault", &no_prefault,
45 "Show only the result without page faults before memset()"),
46 OPT_END()
47};
48
49typedef void *(*memset_t)(void *, int, size_t);
50
51struct routine {
52 const char *name;
53 const char *desc;
54 memset_t fn;
55};
56
57static const struct routine routines[] = {
58 { "default",
59 "Default memset() provided by glibc",
60 memset },
61#ifdef ARCH_X86_64
62
63#define MEMSET_FN(fn, name, desc) { name, desc, fn },
64#include "mem-memset-x86-64-asm-def.h"
65#undef MEMSET_FN
66
67#endif
68
69 { NULL,
70 NULL,
71 NULL }
72};
73
74static const char * const bench_mem_memset_usage[] = {
75 "perf bench mem memset <options>",
76 NULL
77};
78
79static struct perf_event_attr cycle_attr = {
80 .type = PERF_TYPE_HARDWARE,
81 .config = PERF_COUNT_HW_CPU_CYCLES
82};
83
84static void init_cycle(void)
85{
86 cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0);
87
88 if (cycle_fd < 0 && errno == ENOSYS)
89 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
90 else
91 BUG_ON(cycle_fd < 0);
92}
93
94static u64 get_cycle(void)
95{
96 int ret;
97 u64 clk;
98
99 ret = read(cycle_fd, &clk, sizeof(u64));
100 BUG_ON(ret != sizeof(u64));
101
102 return clk;
103}
104
105static double timeval2double(struct timeval *ts)
106{
107 return (double)ts->tv_sec +
108 (double)ts->tv_usec / (double)1000000;
109}
110
111static void alloc_mem(void **dst, size_t length)
112{
113 *dst = zalloc(length);
114 if (!dst)
115 die("memory allocation failed - maybe length is too large?\n");
116}
117
118static u64 do_memset_cycle(memset_t fn, size_t len, bool prefault)
119{
120 u64 cycle_start = 0ULL, cycle_end = 0ULL;
121 void *dst = NULL;
122 int i;
123
124 alloc_mem(&dst, len);
125
126 if (prefault)
127 fn(dst, -1, len);
128
129 cycle_start = get_cycle();
130 for (i = 0; i < iterations; ++i)
131 fn(dst, i, len);
132 cycle_end = get_cycle();
133
134 free(dst);
135 return cycle_end - cycle_start;
136}
137
138static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault)
139{
140 struct timeval tv_start, tv_end, tv_diff;
141 void *dst = NULL;
142 int i;
143
144 alloc_mem(&dst, len);
145
146 if (prefault)
147 fn(dst, -1, len);
148
149 BUG_ON(gettimeofday(&tv_start, NULL));
150 for (i = 0; i < iterations; ++i)
151 fn(dst, i, len);
152 BUG_ON(gettimeofday(&tv_end, NULL));
153
154 timersub(&tv_end, &tv_start, &tv_diff);
155
156 free(dst);
157 return (double)((double)len / timeval2double(&tv_diff));
158}
159
160#define pf (no_prefault ? 0 : 1)
161
162#define print_bps(x) do { \
163 if (x < K) \
164 printf(" %14lf B/Sec", x); \
165 else if (x < K * K) \
166 printf(" %14lfd KB/Sec", x / K); \
167 else if (x < K * K * K) \
168 printf(" %14lf MB/Sec", x / K / K); \
169 else \
170 printf(" %14lf GB/Sec", x / K / K / K); \
171 } while (0)
172
173int bench_mem_memset(int argc, const char **argv,
174 const char *prefix __maybe_unused)
175{
176 int i;
177 size_t len;
178 double result_bps[2];
179 u64 result_cycle[2];
180
181 argc = parse_options(argc, argv, options,
182 bench_mem_memset_usage, 0);
183
184 if (use_cycle)
185 init_cycle();
186
187 len = (size_t)perf_atoll((char *)length_str);
188
189 result_cycle[0] = result_cycle[1] = 0ULL;
190 result_bps[0] = result_bps[1] = 0.0;
191
192 if ((s64)len <= 0) {
193 fprintf(stderr, "Invalid length:%s\n", length_str);
194 return 1;
195 }
196
197 /* same to without specifying either of prefault and no-prefault */
198 if (only_prefault && no_prefault)
199 only_prefault = no_prefault = false;
200
201 for (i = 0; routines[i].name; i++) {
202 if (!strcmp(routines[i].name, routine))
203 break;
204 }
205 if (!routines[i].name) {
206 printf("Unknown routine:%s\n", routine);
207 printf("Available routines...\n");
208 for (i = 0; routines[i].name; i++) {
209 printf("\t%s ... %s\n",
210 routines[i].name, routines[i].desc);
211 }
212 return 1;
213 }
214
215 if (bench_format == BENCH_FORMAT_DEFAULT)
216 printf("# Copying %s Bytes ...\n\n", length_str);
217
218 if (!only_prefault && !no_prefault) {
219 /* show both of results */
220 if (use_cycle) {
221 result_cycle[0] =
222 do_memset_cycle(routines[i].fn, len, false);
223 result_cycle[1] =
224 do_memset_cycle(routines[i].fn, len, true);
225 } else {
226 result_bps[0] =
227 do_memset_gettimeofday(routines[i].fn,
228 len, false);
229 result_bps[1] =
230 do_memset_gettimeofday(routines[i].fn,
231 len, true);
232 }
233 } else {
234 if (use_cycle) {
235 result_cycle[pf] =
236 do_memset_cycle(routines[i].fn,
237 len, only_prefault);
238 } else {
239 result_bps[pf] =
240 do_memset_gettimeofday(routines[i].fn,
241 len, only_prefault);
242 }
243 }
244
245 switch (bench_format) {
246 case BENCH_FORMAT_DEFAULT:
247 if (!only_prefault && !no_prefault) {
248 if (use_cycle) {
249 printf(" %14lf Cycle/Byte\n",
250 (double)result_cycle[0]
251 / (double)len);
252 printf(" %14lf Cycle/Byte (with prefault)\n ",
253 (double)result_cycle[1]
254 / (double)len);
255 } else {
256 print_bps(result_bps[0]);
257 printf("\n");
258 print_bps(result_bps[1]);
259 printf(" (with prefault)\n");
260 }
261 } else {
262 if (use_cycle) {
263 printf(" %14lf Cycle/Byte",
264 (double)result_cycle[pf]
265 / (double)len);
266 } else
267 print_bps(result_bps[pf]);
268
269 printf("%s\n", only_prefault ? " (with prefault)" : "");
270 }
271 break;
272 case BENCH_FORMAT_SIMPLE:
273 if (!only_prefault && !no_prefault) {
274 if (use_cycle) {
275 printf("%lf %lf\n",
276 (double)result_cycle[0] / (double)len,
277 (double)result_cycle[1] / (double)len);
278 } else {
279 printf("%lf %lf\n",
280 result_bps[0], result_bps[1]);
281 }
282 } else {
283 if (use_cycle) {
284 printf("%lf\n", (double)result_cycle[pf]
285 / (double)len);
286 } else
287 printf("%lf\n", result_bps[pf]);
288 }
289 break;
290 default:
291 /* reaching this means there's some disaster: */
292 die("unknown format: %d\n", bench_format);
293 break;
294 }
295
296 return 0;
297}
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index cc1190a0849..d1d1b30f99c 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -267,7 +267,7 @@ static const char * const bench_sched_message_usage[] = {
267}; 267};
268 268
269int bench_sched_messaging(int argc, const char **argv, 269int bench_sched_messaging(int argc, const char **argv,
270 const char *prefix __maybe_unused) 270 const char *prefix __used)
271{ 271{
272 unsigned int i, total_children; 272 unsigned int i, total_children;
273 struct timeval start, stop, diff; 273 struct timeval start, stop, diff;
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 69cfba8d4c6..0c7454f8b8a 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -43,7 +43,7 @@ static const char * const bench_sched_pipe_usage[] = {
43}; 43};
44 44
45int bench_sched_pipe(int argc, const char **argv, 45int bench_sched_pipe(int argc, const char **argv,
46 const char *prefix __maybe_unused) 46 const char *prefix __used)
47{ 47{
48 int pipe_1[2], pipe_2[2]; 48 int pipe_1[2], pipe_2[2];
49 int m = 0, i; 49 int m = 0, i;
@@ -55,14 +55,14 @@ int bench_sched_pipe(int argc, const char **argv,
55 * discarding returned value of read(), write() 55 * discarding returned value of read(), write()
56 * causes error in building environment for perf 56 * causes error in building environment for perf
57 */ 57 */
58 int __maybe_unused ret, wait_stat; 58 int __used ret, wait_stat;
59 pid_t pid, retpid __maybe_unused; 59 pid_t pid, retpid;
60 60
61 argc = parse_options(argc, argv, options, 61 argc = parse_options(argc, argv, options,
62 bench_sched_pipe_usage, 0); 62 bench_sched_pipe_usage, 0);
63 63
64 BUG_ON(pipe(pipe_1)); 64 assert(!pipe(pipe_1));
65 BUG_ON(pipe(pipe_2)); 65 assert(!pipe(pipe_2));
66 66
67 pid = fork(); 67 pid = fork();
68 assert(pid >= 0); 68 assert(pid >= 0);
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index dc870cf31b7..555aefd7fe0 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -27,32 +27,32 @@
27#include "util/sort.h" 27#include "util/sort.h"
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30#include "util/tool.h"
31#include "arch/common.h"
32 30
33#include <linux/bitmap.h> 31#include <linux/bitmap.h>
34 32
35struct perf_annotate { 33static char const *input_name = "perf.data";
36 struct perf_tool tool; 34
37 bool force, use_tui, use_stdio; 35static bool force, use_tui, use_stdio;
38 bool full_paths; 36
39 bool print_line; 37static bool full_paths;
40 const char *sym_hist_filter; 38
41 const char *cpu_list; 39static bool print_line;
42 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 40
43}; 41static const char *sym_hist_filter;
44 42
45static int perf_evsel__add_sample(struct perf_evsel *evsel, 43static const char *cpu_list;
46 struct perf_sample *sample, 44static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
47 struct addr_location *al, 45
48 struct perf_annotate *ann) 46static int perf_evlist__add_sample(struct perf_evlist *evlist,
47 struct perf_sample *sample,
48 struct perf_evsel *evsel,
49 struct addr_location *al)
49{ 50{
50 struct hist_entry *he; 51 struct hist_entry *he;
51 int ret; 52 int ret;
52 53
53 if (ann->sym_hist_filter != NULL && 54 if (sym_hist_filter != NULL &&
54 (al->sym == NULL || 55 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
55 strcmp(ann->sym_hist_filter, al->sym->name) != 0)) {
56 /* We're only interested in a symbol named sym_hist_filter */ 56 /* We're only interested in a symbol named sym_hist_filter */
57 if (al->sym != NULL) { 57 if (al->sym != NULL) {
58 rb_erase(&al->sym->rb_node, 58 rb_erase(&al->sym->rb_node,
@@ -69,7 +69,8 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
69 ret = 0; 69 ret = 0;
70 if (he->ms.sym != NULL) { 70 if (he->ms.sym != NULL) {
71 struct annotation *notes = symbol__annotation(he->ms.sym); 71 struct annotation *notes = symbol__annotation(he->ms.sym);
72 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) 72 if (notes->src == NULL &&
73 symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
73 return -ENOMEM; 74 return -ENOMEM;
74 75
75 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 76 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
@@ -80,26 +81,25 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
80 return ret; 81 return ret;
81} 82}
82 83
83static int process_sample_event(struct perf_tool *tool, 84static int process_sample_event(union perf_event *event,
84 union perf_event *event,
85 struct perf_sample *sample, 85 struct perf_sample *sample,
86 struct perf_evsel *evsel, 86 struct perf_evsel *evsel,
87 struct machine *machine) 87 struct perf_session *session)
88{ 88{
89 struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
90 struct addr_location al; 89 struct addr_location al;
91 90
92 if (perf_event__preprocess_sample(event, machine, &al, sample, 91 if (perf_event__preprocess_sample(event, session, &al, sample,
93 symbol__annotate_init) < 0) { 92 symbol__annotate_init) < 0) {
94 pr_warning("problem processing %d event, skipping it.\n", 93 pr_warning("problem processing %d event, skipping it.\n",
95 event->header.type); 94 event->header.type);
96 return -1; 95 return -1;
97 } 96 }
98 97
99 if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) 98 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
100 return 0; 99 return 0;
101 100
102 if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) { 101 if (!al.filtered &&
102 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
103 pr_warning("problem incrementing symbol count, " 103 pr_warning("problem incrementing symbol count, "
104 "skipping event\n"); 104 "skipping event\n");
105 return -1; 105 return -1;
@@ -108,18 +108,16 @@ static int process_sample_event(struct perf_tool *tool,
108 return 0; 108 return 0;
109} 109}
110 110
111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, 111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
112 struct perf_annotate *ann)
113{ 112{
114 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, 113 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
115 ann->print_line, ann->full_paths, 0, 0); 114 print_line, full_paths, 0, 0);
116} 115}
117 116
118static void hists__find_annotations(struct hists *self, int evidx, 117static void hists__find_annotations(struct hists *self, int evidx)
119 struct perf_annotate *ann)
120{ 118{
121 struct rb_node *nd = rb_first(&self->entries), *next; 119 struct rb_node *nd = rb_first(&self->entries), *next;
122 int key = K_RIGHT; 120 int key = KEY_RIGHT;
123 121
124 while (nd) { 122 while (nd) {
125 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 123 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
@@ -131,7 +129,7 @@ static void hists__find_annotations(struct hists *self, int evidx,
131 notes = symbol__annotation(he->ms.sym); 129 notes = symbol__annotation(he->ms.sym);
132 if (notes->src == NULL) { 130 if (notes->src == NULL) {
133find_next: 131find_next:
134 if (key == K_LEFT) 132 if (key == KEY_LEFT)
135 nd = rb_prev(nd); 133 nd = rb_prev(nd);
136 else 134 else
137 nd = rb_next(nd); 135 nd = rb_next(nd);
@@ -139,12 +137,12 @@ find_next:
139 } 137 }
140 138
141 if (use_browser > 0) { 139 if (use_browser > 0) {
142 key = hist_entry__tui_annotate(he, evidx, NULL); 140 key = hist_entry__tui_annotate(he, evidx);
143 switch (key) { 141 switch (key) {
144 case K_RIGHT: 142 case KEY_RIGHT:
145 next = rb_next(nd); 143 next = rb_next(nd);
146 break; 144 break;
147 case K_LEFT: 145 case KEY_LEFT:
148 next = rb_prev(nd); 146 next = rb_prev(nd);
149 break; 147 break;
150 default: 148 default:
@@ -154,7 +152,7 @@ find_next:
154 if (next != NULL) 152 if (next != NULL)
155 nd = next; 153 nd = next;
156 } else { 154 } else {
157 hist_entry__tty_annotate(he, evidx, ann); 155 hist_entry__tty_annotate(he, evidx);
158 nd = rb_next(nd); 156 nd = rb_next(nd);
159 /* 157 /*
160 * Since we have a hist_entry per IP for the same 158 * Since we have a hist_entry per IP for the same
@@ -167,32 +165,33 @@ find_next:
167 } 165 }
168} 166}
169 167
170static int __cmd_annotate(struct perf_annotate *ann) 168static struct perf_event_ops event_ops = {
169 .sample = process_sample_event,
170 .mmap = perf_event__process_mmap,
171 .comm = perf_event__process_comm,
172 .fork = perf_event__process_task,
173 .ordered_samples = true,
174 .ordering_requires_timestamps = true,
175};
176
177static int __cmd_annotate(void)
171{ 178{
172 int ret; 179 int ret;
173 struct perf_session *session; 180 struct perf_session *session;
174 struct perf_evsel *pos; 181 struct perf_evsel *pos;
175 u64 total_nr_samples; 182 u64 total_nr_samples;
176 183
177 session = perf_session__new(input_name, O_RDONLY, 184 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
178 ann->force, false, &ann->tool);
179 if (session == NULL) 185 if (session == NULL)
180 return -ENOMEM; 186 return -ENOMEM;
181 187
182 if (ann->cpu_list) { 188 if (cpu_list) {
183 ret = perf_session__cpu_bitmap(session, ann->cpu_list, 189 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
184 ann->cpu_bitmap);
185 if (ret)
186 goto out_delete;
187 }
188
189 if (!objdump_path) {
190 ret = perf_session_env__lookup_objdump(&session->header.env);
191 if (ret) 190 if (ret)
192 goto out_delete; 191 goto out_delete;
193 } 192 }
194 193
195 ret = perf_session__process_events(session, &ann->tool); 194 ret = perf_session__process_events(session, &event_ops);
196 if (ret) 195 if (ret)
197 goto out_delete; 196 goto out_delete;
198 197
@@ -216,12 +215,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
216 total_nr_samples += nr_samples; 215 total_nr_samples += nr_samples;
217 hists__collapse_resort(hists); 216 hists__collapse_resort(hists);
218 hists__output_resort(hists); 217 hists__output_resort(hists);
219 hists__find_annotations(hists, pos->idx, ann); 218 hists__find_annotations(hists, pos->idx);
220 } 219 }
221 } 220 }
222 221
223 if (total_nr_samples == 0) { 222 if (total_nr_samples == 0) {
224 ui__error("The %s file has no samples!\n", session->filename); 223 ui__warning("The %s file has no samples!\n", input_name);
225 goto out_delete; 224 goto out_delete;
226 } 225 }
227out_delete: 226out_delete:
@@ -241,64 +240,43 @@ out_delete:
241} 240}
242 241
243static const char * const annotate_usage[] = { 242static const char * const annotate_usage[] = {
244 "perf annotate [<options>]", 243 "perf annotate [<options>] <command>",
245 NULL 244 NULL
246}; 245};
247 246
248int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) 247static const struct option options[] = {
249{
250 struct perf_annotate annotate = {
251 .tool = {
252 .sample = process_sample_event,
253 .mmap = perf_event__process_mmap,
254 .comm = perf_event__process_comm,
255 .exit = perf_event__process_exit,
256 .fork = perf_event__process_fork,
257 .ordered_samples = true,
258 .ordering_requires_timestamps = true,
259 },
260 };
261 const struct option options[] = {
262 OPT_STRING('i', "input", &input_name, "file", 248 OPT_STRING('i', "input", &input_name, "file",
263 "input file name"), 249 "input file name"),
264 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 250 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
265 "only consider symbols in these dsos"), 251 "only consider symbols in these dsos"),
266 OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", 252 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
267 "symbol to annotate"), 253 "symbol to annotate"),
268 OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"), 254 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
269 OPT_INCR('v', "verbose", &verbose, 255 OPT_INCR('v', "verbose", &verbose,
270 "be more verbose (show symbol address, etc)"), 256 "be more verbose (show symbol address, etc)"),
271 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 257 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
272 "dump raw trace in ASCII"), 258 "dump raw trace in ASCII"),
273 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), 259 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
274 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), 260 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
275 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 261 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
276 "file", "vmlinux pathname"), 262 "file", "vmlinux pathname"),
277 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 263 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
278 "load module symbols - WARNING: use only with -k and LIVE kernel"), 264 "load module symbols - WARNING: use only with -k and LIVE kernel"),
279 OPT_BOOLEAN('l', "print-line", &annotate.print_line, 265 OPT_BOOLEAN('l', "print-line", &print_line,
280 "print matching source lines (may be slow)"), 266 "print matching source lines (may be slow)"),
281 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, 267 OPT_BOOLEAN('P', "full-paths", &full_paths,
282 "Don't shorten the displayed pathnames"), 268 "Don't shorten the displayed pathnames"),
283 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), 269 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
284 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
285 "Look for files with symbols relative to this directory"),
286 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
287 "Interleave source code with assembly code (default)"),
288 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
289 "Display raw encoding of assembly instructions (default)"),
290 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
291 "Specify disassembler style (e.g. -M intel for intel syntax)"),
292 OPT_STRING(0, "objdump", &objdump_path, "path",
293 "objdump binary to use for disassembly and annotations"),
294 OPT_END() 270 OPT_END()
295 }; 271};
296 272
273int cmd_annotate(int argc, const char **argv, const char *prefix __used)
274{
297 argc = parse_options(argc, argv, options, annotate_usage, 0); 275 argc = parse_options(argc, argv, options, annotate_usage, 0);
298 276
299 if (annotate.use_stdio) 277 if (use_stdio)
300 use_browser = 0; 278 use_browser = 0;
301 else if (annotate.use_tui) 279 else if (use_tui)
302 use_browser = 1; 280 use_browser = 1;
303 281
304 setup_browser(true); 282 setup_browser(true);
@@ -319,8 +297,13 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
319 if (argc > 1) 297 if (argc > 1)
320 usage_with_options(annotate_usage, options); 298 usage_with_options(annotate_usage, options);
321 299
322 annotate.sym_hist_filter = argv[0]; 300 sym_hist_filter = argv[0];
301 }
302
303 if (field_sep && *field_sep == '.') {
304 pr_err("'.' is the only non valid --field-separator argument\n");
305 return -1;
323 } 306 }
324 307
325 return __cmd_annotate(&annotate); 308 return __cmd_annotate();
326} 309}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index cae9a5fd2ec..fcb96269852 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -33,7 +33,7 @@ struct bench_suite {
33}; 33};
34 \ 34 \
35/* sentinel: easy for help */ 35/* sentinel: easy for help */
36#define suite_all { "all", "Test all benchmark suites", NULL } 36#define suite_all { "all", "test all suite (pseudo suite)", NULL }
37 37
38static struct bench_suite sched_suites[] = { 38static struct bench_suite sched_suites[] = {
39 { "messaging", 39 { "messaging",
@@ -52,9 +52,6 @@ static struct bench_suite mem_suites[] = {
52 { "memcpy", 52 { "memcpy",
53 "Simple memory copy in various ways", 53 "Simple memory copy in various ways",
54 bench_mem_memcpy }, 54 bench_mem_memcpy },
55 { "memset",
56 "Simple memory set in various ways",
57 bench_mem_memset },
58 suite_all, 55 suite_all,
59 { NULL, 56 { NULL,
60 NULL, 57 NULL,
@@ -75,7 +72,7 @@ static struct bench_subsys subsystems[] = {
75 "memory access performance", 72 "memory access performance",
76 mem_suites }, 73 mem_suites },
77 { "all", /* sentinel: easy for help */ 74 { "all", /* sentinel: easy for help */
78 "all benchmark subsystem", 75 "test all subsystem (pseudo subsystem)",
79 NULL }, 76 NULL },
80 { NULL, 77 { NULL,
81 NULL, 78 NULL,
@@ -173,7 +170,7 @@ static void all_subsystem(void)
173 all_suite(&subsystems[i]); 170 all_suite(&subsystems[i]);
174} 171}
175 172
176int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) 173int cmd_bench(int argc, const char **argv, const char *prefix __used)
177{ 174{
178 int i, j, status = 0; 175 int i, j, status = 0;
179 176
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index fae8b250b2c..29ad20e6791 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -13,9 +13,24 @@
13#include "util/header.h" 13#include "util/header.h"
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/strlist.h" 15#include "util/strlist.h"
16#include "util/build-id.h"
17#include "util/symbol.h" 16#include "util/symbol.h"
18 17
18static char const *add_name_list_str, *remove_name_list_str;
19
20static const char * const buildid_cache_usage[] = {
21 "perf buildid-cache [<options>]",
22 NULL
23};
24
25static const struct option buildid_cache_options[] = {
26 OPT_STRING('a', "add", &add_name_list_str,
27 "file list", "file(s) to add"),
28 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
29 "file(s) to remove"),
30 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
31 OPT_END()
32};
33
19static int build_id_cache__add_file(const char *filename, const char *debugdir) 34static int build_id_cache__add_file(const char *filename, const char *debugdir)
20{ 35{
21 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 36 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -28,16 +43,15 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir)
28 } 43 }
29 44
30 build_id__sprintf(build_id, sizeof(build_id), sbuild_id); 45 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
31 err = build_id_cache__add_s(sbuild_id, debugdir, filename, 46 err = build_id_cache__add_s(sbuild_id, debugdir, filename, false);
32 false, false);
33 if (verbose) 47 if (verbose)
34 pr_info("Adding %s %s: %s\n", sbuild_id, filename, 48 pr_info("Adding %s %s: %s\n", sbuild_id, filename,
35 err ? "FAIL" : "Ok"); 49 err ? "FAIL" : "Ok");
36 return err; 50 return err;
37} 51}
38 52
39static int build_id_cache__remove_file(const char *filename, 53static int build_id_cache__remove_file(const char *filename __used,
40 const char *debugdir) 54 const char *debugdir __used)
41{ 55{
42 u8 build_id[BUILD_ID_SIZE]; 56 u8 build_id[BUILD_ID_SIZE];
43 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 57 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -58,34 +72,11 @@ static int build_id_cache__remove_file(const char *filename,
58 return err; 72 return err;
59} 73}
60 74
61int cmd_buildid_cache(int argc, const char **argv, 75static int __cmd_buildid_cache(void)
62 const char *prefix __maybe_unused)
63{ 76{
64 struct strlist *list; 77 struct strlist *list;
65 struct str_node *pos; 78 struct str_node *pos;
66 char debugdir[PATH_MAX]; 79 char debugdir[PATH_MAX];
67 char const *add_name_list_str = NULL,
68 *remove_name_list_str = NULL;
69 const struct option buildid_cache_options[] = {
70 OPT_STRING('a', "add", &add_name_list_str,
71 "file list", "file(s) to add"),
72 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
73 "file(s) to remove"),
74 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
75 OPT_END()
76 };
77 const char * const buildid_cache_usage[] = {
78 "perf buildid-cache [<options>]",
79 NULL
80 };
81
82 argc = parse_options(argc, argv, buildid_cache_options,
83 buildid_cache_usage, 0);
84
85 if (symbol__init() < 0)
86 return -1;
87
88 setup_pager();
89 80
90 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); 81 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
91 82
@@ -127,3 +118,15 @@ int cmd_buildid_cache(int argc, const char **argv,
127 118
128 return 0; 119 return 0;
129} 120}
121
122int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used)
123{
124 argc = parse_options(argc, argv, buildid_cache_options,
125 buildid_cache_usage, 0);
126
127 if (symbol__init() < 0)
128 return -1;
129
130 setup_pager();
131 return __cmd_buildid_cache();
132}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index a82d99fec83..5af32ae9031 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -1,8 +1,7 @@
1/* 1/*
2 * builtin-buildid-list.c 2 * builtin-buildid-list.c
3 * 3 *
4 * Builtin buildid-list command: list buildids in perf.data, in the running 4 * Builtin buildid-list command: list buildids in perf.data
5 * kernel and in ELF files.
6 * 5 *
7 * Copyright (C) 2009, Red Hat Inc. 6 * Copyright (C) 2009, Red Hat Inc.
8 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com> 7 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
@@ -16,88 +15,46 @@
16#include "util/session.h" 15#include "util/session.h"
17#include "util/symbol.h" 16#include "util/symbol.h"
18 17
19static int sysfs__fprintf_build_id(FILE *fp) 18static char const *input_name = "perf.data";
20{ 19static bool force;
21 u8 kallsyms_build_id[BUILD_ID_SIZE]; 20static bool with_hits;
22 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
23
24 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
25 sizeof(kallsyms_build_id)) != 0)
26 return -1;
27 21
28 build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id), 22static const char * const buildid_list_usage[] = {
29 sbuild_id); 23 "perf buildid-list [<options>]",
30 fprintf(fp, "%s\n", sbuild_id); 24 NULL
31 return 0; 25};
32}
33 26
34static int filename__fprintf_build_id(const char *name, FILE *fp) 27static const struct option options[] = {
35{ 28 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
36 u8 build_id[BUILD_ID_SIZE]; 29 OPT_STRING('i', "input", &input_name, "file",
37 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 30 "input file name"),
38 31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
39 if (filename__read_build_id(name, build_id, 32 OPT_INCR('v', "verbose", &verbose,
40 sizeof(build_id)) != sizeof(build_id)) 33 "be more verbose"),
41 return 0; 34 OPT_END()
42 35};
43 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
44 return fprintf(fp, "%s\n", sbuild_id);
45}
46 36
47static int perf_session__list_build_ids(bool force, bool with_hits) 37static int __cmd_buildid_list(void)
48{ 38{
49 struct perf_session *session; 39 struct perf_session *session;
50 40
51 symbol__elf_init();
52
53 session = perf_session__new(input_name, O_RDONLY, force, false, 41 session = perf_session__new(input_name, O_RDONLY, force, false,
54 &build_id__mark_dso_hit_ops); 42 &build_id__mark_dso_hit_ops);
55 if (session == NULL) 43 if (session == NULL)
56 return -1; 44 return -1;
57 45
58 /* 46 if (with_hits)
59 * See if this is an ELF file first:
60 */
61 if (filename__fprintf_build_id(session->filename, stdout))
62 goto out;
63
64 /*
65 * in pipe-mode, the only way to get the buildids is to parse
66 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
67 */
68 if (with_hits || session->fd_pipe)
69 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 47 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
70 48
71 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 49 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
72out: 50
73 perf_session__delete(session); 51 perf_session__delete(session);
74 return 0; 52 return 0;
75} 53}
76 54
77int cmd_buildid_list(int argc, const char **argv, 55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
78 const char *prefix __maybe_unused)
79{ 56{
80 bool show_kernel = false;
81 bool with_hits = false;
82 bool force = false;
83 const struct option options[] = {
84 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
85 OPT_STRING('i', "input", &input_name, "file", "input file name"),
86 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
87 OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"),
88 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
89 OPT_END()
90 };
91 const char * const buildid_list_usage[] = {
92 "perf buildid-list [<options>]",
93 NULL
94 };
95
96 argc = parse_options(argc, argv, options, buildid_list_usage, 0); 57 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
97 setup_pager(); 58 setup_pager();
98 59 return __cmd_buildid_list();
99 if (show_kernel)
100 return sysfs__fprintf_build_id(stdout);
101
102 return perf_session__list_build_ids(force, with_hits);
103} 60}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 93b852f8a5d..e8219990f8b 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -9,10 +9,7 @@
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/event.h" 10#include "util/event.h"
11#include "util/hist.h" 11#include "util/hist.h"
12#include "util/evsel.h"
13#include "util/evlist.h"
14#include "util/session.h" 12#include "util/session.h"
15#include "util/tool.h"
16#include "util/sort.h" 13#include "util/sort.h"
17#include "util/symbol.h" 14#include "util/symbol.h"
18#include "util/util.h" 15#include "util/util.h"
@@ -24,228 +21,6 @@ static char const *input_old = "perf.data.old",
24static char diff__default_sort_order[] = "dso,symbol"; 21static char diff__default_sort_order[] = "dso,symbol";
25static bool force; 22static bool force;
26static bool show_displacement; 23static bool show_displacement;
27static bool show_period;
28static bool show_formula;
29static bool show_baseline_only;
30static bool sort_compute;
31
32static s64 compute_wdiff_w1;
33static s64 compute_wdiff_w2;
34
35enum {
36 COMPUTE_DELTA,
37 COMPUTE_RATIO,
38 COMPUTE_WEIGHTED_DIFF,
39 COMPUTE_MAX,
40};
41
42const char *compute_names[COMPUTE_MAX] = {
43 [COMPUTE_DELTA] = "delta",
44 [COMPUTE_RATIO] = "ratio",
45 [COMPUTE_WEIGHTED_DIFF] = "wdiff",
46};
47
48static int compute;
49
50static int setup_compute_opt_wdiff(char *opt)
51{
52 char *w1_str = opt;
53 char *w2_str;
54
55 int ret = -EINVAL;
56
57 if (!opt)
58 goto out;
59
60 w2_str = strchr(opt, ',');
61 if (!w2_str)
62 goto out;
63
64 *w2_str++ = 0x0;
65 if (!*w2_str)
66 goto out;
67
68 compute_wdiff_w1 = strtol(w1_str, NULL, 10);
69 compute_wdiff_w2 = strtol(w2_str, NULL, 10);
70
71 if (!compute_wdiff_w1 || !compute_wdiff_w2)
72 goto out;
73
74 pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
75 compute_wdiff_w1, compute_wdiff_w2);
76
77 ret = 0;
78
79 out:
80 if (ret)
81 pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
82
83 return ret;
84}
85
86static int setup_compute_opt(char *opt)
87{
88 if (compute == COMPUTE_WEIGHTED_DIFF)
89 return setup_compute_opt_wdiff(opt);
90
91 if (opt) {
92 pr_err("Failed: extra option specified '%s'", opt);
93 return -EINVAL;
94 }
95
96 return 0;
97}
98
99static int setup_compute(const struct option *opt, const char *str,
100 int unset __maybe_unused)
101{
102 int *cp = (int *) opt->value;
103 char *cstr = (char *) str;
104 char buf[50];
105 unsigned i;
106 char *option;
107
108 if (!str) {
109 *cp = COMPUTE_DELTA;
110 return 0;
111 }
112
113 if (*str == '+') {
114 sort_compute = true;
115 cstr = (char *) ++str;
116 if (!*str)
117 return 0;
118 }
119
120 option = strchr(str, ':');
121 if (option) {
122 unsigned len = option++ - str;
123
124 /*
125 * The str data are not writeable, so we need
126 * to use another buffer.
127 */
128
129 /* No option value is longer. */
130 if (len >= sizeof(buf))
131 return -EINVAL;
132
133 strncpy(buf, str, len);
134 buf[len] = 0x0;
135 cstr = buf;
136 }
137
138 for (i = 0; i < COMPUTE_MAX; i++)
139 if (!strcmp(cstr, compute_names[i])) {
140 *cp = i;
141 return setup_compute_opt(option);
142 }
143
144 pr_err("Failed: '%s' is not computation method "
145 "(use 'delta','ratio' or 'wdiff')\n", str);
146 return -EINVAL;
147}
148
149static double get_period_percent(struct hist_entry *he, u64 period)
150{
151 u64 total = he->hists->stats.total_period;
152 return (period * 100.0) / total;
153}
154
155double perf_diff__compute_delta(struct hist_entry *he)
156{
157 struct hist_entry *pair = hist_entry__next_pair(he);
158 double new_percent = get_period_percent(he, he->stat.period);
159 double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0;
160
161 he->diff.period_ratio_delta = new_percent - old_percent;
162 he->diff.computed = true;
163 return he->diff.period_ratio_delta;
164}
165
166double perf_diff__compute_ratio(struct hist_entry *he)
167{
168 struct hist_entry *pair = hist_entry__next_pair(he);
169 double new_period = he->stat.period;
170 double old_period = pair ? pair->stat.period : 0;
171
172 he->diff.computed = true;
173 he->diff.period_ratio = pair ? (new_period / old_period) : 0;
174 return he->diff.period_ratio;
175}
176
177s64 perf_diff__compute_wdiff(struct hist_entry *he)
178{
179 struct hist_entry *pair = hist_entry__next_pair(he);
180 u64 new_period = he->stat.period;
181 u64 old_period = pair ? pair->stat.period : 0;
182
183 he->diff.computed = true;
184
185 if (!pair)
186 he->diff.wdiff = 0;
187 else
188 he->diff.wdiff = new_period * compute_wdiff_w2 -
189 old_period * compute_wdiff_w1;
190
191 return he->diff.wdiff;
192}
193
194static int formula_delta(struct hist_entry *he, char *buf, size_t size)
195{
196 struct hist_entry *pair = hist_entry__next_pair(he);
197
198 if (!pair)
199 return -1;
200
201 return scnprintf(buf, size,
202 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
203 "(%" PRIu64 " * 100 / %" PRIu64 ")",
204 he->stat.period, he->hists->stats.total_period,
205 pair->stat.period, pair->hists->stats.total_period);
206}
207
208static int formula_ratio(struct hist_entry *he, char *buf, size_t size)
209{
210 struct hist_entry *pair = hist_entry__next_pair(he);
211 double new_period = he->stat.period;
212 double old_period = pair ? pair->stat.period : 0;
213
214 if (!pair)
215 return -1;
216
217 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
218}
219
220static int formula_wdiff(struct hist_entry *he, char *buf, size_t size)
221{
222 struct hist_entry *pair = hist_entry__next_pair(he);
223 u64 new_period = he->stat.period;
224 u64 old_period = pair ? pair->stat.period : 0;
225
226 if (!pair)
227 return -1;
228
229 return scnprintf(buf, size,
230 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
231 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
232}
233
234int perf_diff__formula(char *buf, size_t size, struct hist_entry *he)
235{
236 switch (compute) {
237 case COMPUTE_DELTA:
238 return formula_delta(he, buf, size);
239 case COMPUTE_RATIO:
240 return formula_ratio(he, buf, size);
241 case COMPUTE_WEIGHTED_DIFF:
242 return formula_wdiff(he, buf, size);
243 default:
244 BUG_ON(1);
245 }
246
247 return -1;
248}
249 24
250static int hists__add_entry(struct hists *self, 25static int hists__add_entry(struct hists *self,
251 struct addr_location *al, u64 period) 26 struct addr_location *al, u64 period)
@@ -255,45 +30,44 @@ static int hists__add_entry(struct hists *self,
255 return -ENOMEM; 30 return -ENOMEM;
256} 31}
257 32
258static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, 33static int diff__process_sample_event(union perf_event *event,
259 union perf_event *event,
260 struct perf_sample *sample, 34 struct perf_sample *sample,
261 struct perf_evsel *evsel, 35 struct perf_evsel *evsel __used,
262 struct machine *machine) 36 struct perf_session *session)
263{ 37{
264 struct addr_location al; 38 struct addr_location al;
265 39
266 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { 40 if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
267 pr_warning("problem processing %d event, skipping it.\n", 41 pr_warning("problem processing %d event, skipping it.\n",
268 event->header.type); 42 event->header.type);
269 return -1; 43 return -1;
270 } 44 }
271 45
272 if (al.filtered) 46 if (al.filtered || al.sym == NULL)
273 return 0; 47 return 0;
274 48
275 if (hists__add_entry(&evsel->hists, &al, sample->period)) { 49 if (hists__add_entry(&session->hists, &al, sample->period)) {
276 pr_warning("problem incrementing symbol period, skipping event\n"); 50 pr_warning("problem incrementing symbol period, skipping event\n");
277 return -1; 51 return -1;
278 } 52 }
279 53
280 evsel->hists.stats.total_period += sample->period; 54 session->hists.stats.total_period += sample->period;
281 return 0; 55 return 0;
282} 56}
283 57
284static struct perf_tool tool = { 58static struct perf_event_ops event_ops = {
285 .sample = diff__process_sample_event, 59 .sample = diff__process_sample_event,
286 .mmap = perf_event__process_mmap, 60 .mmap = perf_event__process_mmap,
287 .comm = perf_event__process_comm, 61 .comm = perf_event__process_comm,
288 .exit = perf_event__process_exit, 62 .exit = perf_event__process_task,
289 .fork = perf_event__process_fork, 63 .fork = perf_event__process_task,
290 .lost = perf_event__process_lost, 64 .lost = perf_event__process_lost,
291 .ordered_samples = true, 65 .ordered_samples = true,
292 .ordering_requires_timestamps = true, 66 .ordering_requires_timestamps = true,
293}; 67};
294 68
295static void insert_hist_entry_by_name(struct rb_root *root, 69static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
296 struct hist_entry *he) 70 struct hist_entry *he)
297{ 71{
298 struct rb_node **p = &root->rb_node; 72 struct rb_node **p = &root->rb_node;
299 struct rb_node *parent = NULL; 73 struct rb_node *parent = NULL;
@@ -312,7 +86,7 @@ static void insert_hist_entry_by_name(struct rb_root *root,
312 rb_insert_color(&he->rb_node, root); 86 rb_insert_color(&he->rb_node, root);
313} 87}
314 88
315static void hists__name_resort(struct hists *self, bool sort) 89static void hists__resort_entries(struct hists *self)
316{ 90{
317 unsigned long position = 1; 91 unsigned long position = 1;
318 struct rb_root tmp = RB_ROOT; 92 struct rb_root tmp = RB_ROOT;
@@ -322,236 +96,77 @@ static void hists__name_resort(struct hists *self, bool sort)
322 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); 96 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
323 97
324 next = rb_next(&n->rb_node); 98 next = rb_next(&n->rb_node);
99 rb_erase(&n->rb_node, &self->entries);
325 n->position = position++; 100 n->position = position++;
326 101 perf_session__insert_hist_entry_by_name(&tmp, n);
327 if (sort) {
328 rb_erase(&n->rb_node, &self->entries);
329 insert_hist_entry_by_name(&tmp, n);
330 }
331 } 102 }
332 103
333 if (sort) 104 self->entries = tmp;
334 self->entries = tmp;
335} 105}
336 106
337static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 107static void hists__set_positions(struct hists *self)
338 struct perf_evlist *evlist)
339{ 108{
340 struct perf_evsel *e; 109 hists__output_resort(self);
341 110 hists__resort_entries(self);
342 list_for_each_entry(e, &evlist->entries, node)
343 if (perf_evsel__match2(evsel, e))
344 return e;
345
346 return NULL;
347}
348
349static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name)
350{
351 struct perf_evsel *evsel;
352
353 list_for_each_entry(evsel, &evlist->entries, node) {
354 struct hists *hists = &evsel->hists;
355
356 hists__output_resort(hists);
357
358 /*
359 * The hists__name_resort only sets possition
360 * if name is false.
361 */
362 if (name || ((!name) && show_displacement))
363 hists__name_resort(hists, name);
364 }
365}
366
367static void hists__baseline_only(struct hists *hists)
368{
369 struct rb_node *next = rb_first(&hists->entries);
370
371 while (next != NULL) {
372 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
373
374 next = rb_next(&he->rb_node);
375 if (!hist_entry__next_pair(he)) {
376 rb_erase(&he->rb_node, &hists->entries);
377 hist_entry__free(he);
378 }
379 }
380}
381
382static void hists__precompute(struct hists *hists)
383{
384 struct rb_node *next = rb_first(&hists->entries);
385
386 while (next != NULL) {
387 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
388
389 next = rb_next(&he->rb_node);
390
391 switch (compute) {
392 case COMPUTE_DELTA:
393 perf_diff__compute_delta(he);
394 break;
395 case COMPUTE_RATIO:
396 perf_diff__compute_ratio(he);
397 break;
398 case COMPUTE_WEIGHTED_DIFF:
399 perf_diff__compute_wdiff(he);
400 break;
401 default:
402 BUG_ON(1);
403 }
404 }
405}
406
407static int64_t cmp_doubles(double l, double r)
408{
409 if (l > r)
410 return -1;
411 else if (l < r)
412 return 1;
413 else
414 return 0;
415}
416
417static int64_t
418hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
419 int c)
420{
421 switch (c) {
422 case COMPUTE_DELTA:
423 {
424 double l = left->diff.period_ratio_delta;
425 double r = right->diff.period_ratio_delta;
426
427 return cmp_doubles(l, r);
428 }
429 case COMPUTE_RATIO:
430 {
431 double l = left->diff.period_ratio;
432 double r = right->diff.period_ratio;
433
434 return cmp_doubles(l, r);
435 }
436 case COMPUTE_WEIGHTED_DIFF:
437 {
438 s64 l = left->diff.wdiff;
439 s64 r = right->diff.wdiff;
440
441 return r - l;
442 }
443 default:
444 BUG_ON(1);
445 }
446
447 return 0;
448}
449
450static void insert_hist_entry_by_compute(struct rb_root *root,
451 struct hist_entry *he,
452 int c)
453{
454 struct rb_node **p = &root->rb_node;
455 struct rb_node *parent = NULL;
456 struct hist_entry *iter;
457
458 while (*p != NULL) {
459 parent = *p;
460 iter = rb_entry(parent, struct hist_entry, rb_node);
461 if (hist_entry__cmp_compute(he, iter, c) < 0)
462 p = &(*p)->rb_left;
463 else
464 p = &(*p)->rb_right;
465 }
466
467 rb_link_node(&he->rb_node, parent, p);
468 rb_insert_color(&he->rb_node, root);
469} 111}
470 112
471static void hists__compute_resort(struct hists *hists) 113static struct hist_entry *hists__find_entry(struct hists *self,
114 struct hist_entry *he)
472{ 115{
473 struct rb_root tmp = RB_ROOT; 116 struct rb_node *n = self->entries.rb_node;
474 struct rb_node *next = rb_first(&hists->entries);
475 117
476 while (next != NULL) { 118 while (n) {
477 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 119 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
120 int64_t cmp = hist_entry__cmp(he, iter);
478 121
479 next = rb_next(&he->rb_node); 122 if (cmp < 0)
480 123 n = n->rb_left;
481 rb_erase(&he->rb_node, &hists->entries); 124 else if (cmp > 0)
482 insert_hist_entry_by_compute(&tmp, he, compute); 125 n = n->rb_right;
126 else
127 return iter;
483 } 128 }
484 129
485 hists->entries = tmp; 130 return NULL;
486} 131}
487 132
488static void hists__process(struct hists *old, struct hists *new) 133static void hists__match(struct hists *older, struct hists *newer)
489{ 134{
490 hists__match(new, old); 135 struct rb_node *nd;
491 136
492 if (show_baseline_only) 137 for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) {
493 hists__baseline_only(new); 138 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
494 else 139 pos->pair = hists__find_entry(older, pos);
495 hists__link(new, old);
496
497 if (sort_compute) {
498 hists__precompute(new);
499 hists__compute_resort(new);
500 } 140 }
501
502 hists__fprintf(new, true, 0, 0, stdout);
503} 141}
504 142
505static int __cmd_diff(void) 143static int __cmd_diff(void)
506{ 144{
507 int ret, i; 145 int ret, i;
508#define older (session[0])
509#define newer (session[1])
510 struct perf_session *session[2]; 146 struct perf_session *session[2];
511 struct perf_evlist *evlist_new, *evlist_old; 147
512 struct perf_evsel *evsel; 148 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops);
513 bool first = true; 149 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
514
515 older = perf_session__new(input_old, O_RDONLY, force, false,
516 &tool);
517 newer = perf_session__new(input_new, O_RDONLY, force, false,
518 &tool);
519 if (session[0] == NULL || session[1] == NULL) 150 if (session[0] == NULL || session[1] == NULL)
520 return -ENOMEM; 151 return -ENOMEM;
521 152
522 for (i = 0; i < 2; ++i) { 153 for (i = 0; i < 2; ++i) {
523 ret = perf_session__process_events(session[i], &tool); 154 ret = perf_session__process_events(session[i], &event_ops);
524 if (ret) 155 if (ret)
525 goto out_delete; 156 goto out_delete;
526 } 157 }
527 158
528 evlist_old = older->evlist; 159 hists__output_resort(&session[1]->hists);
529 evlist_new = newer->evlist; 160 if (show_displacement)
530 161 hists__set_positions(&session[0]->hists);
531 perf_evlist__resort_hists(evlist_old, true);
532 perf_evlist__resort_hists(evlist_new, false);
533
534 list_for_each_entry(evsel, &evlist_new->entries, node) {
535 struct perf_evsel *evsel_old;
536
537 evsel_old = evsel_match(evsel, evlist_old);
538 if (!evsel_old)
539 continue;
540
541 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
542 perf_evsel__name(evsel));
543
544 first = false;
545
546 hists__process(&evsel_old->hists, &evsel->hists);
547 }
548 162
163 hists__match(&session[0]->hists, &session[1]->hists);
164 hists__fprintf(&session[1]->hists, &session[0]->hists,
165 show_displacement, stdout);
549out_delete: 166out_delete:
550 for (i = 0; i < 2; ++i) 167 for (i = 0; i < 2; ++i)
551 perf_session__delete(session[i]); 168 perf_session__delete(session[i]);
552 return ret; 169 return ret;
553#undef older
554#undef newer
555} 170}
556 171
557static const char * const diff_usage[] = { 172static const char * const diff_usage[] = {
@@ -564,16 +179,6 @@ static const struct option options[] = {
564 "be more verbose (show symbol address, etc)"), 179 "be more verbose (show symbol address, etc)"),
565 OPT_BOOLEAN('M', "displacement", &show_displacement, 180 OPT_BOOLEAN('M', "displacement", &show_displacement,
566 "Show position displacement relative to baseline"), 181 "Show position displacement relative to baseline"),
567 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
568 "Show only items with match in baseline"),
569 OPT_CALLBACK('c', "compute", &compute,
570 "delta,ratio,wdiff:w1,w2 (default delta)",
571 "Entries differential computation selection",
572 setup_compute),
573 OPT_BOOLEAN('p', "period", &show_period,
574 "Show period values."),
575 OPT_BOOLEAN('F', "formula", &show_formula,
576 "Show formula."),
577 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 182 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
578 "dump raw trace in ASCII"), 183 "dump raw trace in ASCII"),
579 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 184 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -595,46 +200,7 @@ static const struct option options[] = {
595 OPT_END() 200 OPT_END()
596}; 201};
597 202
598static void ui_init(void) 203int cmd_diff(int argc, const char **argv, const char *prefix __used)
599{
600 perf_hpp__init();
601
602 /* No overhead column. */
603 perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
604
605 /*
606 * Display baseline/delta/ratio/displacement/
607 * formula/periods columns.
608 */
609 perf_hpp__column_enable(PERF_HPP__BASELINE, true);
610
611 switch (compute) {
612 case COMPUTE_DELTA:
613 perf_hpp__column_enable(PERF_HPP__DELTA, true);
614 break;
615 case COMPUTE_RATIO:
616 perf_hpp__column_enable(PERF_HPP__RATIO, true);
617 break;
618 case COMPUTE_WEIGHTED_DIFF:
619 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true);
620 break;
621 default:
622 BUG_ON(1);
623 };
624
625 if (show_displacement)
626 perf_hpp__column_enable(PERF_HPP__DISPL, true);
627
628 if (show_formula)
629 perf_hpp__column_enable(PERF_HPP__FORMULA, true);
630
631 if (show_period) {
632 perf_hpp__column_enable(PERF_HPP__PERIOD, true);
633 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true);
634 }
635}
636
637int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
638{ 204{
639 sort_order = diff__default_sort_order; 205 sort_order = diff__default_sort_order;
640 argc = parse_options(argc, argv, options, diff_usage, 0); 206 argc = parse_options(argc, argv, options, diff_usage, 0);
@@ -656,8 +222,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
656 if (symbol__init() < 0) 222 if (symbol__init() < 0)
657 return -1; 223 return -1;
658 224
659 ui_init();
660
661 setup_sorting(diff_usage, options); 225 setup_sorting(diff_usage, options);
662 setup_pager(); 226 setup_pager();
663 227
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index c20f1dcfb7e..4c5e9e04a41 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,117 +15,40 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17 17
18struct perf_attr_details { 18static char const *input_name = "perf.data";
19 bool freq;
20 bool verbose;
21};
22
23static int comma_printf(bool *first, const char *fmt, ...)
24{
25 va_list args;
26 int ret = 0;
27
28 if (!*first) {
29 ret += printf(",");
30 } else {
31 ret += printf(":");
32 *first = false;
33 }
34
35 va_start(args, fmt);
36 ret += vprintf(fmt, args);
37 va_end(args);
38 return ret;
39}
40
41static int __if_print(bool *first, const char *field, u64 value)
42{
43 if (value == 0)
44 return 0;
45
46 return comma_printf(first, " %s: %" PRIu64, field, value);
47}
48 19
49#define if_print(field) __if_print(&first, #field, pos->attr.field) 20static int __cmd_evlist(void)
50
51static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
52{ 21{
53 struct perf_session *session; 22 struct perf_session *session;
54 struct perf_evsel *pos; 23 struct perf_evsel *pos;
55 24
56 session = perf_session__new(file_name, O_RDONLY, 0, false, NULL); 25 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
57 if (session == NULL) 26 if (session == NULL)
58 return -ENOMEM; 27 return -ENOMEM;
59 28
60 list_for_each_entry(pos, &session->evlist->entries, node) { 29 list_for_each_entry(pos, &session->evlist->entries, node)
61 bool first = true; 30 printf("%s\n", event_name(pos));
62
63 printf("%s", perf_evsel__name(pos));
64
65 if (details->verbose || details->freq) {
66 comma_printf(&first, " sample_freq=%" PRIu64,
67 (u64)pos->attr.sample_freq);
68 }
69
70 if (details->verbose) {
71 if_print(type);
72 if_print(config);
73 if_print(config1);
74 if_print(config2);
75 if_print(size);
76 if_print(sample_type);
77 if_print(read_format);
78 if_print(disabled);
79 if_print(inherit);
80 if_print(pinned);
81 if_print(exclusive);
82 if_print(exclude_user);
83 if_print(exclude_kernel);
84 if_print(exclude_hv);
85 if_print(exclude_idle);
86 if_print(mmap);
87 if_print(comm);
88 if_print(freq);
89 if_print(inherit_stat);
90 if_print(enable_on_exec);
91 if_print(task);
92 if_print(watermark);
93 if_print(precise_ip);
94 if_print(mmap_data);
95 if_print(sample_id_all);
96 if_print(exclude_host);
97 if_print(exclude_guest);
98 if_print(__reserved_1);
99 if_print(wakeup_events);
100 if_print(bp_type);
101 if_print(branch_sample_type);
102 }
103
104 putchar('\n');
105 }
106 31
107 perf_session__delete(session); 32 perf_session__delete(session);
108 return 0; 33 return 0;
109} 34}
110 35
111int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) 36static const char * const evlist_usage[] = {
112{ 37 "perf evlist [<options>]",
113 struct perf_attr_details details = { .verbose = false, }; 38 NULL
114 const struct option options[] = { 39};
115 OPT_STRING('i', "input", &input_name, "file", "Input file name"), 40
116 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), 41static const struct option options[] = {
117 OPT_BOOLEAN('v', "verbose", &details.verbose, 42 OPT_STRING('i', "input", &input_name, "file",
118 "Show all event attr details"), 43 "input file name"),
119 OPT_END() 44 OPT_END()
120 }; 45};
121 const char * const evlist_usage[] = {
122 "perf evlist [<options>]",
123 NULL
124 };
125 46
47int cmd_evlist(int argc, const char **argv, const char *prefix __used)
48{
126 argc = parse_options(argc, argv, options, evlist_usage, 0); 49 argc = parse_options(argc, argv, options, evlist_usage, 0);
127 if (argc) 50 if (argc)
128 usage_with_options(evlist_usage, options); 51 usage_with_options(evlist_usage, options);
129 52
130 return __cmd_evlist(input_name, &details); 53 return __cmd_evlist();
131} 54}
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 178b88ae3d2..6d5a8a7faf4 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -24,12 +24,28 @@ static struct man_viewer_info_list {
24} *man_viewer_info_list; 24} *man_viewer_info_list;
25 25
26enum help_format { 26enum help_format {
27 HELP_FORMAT_NONE,
28 HELP_FORMAT_MAN, 27 HELP_FORMAT_MAN,
29 HELP_FORMAT_INFO, 28 HELP_FORMAT_INFO,
30 HELP_FORMAT_WEB, 29 HELP_FORMAT_WEB,
31}; 30};
32 31
32static bool show_all = false;
33static enum help_format help_format = HELP_FORMAT_MAN;
34static struct option builtin_help_options[] = {
35 OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
36 OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
37 OPT_SET_UINT('w', "web", &help_format, "show manual in web browser",
38 HELP_FORMAT_WEB),
39 OPT_SET_UINT('i', "info", &help_format, "show info page",
40 HELP_FORMAT_INFO),
41 OPT_END(),
42};
43
44static const char * const builtin_help_usage[] = {
45 "perf help [--all] [--man|--web|--info] [command]",
46 NULL
47};
48
33static enum help_format parse_help_format(const char *format) 49static enum help_format parse_help_format(const char *format)
34{ 50{
35 if (!strcmp(format, "man")) 51 if (!strcmp(format, "man"))
@@ -38,9 +54,7 @@ static enum help_format parse_help_format(const char *format)
38 return HELP_FORMAT_INFO; 54 return HELP_FORMAT_INFO;
39 if (!strcmp(format, "web") || !strcmp(format, "html")) 55 if (!strcmp(format, "web") || !strcmp(format, "html"))
40 return HELP_FORMAT_WEB; 56 return HELP_FORMAT_WEB;
41 57 die("unrecognized help format '%s'", format);
42 pr_err("unrecognized help format '%s'", format);
43 return HELP_FORMAT_NONE;
44} 58}
45 59
46static const char *get_man_viewer_info(const char *name) 60static const char *get_man_viewer_info(const char *name)
@@ -241,14 +255,10 @@ static int add_man_viewer_info(const char *var, const char *value)
241 255
242static int perf_help_config(const char *var, const char *value, void *cb) 256static int perf_help_config(const char *var, const char *value, void *cb)
243{ 257{
244 enum help_format *help_formatp = cb;
245
246 if (!strcmp(var, "help.format")) { 258 if (!strcmp(var, "help.format")) {
247 if (!value) 259 if (!value)
248 return config_error_nonbool(var); 260 return config_error_nonbool(var);
249 *help_formatp = parse_help_format(value); 261 help_format = parse_help_format(value);
250 if (*help_formatp == HELP_FORMAT_NONE)
251 return -1;
252 return 0; 262 return 0;
253 } 263 }
254 if (!strcmp(var, "man.viewer")) { 264 if (!strcmp(var, "man.viewer")) {
@@ -342,7 +352,7 @@ static void exec_viewer(const char *name, const char *page)
342 warning("'%s': unknown man viewer.", name); 352 warning("'%s': unknown man viewer.", name);
343} 353}
344 354
345static int show_man_page(const char *perf_cmd) 355static void show_man_page(const char *perf_cmd)
346{ 356{
347 struct man_viewer_list *viewer; 357 struct man_viewer_list *viewer;
348 const char *page = cmd_to_page(perf_cmd); 358 const char *page = cmd_to_page(perf_cmd);
@@ -355,35 +365,28 @@ static int show_man_page(const char *perf_cmd)
355 if (fallback) 365 if (fallback)
356 exec_viewer(fallback, page); 366 exec_viewer(fallback, page);
357 exec_viewer("man", page); 367 exec_viewer("man", page);
358 368 die("no man viewer handled the request");
359 pr_err("no man viewer handled the request");
360 return -1;
361} 369}
362 370
363static int show_info_page(const char *perf_cmd) 371static void show_info_page(const char *perf_cmd)
364{ 372{
365 const char *page = cmd_to_page(perf_cmd); 373 const char *page = cmd_to_page(perf_cmd);
366 setenv("INFOPATH", system_path(PERF_INFO_PATH), 1); 374 setenv("INFOPATH", system_path(PERF_INFO_PATH), 1);
367 execlp("info", "info", "perfman", page, NULL); 375 execlp("info", "info", "perfman", page, NULL);
368 return -1;
369} 376}
370 377
371static int get_html_page_path(struct strbuf *page_path, const char *page) 378static void get_html_page_path(struct strbuf *page_path, const char *page)
372{ 379{
373 struct stat st; 380 struct stat st;
374 const char *html_path = system_path(PERF_HTML_PATH); 381 const char *html_path = system_path(PERF_HTML_PATH);
375 382
376 /* Check that we have a perf documentation directory. */ 383 /* Check that we have a perf documentation directory. */
377 if (stat(mkpath("%s/perf.html", html_path), &st) 384 if (stat(mkpath("%s/perf.html", html_path), &st)
378 || !S_ISREG(st.st_mode)) { 385 || !S_ISREG(st.st_mode))
379 pr_err("'%s': not a documentation directory.", html_path); 386 die("'%s': not a documentation directory.", html_path);
380 return -1;
381 }
382 387
383 strbuf_init(page_path, 0); 388 strbuf_init(page_path, 0);
384 strbuf_addf(page_path, "%s/%s.html", html_path, page); 389 strbuf_addf(page_path, "%s/%s.html", html_path, page);
385
386 return 0;
387} 390}
388 391
389/* 392/*
@@ -398,42 +401,23 @@ static void open_html(const char *path)
398} 401}
399#endif 402#endif
400 403
401static int show_html_page(const char *perf_cmd) 404static void show_html_page(const char *perf_cmd)
402{ 405{
403 const char *page = cmd_to_page(perf_cmd); 406 const char *page = cmd_to_page(perf_cmd);
404 struct strbuf page_path; /* it leaks but we exec bellow */ 407 struct strbuf page_path; /* it leaks but we exec bellow */
405 408
406 if (get_html_page_path(&page_path, page) != 0) 409 get_html_page_path(&page_path, page);
407 return -1;
408 410
409 open_html(page_path.buf); 411 open_html(page_path.buf);
410
411 return 0;
412} 412}
413 413
414int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) 414int cmd_help(int argc, const char **argv, const char *prefix __used)
415{ 415{
416 bool show_all = false;
417 enum help_format help_format = HELP_FORMAT_MAN;
418 struct option builtin_help_options[] = {
419 OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
420 OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
421 OPT_SET_UINT('w', "web", &help_format, "show manual in web browser",
422 HELP_FORMAT_WEB),
423 OPT_SET_UINT('i', "info", &help_format, "show info page",
424 HELP_FORMAT_INFO),
425 OPT_END(),
426 };
427 const char * const builtin_help_usage[] = {
428 "perf help [--all] [--man|--web|--info] [command]",
429 NULL
430 };
431 const char *alias; 416 const char *alias;
432 int rc = 0;
433 417
434 load_command_list("perf-", &main_cmds, &other_cmds); 418 load_command_list("perf-", &main_cmds, &other_cmds);
435 419
436 perf_config(perf_help_config, &help_format); 420 perf_config(perf_help_config, NULL);
437 421
438 argc = parse_options(argc, argv, builtin_help_options, 422 argc = parse_options(argc, argv, builtin_help_options,
439 builtin_help_usage, 0); 423 builtin_help_usage, 0);
@@ -460,20 +444,16 @@ int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused)
460 444
461 switch (help_format) { 445 switch (help_format) {
462 case HELP_FORMAT_MAN: 446 case HELP_FORMAT_MAN:
463 rc = show_man_page(argv[0]); 447 show_man_page(argv[0]);
464 break; 448 break;
465 case HELP_FORMAT_INFO: 449 case HELP_FORMAT_INFO:
466 rc = show_info_page(argv[0]); 450 show_info_page(argv[0]);
467 break; 451 break;
468 case HELP_FORMAT_WEB: 452 case HELP_FORMAT_WEB:
469 rc = show_html_page(argv[0]); 453 show_html_page(argv[0]);
470 break;
471 case HELP_FORMAT_NONE:
472 /* fall-through */
473 default: 454 default:
474 rc = -1;
475 break; 455 break;
476 } 456 }
477 457
478 return rc; 458 return 0;
479} 459}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 84ad6abe425..8dfc12bb119 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -8,142 +8,69 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "perf.h" 10#include "perf.h"
11#include "util/color.h"
12#include "util/evlist.h"
13#include "util/evsel.h"
14#include "util/session.h" 11#include "util/session.h"
15#include "util/tool.h"
16#include "util/debug.h" 12#include "util/debug.h"
17#include "util/build-id.h"
18 13
19#include "util/parse-options.h" 14#include "util/parse-options.h"
20 15
21#include <linux/list.h> 16static char const *input_name = "-";
22 17static bool inject_build_ids;
23struct perf_inject {
24 struct perf_tool tool;
25 bool build_ids;
26 bool sched_stat;
27 const char *input_name;
28 int pipe_output,
29 output;
30 u64 bytes_written;
31 struct list_head samples;
32};
33
34struct event_entry {
35 struct list_head node;
36 u32 tid;
37 union perf_event event[0];
38};
39 18
40static int perf_event__repipe_synth(struct perf_tool *tool, 19static int perf_event__repipe_synth(union perf_event *event,
41 union perf_event *event, 20 struct perf_session *session __used)
42 struct machine *machine __maybe_unused)
43{ 21{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
45 uint32_t size; 22 uint32_t size;
46 void *buf = event; 23 void *buf = event;
47 24
48 size = event->header.size; 25 size = event->header.size;
49 26
50 while (size) { 27 while (size) {
51 int ret = write(inject->output, buf, size); 28 int ret = write(STDOUT_FILENO, buf, size);
52 if (ret < 0) 29 if (ret < 0)
53 return -errno; 30 return -errno;
54 31
55 size -= ret; 32 size -= ret;
56 buf += ret; 33 buf += ret;
57 inject->bytes_written += ret;
58 } 34 }
59 35
60 return 0; 36 return 0;
61} 37}
62 38
63static int perf_event__repipe_op2_synth(struct perf_tool *tool, 39static int perf_event__repipe(union perf_event *event,
64 union perf_event *event, 40 struct perf_sample *sample __used,
65 struct perf_session *session 41 struct perf_session *session)
66 __maybe_unused)
67{
68 return perf_event__repipe_synth(tool, event, NULL);
69}
70
71static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
72 union perf_event *event)
73{
74 return perf_event__repipe_synth(tool, event, NULL);
75}
76
77static int perf_event__repipe_tracing_data_synth(union perf_event *event,
78 struct perf_session *session
79 __maybe_unused)
80{ 42{
81 return perf_event__repipe_synth(NULL, event, NULL); 43 return perf_event__repipe_synth(event, session);
82} 44}
83 45
84static int perf_event__repipe_attr(union perf_event *event, 46static int perf_event__repipe_sample(union perf_event *event,
85 struct perf_evlist **pevlist __maybe_unused) 47 struct perf_sample *sample __used,
48 struct perf_evsel *evsel __used,
49 struct perf_session *session)
86{ 50{
87 int ret; 51 return perf_event__repipe_synth(event, session);
88 ret = perf_event__process_attr(event, pevlist);
89 if (ret)
90 return ret;
91
92 return perf_event__repipe_synth(NULL, event, NULL);
93}
94
95static int perf_event__repipe(struct perf_tool *tool,
96 union perf_event *event,
97 struct perf_sample *sample __maybe_unused,
98 struct machine *machine)
99{
100 return perf_event__repipe_synth(tool, event, machine);
101}
102
103typedef int (*inject_handler)(struct perf_tool *tool,
104 union perf_event *event,
105 struct perf_sample *sample,
106 struct perf_evsel *evsel,
107 struct machine *machine);
108
109static int perf_event__repipe_sample(struct perf_tool *tool,
110 union perf_event *event,
111 struct perf_sample *sample,
112 struct perf_evsel *evsel,
113 struct machine *machine)
114{
115 if (evsel->handler.func) {
116 inject_handler f = evsel->handler.func;
117 return f(tool, event, sample, evsel, machine);
118 }
119
120 build_id__mark_dso_hit(tool, event, sample, evsel, machine);
121
122 return perf_event__repipe_synth(tool, event, machine);
123} 52}
124 53
125static int perf_event__repipe_mmap(struct perf_tool *tool, 54static int perf_event__repipe_mmap(union perf_event *event,
126 union perf_event *event,
127 struct perf_sample *sample, 55 struct perf_sample *sample,
128 struct machine *machine) 56 struct perf_session *session)
129{ 57{
130 int err; 58 int err;
131 59
132 err = perf_event__process_mmap(tool, event, sample, machine); 60 err = perf_event__process_mmap(event, sample, session);
133 perf_event__repipe(tool, event, sample, machine); 61 perf_event__repipe(event, sample, session);
134 62
135 return err; 63 return err;
136} 64}
137 65
138static int perf_event__repipe_fork(struct perf_tool *tool, 66static int perf_event__repipe_task(union perf_event *event,
139 union perf_event *event,
140 struct perf_sample *sample, 67 struct perf_sample *sample,
141 struct machine *machine) 68 struct perf_session *session)
142{ 69{
143 int err; 70 int err;
144 71
145 err = perf_event__process_fork(tool, event, sample, machine); 72 err = perf_event__process_task(event, sample, session);
146 perf_event__repipe(tool, event, sample, machine); 73 perf_event__repipe(event, sample, session);
147 74
148 return err; 75 return err;
149} 76}
@@ -153,7 +80,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event,
153{ 80{
154 int err; 81 int err;
155 82
156 perf_event__repipe_synth(NULL, event, NULL); 83 perf_event__repipe_synth(event, session);
157 err = perf_event__process_tracing_data(event, session); 84 err = perf_event__process_tracing_data(event, session);
158 85
159 return err; 86 return err;
@@ -173,10 +100,10 @@ static int dso__read_build_id(struct dso *self)
173 return -1; 100 return -1;
174} 101}
175 102
176static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, 103static int dso__inject_build_id(struct dso *self, struct perf_session *session)
177 struct machine *machine)
178{ 104{
179 u16 misc = PERF_RECORD_MISC_USER; 105 u16 misc = PERF_RECORD_MISC_USER;
106 struct machine *machine;
180 int err; 107 int err;
181 108
182 if (dso__read_build_id(self) < 0) { 109 if (dso__read_build_id(self) < 0) {
@@ -184,11 +111,17 @@ static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
184 return -1; 111 return -1;
185 } 112 }
186 113
114 machine = perf_session__find_host_machine(session);
115 if (machine == NULL) {
116 pr_err("Can't find machine for session\n");
117 return -1;
118 }
119
187 if (self->kernel) 120 if (self->kernel)
188 misc = PERF_RECORD_MISC_KERNEL; 121 misc = PERF_RECORD_MISC_KERNEL;
189 122
190 err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe, 123 err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
191 machine); 124 machine, session);
192 if (err) { 125 if (err) {
193 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 126 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
194 return -1; 127 return -1;
@@ -197,11 +130,10 @@ static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
197 return 0; 130 return 0;
198} 131}
199 132
200static int perf_event__inject_buildid(struct perf_tool *tool, 133static int perf_event__inject_buildid(union perf_event *event,
201 union perf_event *event,
202 struct perf_sample *sample, 134 struct perf_sample *sample,
203 struct perf_evsel *evsel __maybe_unused, 135 struct perf_evsel *evsel __used,
204 struct machine *machine) 136 struct perf_session *session)
205{ 137{
206 struct addr_location al; 138 struct addr_location al;
207 struct thread *thread; 139 struct thread *thread;
@@ -209,253 +141,110 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
209 141
210 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 142 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
211 143
212 thread = machine__findnew_thread(machine, event->ip.pid); 144 thread = perf_session__findnew(session, event->ip.pid);
213 if (thread == NULL) { 145 if (thread == NULL) {
214 pr_err("problem processing %d event, skipping it.\n", 146 pr_err("problem processing %d event, skipping it.\n",
215 event->header.type); 147 event->header.type);
216 goto repipe; 148 goto repipe;
217 } 149 }
218 150
219 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 151 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
220 event->ip.ip, &al); 152 event->ip.pid, event->ip.ip, &al);
221 153
222 if (al.map != NULL) { 154 if (al.map != NULL) {
223 if (!al.map->dso->hit) { 155 if (!al.map->dso->hit) {
224 al.map->dso->hit = 1; 156 al.map->dso->hit = 1;
225 if (map__load(al.map, NULL) >= 0) { 157 if (map__load(al.map, NULL) >= 0) {
226 dso__inject_build_id(al.map->dso, tool, machine); 158 dso__inject_build_id(al.map->dso, session);
227 /* 159 /*
228 * If this fails, too bad, let the other side 160 * If this fails, too bad, let the other side
229 * account this as unresolved. 161 * account this as unresolved.
230 */ 162 */
231 } else { 163 } else
232#ifdef LIBELF_SUPPORT
233 pr_warning("no symbols found in %s, maybe " 164 pr_warning("no symbols found in %s, maybe "
234 "install a debug package?\n", 165 "install a debug package?\n",
235 al.map->dso->long_name); 166 al.map->dso->long_name);
236#endif
237 }
238 } 167 }
239 } 168 }
240 169
241repipe: 170repipe:
242 perf_event__repipe(tool, event, sample, machine); 171 perf_event__repipe(event, sample, session);
243 return 0;
244}
245
246static int perf_inject__sched_process_exit(struct perf_tool *tool,
247 union perf_event *event __maybe_unused,
248 struct perf_sample *sample,
249 struct perf_evsel *evsel __maybe_unused,
250 struct machine *machine __maybe_unused)
251{
252 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
253 struct event_entry *ent;
254
255 list_for_each_entry(ent, &inject->samples, node) {
256 if (sample->tid == ent->tid) {
257 list_del_init(&ent->node);
258 free(ent);
259 break;
260 }
261 }
262
263 return 0;
264}
265
266static int perf_inject__sched_switch(struct perf_tool *tool,
267 union perf_event *event,
268 struct perf_sample *sample,
269 struct perf_evsel *evsel,
270 struct machine *machine)
271{
272 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
273 struct event_entry *ent;
274
275 perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
276
277 ent = malloc(event->header.size + sizeof(struct event_entry));
278 if (ent == NULL) {
279 color_fprintf(stderr, PERF_COLOR_RED,
280 "Not enough memory to process sched switch event!");
281 return -1;
282 }
283
284 ent->tid = sample->tid;
285 memcpy(&ent->event, event, event->header.size);
286 list_add(&ent->node, &inject->samples);
287 return 0; 172 return 0;
288} 173}
289 174
290static int perf_inject__sched_stat(struct perf_tool *tool, 175struct perf_event_ops inject_ops = {
291 union perf_event *event __maybe_unused, 176 .sample = perf_event__repipe_sample,
292 struct perf_sample *sample, 177 .mmap = perf_event__repipe,
293 struct perf_evsel *evsel, 178 .comm = perf_event__repipe,
294 struct machine *machine) 179 .fork = perf_event__repipe,
295{ 180 .exit = perf_event__repipe,
296 struct event_entry *ent; 181 .lost = perf_event__repipe,
297 union perf_event *event_sw; 182 .read = perf_event__repipe,
298 struct perf_sample sample_sw; 183 .throttle = perf_event__repipe,
299 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 184 .unthrottle = perf_event__repipe,
300 u32 pid = perf_evsel__intval(evsel, sample, "pid"); 185 .attr = perf_event__repipe_synth,
301 186 .event_type = perf_event__repipe_synth,
302 list_for_each_entry(ent, &inject->samples, node) { 187 .tracing_data = perf_event__repipe_synth,
303 if (pid == ent->tid) 188 .build_id = perf_event__repipe_synth,
304 goto found; 189};
305 }
306
307 return 0;
308found:
309 event_sw = &ent->event[0];
310 perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
311
312 sample_sw.period = sample->period;
313 sample_sw.time = sample->time;
314 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
315 &sample_sw, false);
316 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
317 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
318}
319 190
320extern volatile int session_done; 191extern volatile int session_done;
321 192
322static void sig_handler(int sig __maybe_unused) 193static void sig_handler(int sig __attribute__((__unused__)))
323{ 194{
324 session_done = 1; 195 session_done = 1;
325} 196}
326 197
327static int perf_evsel__check_stype(struct perf_evsel *evsel, 198static int __cmd_inject(void)
328 u64 sample_type, const char *sample_msg)
329{
330 struct perf_event_attr *attr = &evsel->attr;
331 const char *name = perf_evsel__name(evsel);
332
333 if (!(attr->sample_type & sample_type)) {
334 pr_err("Samples for %s event do not have %s attribute set.",
335 name, sample_msg);
336 return -EINVAL;
337 }
338
339 return 0;
340}
341
342static int __cmd_inject(struct perf_inject *inject)
343{ 199{
344 struct perf_session *session; 200 struct perf_session *session;
345 int ret = -EINVAL; 201 int ret = -EINVAL;
346 202
347 signal(SIGINT, sig_handler); 203 signal(SIGINT, sig_handler);
348 204
349 if (inject->build_ids || inject->sched_stat) { 205 if (inject_build_ids) {
350 inject->tool.mmap = perf_event__repipe_mmap; 206 inject_ops.sample = perf_event__inject_buildid;
351 inject->tool.fork = perf_event__repipe_fork; 207 inject_ops.mmap = perf_event__repipe_mmap;
352 inject->tool.tracing_data = perf_event__repipe_tracing_data; 208 inject_ops.fork = perf_event__repipe_task;
209 inject_ops.tracing_data = perf_event__repipe_tracing_data;
353 } 210 }
354 211
355 session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool); 212 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
356 if (session == NULL) 213 if (session == NULL)
357 return -ENOMEM; 214 return -ENOMEM;
358 215
359 if (inject->build_ids) { 216 ret = perf_session__process_events(session, &inject_ops);
360 inject->tool.sample = perf_event__inject_buildid;
361 } else if (inject->sched_stat) {
362 struct perf_evsel *evsel;
363
364 inject->tool.ordered_samples = true;
365
366 list_for_each_entry(evsel, &session->evlist->entries, node) {
367 const char *name = perf_evsel__name(evsel);
368
369 if (!strcmp(name, "sched:sched_switch")) {
370 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
371 return -EINVAL;
372
373 evsel->handler.func = perf_inject__sched_switch;
374 } else if (!strcmp(name, "sched:sched_process_exit"))
375 evsel->handler.func = perf_inject__sched_process_exit;
376 else if (!strncmp(name, "sched:sched_stat_", 17))
377 evsel->handler.func = perf_inject__sched_stat;
378 }
379 }
380
381 if (!inject->pipe_output)
382 lseek(inject->output, session->header.data_offset, SEEK_SET);
383
384 ret = perf_session__process_events(session, &inject->tool);
385
386 if (!inject->pipe_output) {
387 session->header.data_size = inject->bytes_written;
388 perf_session__write_header(session, session->evlist, inject->output, true);
389 }
390 217
391 perf_session__delete(session); 218 perf_session__delete(session);
392 219
393 return ret; 220 return ret;
394} 221}
395 222
396int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) 223static const char * const report_usage[] = {
224 "perf inject [<options>]",
225 NULL
226};
227
228static const struct option options[] = {
229 OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
230 "Inject build-ids into the output stream"),
231 OPT_INCR('v', "verbose", &verbose,
232 "be more verbose (show build ids, etc)"),
233 OPT_END()
234};
235
236int cmd_inject(int argc, const char **argv, const char *prefix __used)
397{ 237{
398 struct perf_inject inject = { 238 argc = parse_options(argc, argv, options, report_usage, 0);
399 .tool = {
400 .sample = perf_event__repipe_sample,
401 .mmap = perf_event__repipe,
402 .comm = perf_event__repipe,
403 .fork = perf_event__repipe,
404 .exit = perf_event__repipe,
405 .lost = perf_event__repipe,
406 .read = perf_event__repipe_sample,
407 .throttle = perf_event__repipe,
408 .unthrottle = perf_event__repipe,
409 .attr = perf_event__repipe_attr,
410 .event_type = perf_event__repipe_event_type_synth,
411 .tracing_data = perf_event__repipe_tracing_data_synth,
412 .build_id = perf_event__repipe_op2_synth,
413 },
414 .input_name = "-",
415 .samples = LIST_HEAD_INIT(inject.samples),
416 };
417 const char *output_name = "-";
418 const struct option options[] = {
419 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
420 "Inject build-ids into the output stream"),
421 OPT_STRING('i', "input", &inject.input_name, "file",
422 "input file name"),
423 OPT_STRING('o', "output", &output_name, "file",
424 "output file name"),
425 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
426 "Merge sched-stat and sched-switch for getting events "
427 "where and how long tasks slept"),
428 OPT_INCR('v', "verbose", &verbose,
429 "be more verbose (show build ids, etc)"),
430 OPT_END()
431 };
432 const char * const inject_usage[] = {
433 "perf inject [<options>]",
434 NULL
435 };
436
437 argc = parse_options(argc, argv, options, inject_usage, 0);
438 239
439 /* 240 /*
440 * Any (unrecognized) arguments left? 241 * Any (unrecognized) arguments left?
441 */ 242 */
442 if (argc) 243 if (argc)
443 usage_with_options(inject_usage, options); 244 usage_with_options(report_usage, options);
444
445 if (!strcmp(output_name, "-")) {
446 inject.pipe_output = 1;
447 inject.output = STDOUT_FILENO;
448 } else {
449 inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC,
450 S_IRUSR | S_IWUSR);
451 if (inject.output < 0) {
452 perror("failed to create output file");
453 return -1;
454 }
455 }
456 245
457 if (symbol__init() < 0) 246 if (symbol__init() < 0)
458 return -1; 247 return -1;
459 248
460 return __cmd_inject(&inject); 249 return __cmd_inject();
461} 250}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0b4b796167b..225e963df10 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -1,15 +1,12 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/evlist.h"
5#include "util/evsel.h"
6#include "util/util.h" 4#include "util/util.h"
7#include "util/cache.h" 5#include "util/cache.h"
8#include "util/symbol.h" 6#include "util/symbol.h"
9#include "util/thread.h" 7#include "util/thread.h"
10#include "util/header.h" 8#include "util/header.h"
11#include "util/session.h" 9#include "util/session.h"
12#include "util/tool.h"
13 10
14#include "util/parse-options.h" 11#include "util/parse-options.h"
15#include "util/trace-event.h" 12#include "util/trace-event.h"
@@ -21,6 +18,8 @@
21struct alloc_stat; 18struct alloc_stat;
22typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 19typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
23 20
21static char const *input_name = "perf.data";
22
24static int alloc_flag; 23static int alloc_flag;
25static int caller_flag; 24static int caller_flag;
26 25
@@ -29,6 +28,8 @@ static int caller_lines = -1;
29 28
30static bool raw_ip; 29static bool raw_ip;
31 30
31static char default_sort_order[] = "frag,hit,bytes";
32
32static int *cpunode_map; 33static int *cpunode_map;
33static int max_cpu_num; 34static int max_cpu_num;
34 35
@@ -55,52 +56,41 @@ static unsigned long nr_allocs, nr_cross_allocs;
55 56
56#define PATH_SYS_NODE "/sys/devices/system/node" 57#define PATH_SYS_NODE "/sys/devices/system/node"
57 58
58static int init_cpunode_map(void) 59static void init_cpunode_map(void)
59{ 60{
60 FILE *fp; 61 FILE *fp;
61 int i, err = -1; 62 int i;
62 63
63 fp = fopen("/sys/devices/system/cpu/kernel_max", "r"); 64 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
64 if (!fp) { 65 if (!fp) {
65 max_cpu_num = 4096; 66 max_cpu_num = 4096;
66 return 0; 67 return;
67 }
68
69 if (fscanf(fp, "%d", &max_cpu_num) < 1) {
70 pr_err("Failed to read 'kernel_max' from sysfs");
71 goto out_close;
72 } 68 }
73 69
70 if (fscanf(fp, "%d", &max_cpu_num) < 1)
71 die("Failed to read 'kernel_max' from sysfs");
74 max_cpu_num++; 72 max_cpu_num++;
75 73
76 cpunode_map = calloc(max_cpu_num, sizeof(int)); 74 cpunode_map = calloc(max_cpu_num, sizeof(int));
77 if (!cpunode_map) { 75 if (!cpunode_map)
78 pr_err("%s: calloc failed\n", __func__); 76 die("calloc");
79 goto out_close;
80 }
81
82 for (i = 0; i < max_cpu_num; i++) 77 for (i = 0; i < max_cpu_num; i++)
83 cpunode_map[i] = -1; 78 cpunode_map[i] = -1;
84
85 err = 0;
86out_close:
87 fclose(fp); 79 fclose(fp);
88 return err;
89} 80}
90 81
91static int setup_cpunode_map(void) 82static void setup_cpunode_map(void)
92{ 83{
93 struct dirent *dent1, *dent2; 84 struct dirent *dent1, *dent2;
94 DIR *dir1, *dir2; 85 DIR *dir1, *dir2;
95 unsigned int cpu, mem; 86 unsigned int cpu, mem;
96 char buf[PATH_MAX]; 87 char buf[PATH_MAX];
97 88
98 if (init_cpunode_map()) 89 init_cpunode_map();
99 return -1;
100 90
101 dir1 = opendir(PATH_SYS_NODE); 91 dir1 = opendir(PATH_SYS_NODE);
102 if (!dir1) 92 if (!dir1)
103 return -1; 93 return;
104 94
105 while ((dent1 = readdir(dir1)) != NULL) { 95 while ((dent1 = readdir(dir1)) != NULL) {
106 if (dent1->d_type != DT_DIR || 96 if (dent1->d_type != DT_DIR ||
@@ -117,14 +107,11 @@ static int setup_cpunode_map(void)
117 continue; 107 continue;
118 cpunode_map[cpu] = mem; 108 cpunode_map[cpu] = mem;
119 } 109 }
120 closedir(dir2);
121 } 110 }
122 closedir(dir1);
123 return 0;
124} 111}
125 112
126static int insert_alloc_stat(unsigned long call_site, unsigned long ptr, 113static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
127 int bytes_req, int bytes_alloc, int cpu) 114 int bytes_req, int bytes_alloc, int cpu)
128{ 115{
129 struct rb_node **node = &root_alloc_stat.rb_node; 116 struct rb_node **node = &root_alloc_stat.rb_node;
130 struct rb_node *parent = NULL; 117 struct rb_node *parent = NULL;
@@ -148,10 +135,8 @@ static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
148 data->bytes_alloc += bytes_alloc; 135 data->bytes_alloc += bytes_alloc;
149 } else { 136 } else {
150 data = malloc(sizeof(*data)); 137 data = malloc(sizeof(*data));
151 if (!data) { 138 if (!data)
152 pr_err("%s: malloc failed\n", __func__); 139 die("malloc");
153 return -1;
154 }
155 data->ptr = ptr; 140 data->ptr = ptr;
156 data->pingpong = 0; 141 data->pingpong = 0;
157 data->hit = 1; 142 data->hit = 1;
@@ -163,10 +148,9 @@ static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
163 } 148 }
164 data->call_site = call_site; 149 data->call_site = call_site;
165 data->alloc_cpu = cpu; 150 data->alloc_cpu = cpu;
166 return 0;
167} 151}
168 152
169static int insert_caller_stat(unsigned long call_site, 153static void insert_caller_stat(unsigned long call_site,
170 int bytes_req, int bytes_alloc) 154 int bytes_req, int bytes_alloc)
171{ 155{
172 struct rb_node **node = &root_caller_stat.rb_node; 156 struct rb_node **node = &root_caller_stat.rb_node;
@@ -191,10 +175,8 @@ static int insert_caller_stat(unsigned long call_site,
191 data->bytes_alloc += bytes_alloc; 175 data->bytes_alloc += bytes_alloc;
192 } else { 176 } else {
193 data = malloc(sizeof(*data)); 177 data = malloc(sizeof(*data));
194 if (!data) { 178 if (!data)
195 pr_err("%s: malloc failed\n", __func__); 179 die("malloc");
196 return -1;
197 }
198 data->call_site = call_site; 180 data->call_site = call_site;
199 data->pingpong = 0; 181 data->pingpong = 0;
200 data->hit = 1; 182 data->hit = 1;
@@ -204,43 +186,39 @@ static int insert_caller_stat(unsigned long call_site,
204 rb_link_node(&data->node, parent, node); 186 rb_link_node(&data->node, parent, node);
205 rb_insert_color(&data->node, &root_caller_stat); 187 rb_insert_color(&data->node, &root_caller_stat);
206 } 188 }
207
208 return 0;
209} 189}
210 190
211static int perf_evsel__process_alloc_event(struct perf_evsel *evsel, 191static void process_alloc_event(void *data,
212 struct perf_sample *sample) 192 struct event *event,
193 int cpu,
194 u64 timestamp __used,
195 struct thread *thread __used,
196 int node)
213{ 197{
214 unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"), 198 unsigned long call_site;
215 call_site = perf_evsel__intval(evsel, sample, "call_site"); 199 unsigned long ptr;
216 int bytes_req = perf_evsel__intval(evsel, sample, "bytes_req"), 200 int bytes_req;
217 bytes_alloc = perf_evsel__intval(evsel, sample, "bytes_alloc"); 201 int bytes_alloc;
202 int node1, node2;
218 203
219 if (insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, sample->cpu) || 204 ptr = raw_field_value(event, "ptr", data);
220 insert_caller_stat(call_site, bytes_req, bytes_alloc)) 205 call_site = raw_field_value(event, "call_site", data);
221 return -1; 206 bytes_req = raw_field_value(event, "bytes_req", data);
207 bytes_alloc = raw_field_value(event, "bytes_alloc", data);
208
209 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
210 insert_caller_stat(call_site, bytes_req, bytes_alloc);
222 211
223 total_requested += bytes_req; 212 total_requested += bytes_req;
224 total_allocated += bytes_alloc; 213 total_allocated += bytes_alloc;
225 214
226 nr_allocs++; 215 if (node) {
227 return 0; 216 node1 = cpunode_map[cpu];
228} 217 node2 = raw_field_value(event, "node", data);
229
230static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
231 struct perf_sample *sample)
232{
233 int ret = perf_evsel__process_alloc_event(evsel, sample);
234
235 if (!ret) {
236 int node1 = cpunode_map[sample->cpu],
237 node2 = perf_evsel__intval(evsel, sample, "node");
238
239 if (node1 != node2) 218 if (node1 != node2)
240 nr_cross_allocs++; 219 nr_cross_allocs++;
241 } 220 }
242 221 nr_allocs++;
243 return ret;
244} 222}
245 223
246static int ptr_cmp(struct alloc_stat *, struct alloc_stat *); 224static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
@@ -271,40 +249,66 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,
271 return NULL; 249 return NULL;
272} 250}
273 251
274static int perf_evsel__process_free_event(struct perf_evsel *evsel, 252static void process_free_event(void *data,
275 struct perf_sample *sample) 253 struct event *event,
254 int cpu,
255 u64 timestamp __used,
256 struct thread *thread __used)
276{ 257{
277 unsigned long ptr = perf_evsel__intval(evsel, sample, "ptr"); 258 unsigned long ptr;
278 struct alloc_stat *s_alloc, *s_caller; 259 struct alloc_stat *s_alloc, *s_caller;
279 260
261 ptr = raw_field_value(event, "ptr", data);
262
280 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); 263 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
281 if (!s_alloc) 264 if (!s_alloc)
282 return 0; 265 return;
283 266
284 if ((short)sample->cpu != s_alloc->alloc_cpu) { 267 if (cpu != s_alloc->alloc_cpu) {
285 s_alloc->pingpong++; 268 s_alloc->pingpong++;
286 269
287 s_caller = search_alloc_stat(0, s_alloc->call_site, 270 s_caller = search_alloc_stat(0, s_alloc->call_site,
288 &root_caller_stat, callsite_cmp); 271 &root_caller_stat, callsite_cmp);
289 if (!s_caller) 272 assert(s_caller);
290 return -1;
291 s_caller->pingpong++; 273 s_caller->pingpong++;
292 } 274 }
293 s_alloc->alloc_cpu = -1; 275 s_alloc->alloc_cpu = -1;
294
295 return 0;
296} 276}
297 277
298typedef int (*tracepoint_handler)(struct perf_evsel *evsel, 278static void process_raw_event(union perf_event *raw_event __used, void *data,
299 struct perf_sample *sample); 279 int cpu, u64 timestamp, struct thread *thread)
280{
281 struct event *event;
282 int type;
283
284 type = trace_parse_common_type(data);
285 event = trace_find_event(type);
286
287 if (!strcmp(event->name, "kmalloc") ||
288 !strcmp(event->name, "kmem_cache_alloc")) {
289 process_alloc_event(data, event, cpu, timestamp, thread, 0);
290 return;
291 }
292
293 if (!strcmp(event->name, "kmalloc_node") ||
294 !strcmp(event->name, "kmem_cache_alloc_node")) {
295 process_alloc_event(data, event, cpu, timestamp, thread, 1);
296 return;
297 }
300 298
301static int process_sample_event(struct perf_tool *tool __maybe_unused, 299 if (!strcmp(event->name, "kfree") ||
302 union perf_event *event, 300 !strcmp(event->name, "kmem_cache_free")) {
301 process_free_event(data, event, cpu, timestamp, thread);
302 return;
303 }
304}
305
306static int process_sample_event(union perf_event *event,
303 struct perf_sample *sample, 307 struct perf_sample *sample,
304 struct perf_evsel *evsel, 308 struct perf_evsel *evsel __used,
305 struct machine *machine) 309 struct perf_session *session)
306{ 310{
307 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 311 struct thread *thread = perf_session__findnew(session, event->ip.pid);
308 312
309 if (thread == NULL) { 313 if (thread == NULL) {
310 pr_debug("problem processing %d event, skipping it.\n", 314 pr_debug("problem processing %d event, skipping it.\n",
@@ -314,18 +318,16 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
314 318
315 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 319 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
316 320
317 if (evsel->handler.func != NULL) { 321 process_raw_event(event, sample->raw_data, sample->cpu,
318 tracepoint_handler f = evsel->handler.func; 322 sample->time, thread);
319 return f(evsel, sample);
320 }
321 323
322 return 0; 324 return 0;
323} 325}
324 326
325static struct perf_tool perf_kmem = { 327static struct perf_event_ops event_ops = {
326 .sample = process_sample_event, 328 .sample = process_sample_event,
327 .comm = perf_event__process_comm, 329 .comm = perf_event__process_comm,
328 .ordered_samples = true, 330 .ordered_samples = true,
329}; 331};
330 332
331static double fragmentation(unsigned long n_req, unsigned long n_alloc) 333static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -480,17 +482,8 @@ static void sort_result(void)
480static int __cmd_kmem(void) 482static int __cmd_kmem(void)
481{ 483{
482 int err = -EINVAL; 484 int err = -EINVAL;
483 struct perf_session *session; 485 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
484 const struct perf_evsel_str_handler kmem_tracepoints[] = { 486 0, false, &event_ops);
485 { "kmem:kmalloc", perf_evsel__process_alloc_event, },
486 { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, },
487 { "kmem:kmalloc_node", perf_evsel__process_alloc_node_event, },
488 { "kmem:kmem_cache_alloc_node", perf_evsel__process_alloc_node_event, },
489 { "kmem:kfree", perf_evsel__process_free_event, },
490 { "kmem:kmem_cache_free", perf_evsel__process_free_event, },
491 };
492
493 session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_kmem);
494 if (session == NULL) 487 if (session == NULL)
495 return -ENOMEM; 488 return -ENOMEM;
496 489
@@ -500,13 +493,8 @@ static int __cmd_kmem(void)
500 if (!perf_session__has_traces(session, "kmem record")) 493 if (!perf_session__has_traces(session, "kmem record"))
501 goto out_delete; 494 goto out_delete;
502 495
503 if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) {
504 pr_err("Initializing perf session tracepoint handlers failed\n");
505 return -1;
506 }
507
508 setup_pager(); 496 setup_pager();
509 err = perf_session__process_events(session, &perf_kmem); 497 err = perf_session__process_events(session, &event_ops);
510 if (err != 0) 498 if (err != 0)
511 goto out_delete; 499 goto out_delete;
512 sort_result(); 500 sort_result();
@@ -516,6 +504,11 @@ out_delete:
516 return err; 504 return err;
517} 505}
518 506
507static const char * const kmem_usage[] = {
508 "perf kmem [<options>] {record|stat}",
509 NULL
510};
511
519static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) 512static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
520{ 513{
521 if (l->ptr < r->ptr) 514 if (l->ptr < r->ptr)
@@ -625,10 +618,8 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
625 for (i = 0; i < NUM_AVAIL_SORTS; i++) { 618 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
626 if (!strcmp(avail_sorts[i]->name, tok)) { 619 if (!strcmp(avail_sorts[i]->name, tok)) {
627 sort = malloc(sizeof(*sort)); 620 sort = malloc(sizeof(*sort));
628 if (!sort) { 621 if (!sort)
629 pr_err("%s: malloc failed\n", __func__); 622 die("malloc");
630 return -1;
631 }
632 memcpy(sort, avail_sorts[i], sizeof(*sort)); 623 memcpy(sort, avail_sorts[i], sizeof(*sort));
633 list_add_tail(&sort->list, list); 624 list_add_tail(&sort->list, list);
634 return 0; 625 return 0;
@@ -643,10 +634,8 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
643 char *tok; 634 char *tok;
644 char *str = strdup(arg); 635 char *str = strdup(arg);
645 636
646 if (!str) { 637 if (!str)
647 pr_err("%s: strdup failed\n", __func__); 638 die("strdup");
648 return -1;
649 }
650 639
651 while (true) { 640 while (true) {
652 tok = strsep(&str, ","); 641 tok = strsep(&str, ",");
@@ -654,7 +643,6 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
654 break; 643 break;
655 if (sort_dimension__add(tok, sort_list) < 0) { 644 if (sort_dimension__add(tok, sort_list) < 0) {
656 error("Unknown --sort key: '%s'", tok); 645 error("Unknown --sort key: '%s'", tok);
657 free(str);
658 return -1; 646 return -1;
659 } 647 }
660 } 648 }
@@ -663,8 +651,8 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
663 return 0; 651 return 0;
664} 652}
665 653
666static int parse_sort_opt(const struct option *opt __maybe_unused, 654static int parse_sort_opt(const struct option *opt __used,
667 const char *arg, int unset __maybe_unused) 655 const char *arg, int unset __used)
668{ 656{
669 if (!arg) 657 if (!arg)
670 return -1; 658 return -1;
@@ -677,24 +665,22 @@ static int parse_sort_opt(const struct option *opt __maybe_unused,
677 return 0; 665 return 0;
678} 666}
679 667
680static int parse_caller_opt(const struct option *opt __maybe_unused, 668static int parse_caller_opt(const struct option *opt __used,
681 const char *arg __maybe_unused, 669 const char *arg __used, int unset __used)
682 int unset __maybe_unused)
683{ 670{
684 caller_flag = (alloc_flag + 1); 671 caller_flag = (alloc_flag + 1);
685 return 0; 672 return 0;
686} 673}
687 674
688static int parse_alloc_opt(const struct option *opt __maybe_unused, 675static int parse_alloc_opt(const struct option *opt __used,
689 const char *arg __maybe_unused, 676 const char *arg __used, int unset __used)
690 int unset __maybe_unused)
691{ 677{
692 alloc_flag = (caller_flag + 1); 678 alloc_flag = (caller_flag + 1);
693 return 0; 679 return 0;
694} 680}
695 681
696static int parse_line_opt(const struct option *opt __maybe_unused, 682static int parse_line_opt(const struct option *opt __used,
697 const char *arg, int unset __maybe_unused) 683 const char *arg, int unset __used)
698{ 684{
699 int lines; 685 int lines;
700 686
@@ -711,17 +697,41 @@ static int parse_line_opt(const struct option *opt __maybe_unused,
711 return 0; 697 return 0;
712} 698}
713 699
714static int __cmd_record(int argc, const char **argv) 700static const struct option kmem_options[] = {
715{ 701 OPT_STRING('i', "input", &input_name, "file",
716 const char * const record_args[] = { 702 "input file name"),
717 "record", "-a", "-R", "-f", "-c", "1", 703 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
704 "show per-callsite statistics",
705 parse_caller_opt),
706 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
707 "show per-allocation statistics",
708 parse_alloc_opt),
709 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
710 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
711 parse_sort_opt),
712 OPT_CALLBACK('l', "line", NULL, "num",
713 "show n lines",
714 parse_line_opt),
715 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
716 OPT_END()
717};
718
719static const char *record_args[] = {
720 "record",
721 "-a",
722 "-R",
723 "-f",
724 "-c", "1",
718 "-e", "kmem:kmalloc", 725 "-e", "kmem:kmalloc",
719 "-e", "kmem:kmalloc_node", 726 "-e", "kmem:kmalloc_node",
720 "-e", "kmem:kfree", 727 "-e", "kmem:kfree",
721 "-e", "kmem:kmem_cache_alloc", 728 "-e", "kmem:kmem_cache_alloc",
722 "-e", "kmem:kmem_cache_alloc_node", 729 "-e", "kmem:kmem_cache_alloc_node",
723 "-e", "kmem:kmem_cache_free", 730 "-e", "kmem:kmem_cache_free",
724 }; 731};
732
733static int __cmd_record(int argc, const char **argv)
734{
725 unsigned int rec_argc, i, j; 735 unsigned int rec_argc, i, j;
726 const char **rec_argv; 736 const char **rec_argv;
727 737
@@ -740,26 +750,8 @@ static int __cmd_record(int argc, const char **argv)
740 return cmd_record(i, rec_argv, NULL); 750 return cmd_record(i, rec_argv, NULL);
741} 751}
742 752
743int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) 753int cmd_kmem(int argc, const char **argv, const char *prefix __used)
744{ 754{
745 const char * const default_sort_order = "frag,hit,bytes";
746 const struct option kmem_options[] = {
747 OPT_STRING('i', "input", &input_name, "file", "input file name"),
748 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
749 "show per-callsite statistics", parse_caller_opt),
750 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
751 "show per-allocation statistics", parse_alloc_opt),
752 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
753 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
754 parse_sort_opt),
755 OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
756 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
757 OPT_END()
758 };
759 const char * const kmem_usage[] = {
760 "perf kmem [<options>] {record|stat}",
761 NULL
762 };
763 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 755 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
764 756
765 if (!argc) 757 if (!argc)
@@ -770,8 +762,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
770 if (!strncmp(argv[0], "rec", 3)) { 762 if (!strncmp(argv[0], "rec", 3)) {
771 return __cmd_record(argc, argv); 763 return __cmd_record(argc, argv);
772 } else if (!strcmp(argv[0], "stat")) { 764 } else if (!strcmp(argv[0], "stat")) {
773 if (setup_cpunode_map()) 765 setup_cpunode_map();
774 return -1;
775 766
776 if (list_empty(&caller_sort)) 767 if (list_empty(&caller_sort))
777 setup_sorting(&caller_sort, default_sort_order); 768 setup_sorting(&caller_sort, default_sort_order);
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index ca3f80ebc10..34d1e853829 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1,7 +1,6 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/evsel.h"
5#include "util/util.h" 4#include "util/util.h"
6#include "util/cache.h" 5#include "util/cache.h"
7#include "util/symbol.h" 6#include "util/symbol.h"
@@ -11,10 +10,8 @@
11 10
12#include "util/parse-options.h" 11#include "util/parse-options.h"
13#include "util/trace-event.h" 12#include "util/trace-event.h"
13
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/debugfs.h"
16#include "util/tool.h"
17#include "util/stat.h"
18 15
19#include <sys/prctl.h> 16#include <sys/prctl.h>
20 17
@@ -22,901 +19,39 @@
22#include <pthread.h> 19#include <pthread.h>
23#include <math.h> 20#include <math.h>
24 21
25#if defined(__i386__) || defined(__x86_64__) 22static const char *file_name;
26#include <asm/svm.h> 23static char name_buffer[256];
27#include <asm/vmx.h>
28#include <asm/kvm.h>
29
30struct event_key {
31 #define INVALID_KEY (~0ULL)
32 u64 key;
33 int info;
34};
35
36struct kvm_event_stats {
37 u64 time;
38 struct stats stats;
39};
40
41struct kvm_event {
42 struct list_head hash_entry;
43 struct rb_node rb;
44
45 struct event_key key;
46
47 struct kvm_event_stats total;
48
49 #define DEFAULT_VCPU_NUM 8
50 int max_vcpu;
51 struct kvm_event_stats *vcpu;
52};
53
54typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
55
56struct kvm_event_key {
57 const char *name;
58 key_cmp_fun key;
59};
60
61
62struct perf_kvm_stat;
63
64struct kvm_events_ops {
65 bool (*is_begin_event)(struct perf_evsel *evsel,
66 struct perf_sample *sample,
67 struct event_key *key);
68 bool (*is_end_event)(struct perf_evsel *evsel,
69 struct perf_sample *sample, struct event_key *key);
70 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
71 char decode[20]);
72 const char *name;
73};
74
75struct exit_reasons_table {
76 unsigned long exit_code;
77 const char *reason;
78};
79
80#define EVENTS_BITS 12
81#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
82
83struct perf_kvm_stat {
84 struct perf_tool tool;
85 struct perf_session *session;
86
87 const char *file_name;
88 const char *report_event;
89 const char *sort_key;
90 int trace_vcpu;
91
92 struct exit_reasons_table *exit_reasons;
93 int exit_reasons_size;
94 const char *exit_reasons_isa;
95
96 struct kvm_events_ops *events_ops;
97 key_cmp_fun compare;
98 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
99 u64 total_time;
100 u64 total_count;
101
102 struct rb_root result;
103};
104
105
106static void exit_event_get_key(struct perf_evsel *evsel,
107 struct perf_sample *sample,
108 struct event_key *key)
109{
110 key->info = 0;
111 key->key = perf_evsel__intval(evsel, sample, "exit_reason");
112}
113
114static bool kvm_exit_event(struct perf_evsel *evsel)
115{
116 return !strcmp(evsel->name, "kvm:kvm_exit");
117}
118
119static bool exit_event_begin(struct perf_evsel *evsel,
120 struct perf_sample *sample, struct event_key *key)
121{
122 if (kvm_exit_event(evsel)) {
123 exit_event_get_key(evsel, sample, key);
124 return true;
125 }
126
127 return false;
128}
129
130static bool kvm_entry_event(struct perf_evsel *evsel)
131{
132 return !strcmp(evsel->name, "kvm:kvm_entry");
133}
134
135static bool exit_event_end(struct perf_evsel *evsel,
136 struct perf_sample *sample __maybe_unused,
137 struct event_key *key __maybe_unused)
138{
139 return kvm_entry_event(evsel);
140}
141
142static struct exit_reasons_table vmx_exit_reasons[] = {
143 VMX_EXIT_REASONS
144};
145
146static struct exit_reasons_table svm_exit_reasons[] = {
147 SVM_EXIT_REASONS
148};
149
150static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
151{
152 int i = kvm->exit_reasons_size;
153 struct exit_reasons_table *tbl = kvm->exit_reasons;
154
155 while (i--) {
156 if (tbl->exit_code == exit_code)
157 return tbl->reason;
158 tbl++;
159 }
160
161 pr_err("unknown kvm exit code:%lld on %s\n",
162 (unsigned long long)exit_code, kvm->exit_reasons_isa);
163 return "UNKNOWN";
164}
165
166static void exit_event_decode_key(struct perf_kvm_stat *kvm,
167 struct event_key *key,
168 char decode[20])
169{
170 const char *exit_reason = get_exit_reason(kvm, key->key);
171 24
172 scnprintf(decode, 20, "%s", exit_reason); 25bool perf_host = 1;
173} 26bool perf_guest;
174 27
175static struct kvm_events_ops exit_events = { 28static const char * const kvm_usage[] = {
176 .is_begin_event = exit_event_begin, 29 "perf kvm [<options>] {top|record|report|diff|buildid-list}",
177 .is_end_event = exit_event_end, 30 NULL
178 .decode_key = exit_event_decode_key,
179 .name = "VM-EXIT"
180}; 31};
181 32
182/* 33static const struct option kvm_options[] = {
183 * For the mmio events, we treat: 34 OPT_STRING('i', "input", &file_name, "file",
184 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry 35 "Input file name"),
185 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). 36 OPT_STRING('o', "output", &file_name, "file",
186 */ 37 "Output file name"),
187static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, 38 OPT_BOOLEAN(0, "guest", &perf_guest,
188 struct event_key *key) 39 "Collect guest os data"),
189{ 40 OPT_BOOLEAN(0, "host", &perf_host,
190 key->key = perf_evsel__intval(evsel, sample, "gpa"); 41 "Collect guest os data"),
191 key->info = perf_evsel__intval(evsel, sample, "type"); 42 OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
192} 43 "guest mount directory under which every guest os"
193 44 " instance has a subdir"),
194#define KVM_TRACE_MMIO_READ_UNSATISFIED 0 45 OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,
195#define KVM_TRACE_MMIO_READ 1 46 "file", "file saving guest os vmlinux"),
196#define KVM_TRACE_MMIO_WRITE 2 47 OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
197 48 "file", "file saving guest os /proc/kallsyms"),
198static bool mmio_event_begin(struct perf_evsel *evsel, 49 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
199 struct perf_sample *sample, struct event_key *key) 50 "file", "file saving guest os /proc/modules"),
200{ 51 OPT_END()
201 /* MMIO read begin event in kernel. */
202 if (kvm_exit_event(evsel))
203 return true;
204
205 /* MMIO write begin event in kernel. */
206 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
207 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
208 mmio_event_get_key(evsel, sample, key);
209 return true;
210 }
211
212 return false;
213}
214
215static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
216 struct event_key *key)
217{
218 /* MMIO write end event in kernel. */
219 if (kvm_entry_event(evsel))
220 return true;
221
222 /* MMIO read end event in kernel.*/
223 if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
224 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
225 mmio_event_get_key(evsel, sample, key);
226 return true;
227 }
228
229 return false;
230}
231
232static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
233 struct event_key *key,
234 char decode[20])
235{
236 scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key,
237 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
238}
239
240static struct kvm_events_ops mmio_events = {
241 .is_begin_event = mmio_event_begin,
242 .is_end_event = mmio_event_end,
243 .decode_key = mmio_event_decode_key,
244 .name = "MMIO Access"
245}; 52};
246 53
247 /* The time of emulation pio access is from kvm_pio to kvm_entry. */ 54static int __cmd_record(int argc, const char **argv)
248static void ioport_event_get_key(struct perf_evsel *evsel,
249 struct perf_sample *sample,
250 struct event_key *key)
251{
252 key->key = perf_evsel__intval(evsel, sample, "port");
253 key->info = perf_evsel__intval(evsel, sample, "rw");
254}
255
256static bool ioport_event_begin(struct perf_evsel *evsel,
257 struct perf_sample *sample,
258 struct event_key *key)
259{
260 if (!strcmp(evsel->name, "kvm:kvm_pio")) {
261 ioport_event_get_key(evsel, sample, key);
262 return true;
263 }
264
265 return false;
266}
267
268static bool ioport_event_end(struct perf_evsel *evsel,
269 struct perf_sample *sample __maybe_unused,
270 struct event_key *key __maybe_unused)
271{
272 return kvm_entry_event(evsel);
273}
274
275static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
276 struct event_key *key,
277 char decode[20])
278{
279 scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key,
280 key->info ? "POUT" : "PIN");
281}
282
283static struct kvm_events_ops ioport_events = {
284 .is_begin_event = ioport_event_begin,
285 .is_end_event = ioport_event_end,
286 .decode_key = ioport_event_decode_key,
287 .name = "IO Port Access"
288};
289
290static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
291{
292 bool ret = true;
293
294 if (!strcmp(kvm->report_event, "vmexit"))
295 kvm->events_ops = &exit_events;
296 else if (!strcmp(kvm->report_event, "mmio"))
297 kvm->events_ops = &mmio_events;
298 else if (!strcmp(kvm->report_event, "ioport"))
299 kvm->events_ops = &ioport_events;
300 else {
301 pr_err("Unknown report event:%s\n", kvm->report_event);
302 ret = false;
303 }
304
305 return ret;
306}
307
308struct vcpu_event_record {
309 int vcpu_id;
310 u64 start_time;
311 struct kvm_event *last_event;
312};
313
314
315static void init_kvm_event_record(struct perf_kvm_stat *kvm)
316{
317 unsigned int i;
318
319 for (i = 0; i < EVENTS_CACHE_SIZE; i++)
320 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
321}
322
323static int kvm_events_hash_fn(u64 key)
324{
325 return key & (EVENTS_CACHE_SIZE - 1);
326}
327
328static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)
329{
330 int old_max_vcpu = event->max_vcpu;
331
332 if (vcpu_id < event->max_vcpu)
333 return true;
334
335 while (event->max_vcpu <= vcpu_id)
336 event->max_vcpu += DEFAULT_VCPU_NUM;
337
338 event->vcpu = realloc(event->vcpu,
339 event->max_vcpu * sizeof(*event->vcpu));
340 if (!event->vcpu) {
341 pr_err("Not enough memory\n");
342 return false;
343 }
344
345 memset(event->vcpu + old_max_vcpu, 0,
346 (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu));
347 return true;
348}
349
350static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
351{
352 struct kvm_event *event;
353
354 event = zalloc(sizeof(*event));
355 if (!event) {
356 pr_err("Not enough memory\n");
357 return NULL;
358 }
359
360 event->key = *key;
361 return event;
362}
363
364static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
365 struct event_key *key)
366{
367 struct kvm_event *event;
368 struct list_head *head;
369
370 BUG_ON(key->key == INVALID_KEY);
371
372 head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)];
373 list_for_each_entry(event, head, hash_entry) {
374 if (event->key.key == key->key && event->key.info == key->info)
375 return event;
376 }
377
378 event = kvm_alloc_init_event(key);
379 if (!event)
380 return NULL;
381
382 list_add(&event->hash_entry, head);
383 return event;
384}
385
386static bool handle_begin_event(struct perf_kvm_stat *kvm,
387 struct vcpu_event_record *vcpu_record,
388 struct event_key *key, u64 timestamp)
389{
390 struct kvm_event *event = NULL;
391
392 if (key->key != INVALID_KEY)
393 event = find_create_kvm_event(kvm, key);
394
395 vcpu_record->last_event = event;
396 vcpu_record->start_time = timestamp;
397 return true;
398}
399
400static void
401kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff)
402{
403 kvm_stats->time += time_diff;
404 update_stats(&kvm_stats->stats, time_diff);
405}
406
407static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
408{
409 struct kvm_event_stats *kvm_stats = &event->total;
410
411 if (vcpu_id != -1)
412 kvm_stats = &event->vcpu[vcpu_id];
413
414 return rel_stddev_stats(stddev_stats(&kvm_stats->stats),
415 avg_stats(&kvm_stats->stats));
416}
417
418static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
419 u64 time_diff)
420{
421 if (vcpu_id == -1) {
422 kvm_update_event_stats(&event->total, time_diff);
423 return true;
424 }
425
426 if (!kvm_event_expand(event, vcpu_id))
427 return false;
428
429 kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff);
430 return true;
431}
432
433static bool handle_end_event(struct perf_kvm_stat *kvm,
434 struct vcpu_event_record *vcpu_record,
435 struct event_key *key,
436 u64 timestamp)
437{
438 struct kvm_event *event;
439 u64 time_begin, time_diff;
440 int vcpu;
441
442 if (kvm->trace_vcpu == -1)
443 vcpu = -1;
444 else
445 vcpu = vcpu_record->vcpu_id;
446
447 event = vcpu_record->last_event;
448 time_begin = vcpu_record->start_time;
449
450 /* The begin event is not caught. */
451 if (!time_begin)
452 return true;
453
454 /*
455 * In some case, the 'begin event' only records the start timestamp,
456 * the actual event is recognized in the 'end event' (e.g. mmio-event).
457 */
458
459 /* Both begin and end events did not get the key. */
460 if (!event && key->key == INVALID_KEY)
461 return true;
462
463 if (!event)
464 event = find_create_kvm_event(kvm, key);
465
466 if (!event)
467 return false;
468
469 vcpu_record->last_event = NULL;
470 vcpu_record->start_time = 0;
471
472 BUG_ON(timestamp < time_begin);
473
474 time_diff = timestamp - time_begin;
475 return update_kvm_event(event, vcpu, time_diff);
476}
477
478static
479struct vcpu_event_record *per_vcpu_record(struct thread *thread,
480 struct perf_evsel *evsel,
481 struct perf_sample *sample)
482{
483 /* Only kvm_entry records vcpu id. */
484 if (!thread->priv && kvm_entry_event(evsel)) {
485 struct vcpu_event_record *vcpu_record;
486
487 vcpu_record = zalloc(sizeof(*vcpu_record));
488 if (!vcpu_record) {
489 pr_err("%s: Not enough memory\n", __func__);
490 return NULL;
491 }
492
493 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id");
494 thread->priv = vcpu_record;
495 }
496
497 return thread->priv;
498}
499
500static bool handle_kvm_event(struct perf_kvm_stat *kvm,
501 struct thread *thread,
502 struct perf_evsel *evsel,
503 struct perf_sample *sample)
504{
505 struct vcpu_event_record *vcpu_record;
506 struct event_key key = {.key = INVALID_KEY};
507
508 vcpu_record = per_vcpu_record(thread, evsel, sample);
509 if (!vcpu_record)
510 return true;
511
512 /* only process events for vcpus user cares about */
513 if ((kvm->trace_vcpu != -1) &&
514 (kvm->trace_vcpu != vcpu_record->vcpu_id))
515 return true;
516
517 if (kvm->events_ops->is_begin_event(evsel, sample, &key))
518 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
519
520 if (kvm->events_ops->is_end_event(evsel, sample, &key))
521 return handle_end_event(kvm, vcpu_record, &key, sample->time);
522
523 return true;
524}
525
526#define GET_EVENT_KEY(func, field) \
527static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \
528{ \
529 if (vcpu == -1) \
530 return event->total.field; \
531 \
532 if (vcpu >= event->max_vcpu) \
533 return 0; \
534 \
535 return event->vcpu[vcpu].field; \
536}
537
538#define COMPARE_EVENT_KEY(func, field) \
539GET_EVENT_KEY(func, field) \
540static int compare_kvm_event_ ## func(struct kvm_event *one, \
541 struct kvm_event *two, int vcpu)\
542{ \
543 return get_event_ ##func(one, vcpu) > \
544 get_event_ ##func(two, vcpu); \
545}
546
547GET_EVENT_KEY(time, time);
548COMPARE_EVENT_KEY(count, stats.n);
549COMPARE_EVENT_KEY(mean, stats.mean);
550
551#define DEF_SORT_NAME_KEY(name, compare_key) \
552 { #name, compare_kvm_event_ ## compare_key }
553
554static struct kvm_event_key keys[] = {
555 DEF_SORT_NAME_KEY(sample, count),
556 DEF_SORT_NAME_KEY(time, mean),
557 { NULL, NULL }
558};
559
560static bool select_key(struct perf_kvm_stat *kvm)
561{
562 int i;
563
564 for (i = 0; keys[i].name; i++) {
565 if (!strcmp(keys[i].name, kvm->sort_key)) {
566 kvm->compare = keys[i].key;
567 return true;
568 }
569 }
570
571 pr_err("Unknown compare key:%s\n", kvm->sort_key);
572 return false;
573}
574
575static void insert_to_result(struct rb_root *result, struct kvm_event *event,
576 key_cmp_fun bigger, int vcpu)
577{
578 struct rb_node **rb = &result->rb_node;
579 struct rb_node *parent = NULL;
580 struct kvm_event *p;
581
582 while (*rb) {
583 p = container_of(*rb, struct kvm_event, rb);
584 parent = *rb;
585
586 if (bigger(event, p, vcpu))
587 rb = &(*rb)->rb_left;
588 else
589 rb = &(*rb)->rb_right;
590 }
591
592 rb_link_node(&event->rb, parent, rb);
593 rb_insert_color(&event->rb, result);
594}
595
596static void
597update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
598{
599 int vcpu = kvm->trace_vcpu;
600
601 kvm->total_count += get_event_count(event, vcpu);
602 kvm->total_time += get_event_time(event, vcpu);
603}
604
605static bool event_is_valid(struct kvm_event *event, int vcpu)
606{
607 return !!get_event_count(event, vcpu);
608}
609
610static void sort_result(struct perf_kvm_stat *kvm)
611{
612 unsigned int i;
613 int vcpu = kvm->trace_vcpu;
614 struct kvm_event *event;
615
616 for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
617 list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) {
618 if (event_is_valid(event, vcpu)) {
619 update_total_count(kvm, event);
620 insert_to_result(&kvm->result, event,
621 kvm->compare, vcpu);
622 }
623 }
624 }
625}
626
627/* returns left most element of result, and erase it */
628static struct kvm_event *pop_from_result(struct rb_root *result)
629{
630 struct rb_node *node = rb_first(result);
631
632 if (!node)
633 return NULL;
634
635 rb_erase(node, result);
636 return container_of(node, struct kvm_event, rb);
637}
638
639static void print_vcpu_info(int vcpu)
640{
641 pr_info("Analyze events for ");
642
643 if (vcpu == -1)
644 pr_info("all VCPUs:\n\n");
645 else
646 pr_info("VCPU %d:\n\n", vcpu);
647}
648
649static void print_result(struct perf_kvm_stat *kvm)
650{
651 char decode[20];
652 struct kvm_event *event;
653 int vcpu = kvm->trace_vcpu;
654
655 pr_info("\n\n");
656 print_vcpu_info(vcpu);
657 pr_info("%20s ", kvm->events_ops->name);
658 pr_info("%10s ", "Samples");
659 pr_info("%9s ", "Samples%");
660
661 pr_info("%9s ", "Time%");
662 pr_info("%16s ", "Avg time");
663 pr_info("\n\n");
664
665 while ((event = pop_from_result(&kvm->result))) {
666 u64 ecount, etime;
667
668 ecount = get_event_count(event, vcpu);
669 etime = get_event_time(event, vcpu);
670
671 kvm->events_ops->decode_key(kvm, &event->key, decode);
672 pr_info("%20s ", decode);
673 pr_info("%10llu ", (unsigned long long)ecount);
674 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
675 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
676 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
677 kvm_event_rel_stddev(vcpu, event));
678 pr_info("\n");
679 }
680
681 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
682 kvm->total_count, kvm->total_time / 1e3);
683}
684
685static int process_sample_event(struct perf_tool *tool,
686 union perf_event *event,
687 struct perf_sample *sample,
688 struct perf_evsel *evsel,
689 struct machine *machine)
690{
691 struct thread *thread = machine__findnew_thread(machine, sample->tid);
692 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
693 tool);
694
695 if (thread == NULL) {
696 pr_debug("problem processing %d event, skipping it.\n",
697 event->header.type);
698 return -1;
699 }
700
701 if (!handle_kvm_event(kvm, thread, evsel, sample))
702 return -1;
703
704 return 0;
705}
706
707static int get_cpu_isa(struct perf_session *session)
708{
709 char *cpuid = session->header.env.cpuid;
710 int isa;
711
712 if (strstr(cpuid, "Intel"))
713 isa = 1;
714 else if (strstr(cpuid, "AMD"))
715 isa = 0;
716 else {
717 pr_err("CPU %s is not supported.\n", cpuid);
718 isa = -ENOTSUP;
719 }
720
721 return isa;
722}
723
724static int read_events(struct perf_kvm_stat *kvm)
725{
726 int ret;
727
728 struct perf_tool eops = {
729 .sample = process_sample_event,
730 .comm = perf_event__process_comm,
731 .ordered_samples = true,
732 };
733
734 kvm->tool = eops;
735 kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false,
736 &kvm->tool);
737 if (!kvm->session) {
738 pr_err("Initializing perf session failed\n");
739 return -EINVAL;
740 }
741
742 if (!perf_session__has_traces(kvm->session, "kvm record"))
743 return -EINVAL;
744
745 /*
746 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
747 * traced in the old kernel.
748 */
749 ret = get_cpu_isa(kvm->session);
750
751 if (ret < 0)
752 return ret;
753
754 if (ret == 1) {
755 kvm->exit_reasons = vmx_exit_reasons;
756 kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
757 kvm->exit_reasons_isa = "VMX";
758 }
759
760 return perf_session__process_events(kvm->session, &kvm->tool);
761}
762
763static bool verify_vcpu(int vcpu)
764{
765 if (vcpu != -1 && vcpu < 0) {
766 pr_err("Invalid vcpu:%d.\n", vcpu);
767 return false;
768 }
769
770 return true;
771}
772
773static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
774{
775 int ret = -EINVAL;
776 int vcpu = kvm->trace_vcpu;
777
778 if (!verify_vcpu(vcpu))
779 goto exit;
780
781 if (!select_key(kvm))
782 goto exit;
783
784 if (!register_kvm_events_ops(kvm))
785 goto exit;
786
787 init_kvm_event_record(kvm);
788 setup_pager();
789
790 ret = read_events(kvm);
791 if (ret)
792 goto exit;
793
794 sort_result(kvm);
795 print_result(kvm);
796
797exit:
798 return ret;
799}
800
801static const char * const record_args[] = {
802 "record",
803 "-R",
804 "-f",
805 "-m", "1024",
806 "-c", "1",
807 "-e", "kvm:kvm_entry",
808 "-e", "kvm:kvm_exit",
809 "-e", "kvm:kvm_mmio",
810 "-e", "kvm:kvm_pio",
811};
812
813#define STRDUP_FAIL_EXIT(s) \
814 ({ char *_p; \
815 _p = strdup(s); \
816 if (!_p) \
817 return -ENOMEM; \
818 _p; \
819 })
820
821static int
822kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
823{
824 unsigned int rec_argc, i, j;
825 const char **rec_argv;
826
827 rec_argc = ARRAY_SIZE(record_args) + argc + 2;
828 rec_argv = calloc(rec_argc + 1, sizeof(char *));
829
830 if (rec_argv == NULL)
831 return -ENOMEM;
832
833 for (i = 0; i < ARRAY_SIZE(record_args); i++)
834 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
835
836 rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
837 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);
838
839 for (j = 1; j < (unsigned int)argc; j++, i++)
840 rec_argv[i] = argv[j];
841
842 return cmd_record(i, rec_argv, NULL);
843}
844
845static int
846kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
847{
848 const struct option kvm_events_report_options[] = {
849 OPT_STRING(0, "event", &kvm->report_event, "report event",
850 "event for reporting: vmexit, mmio, ioport"),
851 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
852 "vcpu id to report"),
853 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
854 "key for sorting: sample(sort by samples number)"
855 " time (sort by avg time)"),
856 OPT_END()
857 };
858
859 const char * const kvm_events_report_usage[] = {
860 "perf kvm stat report [<options>]",
861 NULL
862 };
863
864 symbol__init();
865
866 if (argc) {
867 argc = parse_options(argc, argv,
868 kvm_events_report_options,
869 kvm_events_report_usage, 0);
870 if (argc)
871 usage_with_options(kvm_events_report_usage,
872 kvm_events_report_options);
873 }
874
875 return kvm_events_report_vcpu(kvm);
876}
877
878static void print_kvm_stat_usage(void)
879{
880 printf("Usage: perf kvm stat <command>\n\n");
881
882 printf("# Available commands:\n");
883 printf("\trecord: record kvm events\n");
884 printf("\treport: report statistical data of kvm events\n");
885
886 printf("\nOtherwise, it is the alias of 'perf stat':\n");
887}
888
889static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
890{
891 struct perf_kvm_stat kvm = {
892 .file_name = file_name,
893
894 .trace_vcpu = -1,
895 .report_event = "vmexit",
896 .sort_key = "sample",
897
898 .exit_reasons = svm_exit_reasons,
899 .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
900 .exit_reasons_isa = "SVM",
901 };
902
903 if (argc == 1) {
904 print_kvm_stat_usage();
905 goto perf_stat;
906 }
907
908 if (!strncmp(argv[1], "rec", 3))
909 return kvm_events_record(&kvm, argc - 1, argv + 1);
910
911 if (!strncmp(argv[1], "rep", 3))
912 return kvm_events_report(&kvm, argc - 1 , argv + 1);
913
914perf_stat:
915 return cmd_stat(argc, argv, NULL);
916}
917#endif
918
919static int __cmd_record(const char *file_name, int argc, const char **argv)
920{ 55{
921 int rec_argc, i = 0, j; 56 int rec_argc, i = 0, j;
922 const char **rec_argv; 57 const char **rec_argv;
@@ -934,7 +69,7 @@ static int __cmd_record(const char *file_name, int argc, const char **argv)
934 return cmd_record(i, rec_argv, NULL); 69 return cmd_record(i, rec_argv, NULL);
935} 70}
936 71
937static int __cmd_report(const char *file_name, int argc, const char **argv) 72static int __cmd_report(int argc, const char **argv)
938{ 73{
939 int rec_argc, i = 0, j; 74 int rec_argc, i = 0, j;
940 const char **rec_argv; 75 const char **rec_argv;
@@ -952,8 +87,7 @@ static int __cmd_report(const char *file_name, int argc, const char **argv)
952 return cmd_report(i, rec_argv, NULL); 87 return cmd_report(i, rec_argv, NULL);
953} 88}
954 89
955static int 90static int __cmd_buildid_list(int argc, const char **argv)
956__cmd_buildid_list(const char *file_name, int argc, const char **argv)
957{ 91{
958 int rec_argc, i = 0, j; 92 int rec_argc, i = 0, j;
959 const char **rec_argv; 93 const char **rec_argv;
@@ -971,39 +105,9 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)
971 return cmd_buildid_list(i, rec_argv, NULL); 105 return cmd_buildid_list(i, rec_argv, NULL);
972} 106}
973 107
974int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) 108int cmd_kvm(int argc, const char **argv, const char *prefix __used)
975{ 109{
976 const char *file_name; 110 perf_host = perf_guest = 0;
977
978 const struct option kvm_options[] = {
979 OPT_STRING('i', "input", &file_name, "file",
980 "Input file name"),
981 OPT_STRING('o', "output", &file_name, "file",
982 "Output file name"),
983 OPT_BOOLEAN(0, "guest", &perf_guest,
984 "Collect guest os data"),
985 OPT_BOOLEAN(0, "host", &perf_host,
986 "Collect host os data"),
987 OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
988 "guest mount directory under which every guest os"
989 " instance has a subdir"),
990 OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,
991 "file", "file saving guest os vmlinux"),
992 OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
993 "file", "file saving guest os /proc/kallsyms"),
994 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
995 "file", "file saving guest os /proc/modules"),
996 OPT_END()
997 };
998
999
1000 const char * const kvm_usage[] = {
1001 "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}",
1002 NULL
1003 };
1004
1005 perf_host = 0;
1006 perf_guest = 1;
1007 111
1008 argc = parse_options(argc, argv, kvm_options, kvm_usage, 112 argc = parse_options(argc, argv, kvm_options, kvm_usage,
1009 PARSE_OPT_STOP_AT_NON_OPTION); 113 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -1015,32 +119,24 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1015 119
1016 if (!file_name) { 120 if (!file_name) {
1017 if (perf_host && !perf_guest) 121 if (perf_host && !perf_guest)
1018 file_name = strdup("perf.data.host"); 122 sprintf(name_buffer, "perf.data.host");
1019 else if (!perf_host && perf_guest) 123 else if (!perf_host && perf_guest)
1020 file_name = strdup("perf.data.guest"); 124 sprintf(name_buffer, "perf.data.guest");
1021 else 125 else
1022 file_name = strdup("perf.data.kvm"); 126 sprintf(name_buffer, "perf.data.kvm");
1023 127 file_name = name_buffer;
1024 if (!file_name) {
1025 pr_err("Failed to allocate memory for filename\n");
1026 return -ENOMEM;
1027 }
1028 } 128 }
1029 129
1030 if (!strncmp(argv[0], "rec", 3)) 130 if (!strncmp(argv[0], "rec", 3))
1031 return __cmd_record(file_name, argc, argv); 131 return __cmd_record(argc, argv);
1032 else if (!strncmp(argv[0], "rep", 3)) 132 else if (!strncmp(argv[0], "rep", 3))
1033 return __cmd_report(file_name, argc, argv); 133 return __cmd_report(argc, argv);
1034 else if (!strncmp(argv[0], "diff", 4)) 134 else if (!strncmp(argv[0], "diff", 4))
1035 return cmd_diff(argc, argv, NULL); 135 return cmd_diff(argc, argv, NULL);
1036 else if (!strncmp(argv[0], "top", 3)) 136 else if (!strncmp(argv[0], "top", 3))
1037 return cmd_top(argc, argv, NULL); 137 return cmd_top(argc, argv, NULL);
1038 else if (!strncmp(argv[0], "buildid-list", 12)) 138 else if (!strncmp(argv[0], "buildid-list", 12))
1039 return __cmd_buildid_list(file_name, argc, argv); 139 return __cmd_buildid_list(argc, argv);
1040#if defined(__i386__) || defined(__x86_64__)
1041 else if (!strncmp(argv[0], "stat", 4))
1042 return kvm_cmd_stat(file_name, argc, argv);
1043#endif
1044 else 140 else
1045 usage_with_options(kvm_usage, kvm_options); 141 usage_with_options(kvm_usage, kvm_options);
1046 142
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 1948eceb517..6313b6eb3eb 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -14,20 +14,20 @@
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/cache.h" 15#include "util/cache.h"
16 16
17int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 17int cmd_list(int argc, const char **argv, const char *prefix __used)
18{ 18{
19 setup_pager(); 19 setup_pager();
20 20
21 if (argc == 1) 21 if (argc == 1)
22 print_events(NULL, false); 22 print_events(NULL);
23 else { 23 else {
24 int i; 24 int i;
25 25
26 for (i = 1; i < argc; ++i) { 26 for (i = 1; i < argc; ++i) {
27 if (i > 2) 27 if (i > 1)
28 putchar('\n'); 28 putchar('\n');
29 if (strncmp(argv[i], "tracepoint", 10) == 0) 29 if (strncmp(argv[i], "tracepoint", 10) == 0)
30 print_tracepoint_events(NULL, NULL, false); 30 print_tracepoint_events(NULL, NULL);
31 else if (strcmp(argv[i], "hw") == 0 || 31 else if (strcmp(argv[i], "hw") == 0 ||
32 strcmp(argv[i], "hardware") == 0) 32 strcmp(argv[i], "hardware") == 0)
33 print_events_type(PERF_TYPE_HARDWARE); 33 print_events_type(PERF_TYPE_HARDWARE);
@@ -36,15 +36,13 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
36 print_events_type(PERF_TYPE_SOFTWARE); 36 print_events_type(PERF_TYPE_SOFTWARE);
37 else if (strcmp(argv[i], "cache") == 0 || 37 else if (strcmp(argv[i], "cache") == 0 ||
38 strcmp(argv[i], "hwcache") == 0) 38 strcmp(argv[i], "hwcache") == 0)
39 print_hwcache_events(NULL, false); 39 print_hwcache_events(NULL);
40 else if (strcmp(argv[i], "--raw-dump") == 0)
41 print_events(NULL, true);
42 else { 40 else {
43 char *sep = strchr(argv[i], ':'), *s; 41 char *sep = strchr(argv[i], ':'), *s;
44 int sep_idx; 42 int sep_idx;
45 43
46 if (sep == NULL) { 44 if (sep == NULL) {
47 print_events(argv[i], false); 45 print_events(argv[i]);
48 continue; 46 continue;
49 } 47 }
50 sep_idx = sep - argv[i]; 48 sep_idx = sep - argv[i];
@@ -53,7 +51,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
53 return -1; 51 return -1;
54 52
55 s[sep_idx] = '\0'; 53 s[sep_idx] = '\0';
56 print_tracepoint_events(s, s + sep_idx + 1, false); 54 print_tracepoint_events(s, s + sep_idx + 1);
57 free(s); 55 free(s);
58 } 56 }
59 } 57 }
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 42583006974..899080ace26 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1,8 +1,6 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/evlist.h"
5#include "util/evsel.h"
6#include "util/util.h" 4#include "util/util.h"
7#include "util/cache.h" 5#include "util/cache.h"
8#include "util/symbol.h" 6#include "util/symbol.h"
@@ -14,7 +12,6 @@
14 12
15#include "util/debug.h" 13#include "util/debug.h"
16#include "util/session.h" 14#include "util/session.h"
17#include "util/tool.h"
18 15
19#include <sys/types.h> 16#include <sys/types.h>
20#include <sys/prctl.h> 17#include <sys/prctl.h>
@@ -42,7 +39,7 @@ struct lock_stat {
42 struct rb_node rb; /* used for sorting */ 39 struct rb_node rb; /* used for sorting */
43 40
44 /* 41 /*
45 * FIXME: perf_evsel__intval() returns u64, 42 * FIXME: raw_field_value() returns unsigned long long,
46 * so address of lockdep_map should be dealed as 64bit. 43 * so address of lockdep_map should be dealed as 64bit.
47 * Is there more better solution? 44 * Is there more better solution?
48 */ 45 */
@@ -162,10 +159,8 @@ static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
162 return st; 159 return st;
163 160
164 st = zalloc(sizeof(struct thread_stat)); 161 st = zalloc(sizeof(struct thread_stat));
165 if (!st) { 162 if (!st)
166 pr_err("memory allocation failed\n"); 163 die("memory allocation failed\n");
167 return NULL;
168 }
169 164
170 st->tid = tid; 165 st->tid = tid;
171 INIT_LIST_HEAD(&st->seq_list); 166 INIT_LIST_HEAD(&st->seq_list);
@@ -184,10 +179,8 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
184 struct thread_stat *st; 179 struct thread_stat *st;
185 180
186 st = zalloc(sizeof(struct thread_stat)); 181 st = zalloc(sizeof(struct thread_stat));
187 if (!st) { 182 if (!st)
188 pr_err("memory allocation failed\n"); 183 die("memory allocation failed\n");
189 return NULL;
190 }
191 st->tid = tid; 184 st->tid = tid;
192 INIT_LIST_HEAD(&st->seq_list); 185 INIT_LIST_HEAD(&st->seq_list);
193 186
@@ -253,20 +246,18 @@ struct lock_key keys[] = {
253 { NULL, NULL } 246 { NULL, NULL }
254}; 247};
255 248
256static int select_key(void) 249static void select_key(void)
257{ 250{
258 int i; 251 int i;
259 252
260 for (i = 0; keys[i].name; i++) { 253 for (i = 0; keys[i].name; i++) {
261 if (!strcmp(keys[i].name, sort_key)) { 254 if (!strcmp(keys[i].name, sort_key)) {
262 compare = keys[i].key; 255 compare = keys[i].key;
263 return 0; 256 return;
264 } 257 }
265 } 258 }
266 259
267 pr_err("Unknown compare key: %s\n", sort_key); 260 die("Unknown compare key:%s\n", sort_key);
268
269 return -1;
270} 261}
271 262
272static void insert_to_result(struct lock_stat *st, 263static void insert_to_result(struct lock_stat *st,
@@ -331,22 +322,61 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
331 return new; 322 return new;
332 323
333alloc_failed: 324alloc_failed:
334 pr_err("memory allocation failed\n"); 325 die("memory allocation failed\n");
335 return NULL;
336} 326}
337 327
338struct trace_lock_handler { 328static char const *input_name = "perf.data";
339 int (*acquire_event)(struct perf_evsel *evsel, 329
340 struct perf_sample *sample); 330struct raw_event_sample {
331 u32 size;
332 char data[0];
333};
341 334
342 int (*acquired_event)(struct perf_evsel *evsel, 335struct trace_acquire_event {
343 struct perf_sample *sample); 336 void *addr;
337 const char *name;
338 int flag;
339};
344 340
345 int (*contended_event)(struct perf_evsel *evsel, 341struct trace_acquired_event {
346 struct perf_sample *sample); 342 void *addr;
343 const char *name;
344};
347 345
348 int (*release_event)(struct perf_evsel *evsel, 346struct trace_contended_event {
349 struct perf_sample *sample); 347 void *addr;
348 const char *name;
349};
350
351struct trace_release_event {
352 void *addr;
353 const char *name;
354};
355
356struct trace_lock_handler {
357 void (*acquire_event)(struct trace_acquire_event *,
358 struct event *,
359 int cpu,
360 u64 timestamp,
361 struct thread *thread);
362
363 void (*acquired_event)(struct trace_acquired_event *,
364 struct event *,
365 int cpu,
366 u64 timestamp,
367 struct thread *thread);
368
369 void (*contended_event)(struct trace_contended_event *,
370 struct event *,
371 int cpu,
372 u64 timestamp,
373 struct thread *thread);
374
375 void (*release_event)(struct trace_release_event *,
376 struct event *,
377 int cpu,
378 u64 timestamp,
379 struct thread *thread);
350}; 380};
351 381
352static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr) 382static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
@@ -359,10 +389,8 @@ static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
359 } 389 }
360 390
361 seq = zalloc(sizeof(struct lock_seq_stat)); 391 seq = zalloc(sizeof(struct lock_seq_stat));
362 if (!seq) { 392 if (!seq)
363 pr_err("memory allocation failed\n"); 393 die("Not enough memory\n");
364 return NULL;
365 }
366 seq->state = SEQ_STATE_UNINITIALIZED; 394 seq->state = SEQ_STATE_UNINITIALIZED;
367 seq->addr = addr; 395 seq->addr = addr;
368 396
@@ -385,42 +413,33 @@ enum acquire_flags {
385 READ_LOCK = 2, 413 READ_LOCK = 2,
386}; 414};
387 415
388static int report_lock_acquire_event(struct perf_evsel *evsel, 416static void
389 struct perf_sample *sample) 417report_lock_acquire_event(struct trace_acquire_event *acquire_event,
418 struct event *__event __used,
419 int cpu __used,
420 u64 timestamp __used,
421 struct thread *thread __used)
390{ 422{
391 void *addr;
392 struct lock_stat *ls; 423 struct lock_stat *ls;
393 struct thread_stat *ts; 424 struct thread_stat *ts;
394 struct lock_seq_stat *seq; 425 struct lock_seq_stat *seq;
395 const char *name = perf_evsel__strval(evsel, sample, "name");
396 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
397 int flag = perf_evsel__intval(evsel, sample, "flag");
398 426
399 memcpy(&addr, &tmp, sizeof(void *)); 427 ls = lock_stat_findnew(acquire_event->addr, acquire_event->name);
400
401 ls = lock_stat_findnew(addr, name);
402 if (!ls)
403 return -1;
404 if (ls->discard) 428 if (ls->discard)
405 return 0; 429 return;
406 430
407 ts = thread_stat_findnew(sample->tid); 431 ts = thread_stat_findnew(thread->pid);
408 if (!ts) 432 seq = get_seq(ts, acquire_event->addr);
409 return -1;
410
411 seq = get_seq(ts, addr);
412 if (!seq)
413 return -1;
414 433
415 switch (seq->state) { 434 switch (seq->state) {
416 case SEQ_STATE_UNINITIALIZED: 435 case SEQ_STATE_UNINITIALIZED:
417 case SEQ_STATE_RELEASED: 436 case SEQ_STATE_RELEASED:
418 if (!flag) { 437 if (!acquire_event->flag) {
419 seq->state = SEQ_STATE_ACQUIRING; 438 seq->state = SEQ_STATE_ACQUIRING;
420 } else { 439 } else {
421 if (flag & TRY_LOCK) 440 if (acquire_event->flag & TRY_LOCK)
422 ls->nr_trylock++; 441 ls->nr_trylock++;
423 if (flag & READ_LOCK) 442 if (acquire_event->flag & READ_LOCK)
424 ls->nr_readlock++; 443 ls->nr_readlock++;
425 seq->state = SEQ_STATE_READ_ACQUIRED; 444 seq->state = SEQ_STATE_READ_ACQUIRED;
426 seq->read_count = 1; 445 seq->read_count = 1;
@@ -428,7 +447,7 @@ static int report_lock_acquire_event(struct perf_evsel *evsel,
428 } 447 }
429 break; 448 break;
430 case SEQ_STATE_READ_ACQUIRED: 449 case SEQ_STATE_READ_ACQUIRED:
431 if (flag & READ_LOCK) { 450 if (acquire_event->flag & READ_LOCK) {
432 seq->read_count++; 451 seq->read_count++;
433 ls->nr_acquired++; 452 ls->nr_acquired++;
434 goto end; 453 goto end;
@@ -453,46 +472,38 @@ broken:
453 } 472 }
454 473
455 ls->nr_acquire++; 474 ls->nr_acquire++;
456 seq->prev_event_time = sample->time; 475 seq->prev_event_time = timestamp;
457end: 476end:
458 return 0; 477 return;
459} 478}
460 479
461static int report_lock_acquired_event(struct perf_evsel *evsel, 480static void
462 struct perf_sample *sample) 481report_lock_acquired_event(struct trace_acquired_event *acquired_event,
482 struct event *__event __used,
483 int cpu __used,
484 u64 timestamp __used,
485 struct thread *thread __used)
463{ 486{
464 void *addr;
465 struct lock_stat *ls; 487 struct lock_stat *ls;
466 struct thread_stat *ts; 488 struct thread_stat *ts;
467 struct lock_seq_stat *seq; 489 struct lock_seq_stat *seq;
468 u64 contended_term; 490 u64 contended_term;
469 const char *name = perf_evsel__strval(evsel, sample, "name");
470 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
471
472 memcpy(&addr, &tmp, sizeof(void *));
473 491
474 ls = lock_stat_findnew(addr, name); 492 ls = lock_stat_findnew(acquired_event->addr, acquired_event->name);
475 if (!ls)
476 return -1;
477 if (ls->discard) 493 if (ls->discard)
478 return 0; 494 return;
479
480 ts = thread_stat_findnew(sample->tid);
481 if (!ts)
482 return -1;
483 495
484 seq = get_seq(ts, addr); 496 ts = thread_stat_findnew(thread->pid);
485 if (!seq) 497 seq = get_seq(ts, acquired_event->addr);
486 return -1;
487 498
488 switch (seq->state) { 499 switch (seq->state) {
489 case SEQ_STATE_UNINITIALIZED: 500 case SEQ_STATE_UNINITIALIZED:
490 /* orphan event, do nothing */ 501 /* orphan event, do nothing */
491 return 0; 502 return;
492 case SEQ_STATE_ACQUIRING: 503 case SEQ_STATE_ACQUIRING:
493 break; 504 break;
494 case SEQ_STATE_CONTENDED: 505 case SEQ_STATE_CONTENDED:
495 contended_term = sample->time - seq->prev_event_time; 506 contended_term = timestamp - seq->prev_event_time;
496 ls->wait_time_total += contended_term; 507 ls->wait_time_total += contended_term;
497 if (contended_term < ls->wait_time_min) 508 if (contended_term < ls->wait_time_min)
498 ls->wait_time_min = contended_term; 509 ls->wait_time_min = contended_term;
@@ -517,41 +528,33 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
517 528
518 seq->state = SEQ_STATE_ACQUIRED; 529 seq->state = SEQ_STATE_ACQUIRED;
519 ls->nr_acquired++; 530 ls->nr_acquired++;
520 seq->prev_event_time = sample->time; 531 seq->prev_event_time = timestamp;
521end: 532end:
522 return 0; 533 return;
523} 534}
524 535
525static int report_lock_contended_event(struct perf_evsel *evsel, 536static void
526 struct perf_sample *sample) 537report_lock_contended_event(struct trace_contended_event *contended_event,
538 struct event *__event __used,
539 int cpu __used,
540 u64 timestamp __used,
541 struct thread *thread __used)
527{ 542{
528 void *addr;
529 struct lock_stat *ls; 543 struct lock_stat *ls;
530 struct thread_stat *ts; 544 struct thread_stat *ts;
531 struct lock_seq_stat *seq; 545 struct lock_seq_stat *seq;
532 const char *name = perf_evsel__strval(evsel, sample, "name");
533 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
534
535 memcpy(&addr, &tmp, sizeof(void *));
536 546
537 ls = lock_stat_findnew(addr, name); 547 ls = lock_stat_findnew(contended_event->addr, contended_event->name);
538 if (!ls)
539 return -1;
540 if (ls->discard) 548 if (ls->discard)
541 return 0; 549 return;
542 550
543 ts = thread_stat_findnew(sample->tid); 551 ts = thread_stat_findnew(thread->pid);
544 if (!ts) 552 seq = get_seq(ts, contended_event->addr);
545 return -1;
546
547 seq = get_seq(ts, addr);
548 if (!seq)
549 return -1;
550 553
551 switch (seq->state) { 554 switch (seq->state) {
552 case SEQ_STATE_UNINITIALIZED: 555 case SEQ_STATE_UNINITIALIZED:
553 /* orphan event, do nothing */ 556 /* orphan event, do nothing */
554 return 0; 557 return;
555 case SEQ_STATE_ACQUIRING: 558 case SEQ_STATE_ACQUIRING:
556 break; 559 break;
557 case SEQ_STATE_RELEASED: 560 case SEQ_STATE_RELEASED:
@@ -572,36 +575,28 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
572 575
573 seq->state = SEQ_STATE_CONTENDED; 576 seq->state = SEQ_STATE_CONTENDED;
574 ls->nr_contended++; 577 ls->nr_contended++;
575 seq->prev_event_time = sample->time; 578 seq->prev_event_time = timestamp;
576end: 579end:
577 return 0; 580 return;
578} 581}
579 582
580static int report_lock_release_event(struct perf_evsel *evsel, 583static void
581 struct perf_sample *sample) 584report_lock_release_event(struct trace_release_event *release_event,
585 struct event *__event __used,
586 int cpu __used,
587 u64 timestamp __used,
588 struct thread *thread __used)
582{ 589{
583 void *addr;
584 struct lock_stat *ls; 590 struct lock_stat *ls;
585 struct thread_stat *ts; 591 struct thread_stat *ts;
586 struct lock_seq_stat *seq; 592 struct lock_seq_stat *seq;
587 const char *name = perf_evsel__strval(evsel, sample, "name");
588 u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
589 593
590 memcpy(&addr, &tmp, sizeof(void *)); 594 ls = lock_stat_findnew(release_event->addr, release_event->name);
591
592 ls = lock_stat_findnew(addr, name);
593 if (!ls)
594 return -1;
595 if (ls->discard) 595 if (ls->discard)
596 return 0; 596 return;
597 597
598 ts = thread_stat_findnew(sample->tid); 598 ts = thread_stat_findnew(thread->pid);
599 if (!ts) 599 seq = get_seq(ts, release_event->addr);
600 return -1;
601
602 seq = get_seq(ts, addr);
603 if (!seq)
604 return -1;
605 600
606 switch (seq->state) { 601 switch (seq->state) {
607 case SEQ_STATE_UNINITIALIZED: 602 case SEQ_STATE_UNINITIALIZED:
@@ -635,7 +630,7 @@ free_seq:
635 list_del(&seq->list); 630 list_del(&seq->list);
636 free(seq); 631 free(seq);
637end: 632end:
638 return 0; 633 return;
639} 634}
640 635
641/* lock oriented handlers */ 636/* lock oriented handlers */
@@ -649,36 +644,96 @@ static struct trace_lock_handler report_lock_ops = {
649 644
650static struct trace_lock_handler *trace_handler; 645static struct trace_lock_handler *trace_handler;
651 646
652static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel, 647static void
653 struct perf_sample *sample) 648process_lock_acquire_event(void *data,
649 struct event *event __used,
650 int cpu __used,
651 u64 timestamp __used,
652 struct thread *thread __used)
654{ 653{
654 struct trace_acquire_event acquire_event;
655 u64 tmp; /* this is required for casting... */
656
657 tmp = raw_field_value(event, "lockdep_addr", data);
658 memcpy(&acquire_event.addr, &tmp, sizeof(void *));
659 acquire_event.name = (char *)raw_field_ptr(event, "name", data);
660 acquire_event.flag = (int)raw_field_value(event, "flag", data);
661
655 if (trace_handler->acquire_event) 662 if (trace_handler->acquire_event)
656 return trace_handler->acquire_event(evsel, sample); 663 trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
657 return 0;
658} 664}
659 665
660static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel, 666static void
661 struct perf_sample *sample) 667process_lock_acquired_event(void *data,
668 struct event *event __used,
669 int cpu __used,
670 u64 timestamp __used,
671 struct thread *thread __used)
662{ 672{
663 if (trace_handler->acquired_event) 673 struct trace_acquired_event acquired_event;
664 return trace_handler->acquired_event(evsel, sample); 674 u64 tmp; /* this is required for casting... */
665 return 0; 675
676 tmp = raw_field_value(event, "lockdep_addr", data);
677 memcpy(&acquired_event.addr, &tmp, sizeof(void *));
678 acquired_event.name = (char *)raw_field_ptr(event, "name", data);
679
680 if (trace_handler->acquire_event)
681 trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread);
666} 682}
667 683
668static int perf_evsel__process_lock_contended(struct perf_evsel *evsel, 684static void
669 struct perf_sample *sample) 685process_lock_contended_event(void *data,
686 struct event *event __used,
687 int cpu __used,
688 u64 timestamp __used,
689 struct thread *thread __used)
670{ 690{
671 if (trace_handler->contended_event) 691 struct trace_contended_event contended_event;
672 return trace_handler->contended_event(evsel, sample); 692 u64 tmp; /* this is required for casting... */
673 return 0; 693
694 tmp = raw_field_value(event, "lockdep_addr", data);
695 memcpy(&contended_event.addr, &tmp, sizeof(void *));
696 contended_event.name = (char *)raw_field_ptr(event, "name", data);
697
698 if (trace_handler->acquire_event)
699 trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
674} 700}
675 701
676static int perf_evsel__process_lock_release(struct perf_evsel *evsel, 702static void
677 struct perf_sample *sample) 703process_lock_release_event(void *data,
704 struct event *event __used,
705 int cpu __used,
706 u64 timestamp __used,
707 struct thread *thread __used)
678{ 708{
679 if (trace_handler->release_event) 709 struct trace_release_event release_event;
680 return trace_handler->release_event(evsel, sample); 710 u64 tmp; /* this is required for casting... */
681 return 0; 711
712 tmp = raw_field_value(event, "lockdep_addr", data);
713 memcpy(&release_event.addr, &tmp, sizeof(void *));
714 release_event.name = (char *)raw_field_ptr(event, "name", data);
715
716 if (trace_handler->acquire_event)
717 trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
718}
719
720static void
721process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
722{
723 struct event *event;
724 int type;
725
726 type = trace_parse_common_type(data);
727 event = trace_find_event(type);
728
729 if (!strcmp(event->name, "lock_acquire"))
730 process_lock_acquire_event(data, event, cpu, timestamp, thread);
731 if (!strcmp(event->name, "lock_acquired"))
732 process_lock_acquired_event(data, event, cpu, timestamp, thread);
733 if (!strcmp(event->name, "lock_contended"))
734 process_lock_contended_event(data, event, cpu, timestamp, thread);
735 if (!strcmp(event->name, "lock_release"))
736 process_lock_release_event(data, event, cpu, timestamp, thread);
682} 737}
683 738
684static void print_bad_events(int bad, int total) 739static void print_bad_events(int bad, int total)
@@ -780,32 +835,22 @@ static void dump_map(void)
780 } 835 }
781} 836}
782 837
783static int dump_info(void) 838static void dump_info(void)
784{ 839{
785 int rc = 0;
786
787 if (info_threads) 840 if (info_threads)
788 dump_threads(); 841 dump_threads();
789 else if (info_map) 842 else if (info_map)
790 dump_map(); 843 dump_map();
791 else { 844 else
792 rc = -1; 845 die("Unknown type of information\n");
793 pr_err("Unknown type of information\n");
794 }
795
796 return rc;
797} 846}
798 847
799typedef int (*tracepoint_handler)(struct perf_evsel *evsel, 848static int process_sample_event(union perf_event *event,
800 struct perf_sample *sample);
801
802static int process_sample_event(struct perf_tool *tool __maybe_unused,
803 union perf_event *event,
804 struct perf_sample *sample, 849 struct perf_sample *sample,
805 struct perf_evsel *evsel, 850 struct perf_evsel *evsel __used,
806 struct machine *machine) 851 struct perf_session *s)
807{ 852{
808 struct thread *thread = machine__findnew_thread(machine, sample->tid); 853 struct thread *thread = perf_session__findnew(s, sample->tid);
809 854
810 if (thread == NULL) { 855 if (thread == NULL) {
811 pr_debug("problem processing %d event, skipping it.\n", 856 pr_debug("problem processing %d event, skipping it.\n",
@@ -813,38 +858,22 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
813 return -1; 858 return -1;
814 } 859 }
815 860
816 if (evsel->handler.func != NULL) { 861 process_raw_event(sample->raw_data, sample->cpu, sample->time, thread);
817 tracepoint_handler f = evsel->handler.func;
818 return f(evsel, sample);
819 }
820 862
821 return 0; 863 return 0;
822} 864}
823 865
824static const struct perf_evsel_str_handler lock_tracepoints[] = { 866static struct perf_event_ops eops = {
825 { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ 867 .sample = process_sample_event,
826 { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ 868 .comm = perf_event__process_comm,
827 { "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ 869 .ordered_samples = true,
828 { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
829}; 870};
830 871
831static int read_events(void) 872static int read_events(void)
832{ 873{
833 struct perf_tool eops = {
834 .sample = process_sample_event,
835 .comm = perf_event__process_comm,
836 .ordered_samples = true,
837 };
838 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); 874 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
839 if (!session) { 875 if (!session)
840 pr_err("Initializing perf session failed\n"); 876 die("Initializing perf session failed\n");
841 return -1;
842 }
843
844 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
845 pr_err("Initializing perf session tracepoint handlers failed\n");
846 return -1;
847 }
848 877
849 return perf_session__process_events(session, &eops); 878 return perf_session__process_events(session, &eops);
850} 879}
@@ -861,53 +890,78 @@ static void sort_result(void)
861 } 890 }
862} 891}
863 892
864static int __cmd_report(void) 893static void __cmd_report(void)
865{ 894{
866 setup_pager(); 895 setup_pager();
867 896 select_key();
868 if ((select_key() != 0) || 897 read_events();
869 (read_events() != 0))
870 return -1;
871
872 sort_result(); 898 sort_result();
873 print_result(); 899 print_result();
874
875 return 0;
876} 900}
877 901
902static const char * const report_usage[] = {
903 "perf lock report [<options>]",
904 NULL
905};
906
907static const struct option report_options[] = {
908 OPT_STRING('k', "key", &sort_key, "acquired",
909 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
910 /* TODO: type */
911 OPT_END()
912};
913
914static const char * const info_usage[] = {
915 "perf lock info [<options>]",
916 NULL
917};
918
919static const struct option info_options[] = {
920 OPT_BOOLEAN('t', "threads", &info_threads,
921 "dump thread list in perf.data"),
922 OPT_BOOLEAN('m', "map", &info_map,
923 "map of lock instances (name:address table)"),
924 OPT_END()
925};
926
927static const char * const lock_usage[] = {
928 "perf lock [<options>] {record|trace|report}",
929 NULL
930};
931
932static const struct option lock_options[] = {
933 OPT_STRING('i', "input", &input_name, "file", "input file name"),
934 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
935 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
936 OPT_END()
937};
938
939static const char *record_args[] = {
940 "record",
941 "-R",
942 "-f",
943 "-m", "1024",
944 "-c", "1",
945 "-e", "lock:lock_acquire",
946 "-e", "lock:lock_acquired",
947 "-e", "lock:lock_contended",
948 "-e", "lock:lock_release",
949};
950
878static int __cmd_record(int argc, const char **argv) 951static int __cmd_record(int argc, const char **argv)
879{ 952{
880 const char *record_args[] = {
881 "record", "-R", "-f", "-m", "1024", "-c", "1",
882 };
883 unsigned int rec_argc, i, j; 953 unsigned int rec_argc, i, j;
884 const char **rec_argv; 954 const char **rec_argv;
885 955
886 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
887 if (!is_valid_tracepoint(lock_tracepoints[i].name)) {
888 pr_err("tracepoint %s is not enabled. "
889 "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
890 lock_tracepoints[i].name);
891 return 1;
892 }
893 }
894
895 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 956 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
896 /* factor of 2 is for -e in front of each tracepoint */
897 rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
898
899 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 957 rec_argv = calloc(rec_argc + 1, sizeof(char *));
958
900 if (rec_argv == NULL) 959 if (rec_argv == NULL)
901 return -ENOMEM; 960 return -ENOMEM;
902 961
903 for (i = 0; i < ARRAY_SIZE(record_args); i++) 962 for (i = 0; i < ARRAY_SIZE(record_args); i++)
904 rec_argv[i] = strdup(record_args[i]); 963 rec_argv[i] = strdup(record_args[i]);
905 964
906 for (j = 0; j < ARRAY_SIZE(lock_tracepoints); j++) {
907 rec_argv[i++] = "-e";
908 rec_argv[i++] = strdup(lock_tracepoints[j].name);
909 }
910
911 for (j = 1; j < (unsigned int)argc; j++, i++) 965 for (j = 1; j < (unsigned int)argc; j++, i++)
912 rec_argv[i] = argv[j]; 966 rec_argv[i] = argv[j];
913 967
@@ -916,41 +970,9 @@ static int __cmd_record(int argc, const char **argv)
916 return cmd_record(i, rec_argv, NULL); 970 return cmd_record(i, rec_argv, NULL);
917} 971}
918 972
919int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) 973int cmd_lock(int argc, const char **argv, const char *prefix __used)
920{ 974{
921 const struct option info_options[] = {
922 OPT_BOOLEAN('t', "threads", &info_threads,
923 "dump thread list in perf.data"),
924 OPT_BOOLEAN('m', "map", &info_map,
925 "map of lock instances (address:name table)"),
926 OPT_END()
927 };
928 const struct option lock_options[] = {
929 OPT_STRING('i', "input", &input_name, "file", "input file name"),
930 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
931 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
932 OPT_END()
933 };
934 const struct option report_options[] = {
935 OPT_STRING('k', "key", &sort_key, "acquired",
936 "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
937 /* TODO: type */
938 OPT_END()
939 };
940 const char * const info_usage[] = {
941 "perf lock info [<options>]",
942 NULL
943 };
944 const char * const lock_usage[] = {
945 "perf lock [<options>] {record|report|script|info}",
946 NULL
947 };
948 const char * const report_usage[] = {
949 "perf lock report [<options>]",
950 NULL
951 };
952 unsigned int i; 975 unsigned int i;
953 int rc = 0;
954 976
955 symbol__init(); 977 symbol__init();
956 for (i = 0; i < LOCKHASH_SIZE; i++) 978 for (i = 0; i < LOCKHASH_SIZE; i++)
@@ -985,13 +1007,11 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
985 /* recycling report_lock_ops */ 1007 /* recycling report_lock_ops */
986 trace_handler = &report_lock_ops; 1008 trace_handler = &report_lock_ops;
987 setup_pager(); 1009 setup_pager();
988 if (read_events() != 0) 1010 read_events();
989 rc = -1; 1011 dump_info();
990 else
991 rc = dump_info();
992 } else { 1012 } else {
993 usage_with_options(lock_usage, lock_options); 1013 usage_with_options(lock_usage, lock_options);
994 } 1014 }
995 1015
996 return rc; 1016 return 0;
997} 1017}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index de38a034b12..710ae3d0a48 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -20,6 +20,7 @@
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * 21 *
22 */ 22 */
23#define _GNU_SOURCE
23#include <sys/utsname.h> 24#include <sys/utsname.h>
24#include <sys/types.h> 25#include <sys/types.h>
25#include <sys/stat.h> 26#include <sys/stat.h>
@@ -30,6 +31,7 @@
30#include <stdlib.h> 31#include <stdlib.h>
31#include <string.h> 32#include <string.h>
32 33
34#undef _GNU_SOURCE
33#include "perf.h" 35#include "perf.h"
34#include "builtin.h" 36#include "builtin.h"
35#include "util/util.h" 37#include "util/util.h"
@@ -44,6 +46,7 @@
44 46
45#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" 47#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
46#define DEFAULT_FUNC_FILTER "!_*" 48#define DEFAULT_FUNC_FILTER "!_*"
49#define MAX_PATH_LEN 256
47 50
48/* Session management structure */ 51/* Session management structure */
49static struct { 52static struct {
@@ -54,12 +57,11 @@ static struct {
54 bool show_ext_vars; 57 bool show_ext_vars;
55 bool show_funcs; 58 bool show_funcs;
56 bool mod_events; 59 bool mod_events;
57 bool uprobes;
58 int nevents; 60 int nevents;
59 struct perf_probe_event events[MAX_PROBES]; 61 struct perf_probe_event events[MAX_PROBES];
60 struct strlist *dellist; 62 struct strlist *dellist;
61 struct line_range line_range; 63 struct line_range line_range;
62 const char *target; 64 const char *target_module;
63 int max_probe_points; 65 int max_probe_points;
64 struct strfilter *filter; 66 struct strfilter *filter;
65} params; 67} params;
@@ -76,8 +78,6 @@ static int parse_probe_event(const char *str)
76 return -1; 78 return -1;
77 } 79 }
78 80
79 pev->uprobes = params.uprobes;
80
81 /* Parse a perf-probe command into event */ 81 /* Parse a perf-probe command into event */
82 ret = parse_perf_probe_command(str, pev); 82 ret = parse_perf_probe_command(str, pev);
83 pr_debug("%d arguments\n", pev->nargs); 83 pr_debug("%d arguments\n", pev->nargs);
@@ -85,66 +85,29 @@ static int parse_probe_event(const char *str)
85 return ret; 85 return ret;
86} 86}
87 87
88static int set_target(const char *ptr)
89{
90 int found = 0;
91 const char *buf;
92
93 /*
94 * The first argument after options can be an absolute path
95 * to an executable / library or kernel module.
96 *
97 * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
98 * short module name.
99 */
100 if (!params.target && ptr && *ptr == '/') {
101 params.target = ptr;
102 found = 1;
103 buf = ptr + (strlen(ptr) - 3);
104
105 if (strcmp(buf, ".ko"))
106 params.uprobes = true;
107
108 }
109
110 return found;
111}
112
113static int parse_probe_event_argv(int argc, const char **argv) 88static int parse_probe_event_argv(int argc, const char **argv)
114{ 89{
115 int i, len, ret, found_target; 90 int i, len, ret;
116 char *buf; 91 char *buf;
117 92
118 found_target = set_target(argv[0]);
119 if (found_target && argc == 1)
120 return 0;
121
122 /* Bind up rest arguments */ 93 /* Bind up rest arguments */
123 len = 0; 94 len = 0;
124 for (i = 0; i < argc; i++) { 95 for (i = 0; i < argc; i++)
125 if (i == 0 && found_target)
126 continue;
127
128 len += strlen(argv[i]) + 1; 96 len += strlen(argv[i]) + 1;
129 }
130 buf = zalloc(len + 1); 97 buf = zalloc(len + 1);
131 if (buf == NULL) 98 if (buf == NULL)
132 return -ENOMEM; 99 return -ENOMEM;
133 len = 0; 100 len = 0;
134 for (i = 0; i < argc; i++) { 101 for (i = 0; i < argc; i++)
135 if (i == 0 && found_target)
136 continue;
137
138 len += sprintf(&buf[len], "%s ", argv[i]); 102 len += sprintf(&buf[len], "%s ", argv[i]);
139 }
140 params.mod_events = true; 103 params.mod_events = true;
141 ret = parse_probe_event(buf); 104 ret = parse_probe_event(buf);
142 free(buf); 105 free(buf);
143 return ret; 106 return ret;
144} 107}
145 108
146static int opt_add_probe_event(const struct option *opt __maybe_unused, 109static int opt_add_probe_event(const struct option *opt __used,
147 const char *str, int unset __maybe_unused) 110 const char *str, int unset __used)
148{ 111{
149 if (str) { 112 if (str) {
150 params.mod_events = true; 113 params.mod_events = true;
@@ -153,8 +116,8 @@ static int opt_add_probe_event(const struct option *opt __maybe_unused,
153 return 0; 116 return 0;
154} 117}
155 118
156static int opt_del_probe_event(const struct option *opt __maybe_unused, 119static int opt_del_probe_event(const struct option *opt __used,
157 const char *str, int unset __maybe_unused) 120 const char *str, int unset __used)
158{ 121{
159 if (str) { 122 if (str) {
160 params.mod_events = true; 123 params.mod_events = true;
@@ -165,31 +128,9 @@ static int opt_del_probe_event(const struct option *opt __maybe_unused,
165 return 0; 128 return 0;
166} 129}
167 130
168static int opt_set_target(const struct option *opt, const char *str,
169 int unset __maybe_unused)
170{
171 int ret = -ENOENT;
172
173 if (str && !params.target) {
174 if (!strcmp(opt->long_name, "exec"))
175 params.uprobes = true;
176#ifdef DWARF_SUPPORT
177 else if (!strcmp(opt->long_name, "module"))
178 params.uprobes = false;
179#endif
180 else
181 return ret;
182
183 params.target = str;
184 ret = 0;
185 }
186
187 return ret;
188}
189
190#ifdef DWARF_SUPPORT 131#ifdef DWARF_SUPPORT
191static int opt_show_lines(const struct option *opt __maybe_unused, 132static int opt_show_lines(const struct option *opt __used,
192 const char *str, int unset __maybe_unused) 133 const char *str, int unset __used)
193{ 134{
194 int ret = 0; 135 int ret = 0;
195 136
@@ -209,8 +150,8 @@ static int opt_show_lines(const struct option *opt __maybe_unused,
209 return ret; 150 return ret;
210} 151}
211 152
212static int opt_show_vars(const struct option *opt __maybe_unused, 153static int opt_show_vars(const struct option *opt __used,
213 const char *str, int unset __maybe_unused) 154 const char *str, int unset __used)
214{ 155{
215 struct perf_probe_event *pev = &params.events[params.nevents]; 156 struct perf_probe_event *pev = &params.events[params.nevents];
216 int ret; 157 int ret;
@@ -229,8 +170,8 @@ static int opt_show_vars(const struct option *opt __maybe_unused,
229} 170}
230#endif 171#endif
231 172
232static int opt_set_filter(const struct option *opt __maybe_unused, 173static int opt_set_filter(const struct option *opt __used,
233 const char *str, int unset __maybe_unused) 174 const char *str, int unset __used)
234{ 175{
235 const char *err; 176 const char *err;
236 177
@@ -250,20 +191,19 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
250 return 0; 191 return 0;
251} 192}
252 193
253int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 194static const char * const probe_usage[] = {
254{ 195 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
255 const char * const probe_usage[] = { 196 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
256 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 197 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
257 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 198 "perf probe --list",
258 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
259 "perf probe --list",
260#ifdef DWARF_SUPPORT 199#ifdef DWARF_SUPPORT
261 "perf probe [<options>] --line 'LINEDESC'", 200 "perf probe [<options>] --line 'LINEDESC'",
262 "perf probe [<options>] --vars 'PROBEPOINT'", 201 "perf probe [<options>] --vars 'PROBEPOINT'",
263#endif 202#endif
264 NULL 203 NULL
265}; 204};
266 const struct option options[] = { 205
206static const struct option options[] = {
267 OPT_INCR('v', "verbose", &verbose, 207 OPT_INCR('v', "verbose", &verbose,
268 "be more verbose (show parsed arguments, etc)"), 208 "be more verbose (show parsed arguments, etc)"),
269 OPT_BOOLEAN('l', "list", &params.list_events, 209 OPT_BOOLEAN('l', "list", &params.list_events,
@@ -309,9 +249,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
309 "file", "vmlinux pathname"), 249 "file", "vmlinux pathname"),
310 OPT_STRING('s', "source", &symbol_conf.source_prefix, 250 OPT_STRING('s', "source", &symbol_conf.source_prefix,
311 "directory", "path to kernel source"), 251 "directory", "path to kernel source"),
312 OPT_CALLBACK('m', "module", NULL, "modname|path", 252 OPT_STRING('m', "module", &params.target_module,
313 "target module name (for online) or path (for offline)", 253 "modname|path",
314 opt_set_target), 254 "target module name (for online) or path (for offline)"),
315#endif 255#endif
316 OPT__DRY_RUN(&probe_event_dry_run), 256 OPT__DRY_RUN(&probe_event_dry_run),
317 OPT_INTEGER('\0', "max-probes", &params.max_probe_points, 257 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -323,10 +263,11 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
323 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" 263 "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
324 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", 264 "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
325 opt_set_filter), 265 opt_set_filter),
326 OPT_CALLBACK('x', "exec", NULL, "executable|path",
327 "target executable name or path", opt_set_target),
328 OPT_END() 266 OPT_END()
329 }; 267};
268
269int cmd_probe(int argc, const char **argv, const char *prefix __used)
270{
330 int ret; 271 int ret;
331 272
332 argc = parse_options(argc, argv, options, probe_usage, 273 argc = parse_options(argc, argv, options, probe_usage,
@@ -372,10 +313,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
372 pr_err(" Error: Don't use --list with --funcs.\n"); 313 pr_err(" Error: Don't use --list with --funcs.\n");
373 usage_with_options(probe_usage, options); 314 usage_with_options(probe_usage, options);
374 } 315 }
375 if (params.uprobes) {
376 pr_warning(" Error: Don't use --list with --exec.\n");
377 usage_with_options(probe_usage, options);
378 }
379 ret = show_perf_probe_events(); 316 ret = show_perf_probe_events();
380 if (ret < 0) 317 if (ret < 0)
381 pr_err(" Error: Failed to show event list. (%d)\n", 318 pr_err(" Error: Failed to show event list. (%d)\n",
@@ -399,8 +336,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
399 if (!params.filter) 336 if (!params.filter)
400 params.filter = strfilter__new(DEFAULT_FUNC_FILTER, 337 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
401 NULL); 338 NULL);
402 ret = show_available_funcs(params.target, params.filter, 339 ret = show_available_funcs(params.target_module,
403 params.uprobes); 340 params.filter);
404 strfilter__delete(params.filter); 341 strfilter__delete(params.filter);
405 if (ret < 0) 342 if (ret < 0)
406 pr_err(" Error: Failed to show functions." 343 pr_err(" Error: Failed to show functions."
@@ -409,7 +346,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
409 } 346 }
410 347
411#ifdef DWARF_SUPPORT 348#ifdef DWARF_SUPPORT
412 if (params.show_lines && !params.uprobes) { 349 if (params.show_lines) {
413 if (params.mod_events) { 350 if (params.mod_events) {
414 pr_err(" Error: Don't use --line with" 351 pr_err(" Error: Don't use --line with"
415 " --add/--del.\n"); 352 " --add/--del.\n");
@@ -420,7 +357,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
420 usage_with_options(probe_usage, options); 357 usage_with_options(probe_usage, options);
421 } 358 }
422 359
423 ret = show_line_range(&params.line_range, params.target); 360 ret = show_line_range(&params.line_range, params.target_module);
424 if (ret < 0) 361 if (ret < 0)
425 pr_err(" Error: Failed to show lines. (%d)\n", ret); 362 pr_err(" Error: Failed to show lines. (%d)\n", ret);
426 return ret; 363 return ret;
@@ -437,7 +374,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
437 374
438 ret = show_available_vars(params.events, params.nevents, 375 ret = show_available_vars(params.events, params.nevents,
439 params.max_probe_points, 376 params.max_probe_points,
440 params.target, 377 params.target_module,
441 params.filter, 378 params.filter,
442 params.show_ext_vars); 379 params.show_ext_vars);
443 strfilter__delete(params.filter); 380 strfilter__delete(params.filter);
@@ -459,7 +396,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
459 if (params.nevents) { 396 if (params.nevents) {
460 ret = add_perf_probe_events(params.events, params.nevents, 397 ret = add_perf_probe_events(params.events, params.nevents,
461 params.max_probe_points, 398 params.max_probe_points,
462 params.target, 399 params.target_module,
463 params.force_add); 400 params.force_add);
464 if (ret < 0) { 401 if (ret < 0) {
465 pr_err(" Error: Failed to add events. (%d)\n", ret); 402 pr_err(" Error: Failed to add events. (%d)\n", ret);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f3151d3c70c..f4c3fbee4ba 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -22,7 +22,6 @@
22#include "util/evsel.h" 22#include "util/evsel.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/session.h" 24#include "util/session.h"
25#include "util/tool.h"
26#include "util/symbol.h" 25#include "util/symbol.h"
27#include "util/cpumap.h" 26#include "util/cpumap.h"
28#include "util/thread_map.h" 27#include "util/thread_map.h"
@@ -31,114 +30,90 @@
31#include <sched.h> 30#include <sched.h>
32#include <sys/mman.h> 31#include <sys/mman.h>
33 32
34#ifndef HAVE_ON_EXIT
35#ifndef ATEXIT_MAX
36#define ATEXIT_MAX 32
37#endif
38static int __on_exit_count = 0;
39typedef void (*on_exit_func_t) (int, void *);
40static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
41static void *__on_exit_args[ATEXIT_MAX];
42static int __exitcode = 0;
43static void __handle_on_exit_funcs(void);
44static int on_exit(on_exit_func_t function, void *arg);
45#define exit(x) (exit)(__exitcode = (x))
46
47static int on_exit(on_exit_func_t function, void *arg)
48{
49 if (__on_exit_count == ATEXIT_MAX)
50 return -ENOMEM;
51 else if (__on_exit_count == 0)
52 atexit(__handle_on_exit_funcs);
53 __on_exit_funcs[__on_exit_count] = function;
54 __on_exit_args[__on_exit_count++] = arg;
55 return 0;
56}
57
58static void __handle_on_exit_funcs(void)
59{
60 int i;
61 for (i = 0; i < __on_exit_count; i++)
62 __on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
63}
64#endif
65
66enum write_mode_t { 33enum write_mode_t {
67 WRITE_FORCE, 34 WRITE_FORCE,
68 WRITE_APPEND 35 WRITE_APPEND
69}; 36};
70 37
71struct perf_record { 38static u64 user_interval = ULLONG_MAX;
72 struct perf_tool tool; 39static u64 default_interval = 0;
73 struct perf_record_opts opts; 40
74 u64 bytes_written; 41static unsigned int page_size;
75 const char *output_name; 42static unsigned int mmap_pages = UINT_MAX;
76 struct perf_evlist *evlist; 43static unsigned int user_freq = UINT_MAX;
77 struct perf_session *session; 44static int freq = 1000;
78 const char *progname; 45static int output;
79 int output; 46static int pipe_output = 0;
80 unsigned int page_size; 47static const char *output_name = NULL;
81 int realtime_prio; 48static bool group = false;
82 enum write_mode_t write_mode; 49static int realtime_prio = 0;
83 bool no_buildid; 50static bool nodelay = false;
84 bool no_buildid_cache; 51static bool raw_samples = false;
85 bool force; 52static bool sample_id_all_avail = true;
86 bool file_new; 53static bool system_wide = false;
87 bool append_file; 54static pid_t target_pid = -1;
88 long samples; 55static pid_t target_tid = -1;
89 off_t post_processing_offset; 56static pid_t child_pid = -1;
90}; 57static bool no_inherit = false;
91 58static enum write_mode_t write_mode = WRITE_FORCE;
92static void advance_output(struct perf_record *rec, size_t size) 59static bool call_graph = false;
60static bool inherit_stat = false;
61static bool no_samples = false;
62static bool sample_address = false;
63static bool sample_time = false;
64static bool no_buildid = false;
65static bool no_buildid_cache = false;
66static struct perf_evlist *evsel_list;
67
68static long samples = 0;
69static u64 bytes_written = 0;
70
71static int file_new = 1;
72static off_t post_processing_offset;
73
74static struct perf_session *session;
75static const char *cpu_list;
76
77static void advance_output(size_t size)
93{ 78{
94 rec->bytes_written += size; 79 bytes_written += size;
95} 80}
96 81
97static int write_output(struct perf_record *rec, void *buf, size_t size) 82static void write_output(void *buf, size_t size)
98{ 83{
99 while (size) { 84 while (size) {
100 int ret = write(rec->output, buf, size); 85 int ret = write(output, buf, size);
101 86
102 if (ret < 0) { 87 if (ret < 0)
103 pr_err("failed to write\n"); 88 die("failed to write");
104 return -1;
105 }
106 89
107 size -= ret; 90 size -= ret;
108 buf += ret; 91 buf += ret;
109 92
110 rec->bytes_written += ret; 93 bytes_written += ret;
111 } 94 }
112
113 return 0;
114} 95}
115 96
116static int process_synthesized_event(struct perf_tool *tool, 97static int process_synthesized_event(union perf_event *event,
117 union perf_event *event, 98 struct perf_sample *sample __used,
118 struct perf_sample *sample __maybe_unused, 99 struct perf_session *self __used)
119 struct machine *machine __maybe_unused)
120{ 100{
121 struct perf_record *rec = container_of(tool, struct perf_record, tool); 101 write_output(event, event->header.size);
122 if (write_output(rec, event, event->header.size) < 0)
123 return -1;
124
125 return 0; 102 return 0;
126} 103}
127 104
128static int perf_record__mmap_read(struct perf_record *rec, 105static void mmap_read(struct perf_mmap *md)
129 struct perf_mmap *md)
130{ 106{
131 unsigned int head = perf_mmap__read_head(md); 107 unsigned int head = perf_mmap__read_head(md);
132 unsigned int old = md->prev; 108 unsigned int old = md->prev;
133 unsigned char *data = md->base + rec->page_size; 109 unsigned char *data = md->base + page_size;
134 unsigned long size; 110 unsigned long size;
135 void *buf; 111 void *buf;
136 int rc = 0;
137 112
138 if (old == head) 113 if (old == head)
139 return 0; 114 return;
140 115
141 rec->samples++; 116 samples++;
142 117
143 size = head - old; 118 size = head - old;
144 119
@@ -147,54 +122,32 @@ static int perf_record__mmap_read(struct perf_record *rec,
147 size = md->mask + 1 - (old & md->mask); 122 size = md->mask + 1 - (old & md->mask);
148 old += size; 123 old += size;
149 124
150 if (write_output(rec, buf, size) < 0) { 125 write_output(buf, size);
151 rc = -1;
152 goto out;
153 }
154 } 126 }
155 127
156 buf = &data[old & md->mask]; 128 buf = &data[old & md->mask];
157 size = head - old; 129 size = head - old;
158 old += size; 130 old += size;
159 131
160 if (write_output(rec, buf, size) < 0) { 132 write_output(buf, size);
161 rc = -1;
162 goto out;
163 }
164 133
165 md->prev = old; 134 md->prev = old;
166 perf_mmap__write_tail(md, old); 135 perf_mmap__write_tail(md, old);
167
168out:
169 return rc;
170} 136}
171 137
172static volatile int done = 0; 138static volatile int done = 0;
173static volatile int signr = -1; 139static volatile int signr = -1;
174static volatile int child_finished = 0;
175 140
176static void sig_handler(int sig) 141static void sig_handler(int sig)
177{ 142{
178 if (sig == SIGCHLD)
179 child_finished = 1;
180
181 done = 1; 143 done = 1;
182 signr = sig; 144 signr = sig;
183} 145}
184 146
185static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) 147static void sig_atexit(void)
186{ 148{
187 struct perf_record *rec = arg; 149 if (child_pid > 0)
188 int status; 150 kill(child_pid, SIGTERM);
189
190 if (rec->evlist->workload.pid > 0) {
191 if (!child_finished)
192 kill(rec->evlist->workload.pid, SIGTERM);
193
194 wait(&status);
195 if (WIFSIGNALED(status))
196 psignal(WTERMSIG(status), rec->progname);
197 }
198 151
199 if (signr == -1 || signr == SIGUSR1) 152 if (signr == -1 || signr == SIGUSR1)
200 return; 153 return;
@@ -203,6 +156,78 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
203 kill(getpid(), signr); 156 kill(getpid(), signr);
204} 157}
205 158
159static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
160{
161 struct perf_event_attr *attr = &evsel->attr;
162 int track = !evsel->idx; /* only the first counter needs these */
163
164 attr->disabled = 1;
165 attr->inherit = !no_inherit;
166 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
167 PERF_FORMAT_TOTAL_TIME_RUNNING |
168 PERF_FORMAT_ID;
169
170 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
171
172 if (evlist->nr_entries > 1)
173 attr->sample_type |= PERF_SAMPLE_ID;
174
175 /*
176 * We default some events to a 1 default interval. But keep
177 * it a weak assumption overridable by the user.
178 */
179 if (!attr->sample_period || (user_freq != UINT_MAX &&
180 user_interval != ULLONG_MAX)) {
181 if (freq) {
182 attr->sample_type |= PERF_SAMPLE_PERIOD;
183 attr->freq = 1;
184 attr->sample_freq = freq;
185 } else {
186 attr->sample_period = default_interval;
187 }
188 }
189
190 if (no_samples)
191 attr->sample_freq = 0;
192
193 if (inherit_stat)
194 attr->inherit_stat = 1;
195
196 if (sample_address) {
197 attr->sample_type |= PERF_SAMPLE_ADDR;
198 attr->mmap_data = track;
199 }
200
201 if (call_graph)
202 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
203
204 if (system_wide)
205 attr->sample_type |= PERF_SAMPLE_CPU;
206
207 if (sample_id_all_avail &&
208 (sample_time || system_wide || !no_inherit || cpu_list))
209 attr->sample_type |= PERF_SAMPLE_TIME;
210
211 if (raw_samples) {
212 attr->sample_type |= PERF_SAMPLE_TIME;
213 attr->sample_type |= PERF_SAMPLE_RAW;
214 attr->sample_type |= PERF_SAMPLE_CPU;
215 }
216
217 if (nodelay) {
218 attr->watermark = 0;
219 attr->wakeup_events = 1;
220 }
221
222 attr->mmap = track;
223 attr->comm = track;
224
225 if (target_pid == -1 && target_tid == -1 && !system_wide) {
226 attr->disabled = 1;
227 attr->enable_on_exec = 1;
228 }
229}
230
206static bool perf_evlist__equal(struct perf_evlist *evlist, 231static bool perf_evlist__equal(struct perf_evlist *evlist,
207 struct perf_evlist *other) 232 struct perf_evlist *other)
208{ 233{
@@ -211,33 +236,23 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
211 if (evlist->nr_entries != other->nr_entries) 236 if (evlist->nr_entries != other->nr_entries)
212 return false; 237 return false;
213 238
214 pair = perf_evlist__first(other); 239 pair = list_entry(other->entries.next, struct perf_evsel, node);
215 240
216 list_for_each_entry(pos, &evlist->entries, node) { 241 list_for_each_entry(pos, &evlist->entries, node) {
217 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0)) 242 if (memcmp(&pos->attr, &pair->attr, sizeof(pos->attr) != 0))
218 return false; 243 return false;
219 pair = perf_evsel__next(pair); 244 pair = list_entry(pair->node.next, struct perf_evsel, node);
220 } 245 }
221 246
222 return true; 247 return true;
223} 248}
224 249
225static int perf_record__open(struct perf_record *rec) 250static void open_counters(struct perf_evlist *evlist)
226{ 251{
227 struct perf_evsel *pos; 252 struct perf_evsel *pos;
228 struct perf_evlist *evlist = rec->evlist;
229 struct perf_session *session = rec->session;
230 struct perf_record_opts *opts = &rec->opts;
231 int rc = 0;
232 253
233 /* 254 if (evlist->cpus->map[0] < 0)
234 * Set the evsel leader links before we configure attributes, 255 no_inherit = true;
235 * since some might depend on this info.
236 */
237 if (opts->group)
238 perf_evlist__set_leader(evlist);
239
240 perf_evlist__config_attrs(evlist, opts);
241 256
242 list_for_each_entry(pos, &evlist->entries, node) { 257 list_for_each_entry(pos, &evlist->entries, node) {
243 struct perf_event_attr *attr = &pos->attr; 258 struct perf_event_attr *attr = &pos->attr;
@@ -255,53 +270,36 @@ static int perf_record__open(struct perf_record *rec)
255 */ 270 */
256 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 271 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
257 272
258fallback_missing_features: 273 config_attr(pos, evlist);
259 if (opts->exclude_guest_missing)
260 attr->exclude_guest = attr->exclude_host = 0;
261retry_sample_id: 274retry_sample_id:
262 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 275 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
263try_again: 276try_again:
264 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 277 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 0) {
265 int err = errno; 278 int err = errno;
266 279
267 if (err == EPERM || err == EACCES) { 280 if (err == EPERM || err == EACCES) {
268 ui__error_paranoid(); 281 ui__warning_paranoid();
269 rc = -err; 282 exit(EXIT_FAILURE);
270 goto out; 283 } else if (err == ENODEV && cpu_list) {
271 } else if (err == ENODEV && opts->target.cpu_list) { 284 die("No such device - did you specify"
272 pr_err("No such device - did you specify" 285 " an out-of-range profile CPU?\n");
273 " an out-of-range profile CPU?\n"); 286 } else if (err == EINVAL && sample_id_all_avail) {
274 rc = -err; 287 /*
275 goto out; 288 * Old kernel, no attr->sample_id_type_all field
276 } else if (err == EINVAL) { 289 */
277 if (!opts->exclude_guest_missing && 290 sample_id_all_avail = false;
278 (attr->exclude_guest || attr->exclude_host)) { 291 if (!sample_time && !raw_samples && !time_needed)
279 pr_debug("Old kernel, cannot exclude " 292 attr->sample_type &= ~PERF_SAMPLE_TIME;
280 "guest or host samples.\n"); 293
281 opts->exclude_guest_missing = true; 294 goto retry_sample_id;
282 goto fallback_missing_features;
283 } else if (!opts->sample_id_all_missing) {
284 /*
285 * Old kernel, no attr->sample_id_type_all field
286 */
287 opts->sample_id_all_missing = true;
288 if (!opts->sample_time && !opts->raw_samples && !time_needed)
289 attr->sample_type &= ~PERF_SAMPLE_TIME;
290
291 goto retry_sample_id;
292 }
293 } 295 }
294 296
295 /* 297 /*
296 * If it's cycles then fall back to hrtimer 298 * If it's cycles then fall back to hrtimer
297 * based cpu-clock-tick sw counter, which 299 * based cpu-clock-tick sw counter, which
298 * is always available even if no PMU support. 300 * is always available even if no PMU support:
299 *
300 * PPC returns ENXIO until 2.6.37 (behavior changed
301 * with commit b0a873e).
302 */ 301 */
303 if ((err == ENOENT || err == ENXIO) 302 if (attr->type == PERF_TYPE_HARDWARE
304 && attr->type == PERF_TYPE_HARDWARE
305 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 303 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
306 304
307 if (verbose) 305 if (verbose)
@@ -309,119 +307,75 @@ try_again:
309 "trying to fall back to cpu-clock-ticks\n"); 307 "trying to fall back to cpu-clock-ticks\n");
310 attr->type = PERF_TYPE_SOFTWARE; 308 attr->type = PERF_TYPE_SOFTWARE;
311 attr->config = PERF_COUNT_SW_CPU_CLOCK; 309 attr->config = PERF_COUNT_SW_CPU_CLOCK;
312 if (pos->name) {
313 free(pos->name);
314 pos->name = NULL;
315 }
316 goto try_again; 310 goto try_again;
317 } 311 }
318 312
319 if (err == ENOENT) { 313 if (err == ENOENT) {
320 ui__error("The %s event is not supported.\n", 314 ui__warning("The %s event is not supported.\n",
321 perf_evsel__name(pos)); 315 event_name(pos));
322 rc = -err; 316 exit(EXIT_FAILURE);
323 goto out;
324 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
325 ui__error("\'precise\' request may not be supported. "
326 "Try removing 'p' modifier\n");
327 rc = -err;
328 goto out;
329 } 317 }
330 318
331 printf("\n"); 319 printf("\n");
332 error("sys_perf_event_open() syscall returned with %d " 320 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
333 "(%s) for event %s. /bin/dmesg may provide " 321 err, strerror(err));
334 "additional information.\n",
335 err, strerror(err), perf_evsel__name(pos));
336 322
337#if defined(__i386__) || defined(__x86_64__) 323#if defined(__i386__) || defined(__x86_64__)
338 if (attr->type == PERF_TYPE_HARDWARE && 324 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
339 err == EOPNOTSUPP) { 325 die("No hardware sampling interrupt available."
340 pr_err("No hardware sampling interrupt available." 326 " No APIC? If so then you can boot the kernel"
341 " No APIC? If so then you can boot the kernel" 327 " with the \"lapic\" boot parameter to"
342 " with the \"lapic\" boot parameter to" 328 " force-enable it.\n");
343 " force-enable it.\n");
344 rc = -err;
345 goto out;
346 }
347#endif 329#endif
348 330
349 pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 331 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
350 rc = -err;
351 goto out;
352 } 332 }
353 } 333 }
354 334
355 if (perf_evlist__apply_filters(evlist)) { 335 if (perf_evlist__set_filters(evlist)) {
356 error("failed to set filter with %d (%s)\n", errno, 336 error("failed to set filter with %d (%s)\n", errno,
357 strerror(errno)); 337 strerror(errno));
358 rc = -1; 338 exit(-1);
359 goto out;
360 } 339 }
361 340
362 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { 341 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
363 if (errno == EPERM) { 342 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
364 pr_err("Permission error mapping pages.\n"
365 "Consider increasing "
366 "/proc/sys/kernel/perf_event_mlock_kb,\n"
367 "or try again with a smaller value of -m/--mmap_pages.\n"
368 "(current value: %d)\n", opts->mmap_pages);
369 rc = -errno;
370 } else if (!is_power_of_2(opts->mmap_pages) &&
371 (opts->mmap_pages != UINT_MAX)) {
372 pr_err("--mmap_pages/-m value must be a power of two.");
373 rc = -EINVAL;
374 } else {
375 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
376 rc = -errno;
377 }
378 goto out;
379 }
380 343
381 if (rec->file_new) 344 if (file_new)
382 session->evlist = evlist; 345 session->evlist = evlist;
383 else { 346 else {
384 if (!perf_evlist__equal(session->evlist, evlist)) { 347 if (!perf_evlist__equal(session->evlist, evlist)) {
385 fprintf(stderr, "incompatible append\n"); 348 fprintf(stderr, "incompatible append\n");
386 rc = -1; 349 exit(-1);
387 goto out;
388 } 350 }
389 } 351 }
390 352
391 perf_session__set_id_hdr_size(session); 353 perf_session__update_sample_type(session);
392out:
393 return rc;
394} 354}
395 355
396static int process_buildids(struct perf_record *rec) 356static int process_buildids(void)
397{ 357{
398 u64 size = lseek(rec->output, 0, SEEK_CUR); 358 u64 size = lseek(output, 0, SEEK_CUR);
399 359
400 if (size == 0) 360 if (size == 0)
401 return 0; 361 return 0;
402 362
403 rec->session->fd = rec->output; 363 session->fd = output;
404 return __perf_session__process_events(rec->session, rec->post_processing_offset, 364 return __perf_session__process_events(session, post_processing_offset,
405 size - rec->post_processing_offset, 365 size - post_processing_offset,
406 size, &build_id__mark_dso_hit_ops); 366 size, &build_id__mark_dso_hit_ops);
407} 367}
408 368
409static void perf_record__exit(int status, void *arg) 369static void atexit_header(void)
410{ 370{
411 struct perf_record *rec = arg; 371 if (!pipe_output) {
412 372 session->header.data_size += bytes_written;
413 if (status != 0) 373
414 return; 374 if (!no_buildid)
415 375 process_buildids();
416 if (!rec->opts.pipe_output) { 376 perf_session__write_header(session, evsel_list, output, true);
417 rec->session->header.data_size += rec->bytes_written; 377 perf_session__delete(session);
418 378 perf_evlist__delete(evsel_list);
419 if (!rec->no_buildid)
420 process_buildids(rec);
421 perf_session__write_header(rec->session, rec->evlist,
422 rec->output, true);
423 perf_session__delete(rec->session);
424 perf_evlist__delete(rec->evlist);
425 symbol__exit(); 379 symbol__exit();
426 } 380 }
427} 381}
@@ -429,7 +383,7 @@ static void perf_record__exit(int status, void *arg)
429static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 383static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
430{ 384{
431 int err; 385 int err;
432 struct perf_tool *tool = data; 386 struct perf_session *psession = data;
433 387
434 if (machine__is_host(machine)) 388 if (machine__is_host(machine))
435 return; 389 return;
@@ -442,8 +396,8 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
442 *method is used to avoid symbol missing when the first addr is 396 *method is used to avoid symbol missing when the first addr is
443 *in module instead of in guest kernel. 397 *in module instead of in guest kernel.
444 */ 398 */
445 err = perf_event__synthesize_modules(tool, process_synthesized_event, 399 err = perf_event__synthesize_modules(process_synthesized_event,
446 machine); 400 psession, machine);
447 if (err < 0) 401 if (err < 0)
448 pr_err("Couldn't record guest kernel [%d]'s reference" 402 pr_err("Couldn't record guest kernel [%d]'s reference"
449 " relocation symbol.\n", machine->pid); 403 " relocation symbol.\n", machine->pid);
@@ -452,11 +406,12 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
452 * We use _stext for guest kernel because guest kernel's /proc/kallsyms 406 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
453 * have no _text sometimes. 407 * have no _text sometimes.
454 */ 408 */
455 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 409 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
456 machine, "_text"); 410 psession, machine, "_text");
457 if (err < 0) 411 if (err < 0)
458 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 412 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
459 machine, "_stext"); 413 psession, machine,
414 "_stext");
460 if (err < 0) 415 if (err < 0)
461 pr_err("Couldn't record guest kernel [%d]'s reference" 416 pr_err("Couldn't record guest kernel [%d]'s reference"
462 " relocation symbol.\n", machine->pid); 417 " relocation symbol.\n", machine->pid);
@@ -467,177 +422,189 @@ static struct perf_event_header finished_round_event = {
467 .type = PERF_RECORD_FINISHED_ROUND, 422 .type = PERF_RECORD_FINISHED_ROUND,
468}; 423};
469 424
470static int perf_record__mmap_read_all(struct perf_record *rec) 425static void mmap_read_all(void)
471{ 426{
472 int i; 427 int i;
473 int rc = 0;
474 428
475 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 429 for (i = 0; i < evsel_list->nr_mmaps; i++) {
476 if (rec->evlist->mmap[i].base) { 430 if (evsel_list->mmap[i].base)
477 if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 431 mmap_read(&evsel_list->mmap[i]);
478 rc = -1;
479 goto out;
480 }
481 }
482 } 432 }
483 433
484 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 434 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
485 rc = write_output(rec, &finished_round_event, 435 write_output(&finished_round_event, sizeof(finished_round_event));
486 sizeof(finished_round_event));
487
488out:
489 return rc;
490} 436}
491 437
492static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 438static int __cmd_record(int argc, const char **argv)
493{ 439{
494 struct stat st; 440 struct stat st;
495 int flags; 441 int flags;
496 int err, output, feat; 442 int err;
497 unsigned long waking = 0; 443 unsigned long waking = 0;
444 int child_ready_pipe[2], go_pipe[2];
498 const bool forks = argc > 0; 445 const bool forks = argc > 0;
446 char buf;
499 struct machine *machine; 447 struct machine *machine;
500 struct perf_tool *tool = &rec->tool;
501 struct perf_record_opts *opts = &rec->opts;
502 struct perf_evlist *evsel_list = rec->evlist;
503 const char *output_name = rec->output_name;
504 struct perf_session *session;
505 bool disabled = false;
506 448
507 rec->progname = argv[0]; 449 page_size = sysconf(_SC_PAGE_SIZE);
508 450
509 rec->page_size = sysconf(_SC_PAGE_SIZE); 451 atexit(sig_atexit);
510
511 on_exit(perf_record__sig_exit, rec);
512 signal(SIGCHLD, sig_handler); 452 signal(SIGCHLD, sig_handler);
513 signal(SIGINT, sig_handler); 453 signal(SIGINT, sig_handler);
514 signal(SIGUSR1, sig_handler); 454 signal(SIGUSR1, sig_handler);
515 455
456 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
457 perror("failed to create pipes");
458 exit(-1);
459 }
460
516 if (!output_name) { 461 if (!output_name) {
517 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 462 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
518 opts->pipe_output = true; 463 pipe_output = 1;
519 else 464 else
520 rec->output_name = output_name = "perf.data"; 465 output_name = "perf.data";
521 } 466 }
522 if (output_name) { 467 if (output_name) {
523 if (!strcmp(output_name, "-")) 468 if (!strcmp(output_name, "-"))
524 opts->pipe_output = true; 469 pipe_output = 1;
525 else if (!stat(output_name, &st) && st.st_size) { 470 else if (!stat(output_name, &st) && st.st_size) {
526 if (rec->write_mode == WRITE_FORCE) { 471 if (write_mode == WRITE_FORCE) {
527 char oldname[PATH_MAX]; 472 char oldname[PATH_MAX];
528 snprintf(oldname, sizeof(oldname), "%s.old", 473 snprintf(oldname, sizeof(oldname), "%s.old",
529 output_name); 474 output_name);
530 unlink(oldname); 475 unlink(oldname);
531 rename(output_name, oldname); 476 rename(output_name, oldname);
532 } 477 }
533 } else if (rec->write_mode == WRITE_APPEND) { 478 } else if (write_mode == WRITE_APPEND) {
534 rec->write_mode = WRITE_FORCE; 479 write_mode = WRITE_FORCE;
535 } 480 }
536 } 481 }
537 482
538 flags = O_CREAT|O_RDWR; 483 flags = O_CREAT|O_RDWR;
539 if (rec->write_mode == WRITE_APPEND) 484 if (write_mode == WRITE_APPEND)
540 rec->file_new = 0; 485 file_new = 0;
541 else 486 else
542 flags |= O_TRUNC; 487 flags |= O_TRUNC;
543 488
544 if (opts->pipe_output) 489 if (pipe_output)
545 output = STDOUT_FILENO; 490 output = STDOUT_FILENO;
546 else 491 else
547 output = open(output_name, flags, S_IRUSR | S_IWUSR); 492 output = open(output_name, flags, S_IRUSR | S_IWUSR);
548 if (output < 0) { 493 if (output < 0) {
549 perror("failed to create output file"); 494 perror("failed to create output file");
550 return -1; 495 exit(-1);
551 } 496 }
552 497
553 rec->output = output;
554
555 session = perf_session__new(output_name, O_WRONLY, 498 session = perf_session__new(output_name, O_WRONLY,
556 rec->write_mode == WRITE_FORCE, false, NULL); 499 write_mode == WRITE_FORCE, false, NULL);
557 if (session == NULL) { 500 if (session == NULL) {
558 pr_err("Not enough memory for reading perf file header\n"); 501 pr_err("Not enough memory for reading perf file header\n");
559 return -1; 502 return -1;
560 } 503 }
561 504
562 rec->session = session; 505 if (!no_buildid)
563 506 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
564 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
565 perf_header__set_feat(&session->header, feat);
566
567 if (rec->no_buildid)
568 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
569
570 if (!have_tracepoints(&evsel_list->entries))
571 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
572
573 if (!rec->opts.branch_stack)
574 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
575 507
576 if (!rec->file_new) { 508 if (!file_new) {
577 err = perf_session__read_header(session, output); 509 err = perf_session__read_header(session, output);
578 if (err < 0) 510 if (err < 0)
579 goto out_delete_session; 511 goto out_delete_session;
580 } 512 }
581 513
514 if (have_tracepoints(&evsel_list->entries))
515 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
516
517 /* 512 kiB: default amount of unprivileged mlocked memory */
518 if (mmap_pages == UINT_MAX)
519 mmap_pages = (512 * 1024) / page_size;
520
582 if (forks) { 521 if (forks) {
583 err = perf_evlist__prepare_workload(evsel_list, opts, argv); 522 child_pid = fork();
584 if (err < 0) { 523 if (child_pid < 0) {
585 pr_err("Couldn't run the workload!\n"); 524 perror("failed to fork");
586 goto out_delete_session; 525 exit(-1);
587 } 526 }
588 }
589 527
590 if (perf_record__open(rec) != 0) { 528 if (!child_pid) {
591 err = -1; 529 if (pipe_output)
592 goto out_delete_session; 530 dup2(2, 1);
531 close(child_ready_pipe[0]);
532 close(go_pipe[1]);
533 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
534
535 /*
536 * Do a dummy execvp to get the PLT entry resolved,
537 * so we avoid the resolver overhead on the real
538 * execvp call.
539 */
540 execvp("", (char **)argv);
541
542 /*
543 * Tell the parent we're ready to go
544 */
545 close(child_ready_pipe[1]);
546
547 /*
548 * Wait until the parent tells us to go.
549 */
550 if (read(go_pipe[0], &buf, 1) == -1)
551 perror("unable to read pipe");
552
553 execvp(argv[0], (char **)argv);
554
555 perror(argv[0]);
556 kill(getppid(), SIGUSR1);
557 exit(-1);
558 }
559
560 if (!system_wide && target_tid == -1 && target_pid == -1)
561 evsel_list->threads->map[0] = child_pid;
562
563 close(child_ready_pipe[1]);
564 close(go_pipe[0]);
565 /*
566 * wait for child to settle
567 */
568 if (read(child_ready_pipe[0], &buf, 1) == -1) {
569 perror("unable to read pipe");
570 exit(-1);
571 }
572 close(child_ready_pipe[0]);
593 } 573 }
594 574
575 open_counters(evsel_list);
576
595 /* 577 /*
596 * perf_session__delete(session) will be called at perf_record__exit() 578 * perf_session__delete(session) will be called at atexit_header()
597 */ 579 */
598 on_exit(perf_record__exit, rec); 580 atexit(atexit_header);
599 581
600 if (opts->pipe_output) { 582 if (pipe_output) {
601 err = perf_header__write_pipe(output); 583 err = perf_header__write_pipe(output);
602 if (err < 0) 584 if (err < 0)
603 goto out_delete_session; 585 return err;
604 } else if (rec->file_new) { 586 } else if (file_new) {
605 err = perf_session__write_header(session, evsel_list, 587 err = perf_session__write_header(session, evsel_list,
606 output, false); 588 output, false);
607 if (err < 0) 589 if (err < 0)
608 goto out_delete_session; 590 return err;
609 } 591 }
610 592
611 if (!rec->no_buildid 593 post_processing_offset = lseek(output, 0, SEEK_CUR);
612 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
613 pr_err("Couldn't generate buildids. "
614 "Use --no-buildid to profile anyway.\n");
615 err = -1;
616 goto out_delete_session;
617 }
618
619 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
620
621 machine = perf_session__find_host_machine(session);
622 if (!machine) {
623 pr_err("Couldn't find native kernel information.\n");
624 err = -1;
625 goto out_delete_session;
626 }
627 594
628 if (opts->pipe_output) { 595 if (pipe_output) {
629 err = perf_event__synthesize_attrs(tool, session, 596 err = perf_session__synthesize_attrs(session,
630 process_synthesized_event); 597 process_synthesized_event);
631 if (err < 0) { 598 if (err < 0) {
632 pr_err("Couldn't synthesize attrs.\n"); 599 pr_err("Couldn't synthesize attrs.\n");
633 goto out_delete_session; 600 return err;
634 } 601 }
635 602
636 err = perf_event__synthesize_event_types(tool, process_synthesized_event, 603 err = perf_event__synthesize_event_types(process_synthesized_event,
637 machine); 604 session);
638 if (err < 0) { 605 if (err < 0) {
639 pr_err("Couldn't synthesize event_types.\n"); 606 pr_err("Couldn't synthesize event_types.\n");
640 goto out_delete_session; 607 return err;
641 } 608 }
642 609
643 if (have_tracepoints(&evsel_list->entries)) { 610 if (have_tracepoints(&evsel_list->entries)) {
@@ -649,97 +616,84 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
649 * return this more properly and also 616 * return this more properly and also
650 * propagate errors that now are calling die() 617 * propagate errors that now are calling die()
651 */ 618 */
652 err = perf_event__synthesize_tracing_data(tool, output, evsel_list, 619 err = perf_event__synthesize_tracing_data(output, evsel_list,
653 process_synthesized_event); 620 process_synthesized_event,
621 session);
654 if (err <= 0) { 622 if (err <= 0) {
655 pr_err("Couldn't record tracing data.\n"); 623 pr_err("Couldn't record tracing data.\n");
656 goto out_delete_session; 624 return err;
657 } 625 }
658 advance_output(rec, err); 626 advance_output(err);
659 } 627 }
660 } 628 }
661 629
662 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 630 machine = perf_session__find_host_machine(session);
663 machine, "_text"); 631 if (!machine) {
632 pr_err("Couldn't find native kernel information.\n");
633 return -1;
634 }
635
636 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
637 session, machine, "_text");
664 if (err < 0) 638 if (err < 0)
665 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, 639 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
666 machine, "_stext"); 640 session, machine, "_stext");
667 if (err < 0) 641 if (err < 0)
668 pr_err("Couldn't record kernel reference relocation symbol\n" 642 pr_err("Couldn't record kernel reference relocation symbol\n"
669 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 643 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
670 "Check /proc/kallsyms permission or run as root.\n"); 644 "Check /proc/kallsyms permission or run as root.\n");
671 645
672 err = perf_event__synthesize_modules(tool, process_synthesized_event, 646 err = perf_event__synthesize_modules(process_synthesized_event,
673 machine); 647 session, machine);
674 if (err < 0) 648 if (err < 0)
675 pr_err("Couldn't record kernel module information.\n" 649 pr_err("Couldn't record kernel module information.\n"
676 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 650 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
677 "Check /proc/modules permission or run as root.\n"); 651 "Check /proc/modules permission or run as root.\n");
678 652
679 if (perf_guest) 653 if (perf_guest)
680 perf_session__process_machines(session, tool, 654 perf_session__process_machines(session,
681 perf_event__synthesize_guest_os); 655 perf_event__synthesize_guest_os);
682 656
683 if (!opts->target.system_wide) 657 if (!system_wide)
684 err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 658 perf_event__synthesize_thread_map(evsel_list->threads,
685 process_synthesized_event, 659 process_synthesized_event,
686 machine); 660 session);
687 else 661 else
688 err = perf_event__synthesize_threads(tool, process_synthesized_event, 662 perf_event__synthesize_threads(process_synthesized_event,
689 machine); 663 session);
690 664
691 if (err != 0) 665 if (realtime_prio) {
692 goto out_delete_session;
693
694 if (rec->realtime_prio) {
695 struct sched_param param; 666 struct sched_param param;
696 667
697 param.sched_priority = rec->realtime_prio; 668 param.sched_priority = realtime_prio;
698 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 669 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
699 pr_err("Could not set realtime priority.\n"); 670 pr_err("Could not set realtime priority.\n");
700 err = -1; 671 exit(-1);
701 goto out_delete_session;
702 } 672 }
703 } 673 }
704 674
705 /* 675 perf_evlist__enable(evsel_list);
706 * When perf is starting the traced process, all the events
707 * (apart from group members) have enable_on_exec=1 set,
708 * so don't spoil it by prematurely enabling them.
709 */
710 if (!perf_target__none(&opts->target))
711 perf_evlist__enable(evsel_list);
712 676
713 /* 677 /*
714 * Let the child rip 678 * Let the child rip
715 */ 679 */
716 if (forks) 680 if (forks)
717 perf_evlist__start_workload(evsel_list); 681 close(go_pipe[1]);
718 682
719 for (;;) { 683 for (;;) {
720 int hits = rec->samples; 684 int hits = samples;
721 685
722 if (perf_record__mmap_read_all(rec) < 0) { 686 mmap_read_all();
723 err = -1;
724 goto out_delete_session;
725 }
726 687
727 if (hits == rec->samples) { 688 if (hits == samples) {
728 if (done) 689 if (done)
729 break; 690 break;
730 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 691 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
731 waking++; 692 waking++;
732 } 693 }
733 694
734 /* 695 if (done)
735 * When perf is starting the traced process, at the end events
736 * die with the process and we wait for that. Thus no need to
737 * disable events in this case.
738 */
739 if (done && !disabled && !perf_target__none(&opts->target)) {
740 perf_evlist__disable(evsel_list); 696 perf_evlist__disable(evsel_list);
741 disabled = true;
742 }
743 } 697 }
744 698
745 if (quiet || signr == SIGUSR1) 699 if (quiet || signr == SIGUSR1)
@@ -752,9 +706,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
752 */ 706 */
753 fprintf(stderr, 707 fprintf(stderr,
754 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 708 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
755 (double)rec->bytes_written / 1024.0 / 1024.0, 709 (double)bytes_written / 1024.0 / 1024.0,
756 output_name, 710 output_name,
757 rec->bytes_written / 24); 711 bytes_written / 24);
758 712
759 return 0; 713 return 0;
760 714
@@ -763,337 +717,97 @@ out_delete_session:
763 return err; 717 return err;
764} 718}
765 719
766#define BRANCH_OPT(n, m) \
767 { .name = n, .mode = (m) }
768
769#define BRANCH_END { .name = NULL }
770
771struct branch_mode {
772 const char *name;
773 int mode;
774};
775
776static const struct branch_mode branch_modes[] = {
777 BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
778 BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
779 BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
780 BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
781 BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
782 BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
783 BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
784 BRANCH_END
785};
786
787static int
788parse_branch_stack(const struct option *opt, const char *str, int unset)
789{
790#define ONLY_PLM \
791 (PERF_SAMPLE_BRANCH_USER |\
792 PERF_SAMPLE_BRANCH_KERNEL |\
793 PERF_SAMPLE_BRANCH_HV)
794
795 uint64_t *mode = (uint64_t *)opt->value;
796 const struct branch_mode *br;
797 char *s, *os = NULL, *p;
798 int ret = -1;
799
800 if (unset)
801 return 0;
802
803 /*
804 * cannot set it twice, -b + --branch-filter for instance
805 */
806 if (*mode)
807 return -1;
808
809 /* str may be NULL in case no arg is passed to -b */
810 if (str) {
811 /* because str is read-only */
812 s = os = strdup(str);
813 if (!s)
814 return -1;
815
816 for (;;) {
817 p = strchr(s, ',');
818 if (p)
819 *p = '\0';
820
821 for (br = branch_modes; br->name; br++) {
822 if (!strcasecmp(s, br->name))
823 break;
824 }
825 if (!br->name) {
826 ui__warning("unknown branch filter %s,"
827 " check man page\n", s);
828 goto error;
829 }
830
831 *mode |= br->mode;
832
833 if (!p)
834 break;
835
836 s = p + 1;
837 }
838 }
839 ret = 0;
840
841 /* default to any branch */
842 if ((*mode & ~ONLY_PLM) == 0) {
843 *mode = PERF_SAMPLE_BRANCH_ANY;
844 }
845error:
846 free(os);
847 return ret;
848}
849
850#ifdef LIBUNWIND_SUPPORT
851static int get_stack_size(char *str, unsigned long *_size)
852{
853 char *endptr;
854 unsigned long size;
855 unsigned long max_size = round_down(USHRT_MAX, sizeof(u64));
856
857 size = strtoul(str, &endptr, 0);
858
859 do {
860 if (*endptr)
861 break;
862
863 size = round_up(size, sizeof(u64));
864 if (!size || size > max_size)
865 break;
866
867 *_size = size;
868 return 0;
869
870 } while (0);
871
872 pr_err("callchain: Incorrect stack dump size (max %ld): %s\n",
873 max_size, str);
874 return -1;
875}
876#endif /* LIBUNWIND_SUPPORT */
877
878static int
879parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
880 int unset)
881{
882 struct perf_record *rec = (struct perf_record *)opt->value;
883 char *tok, *name, *saveptr = NULL;
884 char *buf;
885 int ret = -1;
886
887 /* --no-call-graph */
888 if (unset)
889 return 0;
890
891 /* We specified default option if none is provided. */
892 BUG_ON(!arg);
893
894 /* We need buffer that we know we can write to. */
895 buf = malloc(strlen(arg) + 1);
896 if (!buf)
897 return -ENOMEM;
898
899 strcpy(buf, arg);
900
901 tok = strtok_r((char *)buf, ",", &saveptr);
902 name = tok ? : (char *)buf;
903
904 do {
905 /* Framepointer style */
906 if (!strncmp(name, "fp", sizeof("fp"))) {
907 if (!strtok_r(NULL, ",", &saveptr)) {
908 rec->opts.call_graph = CALLCHAIN_FP;
909 ret = 0;
910 } else
911 pr_err("callchain: No more arguments "
912 "needed for -g fp\n");
913 break;
914
915#ifdef LIBUNWIND_SUPPORT
916 /* Dwarf style */
917 } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
918 const unsigned long default_stack_dump_size = 8192;
919
920 ret = 0;
921 rec->opts.call_graph = CALLCHAIN_DWARF;
922 rec->opts.stack_dump_size = default_stack_dump_size;
923
924 tok = strtok_r(NULL, ",", &saveptr);
925 if (tok) {
926 unsigned long size = 0;
927
928 ret = get_stack_size(tok, &size);
929 rec->opts.stack_dump_size = size;
930 }
931
932 if (!ret)
933 pr_debug("callchain: stack dump size %d\n",
934 rec->opts.stack_dump_size);
935#endif /* LIBUNWIND_SUPPORT */
936 } else {
937 pr_err("callchain: Unknown -g option "
938 "value: %s\n", arg);
939 break;
940 }
941
942 } while (0);
943
944 free(buf);
945
946 if (!ret)
947 pr_debug("callchain: type %d\n", rec->opts.call_graph);
948
949 return ret;
950}
951
952static const char * const record_usage[] = { 720static const char * const record_usage[] = {
953 "perf record [<options>] [<command>]", 721 "perf record [<options>] [<command>]",
954 "perf record [<options>] -- <command> [<options>]", 722 "perf record [<options>] -- <command> [<options>]",
955 NULL 723 NULL
956}; 724};
957 725
958/* 726static bool force, append_file;
959 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
960 * because we need to have access to it in perf_record__exit, that is called
961 * after cmd_record() exits, but since record_options need to be accessible to
962 * builtin-script, leave it here.
963 *
964 * At least we don't ouch it in all the other functions here directly.
965 *
966 * Just say no to tons of global variables, sigh.
967 */
968static struct perf_record record = {
969 .opts = {
970 .mmap_pages = UINT_MAX,
971 .user_freq = UINT_MAX,
972 .user_interval = ULLONG_MAX,
973 .freq = 4000,
974 .target = {
975 .uses_mmap = true,
976 },
977 },
978 .write_mode = WRITE_FORCE,
979 .file_new = true,
980};
981
982#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
983
984#ifdef LIBUNWIND_SUPPORT
985static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
986#else
987static const char callchain_help[] = CALLCHAIN_HELP "[fp]";
988#endif
989 727
990/*
991 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
992 * with it and switch to use the library functions in perf_evlist that came
993 * from builtin-record.c, i.e. use perf_record_opts,
994 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
995 * using pipes, etc.
996 */
997const struct option record_options[] = { 728const struct option record_options[] = {
998 OPT_CALLBACK('e', "event", &record.evlist, "event", 729 OPT_CALLBACK('e', "event", &evsel_list, "event",
999 "event selector. use 'perf list' to list available events", 730 "event selector. use 'perf list' to list available events",
1000 parse_events_option), 731 parse_events_option),
1001 OPT_CALLBACK(0, "filter", &record.evlist, "filter", 732 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1002 "event filter", parse_filter), 733 "event filter", parse_filter),
1003 OPT_STRING('p', "pid", &record.opts.target.pid, "pid", 734 OPT_INTEGER('p', "pid", &target_pid,
1004 "record events on existing process id"), 735 "record events on existing process id"),
1005 OPT_STRING('t', "tid", &record.opts.target.tid, "tid", 736 OPT_INTEGER('t', "tid", &target_tid,
1006 "record events on existing thread id"), 737 "record events on existing thread id"),
1007 OPT_INTEGER('r', "realtime", &record.realtime_prio, 738 OPT_INTEGER('r', "realtime", &realtime_prio,
1008 "collect data with this RT SCHED_FIFO priority"), 739 "collect data with this RT SCHED_FIFO priority"),
1009 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, 740 OPT_BOOLEAN('D', "no-delay", &nodelay,
1010 "collect data without buffering"), 741 "collect data without buffering"),
1011 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 742 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
1012 "collect raw sample records from all opened counters"), 743 "collect raw sample records from all opened counters"),
1013 OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide, 744 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1014 "system-wide collection from all CPUs"), 745 "system-wide collection from all CPUs"),
1015 OPT_BOOLEAN('A', "append", &record.append_file, 746 OPT_BOOLEAN('A', "append", &append_file,
1016 "append to the output file to do incremental profiling"), 747 "append to the output file to do incremental profiling"),
1017 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 748 OPT_STRING('C', "cpu", &cpu_list, "cpu",
1018 "list of cpus to monitor"), 749 "list of cpus to monitor"),
1019 OPT_BOOLEAN('f', "force", &record.force, 750 OPT_BOOLEAN('f', "force", &force,
1020 "overwrite existing data file (deprecated)"), 751 "overwrite existing data file (deprecated)"),
1021 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 752 OPT_U64('c', "count", &user_interval, "event period to sample"),
1022 OPT_STRING('o', "output", &record.output_name, "file", 753 OPT_STRING('o', "output", &output_name, "file",
1023 "output file name"), 754 "output file name"),
1024 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 755 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1025 "child tasks do not inherit counters"), 756 "child tasks do not inherit counters"),
1026 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 757 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
1027 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, 758 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1028 "number of mmap data pages"), 759 OPT_BOOLEAN(0, "group", &group,
1029 OPT_BOOLEAN(0, "group", &record.opts.group,
1030 "put the counters into a counter group"), 760 "put the counters into a counter group"),
1031 OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", 761 OPT_BOOLEAN('g', "call-graph", &call_graph,
1032 callchain_help, &parse_callchain_opt, 762 "do call-graph (stack chain/backtrace) recording"),
1033 "fp"),
1034 OPT_INCR('v', "verbose", &verbose, 763 OPT_INCR('v', "verbose", &verbose,
1035 "be more verbose (show counter open errors, etc)"), 764 "be more verbose (show counter open errors, etc)"),
1036 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 765 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
1037 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, 766 OPT_BOOLEAN('s', "stat", &inherit_stat,
1038 "per thread counts"), 767 "per thread counts"),
1039 OPT_BOOLEAN('d', "data", &record.opts.sample_address, 768 OPT_BOOLEAN('d', "data", &sample_address,
1040 "Sample addresses"), 769 "Sample addresses"),
1041 OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), 770 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
1042 OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), 771 OPT_BOOLEAN('n', "no-samples", &no_samples,
1043 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1044 "don't sample"), 772 "don't sample"),
1045 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 773 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
1046 "do not update the buildid cache"), 774 "do not update the buildid cache"),
1047 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 775 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
1048 "do not collect buildids in perf.data"), 776 "do not collect buildids in perf.data"),
1049 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 777 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1050 "monitor event in cgroup name only", 778 "monitor event in cgroup name only",
1051 parse_cgroups), 779 parse_cgroups),
1052 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
1053 "user to profile"),
1054
1055 OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
1056 "branch any", "sample any taken branches",
1057 parse_branch_stack),
1058
1059 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
1060 "branch filter mask", "branch stack filter modes",
1061 parse_branch_stack),
1062 OPT_END() 780 OPT_END()
1063}; 781};
1064 782
1065int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 783int cmd_record(int argc, const char **argv, const char *prefix __used)
1066{ 784{
1067 int err = -ENOMEM; 785 int err = -ENOMEM;
1068 struct perf_evsel *pos; 786 struct perf_evsel *pos;
1069 struct perf_evlist *evsel_list;
1070 struct perf_record *rec = &record;
1071 char errbuf[BUFSIZ];
1072 787
1073 evsel_list = perf_evlist__new(NULL, NULL); 788 evsel_list = perf_evlist__new(NULL, NULL);
1074 if (evsel_list == NULL) 789 if (evsel_list == NULL)
1075 return -ENOMEM; 790 return -ENOMEM;
1076 791
1077 rec->evlist = evsel_list;
1078
1079 argc = parse_options(argc, argv, record_options, record_usage, 792 argc = parse_options(argc, argv, record_options, record_usage,
1080 PARSE_OPT_STOP_AT_NON_OPTION); 793 PARSE_OPT_STOP_AT_NON_OPTION);
1081 if (!argc && perf_target__none(&rec->opts.target)) 794 if (!argc && target_pid == -1 && target_tid == -1 &&
795 !system_wide && !cpu_list)
1082 usage_with_options(record_usage, record_options); 796 usage_with_options(record_usage, record_options);
1083 797
1084 if (rec->force && rec->append_file) { 798 if (force && append_file) {
1085 ui__error("Can't overwrite and append at the same time." 799 fprintf(stderr, "Can't overwrite and append at the same time."
1086 " You need to choose between -f and -A"); 800 " You need to choose between -f and -A");
1087 usage_with_options(record_usage, record_options); 801 usage_with_options(record_usage, record_options);
1088 } else if (rec->append_file) { 802 } else if (append_file) {
1089 rec->write_mode = WRITE_APPEND; 803 write_mode = WRITE_APPEND;
1090 } else { 804 } else {
1091 rec->write_mode = WRITE_FORCE; 805 write_mode = WRITE_FORCE;
1092 } 806 }
1093 807
1094 if (nr_cgroups && !rec->opts.target.system_wide) { 808 if (nr_cgroups && !system_wide) {
1095 ui__error("cgroup monitoring only available in" 809 fprintf(stderr, "cgroup monitoring only available in"
1096 " system-wide mode\n"); 810 " system-wide mode\n");
1097 usage_with_options(record_usage, record_options); 811 usage_with_options(record_usage, record_options);
1098 } 812 }
1099 813
@@ -1109,7 +823,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1109"If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 823"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
1110"even with a suitable vmlinux or kallsyms file.\n\n"); 824"even with a suitable vmlinux or kallsyms file.\n\n");
1111 825
1112 if (rec->no_buildid_cache || rec->no_buildid) 826 if (no_buildid_cache || no_buildid)
1113 disable_buildid_cache(); 827 disable_buildid_cache();
1114 828
1115 if (evsel_list->nr_entries == 0 && 829 if (evsel_list->nr_entries == 0 &&
@@ -1118,51 +832,43 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1118 goto out_symbol_exit; 832 goto out_symbol_exit;
1119 } 833 }
1120 834
1121 err = perf_target__validate(&rec->opts.target); 835 if (target_pid != -1)
1122 if (err) { 836 target_tid = target_pid;
1123 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
1124 ui__warning("%s", errbuf);
1125 }
1126
1127 err = perf_target__parse_uid(&rec->opts.target);
1128 if (err) {
1129 int saved_errno = errno;
1130
1131 perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
1132 ui__error("%s", errbuf);
1133 837
1134 err = -saved_errno; 838 if (perf_evlist__create_maps(evsel_list, target_pid,
1135 goto out_free_fd; 839 target_tid, cpu_list) < 0)
1136 }
1137
1138 err = -ENOMEM;
1139 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
1140 usage_with_options(record_usage, record_options); 840 usage_with_options(record_usage, record_options);
1141 841
1142 list_for_each_entry(pos, &evsel_list->entries, node) { 842 list_for_each_entry(pos, &evsel_list->entries, node) {
1143 if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos))) 843 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
844 evsel_list->threads->nr) < 0)
845 goto out_free_fd;
846 if (perf_header__push_event(pos->attr.config, event_name(pos)))
1144 goto out_free_fd; 847 goto out_free_fd;
1145 } 848 }
1146 849
1147 if (rec->opts.user_interval != ULLONG_MAX) 850 if (perf_evlist__alloc_pollfd(evsel_list) < 0)
1148 rec->opts.default_interval = rec->opts.user_interval; 851 goto out_free_fd;
1149 if (rec->opts.user_freq != UINT_MAX) 852
1150 rec->opts.freq = rec->opts.user_freq; 853 if (user_interval != ULLONG_MAX)
854 default_interval = user_interval;
855 if (user_freq != UINT_MAX)
856 freq = user_freq;
1151 857
1152 /* 858 /*
1153 * User specified count overrides default frequency. 859 * User specified count overrides default frequency.
1154 */ 860 */
1155 if (rec->opts.default_interval) 861 if (default_interval)
1156 rec->opts.freq = 0; 862 freq = 0;
1157 else if (rec->opts.freq) { 863 else if (freq) {
1158 rec->opts.default_interval = rec->opts.freq; 864 default_interval = freq;
1159 } else { 865 } else {
1160 ui__error("frequency and count are zero, aborting\n"); 866 fprintf(stderr, "frequency and count are zero, aborting\n");
1161 err = -EINVAL; 867 err = -EINVAL;
1162 goto out_free_fd; 868 goto out_free_fd;
1163 } 869 }
1164 870
1165 err = __cmd_record(&record, argc, argv); 871 err = __cmd_record(argc, argv);
1166out_free_fd: 872out_free_fd:
1167 perf_evlist__delete_maps(evsel_list); 873 perf_evlist__delete_maps(evsel_list);
1168out_symbol_exit: 874out_symbol_exit:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index fc251005dd3..d7ff277bdb7 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -25,7 +25,6 @@
25#include "util/evsel.h" 25#include "util/evsel.h"
26#include "util/header.h" 26#include "util/header.h"
27#include "util/session.h" 27#include "util/session.h"
28#include "util/tool.h"
29 28
30#include "util/parse-options.h" 29#include "util/parse-options.h"
31#include "util/parse-events.h" 30#include "util/parse-events.h"
@@ -33,115 +32,40 @@
33#include "util/thread.h" 32#include "util/thread.h"
34#include "util/sort.h" 33#include "util/sort.h"
35#include "util/hist.h" 34#include "util/hist.h"
36#include "arch/common.h"
37 35
38#include <linux/bitmap.h> 36#include <linux/bitmap.h>
39 37
40struct perf_report { 38static char const *input_name = "perf.data";
41 struct perf_tool tool;
42 struct perf_session *session;
43 bool force, use_tui, use_gtk, use_stdio;
44 bool hide_unresolved;
45 bool dont_use_callchains;
46 bool show_full_info;
47 bool show_threads;
48 bool inverted_callchain;
49 struct perf_read_values show_threads_values;
50 const char *pretty_printing_style;
51 symbol_filter_t annotate_init;
52 const char *cpu_list;
53 const char *symbol_filter_str;
54 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
55};
56 39
57static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 40static bool force, use_tui, use_stdio;
58 struct addr_location *al, 41static bool hide_unresolved;
59 struct perf_sample *sample, 42static bool dont_use_callchains;
60 struct perf_evsel *evsel,
61 struct machine *machine)
62{
63 struct perf_report *rep = container_of(tool, struct perf_report, tool);
64 struct symbol *parent = NULL;
65 int err = 0;
66 unsigned i;
67 struct hist_entry *he;
68 struct branch_info *bi, *bx;
69 43
70 if ((sort__has_parent || symbol_conf.use_callchain) 44static bool show_threads;
71 && sample->callchain) { 45static struct perf_read_values show_threads_values;
72 err = machine__resolve_callchain(machine, evsel, al->thread,
73 sample, &parent);
74 if (err)
75 return err;
76 }
77 46
78 bi = machine__resolve_bstack(machine, al->thread, 47static const char default_pretty_printing_style[] = "normal";
79 sample->branch_stack); 48static const char *pretty_printing_style = default_pretty_printing_style;
80 if (!bi)
81 return -ENOMEM;
82 49
83 for (i = 0; i < sample->branch_stack->nr; i++) { 50static char callchain_default_opt[] = "fractal,0.5,callee";
84 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) 51static bool inverted_callchain;
85 continue; 52static symbol_filter_t annotate_init;
86 /*
87 * The report shows the percentage of total branches captured
88 * and not events sampled. Thus we use a pseudo period of 1.
89 */
90 he = __hists__add_branch_entry(&evsel->hists, al, parent,
91 &bi[i], 1);
92 if (he) {
93 struct annotation *notes;
94 err = -ENOMEM;
95 bx = he->branch_info;
96 if (bx->from.sym && use_browser == 1 && sort__has_sym) {
97 notes = symbol__annotation(bx->from.sym);
98 if (!notes->src
99 && symbol__alloc_hist(bx->from.sym) < 0)
100 goto out;
101
102 err = symbol__inc_addr_samples(bx->from.sym,
103 bx->from.map,
104 evsel->idx,
105 bx->from.al_addr);
106 if (err)
107 goto out;
108 }
109 53
110 if (bx->to.sym && use_browser == 1 && sort__has_sym) { 54static const char *cpu_list;
111 notes = symbol__annotation(bx->to.sym); 55static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
112 if (!notes->src
113 && symbol__alloc_hist(bx->to.sym) < 0)
114 goto out;
115
116 err = symbol__inc_addr_samples(bx->to.sym,
117 bx->to.map,
118 evsel->idx,
119 bx->to.al_addr);
120 if (err)
121 goto out;
122 }
123 evsel->hists.stats.total_period += 1;
124 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
125 err = 0;
126 } else
127 return -ENOMEM;
128 }
129out:
130 return err;
131}
132 56
133static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, 57static int perf_session__add_hist_entry(struct perf_session *session,
134 struct addr_location *al, 58 struct addr_location *al,
135 struct perf_sample *sample, 59 struct perf_sample *sample,
136 struct machine *machine) 60 struct perf_evsel *evsel)
137{ 61{
138 struct symbol *parent = NULL; 62 struct symbol *parent = NULL;
139 int err = 0; 63 int err = 0;
140 struct hist_entry *he; 64 struct hist_entry *he;
141 65
142 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 66 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
143 err = machine__resolve_callchain(machine, evsel, al->thread, 67 err = perf_session__resolve_callchain(session, al->thread,
144 sample, &parent); 68 sample->callchain, &parent);
145 if (err) 69 if (err)
146 return err; 70 return err;
147 } 71 }
@@ -151,8 +75,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
151 return -ENOMEM; 75 return -ENOMEM;
152 76
153 if (symbol_conf.use_callchain) { 77 if (symbol_conf.use_callchain) {
154 err = callchain_append(he->callchain, 78 err = callchain_append(he->callchain, &session->callchain_cursor,
155 &callchain_cursor,
156 sample->period); 79 sample->period);
157 if (err) 80 if (err)
158 return err; 81 return err;
@@ -162,13 +85,14 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
162 * so we don't allocated the extra space needed because the stdio 85 * so we don't allocated the extra space needed because the stdio
163 * code will not use it. 86 * code will not use it.
164 */ 87 */
165 if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) { 88 if (al->sym != NULL && use_browser > 0) {
166 struct annotation *notes = symbol__annotation(he->ms.sym); 89 struct annotation *notes = symbol__annotation(he->ms.sym);
167 90
168 assert(evsel != NULL); 91 assert(evsel != NULL);
169 92
170 err = -ENOMEM; 93 err = -ENOMEM;
171 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) 94 if (notes->src == NULL &&
95 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
172 goto out; 96 goto out;
173 97
174 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 98 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
@@ -181,57 +105,46 @@ out:
181} 105}
182 106
183 107
184static int process_sample_event(struct perf_tool *tool, 108static int process_sample_event(union perf_event *event,
185 union perf_event *event,
186 struct perf_sample *sample, 109 struct perf_sample *sample,
187 struct perf_evsel *evsel, 110 struct perf_evsel *evsel,
188 struct machine *machine) 111 struct perf_session *session)
189{ 112{
190 struct perf_report *rep = container_of(tool, struct perf_report, tool);
191 struct addr_location al; 113 struct addr_location al;
192 114
193 if (perf_event__preprocess_sample(event, machine, &al, sample, 115 if (perf_event__preprocess_sample(event, session, &al, sample,
194 rep->annotate_init) < 0) { 116 annotate_init) < 0) {
195 fprintf(stderr, "problem processing %d event, skipping it.\n", 117 fprintf(stderr, "problem processing %d event, skipping it.\n",
196 event->header.type); 118 event->header.type);
197 return -1; 119 return -1;
198 } 120 }
199 121
200 if (al.filtered || (rep->hide_unresolved && al.sym == NULL)) 122 if (al.filtered || (hide_unresolved && al.sym == NULL))
201 return 0; 123 return 0;
202 124
203 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 125 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
204 return 0; 126 return 0;
205 127
206 if (sort__branch_mode == 1) { 128 if (al.map != NULL)
207 if (perf_report__add_branch_hist_entry(tool, &al, sample, 129 al.map->dso->hit = 1;
208 evsel, machine)) {
209 pr_debug("problem adding lbr entry, skipping event\n");
210 return -1;
211 }
212 } else {
213 if (al.map != NULL)
214 al.map->dso->hit = 1;
215 130
216 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { 131 if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
217 pr_debug("problem incrementing symbol period, skipping event\n"); 132 pr_debug("problem incrementing symbol period, skipping event\n");
218 return -1; 133 return -1;
219 }
220 } 134 }
135
221 return 0; 136 return 0;
222} 137}
223 138
224static int process_read_event(struct perf_tool *tool, 139static int process_read_event(union perf_event *event,
225 union perf_event *event, 140 struct perf_sample *sample __used,
226 struct perf_sample *sample __maybe_unused, 141 struct perf_session *session)
227 struct perf_evsel *evsel,
228 struct machine *machine __maybe_unused)
229{ 142{
230 struct perf_report *rep = container_of(tool, struct perf_report, tool); 143 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
231 144 event->read.id);
232 if (rep->show_threads) { 145 if (show_threads) {
233 const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; 146 const char *name = evsel ? event_name(evsel) : "unknown";
234 perf_read_values_add_value(&rep->show_threads_values, 147 perf_read_values_add_value(&show_threads_values,
235 event->read.pid, event->read.tid, 148 event->read.pid, event->read.tid,
236 event->read.id, 149 event->read.id,
237 name, 150 name,
@@ -239,55 +152,58 @@ static int process_read_event(struct perf_tool *tool,
239 } 152 }
240 153
241 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, 154 dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
242 evsel ? perf_evsel__name(evsel) : "FAIL", 155 evsel ? event_name(evsel) : "FAIL",
243 event->read.value); 156 event->read.value);
244 157
245 return 0; 158 return 0;
246} 159}
247 160
248/* For pipe mode, sample_type is not currently set */ 161static int perf_session__setup_sample_type(struct perf_session *self)
249static int perf_report__setup_sample_type(struct perf_report *rep)
250{ 162{
251 struct perf_session *self = rep->session; 163 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
252 u64 sample_type = perf_evlist__sample_type(self->evlist);
253
254 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
255 if (sort__has_parent) { 164 if (sort__has_parent) {
256 ui__error("Selected --sort parent, but no " 165 ui__warning("Selected --sort parent, but no "
257 "callchain data. Did you call " 166 "callchain data. Did you call "
258 "'perf record' without -g?\n"); 167 "'perf record' without -g?\n");
259 return -EINVAL; 168 return -EINVAL;
260 } 169 }
261 if (symbol_conf.use_callchain) { 170 if (symbol_conf.use_callchain) {
262 ui__error("Selected -g but no callchain data. Did " 171 ui__warning("Selected -g but no callchain data. Did "
263 "you call 'perf record' without -g?\n"); 172 "you call 'perf record' without -g?\n");
264 return -1; 173 return -1;
265 } 174 }
266 } else if (!rep->dont_use_callchains && 175 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
267 callchain_param.mode != CHAIN_NONE &&
268 !symbol_conf.use_callchain) { 176 !symbol_conf.use_callchain) {
269 symbol_conf.use_callchain = true; 177 symbol_conf.use_callchain = true;
270 if (callchain_register_param(&callchain_param) < 0) { 178 if (callchain_register_param(&callchain_param) < 0) {
271 ui__error("Can't register callchain params.\n"); 179 ui__warning("Can't register callchain "
180 "params.\n");
272 return -EINVAL; 181 return -EINVAL;
273 } 182 }
274 } 183 }
275 184
276 if (sort__branch_mode == 1) {
277 if (!self->fd_pipe &&
278 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
279 ui__error("Selected -b but no branch data. "
280 "Did you call perf record without -b?\n");
281 return -1;
282 }
283 }
284
285 return 0; 185 return 0;
286} 186}
287 187
188static struct perf_event_ops event_ops = {
189 .sample = process_sample_event,
190 .mmap = perf_event__process_mmap,
191 .comm = perf_event__process_comm,
192 .exit = perf_event__process_task,
193 .fork = perf_event__process_task,
194 .lost = perf_event__process_lost,
195 .read = process_read_event,
196 .attr = perf_event__process_attr,
197 .event_type = perf_event__process_event_type,
198 .tracing_data = perf_event__process_tracing_data,
199 .build_id = perf_event__process_build_id,
200 .ordered_samples = true,
201 .ordering_requires_timestamps = true,
202};
203
288extern volatile int session_done; 204extern volatile int session_done;
289 205
290static void sig_handler(int sig __maybe_unused) 206static void sig_handler(int sig __used)
291{ 207{
292 session_done = 1; 208 session_done = 1;
293} 209}
@@ -297,30 +213,29 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
297{ 213{
298 size_t ret; 214 size_t ret;
299 char unit; 215 char unit;
300 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; 216 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
301 u64 nr_events = self->stats.total_period;
302 217
303 nr_samples = convert_unit(nr_samples, &unit); 218 nr_events = convert_unit(nr_events, &unit);
304 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); 219 ret = fprintf(fp, "# Events: %lu%c", nr_events, unit);
305 if (evname != NULL) 220 if (evname != NULL)
306 ret += fprintf(fp, " of event '%s'", evname); 221 ret += fprintf(fp, " %s", evname);
307
308 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
309 return ret + fprintf(fp, "\n#\n"); 222 return ret + fprintf(fp, "\n#\n");
310} 223}
311 224
312static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, 225static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
313 struct perf_report *rep,
314 const char *help) 226 const char *help)
315{ 227{
316 struct perf_evsel *pos; 228 struct perf_evsel *pos;
317 229
318 list_for_each_entry(pos, &evlist->entries, node) { 230 list_for_each_entry(pos, &evlist->entries, node) {
319 struct hists *hists = &pos->hists; 231 struct hists *hists = &pos->hists;
320 const char *evname = perf_evsel__name(pos); 232 const char *evname = NULL;
233
234 if (rb_first(&hists->entries) != rb_last(&hists->entries))
235 evname = event_name(pos);
321 236
322 hists__fprintf_nr_sample_events(hists, evname, stdout); 237 hists__fprintf_nr_sample_events(hists, evname, stdout);
323 hists__fprintf(hists, true, 0, 0, stdout); 238 hists__fprintf(hists, NULL, false, stdout);
324 fprintf(stdout, "\n\n"); 239 fprintf(stdout, "\n\n");
325 } 240 }
326 241
@@ -328,22 +243,22 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
328 parent_pattern == default_parent_pattern) { 243 parent_pattern == default_parent_pattern) {
329 fprintf(stdout, "#\n# (%s)\n#\n", help); 244 fprintf(stdout, "#\n# (%s)\n#\n", help);
330 245
331 if (rep->show_threads) { 246 if (show_threads) {
332 bool style = !strcmp(rep->pretty_printing_style, "raw"); 247 bool style = !strcmp(pretty_printing_style, "raw");
333 perf_read_values_display(stdout, &rep->show_threads_values, 248 perf_read_values_display(stdout, &show_threads_values,
334 style); 249 style);
335 perf_read_values_destroy(&rep->show_threads_values); 250 perf_read_values_destroy(&show_threads_values);
336 } 251 }
337 } 252 }
338 253
339 return 0; 254 return 0;
340} 255}
341 256
342static int __cmd_report(struct perf_report *rep) 257static int __cmd_report(void)
343{ 258{
344 int ret = -EINVAL; 259 int ret = -EINVAL;
345 u64 nr_samples; 260 u64 nr_samples;
346 struct perf_session *session = rep->session; 261 struct perf_session *session;
347 struct perf_evsel *pos; 262 struct perf_evsel *pos;
348 struct map *kernel_map; 263 struct map *kernel_map;
349 struct kmap *kernel_kmap; 264 struct kmap *kernel_kmap;
@@ -351,24 +266,24 @@ static int __cmd_report(struct perf_report *rep)
351 266
352 signal(SIGINT, sig_handler); 267 signal(SIGINT, sig_handler);
353 268
354 if (rep->cpu_list) { 269 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
355 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 270 if (session == NULL)
356 rep->cpu_bitmap); 271 return -ENOMEM;
272
273 if (cpu_list) {
274 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
357 if (ret) 275 if (ret)
358 goto out_delete; 276 goto out_delete;
359 } 277 }
360 278
361 if (use_browser <= 0) 279 if (show_threads)
362 perf_session__fprintf_info(session, stdout, rep->show_full_info); 280 perf_read_values_init(&show_threads_values);
363 281
364 if (rep->show_threads) 282 ret = perf_session__setup_sample_type(session);
365 perf_read_values_init(&rep->show_threads_values);
366
367 ret = perf_report__setup_sample_type(rep);
368 if (ret) 283 if (ret)
369 goto out_delete; 284 goto out_delete;
370 285
371 ret = perf_session__process_events(session, &rep->tool); 286 ret = perf_session__process_events(session, &event_ops);
372 if (ret) 287 if (ret)
373 goto out_delete; 288 goto out_delete;
374 289
@@ -378,23 +293,21 @@ static int __cmd_report(struct perf_report *rep)
378 (kernel_map->dso->hit && 293 (kernel_map->dso->hit &&
379 (kernel_kmap->ref_reloc_sym == NULL || 294 (kernel_kmap->ref_reloc_sym == NULL ||
380 kernel_kmap->ref_reloc_sym->addr == 0))) { 295 kernel_kmap->ref_reloc_sym->addr == 0))) {
381 const char *desc = 296 const struct dso *kdso = kernel_map->dso;
382 "As no suitable kallsyms nor vmlinux was found, kernel samples\n"
383 "can't be resolved.";
384
385 if (kernel_map) {
386 const struct dso *kdso = kernel_map->dso;
387 if (!RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION])) {
388 desc = "If some relocation was applied (e.g. "
389 "kexec) symbols may be misresolved.";
390 }
391 }
392 297
393 ui__warning( 298 ui__warning(
394"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n" 299"Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"
395"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n" 300"Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"
396"Samples in kernel modules can't be resolved as well.\n\n", 301"Samples in kernel modules can't be resolved as well.\n\n",
397 desc); 302 RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ?
303"As no suitable kallsyms nor vmlinux was found, kernel samples\n"
304"can't be resolved." :
305"If some relocation was applied (e.g. kexec) symbols may be misresolved.");
306 }
307
308 if (dump_trace) {
309 perf_session__fprintf_nr_events(session, stdout);
310 goto out_delete;
398 } 311 }
399 312
400 if (verbose > 3) 313 if (verbose > 3)
@@ -403,39 +316,24 @@ static int __cmd_report(struct perf_report *rep)
403 if (verbose > 2) 316 if (verbose > 2)
404 perf_session__fprintf_dsos(session, stdout); 317 perf_session__fprintf_dsos(session, stdout);
405 318
406 if (dump_trace) {
407 perf_session__fprintf_nr_events(session, stdout);
408 goto out_delete;
409 }
410
411 nr_samples = 0; 319 nr_samples = 0;
412 list_for_each_entry(pos, &session->evlist->entries, node) { 320 list_for_each_entry(pos, &session->evlist->entries, node) {
413 struct hists *hists = &pos->hists; 321 struct hists *hists = &pos->hists;
414 322
415 if (pos->idx == 0)
416 hists->symbol_filter_str = rep->symbol_filter_str;
417
418 hists__collapse_resort(hists); 323 hists__collapse_resort(hists);
419 hists__output_resort(hists); 324 hists__output_resort(hists);
420 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 325 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
421 } 326 }
422 327
423 if (nr_samples == 0) { 328 if (nr_samples == 0) {
424 ui__error("The %s file has no samples!\n", session->filename); 329 ui__warning("The %s file has no samples!\n", input_name);
425 goto out_delete; 330 goto out_delete;
426 } 331 }
427 332
428 if (use_browser > 0) { 333 if (use_browser > 0)
429 if (use_browser == 1) { 334 perf_evlist__tui_browse_hists(session->evlist, help);
430 perf_evlist__tui_browse_hists(session->evlist, help, 335 else
431 NULL, 336 perf_evlist__tty_browse_hists(session->evlist, help);
432 &session->header.env);
433 } else if (use_browser == 2) {
434 perf_evlist__gtk_browse_hists(session->evlist, help,
435 NULL);
436 }
437 } else
438 perf_evlist__tty_browse_hists(session->evlist, rep, help);
439 337
440out_delete: 338out_delete:
441 /* 339 /*
@@ -454,9 +352,9 @@ out_delete:
454} 352}
455 353
456static int 354static int
457parse_callchain_opt(const struct option *opt, const char *arg, int unset) 355parse_callchain_opt(const struct option *opt __used, const char *arg,
356 int unset)
458{ 357{
459 struct perf_report *rep = (struct perf_report *)opt->value;
460 char *tok, *tok2; 358 char *tok, *tok2;
461 char *endptr; 359 char *endptr;
462 360
@@ -464,7 +362,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
464 * --no-call-graph 362 * --no-call-graph
465 */ 363 */
466 if (unset) { 364 if (unset) {
467 rep->dont_use_callchains = true; 365 dont_use_callchains = true;
468 return 0; 366 return 0;
469 } 367 }
470 368
@@ -512,7 +410,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
512 goto setup; 410 goto setup;
513 411
514 if (tok2[0] != 'c') { 412 if (tok2[0] != 'c') {
515 callchain_param.print_limit = strtoul(tok2, &endptr, 0); 413 callchain_param.print_limit = strtod(tok2, &endptr);
516 tok2 = strtok(NULL, ","); 414 tok2 = strtok(NULL, ",");
517 if (!tok2) 415 if (!tok2)
518 goto setup; 416 goto setup;
@@ -533,44 +431,12 @@ setup:
533 return 0; 431 return 0;
534} 432}
535 433
536static int 434static const char * const report_usage[] = {
537parse_branch_mode(const struct option *opt __maybe_unused, 435 "perf report [<options>] <command>",
538 const char *str __maybe_unused, int unset) 436 NULL
539{ 437};
540 sort__branch_mode = !unset;
541 return 0;
542}
543 438
544int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) 439static const struct option options[] = {
545{
546 struct perf_session *session;
547 struct stat st;
548 bool has_br_stack = false;
549 int ret = -1;
550 char callchain_default_opt[] = "fractal,0.5,callee";
551 const char * const report_usage[] = {
552 "perf report [<options>]",
553 NULL
554 };
555 struct perf_report report = {
556 .tool = {
557 .sample = process_sample_event,
558 .mmap = perf_event__process_mmap,
559 .comm = perf_event__process_comm,
560 .exit = perf_event__process_exit,
561 .fork = perf_event__process_fork,
562 .lost = perf_event__process_lost,
563 .read = process_read_event,
564 .attr = perf_event__process_attr,
565 .event_type = perf_event__process_event_type,
566 .tracing_data = perf_event__process_tracing_data,
567 .build_id = perf_event__process_build_id,
568 .ordered_samples = true,
569 .ordering_requires_timestamps = true,
570 },
571 .pretty_printing_style = "normal",
572 };
573 const struct option options[] = {
574 OPT_STRING('i', "input", &input_name, "file", 440 OPT_STRING('i', "input", &input_name, "file",
575 "input file name"), 441 "input file name"),
576 OPT_INCR('v', "verbose", &verbose, 442 OPT_INCR('v', "verbose", &verbose,
@@ -581,130 +447,73 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
581 "file", "vmlinux pathname"), 447 "file", "vmlinux pathname"),
582 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 448 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
583 "file", "kallsyms pathname"), 449 "file", "kallsyms pathname"),
584 OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"), 450 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
585 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 451 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
586 "load module symbols - WARNING: use only with -k and LIVE kernel"), 452 "load module symbols - WARNING: use only with -k and LIVE kernel"),
587 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 453 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
588 "Show a column with the number of samples"), 454 "Show a column with the number of samples"),
589 OPT_BOOLEAN('T', "threads", &report.show_threads, 455 OPT_BOOLEAN('T', "threads", &show_threads,
590 "Show per-thread event counters"), 456 "Show per-thread event counters"),
591 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key", 457 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
592 "pretty printing style key: normal raw"), 458 "pretty printing style key: normal raw"),
593 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"), 459 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
594 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), 460 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
595 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
596 "Use the stdio interface"),
597 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 461 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
598 "sort by key(s): pid, comm, dso, symbol, parent, dso_to," 462 "sort by key(s): pid, comm, dso, symbol, parent"),
599 " dso_from, symbol_to, symbol_from, mispredict"),
600 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 463 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
601 "Show sample percentage for different cpu modes"), 464 "Show sample percentage for different cpu modes"),
602 OPT_STRING('p', "parent", &parent_pattern, "regex", 465 OPT_STRING('p', "parent", &parent_pattern, "regex",
603 "regex filter to identify parent, see: '--sort parent'"), 466 "regex filter to identify parent, see: '--sort parent'"),
604 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 467 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
605 "Only display entries with parent-match"), 468 "Only display entries with parent-match"),
606 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 469 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order",
607 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. " 470 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
608 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), 471 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
609 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 472 OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"),
610 "alias for inverted call graph"),
611 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 473 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
612 "only consider symbols in these dsos"), 474 "only consider symbols in these dsos"),
613 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 475 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
614 "only consider symbols in these comms"), 476 "only consider symbols in these comms"),
615 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 477 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
616 "only consider these symbols"), 478 "only consider these symbols"),
617 OPT_STRING(0, "symbol-filter", &report.symbol_filter_str, "filter",
618 "only show symbols that (partially) match with this filter"),
619 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, 479 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
620 "width[,width...]", 480 "width[,width...]",
621 "don't try to adjust column width, use these fixed values"), 481 "don't try to adjust column width, use these fixed values"),
622 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 482 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
623 "separator for columns, no spaces will be added between " 483 "separator for columns, no spaces will be added between "
624 "columns '.' is reserved."), 484 "columns '.' is reserved."),
625 OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved, 485 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
626 "Only display entries resolved to a symbol"), 486 "Only display entries resolved to a symbol"),
627 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 487 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
628 "Look for files with symbols relative to this directory"), 488 "Look for files with symbols relative to this directory"),
629 OPT_STRING('C', "cpu", &report.cpu_list, "cpu", 489 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
630 "list of cpus to profile"),
631 OPT_BOOLEAN('I', "show-info", &report.show_full_info,
632 "Display extended information about perf.data file"),
633 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
634 "Interleave source code with assembly code (default)"),
635 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
636 "Display raw encoding of assembly instructions (default)"),
637 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
638 "Specify disassembler style (e.g. -M intel for intel syntax)"),
639 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
640 "Show a column with the sum of periods"),
641 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
642 "use branch records for histogram filling", parse_branch_mode),
643 OPT_STRING(0, "objdump", &objdump_path, "path",
644 "objdump binary to use for disassembly and annotations"),
645 OPT_END() 490 OPT_END()
646 }; 491};
647 492
493int cmd_report(int argc, const char **argv, const char *prefix __used)
494{
648 argc = parse_options(argc, argv, options, report_usage, 0); 495 argc = parse_options(argc, argv, options, report_usage, 0);
649 496
650 if (report.use_stdio) 497 if (use_stdio)
651 use_browser = 0; 498 use_browser = 0;
652 else if (report.use_tui) 499 else if (use_tui)
653 use_browser = 1; 500 use_browser = 1;
654 else if (report.use_gtk)
655 use_browser = 2;
656 501
657 if (report.inverted_callchain) 502 if (inverted_callchain)
658 callchain_param.order = ORDER_CALLER; 503 callchain_param.order = ORDER_CALLER;
659 504
660 if (!input_name || !strlen(input_name)) {
661 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
662 input_name = "-";
663 else
664 input_name = "perf.data";
665 }
666 session = perf_session__new(input_name, O_RDONLY,
667 report.force, false, &report.tool);
668 if (session == NULL)
669 return -ENOMEM;
670
671 report.session = session;
672
673 has_br_stack = perf_header__has_feat(&session->header,
674 HEADER_BRANCH_STACK);
675
676 if (sort__branch_mode == -1 && has_br_stack)
677 sort__branch_mode = 1;
678
679 /* sort__branch_mode could be 0 if --no-branch-stack */
680 if (sort__branch_mode == 1) {
681 /*
682 * if no sort_order is provided, then specify
683 * branch-mode specific order
684 */
685 if (sort_order == default_sort_order)
686 sort_order = "comm,dso_from,symbol_from,"
687 "dso_to,symbol_to";
688
689 }
690
691 if (strcmp(input_name, "-") != 0) 505 if (strcmp(input_name, "-") != 0)
692 setup_browser(true); 506 setup_browser(true);
693 else { 507 else
694 use_browser = 0; 508 use_browser = 0;
695 perf_hpp__init();
696 }
697
698 setup_sorting(report_usage, options);
699
700 /* 509 /*
701 * Only in the newt browser we are doing integrated annotation, 510 * Only in the newt browser we are doing integrated annotation,
702 * so don't allocate extra space that won't be used in the stdio 511 * so don't allocate extra space that won't be used in the stdio
703 * implementation. 512 * implementation.
704 */ 513 */
705 if (use_browser == 1 && sort__has_sym) { 514 if (use_browser > 0) {
706 symbol_conf.priv_size = sizeof(struct annotation); 515 symbol_conf.priv_size = sizeof(struct annotation);
707 report.annotate_init = symbol__annotate_init; 516 annotate_init = symbol__annotate_init;
708 /* 517 /*
709 * For searching by name on the "Browse map details". 518 * For searching by name on the "Browse map details".
710 * providing it only in verbose mode not to bloat too 519 * providing it only in verbose mode not to bloat too
@@ -723,11 +532,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
723 } 532 }
724 533
725 if (symbol__init() < 0) 534 if (symbol__init() < 0)
726 goto error; 535 return -1;
536
537 setup_sorting(report_usage, options);
727 538
728 if (parent_pattern != default_parent_pattern) { 539 if (parent_pattern != default_parent_pattern) {
729 if (sort_dimension__add("parent") < 0) 540 if (sort_dimension__add("parent") < 0)
730 goto error; 541 return -1;
731 542
732 /* 543 /*
733 * Only show the parent fields if we explicitly 544 * Only show the parent fields if we explicitly
@@ -739,31 +550,15 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
739 } else 550 } else
740 symbol_conf.exclude_other = false; 551 symbol_conf.exclude_other = false;
741 552
742 if (argc) { 553 /*
743 /* 554 * Any (unrecognized) arguments left?
744 * Special case: if there's an argument left then assume that 555 */
745 * it's a symbol filter: 556 if (argc)
746 */ 557 usage_with_options(report_usage, options);
747 if (argc > 1)
748 usage_with_options(report_usage, options);
749
750 report.symbol_filter_str = argv[0];
751 }
752 558
559 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
753 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 560 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
561 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
754 562
755 if (sort__branch_mode == 1) { 563 return __cmd_report();
756 sort_entry__setup_elide(&sort_dso_from, symbol_conf.dso_from_list, "dso_from", stdout);
757 sort_entry__setup_elide(&sort_dso_to, symbol_conf.dso_to_list, "dso_to", stdout);
758 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
759 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
760 } else {
761 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
762 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
763 }
764
765 ret = __cmd_report(&report);
766error:
767 perf_session__delete(session);
768 return ret;
769} 564}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index cc28b85dabd..5177964943e 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -2,14 +2,11 @@
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/util.h" 4#include "util/util.h"
5#include "util/evlist.h"
6#include "util/cache.h" 5#include "util/cache.h"
7#include "util/evsel.h"
8#include "util/symbol.h" 6#include "util/symbol.h"
9#include "util/thread.h" 7#include "util/thread.h"
10#include "util/header.h" 8#include "util/header.h"
11#include "util/session.h" 9#include "util/session.h"
12#include "util/tool.h"
13 10
14#include "util/parse-options.h" 11#include "util/parse-options.h"
15#include "util/trace-event.h" 12#include "util/trace-event.h"
@@ -17,18 +14,31 @@
17#include "util/debug.h" 14#include "util/debug.h"
18 15
19#include <sys/prctl.h> 16#include <sys/prctl.h>
20#include <sys/resource.h>
21 17
22#include <semaphore.h> 18#include <semaphore.h>
23#include <pthread.h> 19#include <pthread.h>
24#include <math.h> 20#include <math.h>
25 21
22static char const *input_name = "perf.data";
23
24static char default_sort_order[] = "avg, max, switch, runtime";
25static const char *sort_order = default_sort_order;
26
27static int profile_cpu = -1;
28
26#define PR_SET_NAME 15 /* Set process name */ 29#define PR_SET_NAME 15 /* Set process name */
27#define MAX_CPUS 4096 30#define MAX_CPUS 4096
31
32static u64 run_measurement_overhead;
33static u64 sleep_measurement_overhead;
34
28#define COMM_LEN 20 35#define COMM_LEN 20
29#define SYM_LEN 129 36#define SYM_LEN 129
37
30#define MAX_PID 65536 38#define MAX_PID 65536
31 39
40static unsigned long nr_tasks;
41
32struct sched_atom; 42struct sched_atom;
33 43
34struct task_desc { 44struct task_desc {
@@ -66,6 +76,44 @@ struct sched_atom {
66 struct task_desc *wakee; 76 struct task_desc *wakee;
67}; 77};
68 78
79static struct task_desc *pid_to_task[MAX_PID];
80
81static struct task_desc **tasks;
82
83static pthread_mutex_t start_work_mutex = PTHREAD_MUTEX_INITIALIZER;
84static u64 start_time;
85
86static pthread_mutex_t work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
87
88static unsigned long nr_run_events;
89static unsigned long nr_sleep_events;
90static unsigned long nr_wakeup_events;
91
92static unsigned long nr_sleep_corrections;
93static unsigned long nr_run_events_optimized;
94
95static unsigned long targetless_wakeups;
96static unsigned long multitarget_wakeups;
97
98static u64 cpu_usage;
99static u64 runavg_cpu_usage;
100static u64 parent_cpu_usage;
101static u64 runavg_parent_cpu_usage;
102
103static unsigned long nr_runs;
104static u64 sum_runtime;
105static u64 sum_fluct;
106static u64 run_avg;
107
108static unsigned int replay_repeat = 10;
109static unsigned long nr_timestamps;
110static unsigned long nr_unordered_timestamps;
111static unsigned long nr_state_machine_bugs;
112static unsigned long nr_context_switch_bugs;
113static unsigned long nr_events;
114static unsigned long nr_lost_chunks;
115static unsigned long nr_lost_events;
116
69#define TASK_STATE_TO_CHAR_STR "RSDTtZX" 117#define TASK_STATE_TO_CHAR_STR "RSDTtZX"
70 118
71enum thread_state { 119enum thread_state {
@@ -97,78 +145,11 @@ struct work_atoms {
97 145
98typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *); 146typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *);
99 147
100struct perf_sched; 148static struct rb_root atom_root, sorted_atom_root;
101 149
102struct trace_sched_handler { 150static u64 all_runtime;
103 int (*switch_event)(struct perf_sched *sched, struct perf_evsel *evsel, 151static u64 all_count;
104 struct perf_sample *sample, struct machine *machine);
105
106 int (*runtime_event)(struct perf_sched *sched, struct perf_evsel *evsel,
107 struct perf_sample *sample, struct machine *machine);
108
109 int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel,
110 struct perf_sample *sample, struct machine *machine);
111
112 int (*fork_event)(struct perf_sched *sched, struct perf_evsel *evsel,
113 struct perf_sample *sample);
114 152
115 int (*migrate_task_event)(struct perf_sched *sched,
116 struct perf_evsel *evsel,
117 struct perf_sample *sample,
118 struct machine *machine);
119};
120
121struct perf_sched {
122 struct perf_tool tool;
123 const char *sort_order;
124 unsigned long nr_tasks;
125 struct task_desc *pid_to_task[MAX_PID];
126 struct task_desc **tasks;
127 const struct trace_sched_handler *tp_handler;
128 pthread_mutex_t start_work_mutex;
129 pthread_mutex_t work_done_wait_mutex;
130 int profile_cpu;
131/*
132 * Track the current task - that way we can know whether there's any
133 * weird events, such as a task being switched away that is not current.
134 */
135 int max_cpu;
136 u32 curr_pid[MAX_CPUS];
137 struct thread *curr_thread[MAX_CPUS];
138 char next_shortname1;
139 char next_shortname2;
140 unsigned int replay_repeat;
141 unsigned long nr_run_events;
142 unsigned long nr_sleep_events;
143 unsigned long nr_wakeup_events;
144 unsigned long nr_sleep_corrections;
145 unsigned long nr_run_events_optimized;
146 unsigned long targetless_wakeups;
147 unsigned long multitarget_wakeups;
148 unsigned long nr_runs;
149 unsigned long nr_timestamps;
150 unsigned long nr_unordered_timestamps;
151 unsigned long nr_state_machine_bugs;
152 unsigned long nr_context_switch_bugs;
153 unsigned long nr_events;
154 unsigned long nr_lost_chunks;
155 unsigned long nr_lost_events;
156 u64 run_measurement_overhead;
157 u64 sleep_measurement_overhead;
158 u64 start_time;
159 u64 cpu_usage;
160 u64 runavg_cpu_usage;
161 u64 parent_cpu_usage;
162 u64 runavg_parent_cpu_usage;
163 u64 sum_runtime;
164 u64 sum_fluct;
165 u64 run_avg;
166 u64 all_runtime;
167 u64 all_count;
168 u64 cpu_last_switched[MAX_CPUS];
169 struct rb_root atom_root, sorted_atom_root;
170 struct list_head sort_list, cmp_pid;
171};
172 153
173static u64 get_nsecs(void) 154static u64 get_nsecs(void)
174{ 155{
@@ -179,13 +160,13 @@ static u64 get_nsecs(void)
179 return ts.tv_sec * 1000000000ULL + ts.tv_nsec; 160 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
180} 161}
181 162
182static void burn_nsecs(struct perf_sched *sched, u64 nsecs) 163static void burn_nsecs(u64 nsecs)
183{ 164{
184 u64 T0 = get_nsecs(), T1; 165 u64 T0 = get_nsecs(), T1;
185 166
186 do { 167 do {
187 T1 = get_nsecs(); 168 T1 = get_nsecs();
188 } while (T1 + sched->run_measurement_overhead < T0 + nsecs); 169 } while (T1 + run_measurement_overhead < T0 + nsecs);
189} 170}
190 171
191static void sleep_nsecs(u64 nsecs) 172static void sleep_nsecs(u64 nsecs)
@@ -198,24 +179,24 @@ static void sleep_nsecs(u64 nsecs)
198 nanosleep(&ts, NULL); 179 nanosleep(&ts, NULL);
199} 180}
200 181
201static void calibrate_run_measurement_overhead(struct perf_sched *sched) 182static void calibrate_run_measurement_overhead(void)
202{ 183{
203 u64 T0, T1, delta, min_delta = 1000000000ULL; 184 u64 T0, T1, delta, min_delta = 1000000000ULL;
204 int i; 185 int i;
205 186
206 for (i = 0; i < 10; i++) { 187 for (i = 0; i < 10; i++) {
207 T0 = get_nsecs(); 188 T0 = get_nsecs();
208 burn_nsecs(sched, 0); 189 burn_nsecs(0);
209 T1 = get_nsecs(); 190 T1 = get_nsecs();
210 delta = T1-T0; 191 delta = T1-T0;
211 min_delta = min(min_delta, delta); 192 min_delta = min(min_delta, delta);
212 } 193 }
213 sched->run_measurement_overhead = min_delta; 194 run_measurement_overhead = min_delta;
214 195
215 printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta); 196 printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
216} 197}
217 198
218static void calibrate_sleep_measurement_overhead(struct perf_sched *sched) 199static void calibrate_sleep_measurement_overhead(void)
219{ 200{
220 u64 T0, T1, delta, min_delta = 1000000000ULL; 201 u64 T0, T1, delta, min_delta = 1000000000ULL;
221 int i; 202 int i;
@@ -228,7 +209,7 @@ static void calibrate_sleep_measurement_overhead(struct perf_sched *sched)
228 min_delta = min(min_delta, delta); 209 min_delta = min(min_delta, delta);
229 } 210 }
230 min_delta -= 10000; 211 min_delta -= 10000;
231 sched->sleep_measurement_overhead = min_delta; 212 sleep_measurement_overhead = min_delta;
232 213
233 printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta); 214 printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
234} 215}
@@ -261,8 +242,8 @@ static struct sched_atom *last_event(struct task_desc *task)
261 return task->atoms[task->nr_events - 1]; 242 return task->atoms[task->nr_events - 1];
262} 243}
263 244
264static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task, 245static void
265 u64 timestamp, u64 duration) 246add_sched_event_run(struct task_desc *task, u64 timestamp, u64 duration)
266{ 247{
267 struct sched_atom *event, *curr_event = last_event(task); 248 struct sched_atom *event, *curr_event = last_event(task);
268 249
@@ -271,7 +252,7 @@ static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task
271 * to it: 252 * to it:
272 */ 253 */
273 if (curr_event && curr_event->type == SCHED_EVENT_RUN) { 254 if (curr_event && curr_event->type == SCHED_EVENT_RUN) {
274 sched->nr_run_events_optimized++; 255 nr_run_events_optimized++;
275 curr_event->duration += duration; 256 curr_event->duration += duration;
276 return; 257 return;
277 } 258 }
@@ -281,11 +262,12 @@ static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task
281 event->type = SCHED_EVENT_RUN; 262 event->type = SCHED_EVENT_RUN;
282 event->duration = duration; 263 event->duration = duration;
283 264
284 sched->nr_run_events++; 265 nr_run_events++;
285} 266}
286 267
287static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *task, 268static void
288 u64 timestamp, struct task_desc *wakee) 269add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
270 struct task_desc *wakee)
289{ 271{
290 struct sched_atom *event, *wakee_event; 272 struct sched_atom *event, *wakee_event;
291 273
@@ -295,11 +277,11 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
295 277
296 wakee_event = last_event(wakee); 278 wakee_event = last_event(wakee);
297 if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) { 279 if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) {
298 sched->targetless_wakeups++; 280 targetless_wakeups++;
299 return; 281 return;
300 } 282 }
301 if (wakee_event->wait_sem) { 283 if (wakee_event->wait_sem) {
302 sched->multitarget_wakeups++; 284 multitarget_wakeups++;
303 return; 285 return;
304 } 286 }
305 287
@@ -308,89 +290,89 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
308 wakee_event->specific_wait = 1; 290 wakee_event->specific_wait = 1;
309 event->wait_sem = wakee_event->wait_sem; 291 event->wait_sem = wakee_event->wait_sem;
310 292
311 sched->nr_wakeup_events++; 293 nr_wakeup_events++;
312} 294}
313 295
314static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *task, 296static void
315 u64 timestamp, u64 task_state __maybe_unused) 297add_sched_event_sleep(struct task_desc *task, u64 timestamp,
298 u64 task_state __used)
316{ 299{
317 struct sched_atom *event = get_new_event(task, timestamp); 300 struct sched_atom *event = get_new_event(task, timestamp);
318 301
319 event->type = SCHED_EVENT_SLEEP; 302 event->type = SCHED_EVENT_SLEEP;
320 303
321 sched->nr_sleep_events++; 304 nr_sleep_events++;
322} 305}
323 306
324static struct task_desc *register_pid(struct perf_sched *sched, 307static struct task_desc *register_pid(unsigned long pid, const char *comm)
325 unsigned long pid, const char *comm)
326{ 308{
327 struct task_desc *task; 309 struct task_desc *task;
328 310
329 BUG_ON(pid >= MAX_PID); 311 BUG_ON(pid >= MAX_PID);
330 312
331 task = sched->pid_to_task[pid]; 313 task = pid_to_task[pid];
332 314
333 if (task) 315 if (task)
334 return task; 316 return task;
335 317
336 task = zalloc(sizeof(*task)); 318 task = zalloc(sizeof(*task));
337 task->pid = pid; 319 task->pid = pid;
338 task->nr = sched->nr_tasks; 320 task->nr = nr_tasks;
339 strcpy(task->comm, comm); 321 strcpy(task->comm, comm);
340 /* 322 /*
341 * every task starts in sleeping state - this gets ignored 323 * every task starts in sleeping state - this gets ignored
342 * if there's no wakeup pointing to this sleep state: 324 * if there's no wakeup pointing to this sleep state:
343 */ 325 */
344 add_sched_event_sleep(sched, task, 0, 0); 326 add_sched_event_sleep(task, 0, 0);
345 327
346 sched->pid_to_task[pid] = task; 328 pid_to_task[pid] = task;
347 sched->nr_tasks++; 329 nr_tasks++;
348 sched->tasks = realloc(sched->tasks, sched->nr_tasks * sizeof(struct task_task *)); 330 tasks = realloc(tasks, nr_tasks*sizeof(struct task_task *));
349 BUG_ON(!sched->tasks); 331 BUG_ON(!tasks);
350 sched->tasks[task->nr] = task; 332 tasks[task->nr] = task;
351 333
352 if (verbose) 334 if (verbose)
353 printf("registered task #%ld, PID %ld (%s)\n", sched->nr_tasks, pid, comm); 335 printf("registered task #%ld, PID %ld (%s)\n", nr_tasks, pid, comm);
354 336
355 return task; 337 return task;
356} 338}
357 339
358 340
359static void print_task_traces(struct perf_sched *sched) 341static void print_task_traces(void)
360{ 342{
361 struct task_desc *task; 343 struct task_desc *task;
362 unsigned long i; 344 unsigned long i;
363 345
364 for (i = 0; i < sched->nr_tasks; i++) { 346 for (i = 0; i < nr_tasks; i++) {
365 task = sched->tasks[i]; 347 task = tasks[i];
366 printf("task %6ld (%20s:%10ld), nr_events: %ld\n", 348 printf("task %6ld (%20s:%10ld), nr_events: %ld\n",
367 task->nr, task->comm, task->pid, task->nr_events); 349 task->nr, task->comm, task->pid, task->nr_events);
368 } 350 }
369} 351}
370 352
371static void add_cross_task_wakeups(struct perf_sched *sched) 353static void add_cross_task_wakeups(void)
372{ 354{
373 struct task_desc *task1, *task2; 355 struct task_desc *task1, *task2;
374 unsigned long i, j; 356 unsigned long i, j;
375 357
376 for (i = 0; i < sched->nr_tasks; i++) { 358 for (i = 0; i < nr_tasks; i++) {
377 task1 = sched->tasks[i]; 359 task1 = tasks[i];
378 j = i + 1; 360 j = i + 1;
379 if (j == sched->nr_tasks) 361 if (j == nr_tasks)
380 j = 0; 362 j = 0;
381 task2 = sched->tasks[j]; 363 task2 = tasks[j];
382 add_sched_event_wakeup(sched, task1, 0, task2); 364 add_sched_event_wakeup(task1, 0, task2);
383 } 365 }
384} 366}
385 367
386static void perf_sched__process_event(struct perf_sched *sched, 368static void
387 struct sched_atom *atom) 369process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
388{ 370{
389 int ret = 0; 371 int ret = 0;
390 372
391 switch (atom->type) { 373 switch (atom->type) {
392 case SCHED_EVENT_RUN: 374 case SCHED_EVENT_RUN:
393 burn_nsecs(sched, atom->duration); 375 burn_nsecs(atom->duration);
394 break; 376 break;
395 case SCHED_EVENT_SLEEP: 377 case SCHED_EVENT_SLEEP:
396 if (atom->wait_sem) 378 if (atom->wait_sem)
@@ -437,8 +419,8 @@ static int self_open_counters(void)
437 fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 419 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
438 420
439 if (fd < 0) 421 if (fd < 0)
440 pr_err("Error: sys_perf_event_open() syscall returned " 422 die("Error: sys_perf_event_open() syscall returned"
441 "with %d (%s)\n", fd, strerror(errno)); 423 "with %d (%s)\n", fd, strerror(errno));
442 return fd; 424 return fd;
443} 425}
444 426
@@ -453,41 +435,31 @@ static u64 get_cpu_usage_nsec_self(int fd)
453 return runtime; 435 return runtime;
454} 436}
455 437
456struct sched_thread_parms {
457 struct task_desc *task;
458 struct perf_sched *sched;
459};
460
461static void *thread_func(void *ctx) 438static void *thread_func(void *ctx)
462{ 439{
463 struct sched_thread_parms *parms = ctx; 440 struct task_desc *this_task = ctx;
464 struct task_desc *this_task = parms->task;
465 struct perf_sched *sched = parms->sched;
466 u64 cpu_usage_0, cpu_usage_1; 441 u64 cpu_usage_0, cpu_usage_1;
467 unsigned long i, ret; 442 unsigned long i, ret;
468 char comm2[22]; 443 char comm2[22];
469 int fd; 444 int fd;
470 445
471 free(parms);
472
473 sprintf(comm2, ":%s", this_task->comm); 446 sprintf(comm2, ":%s", this_task->comm);
474 prctl(PR_SET_NAME, comm2); 447 prctl(PR_SET_NAME, comm2);
475 fd = self_open_counters(); 448 fd = self_open_counters();
476 if (fd < 0) 449
477 return NULL;
478again: 450again:
479 ret = sem_post(&this_task->ready_for_work); 451 ret = sem_post(&this_task->ready_for_work);
480 BUG_ON(ret); 452 BUG_ON(ret);
481 ret = pthread_mutex_lock(&sched->start_work_mutex); 453 ret = pthread_mutex_lock(&start_work_mutex);
482 BUG_ON(ret); 454 BUG_ON(ret);
483 ret = pthread_mutex_unlock(&sched->start_work_mutex); 455 ret = pthread_mutex_unlock(&start_work_mutex);
484 BUG_ON(ret); 456 BUG_ON(ret);
485 457
486 cpu_usage_0 = get_cpu_usage_nsec_self(fd); 458 cpu_usage_0 = get_cpu_usage_nsec_self(fd);
487 459
488 for (i = 0; i < this_task->nr_events; i++) { 460 for (i = 0; i < this_task->nr_events; i++) {
489 this_task->curr_event = i; 461 this_task->curr_event = i;
490 perf_sched__process_event(sched, this_task->atoms[i]); 462 process_sched_event(this_task, this_task->atoms[i]);
491 } 463 }
492 464
493 cpu_usage_1 = get_cpu_usage_nsec_self(fd); 465 cpu_usage_1 = get_cpu_usage_nsec_self(fd);
@@ -495,15 +467,15 @@ again:
495 ret = sem_post(&this_task->work_done_sem); 467 ret = sem_post(&this_task->work_done_sem);
496 BUG_ON(ret); 468 BUG_ON(ret);
497 469
498 ret = pthread_mutex_lock(&sched->work_done_wait_mutex); 470 ret = pthread_mutex_lock(&work_done_wait_mutex);
499 BUG_ON(ret); 471 BUG_ON(ret);
500 ret = pthread_mutex_unlock(&sched->work_done_wait_mutex); 472 ret = pthread_mutex_unlock(&work_done_wait_mutex);
501 BUG_ON(ret); 473 BUG_ON(ret);
502 474
503 goto again; 475 goto again;
504} 476}
505 477
506static void create_tasks(struct perf_sched *sched) 478static void create_tasks(void)
507{ 479{
508 struct task_desc *task; 480 struct task_desc *task;
509 pthread_attr_t attr; 481 pthread_attr_t attr;
@@ -515,129 +487,128 @@ static void create_tasks(struct perf_sched *sched)
515 err = pthread_attr_setstacksize(&attr, 487 err = pthread_attr_setstacksize(&attr,
516 (size_t) max(16 * 1024, PTHREAD_STACK_MIN)); 488 (size_t) max(16 * 1024, PTHREAD_STACK_MIN));
517 BUG_ON(err); 489 BUG_ON(err);
518 err = pthread_mutex_lock(&sched->start_work_mutex); 490 err = pthread_mutex_lock(&start_work_mutex);
519 BUG_ON(err); 491 BUG_ON(err);
520 err = pthread_mutex_lock(&sched->work_done_wait_mutex); 492 err = pthread_mutex_lock(&work_done_wait_mutex);
521 BUG_ON(err); 493 BUG_ON(err);
522 for (i = 0; i < sched->nr_tasks; i++) { 494 for (i = 0; i < nr_tasks; i++) {
523 struct sched_thread_parms *parms = malloc(sizeof(*parms)); 495 task = tasks[i];
524 BUG_ON(parms == NULL);
525 parms->task = task = sched->tasks[i];
526 parms->sched = sched;
527 sem_init(&task->sleep_sem, 0, 0); 496 sem_init(&task->sleep_sem, 0, 0);
528 sem_init(&task->ready_for_work, 0, 0); 497 sem_init(&task->ready_for_work, 0, 0);
529 sem_init(&task->work_done_sem, 0, 0); 498 sem_init(&task->work_done_sem, 0, 0);
530 task->curr_event = 0; 499 task->curr_event = 0;
531 err = pthread_create(&task->thread, &attr, thread_func, parms); 500 err = pthread_create(&task->thread, &attr, thread_func, task);
532 BUG_ON(err); 501 BUG_ON(err);
533 } 502 }
534} 503}
535 504
536static void wait_for_tasks(struct perf_sched *sched) 505static void wait_for_tasks(void)
537{ 506{
538 u64 cpu_usage_0, cpu_usage_1; 507 u64 cpu_usage_0, cpu_usage_1;
539 struct task_desc *task; 508 struct task_desc *task;
540 unsigned long i, ret; 509 unsigned long i, ret;
541 510
542 sched->start_time = get_nsecs(); 511 start_time = get_nsecs();
543 sched->cpu_usage = 0; 512 cpu_usage = 0;
544 pthread_mutex_unlock(&sched->work_done_wait_mutex); 513 pthread_mutex_unlock(&work_done_wait_mutex);
545 514
546 for (i = 0; i < sched->nr_tasks; i++) { 515 for (i = 0; i < nr_tasks; i++) {
547 task = sched->tasks[i]; 516 task = tasks[i];
548 ret = sem_wait(&task->ready_for_work); 517 ret = sem_wait(&task->ready_for_work);
549 BUG_ON(ret); 518 BUG_ON(ret);
550 sem_init(&task->ready_for_work, 0, 0); 519 sem_init(&task->ready_for_work, 0, 0);
551 } 520 }
552 ret = pthread_mutex_lock(&sched->work_done_wait_mutex); 521 ret = pthread_mutex_lock(&work_done_wait_mutex);
553 BUG_ON(ret); 522 BUG_ON(ret);
554 523
555 cpu_usage_0 = get_cpu_usage_nsec_parent(); 524 cpu_usage_0 = get_cpu_usage_nsec_parent();
556 525
557 pthread_mutex_unlock(&sched->start_work_mutex); 526 pthread_mutex_unlock(&start_work_mutex);
558 527
559 for (i = 0; i < sched->nr_tasks; i++) { 528 for (i = 0; i < nr_tasks; i++) {
560 task = sched->tasks[i]; 529 task = tasks[i];
561 ret = sem_wait(&task->work_done_sem); 530 ret = sem_wait(&task->work_done_sem);
562 BUG_ON(ret); 531 BUG_ON(ret);
563 sem_init(&task->work_done_sem, 0, 0); 532 sem_init(&task->work_done_sem, 0, 0);
564 sched->cpu_usage += task->cpu_usage; 533 cpu_usage += task->cpu_usage;
565 task->cpu_usage = 0; 534 task->cpu_usage = 0;
566 } 535 }
567 536
568 cpu_usage_1 = get_cpu_usage_nsec_parent(); 537 cpu_usage_1 = get_cpu_usage_nsec_parent();
569 if (!sched->runavg_cpu_usage) 538 if (!runavg_cpu_usage)
570 sched->runavg_cpu_usage = sched->cpu_usage; 539 runavg_cpu_usage = cpu_usage;
571 sched->runavg_cpu_usage = (sched->runavg_cpu_usage * 9 + sched->cpu_usage) / 10; 540 runavg_cpu_usage = (runavg_cpu_usage*9 + cpu_usage)/10;
572 541
573 sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0; 542 parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
574 if (!sched->runavg_parent_cpu_usage) 543 if (!runavg_parent_cpu_usage)
575 sched->runavg_parent_cpu_usage = sched->parent_cpu_usage; 544 runavg_parent_cpu_usage = parent_cpu_usage;
576 sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * 9 + 545 runavg_parent_cpu_usage = (runavg_parent_cpu_usage*9 +
577 sched->parent_cpu_usage)/10; 546 parent_cpu_usage)/10;
578 547
579 ret = pthread_mutex_lock(&sched->start_work_mutex); 548 ret = pthread_mutex_lock(&start_work_mutex);
580 BUG_ON(ret); 549 BUG_ON(ret);
581 550
582 for (i = 0; i < sched->nr_tasks; i++) { 551 for (i = 0; i < nr_tasks; i++) {
583 task = sched->tasks[i]; 552 task = tasks[i];
584 sem_init(&task->sleep_sem, 0, 0); 553 sem_init(&task->sleep_sem, 0, 0);
585 task->curr_event = 0; 554 task->curr_event = 0;
586 } 555 }
587} 556}
588 557
589static void run_one_test(struct perf_sched *sched) 558static void run_one_test(void)
590{ 559{
591 u64 T0, T1, delta, avg_delta, fluct; 560 u64 T0, T1, delta, avg_delta, fluct;
592 561
593 T0 = get_nsecs(); 562 T0 = get_nsecs();
594 wait_for_tasks(sched); 563 wait_for_tasks();
595 T1 = get_nsecs(); 564 T1 = get_nsecs();
596 565
597 delta = T1 - T0; 566 delta = T1 - T0;
598 sched->sum_runtime += delta; 567 sum_runtime += delta;
599 sched->nr_runs++; 568 nr_runs++;
600 569
601 avg_delta = sched->sum_runtime / sched->nr_runs; 570 avg_delta = sum_runtime / nr_runs;
602 if (delta < avg_delta) 571 if (delta < avg_delta)
603 fluct = avg_delta - delta; 572 fluct = avg_delta - delta;
604 else 573 else
605 fluct = delta - avg_delta; 574 fluct = delta - avg_delta;
606 sched->sum_fluct += fluct; 575 sum_fluct += fluct;
607 if (!sched->run_avg) 576 if (!run_avg)
608 sched->run_avg = delta; 577 run_avg = delta;
609 sched->run_avg = (sched->run_avg * 9 + delta) / 10; 578 run_avg = (run_avg*9 + delta)/10;
610 579
611 printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0); 580 printf("#%-3ld: %0.3f, ",
581 nr_runs, (double)delta/1000000.0);
612 582
613 printf("ravg: %0.2f, ", (double)sched->run_avg / 1e6); 583 printf("ravg: %0.2f, ",
584 (double)run_avg/1e6);
614 585
615 printf("cpu: %0.2f / %0.2f", 586 printf("cpu: %0.2f / %0.2f",
616 (double)sched->cpu_usage / 1e6, (double)sched->runavg_cpu_usage / 1e6); 587 (double)cpu_usage/1e6, (double)runavg_cpu_usage/1e6);
617 588
618#if 0 589#if 0
619 /* 590 /*
620 * rusage statistics done by the parent, these are less 591 * rusage statistics done by the parent, these are less
621 * accurate than the sched->sum_exec_runtime based statistics: 592 * accurate than the sum_exec_runtime based statistics:
622 */ 593 */
623 printf(" [%0.2f / %0.2f]", 594 printf(" [%0.2f / %0.2f]",
624 (double)sched->parent_cpu_usage/1e6, 595 (double)parent_cpu_usage/1e6,
625 (double)sched->runavg_parent_cpu_usage/1e6); 596 (double)runavg_parent_cpu_usage/1e6);
626#endif 597#endif
627 598
628 printf("\n"); 599 printf("\n");
629 600
630 if (sched->nr_sleep_corrections) 601 if (nr_sleep_corrections)
631 printf(" (%ld sleep corrections)\n", sched->nr_sleep_corrections); 602 printf(" (%ld sleep corrections)\n", nr_sleep_corrections);
632 sched->nr_sleep_corrections = 0; 603 nr_sleep_corrections = 0;
633} 604}
634 605
635static void test_calibrations(struct perf_sched *sched) 606static void test_calibrations(void)
636{ 607{
637 u64 T0, T1; 608 u64 T0, T1;
638 609
639 T0 = get_nsecs(); 610 T0 = get_nsecs();
640 burn_nsecs(sched, 1e6); 611 burn_nsecs(1e6);
641 T1 = get_nsecs(); 612 T1 = get_nsecs();
642 613
643 printf("the run test took %" PRIu64 " nsecs\n", T1 - T0); 614 printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
@@ -649,99 +620,245 @@ static void test_calibrations(struct perf_sched *sched)
649 printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0); 620 printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
650} 621}
651 622
652static int 623#define FILL_FIELD(ptr, field, event, data) \
653replay_wakeup_event(struct perf_sched *sched, 624 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
654 struct perf_evsel *evsel, struct perf_sample *sample, 625
655 struct machine *machine __maybe_unused) 626#define FILL_ARRAY(ptr, array, event, data) \
627do { \
628 void *__array = raw_field_ptr(event, #array, data); \
629 memcpy(ptr.array, __array, sizeof(ptr.array)); \
630} while(0)
631
632#define FILL_COMMON_FIELDS(ptr, event, data) \
633do { \
634 FILL_FIELD(ptr, common_type, event, data); \
635 FILL_FIELD(ptr, common_flags, event, data); \
636 FILL_FIELD(ptr, common_preempt_count, event, data); \
637 FILL_FIELD(ptr, common_pid, event, data); \
638 FILL_FIELD(ptr, common_tgid, event, data); \
639} while (0)
640
641
642
643struct trace_switch_event {
644 u32 size;
645
646 u16 common_type;
647 u8 common_flags;
648 u8 common_preempt_count;
649 u32 common_pid;
650 u32 common_tgid;
651
652 char prev_comm[16];
653 u32 prev_pid;
654 u32 prev_prio;
655 u64 prev_state;
656 char next_comm[16];
657 u32 next_pid;
658 u32 next_prio;
659};
660
661struct trace_runtime_event {
662 u32 size;
663
664 u16 common_type;
665 u8 common_flags;
666 u8 common_preempt_count;
667 u32 common_pid;
668 u32 common_tgid;
669
670 char comm[16];
671 u32 pid;
672 u64 runtime;
673 u64 vruntime;
674};
675
676struct trace_wakeup_event {
677 u32 size;
678
679 u16 common_type;
680 u8 common_flags;
681 u8 common_preempt_count;
682 u32 common_pid;
683 u32 common_tgid;
684
685 char comm[16];
686 u32 pid;
687
688 u32 prio;
689 u32 success;
690 u32 cpu;
691};
692
693struct trace_fork_event {
694 u32 size;
695
696 u16 common_type;
697 u8 common_flags;
698 u8 common_preempt_count;
699 u32 common_pid;
700 u32 common_tgid;
701
702 char parent_comm[16];
703 u32 parent_pid;
704 char child_comm[16];
705 u32 child_pid;
706};
707
708struct trace_migrate_task_event {
709 u32 size;
710
711 u16 common_type;
712 u8 common_flags;
713 u8 common_preempt_count;
714 u32 common_pid;
715 u32 common_tgid;
716
717 char comm[16];
718 u32 pid;
719
720 u32 prio;
721 u32 cpu;
722};
723
724struct trace_sched_handler {
725 void (*switch_event)(struct trace_switch_event *,
726 struct perf_session *,
727 struct event *,
728 int cpu,
729 u64 timestamp,
730 struct thread *thread);
731
732 void (*runtime_event)(struct trace_runtime_event *,
733 struct perf_session *,
734 struct event *,
735 int cpu,
736 u64 timestamp,
737 struct thread *thread);
738
739 void (*wakeup_event)(struct trace_wakeup_event *,
740 struct perf_session *,
741 struct event *,
742 int cpu,
743 u64 timestamp,
744 struct thread *thread);
745
746 void (*fork_event)(struct trace_fork_event *,
747 struct event *,
748 int cpu,
749 u64 timestamp,
750 struct thread *thread);
751
752 void (*migrate_task_event)(struct trace_migrate_task_event *,
753 struct perf_session *session,
754 struct event *,
755 int cpu,
756 u64 timestamp,
757 struct thread *thread);
758};
759
760
761static void
762replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
763 struct perf_session *session __used,
764 struct event *event,
765 int cpu __used,
766 u64 timestamp __used,
767 struct thread *thread __used)
656{ 768{
657 const char *comm = perf_evsel__strval(evsel, sample, "comm");
658 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
659 struct task_desc *waker, *wakee; 769 struct task_desc *waker, *wakee;
660 770
661 if (verbose) { 771 if (verbose) {
662 printf("sched_wakeup event %p\n", evsel); 772 printf("sched_wakeup event %p\n", event);
663 773
664 printf(" ... pid %d woke up %s/%d\n", sample->tid, comm, pid); 774 printf(" ... pid %d woke up %s/%d\n",
775 wakeup_event->common_pid,
776 wakeup_event->comm,
777 wakeup_event->pid);
665 } 778 }
666 779
667 waker = register_pid(sched, sample->tid, "<unknown>"); 780 waker = register_pid(wakeup_event->common_pid, "<unknown>");
668 wakee = register_pid(sched, pid, comm); 781 wakee = register_pid(wakeup_event->pid, wakeup_event->comm);
669 782
670 add_sched_event_wakeup(sched, waker, sample->time, wakee); 783 add_sched_event_wakeup(waker, timestamp, wakee);
671 return 0;
672} 784}
673 785
674static int replay_switch_event(struct perf_sched *sched, 786static u64 cpu_last_switched[MAX_CPUS];
675 struct perf_evsel *evsel, 787
676 struct perf_sample *sample, 788static void
677 struct machine *machine __maybe_unused) 789replay_switch_event(struct trace_switch_event *switch_event,
790 struct perf_session *session __used,
791 struct event *event,
792 int cpu,
793 u64 timestamp,
794 struct thread *thread __used)
678{ 795{
679 const char *prev_comm = perf_evsel__strval(evsel, sample, "prev_comm"), 796 struct task_desc *prev, __used *next;
680 *next_comm = perf_evsel__strval(evsel, sample, "next_comm"); 797 u64 timestamp0;
681 const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
682 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
683 const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
684 struct task_desc *prev, __maybe_unused *next;
685 u64 timestamp0, timestamp = sample->time;
686 int cpu = sample->cpu;
687 s64 delta; 798 s64 delta;
688 799
689 if (verbose) 800 if (verbose)
690 printf("sched_switch event %p\n", evsel); 801 printf("sched_switch event %p\n", event);
691 802
692 if (cpu >= MAX_CPUS || cpu < 0) 803 if (cpu >= MAX_CPUS || cpu < 0)
693 return 0; 804 return;
694 805
695 timestamp0 = sched->cpu_last_switched[cpu]; 806 timestamp0 = cpu_last_switched[cpu];
696 if (timestamp0) 807 if (timestamp0)
697 delta = timestamp - timestamp0; 808 delta = timestamp - timestamp0;
698 else 809 else
699 delta = 0; 810 delta = 0;
700 811
701 if (delta < 0) { 812 if (delta < 0)
702 pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); 813 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
703 return -1;
704 }
705
706 pr_debug(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
707 prev_comm, prev_pid, next_comm, next_pid, delta);
708 814
709 prev = register_pid(sched, prev_pid, prev_comm); 815 if (verbose) {
710 next = register_pid(sched, next_pid, next_comm); 816 printf(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
817 switch_event->prev_comm, switch_event->prev_pid,
818 switch_event->next_comm, switch_event->next_pid,
819 delta);
820 }
711 821
712 sched->cpu_last_switched[cpu] = timestamp; 822 prev = register_pid(switch_event->prev_pid, switch_event->prev_comm);
823 next = register_pid(switch_event->next_pid, switch_event->next_comm);
713 824
714 add_sched_event_run(sched, prev, timestamp, delta); 825 cpu_last_switched[cpu] = timestamp;
715 add_sched_event_sleep(sched, prev, timestamp, prev_state);
716 826
717 return 0; 827 add_sched_event_run(prev, timestamp, delta);
828 add_sched_event_sleep(prev, timestamp, switch_event->prev_state);
718} 829}
719 830
720static int replay_fork_event(struct perf_sched *sched, struct perf_evsel *evsel,
721 struct perf_sample *sample)
722{
723 const char *parent_comm = perf_evsel__strval(evsel, sample, "parent_comm"),
724 *child_comm = perf_evsel__strval(evsel, sample, "child_comm");
725 const u32 parent_pid = perf_evsel__intval(evsel, sample, "parent_pid"),
726 child_pid = perf_evsel__intval(evsel, sample, "child_pid");
727 831
832static void
833replay_fork_event(struct trace_fork_event *fork_event,
834 struct event *event,
835 int cpu __used,
836 u64 timestamp __used,
837 struct thread *thread __used)
838{
728 if (verbose) { 839 if (verbose) {
729 printf("sched_fork event %p\n", evsel); 840 printf("sched_fork event %p\n", event);
730 printf("... parent: %s/%d\n", parent_comm, parent_pid); 841 printf("... parent: %s/%d\n", fork_event->parent_comm, fork_event->parent_pid);
731 printf("... child: %s/%d\n", child_comm, child_pid); 842 printf("... child: %s/%d\n", fork_event->child_comm, fork_event->child_pid);
732 } 843 }
733 844 register_pid(fork_event->parent_pid, fork_event->parent_comm);
734 register_pid(sched, parent_pid, parent_comm); 845 register_pid(fork_event->child_pid, fork_event->child_comm);
735 register_pid(sched, child_pid, child_comm);
736 return 0;
737} 846}
738 847
848static struct trace_sched_handler replay_ops = {
849 .wakeup_event = replay_wakeup_event,
850 .switch_event = replay_switch_event,
851 .fork_event = replay_fork_event,
852};
853
739struct sort_dimension { 854struct sort_dimension {
740 const char *name; 855 const char *name;
741 sort_fn_t cmp; 856 sort_fn_t cmp;
742 struct list_head list; 857 struct list_head list;
743}; 858};
744 859
860static LIST_HEAD(cmp_pid);
861
745static int 862static int
746thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r) 863thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r)
747{ 864{
@@ -810,45 +927,43 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
810 rb_insert_color(&data->node, root); 927 rb_insert_color(&data->node, root);
811} 928}
812 929
813static int thread_atoms_insert(struct perf_sched *sched, struct thread *thread) 930static void thread_atoms_insert(struct thread *thread)
814{ 931{
815 struct work_atoms *atoms = zalloc(sizeof(*atoms)); 932 struct work_atoms *atoms = zalloc(sizeof(*atoms));
816 if (!atoms) { 933 if (!atoms)
817 pr_err("No memory at %s\n", __func__); 934 die("No memory");
818 return -1;
819 }
820 935
821 atoms->thread = thread; 936 atoms->thread = thread;
822 INIT_LIST_HEAD(&atoms->work_list); 937 INIT_LIST_HEAD(&atoms->work_list);
823 __thread_latency_insert(&sched->atom_root, atoms, &sched->cmp_pid); 938 __thread_latency_insert(&atom_root, atoms, &cmp_pid);
824 return 0;
825} 939}
826 940
827static int latency_fork_event(struct perf_sched *sched __maybe_unused, 941static void
828 struct perf_evsel *evsel __maybe_unused, 942latency_fork_event(struct trace_fork_event *fork_event __used,
829 struct perf_sample *sample __maybe_unused) 943 struct event *event __used,
944 int cpu __used,
945 u64 timestamp __used,
946 struct thread *thread __used)
830{ 947{
831 /* should insert the newcomer */ 948 /* should insert the newcomer */
832 return 0;
833} 949}
834 950
835static char sched_out_state(u64 prev_state) 951__used
952static char sched_out_state(struct trace_switch_event *switch_event)
836{ 953{
837 const char *str = TASK_STATE_TO_CHAR_STR; 954 const char *str = TASK_STATE_TO_CHAR_STR;
838 955
839 return str[prev_state]; 956 return str[switch_event->prev_state];
840} 957}
841 958
842static int 959static void
843add_sched_out_event(struct work_atoms *atoms, 960add_sched_out_event(struct work_atoms *atoms,
844 char run_state, 961 char run_state,
845 u64 timestamp) 962 u64 timestamp)
846{ 963{
847 struct work_atom *atom = zalloc(sizeof(*atom)); 964 struct work_atom *atom = zalloc(sizeof(*atom));
848 if (!atom) { 965 if (!atom)
849 pr_err("Non memory at %s", __func__); 966 die("Non memory");
850 return -1;
851 }
852 967
853 atom->sched_out_time = timestamp; 968 atom->sched_out_time = timestamp;
854 969
@@ -858,12 +973,10 @@ add_sched_out_event(struct work_atoms *atoms,
858 } 973 }
859 974
860 list_add_tail(&atom->list, &atoms->work_list); 975 list_add_tail(&atom->list, &atoms->work_list);
861 return 0;
862} 976}
863 977
864static void 978static void
865add_runtime_event(struct work_atoms *atoms, u64 delta, 979add_runtime_event(struct work_atoms *atoms, u64 delta, u64 timestamp __used)
866 u64 timestamp __maybe_unused)
867{ 980{
868 struct work_atom *atom; 981 struct work_atom *atom;
869 982
@@ -906,128 +1019,106 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
906 atoms->nb_atoms++; 1019 atoms->nb_atoms++;
907} 1020}
908 1021
909static int latency_switch_event(struct perf_sched *sched, 1022static void
910 struct perf_evsel *evsel, 1023latency_switch_event(struct trace_switch_event *switch_event,
911 struct perf_sample *sample, 1024 struct perf_session *session,
912 struct machine *machine) 1025 struct event *event __used,
1026 int cpu,
1027 u64 timestamp,
1028 struct thread *thread __used)
913{ 1029{
914 const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"),
915 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
916 const u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
917 struct work_atoms *out_events, *in_events; 1030 struct work_atoms *out_events, *in_events;
918 struct thread *sched_out, *sched_in; 1031 struct thread *sched_out, *sched_in;
919 u64 timestamp0, timestamp = sample->time; 1032 u64 timestamp0;
920 int cpu = sample->cpu;
921 s64 delta; 1033 s64 delta;
922 1034
923 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1035 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
924 1036
925 timestamp0 = sched->cpu_last_switched[cpu]; 1037 timestamp0 = cpu_last_switched[cpu];
926 sched->cpu_last_switched[cpu] = timestamp; 1038 cpu_last_switched[cpu] = timestamp;
927 if (timestamp0) 1039 if (timestamp0)
928 delta = timestamp - timestamp0; 1040 delta = timestamp - timestamp0;
929 else 1041 else
930 delta = 0; 1042 delta = 0;
931 1043
932 if (delta < 0) { 1044 if (delta < 0)
933 pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1045 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
934 return -1;
935 }
936 1046
937 sched_out = machine__findnew_thread(machine, prev_pid);
938 sched_in = machine__findnew_thread(machine, next_pid);
939 1047
940 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 1048 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1049 sched_in = perf_session__findnew(session, switch_event->next_pid);
1050
1051 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
941 if (!out_events) { 1052 if (!out_events) {
942 if (thread_atoms_insert(sched, sched_out)) 1053 thread_atoms_insert(sched_out);
943 return -1; 1054 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
944 out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid); 1055 if (!out_events)
945 if (!out_events) { 1056 die("out-event: Internal tree error");
946 pr_err("out-event: Internal tree error");
947 return -1;
948 }
949 } 1057 }
950 if (add_sched_out_event(out_events, sched_out_state(prev_state), timestamp)) 1058 add_sched_out_event(out_events, sched_out_state(switch_event), timestamp);
951 return -1;
952 1059
953 in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid); 1060 in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
954 if (!in_events) { 1061 if (!in_events) {
955 if (thread_atoms_insert(sched, sched_in)) 1062 thread_atoms_insert(sched_in);
956 return -1; 1063 in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
957 in_events = thread_atoms_search(&sched->atom_root, sched_in, &sched->cmp_pid); 1064 if (!in_events)
958 if (!in_events) { 1065 die("in-event: Internal tree error");
959 pr_err("in-event: Internal tree error");
960 return -1;
961 }
962 /* 1066 /*
963 * Take came in we have not heard about yet, 1067 * Take came in we have not heard about yet,
964 * add in an initial atom in runnable state: 1068 * add in an initial atom in runnable state:
965 */ 1069 */
966 if (add_sched_out_event(in_events, 'R', timestamp)) 1070 add_sched_out_event(in_events, 'R', timestamp);
967 return -1;
968 } 1071 }
969 add_sched_in_event(in_events, timestamp); 1072 add_sched_in_event(in_events, timestamp);
970
971 return 0;
972} 1073}
973 1074
974static int latency_runtime_event(struct perf_sched *sched, 1075static void
975 struct perf_evsel *evsel, 1076latency_runtime_event(struct trace_runtime_event *runtime_event,
976 struct perf_sample *sample, 1077 struct perf_session *session,
977 struct machine *machine) 1078 struct event *event __used,
1079 int cpu,
1080 u64 timestamp,
1081 struct thread *this_thread __used)
978{ 1082{
979 const u32 pid = perf_evsel__intval(evsel, sample, "pid"); 1083 struct thread *thread = perf_session__findnew(session, runtime_event->pid);
980 const u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); 1084 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
981 struct thread *thread = machine__findnew_thread(machine, pid);
982 struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
983 u64 timestamp = sample->time;
984 int cpu = sample->cpu;
985 1085
986 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1086 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
987 if (!atoms) { 1087 if (!atoms) {
988 if (thread_atoms_insert(sched, thread)) 1088 thread_atoms_insert(thread);
989 return -1; 1089 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
990 atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); 1090 if (!atoms)
991 if (!atoms) { 1091 die("in-event: Internal tree error");
992 pr_err("in-event: Internal tree error"); 1092 add_sched_out_event(atoms, 'R', timestamp);
993 return -1;
994 }
995 if (add_sched_out_event(atoms, 'R', timestamp))
996 return -1;
997 } 1093 }
998 1094
999 add_runtime_event(atoms, runtime, timestamp); 1095 add_runtime_event(atoms, runtime_event->runtime, timestamp);
1000 return 0;
1001} 1096}
1002 1097
1003static int latency_wakeup_event(struct perf_sched *sched, 1098static void
1004 struct perf_evsel *evsel, 1099latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1005 struct perf_sample *sample, 1100 struct perf_session *session,
1006 struct machine *machine) 1101 struct event *__event __used,
1102 int cpu __used,
1103 u64 timestamp,
1104 struct thread *thread __used)
1007{ 1105{
1008 const u32 pid = perf_evsel__intval(evsel, sample, "pid"),
1009 success = perf_evsel__intval(evsel, sample, "success");
1010 struct work_atoms *atoms; 1106 struct work_atoms *atoms;
1011 struct work_atom *atom; 1107 struct work_atom *atom;
1012 struct thread *wakee; 1108 struct thread *wakee;
1013 u64 timestamp = sample->time;
1014 1109
1015 /* Note for later, it may be interesting to observe the failing cases */ 1110 /* Note for later, it may be interesting to observe the failing cases */
1016 if (!success) 1111 if (!wakeup_event->success)
1017 return 0; 1112 return;
1018 1113
1019 wakee = machine__findnew_thread(machine, pid); 1114 wakee = perf_session__findnew(session, wakeup_event->pid);
1020 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1115 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1021 if (!atoms) { 1116 if (!atoms) {
1022 if (thread_atoms_insert(sched, wakee)) 1117 thread_atoms_insert(wakee);
1023 return -1; 1118 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1024 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1119 if (!atoms)
1025 if (!atoms) { 1120 die("wakeup-event: Internal tree error");
1026 pr_err("wakeup-event: Internal tree error"); 1121 add_sched_out_event(atoms, 'S', timestamp);
1027 return -1;
1028 }
1029 if (add_sched_out_event(atoms, 'S', timestamp))
1030 return -1;
1031 } 1122 }
1032 1123
1033 BUG_ON(list_empty(&atoms->work_list)); 1124 BUG_ON(list_empty(&atoms->work_list));
@@ -1039,27 +1130,27 @@ static int latency_wakeup_event(struct perf_sched *sched,
1039 * one CPU, or are only looking at only one, so don't 1130 * one CPU, or are only looking at only one, so don't
1040 * make useless noise. 1131 * make useless noise.
1041 */ 1132 */
1042 if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING) 1133 if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1043 sched->nr_state_machine_bugs++; 1134 nr_state_machine_bugs++;
1044 1135
1045 sched->nr_timestamps++; 1136 nr_timestamps++;
1046 if (atom->sched_out_time > timestamp) { 1137 if (atom->sched_out_time > timestamp) {
1047 sched->nr_unordered_timestamps++; 1138 nr_unordered_timestamps++;
1048 return 0; 1139 return;
1049 } 1140 }
1050 1141
1051 atom->state = THREAD_WAIT_CPU; 1142 atom->state = THREAD_WAIT_CPU;
1052 atom->wake_up_time = timestamp; 1143 atom->wake_up_time = timestamp;
1053 return 0;
1054} 1144}
1055 1145
1056static int latency_migrate_task_event(struct perf_sched *sched, 1146static void
1057 struct perf_evsel *evsel, 1147latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1058 struct perf_sample *sample, 1148 struct perf_session *session,
1059 struct machine *machine) 1149 struct event *__event __used,
1150 int cpu __used,
1151 u64 timestamp,
1152 struct thread *thread __used)
1060{ 1153{
1061 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
1062 u64 timestamp = sample->time;
1063 struct work_atoms *atoms; 1154 struct work_atoms *atoms;
1064 struct work_atom *atom; 1155 struct work_atom *atom;
1065 struct thread *migrant; 1156 struct thread *migrant;
@@ -1067,22 +1158,18 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1067 /* 1158 /*
1068 * Only need to worry about migration when profiling one CPU. 1159 * Only need to worry about migration when profiling one CPU.
1069 */ 1160 */
1070 if (sched->profile_cpu == -1) 1161 if (profile_cpu == -1)
1071 return 0; 1162 return;
1072 1163
1073 migrant = machine__findnew_thread(machine, pid); 1164 migrant = perf_session__findnew(session, migrate_task_event->pid);
1074 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1165 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1075 if (!atoms) { 1166 if (!atoms) {
1076 if (thread_atoms_insert(sched, migrant)) 1167 thread_atoms_insert(migrant);
1077 return -1; 1168 register_pid(migrant->pid, migrant->comm);
1078 register_pid(sched, migrant->pid, migrant->comm); 1169 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1079 atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); 1170 if (!atoms)
1080 if (!atoms) { 1171 die("migration-event: Internal tree error");
1081 pr_err("migration-event: Internal tree error"); 1172 add_sched_out_event(atoms, 'R', timestamp);
1082 return -1;
1083 }
1084 if (add_sched_out_event(atoms, 'R', timestamp))
1085 return -1;
1086 } 1173 }
1087 1174
1088 BUG_ON(list_empty(&atoms->work_list)); 1175 BUG_ON(list_empty(&atoms->work_list));
@@ -1090,15 +1177,21 @@ static int latency_migrate_task_event(struct perf_sched *sched,
1090 atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1177 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1091 atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp; 1178 atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
1092 1179
1093 sched->nr_timestamps++; 1180 nr_timestamps++;
1094 1181
1095 if (atom->sched_out_time > timestamp) 1182 if (atom->sched_out_time > timestamp)
1096 sched->nr_unordered_timestamps++; 1183 nr_unordered_timestamps++;
1097
1098 return 0;
1099} 1184}
1100 1185
1101static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_list) 1186static struct trace_sched_handler lat_ops = {
1187 .wakeup_event = latency_wakeup_event,
1188 .switch_event = latency_switch_event,
1189 .runtime_event = latency_runtime_event,
1190 .fork_event = latency_fork_event,
1191 .migrate_task_event = latency_migrate_task_event,
1192};
1193
1194static void output_lat_thread(struct work_atoms *work_list)
1102{ 1195{
1103 int i; 1196 int i;
1104 int ret; 1197 int ret;
@@ -1112,8 +1205,8 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
1112 if (!strcmp(work_list->thread->comm, "swapper")) 1205 if (!strcmp(work_list->thread->comm, "swapper"))
1113 return; 1206 return;
1114 1207
1115 sched->all_runtime += work_list->total_runtime; 1208 all_runtime += work_list->total_runtime;
1116 sched->all_count += work_list->nb_atoms; 1209 all_count += work_list->nb_atoms;
1117 1210
1118 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); 1211 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid);
1119 1212
@@ -1139,6 +1232,11 @@ static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1139 return 0; 1232 return 0;
1140} 1233}
1141 1234
1235static struct sort_dimension pid_sort_dimension = {
1236 .name = "pid",
1237 .cmp = pid_cmp,
1238};
1239
1142static int avg_cmp(struct work_atoms *l, struct work_atoms *r) 1240static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
1143{ 1241{
1144 u64 avgl, avgr; 1242 u64 avgl, avgr;
@@ -1160,6 +1258,11 @@ static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
1160 return 0; 1258 return 0;
1161} 1259}
1162 1260
1261static struct sort_dimension avg_sort_dimension = {
1262 .name = "avg",
1263 .cmp = avg_cmp,
1264};
1265
1163static int max_cmp(struct work_atoms *l, struct work_atoms *r) 1266static int max_cmp(struct work_atoms *l, struct work_atoms *r)
1164{ 1267{
1165 if (l->max_lat < r->max_lat) 1268 if (l->max_lat < r->max_lat)
@@ -1170,6 +1273,11 @@ static int max_cmp(struct work_atoms *l, struct work_atoms *r)
1170 return 0; 1273 return 0;
1171} 1274}
1172 1275
1276static struct sort_dimension max_sort_dimension = {
1277 .name = "max",
1278 .cmp = max_cmp,
1279};
1280
1173static int switch_cmp(struct work_atoms *l, struct work_atoms *r) 1281static int switch_cmp(struct work_atoms *l, struct work_atoms *r)
1174{ 1282{
1175 if (l->nb_atoms < r->nb_atoms) 1283 if (l->nb_atoms < r->nb_atoms)
@@ -1180,6 +1288,11 @@ static int switch_cmp(struct work_atoms *l, struct work_atoms *r)
1180 return 0; 1288 return 0;
1181} 1289}
1182 1290
1291static struct sort_dimension switch_sort_dimension = {
1292 .name = "switch",
1293 .cmp = switch_cmp,
1294};
1295
1183static int runtime_cmp(struct work_atoms *l, struct work_atoms *r) 1296static int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
1184{ 1297{
1185 if (l->total_runtime < r->total_runtime) 1298 if (l->total_runtime < r->total_runtime)
@@ -1190,38 +1303,28 @@ static int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
1190 return 0; 1303 return 0;
1191} 1304}
1192 1305
1306static struct sort_dimension runtime_sort_dimension = {
1307 .name = "runtime",
1308 .cmp = runtime_cmp,
1309};
1310
1311static struct sort_dimension *available_sorts[] = {
1312 &pid_sort_dimension,
1313 &avg_sort_dimension,
1314 &max_sort_dimension,
1315 &switch_sort_dimension,
1316 &runtime_sort_dimension,
1317};
1318
1319#define NB_AVAILABLE_SORTS (int)(sizeof(available_sorts) / sizeof(struct sort_dimension *))
1320
1321static LIST_HEAD(sort_list);
1322
1193static int sort_dimension__add(const char *tok, struct list_head *list) 1323static int sort_dimension__add(const char *tok, struct list_head *list)
1194{ 1324{
1195 size_t i; 1325 int i;
1196 static struct sort_dimension avg_sort_dimension = { 1326
1197 .name = "avg", 1327 for (i = 0; i < NB_AVAILABLE_SORTS; i++) {
1198 .cmp = avg_cmp,
1199 };
1200 static struct sort_dimension max_sort_dimension = {
1201 .name = "max",
1202 .cmp = max_cmp,
1203 };
1204 static struct sort_dimension pid_sort_dimension = {
1205 .name = "pid",
1206 .cmp = pid_cmp,
1207 };
1208 static struct sort_dimension runtime_sort_dimension = {
1209 .name = "runtime",
1210 .cmp = runtime_cmp,
1211 };
1212 static struct sort_dimension switch_sort_dimension = {
1213 .name = "switch",
1214 .cmp = switch_cmp,
1215 };
1216 struct sort_dimension *available_sorts[] = {
1217 &pid_sort_dimension,
1218 &avg_sort_dimension,
1219 &max_sort_dimension,
1220 &switch_sort_dimension,
1221 &runtime_sort_dimension,
1222 };
1223
1224 for (i = 0; i < ARRAY_SIZE(available_sorts); i++) {
1225 if (!strcmp(available_sorts[i]->name, tok)) { 1328 if (!strcmp(available_sorts[i]->name, tok)) {
1226 list_add_tail(&available_sorts[i]->list, list); 1329 list_add_tail(&available_sorts[i]->list, list);
1227 1330
@@ -1232,97 +1335,125 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
1232 return -1; 1335 return -1;
1233} 1336}
1234 1337
1235static void perf_sched__sort_lat(struct perf_sched *sched) 1338static void setup_sorting(void);
1339
1340static void sort_lat(void)
1236{ 1341{
1237 struct rb_node *node; 1342 struct rb_node *node;
1238 1343
1239 for (;;) { 1344 for (;;) {
1240 struct work_atoms *data; 1345 struct work_atoms *data;
1241 node = rb_first(&sched->atom_root); 1346 node = rb_first(&atom_root);
1242 if (!node) 1347 if (!node)
1243 break; 1348 break;
1244 1349
1245 rb_erase(node, &sched->atom_root); 1350 rb_erase(node, &atom_root);
1246 data = rb_entry(node, struct work_atoms, node); 1351 data = rb_entry(node, struct work_atoms, node);
1247 __thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list); 1352 __thread_latency_insert(&sorted_atom_root, data, &sort_list);
1248 } 1353 }
1249} 1354}
1250 1355
1251static int process_sched_wakeup_event(struct perf_tool *tool, 1356static struct trace_sched_handler *trace_handler;
1252 struct perf_evsel *evsel, 1357
1253 struct perf_sample *sample, 1358static void
1254 struct machine *machine) 1359process_sched_wakeup_event(void *data, struct perf_session *session,
1360 struct event *event,
1361 int cpu __used,
1362 u64 timestamp __used,
1363 struct thread *thread __used)
1255{ 1364{
1256 struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1365 struct trace_wakeup_event wakeup_event;
1257 1366
1258 if (sched->tp_handler->wakeup_event) 1367 FILL_COMMON_FIELDS(wakeup_event, event, data);
1259 return sched->tp_handler->wakeup_event(sched, evsel, sample, machine);
1260 1368
1261 return 0; 1369 FILL_ARRAY(wakeup_event, comm, event, data);
1370 FILL_FIELD(wakeup_event, pid, event, data);
1371 FILL_FIELD(wakeup_event, prio, event, data);
1372 FILL_FIELD(wakeup_event, success, event, data);
1373 FILL_FIELD(wakeup_event, cpu, event, data);
1374
1375 if (trace_handler->wakeup_event)
1376 trace_handler->wakeup_event(&wakeup_event, session, event,
1377 cpu, timestamp, thread);
1262} 1378}
1263 1379
1264static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, 1380/*
1265 struct perf_sample *sample, struct machine *machine) 1381 * Track the current task - that way we can know whether there's any
1382 * weird events, such as a task being switched away that is not current.
1383 */
1384static int max_cpu;
1385
1386static u32 curr_pid[MAX_CPUS] = { [0 ... MAX_CPUS-1] = -1 };
1387
1388static struct thread *curr_thread[MAX_CPUS];
1389
1390static char next_shortname1 = 'A';
1391static char next_shortname2 = '0';
1392
1393static void
1394map_switch_event(struct trace_switch_event *switch_event,
1395 struct perf_session *session,
1396 struct event *event __used,
1397 int this_cpu,
1398 u64 timestamp,
1399 struct thread *thread __used)
1266{ 1400{
1267 const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"), 1401 struct thread *sched_out __used, *sched_in;
1268 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1269 struct thread *sched_out __maybe_unused, *sched_in;
1270 int new_shortname; 1402 int new_shortname;
1271 u64 timestamp0, timestamp = sample->time; 1403 u64 timestamp0;
1272 s64 delta; 1404 s64 delta;
1273 int cpu, this_cpu = sample->cpu; 1405 int cpu;
1274 1406
1275 BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); 1407 BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
1276 1408
1277 if (this_cpu > sched->max_cpu) 1409 if (this_cpu > max_cpu)
1278 sched->max_cpu = this_cpu; 1410 max_cpu = this_cpu;
1279 1411
1280 timestamp0 = sched->cpu_last_switched[this_cpu]; 1412 timestamp0 = cpu_last_switched[this_cpu];
1281 sched->cpu_last_switched[this_cpu] = timestamp; 1413 cpu_last_switched[this_cpu] = timestamp;
1282 if (timestamp0) 1414 if (timestamp0)
1283 delta = timestamp - timestamp0; 1415 delta = timestamp - timestamp0;
1284 else 1416 else
1285 delta = 0; 1417 delta = 0;
1286 1418
1287 if (delta < 0) { 1419 if (delta < 0)
1288 pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1420 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1289 return -1;
1290 }
1291 1421
1292 sched_out = machine__findnew_thread(machine, prev_pid);
1293 sched_in = machine__findnew_thread(machine, next_pid);
1294 1422
1295 sched->curr_thread[this_cpu] = sched_in; 1423 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1424 sched_in = perf_session__findnew(session, switch_event->next_pid);
1425
1426 curr_thread[this_cpu] = sched_in;
1296 1427
1297 printf(" "); 1428 printf(" ");
1298 1429
1299 new_shortname = 0; 1430 new_shortname = 0;
1300 if (!sched_in->shortname[0]) { 1431 if (!sched_in->shortname[0]) {
1301 sched_in->shortname[0] = sched->next_shortname1; 1432 sched_in->shortname[0] = next_shortname1;
1302 sched_in->shortname[1] = sched->next_shortname2; 1433 sched_in->shortname[1] = next_shortname2;
1303 1434
1304 if (sched->next_shortname1 < 'Z') { 1435 if (next_shortname1 < 'Z') {
1305 sched->next_shortname1++; 1436 next_shortname1++;
1306 } else { 1437 } else {
1307 sched->next_shortname1='A'; 1438 next_shortname1='A';
1308 if (sched->next_shortname2 < '9') { 1439 if (next_shortname2 < '9') {
1309 sched->next_shortname2++; 1440 next_shortname2++;
1310 } else { 1441 } else {
1311 sched->next_shortname2='0'; 1442 next_shortname2='0';
1312 } 1443 }
1313 } 1444 }
1314 new_shortname = 1; 1445 new_shortname = 1;
1315 } 1446 }
1316 1447
1317 for (cpu = 0; cpu <= sched->max_cpu; cpu++) { 1448 for (cpu = 0; cpu <= max_cpu; cpu++) {
1318 if (cpu != this_cpu) 1449 if (cpu != this_cpu)
1319 printf(" "); 1450 printf(" ");
1320 else 1451 else
1321 printf("*"); 1452 printf("*");
1322 1453
1323 if (sched->curr_thread[cpu]) { 1454 if (curr_thread[cpu]) {
1324 if (sched->curr_thread[cpu]->pid) 1455 if (curr_thread[cpu]->pid)
1325 printf("%2s ", sched->curr_thread[cpu]->shortname); 1456 printf("%2s ", curr_thread[cpu]->shortname);
1326 else 1457 else
1327 printf(". "); 1458 printf(". ");
1328 } else 1459 } else
@@ -1336,148 +1467,192 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1336 } else { 1467 } else {
1337 printf("\n"); 1468 printf("\n");
1338 } 1469 }
1339
1340 return 0;
1341} 1470}
1342 1471
1343static int process_sched_switch_event(struct perf_tool *tool, 1472
1344 struct perf_evsel *evsel, 1473static void
1345 struct perf_sample *sample, 1474process_sched_switch_event(void *data, struct perf_session *session,
1346 struct machine *machine) 1475 struct event *event,
1476 int this_cpu,
1477 u64 timestamp __used,
1478 struct thread *thread __used)
1347{ 1479{
1348 struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1480 struct trace_switch_event switch_event;
1349 int this_cpu = sample->cpu, err = 0; 1481
1350 u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"), 1482 FILL_COMMON_FIELDS(switch_event, event, data);
1351 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1352 1483
1353 if (sched->curr_pid[this_cpu] != (u32)-1) { 1484 FILL_ARRAY(switch_event, prev_comm, event, data);
1485 FILL_FIELD(switch_event, prev_pid, event, data);
1486 FILL_FIELD(switch_event, prev_prio, event, data);
1487 FILL_FIELD(switch_event, prev_state, event, data);
1488 FILL_ARRAY(switch_event, next_comm, event, data);
1489 FILL_FIELD(switch_event, next_pid, event, data);
1490 FILL_FIELD(switch_event, next_prio, event, data);
1491
1492 if (curr_pid[this_cpu] != (u32)-1) {
1354 /* 1493 /*
1355 * Are we trying to switch away a PID that is 1494 * Are we trying to switch away a PID that is
1356 * not current? 1495 * not current?
1357 */ 1496 */
1358 if (sched->curr_pid[this_cpu] != prev_pid) 1497 if (curr_pid[this_cpu] != switch_event.prev_pid)
1359 sched->nr_context_switch_bugs++; 1498 nr_context_switch_bugs++;
1360 } 1499 }
1500 if (trace_handler->switch_event)
1501 trace_handler->switch_event(&switch_event, session, event,
1502 this_cpu, timestamp, thread);
1361 1503
1362 if (sched->tp_handler->switch_event) 1504 curr_pid[this_cpu] = switch_event.next_pid;
1363 err = sched->tp_handler->switch_event(sched, evsel, sample, machine);
1364
1365 sched->curr_pid[this_cpu] = next_pid;
1366 return err;
1367} 1505}
1368 1506
1369static int process_sched_runtime_event(struct perf_tool *tool, 1507static void
1370 struct perf_evsel *evsel, 1508process_sched_runtime_event(void *data, struct perf_session *session,
1371 struct perf_sample *sample, 1509 struct event *event,
1372 struct machine *machine) 1510 int cpu __used,
1511 u64 timestamp __used,
1512 struct thread *thread __used)
1373{ 1513{
1374 struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1514 struct trace_runtime_event runtime_event;
1375 1515
1376 if (sched->tp_handler->runtime_event) 1516 FILL_ARRAY(runtime_event, comm, event, data);
1377 return sched->tp_handler->runtime_event(sched, evsel, sample, machine); 1517 FILL_FIELD(runtime_event, pid, event, data);
1518 FILL_FIELD(runtime_event, runtime, event, data);
1519 FILL_FIELD(runtime_event, vruntime, event, data);
1378 1520
1379 return 0; 1521 if (trace_handler->runtime_event)
1522 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
1380} 1523}
1381 1524
1382static int process_sched_fork_event(struct perf_tool *tool, 1525static void
1383 struct perf_evsel *evsel, 1526process_sched_fork_event(void *data,
1384 struct perf_sample *sample, 1527 struct event *event,
1385 struct machine *machine __maybe_unused) 1528 int cpu __used,
1529 u64 timestamp __used,
1530 struct thread *thread __used)
1386{ 1531{
1387 struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1532 struct trace_fork_event fork_event;
1388 1533
1389 if (sched->tp_handler->fork_event) 1534 FILL_COMMON_FIELDS(fork_event, event, data);
1390 return sched->tp_handler->fork_event(sched, evsel, sample);
1391 1535
1392 return 0; 1536 FILL_ARRAY(fork_event, parent_comm, event, data);
1537 FILL_FIELD(fork_event, parent_pid, event, data);
1538 FILL_ARRAY(fork_event, child_comm, event, data);
1539 FILL_FIELD(fork_event, child_pid, event, data);
1540
1541 if (trace_handler->fork_event)
1542 trace_handler->fork_event(&fork_event, event,
1543 cpu, timestamp, thread);
1393} 1544}
1394 1545
1395static int process_sched_exit_event(struct perf_tool *tool __maybe_unused, 1546static void
1396 struct perf_evsel *evsel, 1547process_sched_exit_event(struct event *event,
1397 struct perf_sample *sample __maybe_unused, 1548 int cpu __used,
1398 struct machine *machine __maybe_unused) 1549 u64 timestamp __used,
1550 struct thread *thread __used)
1399{ 1551{
1400 pr_debug("sched_exit event %p\n", evsel); 1552 if (verbose)
1401 return 0; 1553 printf("sched_exit event %p\n", event);
1402} 1554}
1403 1555
1404static int process_sched_migrate_task_event(struct perf_tool *tool, 1556static void
1405 struct perf_evsel *evsel, 1557process_sched_migrate_task_event(void *data, struct perf_session *session,
1406 struct perf_sample *sample, 1558 struct event *event,
1407 struct machine *machine) 1559 int cpu __used,
1560 u64 timestamp __used,
1561 struct thread *thread __used)
1408{ 1562{
1409 struct perf_sched *sched = container_of(tool, struct perf_sched, tool); 1563 struct trace_migrate_task_event migrate_task_event;
1410 1564
1411 if (sched->tp_handler->migrate_task_event) 1565 FILL_COMMON_FIELDS(migrate_task_event, event, data);
1412 return sched->tp_handler->migrate_task_event(sched, evsel, sample, machine);
1413 1566
1414 return 0; 1567 FILL_ARRAY(migrate_task_event, comm, event, data);
1568 FILL_FIELD(migrate_task_event, pid, event, data);
1569 FILL_FIELD(migrate_task_event, prio, event, data);
1570 FILL_FIELD(migrate_task_event, cpu, event, data);
1571
1572 if (trace_handler->migrate_task_event)
1573 trace_handler->migrate_task_event(&migrate_task_event, session,
1574 event, cpu, timestamp, thread);
1415} 1575}
1416 1576
1417typedef int (*tracepoint_handler)(struct perf_tool *tool, 1577static void process_raw_event(union perf_event *raw_event __used,
1418 struct perf_evsel *evsel, 1578 struct perf_session *session, void *data, int cpu,
1419 struct perf_sample *sample, 1579 u64 timestamp, struct thread *thread)
1420 struct machine *machine); 1580{
1581 struct event *event;
1582 int type;
1583
1584
1585 type = trace_parse_common_type(data);
1586 event = trace_find_event(type);
1587
1588 if (!strcmp(event->name, "sched_switch"))
1589 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1590 if (!strcmp(event->name, "sched_stat_runtime"))
1591 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1592 if (!strcmp(event->name, "sched_wakeup"))
1593 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1594 if (!strcmp(event->name, "sched_wakeup_new"))
1595 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1596 if (!strcmp(event->name, "sched_process_fork"))
1597 process_sched_fork_event(data, event, cpu, timestamp, thread);
1598 if (!strcmp(event->name, "sched_process_exit"))
1599 process_sched_exit_event(event, cpu, timestamp, thread);
1600 if (!strcmp(event->name, "sched_migrate_task"))
1601 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1602}
1421 1603
1422static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_unused, 1604static int process_sample_event(union perf_event *event,
1423 union perf_event *event __maybe_unused, 1605 struct perf_sample *sample,
1424 struct perf_sample *sample, 1606 struct perf_evsel *evsel __used,
1425 struct perf_evsel *evsel, 1607 struct perf_session *session)
1426 struct machine *machine)
1427{ 1608{
1428 struct thread *thread = machine__findnew_thread(machine, sample->tid); 1609 struct thread *thread;
1429 int err = 0; 1610
1611 if (!(session->sample_type & PERF_SAMPLE_RAW))
1612 return 0;
1430 1613
1614 thread = perf_session__findnew(session, sample->pid);
1431 if (thread == NULL) { 1615 if (thread == NULL) {
1432 pr_debug("problem processing %s event, skipping it.\n", 1616 pr_debug("problem processing %d event, skipping it.\n",
1433 perf_evsel__name(evsel)); 1617 event->header.type);
1434 return -1; 1618 return -1;
1435 } 1619 }
1436 1620
1437 evsel->hists.stats.total_period += sample->period; 1621 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1438 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
1439 1622
1440 if (evsel->handler.func != NULL) { 1623 if (profile_cpu != -1 && profile_cpu != (int)sample->cpu)
1441 tracepoint_handler f = evsel->handler.func; 1624 return 0;
1442 err = f(tool, evsel, sample, machine);
1443 }
1444 1625
1445 return err; 1626 process_raw_event(event, session, sample->raw_data, sample->cpu,
1446} 1627 sample->time, thread);
1447 1628
1448static int perf_sched__read_events(struct perf_sched *sched, bool destroy, 1629 return 0;
1449 struct perf_session **psession) 1630}
1450{
1451 const struct perf_evsel_str_handler handlers[] = {
1452 { "sched:sched_switch", process_sched_switch_event, },
1453 { "sched:sched_stat_runtime", process_sched_runtime_event, },
1454 { "sched:sched_wakeup", process_sched_wakeup_event, },
1455 { "sched:sched_wakeup_new", process_sched_wakeup_event, },
1456 { "sched:sched_process_fork", process_sched_fork_event, },
1457 { "sched:sched_process_exit", process_sched_exit_event, },
1458 { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1459 };
1460 struct perf_session *session;
1461 1631
1462 session = perf_session__new(input_name, O_RDONLY, 0, false, &sched->tool); 1632static struct perf_event_ops event_ops = {
1463 if (session == NULL) { 1633 .sample = process_sample_event,
1464 pr_debug("No Memory for session\n"); 1634 .comm = perf_event__process_comm,
1465 return -1; 1635 .lost = perf_event__process_lost,
1466 } 1636 .fork = perf_event__process_task,
1637 .ordered_samples = true,
1638};
1467 1639
1468 if (perf_session__set_tracepoints_handlers(session, handlers)) 1640static void read_events(bool destroy, struct perf_session **psession)
1469 goto out_delete; 1641{
1642 int err = -EINVAL;
1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1644 0, false, &event_ops);
1645 if (session == NULL)
1646 die("No Memory");
1470 1647
1471 if (perf_session__has_traces(session, "record -R")) { 1648 if (perf_session__has_traces(session, "record -R")) {
1472 int err = perf_session__process_events(session, &sched->tool); 1649 err = perf_session__process_events(session, &event_ops);
1473 if (err) { 1650 if (err)
1474 pr_err("Failed to process events, error %d", err); 1651 die("Failed to process events, error %d", err);
1475 goto out_delete;
1476 }
1477 1652
1478 sched->nr_events = session->hists.stats.nr_events[0]; 1653 nr_events = session->hists.stats.nr_events[0];
1479 sched->nr_lost_events = session->hists.stats.total_lost; 1654 nr_lost_events = session->hists.stats.total_lost;
1480 sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; 1655 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
1481 } 1656 }
1482 1657
1483 if (destroy) 1658 if (destroy)
@@ -1485,166 +1660,208 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1485 1660
1486 if (psession) 1661 if (psession)
1487 *psession = session; 1662 *psession = session;
1488
1489 return 0;
1490
1491out_delete:
1492 perf_session__delete(session);
1493 return -1;
1494} 1663}
1495 1664
1496static void print_bad_events(struct perf_sched *sched) 1665static void print_bad_events(void)
1497{ 1666{
1498 if (sched->nr_unordered_timestamps && sched->nr_timestamps) { 1667 if (nr_unordered_timestamps && nr_timestamps) {
1499 printf(" INFO: %.3f%% unordered timestamps (%ld out of %ld)\n", 1668 printf(" INFO: %.3f%% unordered timestamps (%ld out of %ld)\n",
1500 (double)sched->nr_unordered_timestamps/(double)sched->nr_timestamps*100.0, 1669 (double)nr_unordered_timestamps/(double)nr_timestamps*100.0,
1501 sched->nr_unordered_timestamps, sched->nr_timestamps); 1670 nr_unordered_timestamps, nr_timestamps);
1502 } 1671 }
1503 if (sched->nr_lost_events && sched->nr_events) { 1672 if (nr_lost_events && nr_events) {
1504 printf(" INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n", 1673 printf(" INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n",
1505 (double)sched->nr_lost_events/(double)sched->nr_events * 100.0, 1674 (double)nr_lost_events/(double)nr_events*100.0,
1506 sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks); 1675 nr_lost_events, nr_events, nr_lost_chunks);
1507 } 1676 }
1508 if (sched->nr_state_machine_bugs && sched->nr_timestamps) { 1677 if (nr_state_machine_bugs && nr_timestamps) {
1509 printf(" INFO: %.3f%% state machine bugs (%ld out of %ld)", 1678 printf(" INFO: %.3f%% state machine bugs (%ld out of %ld)",
1510 (double)sched->nr_state_machine_bugs/(double)sched->nr_timestamps*100.0, 1679 (double)nr_state_machine_bugs/(double)nr_timestamps*100.0,
1511 sched->nr_state_machine_bugs, sched->nr_timestamps); 1680 nr_state_machine_bugs, nr_timestamps);
1512 if (sched->nr_lost_events) 1681 if (nr_lost_events)
1513 printf(" (due to lost events?)"); 1682 printf(" (due to lost events?)");
1514 printf("\n"); 1683 printf("\n");
1515 } 1684 }
1516 if (sched->nr_context_switch_bugs && sched->nr_timestamps) { 1685 if (nr_context_switch_bugs && nr_timestamps) {
1517 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)", 1686 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)",
1518 (double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0, 1687 (double)nr_context_switch_bugs/(double)nr_timestamps*100.0,
1519 sched->nr_context_switch_bugs, sched->nr_timestamps); 1688 nr_context_switch_bugs, nr_timestamps);
1520 if (sched->nr_lost_events) 1689 if (nr_lost_events)
1521 printf(" (due to lost events?)"); 1690 printf(" (due to lost events?)");
1522 printf("\n"); 1691 printf("\n");
1523 } 1692 }
1524} 1693}
1525 1694
1526static int perf_sched__lat(struct perf_sched *sched) 1695static void __cmd_lat(void)
1527{ 1696{
1528 struct rb_node *next; 1697 struct rb_node *next;
1529 struct perf_session *session; 1698 struct perf_session *session;
1530 1699
1531 setup_pager(); 1700 setup_pager();
1532 if (perf_sched__read_events(sched, false, &session)) 1701 read_events(false, &session);
1533 return -1; 1702 sort_lat();
1534 perf_sched__sort_lat(sched);
1535 1703
1536 printf("\n ---------------------------------------------------------------------------------------------------------------\n"); 1704 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1537 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n"); 1705 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
1538 printf(" ---------------------------------------------------------------------------------------------------------------\n"); 1706 printf(" ---------------------------------------------------------------------------------------------------------------\n");
1539 1707
1540 next = rb_first(&sched->sorted_atom_root); 1708 next = rb_first(&sorted_atom_root);
1541 1709
1542 while (next) { 1710 while (next) {
1543 struct work_atoms *work_list; 1711 struct work_atoms *work_list;
1544 1712
1545 work_list = rb_entry(next, struct work_atoms, node); 1713 work_list = rb_entry(next, struct work_atoms, node);
1546 output_lat_thread(sched, work_list); 1714 output_lat_thread(work_list);
1547 next = rb_next(next); 1715 next = rb_next(next);
1548 } 1716 }
1549 1717
1550 printf(" -----------------------------------------------------------------------------------------\n"); 1718 printf(" -----------------------------------------------------------------------------------------\n");
1551 printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n", 1719 printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n",
1552 (double)sched->all_runtime / 1e6, sched->all_count); 1720 (double)all_runtime/1e6, all_count);
1553 1721
1554 printf(" ---------------------------------------------------\n"); 1722 printf(" ---------------------------------------------------\n");
1555 1723
1556 print_bad_events(sched); 1724 print_bad_events();
1557 printf("\n"); 1725 printf("\n");
1558 1726
1559 perf_session__delete(session); 1727 perf_session__delete(session);
1560 return 0;
1561} 1728}
1562 1729
1563static int perf_sched__map(struct perf_sched *sched) 1730static struct trace_sched_handler map_ops = {
1731 .wakeup_event = NULL,
1732 .switch_event = map_switch_event,
1733 .runtime_event = NULL,
1734 .fork_event = NULL,
1735};
1736
1737static void __cmd_map(void)
1564{ 1738{
1565 sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); 1739 max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1566 1740
1567 setup_pager(); 1741 setup_pager();
1568 if (perf_sched__read_events(sched, true, NULL)) 1742 read_events(true, NULL);
1569 return -1; 1743 print_bad_events();
1570 print_bad_events(sched);
1571 return 0;
1572} 1744}
1573 1745
1574static int perf_sched__replay(struct perf_sched *sched) 1746static void __cmd_replay(void)
1575{ 1747{
1576 unsigned long i; 1748 unsigned long i;
1577 1749
1578 calibrate_run_measurement_overhead(sched); 1750 calibrate_run_measurement_overhead();
1579 calibrate_sleep_measurement_overhead(sched); 1751 calibrate_sleep_measurement_overhead();
1580 1752
1581 test_calibrations(sched); 1753 test_calibrations();
1582 1754
1583 if (perf_sched__read_events(sched, true, NULL)) 1755 read_events(true, NULL);
1584 return -1;
1585 1756
1586 printf("nr_run_events: %ld\n", sched->nr_run_events); 1757 printf("nr_run_events: %ld\n", nr_run_events);
1587 printf("nr_sleep_events: %ld\n", sched->nr_sleep_events); 1758 printf("nr_sleep_events: %ld\n", nr_sleep_events);
1588 printf("nr_wakeup_events: %ld\n", sched->nr_wakeup_events); 1759 printf("nr_wakeup_events: %ld\n", nr_wakeup_events);
1589 1760
1590 if (sched->targetless_wakeups) 1761 if (targetless_wakeups)
1591 printf("target-less wakeups: %ld\n", sched->targetless_wakeups); 1762 printf("target-less wakeups: %ld\n", targetless_wakeups);
1592 if (sched->multitarget_wakeups) 1763 if (multitarget_wakeups)
1593 printf("multi-target wakeups: %ld\n", sched->multitarget_wakeups); 1764 printf("multi-target wakeups: %ld\n", multitarget_wakeups);
1594 if (sched->nr_run_events_optimized) 1765 if (nr_run_events_optimized)
1595 printf("run atoms optimized: %ld\n", 1766 printf("run atoms optimized: %ld\n",
1596 sched->nr_run_events_optimized); 1767 nr_run_events_optimized);
1597 1768
1598 print_task_traces(sched); 1769 print_task_traces();
1599 add_cross_task_wakeups(sched); 1770 add_cross_task_wakeups();
1600 1771
1601 create_tasks(sched); 1772 create_tasks();
1602 printf("------------------------------------------------------------\n"); 1773 printf("------------------------------------------------------------\n");
1603 for (i = 0; i < sched->replay_repeat; i++) 1774 for (i = 0; i < replay_repeat; i++)
1604 run_one_test(sched); 1775 run_one_test();
1605
1606 return 0;
1607} 1776}
1608 1777
1609static void setup_sorting(struct perf_sched *sched, const struct option *options, 1778
1610 const char * const usage_msg[]) 1779static const char * const sched_usage[] = {
1780 "perf sched [<options>] {record|latency|map|replay|script}",
1781 NULL
1782};
1783
1784static const struct option sched_options[] = {
1785 OPT_STRING('i', "input", &input_name, "file",
1786 "input file name"),
1787 OPT_INCR('v', "verbose", &verbose,
1788 "be more verbose (show symbol address, etc)"),
1789 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1790 "dump raw trace in ASCII"),
1791 OPT_END()
1792};
1793
1794static const char * const latency_usage[] = {
1795 "perf sched latency [<options>]",
1796 NULL
1797};
1798
1799static const struct option latency_options[] = {
1800 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1801 "sort by key(s): runtime, switch, avg, max"),
1802 OPT_INCR('v', "verbose", &verbose,
1803 "be more verbose (show symbol address, etc)"),
1804 OPT_INTEGER('C', "CPU", &profile_cpu,
1805 "CPU to profile on"),
1806 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1807 "dump raw trace in ASCII"),
1808 OPT_END()
1809};
1810
1811static const char * const replay_usage[] = {
1812 "perf sched replay [<options>]",
1813 NULL
1814};
1815
1816static const struct option replay_options[] = {
1817 OPT_UINTEGER('r', "repeat", &replay_repeat,
1818 "repeat the workload replay N times (-1: infinite)"),
1819 OPT_INCR('v', "verbose", &verbose,
1820 "be more verbose (show symbol address, etc)"),
1821 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1822 "dump raw trace in ASCII"),
1823 OPT_END()
1824};
1825
1826static void setup_sorting(void)
1611{ 1827{
1612 char *tmp, *tok, *str = strdup(sched->sort_order); 1828 char *tmp, *tok, *str = strdup(sort_order);
1613 1829
1614 for (tok = strtok_r(str, ", ", &tmp); 1830 for (tok = strtok_r(str, ", ", &tmp);
1615 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1831 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1616 if (sort_dimension__add(tok, &sched->sort_list) < 0) { 1832 if (sort_dimension__add(tok, &sort_list) < 0) {
1617 error("Unknown --sort key: `%s'", tok); 1833 error("Unknown --sort key: `%s'", tok);
1618 usage_with_options(usage_msg, options); 1834 usage_with_options(latency_usage, latency_options);
1619 } 1835 }
1620 } 1836 }
1621 1837
1622 free(str); 1838 free(str);
1623 1839
1624 sort_dimension__add("pid", &sched->cmp_pid); 1840 sort_dimension__add("pid", &cmp_pid);
1625} 1841}
1626 1842
1843static const char *record_args[] = {
1844 "record",
1845 "-a",
1846 "-R",
1847 "-f",
1848 "-m", "1024",
1849 "-c", "1",
1850 "-e", "sched:sched_switch",
1851 "-e", "sched:sched_stat_wait",
1852 "-e", "sched:sched_stat_sleep",
1853 "-e", "sched:sched_stat_iowait",
1854 "-e", "sched:sched_stat_runtime",
1855 "-e", "sched:sched_process_exit",
1856 "-e", "sched:sched_process_fork",
1857 "-e", "sched:sched_wakeup",
1858 "-e", "sched:sched_migrate_task",
1859};
1860
1627static int __cmd_record(int argc, const char **argv) 1861static int __cmd_record(int argc, const char **argv)
1628{ 1862{
1629 unsigned int rec_argc, i, j; 1863 unsigned int rec_argc, i, j;
1630 const char **rec_argv; 1864 const char **rec_argv;
1631 const char * const record_args[] = {
1632 "record",
1633 "-a",
1634 "-R",
1635 "-f",
1636 "-m", "1024",
1637 "-c", "1",
1638 "-e", "sched:sched_switch",
1639 "-e", "sched:sched_stat_wait",
1640 "-e", "sched:sched_stat_sleep",
1641 "-e", "sched:sched_stat_iowait",
1642 "-e", "sched:sched_stat_runtime",
1643 "-e", "sched:sched_process_exit",
1644 "-e", "sched:sched_process_fork",
1645 "-e", "sched:sched_wakeup",
1646 "-e", "sched:sched_migrate_task",
1647 };
1648 1865
1649 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 1866 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1650 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1867 rec_argv = calloc(rec_argc + 1, sizeof(char *));
@@ -1663,86 +1880,8 @@ static int __cmd_record(int argc, const char **argv)
1663 return cmd_record(i, rec_argv, NULL); 1880 return cmd_record(i, rec_argv, NULL);
1664} 1881}
1665 1882
1666int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) 1883int cmd_sched(int argc, const char **argv, const char *prefix __used)
1667{ 1884{
1668 const char default_sort_order[] = "avg, max, switch, runtime";
1669 struct perf_sched sched = {
1670 .tool = {
1671 .sample = perf_sched__process_tracepoint_sample,
1672 .comm = perf_event__process_comm,
1673 .lost = perf_event__process_lost,
1674 .exit = perf_event__process_exit,
1675 .fork = perf_event__process_fork,
1676 .ordered_samples = true,
1677 },
1678 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
1679 .sort_list = LIST_HEAD_INIT(sched.sort_list),
1680 .start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
1681 .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
1682 .curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
1683 .sort_order = default_sort_order,
1684 .replay_repeat = 10,
1685 .profile_cpu = -1,
1686 .next_shortname1 = 'A',
1687 .next_shortname2 = '0',
1688 };
1689 const struct option latency_options[] = {
1690 OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
1691 "sort by key(s): runtime, switch, avg, max"),
1692 OPT_INCR('v', "verbose", &verbose,
1693 "be more verbose (show symbol address, etc)"),
1694 OPT_INTEGER('C', "CPU", &sched.profile_cpu,
1695 "CPU to profile on"),
1696 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1697 "dump raw trace in ASCII"),
1698 OPT_END()
1699 };
1700 const struct option replay_options[] = {
1701 OPT_UINTEGER('r', "repeat", &sched.replay_repeat,
1702 "repeat the workload replay N times (-1: infinite)"),
1703 OPT_INCR('v', "verbose", &verbose,
1704 "be more verbose (show symbol address, etc)"),
1705 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1706 "dump raw trace in ASCII"),
1707 OPT_END()
1708 };
1709 const struct option sched_options[] = {
1710 OPT_STRING('i', "input", &input_name, "file",
1711 "input file name"),
1712 OPT_INCR('v', "verbose", &verbose,
1713 "be more verbose (show symbol address, etc)"),
1714 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1715 "dump raw trace in ASCII"),
1716 OPT_END()
1717 };
1718 const char * const latency_usage[] = {
1719 "perf sched latency [<options>]",
1720 NULL
1721 };
1722 const char * const replay_usage[] = {
1723 "perf sched replay [<options>]",
1724 NULL
1725 };
1726 const char * const sched_usage[] = {
1727 "perf sched [<options>] {record|latency|map|replay|script}",
1728 NULL
1729 };
1730 struct trace_sched_handler lat_ops = {
1731 .wakeup_event = latency_wakeup_event,
1732 .switch_event = latency_switch_event,
1733 .runtime_event = latency_runtime_event,
1734 .fork_event = latency_fork_event,
1735 .migrate_task_event = latency_migrate_task_event,
1736 };
1737 struct trace_sched_handler map_ops = {
1738 .switch_event = map_switch_event,
1739 };
1740 struct trace_sched_handler replay_ops = {
1741 .wakeup_event = replay_wakeup_event,
1742 .switch_event = replay_switch_event,
1743 .fork_event = replay_fork_event,
1744 };
1745
1746 argc = parse_options(argc, argv, sched_options, sched_usage, 1885 argc = parse_options(argc, argv, sched_options, sched_usage,
1747 PARSE_OPT_STOP_AT_NON_OPTION); 1886 PARSE_OPT_STOP_AT_NON_OPTION);
1748 if (!argc) 1887 if (!argc)
@@ -1758,26 +1897,26 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1758 if (!strncmp(argv[0], "rec", 3)) { 1897 if (!strncmp(argv[0], "rec", 3)) {
1759 return __cmd_record(argc, argv); 1898 return __cmd_record(argc, argv);
1760 } else if (!strncmp(argv[0], "lat", 3)) { 1899 } else if (!strncmp(argv[0], "lat", 3)) {
1761 sched.tp_handler = &lat_ops; 1900 trace_handler = &lat_ops;
1762 if (argc > 1) { 1901 if (argc > 1) {
1763 argc = parse_options(argc, argv, latency_options, latency_usage, 0); 1902 argc = parse_options(argc, argv, latency_options, latency_usage, 0);
1764 if (argc) 1903 if (argc)
1765 usage_with_options(latency_usage, latency_options); 1904 usage_with_options(latency_usage, latency_options);
1766 } 1905 }
1767 setup_sorting(&sched, latency_options, latency_usage); 1906 setup_sorting();
1768 return perf_sched__lat(&sched); 1907 __cmd_lat();
1769 } else if (!strcmp(argv[0], "map")) { 1908 } else if (!strcmp(argv[0], "map")) {
1770 sched.tp_handler = &map_ops; 1909 trace_handler = &map_ops;
1771 setup_sorting(&sched, latency_options, latency_usage); 1910 setup_sorting();
1772 return perf_sched__map(&sched); 1911 __cmd_map();
1773 } else if (!strncmp(argv[0], "rep", 3)) { 1912 } else if (!strncmp(argv[0], "rep", 3)) {
1774 sched.tp_handler = &replay_ops; 1913 trace_handler = &replay_ops;
1775 if (argc) { 1914 if (argc) {
1776 argc = parse_options(argc, argv, replay_options, replay_usage, 0); 1915 argc = parse_options(argc, argv, replay_options, replay_usage, 0);
1777 if (argc) 1916 if (argc)
1778 usage_with_options(replay_usage, replay_options); 1917 usage_with_options(replay_usage, replay_options);
1779 } 1918 }
1780 return perf_sched__replay(&sched); 1919 __cmd_replay();
1781 } else { 1920 } else {
1782 usage_with_options(sched_usage, sched_options); 1921 usage_with_options(sched_usage, sched_options);
1783 } 1922 }
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b363e7b292b..09024ec2ab2 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -7,14 +7,12 @@
7#include "util/header.h" 7#include "util/header.h"
8#include "util/parse-options.h" 8#include "util/parse-options.h"
9#include "util/session.h" 9#include "util/session.h"
10#include "util/tool.h"
11#include "util/symbol.h" 10#include "util/symbol.h"
12#include "util/thread.h" 11#include "util/thread.h"
13#include "util/trace-event.h" 12#include "util/trace-event.h"
14#include "util/util.h" 13#include "util/util.h"
15#include "util/evlist.h" 14#include "util/evlist.h"
16#include "util/evsel.h" 15#include "util/evsel.h"
17#include "util/sort.h"
18#include <linux/bitmap.h> 16#include <linux/bitmap.h>
19 17
20static char const *script_name; 18static char const *script_name;
@@ -24,7 +22,6 @@ static u64 last_timestamp;
24static u64 nr_unordered; 22static u64 nr_unordered;
25extern const struct option record_options[]; 23extern const struct option record_options[];
26static bool no_callchain; 24static bool no_callchain;
27static bool system_wide;
28static const char *cpu_list; 25static const char *cpu_list;
29static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 26static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
30 27
@@ -40,7 +37,6 @@ enum perf_output_field {
40 PERF_OUTPUT_SYM = 1U << 8, 37 PERF_OUTPUT_SYM = 1U << 8,
41 PERF_OUTPUT_DSO = 1U << 9, 38 PERF_OUTPUT_DSO = 1U << 9,
42 PERF_OUTPUT_ADDR = 1U << 10, 39 PERF_OUTPUT_ADDR = 1U << 10,
43 PERF_OUTPUT_SYMOFFSET = 1U << 11,
44}; 40};
45 41
46struct output_option { 42struct output_option {
@@ -58,7 +54,6 @@ struct output_option {
58 {.str = "sym", .field = PERF_OUTPUT_SYM}, 54 {.str = "sym", .field = PERF_OUTPUT_SYM},
59 {.str = "dso", .field = PERF_OUTPUT_DSO}, 55 {.str = "dso", .field = PERF_OUTPUT_DSO},
60 {.str = "addr", .field = PERF_OUTPUT_ADDR}, 56 {.str = "addr", .field = PERF_OUTPUT_ADDR},
61 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
62}; 57};
63 58
64/* default set to maintain compatibility with current format */ 59/* default set to maintain compatibility with current format */
@@ -137,11 +132,10 @@ static const char *output_field2str(enum perf_output_field field)
137 132
138#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) 133#define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x)
139 134
140static int perf_evsel__check_stype(struct perf_evsel *evsel, 135static int perf_event_attr__check_stype(struct perf_event_attr *attr,
141 u64 sample_type, const char *sample_msg, 136 u64 sample_type, const char *sample_msg,
142 enum perf_output_field field) 137 enum perf_output_field field)
143{ 138{
144 struct perf_event_attr *attr = &evsel->attr;
145 int type = attr->type; 139 int type = attr->type;
146 const char *evname; 140 const char *evname;
147 141
@@ -149,7 +143,7 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
149 return 0; 143 return 0;
150 144
151 if (output[type].user_set) { 145 if (output[type].user_set) {
152 evname = perf_evsel__name(evsel); 146 evname = __event_name(attr->type, attr->config);
153 pr_err("Samples for '%s' event do not have %s attribute set. " 147 pr_err("Samples for '%s' event do not have %s attribute set. "
154 "Cannot print '%s' field.\n", 148 "Cannot print '%s' field.\n",
155 evname, sample_msg, output_field2str(field)); 149 evname, sample_msg, output_field2str(field));
@@ -158,7 +152,7 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
158 152
159 /* user did not ask for it explicitly so remove from the default list */ 153 /* user did not ask for it explicitly so remove from the default list */
160 output[type].fields &= ~field; 154 output[type].fields &= ~field;
161 evname = perf_evsel__name(evsel); 155 evname = __event_name(attr->type, attr->config);
162 pr_debug("Samples for '%s' event do not have %s attribute set. " 156 pr_debug("Samples for '%s' event do not have %s attribute set. "
163 "Skipping '%s' field.\n", 157 "Skipping '%s' field.\n",
164 evname, sample_msg, output_field2str(field)); 158 evname, sample_msg, output_field2str(field));
@@ -176,8 +170,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
176 return -EINVAL; 170 return -EINVAL;
177 171
178 if (PRINT_FIELD(IP)) { 172 if (PRINT_FIELD(IP)) {
179 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", 173 if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
180 PERF_OUTPUT_IP)) 174 PERF_OUTPUT_IP))
181 return -EINVAL; 175 return -EINVAL;
182 176
183 if (!no_callchain && 177 if (!no_callchain &&
@@ -186,8 +180,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
186 } 180 }
187 181
188 if (PRINT_FIELD(ADDR) && 182 if (PRINT_FIELD(ADDR) &&
189 perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", 183 perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
190 PERF_OUTPUT_ADDR)) 184 PERF_OUTPUT_ADDR))
191 return -EINVAL; 185 return -EINVAL;
192 186
193 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 187 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
@@ -196,11 +190,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
196 "to symbols.\n"); 190 "to symbols.\n");
197 return -EINVAL; 191 return -EINVAL;
198 } 192 }
199 if (PRINT_FIELD(SYMOFFSET) && !PRINT_FIELD(SYM)) {
200 pr_err("Display of offsets requested but symbol is not"
201 "selected.\n");
202 return -EINVAL;
203 }
204 if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 193 if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
205 pr_err("Display of DSO requested but neither sample IP nor " 194 pr_err("Display of DSO requested but neither sample IP nor "
206 "sample address\nis selected. Hence, no addresses to convert " 195 "sample address\nis selected. Hence, no addresses to convert "
@@ -209,18 +198,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
209 } 198 }
210 199
211 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 200 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
212 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", 201 perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
213 PERF_OUTPUT_TID|PERF_OUTPUT_PID)) 202 PERF_OUTPUT_TID|PERF_OUTPUT_PID))
214 return -EINVAL; 203 return -EINVAL;
215 204
216 if (PRINT_FIELD(TIME) && 205 if (PRINT_FIELD(TIME) &&
217 perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME", 206 perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
218 PERF_OUTPUT_TIME)) 207 PERF_OUTPUT_TIME))
219 return -EINVAL; 208 return -EINVAL;
220 209
221 if (PRINT_FIELD(CPU) && 210 if (PRINT_FIELD(CPU) &&
222 perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU", 211 perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
223 PERF_OUTPUT_CPU)) 212 PERF_OUTPUT_CPU))
224 return -EINVAL; 213 return -EINVAL;
225 214
226 return 0; 215 return 0;
@@ -259,9 +248,10 @@ static int perf_session__check_output_opt(struct perf_session *session)
259 248
260static void print_sample_start(struct perf_sample *sample, 249static void print_sample_start(struct perf_sample *sample,
261 struct thread *thread, 250 struct thread *thread,
262 struct perf_evsel *evsel) 251 struct perf_event_attr *attr)
263{ 252{
264 struct perf_event_attr *attr = &evsel->attr; 253 int type;
254 struct event *event;
265 const char *evname = NULL; 255 const char *evname = NULL;
266 unsigned long secs; 256 unsigned long secs;
267 unsigned long usecs; 257 unsigned long usecs;
@@ -299,18 +289,18 @@ static void print_sample_start(struct perf_sample *sample,
299 } 289 }
300 290
301 if (PRINT_FIELD(EVNAME)) { 291 if (PRINT_FIELD(EVNAME)) {
302 evname = perf_evsel__name(evsel); 292 if (attr->type == PERF_TYPE_TRACEPOINT) {
303 printf("%s: ", evname ? evname : "[unknown]"); 293 type = trace_parse_common_type(sample->raw_data);
294 event = trace_find_event(type);
295 if (event)
296 evname = event->name;
297 } else
298 evname = __event_name(attr->type, attr->config);
299
300 printf("%s: ", evname ? evname : "(unknown)");
304 } 301 }
305} 302}
306 303
307static bool is_bts_event(struct perf_event_attr *attr)
308{
309 return ((attr->type == PERF_TYPE_HARDWARE) &&
310 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
311 (attr->sample_period == 1));
312}
313
314static bool sample_addr_correlates_sym(struct perf_event_attr *attr) 304static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
315{ 305{
316 if ((attr->type == PERF_TYPE_SOFTWARE) && 306 if ((attr->type == PERF_TYPE_SOFTWARE) &&
@@ -319,31 +309,29 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
319 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))) 309 (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
320 return true; 310 return true;
321 311
322 if (is_bts_event(attr))
323 return true;
324
325 return false; 312 return false;
326} 313}
327 314
328static void print_sample_addr(union perf_event *event, 315static void print_sample_addr(union perf_event *event,
329 struct perf_sample *sample, 316 struct perf_sample *sample,
330 struct machine *machine, 317 struct perf_session *session,
331 struct thread *thread, 318 struct thread *thread,
332 struct perf_event_attr *attr) 319 struct perf_event_attr *attr)
333{ 320{
334 struct addr_location al; 321 struct addr_location al;
335 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 322 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
323 const char *symname, *dsoname;
336 324
337 printf("%16" PRIx64, sample->addr); 325 printf("%16" PRIx64, sample->addr);
338 326
339 if (!sample_addr_correlates_sym(attr)) 327 if (!sample_addr_correlates_sym(attr))
340 return; 328 return;
341 329
342 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 330 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
343 sample->addr, &al); 331 event->ip.pid, sample->addr, &al);
344 if (!al.map) 332 if (!al.map)
345 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, 333 thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE,
346 sample->addr, &al); 334 event->ip.pid, sample->addr, &al);
347 335
348 al.cpu = sample->cpu; 336 al.cpu = sample->cpu;
349 al.sym = NULL; 337 al.sym = NULL;
@@ -352,87 +340,59 @@ static void print_sample_addr(union perf_event *event,
352 al.sym = map__find_symbol(al.map, al.addr, NULL); 340 al.sym = map__find_symbol(al.map, al.addr, NULL);
353 341
354 if (PRINT_FIELD(SYM)) { 342 if (PRINT_FIELD(SYM)) {
355 printf(" "); 343 if (al.sym && al.sym->name)
356 if (PRINT_FIELD(SYMOFFSET)) 344 symname = al.sym->name;
357 symbol__fprintf_symname_offs(al.sym, &al, stdout);
358 else 345 else
359 symbol__fprintf_symname(al.sym, stdout); 346 symname = "";
360 }
361 347
362 if (PRINT_FIELD(DSO)) { 348 printf(" %16s", symname);
363 printf(" (");
364 map__fprintf_dsoname(al.map, stdout);
365 printf(")");
366 } 349 }
367}
368 350
369static void print_sample_bts(union perf_event *event, 351 if (PRINT_FIELD(DSO)) {
370 struct perf_sample *sample, 352 if (al.map && al.map->dso && al.map->dso->name)
371 struct perf_evsel *evsel, 353 dsoname = al.map->dso->name;
372 struct machine *machine,
373 struct thread *thread)
374{
375 struct perf_event_attr *attr = &evsel->attr;
376
377 /* print branch_from information */
378 if (PRINT_FIELD(IP)) {
379 if (!symbol_conf.use_callchain)
380 printf(" ");
381 else 354 else
382 printf("\n"); 355 dsoname = "";
383 perf_evsel__print_ip(evsel, event, sample, machine,
384 PRINT_FIELD(SYM), PRINT_FIELD(DSO),
385 PRINT_FIELD(SYMOFFSET));
386 }
387
388 printf(" => ");
389
390 /* print branch_to information */
391 if (PRINT_FIELD(ADDR))
392 print_sample_addr(event, sample, machine, thread, attr);
393 356
394 printf("\n"); 357 printf(" (%s)", dsoname);
358 }
395} 359}
396 360
397static void process_event(union perf_event *event, struct perf_sample *sample, 361static void process_event(union perf_event *event __unused,
398 struct perf_evsel *evsel, struct machine *machine, 362 struct perf_sample *sample,
399 struct addr_location *al) 363 struct perf_evsel *evsel,
364 struct perf_session *session,
365 struct thread *thread)
400{ 366{
401 struct perf_event_attr *attr = &evsel->attr; 367 struct perf_event_attr *attr = &evsel->attr;
402 struct thread *thread = al->thread;
403 368
404 if (output[attr->type].fields == 0) 369 if (output[attr->type].fields == 0)
405 return; 370 return;
406 371
407 print_sample_start(sample, thread, evsel); 372 print_sample_start(sample, thread, attr);
408
409 if (is_bts_event(attr)) {
410 print_sample_bts(event, sample, evsel, machine, thread);
411 return;
412 }
413 373
414 if (PRINT_FIELD(TRACE)) 374 if (PRINT_FIELD(TRACE))
415 event_format__print(evsel->tp_format, sample->cpu, 375 print_trace_event(sample->cpu, sample->raw_data,
416 sample->raw_data, sample->raw_size); 376 sample->raw_size);
377
417 if (PRINT_FIELD(ADDR)) 378 if (PRINT_FIELD(ADDR))
418 print_sample_addr(event, sample, machine, thread, attr); 379 print_sample_addr(event, sample, session, thread, attr);
419 380
420 if (PRINT_FIELD(IP)) { 381 if (PRINT_FIELD(IP)) {
421 if (!symbol_conf.use_callchain) 382 if (!symbol_conf.use_callchain)
422 printf(" "); 383 printf(" ");
423 else 384 else
424 printf("\n"); 385 printf("\n");
425 perf_evsel__print_ip(evsel, event, sample, machine, 386 perf_session__print_ip(event, sample, session,
426 PRINT_FIELD(SYM), PRINT_FIELD(DSO), 387 PRINT_FIELD(SYM), PRINT_FIELD(DSO));
427 PRINT_FIELD(SYMOFFSET));
428 } 388 }
429 389
430 printf("\n"); 390 printf("\n");
431} 391}
432 392
433static int default_start_script(const char *script __maybe_unused, 393static int default_start_script(const char *script __unused,
434 int argc __maybe_unused, 394 int argc __unused,
435 const char **argv __maybe_unused) 395 const char **argv __unused)
436{ 396{
437 return 0; 397 return 0;
438} 398}
@@ -442,8 +402,7 @@ static int default_stop_script(void)
442 return 0; 402 return 0;
443} 403}
444 404
445static int default_generate_script(struct pevent *pevent __maybe_unused, 405static int default_generate_script(const char *outfile __unused)
446 const char *outfile __maybe_unused)
447{ 406{
448 return 0; 407 return 0;
449} 408}
@@ -472,14 +431,14 @@ static int cleanup_scripting(void)
472 return scripting_ops->stop_script(); 431 return scripting_ops->stop_script();
473} 432}
474 433
475static int process_sample_event(struct perf_tool *tool __maybe_unused, 434static char const *input_name = "perf.data";
476 union perf_event *event, 435
436static int process_sample_event(union perf_event *event,
477 struct perf_sample *sample, 437 struct perf_sample *sample,
478 struct perf_evsel *evsel, 438 struct perf_evsel *evsel,
479 struct machine *machine) 439 struct perf_session *session)
480{ 440{
481 struct addr_location al; 441 struct thread *thread = perf_session__findnew(session, event->ip.pid);
482 struct thread *thread = machine__findnew_thread(machine, event->ip.tid);
483 442
484 if (thread == NULL) { 443 if (thread == NULL) {
485 pr_debug("problem processing %d event, skipping it.\n", 444 pr_debug("problem processing %d event, skipping it.\n",
@@ -498,30 +457,21 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
498 return 0; 457 return 0;
499 } 458 }
500 459
501 if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) {
502 pr_err("problem processing %d event, skipping it.\n",
503 event->header.type);
504 return -1;
505 }
506
507 if (al.filtered)
508 return 0;
509
510 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 460 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
511 return 0; 461 return 0;
512 462
513 scripting_ops->process_event(event, sample, evsel, machine, &al); 463 scripting_ops->process_event(event, sample, evsel, session, thread);
514 464
515 evsel->hists.stats.total_period += sample->period; 465 session->hists.stats.total_period += sample->period;
516 return 0; 466 return 0;
517} 467}
518 468
519static struct perf_tool perf_script = { 469static struct perf_event_ops event_ops = {
520 .sample = process_sample_event, 470 .sample = process_sample_event,
521 .mmap = perf_event__process_mmap, 471 .mmap = perf_event__process_mmap,
522 .comm = perf_event__process_comm, 472 .comm = perf_event__process_comm,
523 .exit = perf_event__process_exit, 473 .exit = perf_event__process_task,
524 .fork = perf_event__process_fork, 474 .fork = perf_event__process_task,
525 .attr = perf_event__process_attr, 475 .attr = perf_event__process_attr,
526 .event_type = perf_event__process_event_type, 476 .event_type = perf_event__process_event_type,
527 .tracing_data = perf_event__process_tracing_data, 477 .tracing_data = perf_event__process_tracing_data,
@@ -532,7 +482,7 @@ static struct perf_tool perf_script = {
532 482
533extern volatile int session_done; 483extern volatile int session_done;
534 484
535static void sig_handler(int sig __maybe_unused) 485static void sig_handler(int sig __unused)
536{ 486{
537 session_done = 1; 487 session_done = 1;
538} 488}
@@ -543,7 +493,7 @@ static int __cmd_script(struct perf_session *session)
543 493
544 signal(SIGINT, sig_handler); 494 signal(SIGINT, sig_handler);
545 495
546 ret = perf_session__process_events(session, &perf_script); 496 ret = perf_session__process_events(session, &event_ops);
547 497
548 if (debug_mode) 498 if (debug_mode)
549 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); 499 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -572,6 +522,12 @@ static struct script_spec *script_spec__new(const char *spec,
572 return s; 522 return s;
573} 523}
574 524
525static void script_spec__delete(struct script_spec *s)
526{
527 free(s->spec);
528 free(s);
529}
530
575static void script_spec__add(struct script_spec *s) 531static void script_spec__add(struct script_spec *s)
576{ 532{
577 list_add_tail(&s->node, &script_specs); 533 list_add_tail(&s->node, &script_specs);
@@ -597,11 +553,16 @@ static struct script_spec *script_spec__findnew(const char *spec,
597 553
598 s = script_spec__new(spec, ops); 554 s = script_spec__new(spec, ops);
599 if (!s) 555 if (!s)
600 return NULL; 556 goto out_delete_spec;
601 557
602 script_spec__add(s); 558 script_spec__add(s);
603 559
604 return s; 560 return s;
561
562out_delete_spec:
563 script_spec__delete(s);
564
565 return NULL;
605} 566}
606 567
607int script_spec_register(const char *spec, struct scripting_ops *ops) 568int script_spec_register(const char *spec, struct scripting_ops *ops)
@@ -642,8 +603,8 @@ static void list_available_languages(void)
642 fprintf(stderr, "\n"); 603 fprintf(stderr, "\n");
643} 604}
644 605
645static int parse_scriptname(const struct option *opt __maybe_unused, 606static int parse_scriptname(const struct option *opt __used,
646 const char *str, int unset __maybe_unused) 607 const char *str, int unset __used)
647{ 608{
648 char spec[PATH_MAX]; 609 char spec[PATH_MAX];
649 const char *script, *ext; 610 const char *script, *ext;
@@ -688,8 +649,8 @@ static int parse_scriptname(const struct option *opt __maybe_unused,
688 return 0; 649 return 0;
689} 650}
690 651
691static int parse_output_fields(const struct option *opt __maybe_unused, 652static int parse_output_fields(const struct option *opt __used,
692 const char *arg, int unset __maybe_unused) 653 const char *arg, int unset __used)
693{ 654{
694 char *tok; 655 char *tok;
695 int i, imax = sizeof(all_output_options) / sizeof(struct output_option); 656 int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
@@ -719,8 +680,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
719 type = PERF_TYPE_RAW; 680 type = PERF_TYPE_RAW;
720 else { 681 else {
721 fprintf(stderr, "Invalid event type in field string.\n"); 682 fprintf(stderr, "Invalid event type in field string.\n");
722 rc = -EINVAL; 683 return -EINVAL;
723 goto out;
724 } 684 }
725 685
726 if (output[type].user_set) 686 if (output[type].user_set)
@@ -962,27 +922,8 @@ static int read_script_info(struct script_desc *desc, const char *filename)
962 return 0; 922 return 0;
963} 923}
964 924
965static char *get_script_root(struct dirent *script_dirent, const char *suffix) 925static int list_available_scripts(const struct option *opt __used,
966{ 926 const char *s __used, int unset __used)
967 char *script_root, *str;
968
969 script_root = strdup(script_dirent->d_name);
970 if (!script_root)
971 return NULL;
972
973 str = (char *)ends_with(script_root, suffix);
974 if (!str) {
975 free(script_root);
976 return NULL;
977 }
978
979 *str = '\0';
980 return script_root;
981}
982
983static int list_available_scripts(const struct option *opt __maybe_unused,
984 const char *s __maybe_unused,
985 int unset __maybe_unused)
986{ 927{
987 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 928 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
988 char scripts_path[MAXPATHLEN]; 929 char scripts_path[MAXPATHLEN];
@@ -992,6 +933,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
992 struct script_desc *desc; 933 struct script_desc *desc;
993 char first_half[BUFSIZ]; 934 char first_half[BUFSIZ];
994 char *script_root; 935 char *script_root;
936 char *str;
995 937
996 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 938 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
997 939
@@ -1007,14 +949,16 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1007 continue; 949 continue;
1008 950
1009 for_each_script(lang_path, lang_dir, script_dirent, script_next) { 951 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
1010 script_root = get_script_root(&script_dirent, REPORT_SUFFIX); 952 script_root = strdup(script_dirent.d_name);
1011 if (script_root) { 953 str = (char *)ends_with(script_root, REPORT_SUFFIX);
954 if (str) {
955 *str = '\0';
1012 desc = script_desc__findnew(script_root); 956 desc = script_desc__findnew(script_root);
1013 snprintf(script_path, MAXPATHLEN, "%s/%s", 957 snprintf(script_path, MAXPATHLEN, "%s/%s",
1014 lang_path, script_dirent.d_name); 958 lang_path, script_dirent.d_name);
1015 read_script_info(desc, script_path); 959 read_script_info(desc, script_path);
1016 free(script_root);
1017 } 960 }
961 free(script_root);
1018 } 962 }
1019 } 963 }
1020 964
@@ -1029,137 +973,6 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1029 exit(0); 973 exit(0);
1030} 974}
1031 975
1032/*
1033 * Some scripts specify the required events in their "xxx-record" file,
1034 * this function will check if the events in perf.data match those
1035 * mentioned in the "xxx-record".
1036 *
1037 * Fixme: All existing "xxx-record" are all in good formats "-e event ",
1038 * which is covered well now. And new parsing code should be added to
1039 * cover the future complexing formats like event groups etc.
1040 */
1041static int check_ev_match(char *dir_name, char *scriptname,
1042 struct perf_session *session)
1043{
1044 char filename[MAXPATHLEN], evname[128];
1045 char line[BUFSIZ], *p;
1046 struct perf_evsel *pos;
1047 int match, len;
1048 FILE *fp;
1049
1050 sprintf(filename, "%s/bin/%s-record", dir_name, scriptname);
1051
1052 fp = fopen(filename, "r");
1053 if (!fp)
1054 return -1;
1055
1056 while (fgets(line, sizeof(line), fp)) {
1057 p = ltrim(line);
1058 if (*p == '#')
1059 continue;
1060
1061 while (strlen(p)) {
1062 p = strstr(p, "-e");
1063 if (!p)
1064 break;
1065
1066 p += 2;
1067 p = ltrim(p);
1068 len = strcspn(p, " \t");
1069 if (!len)
1070 break;
1071
1072 snprintf(evname, len + 1, "%s", p);
1073
1074 match = 0;
1075 list_for_each_entry(pos,
1076 &session->evlist->entries, node) {
1077 if (!strcmp(perf_evsel__name(pos), evname)) {
1078 match = 1;
1079 break;
1080 }
1081 }
1082
1083 if (!match) {
1084 fclose(fp);
1085 return -1;
1086 }
1087 }
1088 }
1089
1090 fclose(fp);
1091 return 0;
1092}
1093
1094/*
1095 * Return -1 if none is found, otherwise the actual scripts number.
1096 *
1097 * Currently the only user of this function is the script browser, which
1098 * will list all statically runnable scripts, select one, execute it and
1099 * show the output in a perf browser.
1100 */
1101int find_scripts(char **scripts_array, char **scripts_path_array)
1102{
1103 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
1104 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
1105 DIR *scripts_dir, *lang_dir;
1106 struct perf_session *session;
1107 char *temp;
1108 int i = 0;
1109
1110 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
1111 if (!session)
1112 return -1;
1113
1114 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
1115
1116 scripts_dir = opendir(scripts_path);
1117 if (!scripts_dir) {
1118 perf_session__delete(session);
1119 return -1;
1120 }
1121
1122 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
1123 snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path,
1124 lang_dirent.d_name);
1125#ifdef NO_LIBPERL
1126 if (strstr(lang_path, "perl"))
1127 continue;
1128#endif
1129#ifdef NO_LIBPYTHON
1130 if (strstr(lang_path, "python"))
1131 continue;
1132#endif
1133
1134 lang_dir = opendir(lang_path);
1135 if (!lang_dir)
1136 continue;
1137
1138 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
1139 /* Skip those real time scripts: xxxtop.p[yl] */
1140 if (strstr(script_dirent.d_name, "top."))
1141 continue;
1142 sprintf(scripts_path_array[i], "%s/%s", lang_path,
1143 script_dirent.d_name);
1144 temp = strchr(script_dirent.d_name, '.');
1145 snprintf(scripts_array[i],
1146 (temp - script_dirent.d_name) + 1,
1147 "%s", script_dirent.d_name);
1148
1149 if (check_ev_match(lang_path,
1150 scripts_array[i], session))
1151 continue;
1152
1153 i++;
1154 }
1155 closedir(lang_dir);
1156 }
1157
1158 closedir(scripts_dir);
1159 perf_session__delete(session);
1160 return i;
1161}
1162
1163static char *get_script_path(const char *script_root, const char *suffix) 976static char *get_script_path(const char *script_root, const char *suffix)
1164{ 977{
1165 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 978 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
@@ -1167,7 +980,8 @@ static char *get_script_path(const char *script_root, const char *suffix)
1167 char script_path[MAXPATHLEN]; 980 char script_path[MAXPATHLEN];
1168 DIR *scripts_dir, *lang_dir; 981 DIR *scripts_dir, *lang_dir;
1169 char lang_path[MAXPATHLEN]; 982 char lang_path[MAXPATHLEN];
1170 char *__script_root; 983 char *str, *__script_root;
984 char *path = NULL;
1171 985
1172 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 986 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
1173 987
@@ -1183,22 +997,23 @@ static char *get_script_path(const char *script_root, const char *suffix)
1183 continue; 997 continue;
1184 998
1185 for_each_script(lang_path, lang_dir, script_dirent, script_next) { 999 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
1186 __script_root = get_script_root(&script_dirent, suffix); 1000 __script_root = strdup(script_dirent.d_name);
1187 if (__script_root && !strcmp(script_root, __script_root)) { 1001 str = (char *)ends_with(__script_root, suffix);
1188 free(__script_root); 1002 if (str) {
1189 closedir(lang_dir); 1003 *str = '\0';
1190 closedir(scripts_dir); 1004 if (strcmp(__script_root, script_root))
1005 continue;
1191 snprintf(script_path, MAXPATHLEN, "%s/%s", 1006 snprintf(script_path, MAXPATHLEN, "%s/%s",
1192 lang_path, script_dirent.d_name); 1007 lang_path, script_dirent.d_name);
1193 return strdup(script_path); 1008 path = strdup(script_path);
1009 free(__script_root);
1010 break;
1194 } 1011 }
1195 free(__script_root); 1012 free(__script_root);
1196 } 1013 }
1197 closedir(lang_dir);
1198 } 1014 }
1199 closedir(scripts_dir);
1200 1015
1201 return NULL; 1016 return path;
1202} 1017}
1203 1018
1204static bool is_top_script(const char *script_path) 1019static bool is_top_script(const char *script_path)
@@ -1229,39 +1044,20 @@ out:
1229 return n_args; 1044 return n_args;
1230} 1045}
1231 1046
1232static int have_cmd(int argc, const char **argv) 1047static const char * const script_usage[] = {
1233{ 1048 "perf script [<options>]",
1234 char **__argv = malloc(sizeof(const char *) * argc); 1049 "perf script [<options>] record <script> [<record-options>] <command>",
1235 1050 "perf script [<options>] report <script> [script-args]",
1236 if (!__argv) { 1051 "perf script [<options>] <script> [<record-options>] <command>",
1237 pr_err("malloc failed\n"); 1052 "perf script [<options>] <top-script> [script-args]",
1238 return -1; 1053 NULL
1239 } 1054};
1240
1241 memcpy(__argv, argv, sizeof(const char *) * argc);
1242 argc = parse_options(argc, (const char **)__argv, record_options,
1243 NULL, PARSE_OPT_STOP_AT_NON_OPTION);
1244 free(__argv);
1245
1246 system_wide = (argc == 0);
1247
1248 return 0;
1249}
1250 1055
1251int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1056static const struct option options[] = {
1252{
1253 bool show_full_info = false;
1254 char *rec_script_path = NULL;
1255 char *rep_script_path = NULL;
1256 struct perf_session *session;
1257 char *script_path = NULL;
1258 const char **__argv;
1259 int i, j, err;
1260 const struct option options[] = {
1261 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1057 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1262 "dump raw trace in ASCII"), 1058 "dump raw trace in ASCII"),
1263 OPT_INCR('v', "verbose", &verbose, 1059 OPT_INCR('v', "verbose", &verbose,
1264 "be more verbose (show symbol address, etc)"), 1060 "be more verbose (show symbol address, etc)"),
1265 OPT_BOOLEAN('L', "Latency", &latency_format, 1061 OPT_BOOLEAN('L', "Latency", &latency_format,
1266 "show latency attributes (irqs/preemption disabled, etc)"), 1062 "show latency attributes (irqs/preemption disabled, etc)"),
1267 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", 1063 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
@@ -1271,7 +1067,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1271 parse_scriptname), 1067 parse_scriptname),
1272 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 1068 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
1273 "generate perf-script.xx script in specified language"), 1069 "generate perf-script.xx script in specified language"),
1274 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1070 OPT_STRING('i', "input", &input_name, "file",
1071 "input file name"),
1275 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 1072 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
1276 "do various checks like samples ordering and lost events"), 1073 "do various checks like samples ordering and lost events"),
1277 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1074 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
@@ -1283,31 +1080,36 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1283 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 1080 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1284 "Look for files with symbols relative to this directory"), 1081 "Look for files with symbols relative to this directory"),
1285 OPT_CALLBACK('f', "fields", NULL, "str", 1082 OPT_CALLBACK('f', "fields", NULL, "str",
1286 "comma separated output fields prepend with 'type:'. " 1083 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
1287 "Valid types: hw,sw,trace,raw. " 1084 parse_output_fields),
1288 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," 1085 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1289 "addr,symoff", parse_output_fields), 1086
1290 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1291 "system-wide collection from all CPUs"),
1292 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1293 "only consider these symbols"),
1294 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1295 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1296 "only display events for these comms"),
1297 OPT_BOOLEAN('I', "show-info", &show_full_info,
1298 "display extended information from perf.data file"),
1299 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
1300 "Show the path of [kernel.kallsyms]"),
1301 OPT_END() 1087 OPT_END()
1302 }; 1088};
1303 const char * const script_usage[] = { 1089
1304 "perf script [<options>]", 1090static bool have_cmd(int argc, const char **argv)
1305 "perf script [<options>] record <script> [<record-options>] <command>", 1091{
1306 "perf script [<options>] report <script> [script-args]", 1092 char **__argv = malloc(sizeof(const char *) * argc);
1307 "perf script [<options>] <script> [<record-options>] <command>", 1093
1308 "perf script [<options>] <top-script> [script-args]", 1094 if (!__argv)
1309 NULL 1095 die("malloc");
1310 }; 1096 memcpy(__argv, argv, sizeof(const char *) * argc);
1097 argc = parse_options(argc, (const char **)__argv, record_options,
1098 NULL, PARSE_OPT_STOP_AT_NON_OPTION);
1099 free(__argv);
1100
1101 return argc != 0;
1102}
1103
1104int cmd_script(int argc, const char **argv, const char *prefix __used)
1105{
1106 char *rec_script_path = NULL;
1107 char *rep_script_path = NULL;
1108 struct perf_session *session;
1109 char *script_path = NULL;
1110 const char **__argv;
1111 bool system_wide;
1112 int i, j, err;
1311 1113
1312 setup_scripting(); 1114 setup_scripting();
1313 1115
@@ -1364,36 +1166,29 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1364 1166
1365 if (pipe(live_pipe) < 0) { 1167 if (pipe(live_pipe) < 0) {
1366 perror("failed to create pipe"); 1168 perror("failed to create pipe");
1367 return -1; 1169 exit(-1);
1368 } 1170 }
1369 1171
1370 pid = fork(); 1172 pid = fork();
1371 if (pid < 0) { 1173 if (pid < 0) {
1372 perror("failed to fork"); 1174 perror("failed to fork");
1373 return -1; 1175 exit(-1);
1374 } 1176 }
1375 1177
1376 if (!pid) { 1178 if (!pid) {
1179 system_wide = true;
1377 j = 0; 1180 j = 0;
1378 1181
1379 dup2(live_pipe[1], 1); 1182 dup2(live_pipe[1], 1);
1380 close(live_pipe[0]); 1183 close(live_pipe[0]);
1381 1184
1382 if (is_top_script(argv[0])) { 1185 if (!is_top_script(argv[0]))
1383 system_wide = true; 1186 system_wide = !have_cmd(argc - rep_args,
1384 } else if (!system_wide) { 1187 &argv[rep_args]);
1385 if (have_cmd(argc - rep_args, &argv[rep_args]) != 0) {
1386 err = -1;
1387 goto out;
1388 }
1389 }
1390 1188
1391 __argv = malloc((argc + 6) * sizeof(const char *)); 1189 __argv = malloc((argc + 6) * sizeof(const char *));
1392 if (!__argv) { 1190 if (!__argv)
1393 pr_err("malloc failed\n"); 1191 die("malloc");
1394 err = -ENOMEM;
1395 goto out;
1396 }
1397 1192
1398 __argv[j++] = "/bin/sh"; 1193 __argv[j++] = "/bin/sh";
1399 __argv[j++] = rec_script_path; 1194 __argv[j++] = rec_script_path;
@@ -1415,12 +1210,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1415 close(live_pipe[1]); 1210 close(live_pipe[1]);
1416 1211
1417 __argv = malloc((argc + 4) * sizeof(const char *)); 1212 __argv = malloc((argc + 4) * sizeof(const char *));
1418 if (!__argv) { 1213 if (!__argv)
1419 pr_err("malloc failed\n"); 1214 die("malloc");
1420 err = -ENOMEM;
1421 goto out;
1422 }
1423
1424 j = 0; 1215 j = 0;
1425 __argv[j++] = "/bin/sh"; 1216 __argv[j++] = "/bin/sh";
1426 __argv[j++] = rep_script_path; 1217 __argv[j++] = rep_script_path;
@@ -1441,24 +1232,15 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1441 script_path = rep_script_path; 1232 script_path = rep_script_path;
1442 1233
1443 if (script_path) { 1234 if (script_path) {
1235 system_wide = false;
1444 j = 0; 1236 j = 0;
1445 1237
1446 if (!rec_script_path) 1238 if (rec_script_path)
1447 system_wide = false; 1239 system_wide = !have_cmd(argc - 1, &argv[1]);
1448 else if (!system_wide) {
1449 if (have_cmd(argc - 1, &argv[1]) != 0) {
1450 err = -1;
1451 goto out;
1452 }
1453 }
1454 1240
1455 __argv = malloc((argc + 2) * sizeof(const char *)); 1241 __argv = malloc((argc + 2) * sizeof(const char *));
1456 if (!__argv) { 1242 if (!__argv)
1457 pr_err("malloc failed\n"); 1243 die("malloc");
1458 err = -ENOMEM;
1459 goto out;
1460 }
1461
1462 __argv[j++] = "/bin/sh"; 1244 __argv[j++] = "/bin/sh";
1463 __argv[j++] = script_path; 1245 __argv[j++] = script_path;
1464 if (system_wide) 1246 if (system_wide)
@@ -1477,8 +1259,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1477 if (!script_name) 1259 if (!script_name)
1478 setup_pager(); 1260 setup_pager();
1479 1261
1480 session = perf_session__new(input_name, O_RDONLY, 0, false, 1262 session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
1481 &perf_script);
1482 if (session == NULL) 1263 if (session == NULL)
1483 return -ENOMEM; 1264 return -ENOMEM;
1484 1265
@@ -1487,8 +1268,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1487 return -1; 1268 return -1;
1488 } 1269 }
1489 1270
1490 perf_session__fprintf_info(session, stdout, show_full_info);
1491
1492 if (!no_callchain) 1271 if (!no_callchain)
1493 symbol_conf.use_callchain = true; 1272 symbol_conf.use_callchain = true;
1494 else 1273 else
@@ -1504,21 +1283,21 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1504 return -1; 1283 return -1;
1505 } 1284 }
1506 1285
1507 input = open(session->filename, O_RDONLY); /* input_name */ 1286 input = open(input_name, O_RDONLY);
1508 if (input < 0) { 1287 if (input < 0) {
1509 perror("failed to open file"); 1288 perror("failed to open file");
1510 return -1; 1289 exit(-1);
1511 } 1290 }
1512 1291
1513 err = fstat(input, &perf_stat); 1292 err = fstat(input, &perf_stat);
1514 if (err < 0) { 1293 if (err < 0) {
1515 perror("failed to stat file"); 1294 perror("failed to stat file");
1516 return -1; 1295 exit(-1);
1517 } 1296 }
1518 1297
1519 if (!perf_stat.st_size) { 1298 if (!perf_stat.st_size) {
1520 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1299 fprintf(stderr, "zero-sized file, nothing to do!\n");
1521 return 0; 1300 exit(0);
1522 } 1301 }
1523 1302
1524 scripting_ops = script_spec__lookup(generate_script_lang); 1303 scripting_ops = script_spec__lookup(generate_script_lang);
@@ -1527,8 +1306,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1527 return -1; 1306 return -1;
1528 } 1307 }
1529 1308
1530 err = scripting_ops->generate_script(session->pevent, 1309 err = scripting_ops->generate_script("perf-script");
1531 "perf-script");
1532 goto out; 1310 goto out;
1533 } 1311 }
1534 1312
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c247faca712..5deb17d9e79 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -51,45 +51,157 @@
51#include "util/evsel.h" 51#include "util/evsel.h"
52#include "util/debug.h" 52#include "util/debug.h"
53#include "util/color.h" 53#include "util/color.h"
54#include "util/stat.h"
55#include "util/header.h" 54#include "util/header.h"
56#include "util/cpumap.h" 55#include "util/cpumap.h"
57#include "util/thread.h" 56#include "util/thread.h"
58#include "util/thread_map.h" 57#include "util/thread_map.h"
59 58
60#include <stdlib.h>
61#include <sys/prctl.h> 59#include <sys/prctl.h>
60#include <math.h>
62#include <locale.h> 61#include <locale.h>
63 62
64#define DEFAULT_SEPARATOR " " 63#define DEFAULT_SEPARATOR " "
65#define CNTR_NOT_SUPPORTED "<not supported>" 64#define CNTR_NOT_SUPPORTED "<not supported>"
66#define CNTR_NOT_COUNTED "<not counted>" 65#define CNTR_NOT_COUNTED "<not counted>"
67 66
68static struct perf_evlist *evsel_list; 67static struct perf_event_attr default_attrs[] = {
68
69 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
70 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
71 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
72 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
73
74 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
75 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
76 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
77 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
78 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
79 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
80
81};
82
83/*
84 * Detailed stats (-d), covering the L1 and last level data caches:
85 */
86static struct perf_event_attr detailed_attrs[] = {
87
88 { .type = PERF_TYPE_HW_CACHE,
89 .config =
90 PERF_COUNT_HW_CACHE_L1D << 0 |
91 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
92 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
93
94 { .type = PERF_TYPE_HW_CACHE,
95 .config =
96 PERF_COUNT_HW_CACHE_L1D << 0 |
97 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
98 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
99
100 { .type = PERF_TYPE_HW_CACHE,
101 .config =
102 PERF_COUNT_HW_CACHE_LL << 0 |
103 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
104 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
105
106 { .type = PERF_TYPE_HW_CACHE,
107 .config =
108 PERF_COUNT_HW_CACHE_LL << 0 |
109 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
110 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
111};
112
113/*
114 * Very detailed stats (-d -d), covering the instruction cache and the TLB caches:
115 */
116static struct perf_event_attr very_detailed_attrs[] = {
117
118 { .type = PERF_TYPE_HW_CACHE,
119 .config =
120 PERF_COUNT_HW_CACHE_L1I << 0 |
121 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
122 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
123
124 { .type = PERF_TYPE_HW_CACHE,
125 .config =
126 PERF_COUNT_HW_CACHE_L1I << 0 |
127 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
128 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
129
130 { .type = PERF_TYPE_HW_CACHE,
131 .config =
132 PERF_COUNT_HW_CACHE_DTLB << 0 |
133 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
134 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
135
136 { .type = PERF_TYPE_HW_CACHE,
137 .config =
138 PERF_COUNT_HW_CACHE_DTLB << 0 |
139 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
140 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
141
142 { .type = PERF_TYPE_HW_CACHE,
143 .config =
144 PERF_COUNT_HW_CACHE_ITLB << 0 |
145 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
146 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
147
148 { .type = PERF_TYPE_HW_CACHE,
149 .config =
150 PERF_COUNT_HW_CACHE_ITLB << 0 |
151 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
152 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
69 153
70static struct perf_target target = {
71 .uid = UINT_MAX,
72}; 154};
73 155
156/*
157 * Very, very detailed stats (-d -d -d), adding prefetch events:
158 */
159static struct perf_event_attr very_very_detailed_attrs[] = {
160
161 { .type = PERF_TYPE_HW_CACHE,
162 .config =
163 PERF_COUNT_HW_CACHE_L1D << 0 |
164 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
165 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
166
167 { .type = PERF_TYPE_HW_CACHE,
168 .config =
169 PERF_COUNT_HW_CACHE_L1D << 0 |
170 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
171 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
172};
173
174
175
176struct perf_evlist *evsel_list;
177
178static bool system_wide = false;
179static int run_idx = 0;
180
74static int run_count = 1; 181static int run_count = 1;
75static bool no_inherit = false; 182static bool no_inherit = false;
76static bool scale = true; 183static bool scale = true;
77static bool no_aggr = false; 184static bool no_aggr = false;
185static pid_t target_pid = -1;
186static pid_t target_tid = -1;
78static pid_t child_pid = -1; 187static pid_t child_pid = -1;
79static bool null_run = false; 188static bool null_run = false;
80static int detailed_run = 0; 189static int detailed_run = 0;
190static bool sync_run = false;
81static bool big_num = true; 191static bool big_num = true;
82static int big_num_opt = -1; 192static int big_num_opt = -1;
193static const char *cpu_list;
83static const char *csv_sep = NULL; 194static const char *csv_sep = NULL;
84static bool csv_output = false; 195static bool csv_output = false;
85static bool group = false; 196static bool group = false;
86static FILE *output = NULL;
87static const char *pre_cmd = NULL;
88static const char *post_cmd = NULL;
89static bool sync_run = false;
90 197
91static volatile int done = 0; 198static volatile int done = 0;
92 199
200struct stats
201{
202 double n, mean, M2;
203};
204
93struct perf_stat { 205struct perf_stat {
94 struct stats res_stats[3]; 206 struct stats res_stats[3];
95}; 207};
@@ -106,34 +218,61 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
106 evsel->priv = NULL; 218 evsel->priv = NULL;
107} 219}
108 220
109static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) 221static void update_stats(struct stats *stats, u64 val)
110{ 222{
111 return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; 223 double delta;
224
225 stats->n++;
226 delta = val - stats->mean;
227 stats->mean += delta / stats->n;
228 stats->M2 += delta*(val - stats->mean);
112} 229}
113 230
114static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) 231static double avg_stats(struct stats *stats)
115{ 232{
116 return perf_evsel__cpus(evsel)->nr; 233 return stats->mean;
117} 234}
118 235
119static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 236/*
120static struct stats runtime_cycles_stats[MAX_NR_CPUS]; 237 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
121static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; 238 *
122static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS]; 239 * (\Sum n_i^2) - ((\Sum n_i)^2)/n
123static struct stats runtime_branches_stats[MAX_NR_CPUS]; 240 * s^2 = -------------------------------
124static struct stats runtime_cacherefs_stats[MAX_NR_CPUS]; 241 * n - 1
125static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS]; 242 *
126static struct stats runtime_l1_icache_stats[MAX_NR_CPUS]; 243 * http://en.wikipedia.org/wiki/Stddev
127static struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; 244 *
128static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; 245 * The std dev of the mean is related to the std dev by:
129static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 246 *
130static struct stats walltime_nsecs_stats; 247 * s
248 * s_mean = -------
249 * sqrt(n)
250 *
251 */
252static double stddev_stats(struct stats *stats)
253{
254 double variance = stats->M2 / (stats->n - 1);
255 double variance_mean = variance / stats->n;
256
257 return sqrt(variance_mean);
258}
259
260struct stats runtime_nsecs_stats[MAX_NR_CPUS];
261struct stats runtime_cycles_stats[MAX_NR_CPUS];
262struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
263struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
264struct stats runtime_branches_stats[MAX_NR_CPUS];
265struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
266struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
267struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
268struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
269struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
270struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
271struct stats walltime_nsecs_stats;
131 272
132static int create_perf_stat_counter(struct perf_evsel *evsel) 273static int create_perf_stat_counter(struct perf_evsel *evsel)
133{ 274{
134 struct perf_event_attr *attr = &evsel->attr; 275 struct perf_event_attr *attr = &evsel->attr;
135 bool exclude_guest_missing = false;
136 int ret;
137 276
138 if (scale) 277 if (scale)
139 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 278 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -141,38 +280,15 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
141 280
142 attr->inherit = !no_inherit; 281 attr->inherit = !no_inherit;
143 282
144retry: 283 if (system_wide)
145 if (exclude_guest_missing) 284 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group);
146 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
147
148 if (perf_target__has_cpu(&target)) {
149 ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
150 if (ret)
151 goto check_ret;
152 return 0;
153 }
154 285
155 if (!perf_target__has_task(&target) && 286 if (target_pid == -1 && target_tid == -1) {
156 !perf_evsel__is_group_member(evsel)) {
157 attr->disabled = 1; 287 attr->disabled = 1;
158 attr->enable_on_exec = 1; 288 attr->enable_on_exec = 1;
159 } 289 }
160 290
161 ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); 291 return perf_evsel__open_per_thread(evsel, evsel_list->threads, group);
162 if (!ret)
163 return 0;
164 /* fall through */
165check_ret:
166 if (ret && errno == EINVAL) {
167 if (!exclude_guest_missing &&
168 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
169 pr_debug("Old kernel, cannot exclude "
170 "guest or host samples.\n");
171 exclude_guest_missing = true;
172 goto retry;
173 }
174 }
175 return ret;
176} 292}
177 293
178/* 294/*
@@ -228,7 +344,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
228 u64 *count = counter->counts->aggr.values; 344 u64 *count = counter->counts->aggr.values;
229 int i; 345 int i;
230 346
231 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), 347 if (__perf_evsel__read(counter, evsel_list->cpus->nr,
232 evsel_list->threads->nr, scale) < 0) 348 evsel_list->threads->nr, scale) < 0)
233 return -1; 349 return -1;
234 350
@@ -236,8 +352,8 @@ static int read_counter_aggr(struct perf_evsel *counter)
236 update_stats(&ps->res_stats[i], count[i]); 352 update_stats(&ps->res_stats[i], count[i]);
237 353
238 if (verbose) { 354 if (verbose) {
239 fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 355 fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
240 perf_evsel__name(counter), count[0], count[1], count[2]); 356 event_name(counter), count[0], count[1], count[2]);
241 } 357 }
242 358
243 /* 359 /*
@@ -257,7 +373,7 @@ static int read_counter(struct perf_evsel *counter)
257 u64 *count; 373 u64 *count;
258 int cpu; 374 int cpu;
259 375
260 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 376 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
261 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) 377 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
262 return -1; 378 return -1;
263 379
@@ -269,7 +385,7 @@ static int read_counter(struct perf_evsel *counter)
269 return 0; 385 return 0;
270} 386}
271 387
272static int __run_perf_stat(int argc __maybe_unused, const char **argv) 388static int run_perf_stat(int argc __used, const char **argv)
273{ 389{
274 unsigned long long t0, t1; 390 unsigned long long t0, t1;
275 struct perf_evsel *counter; 391 struct perf_evsel *counter;
@@ -280,7 +396,7 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
280 396
281 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 397 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
282 perror("failed to create pipes"); 398 perror("failed to create pipes");
283 return -1; 399 exit(1);
284 } 400 }
285 401
286 if (forks) { 402 if (forks) {
@@ -316,7 +432,7 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
316 exit(-1); 432 exit(-1);
317 } 433 }
318 434
319 if (perf_target__none(&target)) 435 if (target_tid == -1 && target_pid == -1 && !system_wide)
320 evsel_list->threads->map[0] = child_pid; 436 evsel_list->threads->map[0] = child_pid;
321 437
322 /* 438 /*
@@ -329,21 +445,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
329 close(child_ready_pipe[0]); 445 close(child_ready_pipe[0]);
330 } 446 }
331 447
332 if (group)
333 perf_evlist__set_leader(evsel_list);
334
335 list_for_each_entry(counter, &evsel_list->entries, node) { 448 list_for_each_entry(counter, &evsel_list->entries, node) {
336 if (create_perf_stat_counter(counter) < 0) { 449 if (create_perf_stat_counter(counter) < 0) {
337 /* 450 if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
338 * PPC returns ENXIO for HW counters until 2.6.37
339 * (behavior changed with commit b0a873e).
340 */
341 if (errno == EINVAL || errno == ENOSYS ||
342 errno == ENOENT || errno == EOPNOTSUPP ||
343 errno == ENXIO) {
344 if (verbose) 451 if (verbose)
345 ui__warning("%s event is not supported by the kernel.\n", 452 ui__warning("%s event is not supported by the kernel.\n",
346 perf_evsel__name(counter)); 453 event_name(counter));
347 counter->supported = false; 454 counter->supported = false;
348 continue; 455 continue;
349 } 456 }
@@ -352,7 +459,7 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
352 error("You may not have permission to collect %sstats.\n" 459 error("You may not have permission to collect %sstats.\n"
353 "\t Consider tweaking" 460 "\t Consider tweaking"
354 " /proc/sys/kernel/perf_event_paranoid or running as root.", 461 " /proc/sys/kernel/perf_event_paranoid or running as root.",
355 target.system_wide ? "system-wide " : ""); 462 system_wide ? "system-wide " : "");
356 } else { 463 } else {
357 error("open_counter returned with %d (%s). " 464 error("open_counter returned with %d (%s). "
358 "/bin/dmesg may provide additional information.\n", 465 "/bin/dmesg may provide additional information.\n",
@@ -360,14 +467,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
360 } 467 }
361 if (child_pid != -1) 468 if (child_pid != -1)
362 kill(child_pid, SIGTERM); 469 kill(child_pid, SIGTERM);
363 470 die("Not all events could be opened.\n");
364 pr_err("Not all events could be opened.\n");
365 return -1; 471 return -1;
366 } 472 }
367 counter->supported = true; 473 counter->supported = true;
368 } 474 }
369 475
370 if (perf_evlist__apply_filters(evsel_list)) { 476 if (perf_evlist__set_filters(evsel_list)) {
371 error("failed to set filter with %d (%s)\n", errno, 477 error("failed to set filter with %d (%s)\n", errno,
372 strerror(errno)); 478 strerror(errno));
373 return -1; 479 return -1;
@@ -381,8 +487,6 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
381 if (forks) { 487 if (forks) {
382 close(go_pipe[1]); 488 close(go_pipe[1]);
383 wait(&status); 489 wait(&status);
384 if (WIFSIGNALED(status))
385 psignal(WTERMSIG(status), argv[0]);
386 } else { 490 } else {
387 while(!done) sleep(1); 491 while(!done) sleep(1);
388 } 492 }
@@ -394,12 +498,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
394 if (no_aggr) { 498 if (no_aggr) {
395 list_for_each_entry(counter, &evsel_list->entries, node) { 499 list_for_each_entry(counter, &evsel_list->entries, node) {
396 read_counter(counter); 500 read_counter(counter);
397 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); 501 perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
398 } 502 }
399 } else { 503 } else {
400 list_for_each_entry(counter, &evsel_list->entries, node) { 504 list_for_each_entry(counter, &evsel_list->entries, node) {
401 read_counter_aggr(counter); 505 read_counter_aggr(counter);
402 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 506 perf_evsel__close_fd(counter, evsel_list->cpus->nr,
403 evsel_list->threads->nr); 507 evsel_list->threads->nr);
404 } 508 }
405 } 509 }
@@ -407,40 +511,17 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
407 return WEXITSTATUS(status); 511 return WEXITSTATUS(status);
408} 512}
409 513
410static int run_perf_stat(int argc __maybe_unused, const char **argv)
411{
412 int ret;
413
414 if (pre_cmd) {
415 ret = system(pre_cmd);
416 if (ret)
417 return ret;
418 }
419
420 if (sync_run)
421 sync();
422
423 ret = __run_perf_stat(argc, argv);
424 if (ret)
425 return ret;
426
427 if (post_cmd) {
428 ret = system(post_cmd);
429 if (ret)
430 return ret;
431 }
432
433 return ret;
434}
435
436static void print_noise_pct(double total, double avg) 514static void print_noise_pct(double total, double avg)
437{ 515{
438 double pct = rel_stddev_stats(total, avg); 516 double pct = 0.0;
517
518 if (avg)
519 pct = 100.0*total/avg;
439 520
440 if (csv_output) 521 if (csv_output)
441 fprintf(output, "%s%.2f%%", csv_sep, pct); 522 fprintf(stderr, "%s%.2f%%", csv_sep, pct);
442 else if (pct) 523 else
443 fprintf(output, " ( +-%6.2f%% )", pct); 524 fprintf(stderr, " ( +-%6.2f%% )", pct);
444} 525}
445 526
446static void print_noise(struct perf_evsel *evsel, double avg) 527static void print_noise(struct perf_evsel *evsel, double avg)
@@ -463,53 +544,21 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
463 if (no_aggr) 544 if (no_aggr)
464 sprintf(cpustr, "CPU%*d%s", 545 sprintf(cpustr, "CPU%*d%s",
465 csv_output ? 0 : -4, 546 csv_output ? 0 : -4,
466 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 547 evsel_list->cpus->map[cpu], csv_sep);
467 548
468 fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); 549 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
469 550
470 if (evsel->cgrp) 551 if (evsel->cgrp)
471 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 552 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
472 553
473 if (csv_output) 554 if (csv_output)
474 return; 555 return;
475 556
476 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 557 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
477 fprintf(output, " # %8.3f CPUs utilized ", 558 fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats));
478 avg / avg_stats(&walltime_nsecs_stats));
479 else
480 fprintf(output, " ");
481}
482
483/* used for get_ratio_color() */
484enum grc_type {
485 GRC_STALLED_CYCLES_FE,
486 GRC_STALLED_CYCLES_BE,
487 GRC_CACHE_MISSES,
488 GRC_MAX_NR
489};
490
491static const char *get_ratio_color(enum grc_type type, double ratio)
492{
493 static const double grc_table[GRC_MAX_NR][3] = {
494 [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 },
495 [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 },
496 [GRC_CACHE_MISSES] = { 20.0, 10.0, 5.0 },
497 };
498 const char *color = PERF_COLOR_NORMAL;
499
500 if (ratio > grc_table[type][0])
501 color = PERF_COLOR_RED;
502 else if (ratio > grc_table[type][1])
503 color = PERF_COLOR_MAGENTA;
504 else if (ratio > grc_table[type][2])
505 color = PERF_COLOR_YELLOW;
506
507 return color;
508} 559}
509 560
510static void print_stalled_cycles_frontend(int cpu, 561static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
511 struct perf_evsel *evsel
512 __maybe_unused, double avg)
513{ 562{
514 double total, ratio = 0.0; 563 double total, ratio = 0.0;
515 const char *color; 564 const char *color;
@@ -519,16 +568,20 @@ static void print_stalled_cycles_frontend(int cpu,
519 if (total) 568 if (total)
520 ratio = avg / total * 100.0; 569 ratio = avg / total * 100.0;
521 570
522 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio); 571 color = PERF_COLOR_NORMAL;
572 if (ratio > 50.0)
573 color = PERF_COLOR_RED;
574 else if (ratio > 30.0)
575 color = PERF_COLOR_MAGENTA;
576 else if (ratio > 10.0)
577 color = PERF_COLOR_YELLOW;
523 578
524 fprintf(output, " # "); 579 fprintf(stderr, " # ");
525 color_fprintf(output, color, "%6.2f%%", ratio); 580 color_fprintf(stderr, color, "%6.2f%%", ratio);
526 fprintf(output, " frontend cycles idle "); 581 fprintf(stderr, " frontend cycles idle ");
527} 582}
528 583
529static void print_stalled_cycles_backend(int cpu, 584static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg)
530 struct perf_evsel *evsel
531 __maybe_unused, double avg)
532{ 585{
533 double total, ratio = 0.0; 586 double total, ratio = 0.0;
534 const char *color; 587 const char *color;
@@ -538,16 +591,20 @@ static void print_stalled_cycles_backend(int cpu,
538 if (total) 591 if (total)
539 ratio = avg / total * 100.0; 592 ratio = avg / total * 100.0;
540 593
541 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio); 594 color = PERF_COLOR_NORMAL;
595 if (ratio > 75.0)
596 color = PERF_COLOR_RED;
597 else if (ratio > 50.0)
598 color = PERF_COLOR_MAGENTA;
599 else if (ratio > 20.0)
600 color = PERF_COLOR_YELLOW;
542 601
543 fprintf(output, " # "); 602 fprintf(stderr, " # ");
544 color_fprintf(output, color, "%6.2f%%", ratio); 603 color_fprintf(stderr, color, "%6.2f%%", ratio);
545 fprintf(output, " backend cycles idle "); 604 fprintf(stderr, " backend cycles idle ");
546} 605}
547 606
548static void print_branch_misses(int cpu, 607static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg)
549 struct perf_evsel *evsel __maybe_unused,
550 double avg)
551{ 608{
552 double total, ratio = 0.0; 609 double total, ratio = 0.0;
553 const char *color; 610 const char *color;
@@ -557,16 +614,20 @@ static void print_branch_misses(int cpu,
557 if (total) 614 if (total)
558 ratio = avg / total * 100.0; 615 ratio = avg / total * 100.0;
559 616
560 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 617 color = PERF_COLOR_NORMAL;
618 if (ratio > 20.0)
619 color = PERF_COLOR_RED;
620 else if (ratio > 10.0)
621 color = PERF_COLOR_MAGENTA;
622 else if (ratio > 5.0)
623 color = PERF_COLOR_YELLOW;
561 624
562 fprintf(output, " # "); 625 fprintf(stderr, " # ");
563 color_fprintf(output, color, "%6.2f%%", ratio); 626 color_fprintf(stderr, color, "%6.2f%%", ratio);
564 fprintf(output, " of all branches "); 627 fprintf(stderr, " of all branches ");
565} 628}
566 629
567static void print_l1_dcache_misses(int cpu, 630static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
568 struct perf_evsel *evsel __maybe_unused,
569 double avg)
570{ 631{
571 double total, ratio = 0.0; 632 double total, ratio = 0.0;
572 const char *color; 633 const char *color;
@@ -576,16 +637,20 @@ static void print_l1_dcache_misses(int cpu,
576 if (total) 637 if (total)
577 ratio = avg / total * 100.0; 638 ratio = avg / total * 100.0;
578 639
579 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 640 color = PERF_COLOR_NORMAL;
641 if (ratio > 20.0)
642 color = PERF_COLOR_RED;
643 else if (ratio > 10.0)
644 color = PERF_COLOR_MAGENTA;
645 else if (ratio > 5.0)
646 color = PERF_COLOR_YELLOW;
580 647
581 fprintf(output, " # "); 648 fprintf(stderr, " # ");
582 color_fprintf(output, color, "%6.2f%%", ratio); 649 color_fprintf(stderr, color, "%6.2f%%", ratio);
583 fprintf(output, " of all L1-dcache hits "); 650 fprintf(stderr, " of all L1-dcache hits ");
584} 651}
585 652
586static void print_l1_icache_misses(int cpu, 653static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
587 struct perf_evsel *evsel __maybe_unused,
588 double avg)
589{ 654{
590 double total, ratio = 0.0; 655 double total, ratio = 0.0;
591 const char *color; 656 const char *color;
@@ -595,16 +660,20 @@ static void print_l1_icache_misses(int cpu,
595 if (total) 660 if (total)
596 ratio = avg / total * 100.0; 661 ratio = avg / total * 100.0;
597 662
598 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 663 color = PERF_COLOR_NORMAL;
664 if (ratio > 20.0)
665 color = PERF_COLOR_RED;
666 else if (ratio > 10.0)
667 color = PERF_COLOR_MAGENTA;
668 else if (ratio > 5.0)
669 color = PERF_COLOR_YELLOW;
599 670
600 fprintf(output, " # "); 671 fprintf(stderr, " # ");
601 color_fprintf(output, color, "%6.2f%%", ratio); 672 color_fprintf(stderr, color, "%6.2f%%", ratio);
602 fprintf(output, " of all L1-icache hits "); 673 fprintf(stderr, " of all L1-icache hits ");
603} 674}
604 675
605static void print_dtlb_cache_misses(int cpu, 676static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
606 struct perf_evsel *evsel __maybe_unused,
607 double avg)
608{ 677{
609 double total, ratio = 0.0; 678 double total, ratio = 0.0;
610 const char *color; 679 const char *color;
@@ -614,16 +683,20 @@ static void print_dtlb_cache_misses(int cpu,
614 if (total) 683 if (total)
615 ratio = avg / total * 100.0; 684 ratio = avg / total * 100.0;
616 685
617 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 686 color = PERF_COLOR_NORMAL;
687 if (ratio > 20.0)
688 color = PERF_COLOR_RED;
689 else if (ratio > 10.0)
690 color = PERF_COLOR_MAGENTA;
691 else if (ratio > 5.0)
692 color = PERF_COLOR_YELLOW;
618 693
619 fprintf(output, " # "); 694 fprintf(stderr, " # ");
620 color_fprintf(output, color, "%6.2f%%", ratio); 695 color_fprintf(stderr, color, "%6.2f%%", ratio);
621 fprintf(output, " of all dTLB cache hits "); 696 fprintf(stderr, " of all dTLB cache hits ");
622} 697}
623 698
624static void print_itlb_cache_misses(int cpu, 699static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
625 struct perf_evsel *evsel __maybe_unused,
626 double avg)
627{ 700{
628 double total, ratio = 0.0; 701 double total, ratio = 0.0;
629 const char *color; 702 const char *color;
@@ -633,16 +706,20 @@ static void print_itlb_cache_misses(int cpu,
633 if (total) 706 if (total)
634 ratio = avg / total * 100.0; 707 ratio = avg / total * 100.0;
635 708
636 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 709 color = PERF_COLOR_NORMAL;
710 if (ratio > 20.0)
711 color = PERF_COLOR_RED;
712 else if (ratio > 10.0)
713 color = PERF_COLOR_MAGENTA;
714 else if (ratio > 5.0)
715 color = PERF_COLOR_YELLOW;
637 716
638 fprintf(output, " # "); 717 fprintf(stderr, " # ");
639 color_fprintf(output, color, "%6.2f%%", ratio); 718 color_fprintf(stderr, color, "%6.2f%%", ratio);
640 fprintf(output, " of all iTLB cache hits "); 719 fprintf(stderr, " of all iTLB cache hits ");
641} 720}
642 721
643static void print_ll_cache_misses(int cpu, 722static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg)
644 struct perf_evsel *evsel __maybe_unused,
645 double avg)
646{ 723{
647 double total, ratio = 0.0; 724 double total, ratio = 0.0;
648 const char *color; 725 const char *color;
@@ -652,11 +729,17 @@ static void print_ll_cache_misses(int cpu,
652 if (total) 729 if (total)
653 ratio = avg / total * 100.0; 730 ratio = avg / total * 100.0;
654 731
655 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 732 color = PERF_COLOR_NORMAL;
733 if (ratio > 20.0)
734 color = PERF_COLOR_RED;
735 else if (ratio > 10.0)
736 color = PERF_COLOR_MAGENTA;
737 else if (ratio > 5.0)
738 color = PERF_COLOR_YELLOW;
656 739
657 fprintf(output, " # "); 740 fprintf(stderr, " # ");
658 color_fprintf(output, color, "%6.2f%%", ratio); 741 color_fprintf(stderr, color, "%6.2f%%", ratio);
659 fprintf(output, " of all LL-cache hits "); 742 fprintf(stderr, " of all LL-cache hits ");
660} 743}
661 744
662static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 745static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
@@ -675,14 +758,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
675 if (no_aggr) 758 if (no_aggr)
676 sprintf(cpustr, "CPU%*d%s", 759 sprintf(cpustr, "CPU%*d%s",
677 csv_output ? 0 : -4, 760 csv_output ? 0 : -4,
678 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 761 evsel_list->cpus->map[cpu], csv_sep);
679 else 762 else
680 cpu = 0; 763 cpu = 0;
681 764
682 fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel)); 765 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
683 766
684 if (evsel->cgrp) 767 if (evsel->cgrp)
685 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 768 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
686 769
687 if (csv_output) 770 if (csv_output)
688 return; 771 return;
@@ -693,14 +776,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
693 if (total) 776 if (total)
694 ratio = avg / total; 777 ratio = avg / total;
695 778
696 fprintf(output, " # %5.2f insns per cycle ", ratio); 779 fprintf(stderr, " # %5.2f insns per cycle ", ratio);
697 780
698 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 781 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
699 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 782 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
700 783
701 if (total && avg) { 784 if (total && avg) {
702 ratio = total / avg; 785 ratio = total / avg;
703 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio); 786 fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio);
704 } 787 }
705 788
706 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 789 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -748,7 +831,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
748 if (total) 831 if (total)
749 ratio = avg * 100 / total; 832 ratio = avg * 100 / total;
750 833
751 fprintf(output, " # %8.3f %% of all cache refs ", ratio); 834 fprintf(stderr, " # %8.3f %% of all cache refs ", ratio);
752 835
753 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 836 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
754 print_stalled_cycles_frontend(cpu, evsel, avg); 837 print_stalled_cycles_frontend(cpu, evsel, avg);
@@ -760,22 +843,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
760 if (total) 843 if (total)
761 ratio = 1.0 * avg / total; 844 ratio = 1.0 * avg / total;
762 845
763 fprintf(output, " # %8.3f GHz ", ratio); 846 fprintf(stderr, " # %8.3f GHz ", ratio);
764 } else if (runtime_nsecs_stats[cpu].n != 0) { 847 } else if (runtime_nsecs_stats[cpu].n != 0) {
765 char unit = 'M';
766
767 total = avg_stats(&runtime_nsecs_stats[cpu]); 848 total = avg_stats(&runtime_nsecs_stats[cpu]);
768 849
769 if (total) 850 if (total)
770 ratio = 1000.0 * avg / total; 851 ratio = 1000.0 * avg / total;
771 if (ratio < 0.001) {
772 ratio *= 1000;
773 unit = 'K';
774 }
775 852
776 fprintf(output, " # %8.3f %c/sec ", ratio, unit); 853 fprintf(stderr, " # %8.3f M/sec ", ratio);
777 } else { 854 } else {
778 fprintf(output, " "); 855 fprintf(stderr, " ");
779 } 856 }
780} 857}
781 858
@@ -790,17 +867,17 @@ static void print_counter_aggr(struct perf_evsel *counter)
790 int scaled = counter->counts->scaled; 867 int scaled = counter->counts->scaled;
791 868
792 if (scaled == -1) { 869 if (scaled == -1) {
793 fprintf(output, "%*s%s%*s", 870 fprintf(stderr, "%*s%s%*s",
794 csv_output ? 0 : 18, 871 csv_output ? 0 : 18,
795 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 872 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
796 csv_sep, 873 csv_sep,
797 csv_output ? 0 : -24, 874 csv_output ? 0 : -24,
798 perf_evsel__name(counter)); 875 event_name(counter));
799 876
800 if (counter->cgrp) 877 if (counter->cgrp)
801 fprintf(output, "%s%s", csv_sep, counter->cgrp->name); 878 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
802 879
803 fputc('\n', output); 880 fputc('\n', stderr);
804 return; 881 return;
805 } 882 }
806 883
@@ -812,7 +889,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
812 print_noise(counter, avg); 889 print_noise(counter, avg);
813 890
814 if (csv_output) { 891 if (csv_output) {
815 fputc('\n', output); 892 fputc('\n', stderr);
816 return; 893 return;
817 } 894 }
818 895
@@ -822,9 +899,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
822 avg_enabled = avg_stats(&ps->res_stats[1]); 899 avg_enabled = avg_stats(&ps->res_stats[1]);
823 avg_running = avg_stats(&ps->res_stats[2]); 900 avg_running = avg_stats(&ps->res_stats[2]);
824 901
825 fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled); 902 fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled);
826 } 903 }
827 fprintf(output, "\n"); 904 fprintf(stderr, "\n");
828} 905}
829 906
830/* 907/*
@@ -836,25 +913,24 @@ static void print_counter(struct perf_evsel *counter)
836 u64 ena, run, val; 913 u64 ena, run, val;
837 int cpu; 914 int cpu;
838 915
839 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 916 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
840 val = counter->counts->cpu[cpu].val; 917 val = counter->counts->cpu[cpu].val;
841 ena = counter->counts->cpu[cpu].ena; 918 ena = counter->counts->cpu[cpu].ena;
842 run = counter->counts->cpu[cpu].run; 919 run = counter->counts->cpu[cpu].run;
843 if (run == 0 || ena == 0) { 920 if (run == 0 || ena == 0) {
844 fprintf(output, "CPU%*d%s%*s%s%*s", 921 fprintf(stderr, "CPU%*d%s%*s%s%*s",
845 csv_output ? 0 : -4, 922 csv_output ? 0 : -4,
846 perf_evsel__cpus(counter)->map[cpu], csv_sep, 923 evsel_list->cpus->map[cpu], csv_sep,
847 csv_output ? 0 : 18, 924 csv_output ? 0 : 18,
848 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 925 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
849 csv_sep, 926 csv_sep,
850 csv_output ? 0 : -24, 927 csv_output ? 0 : -24,
851 perf_evsel__name(counter)); 928 event_name(counter));
852 929
853 if (counter->cgrp) 930 if (counter->cgrp)
854 fprintf(output, "%s%s", 931 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
855 csv_sep, counter->cgrp->name);
856 932
857 fputc('\n', output); 933 fputc('\n', stderr);
858 continue; 934 continue;
859 } 935 }
860 936
@@ -867,10 +943,9 @@ static void print_counter(struct perf_evsel *counter)
867 print_noise(counter, 1.0); 943 print_noise(counter, 1.0);
868 944
869 if (run != ena) 945 if (run != ena)
870 fprintf(output, " (%.2f%%)", 946 fprintf(stderr, " (%.2f%%)", 100.0 * run / ena);
871 100.0 * run / ena);
872 } 947 }
873 fputc('\n', output); 948 fputc('\n', stderr);
874 } 949 }
875} 950}
876 951
@@ -882,21 +957,21 @@ static void print_stat(int argc, const char **argv)
882 fflush(stdout); 957 fflush(stdout);
883 958
884 if (!csv_output) { 959 if (!csv_output) {
885 fprintf(output, "\n"); 960 fprintf(stderr, "\n");
886 fprintf(output, " Performance counter stats for "); 961 fprintf(stderr, " Performance counter stats for ");
887 if (!perf_target__has_task(&target)) { 962 if(target_pid == -1 && target_tid == -1) {
888 fprintf(output, "\'%s", argv[0]); 963 fprintf(stderr, "\'%s", argv[0]);
889 for (i = 1; i < argc; i++) 964 for (i = 1; i < argc; i++)
890 fprintf(output, " %s", argv[i]); 965 fprintf(stderr, " %s", argv[i]);
891 } else if (target.pid) 966 } else if (target_pid != -1)
892 fprintf(output, "process id \'%s", target.pid); 967 fprintf(stderr, "process id \'%d", target_pid);
893 else 968 else
894 fprintf(output, "thread id \'%s", target.tid); 969 fprintf(stderr, "thread id \'%d", target_tid);
895 970
896 fprintf(output, "\'"); 971 fprintf(stderr, "\'");
897 if (run_count > 1) 972 if (run_count > 1)
898 fprintf(output, " (%d runs)", run_count); 973 fprintf(stderr, " (%d runs)", run_count);
899 fprintf(output, ":\n\n"); 974 fprintf(stderr, ":\n\n");
900 } 975 }
901 976
902 if (no_aggr) { 977 if (no_aggr) {
@@ -909,15 +984,15 @@ static void print_stat(int argc, const char **argv)
909 984
910 if (!csv_output) { 985 if (!csv_output) {
911 if (!null_run) 986 if (!null_run)
912 fprintf(output, "\n"); 987 fprintf(stderr, "\n");
913 fprintf(output, " %17.9f seconds time elapsed", 988 fprintf(stderr, " %17.9f seconds time elapsed",
914 avg_stats(&walltime_nsecs_stats)/1e9); 989 avg_stats(&walltime_nsecs_stats)/1e9);
915 if (run_count > 1) { 990 if (run_count > 1) {
916 fprintf(output, " "); 991 fprintf(stderr, " ");
917 print_noise_pct(stddev_stats(&walltime_nsecs_stats), 992 print_noise_pct(stddev_stats(&walltime_nsecs_stats),
918 avg_stats(&walltime_nsecs_stats)); 993 avg_stats(&walltime_nsecs_stats));
919 } 994 }
920 fprintf(output, "\n\n"); 995 fprintf(stderr, "\n\n");
921 } 996 }
922} 997}
923 998
@@ -943,133 +1018,83 @@ static void sig_atexit(void)
943 kill(getpid(), signr); 1018 kill(getpid(), signr);
944} 1019}
945 1020
946static int stat__set_big_num(const struct option *opt __maybe_unused, 1021static const char * const stat_usage[] = {
947 const char *s __maybe_unused, int unset) 1022 "perf stat [<options>] [<command>]",
1023 NULL
1024};
1025
1026static int stat__set_big_num(const struct option *opt __used,
1027 const char *s __used, int unset)
948{ 1028{
949 big_num_opt = unset ? 0 : 1; 1029 big_num_opt = unset ? 0 : 1;
950 return 0; 1030 return 0;
951} 1031}
952 1032
1033static const struct option options[] = {
1034 OPT_CALLBACK('e', "event", &evsel_list, "event",
1035 "event selector. use 'perf list' to list available events",
1036 parse_events_option),
1037 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1038 "event filter", parse_filter),
1039 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1040 "child tasks do not inherit counters"),
1041 OPT_INTEGER('p', "pid", &target_pid,
1042 "stat events on existing process id"),
1043 OPT_INTEGER('t', "tid", &target_tid,
1044 "stat events on existing thread id"),
1045 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1046 "system-wide collection from all CPUs"),
1047 OPT_BOOLEAN('g', "group", &group,
1048 "put the counters into a counter group"),
1049 OPT_BOOLEAN('c', "scale", &scale,
1050 "scale/normalize counters"),
1051 OPT_INCR('v', "verbose", &verbose,
1052 "be more verbose (show counter open errors, etc)"),
1053 OPT_INTEGER('r', "repeat", &run_count,
1054 "repeat command and print average + stddev (max: 100)"),
1055 OPT_BOOLEAN('n', "null", &null_run,
1056 "null run - dont start any counters"),
1057 OPT_INCR('d', "detailed", &detailed_run,
1058 "detailed run - start a lot of events"),
1059 OPT_BOOLEAN('S', "sync", &sync_run,
1060 "call sync() before starting a run"),
1061 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1062 "print large numbers with thousands\' separators",
1063 stat__set_big_num),
1064 OPT_STRING('C', "cpu", &cpu_list, "cpu",
1065 "list of cpus to monitor in system-wide"),
1066 OPT_BOOLEAN('A', "no-aggr", &no_aggr,
1067 "disable CPU count aggregation"),
1068 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1069 "print counts with custom separator"),
1070 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1071 "monitor event in cgroup name only",
1072 parse_cgroups),
1073 OPT_END()
1074};
1075
953/* 1076/*
954 * Add default attributes, if there were no attributes specified or 1077 * Add default attributes, if there were no attributes specified or
955 * if -d/--detailed, -d -d or -d -d -d is used: 1078 * if -d/--detailed, -d -d or -d -d -d is used:
956 */ 1079 */
957static int add_default_attributes(void) 1080static int add_default_attributes(void)
958{ 1081{
959 struct perf_event_attr default_attrs[] = { 1082 struct perf_evsel *pos;
960 1083 size_t attr_nr = 0;
961 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 1084 size_t c;
962 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
963 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
964 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
965
966 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
967 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
968 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
969 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
970 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
971 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
972
973};
974
975/*
976 * Detailed stats (-d), covering the L1 and last level data caches:
977 */
978 struct perf_event_attr detailed_attrs[] = {
979
980 { .type = PERF_TYPE_HW_CACHE,
981 .config =
982 PERF_COUNT_HW_CACHE_L1D << 0 |
983 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
984 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
985
986 { .type = PERF_TYPE_HW_CACHE,
987 .config =
988 PERF_COUNT_HW_CACHE_L1D << 0 |
989 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
990 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
991
992 { .type = PERF_TYPE_HW_CACHE,
993 .config =
994 PERF_COUNT_HW_CACHE_LL << 0 |
995 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
996 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
997
998 { .type = PERF_TYPE_HW_CACHE,
999 .config =
1000 PERF_COUNT_HW_CACHE_LL << 0 |
1001 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1002 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
1003};
1004
1005/*
1006 * Very detailed stats (-d -d), covering the instruction cache and the TLB caches:
1007 */
1008 struct perf_event_attr very_detailed_attrs[] = {
1009
1010 { .type = PERF_TYPE_HW_CACHE,
1011 .config =
1012 PERF_COUNT_HW_CACHE_L1I << 0 |
1013 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1014 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
1015
1016 { .type = PERF_TYPE_HW_CACHE,
1017 .config =
1018 PERF_COUNT_HW_CACHE_L1I << 0 |
1019 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1020 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
1021
1022 { .type = PERF_TYPE_HW_CACHE,
1023 .config =
1024 PERF_COUNT_HW_CACHE_DTLB << 0 |
1025 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1026 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
1027
1028 { .type = PERF_TYPE_HW_CACHE,
1029 .config =
1030 PERF_COUNT_HW_CACHE_DTLB << 0 |
1031 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1032 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
1033
1034 { .type = PERF_TYPE_HW_CACHE,
1035 .config =
1036 PERF_COUNT_HW_CACHE_ITLB << 0 |
1037 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1038 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
1039
1040 { .type = PERF_TYPE_HW_CACHE,
1041 .config =
1042 PERF_COUNT_HW_CACHE_ITLB << 0 |
1043 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1044 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
1045
1046};
1047
1048/*
1049 * Very, very detailed stats (-d -d -d), adding prefetch events:
1050 */
1051 struct perf_event_attr very_very_detailed_attrs[] = {
1052
1053 { .type = PERF_TYPE_HW_CACHE,
1054 .config =
1055 PERF_COUNT_HW_CACHE_L1D << 0 |
1056 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
1057 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
1058
1059 { .type = PERF_TYPE_HW_CACHE,
1060 .config =
1061 PERF_COUNT_HW_CACHE_L1D << 0 |
1062 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
1063 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
1064};
1065 1085
1066 /* Set attrs if no event is selected and !null_run: */ 1086 /* Set attrs if no event is selected and !null_run: */
1067 if (null_run) 1087 if (null_run)
1068 return 0; 1088 return 0;
1069 1089
1070 if (!evsel_list->nr_entries) { 1090 if (!evsel_list->nr_entries) {
1071 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) 1091 for (c = 0; c < ARRAY_SIZE(default_attrs); c++) {
1072 return -1; 1092 pos = perf_evsel__new(default_attrs + c, c + attr_nr);
1093 if (pos == NULL)
1094 return -1;
1095 perf_evlist__add(evsel_list, pos);
1096 }
1097 attr_nr += c;
1073 } 1098 }
1074 1099
1075 /* Detailed events get appended to the event list: */ 1100 /* Detailed events get appended to the event list: */
@@ -1078,82 +1103,44 @@ static int add_default_attributes(void)
1078 return 0; 1103 return 0;
1079 1104
1080 /* Append detailed run extra attributes: */ 1105 /* Append detailed run extra attributes: */
1081 if (perf_evlist__add_default_attrs(evsel_list, detailed_attrs) < 0) 1106 for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) {
1082 return -1; 1107 pos = perf_evsel__new(detailed_attrs + c, c + attr_nr);
1108 if (pos == NULL)
1109 return -1;
1110 perf_evlist__add(evsel_list, pos);
1111 }
1112 attr_nr += c;
1083 1113
1084 if (detailed_run < 2) 1114 if (detailed_run < 2)
1085 return 0; 1115 return 0;
1086 1116
1087 /* Append very detailed run extra attributes: */ 1117 /* Append very detailed run extra attributes: */
1088 if (perf_evlist__add_default_attrs(evsel_list, very_detailed_attrs) < 0) 1118 for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) {
1089 return -1; 1119 pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr);
1120 if (pos == NULL)
1121 return -1;
1122 perf_evlist__add(evsel_list, pos);
1123 }
1090 1124
1091 if (detailed_run < 3) 1125 if (detailed_run < 3)
1092 return 0; 1126 return 0;
1093 1127
1094 /* Append very, very detailed run extra attributes: */ 1128 /* Append very, very detailed run extra attributes: */
1095 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); 1129 for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) {
1130 pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr);
1131 if (pos == NULL)
1132 return -1;
1133 perf_evlist__add(evsel_list, pos);
1134 }
1135
1136
1137 return 0;
1096} 1138}
1097 1139
1098int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 1140int cmd_stat(int argc, const char **argv, const char *prefix __used)
1099{ 1141{
1100 bool append_file = false;
1101 int output_fd = 0;
1102 const char *output_name = NULL;
1103 const struct option options[] = {
1104 OPT_CALLBACK('e', "event", &evsel_list, "event",
1105 "event selector. use 'perf list' to list available events",
1106 parse_events_option),
1107 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1108 "event filter", parse_filter),
1109 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1110 "child tasks do not inherit counters"),
1111 OPT_STRING('p', "pid", &target.pid, "pid",
1112 "stat events on existing process id"),
1113 OPT_STRING('t', "tid", &target.tid, "tid",
1114 "stat events on existing thread id"),
1115 OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
1116 "system-wide collection from all CPUs"),
1117 OPT_BOOLEAN('g', "group", &group,
1118 "put the counters into a counter group"),
1119 OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"),
1120 OPT_INCR('v', "verbose", &verbose,
1121 "be more verbose (show counter open errors, etc)"),
1122 OPT_INTEGER('r', "repeat", &run_count,
1123 "repeat command and print average + stddev (max: 100)"),
1124 OPT_BOOLEAN('n', "null", &null_run,
1125 "null run - dont start any counters"),
1126 OPT_INCR('d', "detailed", &detailed_run,
1127 "detailed run - start a lot of events"),
1128 OPT_BOOLEAN('S', "sync", &sync_run,
1129 "call sync() before starting a run"),
1130 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1131 "print large numbers with thousands\' separators",
1132 stat__set_big_num),
1133 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1134 "list of cpus to monitor in system-wide"),
1135 OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"),
1136 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1137 "print counts with custom separator"),
1138 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1139 "monitor event in cgroup name only", parse_cgroups),
1140 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1141 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1142 OPT_INTEGER(0, "log-fd", &output_fd,
1143 "log output to fd, instead of stderr"),
1144 OPT_STRING(0, "pre", &pre_cmd, "command",
1145 "command to run prior to the measured command"),
1146 OPT_STRING(0, "post", &post_cmd, "command",
1147 "command to run after to the measured command"),
1148 OPT_END()
1149 };
1150 const char * const stat_usage[] = {
1151 "perf stat [<options>] [<command>]",
1152 NULL
1153 };
1154 struct perf_evsel *pos; 1142 struct perf_evsel *pos;
1155 int status = -ENOMEM, run_idx; 1143 int status = -ENOMEM;
1156 const char *mode;
1157 1144
1158 setlocale(LC_ALL, ""); 1145 setlocale(LC_ALL, "");
1159 1146
@@ -1164,52 +1151,16 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1164 argc = parse_options(argc, argv, options, stat_usage, 1151 argc = parse_options(argc, argv, options, stat_usage,
1165 PARSE_OPT_STOP_AT_NON_OPTION); 1152 PARSE_OPT_STOP_AT_NON_OPTION);
1166 1153
1167 output = stderr; 1154 if (csv_sep)
1168 if (output_name && strcmp(output_name, "-"))
1169 output = NULL;
1170
1171 if (output_name && output_fd) {
1172 fprintf(stderr, "cannot use both --output and --log-fd\n");
1173 usage_with_options(stat_usage, options);
1174 }
1175
1176 if (output_fd < 0) {
1177 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1178 usage_with_options(stat_usage, options);
1179 }
1180
1181 if (!output) {
1182 struct timespec tm;
1183 mode = append_file ? "a" : "w";
1184
1185 output = fopen(output_name, mode);
1186 if (!output) {
1187 perror("failed to create output file");
1188 return -1;
1189 }
1190 clock_gettime(CLOCK_REALTIME, &tm);
1191 fprintf(output, "# started on %s\n", ctime(&tm.tv_sec));
1192 } else if (output_fd > 0) {
1193 mode = append_file ? "a" : "w";
1194 output = fdopen(output_fd, mode);
1195 if (!output) {
1196 perror("Failed opening logfd");
1197 return -errno;
1198 }
1199 }
1200
1201 if (csv_sep) {
1202 csv_output = true; 1155 csv_output = true;
1203 if (!strcmp(csv_sep, "\\t")) 1156 else
1204 csv_sep = "\t";
1205 } else
1206 csv_sep = DEFAULT_SEPARATOR; 1157 csv_sep = DEFAULT_SEPARATOR;
1207 1158
1208 /* 1159 /*
1209 * let the spreadsheet do the pretty-printing 1160 * let the spreadsheet do the pretty-printing
1210 */ 1161 */
1211 if (csv_output) { 1162 if (csv_output) {
1212 /* User explicitly passed -B? */ 1163 /* User explicitely passed -B? */
1213 if (big_num_opt == 1) { 1164 if (big_num_opt == 1) {
1214 fprintf(stderr, "-B option not supported with -x\n"); 1165 fprintf(stderr, "-B option not supported with -x\n");
1215 usage_with_options(stat_usage, options); 1166 usage_with_options(stat_usage, options);
@@ -1218,13 +1169,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1218 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1169 } else if (big_num_opt == 0) /* User passed --no-big-num */
1219 big_num = false; 1170 big_num = false;
1220 1171
1221 if (!argc && !perf_target__has_task(&target)) 1172 if (!argc && target_pid == -1 && target_tid == -1)
1222 usage_with_options(stat_usage, options); 1173 usage_with_options(stat_usage, options);
1223 if (run_count <= 0) 1174 if (run_count <= 0)
1224 usage_with_options(stat_usage, options); 1175 usage_with_options(stat_usage, options);
1225 1176
1226 /* no_aggr, cgroup are for system-wide only */ 1177 /* no_aggr, cgroup are for system-wide only */
1227 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { 1178 if ((no_aggr || nr_cgroups) && !system_wide) {
1228 fprintf(stderr, "both cgroup and no-aggregation " 1179 fprintf(stderr, "both cgroup and no-aggregation "
1229 "modes only available in system-wide mode\n"); 1180 "modes only available in system-wide mode\n");
1230 1181
@@ -1234,21 +1185,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1234 if (add_default_attributes()) 1185 if (add_default_attributes())
1235 goto out; 1186 goto out;
1236 1187
1237 perf_target__validate(&target); 1188 if (target_pid != -1)
1189 target_tid = target_pid;
1238 1190
1239 if (perf_evlist__create_maps(evsel_list, &target) < 0) { 1191 evsel_list->threads = thread_map__new(target_pid, target_tid);
1240 if (perf_target__has_task(&target)) 1192 if (evsel_list->threads == NULL) {
1241 pr_err("Problems finding threads of monitor\n"); 1193 pr_err("Problems finding threads of monitor\n");
1242 if (perf_target__has_cpu(&target)) 1194 usage_with_options(stat_usage, options);
1243 perror("failed to parse CPUs map"); 1195 }
1244 1196
1197 if (system_wide)
1198 evsel_list->cpus = cpu_map__new(cpu_list);
1199 else
1200 evsel_list->cpus = cpu_map__dummy_new();
1201
1202 if (evsel_list->cpus == NULL) {
1203 perror("failed to parse CPUs map");
1245 usage_with_options(stat_usage, options); 1204 usage_with_options(stat_usage, options);
1246 return -1; 1205 return -1;
1247 } 1206 }
1248 1207
1249 list_for_each_entry(pos, &evsel_list->entries, node) { 1208 list_for_each_entry(pos, &evsel_list->entries, node) {
1250 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1209 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
1251 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) 1210 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
1211 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
1252 goto out_free_fd; 1212 goto out_free_fd;
1253 } 1213 }
1254 1214
@@ -1266,8 +1226,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1266 status = 0; 1226 status = 0;
1267 for (run_idx = 0; run_idx < run_count; run_idx++) { 1227 for (run_idx = 0; run_idx < run_count; run_idx++) {
1268 if (run_count != 1 && verbose) 1228 if (run_count != 1 && verbose)
1269 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1229 fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1);
1270 run_idx + 1); 1230
1231 if (sync_run)
1232 sync();
1271 1233
1272 status = run_perf_stat(argc, argv); 1234 status = run_perf_stat(argc, argv);
1273 } 1235 }
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index ab4cf232b85..aa26f4d66d1 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -19,7 +19,6 @@
19#include "util/color.h" 19#include "util/color.h"
20#include <linux/list.h> 20#include <linux/list.h>
21#include "util/cache.h" 21#include "util/cache.h"
22#include "util/evsel.h"
23#include <linux/rbtree.h> 22#include <linux/rbtree.h>
24#include "util/symbol.h" 23#include "util/symbol.h"
25#include "util/callchain.h" 24#include "util/callchain.h"
@@ -32,12 +31,14 @@
32#include "util/event.h" 31#include "util/event.h"
33#include "util/session.h" 32#include "util/session.h"
34#include "util/svghelper.h" 33#include "util/svghelper.h"
35#include "util/tool.h"
36 34
37#define SUPPORT_OLD_POWER_EVENTS 1 35#define SUPPORT_OLD_POWER_EVENTS 1
38#define PWR_EVENT_EXIT -1 36#define PWR_EVENT_EXIT -1
39 37
40 38
39static char const *input_name = "perf.data";
40static char const *output_name = "output.svg";
41
41static unsigned int numcpus; 42static unsigned int numcpus;
42static u64 min_freq; /* Lowest CPU frequency seen */ 43static u64 min_freq; /* Lowest CPU frequency seen */
43static u64 max_freq; /* Highest CPU frequency seen */ 44static u64 max_freq; /* Highest CPU frequency seen */
@@ -165,8 +166,9 @@ static struct per_pid *find_create_pid(int pid)
165 return cursor; 166 return cursor;
166 cursor = cursor->next; 167 cursor = cursor->next;
167 } 168 }
168 cursor = zalloc(sizeof(*cursor)); 169 cursor = malloc(sizeof(struct per_pid));
169 assert(cursor != NULL); 170 assert(cursor != NULL);
171 memset(cursor, 0, sizeof(struct per_pid));
170 cursor->pid = pid; 172 cursor->pid = pid;
171 cursor->next = all_data; 173 cursor->next = all_data;
172 all_data = cursor; 174 all_data = cursor;
@@ -191,8 +193,9 @@ static void pid_set_comm(int pid, char *comm)
191 } 193 }
192 c = c->next; 194 c = c->next;
193 } 195 }
194 c = zalloc(sizeof(*c)); 196 c = malloc(sizeof(struct per_pidcomm));
195 assert(c != NULL); 197 assert(c != NULL);
198 memset(c, 0, sizeof(struct per_pidcomm));
196 c->comm = strdup(comm); 199 c->comm = strdup(comm);
197 p->current = c; 200 p->current = c;
198 c->next = p->all; 201 c->next = p->all;
@@ -234,15 +237,17 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
234 p = find_create_pid(pid); 237 p = find_create_pid(pid);
235 c = p->current; 238 c = p->current;
236 if (!c) { 239 if (!c) {
237 c = zalloc(sizeof(*c)); 240 c = malloc(sizeof(struct per_pidcomm));
238 assert(c != NULL); 241 assert(c != NULL);
242 memset(c, 0, sizeof(struct per_pidcomm));
239 p->current = c; 243 p->current = c;
240 c->next = p->all; 244 c->next = p->all;
241 p->all = c; 245 p->all = c;
242 } 246 }
243 247
244 sample = zalloc(sizeof(*sample)); 248 sample = malloc(sizeof(struct cpu_sample));
245 assert(sample != NULL); 249 assert(sample != NULL);
250 memset(sample, 0, sizeof(struct cpu_sample));
246 sample->start_time = start; 251 sample->start_time = start;
247 sample->end_time = end; 252 sample->end_time = end;
248 sample->type = type; 253 sample->type = type;
@@ -268,28 +273,25 @@ static int cpus_cstate_state[MAX_CPUS];
268static u64 cpus_pstate_start_times[MAX_CPUS]; 273static u64 cpus_pstate_start_times[MAX_CPUS];
269static u64 cpus_pstate_state[MAX_CPUS]; 274static u64 cpus_pstate_state[MAX_CPUS];
270 275
271static int process_comm_event(struct perf_tool *tool __maybe_unused, 276static int process_comm_event(union perf_event *event,
272 union perf_event *event, 277 struct perf_sample *sample __used,
273 struct perf_sample *sample __maybe_unused, 278 struct perf_session *session __used)
274 struct machine *machine __maybe_unused)
275{ 279{
276 pid_set_comm(event->comm.tid, event->comm.comm); 280 pid_set_comm(event->comm.tid, event->comm.comm);
277 return 0; 281 return 0;
278} 282}
279 283
280static int process_fork_event(struct perf_tool *tool __maybe_unused, 284static int process_fork_event(union perf_event *event,
281 union perf_event *event, 285 struct perf_sample *sample __used,
282 struct perf_sample *sample __maybe_unused, 286 struct perf_session *session __used)
283 struct machine *machine __maybe_unused)
284{ 287{
285 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 288 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
286 return 0; 289 return 0;
287} 290}
288 291
289static int process_exit_event(struct perf_tool *tool __maybe_unused, 292static int process_exit_event(union perf_event *event,
290 union perf_event *event, 293 struct perf_sample *sample __used,
291 struct perf_sample *sample __maybe_unused, 294 struct perf_session *session __used)
292 struct machine *machine __maybe_unused)
293{ 295{
294 pid_exit(event->fork.pid, event->fork.time); 296 pid_exit(event->fork.pid, event->fork.time);
295 return 0; 297 return 0;
@@ -366,10 +368,11 @@ static void c_state_start(int cpu, u64 timestamp, int state)
366 368
367static void c_state_end(int cpu, u64 timestamp) 369static void c_state_end(int cpu, u64 timestamp)
368{ 370{
369 struct power_event *pwr = zalloc(sizeof(*pwr)); 371 struct power_event *pwr;
370 372 pwr = malloc(sizeof(struct power_event));
371 if (!pwr) 373 if (!pwr)
372 return; 374 return;
375 memset(pwr, 0, sizeof(struct power_event));
373 376
374 pwr->state = cpus_cstate_state[cpu]; 377 pwr->state = cpus_cstate_state[cpu];
375 pwr->start_time = cpus_cstate_start_times[cpu]; 378 pwr->start_time = cpus_cstate_start_times[cpu];
@@ -384,13 +387,14 @@ static void c_state_end(int cpu, u64 timestamp)
384static void p_state_change(int cpu, u64 timestamp, u64 new_freq) 387static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
385{ 388{
386 struct power_event *pwr; 389 struct power_event *pwr;
390 pwr = malloc(sizeof(struct power_event));
387 391
388 if (new_freq > 8000000) /* detect invalid data */ 392 if (new_freq > 8000000) /* detect invalid data */
389 return; 393 return;
390 394
391 pwr = zalloc(sizeof(*pwr));
392 if (!pwr) 395 if (!pwr)
393 return; 396 return;
397 memset(pwr, 0, sizeof(struct power_event));
394 398
395 pwr->state = cpus_pstate_state[cpu]; 399 pwr->state = cpus_pstate_state[cpu];
396 pwr->start_time = cpus_pstate_start_times[cpu]; 400 pwr->start_time = cpus_pstate_start_times[cpu];
@@ -420,13 +424,15 @@ static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
420static void 424static void
421sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te) 425sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te)
422{ 426{
427 struct wake_event *we;
423 struct per_pid *p; 428 struct per_pid *p;
424 struct wakeup_entry *wake = (void *)te; 429 struct wakeup_entry *wake = (void *)te;
425 struct wake_event *we = zalloc(sizeof(*we));
426 430
431 we = malloc(sizeof(struct wake_event));
427 if (!we) 432 if (!we)
428 return; 433 return;
429 434
435 memset(we, 0, sizeof(struct wake_event));
430 we->time = timestamp; 436 we->time = timestamp;
431 we->waker = pid; 437 we->waker = pid;
432 438
@@ -480,15 +486,14 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
480} 486}
481 487
482 488
483static int process_sample_event(struct perf_tool *tool __maybe_unused, 489static int process_sample_event(union perf_event *event __used,
484 union perf_event *event __maybe_unused,
485 struct perf_sample *sample, 490 struct perf_sample *sample,
486 struct perf_evsel *evsel, 491 struct perf_evsel *evsel __used,
487 struct machine *machine __maybe_unused) 492 struct perf_session *session)
488{ 493{
489 struct trace_entry *te; 494 struct trace_entry *te;
490 495
491 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { 496 if (session->sample_type & PERF_SAMPLE_TIME) {
492 if (!first_time || first_time > sample->time) 497 if (!first_time || first_time > sample->time)
493 first_time = sample->time; 498 first_time = sample->time;
494 if (last_time < sample->time) 499 if (last_time < sample->time)
@@ -496,7 +501,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
496 } 501 }
497 502
498 te = (void *)sample->raw_data; 503 te = (void *)sample->raw_data;
499 if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { 504 if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
500 char *event_str; 505 char *event_str;
501#ifdef SUPPORT_OLD_POWER_EVENTS 506#ifdef SUPPORT_OLD_POWER_EVENTS
502 struct power_entry_old *peo; 507 struct power_entry_old *peo;
@@ -568,12 +573,13 @@ static void end_sample_processing(void)
568 struct power_event *pwr; 573 struct power_event *pwr;
569 574
570 for (cpu = 0; cpu <= numcpus; cpu++) { 575 for (cpu = 0; cpu <= numcpus; cpu++) {
571 /* C state */ 576 pwr = malloc(sizeof(struct power_event));
572#if 0
573 pwr = zalloc(sizeof(*pwr));
574 if (!pwr) 577 if (!pwr)
575 return; 578 return;
579 memset(pwr, 0, sizeof(struct power_event));
576 580
581 /* C state */
582#if 0
577 pwr->state = cpus_cstate_state[cpu]; 583 pwr->state = cpus_cstate_state[cpu];
578 pwr->start_time = cpus_cstate_start_times[cpu]; 584 pwr->start_time = cpus_cstate_start_times[cpu];
579 pwr->end_time = last_time; 585 pwr->end_time = last_time;
@@ -585,9 +591,10 @@ static void end_sample_processing(void)
585#endif 591#endif
586 /* P state */ 592 /* P state */
587 593
588 pwr = zalloc(sizeof(*pwr)); 594 pwr = malloc(sizeof(struct power_event));
589 if (!pwr) 595 if (!pwr)
590 return; 596 return;
597 memset(pwr, 0, sizeof(struct power_event));
591 598
592 pwr->state = cpus_pstate_state[cpu]; 599 pwr->state = cpus_pstate_state[cpu];
593 pwr->start_time = cpus_pstate_start_times[cpu]; 600 pwr->start_time = cpus_pstate_start_times[cpu];
@@ -817,9 +824,11 @@ static void draw_process_bars(void)
817 824
818static void add_process_filter(const char *string) 825static void add_process_filter(const char *string)
819{ 826{
820 int pid = strtoull(string, NULL, 10); 827 struct process_filter *filt;
821 struct process_filter *filt = malloc(sizeof(*filt)); 828 int pid;
822 829
830 pid = strtoull(string, NULL, 10);
831 filt = malloc(sizeof(struct process_filter));
823 if (!filt) 832 if (!filt)
824 return; 833 return;
825 834
@@ -965,17 +974,18 @@ static void write_svg_file(const char *filename)
965 svg_close(); 974 svg_close();
966} 975}
967 976
968static int __cmd_timechart(const char *output_name) 977static struct perf_event_ops event_ops = {
978 .comm = process_comm_event,
979 .fork = process_fork_event,
980 .exit = process_exit_event,
981 .sample = process_sample_event,
982 .ordered_samples = true,
983};
984
985static int __cmd_timechart(void)
969{ 986{
970 struct perf_tool perf_timechart = {
971 .comm = process_comm_event,
972 .fork = process_fork_event,
973 .exit = process_exit_event,
974 .sample = process_sample_event,
975 .ordered_samples = true,
976 };
977 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 987 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
978 0, false, &perf_timechart); 988 0, false, &event_ops);
979 int ret = -EINVAL; 989 int ret = -EINVAL;
980 990
981 if (session == NULL) 991 if (session == NULL)
@@ -984,7 +994,7 @@ static int __cmd_timechart(const char *output_name)
984 if (!perf_session__has_traces(session, "timechart record")) 994 if (!perf_session__has_traces(session, "timechart record"))
985 goto out_delete; 995 goto out_delete;
986 996
987 ret = perf_session__process_events(session, &perf_timechart); 997 ret = perf_session__process_events(session, &event_ops);
988 if (ret) 998 if (ret)
989 goto out_delete; 999 goto out_delete;
990 1000
@@ -1001,25 +1011,40 @@ out_delete:
1001 return ret; 1011 return ret;
1002} 1012}
1003 1013
1004static int __cmd_record(int argc, const char **argv) 1014static const char * const timechart_usage[] = {
1005{ 1015 "perf timechart [<options>] {record}",
1016 NULL
1017};
1018
1006#ifdef SUPPORT_OLD_POWER_EVENTS 1019#ifdef SUPPORT_OLD_POWER_EVENTS
1007 const char * const record_old_args[] = { 1020static const char * const record_old_args[] = {
1008 "record", "-a", "-R", "-f", "-c", "1", 1021 "record",
1009 "-e", "power:power_start", 1022 "-a",
1010 "-e", "power:power_end", 1023 "-R",
1011 "-e", "power:power_frequency", 1024 "-f",
1012 "-e", "sched:sched_wakeup", 1025 "-c", "1",
1013 "-e", "sched:sched_switch", 1026 "-e", "power:power_start",
1014 }; 1027 "-e", "power:power_end",
1028 "-e", "power:power_frequency",
1029 "-e", "sched:sched_wakeup",
1030 "-e", "sched:sched_switch",
1031};
1015#endif 1032#endif
1016 const char * const record_new_args[] = { 1033
1017 "record", "-a", "-R", "-f", "-c", "1", 1034static const char * const record_new_args[] = {
1018 "-e", "power:cpu_frequency", 1035 "record",
1019 "-e", "power:cpu_idle", 1036 "-a",
1020 "-e", "sched:sched_wakeup", 1037 "-R",
1021 "-e", "sched:sched_switch", 1038 "-f",
1022 }; 1039 "-c", "1",
1040 "-e", "power:cpu_frequency",
1041 "-e", "power:cpu_idle",
1042 "-e", "sched:sched_wakeup",
1043 "-e", "sched:sched_switch",
1044};
1045
1046static int __cmd_record(int argc, const char **argv)
1047{
1023 unsigned int rec_argc, i, j; 1048 unsigned int rec_argc, i, j;
1024 const char **rec_argv; 1049 const char **rec_argv;
1025 const char * const *record_args = record_new_args; 1050 const char * const *record_args = record_new_args;
@@ -1050,35 +1075,33 @@ static int __cmd_record(int argc, const char **argv)
1050} 1075}
1051 1076
1052static int 1077static int
1053parse_process(const struct option *opt __maybe_unused, const char *arg, 1078parse_process(const struct option *opt __used, const char *arg, int __used unset)
1054 int __maybe_unused unset)
1055{ 1079{
1056 if (arg) 1080 if (arg)
1057 add_process_filter(arg); 1081 add_process_filter(arg);
1058 return 0; 1082 return 0;
1059} 1083}
1060 1084
1061int cmd_timechart(int argc, const char **argv, 1085static const struct option options[] = {
1062 const char *prefix __maybe_unused) 1086 OPT_STRING('i', "input", &input_name, "file",
1063{ 1087 "input file name"),
1064 const char *output_name = "output.svg"; 1088 OPT_STRING('o', "output", &output_name, "file",
1065 const struct option options[] = { 1089 "output file name"),
1066 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1090 OPT_INTEGER('w', "width", &svg_page_width,
1067 OPT_STRING('o', "output", &output_name, "file", "output file name"), 1091 "page width"),
1068 OPT_INTEGER('w', "width", &svg_page_width, "page width"), 1092 OPT_BOOLEAN('P', "power-only", &power_only,
1069 OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), 1093 "output power data only"),
1070 OPT_CALLBACK('p', "process", NULL, "process", 1094 OPT_CALLBACK('p', "process", NULL, "process",
1071 "process selector. Pass a pid or process name.", 1095 "process selector. Pass a pid or process name.",
1072 parse_process), 1096 parse_process),
1073 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 1097 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1074 "Look for files with symbols relative to this directory"), 1098 "Look for files with symbols relative to this directory"),
1075 OPT_END() 1099 OPT_END()
1076 }; 1100};
1077 const char * const timechart_usage[] = { 1101
1078 "perf timechart [<options>] {record}",
1079 NULL
1080 };
1081 1102
1103int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1104{
1082 argc = parse_options(argc, argv, options, timechart_usage, 1105 argc = parse_options(argc, argv, options, timechart_usage,
1083 PARSE_OPT_STOP_AT_NON_OPTION); 1106 PARSE_OPT_STOP_AT_NON_OPTION);
1084 1107
@@ -1091,5 +1114,5 @@ int cmd_timechart(int argc, const char **argv,
1091 1114
1092 setup_pager(); 1115 setup_pager();
1093 1116
1094 return __cmd_timechart(output_name); 1117 return __cmd_timechart();
1095} 1118}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9ff3950cd4..d28013b7d61 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -5,7 +5,6 @@
5 * any workload, CPU or specific PID. 5 * any workload, CPU or specific PID.
6 * 6 *
7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
9 * 8 *
10 * Improvements and fixes by: 9 * Improvements and fixes by:
11 * 10 *
@@ -26,7 +25,6 @@
26#include "util/color.h" 25#include "util/color.h"
27#include "util/evlist.h" 26#include "util/evlist.h"
28#include "util/evsel.h" 27#include "util/evsel.h"
29#include "util/machine.h"
30#include "util/session.h" 28#include "util/session.h"
31#include "util/symbol.h" 29#include "util/symbol.h"
32#include "util/thread.h" 30#include "util/thread.h"
@@ -38,13 +36,10 @@
38#include "util/parse-events.h" 36#include "util/parse-events.h"
39#include "util/cpumap.h" 37#include "util/cpumap.h"
40#include "util/xyarray.h" 38#include "util/xyarray.h"
41#include "util/sort.h"
42#include "util/intlist.h"
43 39
44#include "util/debug.h" 40#include "util/debug.h"
45 41
46#include <assert.h> 42#include <assert.h>
47#include <elf.h>
48#include <fcntl.h> 43#include <fcntl.h>
49 44
50#include <stdio.h> 45#include <stdio.h>
@@ -62,12 +57,49 @@
62#include <sys/prctl.h> 57#include <sys/prctl.h>
63#include <sys/wait.h> 58#include <sys/wait.h>
64#include <sys/uio.h> 59#include <sys/uio.h>
65#include <sys/utsname.h>
66#include <sys/mman.h> 60#include <sys/mman.h>
67 61
68#include <linux/unistd.h> 62#include <linux/unistd.h>
69#include <linux/types.h> 63#include <linux/types.h>
70 64
65static struct perf_top top = {
66 .count_filter = 5,
67 .delay_secs = 2,
68 .display_weighted = -1,
69 .target_pid = -1,
70 .target_tid = -1,
71 .active_symbols = LIST_HEAD_INIT(top.active_symbols),
72 .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER,
73 .active_symbols_cond = PTHREAD_COND_INITIALIZER,
74 .freq = 1000, /* 1 KHz */
75};
76
77static bool system_wide = false;
78
79static bool use_tui, use_stdio;
80
81static int default_interval = 0;
82
83static bool kptr_restrict_warned;
84static bool vmlinux_warned;
85static bool inherit = false;
86static int realtime_prio = 0;
87static bool group = false;
88static unsigned int page_size;
89static unsigned int mmap_pages = 128;
90
91static bool dump_symtab = false;
92
93static struct winsize winsize;
94
95static const char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5;
98
99/*
100 * Source functions
101 */
102
71void get_term_dimensions(struct winsize *ws) 103void get_term_dimensions(struct winsize *ws)
72{ 104{
73 char *s = getenv("LINES"); 105 char *s = getenv("LINES");
@@ -90,45 +122,37 @@ void get_term_dimensions(struct winsize *ws)
90 ws->ws_col = 80; 122 ws->ws_col = 80;
91} 123}
92 124
93static void perf_top__update_print_entries(struct perf_top *top) 125static void update_print_entries(struct winsize *ws)
94{ 126{
95 if (top->print_entries > 9) 127 top.print_entries = ws->ws_row;
96 top->print_entries -= 9; 128
129 if (top.print_entries > 9)
130 top.print_entries -= 9;
97} 131}
98 132
99static void perf_top__sig_winch(int sig __maybe_unused, 133static void sig_winch_handler(int sig __used)
100 siginfo_t *info __maybe_unused, void *arg)
101{ 134{
102 struct perf_top *top = arg; 135 get_term_dimensions(&winsize);
103 136 update_print_entries(&winsize);
104 get_term_dimensions(&top->winsize);
105 if (!top->print_entries
106 || (top->print_entries+4) > top->winsize.ws_row) {
107 top->print_entries = top->winsize.ws_row;
108 } else {
109 top->print_entries += 4;
110 top->winsize.ws_row = top->print_entries;
111 }
112 perf_top__update_print_entries(top);
113} 137}
114 138
115static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) 139static int parse_source(struct sym_entry *syme)
116{ 140{
117 struct symbol *sym; 141 struct symbol *sym;
118 struct annotation *notes; 142 struct annotation *notes;
119 struct map *map; 143 struct map *map;
120 int err = -1; 144 int err = -1;
121 145
122 if (!he || !he->ms.sym) 146 if (!syme)
123 return -1; 147 return -1;
124 148
125 sym = he->ms.sym; 149 sym = sym_entry__symbol(syme);
126 map = he->ms.map; 150 map = syme->map;
127 151
128 /* 152 /*
129 * We can't annotate with just /proc/kallsyms 153 * We can't annotate with just /proc/kallsyms
130 */ 154 */
131 if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { 155 if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
132 pr_err("Can't annotate %s: No vmlinux file was found in the " 156 pr_err("Can't annotate %s: No vmlinux file was found in the "
133 "path\n", sym->name); 157 "path\n", sym->name);
134 sleep(1); 158 sleep(1);
@@ -143,7 +167,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
143 167
144 pthread_mutex_lock(&notes->lock); 168 pthread_mutex_lock(&notes->lock);
145 169
146 if (symbol__alloc_hist(sym) < 0) { 170 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
147 pthread_mutex_unlock(&notes->lock); 171 pthread_mutex_unlock(&notes->lock);
148 pr_err("Not enough memory for annotating '%s' symbol!\n", 172 pr_err("Not enough memory for annotating '%s' symbol!\n",
149 sym->name); 173 sym->name);
@@ -151,96 +175,53 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
151 return err; 175 return err;
152 } 176 }
153 177
154 err = symbol__annotate(sym, map, 0); 178 err = symbol__annotate(sym, syme->map, 0);
155 if (err == 0) { 179 if (err == 0) {
156out_assign: 180out_assign:
157 top->sym_filter_entry = he; 181 top.sym_filter_entry = syme;
158 } 182 }
159 183
160 pthread_mutex_unlock(&notes->lock); 184 pthread_mutex_unlock(&notes->lock);
161 return err; 185 return err;
162} 186}
163 187
164static void __zero_source_counters(struct hist_entry *he) 188static void __zero_source_counters(struct sym_entry *syme)
165{ 189{
166 struct symbol *sym = he->ms.sym; 190 struct symbol *sym = sym_entry__symbol(syme);
167 symbol__annotate_zero_histograms(sym); 191 symbol__annotate_zero_histograms(sym);
168} 192}
169 193
170static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) 194static void record_precise_ip(struct sym_entry *syme, struct map *map,
171{ 195 int counter, u64 ip)
172 struct utsname uts;
173 int err = uname(&uts);
174
175 ui__warning("Out of bounds address found:\n\n"
176 "Addr: %" PRIx64 "\n"
177 "DSO: %s %c\n"
178 "Map: %" PRIx64 "-%" PRIx64 "\n"
179 "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n"
180 "Arch: %s\n"
181 "Kernel: %s\n"
182 "Tools: %s\n\n"
183 "Not all samples will be on the annotation output.\n\n"
184 "Please report to linux-kernel@vger.kernel.org\n",
185 ip, map->dso->long_name, dso__symtab_origin(map->dso),
186 map->start, map->end, sym->start, sym->end,
187 sym->binding == STB_GLOBAL ? 'g' :
188 sym->binding == STB_LOCAL ? 'l' : 'w', sym->name,
189 err ? "[unknown]" : uts.machine,
190 err ? "[unknown]" : uts.release, perf_version_string);
191 if (use_browser <= 0)
192 sleep(5);
193
194 map->erange_warned = true;
195}
196
197static void perf_top__record_precise_ip(struct perf_top *top,
198 struct hist_entry *he,
199 int counter, u64 ip)
200{ 196{
201 struct annotation *notes; 197 struct annotation *notes;
202 struct symbol *sym; 198 struct symbol *sym;
203 int err;
204 199
205 if (he == NULL || he->ms.sym == NULL || 200 if (syme != top.sym_filter_entry)
206 ((top->sym_filter_entry == NULL ||
207 top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
208 return; 201 return;
209 202
210 sym = he->ms.sym; 203 sym = sym_entry__symbol(syme);
211 notes = symbol__annotation(sym); 204 notes = symbol__annotation(sym);
212 205
213 if (pthread_mutex_trylock(&notes->lock)) 206 if (pthread_mutex_trylock(&notes->lock))
214 return; 207 return;
215 208
216 if (notes->src == NULL && symbol__alloc_hist(sym) < 0) { 209 ip = map->map_ip(map, ip);
217 pthread_mutex_unlock(&notes->lock); 210 symbol__inc_addr_samples(sym, map, counter, ip);
218 pr_err("Not enough memory for annotating '%s' symbol!\n",
219 sym->name);
220 sleep(1);
221 return;
222 }
223
224 ip = he->ms.map->map_ip(he->ms.map, ip);
225 err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
226 211
227 pthread_mutex_unlock(&notes->lock); 212 pthread_mutex_unlock(&notes->lock);
228
229 if (err == -ERANGE && !he->ms.map->erange_warned)
230 ui__warn_map_erange(he->ms.map, sym, ip);
231} 213}
232 214
233static void perf_top__show_details(struct perf_top *top) 215static void show_details(struct sym_entry *syme)
234{ 216{
235 struct hist_entry *he = top->sym_filter_entry;
236 struct annotation *notes; 217 struct annotation *notes;
237 struct symbol *symbol; 218 struct symbol *symbol;
238 int more; 219 int more;
239 220
240 if (!he) 221 if (!syme)
241 return; 222 return;
242 223
243 symbol = he->ms.sym; 224 symbol = sym_entry__symbol(syme);
244 notes = symbol__annotation(symbol); 225 notes = symbol__annotation(symbol);
245 226
246 pthread_mutex_lock(&notes->lock); 227 pthread_mutex_lock(&notes->lock);
@@ -248,15 +229,15 @@ static void perf_top__show_details(struct perf_top *top)
248 if (notes->src == NULL) 229 if (notes->src == NULL)
249 goto out_unlock; 230 goto out_unlock;
250 231
251 printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); 232 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
252 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); 233 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
253 234
254 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, 235 more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx,
255 0, top->sym_pcnt_filter, top->print_entries, 4); 236 0, sym_pcnt_filter, top.print_entries, 4);
256 if (top->zero) 237 if (top.zero)
257 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); 238 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
258 else 239 else
259 symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); 240 symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx);
260 if (more != 0) 241 if (more != 0)
261 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 242 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
262out_unlock: 243out_unlock:
@@ -265,60 +246,94 @@ out_unlock:
265 246
266static const char CONSOLE_CLEAR[] = ""; 247static const char CONSOLE_CLEAR[] = "";
267 248
268static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, 249static void __list_insert_active_sym(struct sym_entry *syme)
269 struct addr_location *al,
270 struct perf_sample *sample)
271{ 250{
272 struct hist_entry *he; 251 list_add(&syme->node, &top.active_symbols);
273
274 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
275 if (he == NULL)
276 return NULL;
277
278 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
279 return he;
280} 252}
281 253
282static void perf_top__print_sym_table(struct perf_top *top) 254static void print_sym_table(struct perf_session *session)
283{ 255{
284 char bf[160]; 256 char bf[160];
285 int printed = 0; 257 int printed = 0;
286 const int win_width = top->winsize.ws_col - 1; 258 struct rb_node *nd;
259 struct sym_entry *syme;
260 struct rb_root tmp = RB_ROOT;
261 const int win_width = winsize.ws_col - 1;
262 int sym_width, dso_width, dso_short_width;
263 float sum_ksamples = perf_top__decay_samples(&top, &tmp);
287 264
288 puts(CONSOLE_CLEAR); 265 puts(CONSOLE_CLEAR);
289 266
290 perf_top__header_snprintf(top, bf, sizeof(bf)); 267 perf_top__header_snprintf(&top, bf, sizeof(bf));
291 printf("%s\n", bf); 268 printf("%s\n", bf);
292 269
293 perf_top__reset_sample_counters(top); 270 perf_top__reset_sample_counters(&top);
294 271
295 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 272 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
296 273
297 if (top->sym_evsel->hists.stats.nr_lost_warned != 274 if (session->hists.stats.total_lost != 0) {
298 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { 275 color_fprintf(stdout, PERF_COLOR_RED, "WARNING:");
299 top->sym_evsel->hists.stats.nr_lost_warned = 276 printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n",
300 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 277 session->hists.stats.total_lost);
301 color_fprintf(stdout, PERF_COLOR_RED,
302 "WARNING: LOST %d chunks, Check IO/CPU overload",
303 top->sym_evsel->hists.stats.nr_lost_warned);
304 ++printed;
305 } 278 }
306 279
307 if (top->sym_filter_entry) { 280 if (top.sym_filter_entry) {
308 perf_top__show_details(top); 281 show_details(top.sym_filter_entry);
309 return; 282 return;
310 } 283 }
311 284
312 hists__collapse_resort_threaded(&top->sym_evsel->hists); 285 perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width,
313 hists__output_resort_threaded(&top->sym_evsel->hists); 286 &sym_width);
314 hists__decay_entries_threaded(&top->sym_evsel->hists, 287
315 top->hide_user_symbols, 288 if (sym_width + dso_width > winsize.ws_col - 29) {
316 top->hide_kernel_symbols); 289 dso_width = dso_short_width;
317 hists__output_recalc_col_len(&top->sym_evsel->hists, 290 if (sym_width + dso_width > winsize.ws_col - 29)
318 top->winsize.ws_row - 3); 291 sym_width = winsize.ws_col - dso_width - 29;
292 }
319 putchar('\n'); 293 putchar('\n');
320 hists__fprintf(&top->sym_evsel->hists, false, 294 if (top.evlist->nr_entries == 1)
321 top->winsize.ws_row - 4 - printed, win_width, stdout); 295 printf(" samples pcnt");
296 else
297 printf(" weight samples pcnt");
298
299 if (verbose)
300 printf(" RIP ");
301 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
302 printf(" %s _______ _____",
303 top.evlist->nr_entries == 1 ? " " : "______");
304 if (verbose)
305 printf(" ________________");
306 printf(" %-*.*s", sym_width, sym_width, graph_line);
307 printf(" %-*.*s", dso_width, dso_width, graph_line);
308 puts("\n");
309
310 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
311 struct symbol *sym;
312 double pcnt;
313
314 syme = rb_entry(nd, struct sym_entry, rb_node);
315 sym = sym_entry__symbol(syme);
316 if (++printed > top.print_entries ||
317 (int)syme->snap_count < top.count_filter)
318 continue;
319
320 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
321 sum_ksamples));
322
323 if (top.evlist->nr_entries == 1 || !top.display_weighted)
324 printf("%20.2f ", syme->weight);
325 else
326 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
327
328 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
329 if (verbose)
330 printf(" %016" PRIx64, sym->start);
331 printf(" %-*.*s", sym_width, sym_width, sym->name);
332 printf(" %-*.*s\n", dso_width, dso_width,
333 dso_width >= syme->map->dso->long_name_len ?
334 syme->map->dso->long_name :
335 syme->map->dso->short_name);
336 }
322} 337}
323 338
324static void prompt_integer(int *target, const char *msg) 339static void prompt_integer(int *target, const char *msg)
@@ -356,17 +371,16 @@ static void prompt_percent(int *target, const char *msg)
356 *target = tmp; 371 *target = tmp;
357} 372}
358 373
359static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) 374static void prompt_symbol(struct sym_entry **target, const char *msg)
360{ 375{
361 char *buf = malloc(0), *p; 376 char *buf = malloc(0), *p;
362 struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; 377 struct sym_entry *syme = *target, *n, *found = NULL;
363 struct rb_node *next;
364 size_t dummy = 0; 378 size_t dummy = 0;
365 379
366 /* zero counters of active symbol */ 380 /* zero counters of active symbol */
367 if (syme) { 381 if (syme) {
368 __zero_source_counters(syme); 382 __zero_source_counters(syme);
369 top->sym_filter_entry = NULL; 383 *target = NULL;
370 } 384 }
371 385
372 fprintf(stdout, "\n%s: ", msg); 386 fprintf(stdout, "\n%s: ", msg);
@@ -377,59 +391,66 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
377 if (p) 391 if (p)
378 *p = 0; 392 *p = 0;
379 393
380 next = rb_first(&top->sym_evsel->hists.entries); 394 pthread_mutex_lock(&top.active_symbols_lock);
381 while (next) { 395 syme = list_entry(top.active_symbols.next, struct sym_entry, node);
382 n = rb_entry(next, struct hist_entry, rb_node); 396 pthread_mutex_unlock(&top.active_symbols_lock);
383 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { 397
384 found = n; 398 list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) {
399 struct symbol *sym = sym_entry__symbol(syme);
400
401 if (!strcmp(buf, sym->name)) {
402 found = syme;
385 break; 403 break;
386 } 404 }
387 next = rb_next(&n->rb_node);
388 } 405 }
389 406
390 if (!found) { 407 if (!found) {
391 fprintf(stderr, "Sorry, %s is not active.\n", buf); 408 fprintf(stderr, "Sorry, %s is not active.\n", buf);
392 sleep(1); 409 sleep(1);
410 return;
393 } else 411 } else
394 perf_top__parse_source(top, found); 412 parse_source(found);
395 413
396out_free: 414out_free:
397 free(buf); 415 free(buf);
398} 416}
399 417
400static void perf_top__print_mapped_keys(struct perf_top *top) 418static void print_mapped_keys(void)
401{ 419{
402 char *name = NULL; 420 char *name = NULL;
403 421
404 if (top->sym_filter_entry) { 422 if (top.sym_filter_entry) {
405 struct symbol *sym = top->sym_filter_entry->ms.sym; 423 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
406 name = sym->name; 424 name = sym->name;
407 } 425 }
408 426
409 fprintf(stdout, "\nMapped keys:\n"); 427 fprintf(stdout, "\nMapped keys:\n");
410 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); 428 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs);
411 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); 429 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries);
412 430
413 if (top->evlist->nr_entries > 1) 431 if (top.evlist->nr_entries > 1)
414 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", perf_evsel__name(top->sym_evsel)); 432 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel));
415 433
416 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); 434 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter);
417 435
418 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); 436 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
419 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 437 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
420 fprintf(stdout, "\t[S] stop annotation.\n"); 438 fprintf(stdout, "\t[S] stop annotation.\n");
421 439
440 if (top.evlist->nr_entries > 1)
441 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0);
442
422 fprintf(stdout, 443 fprintf(stdout,
423 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 444 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
424 top->hide_kernel_symbols ? "yes" : "no"); 445 top.hide_kernel_symbols ? "yes" : "no");
425 fprintf(stdout, 446 fprintf(stdout,
426 "\t[U] hide user symbols. \t(%s)\n", 447 "\t[U] hide user symbols. \t(%s)\n",
427 top->hide_user_symbols ? "yes" : "no"); 448 top.hide_user_symbols ? "yes" : "no");
428 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0); 449 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0);
429 fprintf(stdout, "\t[qQ] quit.\n"); 450 fprintf(stdout, "\t[qQ] quit.\n");
430} 451}
431 452
432static int perf_top__key_mapped(struct perf_top *top, int c) 453static int key_mapped(int c)
433{ 454{
434 switch (c) { 455 switch (c) {
435 case 'd': 456 case 'd':
@@ -445,7 +466,8 @@ static int perf_top__key_mapped(struct perf_top *top, int c)
445 case 'S': 466 case 'S':
446 return 1; 467 return 1;
447 case 'E': 468 case 'E':
448 return top->evlist->nr_entries > 1 ? 1 : 0; 469 case 'w':
470 return top.evlist->nr_entries > 1 ? 1 : 0;
449 default: 471 default:
450 break; 472 break;
451 } 473 }
@@ -453,13 +475,13 @@ static int perf_top__key_mapped(struct perf_top *top, int c)
453 return 0; 475 return 0;
454} 476}
455 477
456static void perf_top__handle_keypress(struct perf_top *top, int c) 478static void handle_keypress(struct perf_session *session, int c)
457{ 479{
458 if (!perf_top__key_mapped(top, c)) { 480 if (!key_mapped(c)) {
459 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 481 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
460 struct termios tc, save; 482 struct termios tc, save;
461 483
462 perf_top__print_mapped_keys(top); 484 print_mapped_keys();
463 fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); 485 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
464 fflush(stdout); 486 fflush(stdout);
465 487
@@ -474,144 +496,114 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
474 c = getc(stdin); 496 c = getc(stdin);
475 497
476 tcsetattr(0, TCSAFLUSH, &save); 498 tcsetattr(0, TCSAFLUSH, &save);
477 if (!perf_top__key_mapped(top, c)) 499 if (!key_mapped(c))
478 return; 500 return;
479 } 501 }
480 502
481 switch (c) { 503 switch (c) {
482 case 'd': 504 case 'd':
483 prompt_integer(&top->delay_secs, "Enter display delay"); 505 prompt_integer(&top.delay_secs, "Enter display delay");
484 if (top->delay_secs < 1) 506 if (top.delay_secs < 1)
485 top->delay_secs = 1; 507 top.delay_secs = 1;
486 break; 508 break;
487 case 'e': 509 case 'e':
488 prompt_integer(&top->print_entries, "Enter display entries (lines)"); 510 prompt_integer(&top.print_entries, "Enter display entries (lines)");
489 if (top->print_entries == 0) { 511 if (top.print_entries == 0) {
490 struct sigaction act = { 512 sig_winch_handler(SIGWINCH);
491 .sa_sigaction = perf_top__sig_winch, 513 signal(SIGWINCH, sig_winch_handler);
492 .sa_flags = SA_SIGINFO, 514 } else
493 };
494 perf_top__sig_winch(SIGWINCH, NULL, top);
495 sigaction(SIGWINCH, &act, NULL);
496 } else {
497 perf_top__sig_winch(SIGWINCH, NULL, top);
498 signal(SIGWINCH, SIG_DFL); 515 signal(SIGWINCH, SIG_DFL);
499 }
500 break; 516 break;
501 case 'E': 517 case 'E':
502 if (top->evlist->nr_entries > 1) { 518 if (top.evlist->nr_entries > 1) {
503 /* Select 0 as the default event: */ 519 /* Select 0 as the default event: */
504 int counter = 0; 520 int counter = 0;
505 521
506 fprintf(stderr, "\nAvailable events:"); 522 fprintf(stderr, "\nAvailable events:");
507 523
508 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) 524 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
509 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); 525 fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
510 526
511 prompt_integer(&counter, "Enter details event counter"); 527 prompt_integer(&counter, "Enter details event counter");
512 528
513 if (counter >= top->evlist->nr_entries) { 529 if (counter >= top.evlist->nr_entries) {
514 top->sym_evsel = perf_evlist__first(top->evlist); 530 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
515 fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel)); 531 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
516 sleep(1); 532 sleep(1);
517 break; 533 break;
518 } 534 }
519 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) 535 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
520 if (top->sym_evsel->idx == counter) 536 if (top.sym_evsel->idx == counter)
521 break; 537 break;
522 } else 538 } else
523 top->sym_evsel = perf_evlist__first(top->evlist); 539 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
524 break; 540 break;
525 case 'f': 541 case 'f':
526 prompt_integer(&top->count_filter, "Enter display event count filter"); 542 prompt_integer(&top.count_filter, "Enter display event count filter");
527 break; 543 break;
528 case 'F': 544 case 'F':
529 prompt_percent(&top->sym_pcnt_filter, 545 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
530 "Enter details display event filter (percent)");
531 break; 546 break;
532 case 'K': 547 case 'K':
533 top->hide_kernel_symbols = !top->hide_kernel_symbols; 548 top.hide_kernel_symbols = !top.hide_kernel_symbols;
534 break; 549 break;
535 case 'q': 550 case 'q':
536 case 'Q': 551 case 'Q':
537 printf("exiting.\n"); 552 printf("exiting.\n");
538 if (top->dump_symtab) 553 if (dump_symtab)
539 perf_session__fprintf_dsos(top->session, stderr); 554 perf_session__fprintf_dsos(session, stderr);
540 exit(0); 555 exit(0);
541 case 's': 556 case 's':
542 perf_top__prompt_symbol(top, "Enter details symbol"); 557 prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
543 break; 558 break;
544 case 'S': 559 case 'S':
545 if (!top->sym_filter_entry) 560 if (!top.sym_filter_entry)
546 break; 561 break;
547 else { 562 else {
548 struct hist_entry *syme = top->sym_filter_entry; 563 struct sym_entry *syme = top.sym_filter_entry;
549 564
550 top->sym_filter_entry = NULL; 565 top.sym_filter_entry = NULL;
551 __zero_source_counters(syme); 566 __zero_source_counters(syme);
552 } 567 }
553 break; 568 break;
554 case 'U': 569 case 'U':
555 top->hide_user_symbols = !top->hide_user_symbols; 570 top.hide_user_symbols = !top.hide_user_symbols;
571 break;
572 case 'w':
573 top.display_weighted = ~top.display_weighted;
556 break; 574 break;
557 case 'z': 575 case 'z':
558 top->zero = !top->zero; 576 top.zero = !top.zero;
559 break; 577 break;
560 default: 578 default:
561 break; 579 break;
562 } 580 }
563} 581}
564 582
565static void perf_top__sort_new_samples(void *arg) 583static void *display_thread_tui(void *arg __used)
566{
567 struct perf_top *t = arg;
568 perf_top__reset_sample_counters(t);
569
570 if (t->evlist->selected != NULL)
571 t->sym_evsel = t->evlist->selected;
572
573 hists__collapse_resort_threaded(&t->sym_evsel->hists);
574 hists__output_resort_threaded(&t->sym_evsel->hists);
575 hists__decay_entries_threaded(&t->sym_evsel->hists,
576 t->hide_user_symbols,
577 t->hide_kernel_symbols);
578}
579
580static void *display_thread_tui(void *arg)
581{ 584{
582 struct perf_evsel *pos; 585 int err = 0;
583 struct perf_top *top = arg; 586 pthread_mutex_lock(&top.active_symbols_lock);
584 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 587 while (list_empty(&top.active_symbols)) {
585 struct hist_browser_timer hbt = { 588 err = pthread_cond_wait(&top.active_symbols_cond,
586 .timer = perf_top__sort_new_samples, 589 &top.active_symbols_lock);
587 .arg = top, 590 if (err)
588 .refresh = top->delay_secs, 591 break;
589 }; 592 }
590 593 pthread_mutex_unlock(&top.active_symbols_lock);
591 perf_top__sort_new_samples(top); 594 if (!err)
592 595 perf_top__tui_browser(&top);
593 /*
594 * Initialize the uid_filter_str, in the future the TUI will allow
595 * Zooming in/out UIDs. For now juse use whatever the user passed
596 * via --uid.
597 */
598 list_for_each_entry(pos, &top->evlist->entries, node)
599 pos->hists.uid_filter_str = top->target.uid_str;
600
601 perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
602 &top->session->header.env);
603
604 exit_browser(0); 596 exit_browser(0);
605 exit(0); 597 exit(0);
606 return NULL; 598 return NULL;
607} 599}
608 600
609static void *display_thread(void *arg) 601static void *display_thread(void *arg __used)
610{ 602{
611 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 603 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
612 struct termios tc, save; 604 struct termios tc, save;
613 struct perf_top *top = arg;
614 int delay_msecs, c; 605 int delay_msecs, c;
606 struct perf_session *session = (struct perf_session *) arg;
615 607
616 tcgetattr(0, &save); 608 tcgetattr(0, &save);
617 tc = save; 609 tc = save;
@@ -619,35 +611,20 @@ static void *display_thread(void *arg)
619 tc.c_cc[VMIN] = 0; 611 tc.c_cc[VMIN] = 0;
620 tc.c_cc[VTIME] = 0; 612 tc.c_cc[VTIME] = 0;
621 613
622 pthread__unblock_sigwinch();
623repeat: 614repeat:
624 delay_msecs = top->delay_secs * 1000; 615 delay_msecs = top.delay_secs * 1000;
625 tcsetattr(0, TCSANOW, &tc); 616 tcsetattr(0, TCSANOW, &tc);
626 /* trash return*/ 617 /* trash return*/
627 getc(stdin); 618 getc(stdin);
628 619
629 while (1) { 620 do {
630 perf_top__print_sym_table(top); 621 print_sym_table(session);
631 /* 622 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
632 * Either timeout expired or we got an EINTR due to SIGWINCH, 623
633 * refresh screen in both cases.
634 */
635 switch (poll(&stdin_poll, 1, delay_msecs)) {
636 case 0:
637 continue;
638 case -1:
639 if (errno == EINTR)
640 continue;
641 /* Fall trhu */
642 default:
643 goto process_hotkey;
644 }
645 }
646process_hotkey:
647 c = getc(stdin); 624 c = getc(stdin);
648 tcsetattr(0, TCSAFLUSH, &save); 625 tcsetattr(0, TCSAFLUSH, &save);
649 626
650 perf_top__handle_keypress(top, c); 627 handle_keypress(session, c);
651 goto repeat; 628 goto repeat;
652 629
653 return NULL; 630 return NULL;
@@ -655,7 +632,6 @@ process_hotkey:
655 632
656/* Tag samples to be skipped. */ 633/* Tag samples to be skipped. */
657static const char *skip_symbols[] = { 634static const char *skip_symbols[] = {
658 "intel_idle",
659 "default_idle", 635 "default_idle",
660 "native_safe_halt", 636 "native_safe_halt",
661 "cpu_idle", 637 "cpu_idle",
@@ -669,8 +645,9 @@ static const char *skip_symbols[] = {
669 NULL 645 NULL
670}; 646};
671 647
672static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) 648static int symbol_filter(struct map *map, struct symbol *sym)
673{ 649{
650 struct sym_entry *syme;
674 const char *name = sym->name; 651 const char *name = sym->name;
675 int i; 652 int i;
676 653
@@ -690,6 +667,16 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
690 strstr(name, "_text_end")) 667 strstr(name, "_text_end"))
691 return 1; 668 return 1;
692 669
670 syme = symbol__priv(sym);
671 syme->map = map;
672 symbol__annotate_init(map, sym);
673
674 if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
675 /* schedule initial sym_filter_entry setup */
676 sym_filter_entry_sched = syme;
677 sym_filter = NULL;
678 }
679
693 for (i = 0; skip_symbols[i]; i++) { 680 for (i = 0; skip_symbols[i]; i++) {
694 if (!strcmp(skip_symbols[i], name)) { 681 if (!strcmp(skip_symbols[i], name)) {
695 sym->ignore = true; 682 sym->ignore = true;
@@ -700,47 +687,61 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
700 return 0; 687 return 0;
701} 688}
702 689
703static void perf_event__process_sample(struct perf_tool *tool, 690static void perf_event__process_sample(const union perf_event *event,
704 const union perf_event *event,
705 struct perf_evsel *evsel,
706 struct perf_sample *sample, 691 struct perf_sample *sample,
707 struct machine *machine) 692 struct perf_session *session)
708{ 693{
709 struct perf_top *top = container_of(tool, struct perf_top, tool);
710 struct symbol *parent = NULL;
711 u64 ip = event->ip.ip; 694 u64 ip = event->ip.ip;
695 struct sym_entry *syme;
712 struct addr_location al; 696 struct addr_location al;
713 int err; 697 struct machine *machine;
714 698 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
715 if (!machine && perf_guest) {
716 static struct intlist *seen;
717 699
718 if (!seen) 700 ++top.samples;
719 seen = intlist__new();
720 701
721 if (!intlist__has_entry(seen, event->ip.pid)) { 702 switch (origin) {
722 pr_err("Can't find guest [%d]'s kernel information\n", 703 case PERF_RECORD_MISC_USER:
723 event->ip.pid); 704 ++top.us_samples;
724 intlist__add(seen, event->ip.pid); 705 if (top.hide_user_symbols)
725 } 706 return;
707 machine = perf_session__find_host_machine(session);
708 break;
709 case PERF_RECORD_MISC_KERNEL:
710 ++top.kernel_samples;
711 if (top.hide_kernel_symbols)
712 return;
713 machine = perf_session__find_host_machine(session);
714 break;
715 case PERF_RECORD_MISC_GUEST_KERNEL:
716 ++top.guest_kernel_samples;
717 machine = perf_session__find_machine(session, event->ip.pid);
718 break;
719 case PERF_RECORD_MISC_GUEST_USER:
720 ++top.guest_us_samples;
721 /*
722 * TODO: we don't process guest user from host side
723 * except simple counting.
724 */
725 return;
726 default:
726 return; 727 return;
727 } 728 }
728 729
729 if (!machine) { 730 if (!machine && perf_guest) {
730 pr_err("%u unprocessable samples recorded.", 731 pr_err("Can't find guest [%d]'s kernel information\n",
731 top->session->hists.stats.nr_unprocessable_samples++); 732 event->ip.pid);
732 return; 733 return;
733 } 734 }
734 735
735 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 736 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
736 top->exact_samples++; 737 top.exact_samples++;
737 738
738 if (perf_event__preprocess_sample(event, machine, &al, sample, 739 if (perf_event__preprocess_sample(event, session, &al, sample,
739 symbol_filter) < 0 || 740 symbol_filter) < 0 ||
740 al.filtered) 741 al.filtered)
741 return; 742 return;
742 743
743 if (!top->kptr_restrict_warned && 744 if (!kptr_restrict_warned &&
744 symbol_conf.kptr_restrict && 745 symbol_conf.kptr_restrict &&
745 al.cpumode == PERF_RECORD_MISC_KERNEL) { 746 al.cpumode == PERF_RECORD_MISC_KERNEL) {
746 ui__warning( 747 ui__warning(
@@ -751,7 +752,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
751 " modules" : ""); 752 " modules" : "");
752 if (use_browser <= 0) 753 if (use_browser <= 0)
753 sleep(5); 754 sleep(5);
754 top->kptr_restrict_warned = true; 755 kptr_restrict_warned = true;
755 } 756 }
756 757
757 if (al.sym == NULL) { 758 if (al.sym == NULL) {
@@ -767,7 +768,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
767 * --hide-kernel-symbols, even if the user specifies an 768 * --hide-kernel-symbols, even if the user specifies an
768 * invalid --vmlinux ;-) 769 * invalid --vmlinux ;-)
769 */ 770 */
770 if (!top->kptr_restrict_warned && !top->vmlinux_warned && 771 if (!kptr_restrict_warned && !vmlinux_warned &&
771 al.map == machine->vmlinux_maps[MAP__FUNCTION] && 772 al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
772 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 773 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
773 if (symbol_conf.vmlinux_name) { 774 if (symbol_conf.vmlinux_name) {
@@ -780,133 +781,91 @@ static void perf_event__process_sample(struct perf_tool *tool,
780 781
781 if (use_browser <= 0) 782 if (use_browser <= 0)
782 sleep(5); 783 sleep(5);
783 top->vmlinux_warned = true; 784 vmlinux_warned = true;
784 } 785 }
785 }
786 786
787 if (al.sym == NULL || !al.sym->ignore) { 787 return;
788 struct hist_entry *he; 788 }
789
790 if ((sort__has_parent || symbol_conf.use_callchain) &&
791 sample->callchain) {
792 err = machine__resolve_callchain(machine, evsel,
793 al.thread, sample,
794 &parent);
795 789
796 if (err) 790 /* let's see, whether we need to install initial sym_filter_entry */
797 return; 791 if (sym_filter_entry_sched) {
792 top.sym_filter_entry = sym_filter_entry_sched;
793 sym_filter_entry_sched = NULL;
794 if (parse_source(top.sym_filter_entry) < 0) {
795 struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
796
797 pr_err("Can't annotate %s", sym->name);
798 if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
799 pr_err(": No vmlinux file was found in the path:\n");
800 machine__fprintf_vmlinux_path(machine, stderr);
801 } else
802 pr_err(".\n");
803 exit(1);
798 } 804 }
805 }
799 806
800 he = perf_evsel__add_hist_entry(evsel, &al, sample); 807 syme = symbol__priv(al.sym);
801 if (he == NULL) { 808 if (!al.sym->ignore) {
802 pr_err("Problem incrementing symbol period, skipping event\n"); 809 struct perf_evsel *evsel;
803 return;
804 }
805 810
806 if (symbol_conf.use_callchain) { 811 evsel = perf_evlist__id2evsel(top.evlist, sample->id);
807 err = callchain_append(he->callchain, &callchain_cursor, 812 assert(evsel != NULL);
808 sample->period); 813 syme->count[evsel->idx]++;
809 if (err) 814 record_precise_ip(syme, al.map, evsel->idx, ip);
810 return; 815 pthread_mutex_lock(&top.active_symbols_lock);
816 if (list_empty(&syme->node) || !syme->node.next) {
817 static bool first = true;
818 __list_insert_active_sym(syme);
819 if (first) {
820 pthread_cond_broadcast(&top.active_symbols_cond);
821 first = false;
822 }
811 } 823 }
812 824 pthread_mutex_unlock(&top.active_symbols_lock);
813 if (top->sort_has_symbols)
814 perf_top__record_precise_ip(top, he, evsel->idx, ip);
815 } 825 }
816
817 return;
818} 826}
819 827
820static void perf_top__mmap_read_idx(struct perf_top *top, int idx) 828static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
821{ 829{
822 struct perf_sample sample; 830 struct perf_sample sample;
823 struct perf_evsel *evsel;
824 struct perf_session *session = top->session;
825 union perf_event *event; 831 union perf_event *event;
826 struct machine *machine;
827 u8 origin;
828 int ret; 832 int ret;
829 833
830 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { 834 while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
831 ret = perf_evlist__parse_sample(top->evlist, event, &sample); 835 ret = perf_session__parse_sample(self, event, &sample);
832 if (ret) { 836 if (ret) {
833 pr_err("Can't parse sample, err = %d\n", ret); 837 pr_err("Can't parse sample, err = %d\n", ret);
834 continue; 838 continue;
835 } 839 }
836 840
837 evsel = perf_evlist__id2evsel(session->evlist, sample.id);
838 assert(evsel != NULL);
839
840 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
841
842 if (event->header.type == PERF_RECORD_SAMPLE) 841 if (event->header.type == PERF_RECORD_SAMPLE)
843 ++top->samples; 842 perf_event__process_sample(event, &sample, self);
844 843 else
845 switch (origin) { 844 perf_event__process(event, &sample, self);
846 case PERF_RECORD_MISC_USER:
847 ++top->us_samples;
848 if (top->hide_user_symbols)
849 continue;
850 machine = perf_session__find_host_machine(session);
851 break;
852 case PERF_RECORD_MISC_KERNEL:
853 ++top->kernel_samples;
854 if (top->hide_kernel_symbols)
855 continue;
856 machine = perf_session__find_host_machine(session);
857 break;
858 case PERF_RECORD_MISC_GUEST_KERNEL:
859 ++top->guest_kernel_samples;
860 machine = perf_session__find_machine(session, event->ip.pid);
861 break;
862 case PERF_RECORD_MISC_GUEST_USER:
863 ++top->guest_us_samples;
864 /*
865 * TODO: we don't process guest user from host side
866 * except simple counting.
867 */
868 /* Fall thru */
869 default:
870 continue;
871 }
872
873
874 if (event->header.type == PERF_RECORD_SAMPLE) {
875 perf_event__process_sample(&top->tool, event, evsel,
876 &sample, machine);
877 } else if (event->header.type < PERF_RECORD_MAX) {
878 hists__inc_nr_events(&evsel->hists, event->header.type);
879 machine__process_event(machine, event);
880 } else
881 ++session->hists.stats.nr_unknown_events;
882 } 845 }
883} 846}
884 847
885static void perf_top__mmap_read(struct perf_top *top) 848static void perf_session__mmap_read(struct perf_session *self)
886{ 849{
887 int i; 850 int i;
888 851
889 for (i = 0; i < top->evlist->nr_mmaps; i++) 852 for (i = 0; i < top.evlist->nr_mmaps; i++)
890 perf_top__mmap_read_idx(top, i); 853 perf_session__mmap_read_idx(self, i);
891} 854}
892 855
893static void perf_top__start_counters(struct perf_top *top) 856static void start_counters(struct perf_evlist *evlist)
894{ 857{
895 struct perf_evsel *counter; 858 struct perf_evsel *counter;
896 struct perf_evlist *evlist = top->evlist;
897
898 if (top->group)
899 perf_evlist__set_leader(evlist);
900 859
901 list_for_each_entry(counter, &evlist->entries, node) { 860 list_for_each_entry(counter, &evlist->entries, node) {
902 struct perf_event_attr *attr = &counter->attr; 861 struct perf_event_attr *attr = &counter->attr;
903 862
904 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 863 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
905 864
906 if (top->freq) { 865 if (top.freq) {
907 attr->sample_type |= PERF_SAMPLE_PERIOD; 866 attr->sample_type |= PERF_SAMPLE_PERIOD;
908 attr->freq = 1; 867 attr->freq = 1;
909 attr->sample_freq = top->freq; 868 attr->sample_freq = top.freq;
910 } 869 }
911 870
912 if (evlist->nr_entries > 1) { 871 if (evlist->nr_entries > 1) {
@@ -914,80 +873,40 @@ static void perf_top__start_counters(struct perf_top *top)
914 attr->read_format |= PERF_FORMAT_ID; 873 attr->read_format |= PERF_FORMAT_ID;
915 } 874 }
916 875
917 if (perf_target__has_cpu(&top->target))
918 attr->sample_type |= PERF_SAMPLE_CPU;
919
920 if (symbol_conf.use_callchain)
921 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
922
923 attr->mmap = 1; 876 attr->mmap = 1;
924 attr->comm = 1; 877 attr->inherit = inherit;
925 attr->inherit = top->inherit;
926fallback_missing_features:
927 if (top->exclude_guest_missing)
928 attr->exclude_guest = attr->exclude_host = 0;
929retry_sample_id:
930 attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
931try_again: 878try_again:
932 if (perf_evsel__open(counter, top->evlist->cpus, 879 if (perf_evsel__open(counter, top.evlist->cpus,
933 top->evlist->threads) < 0) { 880 top.evlist->threads, group) < 0) {
934 int err = errno; 881 int err = errno;
935 882
936 if (err == EPERM || err == EACCES) { 883 if (err == EPERM || err == EACCES) {
937 ui__error_paranoid(); 884 ui__warning_paranoid();
938 goto out_err; 885 goto out_err;
939 } else if (err == EINVAL) {
940 if (!top->exclude_guest_missing &&
941 (attr->exclude_guest || attr->exclude_host)) {
942 pr_debug("Old kernel, cannot exclude "
943 "guest or host samples.\n");
944 top->exclude_guest_missing = true;
945 goto fallback_missing_features;
946 } else if (!top->sample_id_all_missing) {
947 /*
948 * Old kernel, no attr->sample_id_type_all field
949 */
950 top->sample_id_all_missing = true;
951 goto retry_sample_id;
952 }
953 } 886 }
954 /* 887 /*
955 * If it's cycles then fall back to hrtimer 888 * If it's cycles then fall back to hrtimer
956 * based cpu-clock-tick sw counter, which 889 * based cpu-clock-tick sw counter, which
957 * is always available even if no PMU support: 890 * is always available even if no PMU support:
958 */ 891 */
959 if ((err == ENOENT || err == ENXIO) && 892 if (attr->type == PERF_TYPE_HARDWARE &&
960 (attr->type == PERF_TYPE_HARDWARE) && 893 attr->config == PERF_COUNT_HW_CPU_CYCLES) {
961 (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
962
963 if (verbose) 894 if (verbose)
964 ui__warning("Cycles event not supported,\n" 895 ui__warning("Cycles event not supported,\n"
965 "trying to fall back to cpu-clock-ticks\n"); 896 "trying to fall back to cpu-clock-ticks\n");
966 897
967 attr->type = PERF_TYPE_SOFTWARE; 898 attr->type = PERF_TYPE_SOFTWARE;
968 attr->config = PERF_COUNT_SW_CPU_CLOCK; 899 attr->config = PERF_COUNT_SW_CPU_CLOCK;
969 if (counter->name) {
970 free(counter->name);
971 counter->name = NULL;
972 }
973 goto try_again; 900 goto try_again;
974 } 901 }
975 902
976 if (err == ENOENT) { 903 if (err == ENOENT) {
977 ui__error("The %s event is not supported.\n", 904 ui__warning("The %s event is not supported.\n",
978 perf_evsel__name(counter)); 905 event_name(counter));
979 goto out_err;
980 } else if (err == EMFILE) {
981 ui__error("Too many events are opened.\n"
982 "Try again after reducing the number of events\n");
983 goto out_err;
984 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
985 ui__error("\'precise\' request may not be supported. "
986 "Try removing 'p' modifier\n");
987 goto out_err; 906 goto out_err;
988 } 907 }
989 908
990 ui__error("The sys_perf_event_open() syscall " 909 ui__warning("The sys_perf_event_open() syscall "
991 "returned with %d (%s). /bin/dmesg " 910 "returned with %d (%s). /bin/dmesg "
992 "may provide additional information.\n" 911 "may provide additional information.\n"
993 "No CONFIG_PERF_EVENTS=y kernel support " 912 "No CONFIG_PERF_EVENTS=y kernel support "
@@ -996,8 +915,8 @@ try_again:
996 } 915 }
997 } 916 }
998 917
999 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { 918 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
1000 ui__error("Failed to mmap with %d (%s)\n", 919 ui__warning("Failed to mmap with %d (%s)\n",
1001 errno, strerror(errno)); 920 errno, strerror(errno));
1002 goto out_err; 921 goto out_err;
1003 } 922 }
@@ -1009,213 +928,98 @@ out_err:
1009 exit(0); 928 exit(0);
1010} 929}
1011 930
1012static int perf_top__setup_sample_type(struct perf_top *top) 931static int __cmd_top(void)
1013{
1014 if (!top->sort_has_symbols) {
1015 if (symbol_conf.use_callchain) {
1016 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
1017 return -EINVAL;
1018 }
1019 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
1020 if (callchain_register_param(&callchain_param) < 0) {
1021 ui__error("Can't register callchain params.\n");
1022 return -EINVAL;
1023 }
1024 }
1025
1026 return 0;
1027}
1028
1029static int __cmd_top(struct perf_top *top)
1030{ 932{
1031 pthread_t thread; 933 pthread_t thread;
1032 int ret; 934 int ret __used;
1033 /* 935 /*
1034 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 936 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1035 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 937 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1036 */ 938 */
1037 top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL); 939 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
1038 if (top->session == NULL) 940 if (session == NULL)
1039 return -ENOMEM; 941 return -ENOMEM;
1040 942
1041 ret = perf_top__setup_sample_type(top); 943 if (top.target_tid != -1)
1042 if (ret) 944 perf_event__synthesize_thread_map(top.evlist->threads,
1043 goto out_delete; 945 perf_event__process, session);
1044
1045 if (perf_target__has_task(&top->target))
1046 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1047 perf_event__process,
1048 &top->session->host_machine);
1049 else 946 else
1050 perf_event__synthesize_threads(&top->tool, perf_event__process, 947 perf_event__synthesize_threads(perf_event__process, session);
1051 &top->session->host_machine); 948
1052 perf_top__start_counters(top); 949 start_counters(top.evlist);
1053 top->session->evlist = top->evlist; 950 session->evlist = top.evlist;
1054 perf_session__set_id_hdr_size(top->session); 951 perf_session__update_sample_type(session);
1055 952
1056 /* Wait for a minimal set of events before starting the snapshot */ 953 /* Wait for a minimal set of events before starting the snapshot */
1057 poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 954 poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1058 955
1059 perf_top__mmap_read(top); 956 perf_session__mmap_read(session);
1060 957
1061 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 958 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1062 display_thread), top)) { 959 display_thread), session)) {
1063 ui__error("Could not create display thread.\n"); 960 printf("Could not create display thread.\n");
1064 exit(-1); 961 exit(-1);
1065 } 962 }
1066 963
1067 if (top->realtime_prio) { 964 if (realtime_prio) {
1068 struct sched_param param; 965 struct sched_param param;
1069 966
1070 param.sched_priority = top->realtime_prio; 967 param.sched_priority = realtime_prio;
1071 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 968 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1072 ui__error("Could not set realtime priority.\n"); 969 printf("Could not set realtime priority.\n");
1073 exit(-1); 970 exit(-1);
1074 } 971 }
1075 } 972 }
1076 973
1077 while (1) { 974 while (1) {
1078 u64 hits = top->samples; 975 u64 hits = top.samples;
1079 976
1080 perf_top__mmap_read(top); 977 perf_session__mmap_read(session);
1081 978
1082 if (hits == top->samples) 979 if (hits == top.samples)
1083 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 980 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
1084 } 981 }
1085 982
1086out_delete:
1087 perf_session__delete(top->session);
1088 top->session = NULL;
1089
1090 return 0; 983 return 0;
1091} 984}
1092 985
1093static int 986static const char * const top_usage[] = {
1094parse_callchain_opt(const struct option *opt, const char *arg, int unset) 987 "perf top [<options>]",
1095{ 988 NULL
1096 struct perf_top *top = (struct perf_top *)opt->value; 989};
1097 char *tok, *tok2;
1098 char *endptr;
1099
1100 /*
1101 * --no-call-graph
1102 */
1103 if (unset) {
1104 top->dont_use_callchains = true;
1105 return 0;
1106 }
1107
1108 symbol_conf.use_callchain = true;
1109
1110 if (!arg)
1111 return 0;
1112
1113 tok = strtok((char *)arg, ",");
1114 if (!tok)
1115 return -1;
1116
1117 /* get the output mode */
1118 if (!strncmp(tok, "graph", strlen(arg)))
1119 callchain_param.mode = CHAIN_GRAPH_ABS;
1120
1121 else if (!strncmp(tok, "flat", strlen(arg)))
1122 callchain_param.mode = CHAIN_FLAT;
1123
1124 else if (!strncmp(tok, "fractal", strlen(arg)))
1125 callchain_param.mode = CHAIN_GRAPH_REL;
1126
1127 else if (!strncmp(tok, "none", strlen(arg))) {
1128 callchain_param.mode = CHAIN_NONE;
1129 symbol_conf.use_callchain = false;
1130
1131 return 0;
1132 } else
1133 return -1;
1134
1135 /* get the min percentage */
1136 tok = strtok(NULL, ",");
1137 if (!tok)
1138 goto setup;
1139
1140 callchain_param.min_percent = strtod(tok, &endptr);
1141 if (tok == endptr)
1142 return -1;
1143
1144 /* get the print limit */
1145 tok2 = strtok(NULL, ",");
1146 if (!tok2)
1147 goto setup;
1148
1149 if (tok2[0] != 'c') {
1150 callchain_param.print_limit = strtod(tok2, &endptr);
1151 tok2 = strtok(NULL, ",");
1152 if (!tok2)
1153 goto setup;
1154 }
1155
1156 /* get the call chain order */
1157 if (!strcmp(tok2, "caller"))
1158 callchain_param.order = ORDER_CALLER;
1159 else if (!strcmp(tok2, "callee"))
1160 callchain_param.order = ORDER_CALLEE;
1161 else
1162 return -1;
1163setup:
1164 if (callchain_register_param(&callchain_param) < 0) {
1165 fprintf(stderr, "Can't register callchain params\n");
1166 return -1;
1167 }
1168 return 0;
1169}
1170 990
1171int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 991static const struct option options[] = {
1172{
1173 struct perf_evsel *pos;
1174 int status;
1175 char errbuf[BUFSIZ];
1176 struct perf_top top = {
1177 .count_filter = 5,
1178 .delay_secs = 2,
1179 .freq = 4000, /* 4 KHz */
1180 .mmap_pages = 128,
1181 .sym_pcnt_filter = 5,
1182 .target = {
1183 .uses_mmap = true,
1184 },
1185 };
1186 char callchain_default_opt[] = "fractal,0.5,callee";
1187 const struct option options[] = {
1188 OPT_CALLBACK('e', "event", &top.evlist, "event", 992 OPT_CALLBACK('e', "event", &top.evlist, "event",
1189 "event selector. use 'perf list' to list available events", 993 "event selector. use 'perf list' to list available events",
1190 parse_events_option), 994 parse_events_option),
1191 OPT_INTEGER('c', "count", &top.default_interval, 995 OPT_INTEGER('c', "count", &default_interval,
1192 "event period to sample"), 996 "event period to sample"),
1193 OPT_STRING('p', "pid", &top.target.pid, "pid", 997 OPT_INTEGER('p', "pid", &top.target_pid,
1194 "profile events on existing process id"), 998 "profile events on existing process id"),
1195 OPT_STRING('t', "tid", &top.target.tid, "tid", 999 OPT_INTEGER('t', "tid", &top.target_tid,
1196 "profile events on existing thread id"), 1000 "profile events on existing thread id"),
1197 OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, 1001 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1198 "system-wide collection from all CPUs"), 1002 "system-wide collection from all CPUs"),
1199 OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", 1003 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1200 "list of cpus to monitor"), 1004 "list of cpus to monitor"),
1201 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1005 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1202 "file", "vmlinux pathname"), 1006 "file", "vmlinux pathname"),
1203 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, 1007 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1204 "hide kernel symbols"), 1008 "hide kernel symbols"),
1205 OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), 1009 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1206 OPT_INTEGER('r', "realtime", &top.realtime_prio, 1010 OPT_INTEGER('r', "realtime", &realtime_prio,
1207 "collect data with this RT SCHED_FIFO priority"), 1011 "collect data with this RT SCHED_FIFO priority"),
1208 OPT_INTEGER('d', "delay", &top.delay_secs, 1012 OPT_INTEGER('d', "delay", &top.delay_secs,
1209 "number of seconds to delay between refreshes"), 1013 "number of seconds to delay between refreshes"),
1210 OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab, 1014 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
1211 "dump the symbol table used for profiling"), 1015 "dump the symbol table used for profiling"),
1212 OPT_INTEGER('f', "count-filter", &top.count_filter, 1016 OPT_INTEGER('f', "count-filter", &top.count_filter,
1213 "only display functions with more events than this"), 1017 "only display functions with more events than this"),
1214 OPT_BOOLEAN('g', "group", &top.group, 1018 OPT_BOOLEAN('g', "group", &group,
1215 "put the counters into a counter group"), 1019 "put the counters into a counter group"),
1216 OPT_BOOLEAN('i', "inherit", &top.inherit, 1020 OPT_BOOLEAN('i', "inherit", &inherit,
1217 "child tasks inherit counters"), 1021 "child tasks inherit counters"),
1218 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", 1022 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1219 "symbol to annotate"), 1023 "symbol to annotate"),
1220 OPT_BOOLEAN('z', "zero", &top.zero, 1024 OPT_BOOLEAN('z', "zero", &top.zero,
1221 "zero history across updates"), 1025 "zero history across updates"),
@@ -1225,147 +1029,111 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1225 "display this many functions"), 1029 "display this many functions"),
1226 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, 1030 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1227 "hide user symbols"), 1031 "hide user symbols"),
1228 OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"), 1032 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
1229 OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"), 1033 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
1230 OPT_INCR('v', "verbose", &verbose, 1034 OPT_INCR('v', "verbose", &verbose,
1231 "be more verbose (show counter open errors, etc)"), 1035 "be more verbose (show counter open errors, etc)"),
1232 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1233 "sort by key(s): pid, comm, dso, symbol, parent"),
1234 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1235 "Show a column with the number of samples"),
1236 OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order",
1237 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1238 "Default: fractal,0.5,callee", &parse_callchain_opt,
1239 callchain_default_opt),
1240 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1241 "Show a column with the sum of periods"),
1242 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1243 "only consider symbols in these dsos"),
1244 OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1245 "only consider symbols in these comms"),
1246 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1247 "only consider these symbols"),
1248 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
1249 "Interleave source code with assembly code (default)"),
1250 OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1251 "Display raw encoding of assembly instructions (default)"),
1252 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1253 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1254 OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
1255 OPT_END() 1036 OPT_END()
1256 }; 1037};
1257 const char * const top_usage[] = { 1038
1258 "perf top [<options>]", 1039int cmd_top(int argc, const char **argv, const char *prefix __used)
1259 NULL 1040{
1260 }; 1041 struct perf_evsel *pos;
1042 int status = -ENOMEM;
1261 1043
1262 top.evlist = perf_evlist__new(NULL, NULL); 1044 top.evlist = perf_evlist__new(NULL, NULL);
1263 if (top.evlist == NULL) 1045 if (top.evlist == NULL)
1264 return -ENOMEM; 1046 return -ENOMEM;
1265 1047
1266 symbol_conf.exclude_other = false; 1048 page_size = sysconf(_SC_PAGE_SIZE);
1267 1049
1268 argc = parse_options(argc, argv, options, top_usage, 0); 1050 argc = parse_options(argc, argv, options, top_usage, 0);
1269 if (argc) 1051 if (argc)
1270 usage_with_options(top_usage, options); 1052 usage_with_options(top_usage, options);
1271 1053
1272 if (sort_order == default_sort_order) 1054 /*
1273 sort_order = "dso,symbol"; 1055 * XXX For now start disabled, only using TUI if explicitely asked for.
1274 1056 * Change that when handle_keys equivalent gets written, live annotation
1275 setup_sorting(top_usage, options); 1057 * done, etc.
1058 */
1059 use_browser = 0;
1276 1060
1277 if (top.use_stdio) 1061 if (use_stdio)
1278 use_browser = 0; 1062 use_browser = 0;
1279 else if (top.use_tui) 1063 else if (use_tui)
1280 use_browser = 1; 1064 use_browser = 1;
1281 1065
1282 setup_browser(false); 1066 setup_browser(false);
1283 1067
1284 status = perf_target__validate(&top.target); 1068 /* CPU and PID are mutually exclusive */
1285 if (status) { 1069 if (top.target_tid > 0 && top.cpu_list) {
1286 perf_target__strerror(&top.target, status, errbuf, BUFSIZ); 1070 printf("WARNING: PID switch overriding CPU\n");
1287 ui__warning("%s", errbuf); 1071 sleep(1);
1288 } 1072 top.cpu_list = NULL;
1289
1290 status = perf_target__parse_uid(&top.target);
1291 if (status) {
1292 int saved_errno = errno;
1293
1294 perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
1295 ui__error("%s", errbuf);
1296
1297 status = -saved_errno;
1298 goto out_delete_evlist;
1299 } 1073 }
1300 1074
1301 if (perf_target__none(&top.target)) 1075 if (top.target_pid != -1)
1302 top.target.system_wide = true; 1076 top.target_tid = top.target_pid;
1303 1077
1304 if (perf_evlist__create_maps(top.evlist, &top.target) < 0) 1078 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1079 top.target_tid, top.cpu_list) < 0)
1305 usage_with_options(top_usage, options); 1080 usage_with_options(top_usage, options);
1306 1081
1307 if (!top.evlist->nr_entries && 1082 if (!top.evlist->nr_entries &&
1308 perf_evlist__add_default(top.evlist) < 0) { 1083 perf_evlist__add_default(top.evlist) < 0) {
1309 ui__error("Not enough memory for event selector list\n"); 1084 pr_err("Not enough memory for event selector list\n");
1310 return -ENOMEM; 1085 return -ENOMEM;
1311 } 1086 }
1312 1087
1313 symbol_conf.nr_events = top.evlist->nr_entries;
1314
1315 if (top.delay_secs < 1) 1088 if (top.delay_secs < 1)
1316 top.delay_secs = 1; 1089 top.delay_secs = 1;
1317 1090
1318 /* 1091 /*
1319 * User specified count overrides default frequency. 1092 * User specified count overrides default frequency.
1320 */ 1093 */
1321 if (top.default_interval) 1094 if (default_interval)
1322 top.freq = 0; 1095 top.freq = 0;
1323 else if (top.freq) { 1096 else if (top.freq) {
1324 top.default_interval = top.freq; 1097 default_interval = top.freq;
1325 } else { 1098 } else {
1326 ui__error("frequency and count are zero, aborting\n"); 1099 fprintf(stderr, "frequency and count are zero, aborting\n");
1327 exit(EXIT_FAILURE); 1100 exit(EXIT_FAILURE);
1328 } 1101 }
1329 1102
1330 list_for_each_entry(pos, &top.evlist->entries, node) { 1103 list_for_each_entry(pos, &top.evlist->entries, node) {
1104 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1105 top.evlist->threads->nr) < 0)
1106 goto out_free_fd;
1331 /* 1107 /*
1332 * Fill in the ones not specifically initialized via -c: 1108 * Fill in the ones not specifically initialized via -c:
1333 */ 1109 */
1334 if (!pos->attr.sample_period) 1110 if (pos->attr.sample_period)
1335 pos->attr.sample_period = top.default_interval; 1111 continue;
1112
1113 pos->attr.sample_period = default_interval;
1336 } 1114 }
1337 1115
1338 top.sym_evsel = perf_evlist__first(top.evlist); 1116 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1117 perf_evlist__alloc_mmap(top.evlist) < 0)
1118 goto out_free_fd;
1119
1120 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1339 1121
1340 symbol_conf.priv_size = sizeof(struct annotation); 1122 symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) +
1123 (top.evlist->nr_entries + 1) * sizeof(unsigned long));
1341 1124
1342 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1125 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1343 if (symbol__init() < 0) 1126 if (symbol__init() < 0)
1344 return -1; 1127 return -1;
1345 1128
1346 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); 1129 get_term_dimensions(&winsize);
1347 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1348 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1349
1350 /*
1351 * Avoid annotation data structures overhead when symbols aren't on the
1352 * sort list.
1353 */
1354 top.sort_has_symbols = sort_sym.list.next != NULL;
1355
1356 get_term_dimensions(&top.winsize);
1357 if (top.print_entries == 0) { 1130 if (top.print_entries == 0) {
1358 struct sigaction act = { 1131 update_print_entries(&winsize);
1359 .sa_sigaction = perf_top__sig_winch, 1132 signal(SIGWINCH, sig_winch_handler);
1360 .sa_flags = SA_SIGINFO,
1361 };
1362 perf_top__update_print_entries(&top);
1363 sigaction(SIGWINCH, &act, NULL);
1364 } 1133 }
1365 1134
1366 status = __cmd_top(&top); 1135 status = __cmd_top();
1367 1136out_free_fd:
1368out_delete_evlist:
1369 perf_evlist__delete(top.evlist); 1137 perf_evlist__delete(top.evlist);
1370 1138
1371 return status; 1139 return status;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
deleted file mode 100644
index 7932ffa2988..00000000000
--- a/tools/perf/builtin-trace.c
+++ /dev/null
@@ -1,685 +0,0 @@
1#include "builtin.h"
2#include "util/color.h"
3#include "util/evlist.h"
4#include "util/machine.h"
5#include "util/thread.h"
6#include "util/parse-options.h"
7#include "util/thread_map.h"
8#include "event-parse.h"
9
10#include <libaudit.h>
11#include <stdlib.h>
12
13static struct syscall_fmt {
14 const char *name;
15 const char *alias;
16 bool errmsg;
17 bool timeout;
18} syscall_fmts[] = {
19 { .name = "access", .errmsg = true, },
20 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
21 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
22 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
23 { .name = "futex", .errmsg = true, },
24 { .name = "open", .errmsg = true, },
25 { .name = "poll", .errmsg = true, .timeout = true, },
26 { .name = "ppoll", .errmsg = true, .timeout = true, },
27 { .name = "read", .errmsg = true, },
28 { .name = "recvfrom", .errmsg = true, },
29 { .name = "select", .errmsg = true, .timeout = true, },
30 { .name = "socket", .errmsg = true, },
31 { .name = "stat", .errmsg = true, .alias = "newstat", },
32};
33
34static int syscall_fmt__cmp(const void *name, const void *fmtp)
35{
36 const struct syscall_fmt *fmt = fmtp;
37 return strcmp(name, fmt->name);
38}
39
40static struct syscall_fmt *syscall_fmt__find(const char *name)
41{
42 const int nmemb = ARRAY_SIZE(syscall_fmts);
43 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
44}
45
46struct syscall {
47 struct event_format *tp_format;
48 const char *name;
49 struct syscall_fmt *fmt;
50};
51
52static size_t fprintf_duration(unsigned long t, FILE *fp)
53{
54 double duration = (double)t / NSEC_PER_MSEC;
55 size_t printed = fprintf(fp, "(");
56
57 if (duration >= 1.0)
58 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
59 else if (duration >= 0.01)
60 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
61 else
62 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
63 return printed + fprintf(stdout, "): ");
64}
65
66struct thread_trace {
67 u64 entry_time;
68 u64 exit_time;
69 bool entry_pending;
70 unsigned long nr_events;
71 char *entry_str;
72 double runtime_ms;
73};
74
75static struct thread_trace *thread_trace__new(void)
76{
77 return zalloc(sizeof(struct thread_trace));
78}
79
80static struct thread_trace *thread__trace(struct thread *thread)
81{
82 struct thread_trace *ttrace;
83
84 if (thread == NULL)
85 goto fail;
86
87 if (thread->priv == NULL)
88 thread->priv = thread_trace__new();
89
90 if (thread->priv == NULL)
91 goto fail;
92
93 ttrace = thread->priv;
94 ++ttrace->nr_events;
95
96 return ttrace;
97fail:
98 color_fprintf(stdout, PERF_COLOR_RED,
99 "WARNING: not enough memory, dropping samples!\n");
100 return NULL;
101}
102
103struct trace {
104 int audit_machine;
105 struct {
106 int max;
107 struct syscall *table;
108 } syscalls;
109 struct perf_record_opts opts;
110 struct machine host;
111 u64 base_time;
112 unsigned long nr_events;
113 bool sched;
114 bool multiple_threads;
115 double duration_filter;
116 double runtime_ms;
117};
118
119static bool trace__filter_duration(struct trace *trace, double t)
120{
121 return t < (trace->duration_filter * NSEC_PER_MSEC);
122}
123
124static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
125{
126 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
127
128 return fprintf(fp, "%10.3f ", ts);
129}
130
131static bool done = false;
132
133static void sig_handler(int sig __maybe_unused)
134{
135 done = true;
136}
137
138static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
139 u64 duration, u64 tstamp, FILE *fp)
140{
141 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
142 printed += fprintf_duration(duration, fp);
143
144 if (trace->multiple_threads)
145 printed += fprintf(fp, "%d ", thread->pid);
146
147 return printed;
148}
149
150static int trace__process_event(struct machine *machine, union perf_event *event)
151{
152 int ret = 0;
153
154 switch (event->header.type) {
155 case PERF_RECORD_LOST:
156 color_fprintf(stdout, PERF_COLOR_RED,
157 "LOST %" PRIu64 " events!\n", event->lost.lost);
158 ret = machine__process_lost_event(machine, event);
159 default:
160 ret = machine__process_event(machine, event);
161 break;
162 }
163
164 return ret;
165}
166
167static int trace__tool_process(struct perf_tool *tool __maybe_unused,
168 union perf_event *event,
169 struct perf_sample *sample __maybe_unused,
170 struct machine *machine)
171{
172 return trace__process_event(machine, event);
173}
174
175static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
176{
177 int err = symbol__init();
178
179 if (err)
180 return err;
181
182 machine__init(&trace->host, "", HOST_KERNEL_ID);
183 machine__create_kernel_maps(&trace->host);
184
185 if (perf_target__has_task(&trace->opts.target)) {
186 err = perf_event__synthesize_thread_map(NULL, evlist->threads,
187 trace__tool_process,
188 &trace->host);
189 } else {
190 err = perf_event__synthesize_threads(NULL, trace__tool_process,
191 &trace->host);
192 }
193
194 if (err)
195 symbol__exit();
196
197 return err;
198}
199
200static int trace__read_syscall_info(struct trace *trace, int id)
201{
202 char tp_name[128];
203 struct syscall *sc;
204 const char *name = audit_syscall_to_name(id, trace->audit_machine);
205
206 if (name == NULL)
207 return -1;
208
209 if (id > trace->syscalls.max) {
210 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
211
212 if (nsyscalls == NULL)
213 return -1;
214
215 if (trace->syscalls.max != -1) {
216 memset(nsyscalls + trace->syscalls.max + 1, 0,
217 (id - trace->syscalls.max) * sizeof(*sc));
218 } else {
219 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
220 }
221
222 trace->syscalls.table = nsyscalls;
223 trace->syscalls.max = id;
224 }
225
226 sc = trace->syscalls.table + id;
227 sc->name = name;
228 sc->fmt = syscall_fmt__find(sc->name);
229
230 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
231 sc->tp_format = event_format__new("syscalls", tp_name);
232
233 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
234 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
235 sc->tp_format = event_format__new("syscalls", tp_name);
236 }
237
238 return sc->tp_format != NULL ? 0 : -1;
239}
240
241static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
242 unsigned long *args)
243{
244 int i = 0;
245 size_t printed = 0;
246
247 if (sc->tp_format != NULL) {
248 struct format_field *field;
249
250 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
251 printed += scnprintf(bf + printed, size - printed,
252 "%s%s: %ld", printed ? ", " : "",
253 field->name, args[i++]);
254 }
255 } else {
256 while (i < 6) {
257 printed += scnprintf(bf + printed, size - printed,
258 "%sarg%d: %ld",
259 printed ? ", " : "", i, args[i]);
260 ++i;
261 }
262 }
263
264 return printed;
265}
266
267typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
268 struct perf_sample *sample);
269
270static struct syscall *trace__syscall_info(struct trace *trace,
271 struct perf_evsel *evsel,
272 struct perf_sample *sample)
273{
274 int id = perf_evsel__intval(evsel, sample, "id");
275
276 if (id < 0) {
277 printf("Invalid syscall %d id, skipping...\n", id);
278 return NULL;
279 }
280
281 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
282 trace__read_syscall_info(trace, id))
283 goto out_cant_read;
284
285 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
286 goto out_cant_read;
287
288 return &trace->syscalls.table[id];
289
290out_cant_read:
291 printf("Problems reading syscall %d", id);
292 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
293 printf("(%s)", trace->syscalls.table[id].name);
294 puts(" information");
295 return NULL;
296}
297
298static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
299 struct perf_sample *sample)
300{
301 char *msg;
302 void *args;
303 size_t printed = 0;
304 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
305 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
306 struct thread_trace *ttrace = thread__trace(thread);
307
308 if (ttrace == NULL || sc == NULL)
309 return -1;
310
311 args = perf_evsel__rawptr(evsel, sample, "args");
312 if (args == NULL) {
313 printf("Problems reading syscall arguments\n");
314 return -1;
315 }
316
317 ttrace = thread->priv;
318
319 if (ttrace->entry_str == NULL) {
320 ttrace->entry_str = malloc(1024);
321 if (!ttrace->entry_str)
322 return -1;
323 }
324
325 ttrace->entry_time = sample->time;
326 msg = ttrace->entry_str;
327 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
328
329 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
330
331 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
332 if (!trace->duration_filter) {
333 trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout);
334 printf("%-70s\n", ttrace->entry_str);
335 }
336 } else
337 ttrace->entry_pending = true;
338
339 return 0;
340}
341
342static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
343 struct perf_sample *sample)
344{
345 int ret;
346 u64 duration = 0;
347 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
348 struct thread_trace *ttrace = thread__trace(thread);
349 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
350
351 if (ttrace == NULL || sc == NULL)
352 return -1;
353
354 ret = perf_evsel__intval(evsel, sample, "ret");
355
356 ttrace = thread->priv;
357
358 ttrace->exit_time = sample->time;
359
360 if (ttrace->entry_time) {
361 duration = sample->time - ttrace->entry_time;
362 if (trace__filter_duration(trace, duration))
363 goto out;
364 } else if (trace->duration_filter)
365 goto out;
366
367 trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout);
368
369 if (ttrace->entry_pending) {
370 printf("%-70s", ttrace->entry_str);
371 } else {
372 printf(" ... [");
373 color_fprintf(stdout, PERF_COLOR_YELLOW, "continued");
374 printf("]: %s()", sc->name);
375 }
376
377 if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
378 char bf[256];
379 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
380 *e = audit_errno_to_name(-ret);
381
382 printf(") = -1 %s %s", e, emsg);
383 } else if (ret == 0 && sc->fmt && sc->fmt->timeout)
384 printf(") = 0 Timeout");
385 else
386 printf(") = %d", ret);
387
388 putchar('\n');
389out:
390 ttrace->entry_pending = false;
391
392 return 0;
393}
394
395static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
396 struct perf_sample *sample)
397{
398 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
399 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
400 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
401 struct thread_trace *ttrace = thread__trace(thread);
402
403 if (ttrace == NULL)
404 goto out_dump;
405
406 ttrace->runtime_ms += runtime_ms;
407 trace->runtime_ms += runtime_ms;
408 return 0;
409
410out_dump:
411 printf("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
412 evsel->name,
413 perf_evsel__strval(evsel, sample, "comm"),
414 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
415 runtime,
416 perf_evsel__intval(evsel, sample, "vruntime"));
417 return 0;
418}
419
420static int trace__run(struct trace *trace, int argc, const char **argv)
421{
422 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
423 struct perf_evsel *evsel;
424 int err = -1, i;
425 unsigned long before;
426 const bool forks = argc > 0;
427
428 if (evlist == NULL) {
429 printf("Not enough memory to run!\n");
430 goto out;
431 }
432
433 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
434 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
435 printf("Couldn't read the raw_syscalls tracepoints information!\n");
436 goto out_delete_evlist;
437 }
438
439 if (trace->sched &&
440 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
441 trace__sched_stat_runtime)) {
442 printf("Couldn't read the sched_stat_runtime tracepoint information!\n");
443 goto out_delete_evlist;
444 }
445
446 err = perf_evlist__create_maps(evlist, &trace->opts.target);
447 if (err < 0) {
448 printf("Problems parsing the target to trace, check your options!\n");
449 goto out_delete_evlist;
450 }
451
452 err = trace__symbols_init(trace, evlist);
453 if (err < 0) {
454 printf("Problems initializing symbol libraries!\n");
455 goto out_delete_evlist;
456 }
457
458 perf_evlist__config_attrs(evlist, &trace->opts);
459
460 signal(SIGCHLD, sig_handler);
461 signal(SIGINT, sig_handler);
462
463 if (forks) {
464 err = perf_evlist__prepare_workload(evlist, &trace->opts, argv);
465 if (err < 0) {
466 printf("Couldn't run the workload!\n");
467 goto out_delete_evlist;
468 }
469 }
470
471 err = perf_evlist__open(evlist);
472 if (err < 0) {
473 printf("Couldn't create the events: %s\n", strerror(errno));
474 goto out_delete_evlist;
475 }
476
477 err = perf_evlist__mmap(evlist, UINT_MAX, false);
478 if (err < 0) {
479 printf("Couldn't mmap the events: %s\n", strerror(errno));
480 goto out_delete_evlist;
481 }
482
483 perf_evlist__enable(evlist);
484
485 if (forks)
486 perf_evlist__start_workload(evlist);
487
488 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
489again:
490 before = trace->nr_events;
491
492 for (i = 0; i < evlist->nr_mmaps; i++) {
493 union perf_event *event;
494
495 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
496 const u32 type = event->header.type;
497 tracepoint_handler handler;
498 struct perf_sample sample;
499
500 ++trace->nr_events;
501
502 err = perf_evlist__parse_sample(evlist, event, &sample);
503 if (err) {
504 printf("Can't parse sample, err = %d, skipping...\n", err);
505 continue;
506 }
507
508 if (trace->base_time == 0)
509 trace->base_time = sample.time;
510
511 if (type != PERF_RECORD_SAMPLE) {
512 trace__process_event(&trace->host, event);
513 continue;
514 }
515
516 evsel = perf_evlist__id2evsel(evlist, sample.id);
517 if (evsel == NULL) {
518 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
519 continue;
520 }
521
522 if (sample.raw_data == NULL) {
523 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
524 perf_evsel__name(evsel), sample.tid,
525 sample.cpu, sample.raw_size);
526 continue;
527 }
528
529 if (sample.raw_data == NULL) {
530 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
531 perf_evsel__name(evsel), sample.tid,
532 sample.cpu, sample.raw_size);
533 continue;
534 }
535
536 handler = evsel->handler.func;
537 handler(trace, evsel, &sample);
538 }
539 }
540
541 if (trace->nr_events == before) {
542 if (done)
543 goto out_delete_evlist;
544
545 poll(evlist->pollfd, evlist->nr_fds, -1);
546 }
547
548 if (done)
549 perf_evlist__disable(evlist);
550
551 goto again;
552
553out_delete_evlist:
554 perf_evlist__delete(evlist);
555out:
556 return err;
557}
558
559static size_t trace__fprintf_threads_header(FILE *fp)
560{
561 size_t printed;
562
563 printed = fprintf(fp, "\n _____________________________________________________________________\n");
564 printed += fprintf(fp," __) Summary of events (__\n\n");
565 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
566 printed += fprintf(fp," _____________________________________________________________________\n\n");
567
568 return printed;
569}
570
571static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
572{
573 size_t printed = trace__fprintf_threads_header(fp);
574 struct rb_node *nd;
575
576 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
577 struct thread *thread = rb_entry(nd, struct thread, rb_node);
578 struct thread_trace *ttrace = thread->priv;
579 const char *color;
580 double ratio;
581
582 if (ttrace == NULL)
583 continue;
584
585 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
586
587 color = PERF_COLOR_NORMAL;
588 if (ratio > 50.0)
589 color = PERF_COLOR_RED;
590 else if (ratio > 25.0)
591 color = PERF_COLOR_GREEN;
592 else if (ratio > 5.0)
593 color = PERF_COLOR_YELLOW;
594
595 printed += color_fprintf(fp, color, "%20s", thread->comm);
596 printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events);
597 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
598 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
599 }
600
601 return printed;
602}
603
604static int trace__set_duration(const struct option *opt, const char *str,
605 int unset __maybe_unused)
606{
607 struct trace *trace = opt->value;
608
609 trace->duration_filter = atof(str);
610 return 0;
611}
612
613int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
614{
615 const char * const trace_usage[] = {
616 "perf trace [<options>] [<command>]",
617 "perf trace [<options>] -- <command> [<options>]",
618 NULL
619 };
620 struct trace trace = {
621 .audit_machine = audit_detect_machine(),
622 .syscalls = {
623 . max = -1,
624 },
625 .opts = {
626 .target = {
627 .uid = UINT_MAX,
628 .uses_mmap = true,
629 },
630 .user_freq = UINT_MAX,
631 .user_interval = ULLONG_MAX,
632 .no_delay = true,
633 .mmap_pages = 1024,
634 },
635 };
636 const struct option trace_options[] = {
637 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
638 "trace events on existing process id"),
639 OPT_STRING(0, "tid", &trace.opts.target.tid, "tid",
640 "trace events on existing thread id"),
641 OPT_BOOLEAN(0, "all-cpus", &trace.opts.target.system_wide,
642 "system-wide collection from all CPUs"),
643 OPT_STRING(0, "cpu", &trace.opts.target.cpu_list, "cpu",
644 "list of cpus to monitor"),
645 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
646 "child tasks do not inherit counters"),
647 OPT_UINTEGER(0, "mmap-pages", &trace.opts.mmap_pages,
648 "number of mmap data pages"),
649 OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
650 "user to profile"),
651 OPT_CALLBACK(0, "duration", &trace, "float",
652 "show only events with duration > N.M ms",
653 trace__set_duration),
654 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
655 OPT_END()
656 };
657 int err;
658 char bf[BUFSIZ];
659
660 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
661
662 err = perf_target__validate(&trace.opts.target);
663 if (err) {
664 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
665 printf("%s", bf);
666 return err;
667 }
668
669 err = perf_target__parse_uid(&trace.opts.target);
670 if (err) {
671 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
672 printf("%s", bf);
673 return err;
674 }
675
676 if (!argc && perf_target__none(&trace.opts.target))
677 trace.opts.target.system_wide = true;
678
679 err = trace__run(&trace, argc, argv);
680
681 if (trace.sched && !err)
682 trace__fprintf_thread_summary(&trace, stdout);
683
684 return err;
685}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 08143bd854c..4702e2443a8 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -4,6 +4,7 @@
4#include "util/util.h" 4#include "util/util.h"
5#include "util/strbuf.h" 5#include "util/strbuf.h"
6 6
7extern const char perf_version_string[];
7extern const char perf_usage_string[]; 8extern const char perf_usage_string[];
8extern const char perf_more_info_string[]; 9extern const char perf_more_info_string[];
9 10
@@ -34,8 +35,6 @@ extern int cmd_kmem(int argc, const char **argv, const char *prefix);
34extern int cmd_lock(int argc, const char **argv, const char *prefix); 35extern int cmd_lock(int argc, const char **argv, const char *prefix);
35extern int cmd_kvm(int argc, const char **argv, const char *prefix); 36extern int cmd_kvm(int argc, const char **argv, const char *prefix);
36extern int cmd_test(int argc, const char **argv, const char *prefix); 37extern int cmd_test(int argc, const char **argv, const char *prefix);
37extern int cmd_trace(int argc, const char **argv, const char *prefix);
38extern int cmd_inject(int argc, const char **argv, const char *prefix); 38extern int cmd_inject(int argc, const char **argv, const char *prefix);
39 39
40extern int find_scripts(char **scripts_array, char **scripts_path_array);
41#endif 40#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 3e86bbd8c2d..d695fe40fbf 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -17,9 +17,8 @@ perf-report mainporcelain common
17perf-stat mainporcelain common 17perf-stat mainporcelain common
18perf-timechart mainporcelain common 18perf-timechart mainporcelain common
19perf-top mainporcelain common 19perf-top mainporcelain common
20perf-trace mainporcelain common
21perf-script mainporcelain common 20perf-script mainporcelain common
22perf-probe mainporcelain full 21perf-probe mainporcelain common
23perf-kmem mainporcelain common 22perf-kmem mainporcelain common
24perf-lock mainporcelain common 23perf-lock mainporcelain common
25perf-kvm mainporcelain common 24perf-kvm mainporcelain common
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index f5ac77485a4..6170fd2531b 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -43,15 +43,6 @@ int main(void)
43} 43}
44endef 44endef
45 45
46define SOURCE_BIONIC
47#include <android/api-level.h>
48
49int main(void)
50{
51 return __ANDROID_API__;
52}
53endef
54
55define SOURCE_ELF_MMAP 46define SOURCE_ELF_MMAP
56#include <libelf.h> 47#include <libelf.h>
57int main(void) 48int main(void)
@@ -74,34 +65,6 @@ int main(void)
74endef 65endef
75endif 66endif
76 67
77ifndef NO_GTK2
78define SOURCE_GTK2
79#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
80#include <gtk/gtk.h>
81#pragma GCC diagnostic error \"-Wstrict-prototypes\"
82
83int main(int argc, char *argv[])
84{
85 gtk_init(&argc, &argv);
86
87 return 0;
88}
89endef
90
91define SOURCE_GTK2_INFOBAR
92#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
93#include <gtk/gtk.h>
94#pragma GCC diagnostic error \"-Wstrict-prototypes\"
95
96int main(void)
97{
98 gtk_info_bar_new();
99
100 return 0;
101}
102endef
103endif
104
105ifndef NO_LIBPERL 68ifndef NO_LIBPERL
106define SOURCE_PERL_EMBED 69define SOURCE_PERL_EMBED
107#include <EXTERN.h> 70#include <EXTERN.h>
@@ -121,10 +84,7 @@ define SOURCE_PYTHON_VERSION
121#if PY_VERSION_HEX >= 0x03000000 84#if PY_VERSION_HEX >= 0x03000000
122 #error 85 #error
123#endif 86#endif
124int main(void) 87int main(void){}
125{
126 return 0;
127}
128endef 88endef
129define SOURCE_PYTHON_EMBED 89define SOURCE_PYTHON_EMBED
130#include <Python.h> 90#include <Python.h>
@@ -166,62 +126,3 @@ int main(void)
166 return 0; 126 return 0;
167} 127}
168endef 128endef
169
170ifndef NO_LIBUNWIND
171define SOURCE_LIBUNWIND
172#include <libunwind.h>
173#include <stdlib.h>
174
175extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
176 unw_word_t ip,
177 unw_dyn_info_t *di,
178 unw_proc_info_t *pi,
179 int need_unwind_info, void *arg);
180
181
182#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
183
184int main(void)
185{
186 unw_addr_space_t addr_space;
187 addr_space = unw_create_addr_space(NULL, 0);
188 unw_init_remote(NULL, addr_space, NULL);
189 dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
190 return 0;
191}
192endef
193endif
194
195ifndef NO_BACKTRACE
196define SOURCE_BACKTRACE
197#include <execinfo.h>
198#include <stdio.h>
199
200int main(void)
201{
202 backtrace(NULL, 0);
203 backtrace_symbols(NULL, 0);
204 return 0;
205}
206endef
207endif
208
209ifndef NO_LIBAUDIT
210define SOURCE_LIBAUDIT
211#include <libaudit.h>
212
213int main(void)
214{
215 return audit_open();
216}
217endef
218endif
219
220define SOURCE_ON_EXIT
221#include <stdio.h>
222
223int main(void)
224{
225 return on_exit(NULL, NULL);
226}
227endef
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index e5413125e6b..8046182a19e 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -180,15 +180,9 @@ _gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181 181
182# try-cc 182# try-cc
183# Usage: option = $(call try-cc, source-to-build, cc-options, msg) 183# Usage: option = $(call try-cc, source-to-build, cc-options)
184ifndef V
185TRY_CC_OUTPUT= > /dev/null 2>&1
186endif
187TRY_CC_MSG=echo " CHK $(3)" 1>&2;
188
189try-cc = $(shell sh -c \ 184try-cc = $(shell sh -c \
190 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ 185 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
191 $(TRY_CC_MSG) \
192 echo "$(1)" | \ 186 echo "$(1)" | \
193 $(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \ 187 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
194 rm -f "$$TMP"') 188 rm -f "$$TMP"')
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index 67e5d0cace8..bd0bb1b1279 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -409,15 +409,14 @@ Counters can be enabled and disabled in two ways: via ioctl and via
409prctl. When a counter is disabled, it doesn't count or generate 409prctl. When a counter is disabled, it doesn't count or generate
410events but does continue to exist and maintain its count value. 410events but does continue to exist and maintain its count value.
411 411
412An individual counter can be enabled with 412An individual counter or counter group can be enabled with
413 413
414 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); 414 ioctl(fd, PERF_EVENT_IOC_ENABLE);
415 415
416or disabled with 416or disabled with
417 417
418 ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); 418 ioctl(fd, PERF_EVENT_IOC_DISABLE);
419 419
420For a counter group, pass PERF_IOC_FLAG_GROUP as the third argument.
421Enabling or disabling the leader of a group enables or disables the 420Enabling or disabling the leader of a group enables or disables the
422whole group; that is, while the group leader is disabled, none of the 421whole group; that is, while the group leader is disabled, none of the
423counters in the group will count. Enabling or disabling a member of a 422counters in the group will count. Enabling or disabling a member of a
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
index e9193062026..677e59d62a8 100644
--- a/tools/perf/perf-archive.sh
+++ b/tools/perf/perf-archive.sh
@@ -24,23 +24,22 @@ NOBUILDID=0000000000000000000000000000000000000000
24perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS 24perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
25if [ ! -s $BUILDIDS ] ; then 25if [ ! -s $BUILDIDS ] ; then
26 echo "perf archive: no build-ids found" 26 echo "perf archive: no build-ids found"
27 rm $BUILDIDS || true 27 rm -f $BUILDIDS
28 exit 1 28 exit 1
29fi 29fi
30 30
31MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX) 31MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
32PERF_BUILDID_LINKDIR=$(readlink -f $PERF_BUILDID_DIR)/
33 32
34cut -d ' ' -f 1 $BUILDIDS | \ 33cut -d ' ' -f 1 $BUILDIDS | \
35while read build_id ; do 34while read build_id ; do
36 linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2} 35 linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2}
37 filename=$(readlink -f $linkname) 36 filename=$(readlink -f $linkname)
38 echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST 37 echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST
39 echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST 38 echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST
40done 39done
41 40
42tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST 41tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
43rm $MANIFEST $BUILDIDS || true 42rm -f $MANIFEST $BUILDIDS
44echo -e "Now please run:\n" 43echo -e "Now please run:\n"
45echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" 44echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
46echo "wherever you need to run 'perf report' on." 45echo "wherever you need to run 'perf report' on."
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 0f661fbce6a..ec635b7cc8e 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -14,7 +14,6 @@
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/debugfs.h" 16#include "util/debugfs.h"
17#include <pthread.h>
18 17
19const char perf_usage_string[] = 18const char perf_usage_string[] =
20 "perf [--version] [--help] COMMAND [ARGS]"; 19 "perf [--version] [--help] COMMAND [ARGS]";
@@ -24,49 +23,14 @@ const char perf_more_info_string[] =
24 23
25int use_browser = -1; 24int use_browser = -1;
26static int use_pager = -1; 25static int use_pager = -1;
27const char *input_name;
28
29struct cmd_struct {
30 const char *cmd;
31 int (*fn)(int, const char **, const char *);
32 int option;
33};
34
35static struct cmd_struct commands[] = {
36 { "buildid-cache", cmd_buildid_cache, 0 },
37 { "buildid-list", cmd_buildid_list, 0 },
38 { "diff", cmd_diff, 0 },
39 { "evlist", cmd_evlist, 0 },
40 { "help", cmd_help, 0 },
41 { "list", cmd_list, 0 },
42 { "record", cmd_record, 0 },
43 { "report", cmd_report, 0 },
44 { "bench", cmd_bench, 0 },
45 { "stat", cmd_stat, 0 },
46 { "timechart", cmd_timechart, 0 },
47 { "top", cmd_top, 0 },
48 { "annotate", cmd_annotate, 0 },
49 { "version", cmd_version, 0 },
50 { "script", cmd_script, 0 },
51 { "sched", cmd_sched, 0 },
52#ifdef LIBELF_SUPPORT
53 { "probe", cmd_probe, 0 },
54#endif
55 { "kmem", cmd_kmem, 0 },
56 { "lock", cmd_lock, 0 },
57 { "kvm", cmd_kvm, 0 },
58 { "test", cmd_test, 0 },
59#ifdef LIBAUDIT_SUPPORT
60 { "trace", cmd_trace, 0 },
61#endif
62 { "inject", cmd_inject, 0 },
63};
64 26
65struct pager_config { 27struct pager_config {
66 const char *cmd; 28 const char *cmd;
67 int val; 29 int val;
68}; 30};
69 31
32static char debugfs_mntpt[MAXPATHLEN];
33
70static int pager_command_config(const char *var, const char *value, void *data) 34static int pager_command_config(const char *var, const char *value, void *data)
71{ 35{
72 struct pager_config *c = data; 36 struct pager_config *c = data;
@@ -85,26 +49,21 @@ int check_pager_config(const char *cmd)
85 return c.val; 49 return c.val;
86} 50}
87 51
88static int browser_command_config(const char *var, const char *value, void *data) 52static int tui_command_config(const char *var, const char *value, void *data)
89{ 53{
90 struct pager_config *c = data; 54 struct pager_config *c = data;
91 if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd)) 55 if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd))
92 c->val = perf_config_bool(var, value); 56 c->val = perf_config_bool(var, value);
93 if (!prefixcmp(var, "gtk.") && !strcmp(var + 4, c->cmd))
94 c->val = perf_config_bool(var, value) ? 2 : 0;
95 return 0; 57 return 0;
96} 58}
97 59
98/* 60/* returns 0 for "no tui", 1 for "use tui", and -1 for "not specified" */
99 * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk", 61static int check_tui_config(const char *cmd)
100 * and -1 for "not specified"
101 */
102static int check_browser_config(const char *cmd)
103{ 62{
104 struct pager_config c; 63 struct pager_config c;
105 c.cmd = cmd; 64 c.cmd = cmd;
106 c.val = -1; 65 c.val = -1;
107 perf_config(browser_command_config, &c); 66 perf_config(tui_command_config, &c);
108 return c.val; 67 return c.val;
109} 68}
110 69
@@ -122,6 +81,15 @@ static void commit_pager_choice(void)
122 } 81 }
123} 82}
124 83
84static void set_debugfs_path(void)
85{
86 char *path;
87
88 path = getenv(PERF_DEBUGFS_ENVIRONMENT);
89 snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
90 "tracing/events");
91}
92
125static int handle_options(const char ***argv, int *argc, int *envchanged) 93static int handle_options(const char ***argv, int *argc, int *envchanged)
126{ 94{
127 int handled = 0; 95 int handled = 0;
@@ -193,24 +161,17 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
193 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 161 fprintf(stderr, "No directory given for --debugfs-dir.\n");
194 usage(perf_usage_string); 162 usage(perf_usage_string);
195 } 163 }
196 debugfs_set_path((*argv)[1]); 164 strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN);
165 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
197 if (envchanged) 166 if (envchanged)
198 *envchanged = 1; 167 *envchanged = 1;
199 (*argv)++; 168 (*argv)++;
200 (*argc)--; 169 (*argc)--;
201 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { 170 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
202 debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); 171 strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
203 fprintf(stderr, "dir: %s\n", debugfs_mountpoint); 172 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
204 if (envchanged) 173 if (envchanged)
205 *envchanged = 1; 174 *envchanged = 1;
206 } else if (!strcmp(cmd, "--list-cmds")) {
207 unsigned int i;
208
209 for (i = 0; i < ARRAY_SIZE(commands); i++) {
210 struct cmd_struct *p = commands+i;
211 printf("%s ", p->cmd);
212 }
213 exit(0);
214 } else { 175 } else {
215 fprintf(stderr, "Unknown option: %s\n", cmd); 176 fprintf(stderr, "Unknown option: %s\n", cmd);
216 usage(perf_usage_string); 177 usage(perf_usage_string);
@@ -296,6 +257,12 @@ const char perf_version_string[] = PERF_VERSION;
296 */ 257 */
297#define NEED_WORK_TREE (1<<2) 258#define NEED_WORK_TREE (1<<2)
298 259
260struct cmd_struct {
261 const char *cmd;
262 int (*fn)(int, const char **, const char *);
263 int option;
264};
265
299static int run_builtin(struct cmd_struct *p, int argc, const char **argv) 266static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
300{ 267{
301 int status; 268 int status;
@@ -307,13 +274,14 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
307 prefix = NULL; /* setup_perf_directory(); */ 274 prefix = NULL; /* setup_perf_directory(); */
308 275
309 if (use_browser == -1) 276 if (use_browser == -1)
310 use_browser = check_browser_config(p->cmd); 277 use_browser = check_tui_config(p->cmd);
311 278
312 if (use_pager == -1 && p->option & RUN_SETUP) 279 if (use_pager == -1 && p->option & RUN_SETUP)
313 use_pager = check_pager_config(p->cmd); 280 use_pager = check_pager_config(p->cmd);
314 if (use_pager == -1 && p->option & USE_PAGER) 281 if (use_pager == -1 && p->option & USE_PAGER)
315 use_pager = 1; 282 use_pager = 1;
316 commit_pager_choice(); 283 commit_pager_choice();
284 set_debugfs_path();
317 285
318 status = p->fn(argc, argv, prefix); 286 status = p->fn(argc, argv, prefix);
319 exit_browser(status); 287 exit_browser(status);
@@ -341,6 +309,30 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
341static void handle_internal_command(int argc, const char **argv) 309static void handle_internal_command(int argc, const char **argv)
342{ 310{
343 const char *cmd = argv[0]; 311 const char *cmd = argv[0];
312 static struct cmd_struct commands[] = {
313 { "buildid-cache", cmd_buildid_cache, 0 },
314 { "buildid-list", cmd_buildid_list, 0 },
315 { "diff", cmd_diff, 0 },
316 { "evlist", cmd_evlist, 0 },
317 { "help", cmd_help, 0 },
318 { "list", cmd_list, 0 },
319 { "record", cmd_record, 0 },
320 { "report", cmd_report, 0 },
321 { "bench", cmd_bench, 0 },
322 { "stat", cmd_stat, 0 },
323 { "timechart", cmd_timechart, 0 },
324 { "top", cmd_top, 0 },
325 { "annotate", cmd_annotate, 0 },
326 { "version", cmd_version, 0 },
327 { "script", cmd_script, 0 },
328 { "sched", cmd_sched, 0 },
329 { "probe", cmd_probe, 0 },
330 { "kmem", cmd_kmem, 0 },
331 { "lock", cmd_lock, 0 },
332 { "kvm", cmd_kvm, 0 },
333 { "test", cmd_test, 0 },
334 { "inject", cmd_inject, 0 },
335 };
344 unsigned int i; 336 unsigned int i;
345 static const char ext[] = STRIP_EXTENSION; 337 static const char ext[] = STRIP_EXTENSION;
346 338
@@ -424,35 +416,26 @@ static int run_argv(int *argcp, const char ***argv)
424 return done_alias; 416 return done_alias;
425} 417}
426 418
427static void pthread__block_sigwinch(void) 419/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
420static void get_debugfs_mntpt(void)
428{ 421{
429 sigset_t set; 422 const char *path = debugfs_mount(NULL);
430 423
431 sigemptyset(&set); 424 if (path)
432 sigaddset(&set, SIGWINCH); 425 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
433 pthread_sigmask(SIG_BLOCK, &set, NULL); 426 else
434} 427 debugfs_mntpt[0] = '\0';
435
436void pthread__unblock_sigwinch(void)
437{
438 sigset_t set;
439
440 sigemptyset(&set);
441 sigaddset(&set, SIGWINCH);
442 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
443} 428}
444 429
445int main(int argc, const char **argv) 430int main(int argc, const char **argv)
446{ 431{
447 const char *cmd; 432 const char *cmd;
448 433
449 page_size = sysconf(_SC_PAGE_SIZE);
450
451 cmd = perf_extract_argv0_path(argv[0]); 434 cmd = perf_extract_argv0_path(argv[0]);
452 if (!cmd) 435 if (!cmd)
453 cmd = "perf-help"; 436 cmd = "perf-help";
454 /* get debugfs mount point from /proc/mounts */ 437 /* get debugfs mount point from /proc/mounts */
455 debugfs_mount(NULL); 438 get_debugfs_mntpt();
456 /* 439 /*
457 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 440 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
458 * 441 *
@@ -475,6 +458,7 @@ int main(int argc, const char **argv)
475 argc--; 458 argc--;
476 handle_options(&argv, &argc, NULL); 459 handle_options(&argv, &argc, NULL);
477 commit_pager_choice(); 460 commit_pager_choice();
461 set_debugfs_path();
478 set_buildid_dir(); 462 set_buildid_dir();
479 463
480 if (argc > 0) { 464 if (argc > 0) {
@@ -489,8 +473,6 @@ int main(int argc, const char **argv)
489 } 473 }
490 cmd = argv[0]; 474 cmd = argv[0];
491 475
492 test_attr__init();
493
494 /* 476 /*
495 * We use PATH to find perf commands, but we prepend some higher 477 * We use PATH to find perf commands, but we prepend some higher
496 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH 478 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
@@ -498,12 +480,6 @@ int main(int argc, const char **argv)
498 * time. 480 * time.
499 */ 481 */
500 setup_path(); 482 setup_path();
501 /*
502 * Block SIGWINCH notifications so that the thread that wants it can
503 * unblock and get syscalls like select interrupted instead of waiting
504 * forever while the signal goes to some other non interested thread.
505 */
506 pthread__block_sigwinch();
507 483
508 while (1) { 484 while (1) {
509 static int done_help; 485 static int done_help;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 2c340e7da45..a5fc660c1f1 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -5,88 +5,76 @@ struct winsize;
5 5
6void get_term_dimensions(struct winsize *ws); 6void get_term_dimensions(struct winsize *ws);
7 7
8#include <asm/unistd.h>
9
10#if defined(__i386__) 8#if defined(__i386__)
9#include "../../arch/x86/include/asm/unistd.h"
11#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
12#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 11#define cpu_relax() asm volatile("rep; nop" ::: "memory");
13#define CPUINFO_PROC "model name"
14#ifndef __NR_perf_event_open
15# define __NR_perf_event_open 336
16#endif
17#endif 12#endif
18 13
19#if defined(__x86_64__) 14#if defined(__x86_64__)
15#include "../../arch/x86/include/asm/unistd.h"
20#define rmb() asm volatile("lfence" ::: "memory") 16#define rmb() asm volatile("lfence" ::: "memory")
21#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 17#define cpu_relax() asm volatile("rep; nop" ::: "memory");
22#define CPUINFO_PROC "model name"
23#ifndef __NR_perf_event_open
24# define __NR_perf_event_open 298
25#endif
26#endif 18#endif
27 19
28#ifdef __powerpc__ 20#ifdef __powerpc__
29#include "../../arch/powerpc/include/uapi/asm/unistd.h" 21#include "../../arch/powerpc/include/asm/unistd.h"
30#define rmb() asm volatile ("sync" ::: "memory") 22#define rmb() asm volatile ("sync" ::: "memory")
31#define cpu_relax() asm volatile ("" ::: "memory"); 23#define cpu_relax() asm volatile ("" ::: "memory");
32#define CPUINFO_PROC "cpu"
33#endif 24#endif
34 25
35#ifdef __s390__ 26#ifdef __s390__
27#include "../../arch/s390/include/asm/unistd.h"
36#define rmb() asm volatile("bcr 15,0" ::: "memory") 28#define rmb() asm volatile("bcr 15,0" ::: "memory")
37#define cpu_relax() asm volatile("" ::: "memory"); 29#define cpu_relax() asm volatile("" ::: "memory");
38#endif 30#endif
39 31
40#ifdef __sh__ 32#ifdef __sh__
33#include "../../arch/sh/include/asm/unistd.h"
41#if defined(__SH4A__) || defined(__SH5__) 34#if defined(__SH4A__) || defined(__SH5__)
42# define rmb() asm volatile("synco" ::: "memory") 35# define rmb() asm volatile("synco" ::: "memory")
43#else 36#else
44# define rmb() asm volatile("" ::: "memory") 37# define rmb() asm volatile("" ::: "memory")
45#endif 38#endif
46#define cpu_relax() asm volatile("" ::: "memory") 39#define cpu_relax() asm volatile("" ::: "memory")
47#define CPUINFO_PROC "cpu type"
48#endif 40#endif
49 41
50#ifdef __hppa__ 42#ifdef __hppa__
43#include "../../arch/parisc/include/asm/unistd.h"
51#define rmb() asm volatile("" ::: "memory") 44#define rmb() asm volatile("" ::: "memory")
52#define cpu_relax() asm volatile("" ::: "memory"); 45#define cpu_relax() asm volatile("" ::: "memory");
53#define CPUINFO_PROC "cpu"
54#endif 46#endif
55 47
56#ifdef __sparc__ 48#ifdef __sparc__
49#include "../../arch/sparc/include/asm/unistd.h"
57#define rmb() asm volatile("":::"memory") 50#define rmb() asm volatile("":::"memory")
58#define cpu_relax() asm volatile("":::"memory") 51#define cpu_relax() asm volatile("":::"memory")
59#define CPUINFO_PROC "cpu"
60#endif 52#endif
61 53
62#ifdef __alpha__ 54#ifdef __alpha__
55#include "../../arch/alpha/include/asm/unistd.h"
63#define rmb() asm volatile("mb" ::: "memory") 56#define rmb() asm volatile("mb" ::: "memory")
64#define cpu_relax() asm volatile("" ::: "memory") 57#define cpu_relax() asm volatile("" ::: "memory")
65#define CPUINFO_PROC "cpu model"
66#endif 58#endif
67 59
68#ifdef __ia64__ 60#ifdef __ia64__
61#include "../../arch/ia64/include/asm/unistd.h"
69#define rmb() asm volatile ("mf" ::: "memory") 62#define rmb() asm volatile ("mf" ::: "memory")
70#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 63#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
71#define CPUINFO_PROC "model name"
72#endif 64#endif
73 65
74#ifdef __arm__ 66#ifdef __arm__
67#include "../../arch/arm/include/asm/unistd.h"
75/* 68/*
76 * Use the __kuser_memory_barrier helper in the CPU helper page. See 69 * Use the __kuser_memory_barrier helper in the CPU helper page. See
77 * arch/arm/kernel/entry-armv.S in the kernel source for details. 70 * arch/arm/kernel/entry-armv.S in the kernel source for details.
78 */ 71 */
79#define rmb() ((void(*)(void))0xffff0fa0)() 72#define rmb() ((void(*)(void))0xffff0fa0)()
80#define cpu_relax() asm volatile("":::"memory") 73#define cpu_relax() asm volatile("":::"memory")
81#define CPUINFO_PROC "Processor"
82#endif
83
84#ifdef __aarch64__
85#define rmb() asm volatile("dmb ld" ::: "memory")
86#define cpu_relax() asm volatile("yield" ::: "memory")
87#endif 74#endif
88 75
89#ifdef __mips__ 76#ifdef __mips__
77#include "../../arch/mips/include/asm/unistd.h"
90#define rmb() asm volatile( \ 78#define rmb() asm volatile( \
91 ".set mips2\n\t" \ 79 ".set mips2\n\t" \
92 "sync\n\t" \ 80 "sync\n\t" \
@@ -95,7 +83,6 @@ void get_term_dimensions(struct winsize *ws);
95 : /* no input */ \ 83 : /* no input */ \
96 : "memory") 84 : "memory")
97#define cpu_relax() asm volatile("" ::: "memory") 85#define cpu_relax() asm volatile("" ::: "memory")
98#define CPUINFO_PROC "cpu model"
99#endif 86#endif
100 87
101#include <time.h> 88#include <time.h>
@@ -103,7 +90,7 @@ void get_term_dimensions(struct winsize *ws);
103#include <sys/types.h> 90#include <sys/types.h>
104#include <sys/syscall.h> 91#include <sys/syscall.h>
105 92
106#include <linux/perf_event.h> 93#include "../../include/linux/perf_event.h"
107#include "util/types.h" 94#include "util/types.h"
108#include <stdbool.h> 95#include <stdbool.h>
109 96
@@ -165,25 +152,14 @@ static inline unsigned long long rdclock(void)
165 (void) (&_min1 == &_min2); \ 152 (void) (&_min1 == &_min2); \
166 _min1 < _min2 ? _min1 : _min2; }) 153 _min1 < _min2 ? _min1 : _min2; })
167 154
168extern bool test_attr__enabled;
169void test_attr__init(void);
170void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
171 int fd, int group_fd, unsigned long flags);
172
173static inline int 155static inline int
174sys_perf_event_open(struct perf_event_attr *attr, 156sys_perf_event_open(struct perf_event_attr *attr,
175 pid_t pid, int cpu, int group_fd, 157 pid_t pid, int cpu, int group_fd,
176 unsigned long flags) 158 unsigned long flags)
177{ 159{
178 int fd; 160 attr->size = sizeof(*attr);
179 161 return syscall(__NR_perf_event_open, attr, pid, cpu,
180 fd = syscall(__NR_perf_event_open, attr, pid, cpu, 162 group_fd, flags);
181 group_fd, flags);
182
183 if (unlikely(test_attr__enabled))
184 test_attr__open(attr, pid, cpu, fd, group_fd, flags);
185
186 return fd;
187} 163}
188 164
189#define MAX_COUNTERS 256 165#define MAX_COUNTERS 256
@@ -194,59 +170,6 @@ struct ip_callchain {
194 u64 ips[0]; 170 u64 ips[0];
195}; 171};
196 172
197struct branch_flags {
198 u64 mispred:1;
199 u64 predicted:1;
200 u64 reserved:62;
201};
202
203struct branch_entry {
204 u64 from;
205 u64 to;
206 struct branch_flags flags;
207};
208
209struct branch_stack {
210 u64 nr;
211 struct branch_entry entries[0];
212};
213
214extern const char *input_name;
215extern bool perf_host, perf_guest; 173extern bool perf_host, perf_guest;
216extern const char perf_version_string[];
217
218void pthread__unblock_sigwinch(void);
219
220#include "util/target.h"
221
222enum perf_call_graph_mode {
223 CALLCHAIN_NONE,
224 CALLCHAIN_FP,
225 CALLCHAIN_DWARF
226};
227
228struct perf_record_opts {
229 struct perf_target target;
230 int call_graph;
231 bool group;
232 bool inherit_stat;
233 bool no_delay;
234 bool no_inherit;
235 bool no_samples;
236 bool pipe_output;
237 bool raw_samples;
238 bool sample_address;
239 bool sample_time;
240 bool sample_id_all_missing;
241 bool exclude_guest_missing;
242 bool period;
243 unsigned int freq;
244 unsigned int mmap_pages;
245 unsigned int user_freq;
246 u64 branch_stack;
247 u64 default_interval;
248 u64 user_interval;
249 u16 stack_dump_size;
250};
251 174
252#endif 175#endif
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index b11cca58423..df638c438a9 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -19,7 +19,7 @@ def main():
19 cpus = perf.cpu_map() 19 cpus = perf.cpu_map()
20 threads = perf.thread_map() 20 threads = perf.thread_map()
21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0, 21 evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
22 wakeup_events = 1, watermark = 1, 22 wakeup_events = 1, sample_period = 1,
23 sample_id_all = 1, 23 sample_id_all = 1,
24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID) 24 sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID)
25 evsel.open(cpus = cpus, threads = threads); 25 evsel.open(cpus = cpus, threads = threads);
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py
deleted file mode 100755
index 9e0985794e2..00000000000
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/EventClass.py
+++ /dev/null
@@ -1,94 +0,0 @@
1# EventClass.py
2#
3# This is a library defining some events types classes, which could
4# be used by other scripts to analyzing the perf samples.
5#
6# Currently there are just a few classes defined for examples,
7# PerfEvent is the base class for all perf event sample, PebsEvent
8# is a HW base Intel x86 PEBS event, and user could add more SW/HW
9# event classes based on requirements.
10
11import struct
12
13# Event types, user could add more here
14EVTYPE_GENERIC = 0
15EVTYPE_PEBS = 1 # Basic PEBS event
16EVTYPE_PEBS_LL = 2 # PEBS event with load latency info
17EVTYPE_IBS = 3
18
19#
20# Currently we don't have good way to tell the event type, but by
21# the size of raw buffer, raw PEBS event with load latency data's
22# size is 176 bytes, while the pure PEBS event's size is 144 bytes.
23#
24def create_event(name, comm, dso, symbol, raw_buf):
25 if (len(raw_buf) == 144):
26 event = PebsEvent(name, comm, dso, symbol, raw_buf)
27 elif (len(raw_buf) == 176):
28 event = PebsNHM(name, comm, dso, symbol, raw_buf)
29 else:
30 event = PerfEvent(name, comm, dso, symbol, raw_buf)
31
32 return event
33
34class PerfEvent(object):
35 event_num = 0
36 def __init__(self, name, comm, dso, symbol, raw_buf, ev_type=EVTYPE_GENERIC):
37 self.name = name
38 self.comm = comm
39 self.dso = dso
40 self.symbol = symbol
41 self.raw_buf = raw_buf
42 self.ev_type = ev_type
43 PerfEvent.event_num += 1
44
45 def show(self):
46 print "PMU event: name=%12s, symbol=%24s, comm=%8s, dso=%12s" % (self.name, self.symbol, self.comm, self.dso)
47
48#
49# Basic Intel PEBS (Precise Event-based Sampling) event, whose raw buffer
50# contains the context info when that event happened: the EFLAGS and
51# linear IP info, as well as all the registers.
52#
53class PebsEvent(PerfEvent):
54 pebs_num = 0
55 def __init__(self, name, comm, dso, symbol, raw_buf, ev_type=EVTYPE_PEBS):
56 tmp_buf=raw_buf[0:80]
57 flags, ip, ax, bx, cx, dx, si, di, bp, sp = struct.unpack('QQQQQQQQQQ', tmp_buf)
58 self.flags = flags
59 self.ip = ip
60 self.ax = ax
61 self.bx = bx
62 self.cx = cx
63 self.dx = dx
64 self.si = si
65 self.di = di
66 self.bp = bp
67 self.sp = sp
68
69 PerfEvent.__init__(self, name, comm, dso, symbol, raw_buf, ev_type)
70 PebsEvent.pebs_num += 1
71 del tmp_buf
72
73#
74# Intel Nehalem and Westmere support PEBS plus Load Latency info which lie
75# in the four 64 bit words write after the PEBS data:
76# Status: records the IA32_PERF_GLOBAL_STATUS register value
77# DLA: Data Linear Address (EIP)
78# DSE: Data Source Encoding, where the latency happens, hit or miss
79# in L1/L2/L3 or IO operations
80# LAT: the actual latency in cycles
81#
82class PebsNHM(PebsEvent):
83 pebs_nhm_num = 0
84 def __init__(self, name, comm, dso, symbol, raw_buf, ev_type=EVTYPE_PEBS_LL):
85 tmp_buf=raw_buf[144:176]
86 status, dla, dse, lat = struct.unpack('QQQQ', tmp_buf)
87 self.status = status
88 self.dla = dla
89 self.dse = dse
90 self.lat = lat
91
92 PebsEvent.__init__(self, name, comm, dso, symbol, raw_buf, ev_type)
93 PebsNHM.pebs_nhm_num += 1
94 del tmp_buf
diff --git a/tools/perf/scripts/python/bin/event_analyzing_sample-record b/tools/perf/scripts/python/bin/event_analyzing_sample-record
deleted file mode 100644
index 5ce652dabd0..00000000000
--- a/tools/perf/scripts/python/bin/event_analyzing_sample-record
+++ /dev/null
@@ -1,8 +0,0 @@
1#!/bin/bash
2
3#
4# event_analyzing_sample.py can cover all type of perf samples including
5# the tracepoints, so no special record requirements, just record what
6# you want to analyze.
7#
8perf record $@
diff --git a/tools/perf/scripts/python/bin/event_analyzing_sample-report b/tools/perf/scripts/python/bin/event_analyzing_sample-report
deleted file mode 100644
index 0941fc94e15..00000000000
--- a/tools/perf/scripts/python/bin/event_analyzing_sample-report
+++ /dev/null
@@ -1,3 +0,0 @@
1#!/bin/bash
2# description: analyze all perf samples
3perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/event_analyzing_sample.py
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-record b/tools/perf/scripts/python/bin/net_dropmonitor-record
deleted file mode 100755
index 423fb81dada..00000000000
--- a/tools/perf/scripts/python/bin/net_dropmonitor-record
+++ /dev/null
@@ -1,2 +0,0 @@
1#!/bin/bash
2perf record -e skb:kfree_skb $@
diff --git a/tools/perf/scripts/python/bin/net_dropmonitor-report b/tools/perf/scripts/python/bin/net_dropmonitor-report
deleted file mode 100755
index 8d698f5a06a..00000000000
--- a/tools/perf/scripts/python/bin/net_dropmonitor-report
+++ /dev/null
@@ -1,4 +0,0 @@
1#!/bin/bash
2# description: display a table of dropped frames
3
4perf script -s "$PERF_EXEC_PATH"/scripts/python/net_dropmonitor.py $@
diff --git a/tools/perf/scripts/python/event_analyzing_sample.py b/tools/perf/scripts/python/event_analyzing_sample.py
deleted file mode 100644
index 163c39fa12d..00000000000
--- a/tools/perf/scripts/python/event_analyzing_sample.py
+++ /dev/null
@@ -1,189 +0,0 @@
1# event_analyzing_sample.py: general event handler in python
2#
3# Current perf report is already very powerful with the annotation integrated,
4# and this script is not trying to be as powerful as perf report, but
5# providing end user/developer a flexible way to analyze the events other
6# than trace points.
7#
8# The 2 database related functions in this script just show how to gather
9# the basic information, and users can modify and write their own functions
10# according to their specific requirement.
11#
12# The first function "show_general_events" just does a basic grouping for all
13# generic events with the help of sqlite, and the 2nd one "show_pebs_ll" is
14# for a x86 HW PMU event: PEBS with load latency data.
15#
16
17import os
18import sys
19import math
20import struct
21import sqlite3
22
23sys.path.append(os.environ['PERF_EXEC_PATH'] + \
24 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
25
26from perf_trace_context import *
27from EventClass import *
28
29#
30# If the perf.data has a big number of samples, then the insert operation
31# will be very time consuming (about 10+ minutes for 10000 samples) if the
32# .db database is on disk. Move the .db file to RAM based FS to speedup
33# the handling, which will cut the time down to several seconds.
34#
35con = sqlite3.connect("/dev/shm/perf.db")
36con.isolation_level = None
37
38def trace_begin():
39 print "In trace_begin:\n"
40
41 #
42 # Will create several tables at the start, pebs_ll is for PEBS data with
43 # load latency info, while gen_events is for general event.
44 #
45 con.execute("""
46 create table if not exists gen_events (
47 name text,
48 symbol text,
49 comm text,
50 dso text
51 );""")
52 con.execute("""
53 create table if not exists pebs_ll (
54 name text,
55 symbol text,
56 comm text,
57 dso text,
58 flags integer,
59 ip integer,
60 status integer,
61 dse integer,
62 dla integer,
63 lat integer
64 );""")
65
66#
67# Create and insert event object to a database so that user could
68# do more analysis with simple database commands.
69#
70def process_event(param_dict):
71 event_attr = param_dict["attr"]
72 sample = param_dict["sample"]
73 raw_buf = param_dict["raw_buf"]
74 comm = param_dict["comm"]
75 name = param_dict["ev_name"]
76
77 # Symbol and dso info are not always resolved
78 if (param_dict.has_key("dso")):
79 dso = param_dict["dso"]
80 else:
81 dso = "Unknown_dso"
82
83 if (param_dict.has_key("symbol")):
84 symbol = param_dict["symbol"]
85 else:
86 symbol = "Unknown_symbol"
87
88 # Create the event object and insert it to the right table in database
89 event = create_event(name, comm, dso, symbol, raw_buf)
90 insert_db(event)
91
92def insert_db(event):
93 if event.ev_type == EVTYPE_GENERIC:
94 con.execute("insert into gen_events values(?, ?, ?, ?)",
95 (event.name, event.symbol, event.comm, event.dso))
96 elif event.ev_type == EVTYPE_PEBS_LL:
97 event.ip &= 0x7fffffffffffffff
98 event.dla &= 0x7fffffffffffffff
99 con.execute("insert into pebs_ll values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
100 (event.name, event.symbol, event.comm, event.dso, event.flags,
101 event.ip, event.status, event.dse, event.dla, event.lat))
102
103def trace_end():
104 print "In trace_end:\n"
105 # We show the basic info for the 2 type of event classes
106 show_general_events()
107 show_pebs_ll()
108 con.close()
109
110#
111# As the event number may be very big, so we can't use linear way
112# to show the histogram in real number, but use a log2 algorithm.
113#
114
115def num2sym(num):
116 # Each number will have at least one '#'
117 snum = '#' * (int)(math.log(num, 2) + 1)
118 return snum
119
120def show_general_events():
121
122 # Check the total record number in the table
123 count = con.execute("select count(*) from gen_events")
124 for t in count:
125 print "There is %d records in gen_events table" % t[0]
126 if t[0] == 0:
127 return
128
129 print "Statistics about the general events grouped by thread/symbol/dso: \n"
130
131 # Group by thread
132 commq = con.execute("select comm, count(comm) from gen_events group by comm order by -count(comm)")
133 print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)
134 for row in commq:
135 print "%16s %8d %s" % (row[0], row[1], num2sym(row[1]))
136
137 # Group by symbol
138 print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)
139 symbolq = con.execute("select symbol, count(symbol) from gen_events group by symbol order by -count(symbol)")
140 for row in symbolq:
141 print "%32s %8d %s" % (row[0], row[1], num2sym(row[1]))
142
143 # Group by dso
144 print "\n%40s %8s %16s\n%s" % ("dso", "number", "histogram", "="*74)
145 dsoq = con.execute("select dso, count(dso) from gen_events group by dso order by -count(dso)")
146 for row in dsoq:
147 print "%40s %8d %s" % (row[0], row[1], num2sym(row[1]))
148
149#
150# This function just shows the basic info, and we could do more with the
151# data in the tables, like checking the function parameters when some
152# big latency events happen.
153#
154def show_pebs_ll():
155
156 count = con.execute("select count(*) from pebs_ll")
157 for t in count:
158 print "There is %d records in pebs_ll table" % t[0]
159 if t[0] == 0:
160 return
161
162 print "Statistics about the PEBS Load Latency events grouped by thread/symbol/dse/latency: \n"
163
164 # Group by thread
165 commq = con.execute("select comm, count(comm) from pebs_ll group by comm order by -count(comm)")
166 print "\n%16s %8s %16s\n%s" % ("comm", "number", "histogram", "="*42)
167 for row in commq:
168 print "%16s %8d %s" % (row[0], row[1], num2sym(row[1]))
169
170 # Group by symbol
171 print "\n%32s %8s %16s\n%s" % ("symbol", "number", "histogram", "="*58)
172 symbolq = con.execute("select symbol, count(symbol) from pebs_ll group by symbol order by -count(symbol)")
173 for row in symbolq:
174 print "%32s %8d %s" % (row[0], row[1], num2sym(row[1]))
175
176 # Group by dse
177 dseq = con.execute("select dse, count(dse) from pebs_ll group by dse order by -count(dse)")
178 print "\n%32s %8s %16s\n%s" % ("dse", "number", "histogram", "="*58)
179 for row in dseq:
180 print "%32s %8d %s" % (row[0], row[1], num2sym(row[1]))
181
182 # Group by latency
183 latq = con.execute("select lat, count(lat) from pebs_ll group by lat order by lat")
184 print "\n%32s %8s %16s\n%s" % ("latency", "number", "histogram", "="*58)
185 for row in latq:
186 print "%32s %8d %s" % (row[0], row[1], num2sym(row[1]))
187
188def trace_unhandled(event_name, context, event_fields_dict):
189 print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
diff --git a/tools/perf/scripts/python/net_dropmonitor.py b/tools/perf/scripts/python/net_dropmonitor.py
deleted file mode 100755
index a4ffc950002..00000000000
--- a/tools/perf/scripts/python/net_dropmonitor.py
+++ /dev/null
@@ -1,72 +0,0 @@
1# Monitor the system for dropped packets and proudce a report of drop locations and counts
2
3import os
4import sys
5
6sys.path.append(os.environ['PERF_EXEC_PATH'] + \
7 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
8
9from perf_trace_context import *
10from Core import *
11from Util import *
12
13drop_log = {}
14kallsyms = []
15
16def get_kallsyms_table():
17 global kallsyms
18 try:
19 f = open("/proc/kallsyms", "r")
20 linecount = 0
21 for line in f:
22 linecount = linecount+1
23 f.seek(0)
24 except:
25 return
26
27
28 j = 0
29 for line in f:
30 loc = int(line.split()[0], 16)
31 name = line.split()[2]
32 j = j +1
33 if ((j % 100) == 0):
34 print "\r" + str(j) + "/" + str(linecount),
35 kallsyms.append({ 'loc': loc, 'name' : name})
36
37 print "\r" + str(j) + "/" + str(linecount)
38 kallsyms.sort()
39 return
40
41def get_sym(sloc):
42 loc = int(sloc)
43 for i in kallsyms:
44 if (i['loc'] >= loc):
45 return (i['name'], i['loc']-loc)
46 return (None, 0)
47
48def print_drop_table():
49 print "%25s %25s %25s" % ("LOCATION", "OFFSET", "COUNT")
50 for i in drop_log.keys():
51 (sym, off) = get_sym(i)
52 if sym == None:
53 sym = i
54 print "%25s %25s %25s" % (sym, off, drop_log[i])
55
56
57def trace_begin():
58 print "Starting trace (Ctrl-C to dump results)"
59
60def trace_end():
61 print "Gathering kallsyms data"
62 get_kallsyms_table()
63 print_drop_table()
64
65# called from perf, when it finds a correspoinding event
66def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
67 skbaddr, protocol, location):
68 slocation = str(location)
69 try:
70 drop_log[slocation] = drop_log[slocation] + 1
71 except:
72 drop_log[slocation] = 1
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
deleted file mode 100644
index 25638a98625..00000000000
--- a/tools/perf/tests/attr.c
+++ /dev/null
@@ -1,175 +0,0 @@
1
2/*
3 * The struct perf_event_attr test support.
4 *
5 * This test is embedded inside into perf directly and is governed
6 * by the PERF_TEST_ATTR environment variable and hook inside
7 * sys_perf_event_open function.
8 *
9 * The general idea is to store 'struct perf_event_attr' details for
10 * each event created within single perf command. Each event details
11 * are stored into separate text file. Once perf command is finished
12 * these files can be checked for values we expect for command.
13 *
14 * Besides 'struct perf_event_attr' values we also store 'fd' and
15 * 'group_fd' values to allow checking for groups created.
16 *
17 * This all is triggered by setting PERF_TEST_ATTR environment variable.
18 * It must contain name of existing directory with access and write
19 * permissions. All the event text files are stored there.
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <inttypes.h>
25#include <linux/types.h>
26#include <linux/kernel.h>
27#include "../perf.h"
28#include "util.h"
29#include "exec_cmd.h"
30#include "tests.h"
31
32#define ENV "PERF_TEST_ATTR"
33
34extern int verbose;
35
36bool test_attr__enabled;
37
38static char *dir;
39
40void test_attr__init(void)
41{
42 dir = getenv(ENV);
43 test_attr__enabled = (dir != NULL);
44}
45
46#define BUFSIZE 1024
47
48#define __WRITE_ASS(str, fmt, data) \
49do { \
50 char buf[BUFSIZE]; \
51 size_t size; \
52 \
53 size = snprintf(buf, BUFSIZE, #str "=%"fmt "\n", data); \
54 if (1 != fwrite(buf, size, 1, file)) { \
55 perror("test attr - failed to write event file"); \
56 fclose(file); \
57 return -1; \
58 } \
59 \
60} while (0)
61
62#define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field)
63
64static int store_event(struct perf_event_attr *attr, pid_t pid, int cpu,
65 int fd, int group_fd, unsigned long flags)
66{
67 FILE *file;
68 char path[PATH_MAX];
69
70 snprintf(path, PATH_MAX, "%s/event-%d-%llu-%d", dir,
71 attr->type, attr->config, fd);
72
73 file = fopen(path, "w+");
74 if (!file) {
75 perror("test attr - failed to open event file");
76 return -1;
77 }
78
79 if (fprintf(file, "[event-%d-%llu-%d]\n",
80 attr->type, attr->config, fd) < 0) {
81 perror("test attr - failed to write event file");
82 fclose(file);
83 return -1;
84 }
85
86 /* syscall arguments */
87 __WRITE_ASS(fd, "d", fd);
88 __WRITE_ASS(group_fd, "d", group_fd);
89 __WRITE_ASS(cpu, "d", cpu);
90 __WRITE_ASS(pid, "d", pid);
91 __WRITE_ASS(flags, "lu", flags);
92
93 /* struct perf_event_attr */
94 WRITE_ASS(type, PRIu32);
95 WRITE_ASS(size, PRIu32);
96 WRITE_ASS(config, "llu");
97 WRITE_ASS(sample_period, "llu");
98 WRITE_ASS(sample_type, "llu");
99 WRITE_ASS(read_format, "llu");
100 WRITE_ASS(disabled, "d");
101 WRITE_ASS(inherit, "d");
102 WRITE_ASS(pinned, "d");
103 WRITE_ASS(exclusive, "d");
104 WRITE_ASS(exclude_user, "d");
105 WRITE_ASS(exclude_kernel, "d");
106 WRITE_ASS(exclude_hv, "d");
107 WRITE_ASS(exclude_idle, "d");
108 WRITE_ASS(mmap, "d");
109 WRITE_ASS(comm, "d");
110 WRITE_ASS(freq, "d");
111 WRITE_ASS(inherit_stat, "d");
112 WRITE_ASS(enable_on_exec, "d");
113 WRITE_ASS(task, "d");
114 WRITE_ASS(watermark, "d");
115 WRITE_ASS(precise_ip, "d");
116 WRITE_ASS(mmap_data, "d");
117 WRITE_ASS(sample_id_all, "d");
118 WRITE_ASS(exclude_host, "d");
119 WRITE_ASS(exclude_guest, "d");
120 WRITE_ASS(exclude_callchain_kernel, "d");
121 WRITE_ASS(exclude_callchain_user, "d");
122 WRITE_ASS(wakeup_events, PRIu32);
123 WRITE_ASS(bp_type, PRIu32);
124 WRITE_ASS(config1, "llu");
125 WRITE_ASS(config2, "llu");
126 WRITE_ASS(branch_sample_type, "llu");
127 WRITE_ASS(sample_regs_user, "llu");
128 WRITE_ASS(sample_stack_user, PRIu32);
129
130 fclose(file);
131 return 0;
132}
133
134void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
135 int fd, int group_fd, unsigned long flags)
136{
137 int errno_saved = errno;
138
139 if (store_event(attr, pid, cpu, fd, group_fd, flags))
140 die("test attr FAILED");
141
142 errno = errno_saved;
143}
144
145static int run_dir(const char *d, const char *perf)
146{
147 char cmd[3*PATH_MAX];
148
149 snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s",
150 d, d, perf, verbose ? "-v" : "");
151
152 return system(cmd);
153}
154
155int test__attr(void)
156{
157 struct stat st;
158 char path_perf[PATH_MAX];
159 char path_dir[PATH_MAX];
160
161 /* First try developement tree tests. */
162 if (!lstat("./tests", &st))
163 return run_dir("./tests", "./perf");
164
165 /* Then installed path. */
166 snprintf(path_dir, PATH_MAX, "%s/tests", perf_exec_path());
167 snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
168
169 if (!lstat(path_dir, &st) &&
170 !lstat(path_perf, &st))
171 return run_dir(path_dir, path_perf);
172
173 fprintf(stderr, " (ommitted)");
174 return 0;
175}
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
deleted file mode 100644
index e702b82dcb8..00000000000
--- a/tools/perf/tests/attr.py
+++ /dev/null
@@ -1,322 +0,0 @@
1#! /usr/bin/python
2
3import os
4import sys
5import glob
6import optparse
7import tempfile
8import logging
9import shutil
10import ConfigParser
11
12class Fail(Exception):
13 def __init__(self, test, msg):
14 self.msg = msg
15 self.test = test
16 def getMsg(self):
17 return '\'%s\' - %s' % (self.test.path, self.msg)
18
19class Unsup(Exception):
20 def __init__(self, test):
21 self.test = test
22 def getMsg(self):
23 return '\'%s\'' % self.test.path
24
25class Event(dict):
26 terms = [
27 'flags',
28 'type',
29 'size',
30 'config',
31 'sample_period',
32 'sample_type',
33 'read_format',
34 'disabled',
35 'inherit',
36 'pinned',
37 'exclusive',
38 'exclude_user',
39 'exclude_kernel',
40 'exclude_hv',
41 'exclude_idle',
42 'mmap',
43 'comm',
44 'freq',
45 'inherit_stat',
46 'enable_on_exec',
47 'task',
48 'watermark',
49 'precise_ip',
50 'mmap_data',
51 'sample_id_all',
52 'exclude_host',
53 'exclude_guest',
54 'exclude_callchain_kernel',
55 'exclude_callchain_user',
56 'wakeup_events',
57 'bp_type',
58 'config1',
59 'config2',
60 'branch_sample_type',
61 'sample_regs_user',
62 'sample_stack_user',
63 ]
64
65 def add(self, data):
66 for key, val in data:
67 log.debug(" %s = %s" % (key, val))
68 self[key] = val
69
70 def __init__(self, name, data, base):
71 log.info(" Event %s" % name);
72 self.name = name;
73 self.group = ''
74 self.add(base)
75 self.add(data)
76
77 def compare_data(self, a, b):
78 # Allow multiple values in assignment separated by '|'
79 a_list = a.split('|')
80 b_list = b.split('|')
81
82 for a_item in a_list:
83 for b_item in b_list:
84 if (a_item == b_item):
85 return True
86 elif (a_item == '*') or (b_item == '*'):
87 return True
88
89 return False
90
91 def equal(self, other):
92 for t in Event.terms:
93 log.debug(" [%s] %s %s" % (t, self[t], other[t]));
94 if not self.has_key(t) or not other.has_key(t):
95 return False
96 if not self.compare_data(self[t], other[t]):
97 return False
98 return True
99
100# Test file description needs to have following sections:
101# [config]
102# - just single instance in file
103# - needs to specify:
104# 'command' - perf command name
105# 'args' - special command arguments
106# 'ret' - expected command return value (0 by default)
107#
108# [eventX:base]
109# - one or multiple instances in file
110# - expected values assignments
111class Test(object):
112 def __init__(self, path, options):
113 parser = ConfigParser.SafeConfigParser()
114 parser.read(path)
115
116 log.warning("running '%s'" % path)
117
118 self.path = path
119 self.test_dir = options.test_dir
120 self.perf = options.perf
121 self.command = parser.get('config', 'command')
122 self.args = parser.get('config', 'args')
123
124 try:
125 self.ret = parser.get('config', 'ret')
126 except:
127 self.ret = 0
128
129 self.expect = {}
130 self.result = {}
131 log.info(" loading expected events");
132 self.load_events(path, self.expect)
133
134 def is_event(self, name):
135 if name.find("event") == -1:
136 return False
137 else:
138 return True
139
140 def load_events(self, path, events):
141 parser_event = ConfigParser.SafeConfigParser()
142 parser_event.read(path)
143
144 # The event record section header contains 'event' word,
145 # optionaly followed by ':' allowing to load 'parent
146 # event' first as a base
147 for section in filter(self.is_event, parser_event.sections()):
148
149 parser_items = parser_event.items(section);
150 base_items = {}
151
152 # Read parent event if there's any
153 if (':' in section):
154 base = section[section.index(':') + 1:]
155 parser_base = ConfigParser.SafeConfigParser()
156 parser_base.read(self.test_dir + '/' + base)
157 base_items = parser_base.items('event')
158
159 e = Event(section, parser_items, base_items)
160 events[section] = e
161
162 def run_cmd(self, tempdir):
163 cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir,
164 self.perf, self.command, tempdir, self.args)
165 ret = os.WEXITSTATUS(os.system(cmd))
166
167 log.info(" running '%s' ret %d " % (cmd, ret))
168
169 if ret != int(self.ret):
170 raise Unsup(self)
171
172 def compare(self, expect, result):
173 match = {}
174
175 log.info(" compare");
176
177 # For each expected event find all matching
178 # events in result. Fail if there's not any.
179 for exp_name, exp_event in expect.items():
180 exp_list = []
181 log.debug(" matching [%s]" % exp_name)
182 for res_name, res_event in result.items():
183 log.debug(" to [%s]" % res_name)
184 if (exp_event.equal(res_event)):
185 exp_list.append(res_name)
186 log.debug(" ->OK")
187 else:
188 log.debug(" ->FAIL");
189
190 log.info(" match: [%s] matches %s" % (exp_name, str(exp_list)))
191
192 # we did not any matching event - fail
193 if (not exp_list):
194 raise Fail(self, 'match failure');
195
196 match[exp_name] = exp_list
197
198 # For each defined group in the expected events
199 # check we match the same group in the result.
200 for exp_name, exp_event in expect.items():
201 group = exp_event.group
202
203 if (group == ''):
204 continue
205
206 for res_name in match[exp_name]:
207 res_group = result[res_name].group
208 if res_group not in match[group]:
209 raise Fail(self, 'group failure')
210
211 log.info(" group: [%s] matches group leader %s" %
212 (exp_name, str(match[group])))
213
214 log.info(" matched")
215
216 def resolve_groups(self, events):
217 for name, event in events.items():
218 group_fd = event['group_fd'];
219 if group_fd == '-1':
220 continue;
221
222 for iname, ievent in events.items():
223 if (ievent['fd'] == group_fd):
224 event.group = iname
225 log.debug('[%s] has group leader [%s]' % (name, iname))
226 break;
227
228 def run(self):
229 tempdir = tempfile.mkdtemp();
230
231 try:
232 # run the test script
233 self.run_cmd(tempdir);
234
235 # load events expectation for the test
236 log.info(" loading result events");
237 for f in glob.glob(tempdir + '/event*'):
238 self.load_events(f, self.result);
239
240 # resolve group_fd to event names
241 self.resolve_groups(self.expect);
242 self.resolve_groups(self.result);
243
244 # do the expectation - results matching - both ways
245 self.compare(self.expect, self.result)
246 self.compare(self.result, self.expect)
247
248 finally:
249 # cleanup
250 shutil.rmtree(tempdir)
251
252
253def run_tests(options):
254 for f in glob.glob(options.test_dir + '/' + options.test):
255 try:
256 Test(f, options).run()
257 except Unsup, obj:
258 log.warning("unsupp %s" % obj.getMsg())
259
260def setup_log(verbose):
261 global log
262 level = logging.CRITICAL
263
264 if verbose == 1:
265 level = logging.WARNING
266 if verbose == 2:
267 level = logging.INFO
268 if verbose >= 3:
269 level = logging.DEBUG
270
271 log = logging.getLogger('test')
272 log.setLevel(level)
273 ch = logging.StreamHandler()
274 ch.setLevel(level)
275 formatter = logging.Formatter('%(message)s')
276 ch.setFormatter(formatter)
277 log.addHandler(ch)
278
279USAGE = '''%s [OPTIONS]
280 -d dir # tests dir
281 -p path # perf binary
282 -t test # single test
283 -v # verbose level
284''' % sys.argv[0]
285
286def main():
287 parser = optparse.OptionParser(usage=USAGE)
288
289 parser.add_option("-t", "--test",
290 action="store", type="string", dest="test")
291 parser.add_option("-d", "--test-dir",
292 action="store", type="string", dest="test_dir")
293 parser.add_option("-p", "--perf",
294 action="store", type="string", dest="perf")
295 parser.add_option("-v", "--verbose",
296 action="count", dest="verbose")
297
298 options, args = parser.parse_args()
299 if args:
300 parser.error('FAILED wrong arguments %s' % ' '.join(args))
301 return -1
302
303 setup_log(options.verbose)
304
305 if not options.test_dir:
306 print 'FAILED no -d option specified'
307 sys.exit(-1)
308
309 if not options.test:
310 options.test = 'test*'
311
312 try:
313 run_tests(options)
314
315 except Fail, obj:
316 print "FAILED %s" % obj.getMsg();
317 sys.exit(-1)
318
319 sys.exit(0)
320
321if __name__ == '__main__':
322 main()
diff --git a/tools/perf/tests/attr/README b/tools/perf/tests/attr/README
deleted file mode 100644
index d102957cd59..00000000000
--- a/tools/perf/tests/attr/README
+++ /dev/null
@@ -1,64 +0,0 @@
1The struct perf_event_attr test (attr tests) support
2====================================================
3This testing support is embedded into perf directly and is governed
4by the PERF_TEST_ATTR environment variable and hook inside the
5sys_perf_event_open function.
6
7The general idea is to store 'struct perf_event_attr' details for
8each event created within single perf command. Each event details
9are stored into separate text file. Once perf command is finished
10these files are checked for values we expect for command.
11
12The attr tests consist of following parts:
13
14tests/attr.c
15------------
16This is the sys_perf_event_open hook implementation. The hook
17is triggered when the PERF_TEST_ATTR environment variable is
18defined. It must contain name of existing directory with access
19and write permissions.
20
21For each sys_perf_event_open call event details are stored in
22separate file. Besides 'struct perf_event_attr' values we also
23store 'fd' and 'group_fd' values to allow checking for groups.
24
25tests/attr.py
26-------------
27This is the python script that does all the hard work. It reads
28the test definition, executes it and checks results.
29
30tests/attr/
31-----------
32Directory containing all attr test definitions.
33Following tests are defined (with perf commands):
34
35 perf record kill (test-record-basic)
36 perf record -b kill (test-record-branch-any)
37 perf record -j any kill (test-record-branch-filter-any)
38 perf record -j any_call kill (test-record-branch-filter-any_call)
39 perf record -j any_ret kill (test-record-branch-filter-any_ret)
40 perf record -j hv kill (test-record-branch-filter-hv)
41 perf record -j ind_call kill (test-record-branch-filter-ind_call)
42 perf record -j k kill (test-record-branch-filter-k)
43 perf record -j u kill (test-record-branch-filter-u)
44 perf record -c 123 kill (test-record-count)
45 perf record -d kill (test-record-data)
46 perf record -F 100 kill (test-record-freq)
47 perf record -g -- kill (test-record-graph-default)
48 perf record -g dwarf -- kill (test-record-graph-dwarf)
49 perf record -g fp kill (test-record-graph-fp)
50 perf record --group -e cycles,instructions kill (test-record-group)
51 perf record -e '{cycles,instructions}' kill (test-record-group1)
52 perf record -D kill (test-record-no-delay)
53 perf record -i kill (test-record-no-inherit)
54 perf record -n kill (test-record-no-samples)
55 perf record -c 100 -P kill (test-record-period)
56 perf record -R kill (test-record-raw)
57 perf stat -e cycles kill (test-stat-basic)
58 perf stat kill (test-stat-default)
59 perf stat -d kill (test-stat-detailed-1)
60 perf stat -dd kill (test-stat-detailed-2)
61 perf stat -ddd kill (test-stat-detailed-3)
62 perf stat --group -e cycles,instructions kill (test-stat-group)
63 perf stat -e '{cycles,instructions}' kill (test-stat-group1)
64 perf stat -i -e cycles kill (test-stat-no-inherit)
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
deleted file mode 100644
index f1485d8e6a0..00000000000
--- a/tools/perf/tests/attr/base-record
+++ /dev/null
@@ -1,39 +0,0 @@
1[event]
2fd=1
3group_fd=-1
4flags=0
5type=0|1
6size=96
7config=0
8sample_period=4000
9sample_type=263
10read_format=7
11disabled=1
12inherit=1
13pinned=0
14exclusive=0
15exclude_user=0
16exclude_kernel=0
17exclude_hv=0
18exclude_idle=0
19mmap=1
20comm=1
21freq=1
22inherit_stat=0
23enable_on_exec=1
24task=0
25watermark=0
26precise_ip=0
27mmap_data=0
28sample_id_all=1
29exclude_host=0
30exclude_guest=1
31exclude_callchain_kernel=0
32exclude_callchain_user=0
33wakeup_events=0
34bp_type=0
35config1=0
36config2=0
37branch_sample_type=0
38sample_regs_user=0
39sample_stack_user=0
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
deleted file mode 100644
index 4bd79a82784..00000000000
--- a/tools/perf/tests/attr/base-stat
+++ /dev/null
@@ -1,39 +0,0 @@
1[event]
2fd=1
3group_fd=-1
4flags=0
5type=0
6size=96
7config=0
8sample_period=0
9sample_type=0
10read_format=3
11disabled=1
12inherit=1
13pinned=0
14exclusive=0
15exclude_user=0
16exclude_kernel=0
17exclude_hv=0
18exclude_idle=0
19mmap=0
20comm=0
21freq=0
22inherit_stat=0
23enable_on_exec=1
24task=0
25watermark=0
26precise_ip=0
27mmap_data=0
28sample_id_all=0
29exclude_host=0
30exclude_guest=1
31exclude_callchain_kernel=0
32exclude_callchain_user=0
33wakeup_events=0
34bp_type=0
35config1=0
36config2=0
37branch_sample_type=0
38sample_regs_user=0
39sample_stack_user=0
diff --git a/tools/perf/tests/attr/test-record-basic b/tools/perf/tests/attr/test-record-basic
deleted file mode 100644
index 55c0428370c..00000000000
--- a/tools/perf/tests/attr/test-record-basic
+++ /dev/null
@@ -1,5 +0,0 @@
1[config]
2command = record
3args = kill >/dev/null 2>&1
4
5[event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-any b/tools/perf/tests/attr/test-record-branch-any
deleted file mode 100644
index 1421960ed4e..00000000000
--- a/tools/perf/tests/attr/test-record-branch-any
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -b kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any b/tools/perf/tests/attr/test-record-branch-filter-any
deleted file mode 100644
index 915c4df0e0c..00000000000
--- a/tools/perf/tests/attr/test-record-branch-filter-any
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -j any kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_call b/tools/perf/tests/attr/test-record-branch-filter-any_call
deleted file mode 100644
index 8708dbd4f37..00000000000
--- a/tools/perf/tests/attr/test-record-branch-filter-any_call
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -j any_call kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=16
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_ret b/tools/perf/tests/attr/test-record-branch-filter-any_ret
deleted file mode 100644
index 0d3607a6dcb..00000000000
--- a/tools/perf/tests/attr/test-record-branch-filter-any_ret
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -j any_ret kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=32
diff --git a/tools/perf/tests/attr/test-record-branch-filter-hv b/tools/perf/tests/attr/test-record-branch-filter-hv
deleted file mode 100644
index f25526740ce..00000000000
--- a/tools/perf/tests/attr/test-record-branch-filter-hv
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -j hv kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-ind_call b/tools/perf/tests/attr/test-record-branch-filter-ind_call
deleted file mode 100644
index e862dd17912..00000000000
--- a/tools/perf/tests/attr/test-record-branch-filter-ind_call
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -j ind_call kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=64
diff --git a/tools/perf/tests/attr/test-record-branch-filter-k b/tools/perf/tests/attr/test-record-branch-filter-k
deleted file mode 100644
index 182971e898f..00000000000
--- a/tools/perf/tests/attr/test-record-branch-filter-k
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -j k kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-u b/tools/perf/tests/attr/test-record-branch-filter-u
deleted file mode 100644
index 83449ef9e68..00000000000
--- a/tools/perf/tests/attr/test-record-branch-filter-u
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -j u kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-count b/tools/perf/tests/attr/test-record-count
deleted file mode 100644
index 2f841de56f6..00000000000
--- a/tools/perf/tests/attr/test-record-count
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -c 123 kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=123
7sample_type=7
8freq=0
diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/attr/test-record-data
deleted file mode 100644
index 6627c3e7534..00000000000
--- a/tools/perf/tests/attr/test-record-data
+++ /dev/null
@@ -1,8 +0,0 @@
1[config]
2command = record
3args = -d kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=271
8mmap_data=1
diff --git a/tools/perf/tests/attr/test-record-freq b/tools/perf/tests/attr/test-record-freq
deleted file mode 100644
index 600d0f8f258..00000000000
--- a/tools/perf/tests/attr/test-record-freq
+++ /dev/null
@@ -1,6 +0,0 @@
1[config]
2command = record
3args = -F 100 kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=100
diff --git a/tools/perf/tests/attr/test-record-graph-default b/tools/perf/tests/attr/test-record-graph-default
deleted file mode 100644
index 833d1849d76..00000000000
--- a/tools/perf/tests/attr/test-record-graph-default
+++ /dev/null
@@ -1,6 +0,0 @@
1[config]
2command = record
3args = -g -- kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=295
diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/attr/test-record-graph-dwarf
deleted file mode 100644
index e93e082f520..00000000000
--- a/tools/perf/tests/attr/test-record-graph-dwarf
+++ /dev/null
@@ -1,10 +0,0 @@
1[config]
2command = record
3args = -g dwarf -- kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=12583
7exclude_callchain_user=1
8sample_stack_user=8192
9# TODO different for each arch, no support for that now
10sample_regs_user=*
diff --git a/tools/perf/tests/attr/test-record-graph-fp b/tools/perf/tests/attr/test-record-graph-fp
deleted file mode 100644
index 7cef3743f03..00000000000
--- a/tools/perf/tests/attr/test-record-graph-fp
+++ /dev/null
@@ -1,6 +0,0 @@
1[config]
2command = record
3args = -g fp kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=295
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group
deleted file mode 100644
index a6599e9a19d..00000000000
--- a/tools/perf/tests/attr/test-record-group
+++ /dev/null
@@ -1,18 +0,0 @@
1[config]
2command = record
3args = --group -e cycles,instructions kill >/dev/null 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=327
9
10[event-2:base-record]
11fd=2
12group_fd=1
13config=1
14sample_type=327
15mmap=0
16comm=0
17enable_on_exec=0
18disabled=0
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
deleted file mode 100644
index 5a8359da38a..00000000000
--- a/tools/perf/tests/attr/test-record-group1
+++ /dev/null
@@ -1,19 +0,0 @@
1[config]
2command = record
3args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=327
9
10[event-2:base-record]
11fd=2
12group_fd=1
13type=0
14config=1
15sample_type=327
16mmap=0
17comm=0
18enable_on_exec=0
19disabled=0
diff --git a/tools/perf/tests/attr/test-record-no-delay b/tools/perf/tests/attr/test-record-no-delay
deleted file mode 100644
index f253b78cdbf..00000000000
--- a/tools/perf/tests/attr/test-record-no-delay
+++ /dev/null
@@ -1,9 +0,0 @@
1[config]
2command = record
3args = -D kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=263
8watermark=0
9wakeup_events=1
diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit
deleted file mode 100644
index 9079a25cd64..00000000000
--- a/tools/perf/tests/attr/test-record-no-inherit
+++ /dev/null
@@ -1,7 +0,0 @@
1[config]
2command = record
3args = -i kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=259
7inherit=0
diff --git a/tools/perf/tests/attr/test-record-no-samples b/tools/perf/tests/attr/test-record-no-samples
deleted file mode 100644
index d0141b2418b..00000000000
--- a/tools/perf/tests/attr/test-record-no-samples
+++ /dev/null
@@ -1,6 +0,0 @@
1[config]
2command = record
3args = -n kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=0
diff --git a/tools/perf/tests/attr/test-record-period b/tools/perf/tests/attr/test-record-period
deleted file mode 100644
index 8abc5314fc5..00000000000
--- a/tools/perf/tests/attr/test-record-period
+++ /dev/null
@@ -1,7 +0,0 @@
1[config]
2command = record
3args = -c 100 -P kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=100
7freq=0
diff --git a/tools/perf/tests/attr/test-record-raw b/tools/perf/tests/attr/test-record-raw
deleted file mode 100644
index 4a8ef25b5f4..00000000000
--- a/tools/perf/tests/attr/test-record-raw
+++ /dev/null
@@ -1,7 +0,0 @@
1[config]
2command = record
3args = -R kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=1415
diff --git a/tools/perf/tests/attr/test-stat-basic b/tools/perf/tests/attr/test-stat-basic
deleted file mode 100644
index 74e17881f2b..00000000000
--- a/tools/perf/tests/attr/test-stat-basic
+++ /dev/null
@@ -1,6 +0,0 @@
1[config]
2command = stat
3args = -e cycles kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
diff --git a/tools/perf/tests/attr/test-stat-default b/tools/perf/tests/attr/test-stat-default
deleted file mode 100644
index 19270f54c96..00000000000
--- a/tools/perf/tests/attr/test-stat-default
+++ /dev/null
@@ -1,64 +0,0 @@
1[config]
2command = stat
3args = kill >/dev/null 2>&1
4ret = 1
5
6# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
7[event1:base-stat]
8fd=1
9type=1
10config=1
11
12# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
13[event2:base-stat]
14fd=2
15type=1
16config=3
17
18# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
19[event3:base-stat]
20fd=3
21type=1
22config=4
23
24# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
25[event4:base-stat]
26fd=4
27type=1
28config=2
29
30# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
31[event5:base-stat]
32fd=5
33type=0
34config=0
35
36# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
37[event6:base-stat]
38fd=6
39type=0
40config=7
41
42# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
43[event7:base-stat]
44fd=7
45type=0
46config=8
47
48# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
49[event8:base-stat]
50fd=8
51type=0
52config=1
53
54# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
55[event9:base-stat]
56fd=9
57type=0
58config=4
59
60# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
61[event10:base-stat]
62fd=10
63type=0
64config=5
diff --git a/tools/perf/tests/attr/test-stat-detailed-1 b/tools/perf/tests/attr/test-stat-detailed-1
deleted file mode 100644
index 51426b87153..00000000000
--- a/tools/perf/tests/attr/test-stat-detailed-1
+++ /dev/null
@@ -1,101 +0,0 @@
1[config]
2command = stat
3args = -d kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
diff --git a/tools/perf/tests/attr/test-stat-detailed-2 b/tools/perf/tests/attr/test-stat-detailed-2
deleted file mode 100644
index 8de5acc31c2..00000000000
--- a/tools/perf/tests/attr/test-stat-detailed-2
+++ /dev/null
@@ -1,155 +0,0 @@
1[config]
2command = stat
3args = -dd kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
102
103# PERF_TYPE_HW_CACHE,
104# PERF_COUNT_HW_CACHE_L1I << 0 |
105# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
106# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
107[event15:base-stat]
108fd=15
109type=3
110config=1
111
112# PERF_TYPE_HW_CACHE,
113# PERF_COUNT_HW_CACHE_L1I << 0 |
114# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
115# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
116[event16:base-stat]
117fd=16
118type=3
119config=65537
120
121# PERF_TYPE_HW_CACHE,
122# PERF_COUNT_HW_CACHE_DTLB << 0 |
123# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
124# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
125[event17:base-stat]
126fd=17
127type=3
128config=3
129
130# PERF_TYPE_HW_CACHE,
131# PERF_COUNT_HW_CACHE_DTLB << 0 |
132# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
133# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
134[event18:base-stat]
135fd=18
136type=3
137config=65539
138
139# PERF_TYPE_HW_CACHE,
140# PERF_COUNT_HW_CACHE_ITLB << 0 |
141# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
142# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
143[event19:base-stat]
144fd=19
145type=3
146config=4
147
148# PERF_TYPE_HW_CACHE,
149# PERF_COUNT_HW_CACHE_ITLB << 0 |
150# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
151# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
152[event20:base-stat]
153fd=20
154type=3
155config=65540
diff --git a/tools/perf/tests/attr/test-stat-detailed-3 b/tools/perf/tests/attr/test-stat-detailed-3
deleted file mode 100644
index 0a1f45bf7d7..00000000000
--- a/tools/perf/tests/attr/test-stat-detailed-3
+++ /dev/null
@@ -1,173 +0,0 @@
1[config]
2command = stat
3args = -ddd kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
102
103# PERF_TYPE_HW_CACHE,
104# PERF_COUNT_HW_CACHE_L1I << 0 |
105# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
106# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
107[event15:base-stat]
108fd=15
109type=3
110config=1
111
112# PERF_TYPE_HW_CACHE,
113# PERF_COUNT_HW_CACHE_L1I << 0 |
114# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
115# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
116[event16:base-stat]
117fd=16
118type=3
119config=65537
120
121# PERF_TYPE_HW_CACHE,
122# PERF_COUNT_HW_CACHE_DTLB << 0 |
123# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
124# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
125[event17:base-stat]
126fd=17
127type=3
128config=3
129
130# PERF_TYPE_HW_CACHE,
131# PERF_COUNT_HW_CACHE_DTLB << 0 |
132# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
133# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
134[event18:base-stat]
135fd=18
136type=3
137config=65539
138
139# PERF_TYPE_HW_CACHE,
140# PERF_COUNT_HW_CACHE_ITLB << 0 |
141# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
142# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
143[event19:base-stat]
144fd=19
145type=3
146config=4
147
148# PERF_TYPE_HW_CACHE,
149# PERF_COUNT_HW_CACHE_ITLB << 0 |
150# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
151# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
152[event20:base-stat]
153fd=20
154type=3
155config=65540
156
157# PERF_TYPE_HW_CACHE,
158# PERF_COUNT_HW_CACHE_L1D << 0 |
159# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
160# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
161[event21:base-stat]
162fd=21
163type=3
164config=512
165
166# PERF_TYPE_HW_CACHE,
167# PERF_COUNT_HW_CACHE_L1D << 0 |
168# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
169# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
170[event22:base-stat]
171fd=22
172type=3
173config=66048
diff --git a/tools/perf/tests/attr/test-stat-group b/tools/perf/tests/attr/test-stat-group
deleted file mode 100644
index fdc1596a886..00000000000
--- a/tools/perf/tests/attr/test-stat-group
+++ /dev/null
@@ -1,15 +0,0 @@
1[config]
2command = stat
3args = --group -e cycles,instructions kill >/dev/null 2>&1
4ret = 1
5
6[event-1:base-stat]
7fd=1
8group_fd=-1
9
10[event-2:base-stat]
11fd=2
12group_fd=1
13config=1
14disabled=0
15enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-stat-group1 b/tools/perf/tests/attr/test-stat-group1
deleted file mode 100644
index 2a1f86e4a90..00000000000
--- a/tools/perf/tests/attr/test-stat-group1
+++ /dev/null
@@ -1,15 +0,0 @@
1[config]
2command = stat
3args = -e '{cycles,instructions}' kill >/dev/null 2>&1
4ret = 1
5
6[event-1:base-stat]
7fd=1
8group_fd=-1
9
10[event-2:base-stat]
11fd=2
12group_fd=1
13config=1
14disabled=0
15enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-stat-no-inherit b/tools/perf/tests/attr/test-stat-no-inherit
deleted file mode 100644
index d54b2a1e3e2..00000000000
--- a/tools/perf/tests/attr/test-stat-no-inherit
+++ /dev/null
@@ -1,7 +0,0 @@
1[config]
2command = stat
3args = -i -e cycles kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
7inherit=0
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
deleted file mode 100644
index 186f6753549..00000000000
--- a/tools/perf/tests/builtin-test.c
+++ /dev/null
@@ -1,173 +0,0 @@
1/*
2 * builtin-test.c
3 *
4 * Builtin regression testing command: ever growing number of sanity tests
5 */
6#include "builtin.h"
7#include "tests.h"
8#include "debug.h"
9#include "color.h"
10#include "parse-options.h"
11#include "symbol.h"
12
13static struct test {
14 const char *desc;
15 int (*func)(void);
16} tests[] = {
17 {
18 .desc = "vmlinux symtab matches kallsyms",
19 .func = test__vmlinux_matches_kallsyms,
20 },
21 {
22 .desc = "detect open syscall event",
23 .func = test__open_syscall_event,
24 },
25 {
26 .desc = "detect open syscall event on all cpus",
27 .func = test__open_syscall_event_on_all_cpus,
28 },
29 {
30 .desc = "read samples using the mmap interface",
31 .func = test__basic_mmap,
32 },
33 {
34 .desc = "parse events tests",
35 .func = test__parse_events,
36 },
37#if defined(__x86_64__) || defined(__i386__)
38 {
39 .desc = "x86 rdpmc test",
40 .func = test__rdpmc,
41 },
42#endif
43 {
44 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
45 .func = test__PERF_RECORD,
46 },
47 {
48 .desc = "Test perf pmu format parsing",
49 .func = test__pmu,
50 },
51 {
52 .desc = "Test dso data interface",
53 .func = test__dso_data,
54 },
55 {
56 .desc = "roundtrip evsel->name check",
57 .func = test__perf_evsel__roundtrip_name_test,
58 },
59 {
60 .desc = "Check parsing of sched tracepoints fields",
61 .func = test__perf_evsel__tp_sched_test,
62 },
63 {
64 .desc = "Generate and check syscalls:sys_enter_open event fields",
65 .func = test__syscall_open_tp_fields,
66 },
67 {
68 .desc = "struct perf_event_attr setup",
69 .func = test__attr,
70 },
71 {
72 .func = NULL,
73 },
74};
75
76static bool perf_test__matches(int curr, int argc, const char *argv[])
77{
78 int i;
79
80 if (argc == 0)
81 return true;
82
83 for (i = 0; i < argc; ++i) {
84 char *end;
85 long nr = strtoul(argv[i], &end, 10);
86
87 if (*end == '\0') {
88 if (nr == curr + 1)
89 return true;
90 continue;
91 }
92
93 if (strstr(tests[curr].desc, argv[i]))
94 return true;
95 }
96
97 return false;
98}
99
100static int __cmd_test(int argc, const char *argv[])
101{
102 int i = 0;
103 int width = 0;
104
105 while (tests[i].func) {
106 int len = strlen(tests[i].desc);
107
108 if (width < len)
109 width = len;
110 ++i;
111 }
112
113 i = 0;
114 while (tests[i].func) {
115 int curr = i++, err;
116
117 if (!perf_test__matches(curr, argc, argv))
118 continue;
119
120 pr_info("%2d: %-*s:", i, width, tests[curr].desc);
121 pr_debug("\n--- start ---\n");
122 err = tests[curr].func();
123 pr_debug("---- end ----\n%s:", tests[curr].desc);
124 if (err)
125 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
126 else
127 pr_info(" Ok\n");
128 }
129
130 return 0;
131}
132
133static int perf_test__list(int argc, const char **argv)
134{
135 int i = 0;
136
137 while (tests[i].func) {
138 int curr = i++;
139
140 if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
141 continue;
142
143 pr_info("%2d: %s\n", i, tests[curr].desc);
144 }
145
146 return 0;
147}
148
149int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
150{
151 const char * const test_usage[] = {
152 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
153 NULL,
154 };
155 const struct option test_options[] = {
156 OPT_INCR('v', "verbose", &verbose,
157 "be more verbose (show symbol address, etc)"),
158 OPT_END()
159 };
160
161 argc = parse_options(argc, argv, test_options, test_usage, 0);
162 if (argc >= 1 && !strcmp(argv[0], "list"))
163 return perf_test__list(argc, argv);
164
165 symbol_conf.priv_size = sizeof(int);
166 symbol_conf.sort_by_name = true;
167 symbol_conf.try_vmlinux_path = true;
168
169 if (symbol__init() < 0)
170 return -1;
171
172 return __cmd_test(argc, argv);
173}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
deleted file mode 100644
index 5eaffa2de9c..00000000000
--- a/tools/perf/tests/dso-data.c
+++ /dev/null
@@ -1,159 +0,0 @@
1#include "util.h"
2
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <string.h>
8
9#include "machine.h"
10#include "symbol.h"
11#include "tests.h"
12
13#define TEST_ASSERT_VAL(text, cond) \
14do { \
15 if (!(cond)) { \
16 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
17 return -1; \
18 } \
19} while (0)
20
21static char *test_file(int size)
22{
23 static char buf_templ[] = "/tmp/test-XXXXXX";
24 char *templ = buf_templ;
25 int fd, i;
26 unsigned char *buf;
27
28 fd = mkstemp(templ);
29 if (fd < 0) {
30 perror("mkstemp failed");
31 return NULL;
32 }
33
34 buf = malloc(size);
35 if (!buf) {
36 close(fd);
37 return NULL;
38 }
39
40 for (i = 0; i < size; i++)
41 buf[i] = (unsigned char) ((int) i % 10);
42
43 if (size != write(fd, buf, size))
44 templ = NULL;
45
46 close(fd);
47 return templ;
48}
49
50#define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20)
51
52struct test_data_offset {
53 off_t offset;
54 u8 data[10];
55 int size;
56};
57
58struct test_data_offset offsets[] = {
59 /* Fill first cache page. */
60 {
61 .offset = 10,
62 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
63 .size = 10,
64 },
65 /* Read first cache page. */
66 {
67 .offset = 10,
68 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
69 .size = 10,
70 },
71 /* Fill cache boundary pages. */
72 {
73 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
74 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
75 .size = 10,
76 },
77 /* Read cache boundary pages. */
78 {
79 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
80 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
81 .size = 10,
82 },
83 /* Fill final cache page. */
84 {
85 .offset = TEST_FILE_SIZE - 10,
86 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
87 .size = 10,
88 },
89 /* Read final cache page. */
90 {
91 .offset = TEST_FILE_SIZE - 10,
92 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
93 .size = 10,
94 },
95 /* Read final cache page. */
96 {
97 .offset = TEST_FILE_SIZE - 3,
98 .data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 },
99 .size = 3,
100 },
101};
102
103int test__dso_data(void)
104{
105 struct machine machine;
106 struct dso *dso;
107 char *file = test_file(TEST_FILE_SIZE);
108 size_t i;
109
110 TEST_ASSERT_VAL("No test file", file);
111
112 memset(&machine, 0, sizeof(machine));
113
114 dso = dso__new((const char *)file);
115
116 /* Basic 10 bytes tests. */
117 for (i = 0; i < ARRAY_SIZE(offsets); i++) {
118 struct test_data_offset *data = &offsets[i];
119 ssize_t size;
120 u8 buf[10];
121
122 memset(buf, 0, 10);
123 size = dso__data_read_offset(dso, &machine, data->offset,
124 buf, 10);
125
126 TEST_ASSERT_VAL("Wrong size", size == data->size);
127 TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10));
128 }
129
130 /* Read cross multiple cache pages. */
131 {
132 ssize_t size;
133 int c;
134 u8 *buf;
135
136 buf = malloc(TEST_FILE_SIZE);
137 TEST_ASSERT_VAL("ENOMEM\n", buf);
138
139 /* First iteration to fill caches, second one to read them. */
140 for (c = 0; c < 2; c++) {
141 memset(buf, 0, TEST_FILE_SIZE);
142 size = dso__data_read_offset(dso, &machine, 10,
143 buf, TEST_FILE_SIZE);
144
145 TEST_ASSERT_VAL("Wrong size",
146 size == (TEST_FILE_SIZE - 10));
147
148 for (i = 0; i < (size_t)size; i++)
149 TEST_ASSERT_VAL("Wrong data",
150 buf[i] == (i % 10));
151 }
152
153 free(buf);
154 }
155
156 dso__delete(dso);
157 unlink(file);
158 return 0;
159}
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
deleted file mode 100644
index e61fc828a15..00000000000
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ /dev/null
@@ -1,114 +0,0 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "parse-events.h"
4#include "tests.h"
5
6static int perf_evsel__roundtrip_cache_name_test(void)
7{
8 char name[128];
9 int type, op, err = 0, ret = 0, i, idx;
10 struct perf_evsel *evsel;
11 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
12
13 if (evlist == NULL)
14 return -ENOMEM;
15
16 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
17 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
18 /* skip invalid cache type */
19 if (!perf_evsel__is_cache_op_valid(type, op))
20 continue;
21
22 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
23 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
24 name, sizeof(name));
25 err = parse_events(evlist, name, 0);
26 if (err)
27 ret = err;
28 }
29 }
30 }
31
32 idx = 0;
33 evsel = perf_evlist__first(evlist);
34
35 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
36 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
37 /* skip invalid cache type */
38 if (!perf_evsel__is_cache_op_valid(type, op))
39 continue;
40
41 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
42 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
43 name, sizeof(name));
44 if (evsel->idx != idx)
45 continue;
46
47 ++idx;
48
49 if (strcmp(perf_evsel__name(evsel), name)) {
50 pr_debug("%s != %s\n", perf_evsel__name(evsel), name);
51 ret = -1;
52 }
53
54 evsel = perf_evsel__next(evsel);
55 }
56 }
57 }
58
59 perf_evlist__delete(evlist);
60 return ret;
61}
62
63static int __perf_evsel__name_array_test(const char *names[], int nr_names)
64{
65 int i, err;
66 struct perf_evsel *evsel;
67 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
68
69 if (evlist == NULL)
70 return -ENOMEM;
71
72 for (i = 0; i < nr_names; ++i) {
73 err = parse_events(evlist, names[i], 0);
74 if (err) {
75 pr_debug("failed to parse event '%s', err %d\n",
76 names[i], err);
77 goto out_delete_evlist;
78 }
79 }
80
81 err = 0;
82 list_for_each_entry(evsel, &evlist->entries, node) {
83 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
84 --err;
85 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
86 }
87 }
88
89out_delete_evlist:
90 perf_evlist__delete(evlist);
91 return err;
92}
93
94#define perf_evsel__name_array_test(names) \
95 __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
96
97int test__perf_evsel__roundtrip_name_test(void)
98{
99 int err = 0, ret = 0;
100
101 err = perf_evsel__name_array_test(perf_evsel__hw_names);
102 if (err)
103 ret = err;
104
105 err = perf_evsel__name_array_test(perf_evsel__sw_names);
106 if (err)
107 ret = err;
108
109 err = perf_evsel__roundtrip_cache_name_test();
110 if (err)
111 ret = err;
112
113 return ret;
114}
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
deleted file mode 100644
index a5d2fcc5ae3..00000000000
--- a/tools/perf/tests/evsel-tp-sched.c
+++ /dev/null
@@ -1,84 +0,0 @@
1#include "evsel.h"
2#include "tests.h"
3#include "event-parse.h"
4
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
6 int size, bool should_be_signed)
7{
8 struct format_field *field = perf_evsel__field(evsel, name);
9 int is_signed;
10 int ret = 0;
11
12 if (field == NULL) {
13 pr_debug("%s: \"%s\" field not found!\n", evsel->name, name);
14 return -1;
15 }
16
17 is_signed = !!(field->flags | FIELD_IS_SIGNED);
18 if (should_be_signed && !is_signed) {
19 pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
20 evsel->name, name, is_signed, should_be_signed);
21 ret = -1;
22 }
23
24 if (field->size != size) {
25 pr_debug("%s: \"%s\" size (%d) should be %d!\n",
26 evsel->name, name, field->size, size);
27 ret = -1;
28 }
29
30 return ret;
31}
32
33int test__perf_evsel__tp_sched_test(void)
34{
35 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0);
36 int ret = 0;
37
38 if (evsel == NULL) {
39 pr_debug("perf_evsel__new\n");
40 return -1;
41 }
42
43 if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
44 ret = -1;
45
46 if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
47 ret = -1;
48
49 if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
50 ret = -1;
51
52 if (perf_evsel__test_field(evsel, "prev_state", 8, true))
53 ret = -1;
54
55 if (perf_evsel__test_field(evsel, "next_comm", 16, true))
56 ret = -1;
57
58 if (perf_evsel__test_field(evsel, "next_pid", 4, true))
59 ret = -1;
60
61 if (perf_evsel__test_field(evsel, "next_prio", 4, true))
62 ret = -1;
63
64 perf_evsel__delete(evsel);
65
66 evsel = perf_evsel__newtp("sched", "sched_wakeup", 0);
67
68 if (perf_evsel__test_field(evsel, "comm", 16, true))
69 ret = -1;
70
71 if (perf_evsel__test_field(evsel, "pid", 4, true))
72 ret = -1;
73
74 if (perf_evsel__test_field(evsel, "prio", 4, true))
75 ret = -1;
76
77 if (perf_evsel__test_field(evsel, "success", 4, true))
78 ret = -1;
79
80 if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
81 ret = -1;
82
83 return ret;
84}
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
deleted file mode 100644
index e1746811e14..00000000000
--- a/tools/perf/tests/mmap-basic.c
+++ /dev/null
@@ -1,162 +0,0 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "tests.h"
6
7/*
8 * This test will generate random numbers of calls to some getpid syscalls,
9 * then establish an mmap for a group of events that are created to monitor
10 * the syscalls.
11 *
12 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
13 * sample.id field to map back to its respective perf_evsel instance.
14 *
15 * Then it checks if the number of syscalls reported as perf events by
16 * the kernel corresponds to the number of syscalls made.
17 */
18int test__basic_mmap(void)
19{
20 int err = -1;
21 union perf_event *event;
22 struct thread_map *threads;
23 struct cpu_map *cpus;
24 struct perf_evlist *evlist;
25 struct perf_event_attr attr = {
26 .type = PERF_TYPE_TRACEPOINT,
27 .read_format = PERF_FORMAT_ID,
28 .sample_type = PERF_SAMPLE_ID,
29 .watermark = 0,
30 };
31 cpu_set_t cpu_set;
32 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
33 "getpgid", };
34 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
35 (void*)getpgid };
36#define nsyscalls ARRAY_SIZE(syscall_names)
37 int ids[nsyscalls];
38 unsigned int nr_events[nsyscalls],
39 expected_nr_events[nsyscalls], i, j;
40 struct perf_evsel *evsels[nsyscalls], *evsel;
41
42 for (i = 0; i < nsyscalls; ++i) {
43 char name[64];
44
45 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
46 ids[i] = trace_event__id(name);
47 if (ids[i] < 0) {
48 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
49 return -1;
50 }
51 nr_events[i] = 0;
52 expected_nr_events[i] = random() % 257;
53 }
54
55 threads = thread_map__new(-1, getpid(), UINT_MAX);
56 if (threads == NULL) {
57 pr_debug("thread_map__new\n");
58 return -1;
59 }
60
61 cpus = cpu_map__new(NULL);
62 if (cpus == NULL) {
63 pr_debug("cpu_map__new\n");
64 goto out_free_threads;
65 }
66
67 CPU_ZERO(&cpu_set);
68 CPU_SET(cpus->map[0], &cpu_set);
69 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
70 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
71 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
72 cpus->map[0], strerror(errno));
73 goto out_free_cpus;
74 }
75
76 evlist = perf_evlist__new(cpus, threads);
77 if (evlist == NULL) {
78 pr_debug("perf_evlist__new\n");
79 goto out_free_cpus;
80 }
81
82 /* anonymous union fields, can't be initialized above */
83 attr.wakeup_events = 1;
84 attr.sample_period = 1;
85
86 for (i = 0; i < nsyscalls; ++i) {
87 attr.config = ids[i];
88 evsels[i] = perf_evsel__new(&attr, i);
89 if (evsels[i] == NULL) {
90 pr_debug("perf_evsel__new\n");
91 goto out_free_evlist;
92 }
93
94 perf_evlist__add(evlist, evsels[i]);
95
96 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
97 pr_debug("failed to open counter: %s, "
98 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
99 strerror(errno));
100 goto out_close_fd;
101 }
102 }
103
104 if (perf_evlist__mmap(evlist, 128, true) < 0) {
105 pr_debug("failed to mmap events: %d (%s)\n", errno,
106 strerror(errno));
107 goto out_close_fd;
108 }
109
110 for (i = 0; i < nsyscalls; ++i)
111 for (j = 0; j < expected_nr_events[i]; ++j) {
112 int foo = syscalls[i]();
113 ++foo;
114 }
115
116 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
117 struct perf_sample sample;
118
119 if (event->header.type != PERF_RECORD_SAMPLE) {
120 pr_debug("unexpected %s event\n",
121 perf_event__name(event->header.type));
122 goto out_munmap;
123 }
124
125 err = perf_evlist__parse_sample(evlist, event, &sample);
126 if (err) {
127 pr_err("Can't parse sample, err = %d\n", err);
128 goto out_munmap;
129 }
130
131 evsel = perf_evlist__id2evsel(evlist, sample.id);
132 if (evsel == NULL) {
133 pr_debug("event with id %" PRIu64
134 " doesn't map to an evsel\n", sample.id);
135 goto out_munmap;
136 }
137 nr_events[evsel->idx]++;
138 }
139
140 list_for_each_entry(evsel, &evlist->entries, node) {
141 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
142 pr_debug("expected %d %s events, got %d\n",
143 expected_nr_events[evsel->idx],
144 perf_evsel__name(evsel), nr_events[evsel->idx]);
145 goto out_munmap;
146 }
147 }
148
149 err = 0;
150out_munmap:
151 perf_evlist__munmap(evlist);
152out_close_fd:
153 for (i = 0; i < nsyscalls; ++i)
154 perf_evsel__close_fd(evsels[i], 1, threads->nr);
155out_free_evlist:
156 perf_evlist__delete(evlist);
157out_free_cpus:
158 cpu_map__delete(cpus);
159out_free_threads:
160 thread_map__delete(threads);
161 return err;
162}
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c
deleted file mode 100644
index 31072aba0d5..00000000000
--- a/tools/perf/tests/open-syscall-all-cpus.c
+++ /dev/null
@@ -1,120 +0,0 @@
1#include "evsel.h"
2#include "tests.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "debug.h"
6
7int test__open_syscall_event_on_all_cpus(void)
8{
9 int err = -1, fd, cpu;
10 struct thread_map *threads;
11 struct cpu_map *cpus;
12 struct perf_evsel *evsel;
13 struct perf_event_attr attr;
14 unsigned int nr_open_calls = 111, i;
15 cpu_set_t cpu_set;
16 int id = trace_event__id("sys_enter_open");
17
18 if (id < 0) {
19 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
20 return -1;
21 }
22
23 threads = thread_map__new(-1, getpid(), UINT_MAX);
24 if (threads == NULL) {
25 pr_debug("thread_map__new\n");
26 return -1;
27 }
28
29 cpus = cpu_map__new(NULL);
30 if (cpus == NULL) {
31 pr_debug("cpu_map__new\n");
32 goto out_thread_map_delete;
33 }
34
35
36 CPU_ZERO(&cpu_set);
37
38 memset(&attr, 0, sizeof(attr));
39 attr.type = PERF_TYPE_TRACEPOINT;
40 attr.config = id;
41 evsel = perf_evsel__new(&attr, 0);
42 if (evsel == NULL) {
43 pr_debug("perf_evsel__new\n");
44 goto out_thread_map_delete;
45 }
46
47 if (perf_evsel__open(evsel, cpus, threads) < 0) {
48 pr_debug("failed to open counter: %s, "
49 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
50 strerror(errno));
51 goto out_evsel_delete;
52 }
53
54 for (cpu = 0; cpu < cpus->nr; ++cpu) {
55 unsigned int ncalls = nr_open_calls + cpu;
56 /*
57 * XXX eventually lift this restriction in a way that
58 * keeps perf building on older glibc installations
59 * without CPU_ALLOC. 1024 cpus in 2010 still seems
60 * a reasonable upper limit tho :-)
61 */
62 if (cpus->map[cpu] >= CPU_SETSIZE) {
63 pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
64 continue;
65 }
66
67 CPU_SET(cpus->map[cpu], &cpu_set);
68 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
69 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
70 cpus->map[cpu],
71 strerror(errno));
72 goto out_close_fd;
73 }
74 for (i = 0; i < ncalls; ++i) {
75 fd = open("/etc/passwd", O_RDONLY);
76 close(fd);
77 }
78 CPU_CLR(cpus->map[cpu], &cpu_set);
79 }
80
81 /*
82 * Here we need to explicitely preallocate the counts, as if
83 * we use the auto allocation it will allocate just for 1 cpu,
84 * as we start by cpu 0.
85 */
86 if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
87 pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
88 goto out_close_fd;
89 }
90
91 err = 0;
92
93 for (cpu = 0; cpu < cpus->nr; ++cpu) {
94 unsigned int expected;
95
96 if (cpus->map[cpu] >= CPU_SETSIZE)
97 continue;
98
99 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
100 pr_debug("perf_evsel__read_on_cpu\n");
101 err = -1;
102 break;
103 }
104
105 expected = nr_open_calls + cpu;
106 if (evsel->counts->cpu[cpu].val != expected) {
107 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
108 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
109 err = -1;
110 }
111 }
112
113out_close_fd:
114 perf_evsel__close_fd(evsel, 1, threads->nr);
115out_evsel_delete:
116 perf_evsel__delete(evsel);
117out_thread_map_delete:
118 thread_map__delete(threads);
119 return err;
120}
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
deleted file mode 100644
index 1c52fdc1164..00000000000
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ /dev/null
@@ -1,117 +0,0 @@
1#include "perf.h"
2#include "evlist.h"
3#include "evsel.h"
4#include "thread_map.h"
5#include "tests.h"
6
7int test__syscall_open_tp_fields(void)
8{
9 struct perf_record_opts opts = {
10 .target = {
11 .uid = UINT_MAX,
12 .uses_mmap = true,
13 },
14 .no_delay = true,
15 .freq = 1,
16 .mmap_pages = 256,
17 .raw_samples = true,
18 };
19 const char *filename = "/etc/passwd";
20 int flags = O_RDONLY | O_DIRECTORY;
21 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
22 struct perf_evsel *evsel;
23 int err = -1, i, nr_events = 0, nr_polls = 0;
24
25 if (evlist == NULL) {
26 pr_debug("%s: perf_evlist__new\n", __func__);
27 goto out;
28 }
29
30 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
31 if (evsel == NULL) {
32 pr_debug("%s: perf_evsel__newtp\n", __func__);
33 goto out_delete_evlist;
34 }
35
36 perf_evlist__add(evlist, evsel);
37
38 err = perf_evlist__create_maps(evlist, &opts.target);
39 if (err < 0) {
40 pr_debug("%s: perf_evlist__create_maps\n", __func__);
41 goto out_delete_evlist;
42 }
43
44 perf_evsel__config(evsel, &opts);
45
46 evlist->threads->map[0] = getpid();
47
48 err = perf_evlist__open(evlist);
49 if (err < 0) {
50 pr_debug("perf_evlist__open: %s\n", strerror(errno));
51 goto out_delete_evlist;
52 }
53
54 err = perf_evlist__mmap(evlist, UINT_MAX, false);
55 if (err < 0) {
56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
57 goto out_delete_evlist;
58 }
59
60 perf_evlist__enable(evlist);
61
62 /*
63 * Generate the event:
64 */
65 open(filename, flags);
66
67 while (1) {
68 int before = nr_events;
69
70 for (i = 0; i < evlist->nr_mmaps; i++) {
71 union perf_event *event;
72
73 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
74 const u32 type = event->header.type;
75 int tp_flags;
76 struct perf_sample sample;
77
78 ++nr_events;
79
80 if (type != PERF_RECORD_SAMPLE)
81 continue;
82
83 err = perf_evsel__parse_sample(evsel, event, &sample);
84 if (err) {
85 pr_err("Can't parse sample, err = %d\n", err);
86 goto out_munmap;
87 }
88
89 tp_flags = perf_evsel__intval(evsel, &sample, "flags");
90
91 if (flags != tp_flags) {
92 pr_debug("%s: Expected flags=%#x, got %#x\n",
93 __func__, flags, tp_flags);
94 goto out_munmap;
95 }
96
97 goto out_ok;
98 }
99 }
100
101 if (nr_events == before)
102 poll(evlist->pollfd, evlist->nr_fds, 10);
103
104 if (++nr_polls > 5) {
105 pr_debug("%s: no events!\n", __func__);
106 goto out_munmap;
107 }
108 }
109out_ok:
110 err = 0;
111out_munmap:
112 perf_evlist__munmap(evlist);
113out_delete_evlist:
114 perf_evlist__delete(evlist);
115out:
116 return err;
117}
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c
deleted file mode 100644
index 98be8b518b4..00000000000
--- a/tools/perf/tests/open-syscall.c
+++ /dev/null
@@ -1,66 +0,0 @@
1#include "thread_map.h"
2#include "evsel.h"
3#include "debug.h"
4#include "tests.h"
5
6int test__open_syscall_event(void)
7{
8 int err = -1, fd;
9 struct thread_map *threads;
10 struct perf_evsel *evsel;
11 struct perf_event_attr attr;
12 unsigned int nr_open_calls = 111, i;
13 int id = trace_event__id("sys_enter_open");
14
15 if (id < 0) {
16 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
17 return -1;
18 }
19
20 threads = thread_map__new(-1, getpid(), UINT_MAX);
21 if (threads == NULL) {
22 pr_debug("thread_map__new\n");
23 return -1;
24 }
25
26 memset(&attr, 0, sizeof(attr));
27 attr.type = PERF_TYPE_TRACEPOINT;
28 attr.config = id;
29 evsel = perf_evsel__new(&attr, 0);
30 if (evsel == NULL) {
31 pr_debug("perf_evsel__new\n");
32 goto out_thread_map_delete;
33 }
34
35 if (perf_evsel__open_per_thread(evsel, threads) < 0) {
36 pr_debug("failed to open counter: %s, "
37 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
38 strerror(errno));
39 goto out_evsel_delete;
40 }
41
42 for (i = 0; i < nr_open_calls; ++i) {
43 fd = open("/etc/passwd", O_RDONLY);
44 close(fd);
45 }
46
47 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
48 pr_debug("perf_evsel__read_on_cpu\n");
49 goto out_close_fd;
50 }
51
52 if (evsel->counts->cpu[0].val != nr_open_calls) {
53 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
54 nr_open_calls, evsel->counts->cpu[0].val);
55 goto out_close_fd;
56 }
57
58 err = 0;
59out_close_fd:
60 perf_evsel__close_fd(evsel, 1, threads->nr);
61out_evsel_delete:
62 perf_evsel__delete(evsel);
63out_thread_map_delete:
64 thread_map__delete(threads);
65 return err;
66}
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
deleted file mode 100644
index 32ee478905e..00000000000
--- a/tools/perf/tests/parse-events.c
+++ /dev/null
@@ -1,1117 +0,0 @@
1
2#include "parse-events.h"
3#include "evsel.h"
4#include "evlist.h"
5#include "sysfs.h"
6#include "tests.h"
7#include <linux/hw_breakpoint.h>
8
9#define TEST_ASSERT_VAL(text, cond) \
10do { \
11 if (!(cond)) { \
12 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
13 return -1; \
14 } \
15} while (0)
16
17#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
18 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
19
20static int test__checkevent_tracepoint(struct perf_evlist *evlist)
21{
22 struct perf_evsel *evsel = perf_evlist__first(evlist);
23
24 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
25 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
26 TEST_ASSERT_VAL("wrong sample_type",
27 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
28 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
29 return 0;
30}
31
32static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
33{
34 struct perf_evsel *evsel;
35
36 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
37
38 list_for_each_entry(evsel, &evlist->entries, node) {
39 TEST_ASSERT_VAL("wrong type",
40 PERF_TYPE_TRACEPOINT == evsel->attr.type);
41 TEST_ASSERT_VAL("wrong sample_type",
42 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
43 TEST_ASSERT_VAL("wrong sample_period",
44 1 == evsel->attr.sample_period);
45 }
46 return 0;
47}
48
49static int test__checkevent_raw(struct perf_evlist *evlist)
50{
51 struct perf_evsel *evsel = perf_evlist__first(evlist);
52
53 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
54 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
55 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
56 return 0;
57}
58
59static int test__checkevent_numeric(struct perf_evlist *evlist)
60{
61 struct perf_evsel *evsel = perf_evlist__first(evlist);
62
63 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
64 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
65 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
66 return 0;
67}
68
69static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
70{
71 struct perf_evsel *evsel = perf_evlist__first(evlist);
72
73 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
74 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
75 TEST_ASSERT_VAL("wrong config",
76 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
77 return 0;
78}
79
80static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
81{
82 struct perf_evsel *evsel = perf_evlist__first(evlist);
83
84 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
85 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
86 TEST_ASSERT_VAL("wrong config",
87 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
88 TEST_ASSERT_VAL("wrong period",
89 100000 == evsel->attr.sample_period);
90 TEST_ASSERT_VAL("wrong config1",
91 0 == evsel->attr.config1);
92 TEST_ASSERT_VAL("wrong config2",
93 1 == evsel->attr.config2);
94 return 0;
95}
96
97static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
98{
99 struct perf_evsel *evsel = perf_evlist__first(evlist);
100
101 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
102 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
103 TEST_ASSERT_VAL("wrong config",
104 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
105 return 0;
106}
107
108static int test__checkevent_genhw(struct perf_evlist *evlist)
109{
110 struct perf_evsel *evsel = perf_evlist__first(evlist);
111
112 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
113 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
114 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
115 return 0;
116}
117
118static int test__checkevent_breakpoint(struct perf_evlist *evlist)
119{
120 struct perf_evsel *evsel = perf_evlist__first(evlist);
121
122 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
123 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
124 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
125 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
126 evsel->attr.bp_type);
127 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
128 evsel->attr.bp_len);
129 return 0;
130}
131
132static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
133{
134 struct perf_evsel *evsel = perf_evlist__first(evlist);
135
136 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
137 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
138 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
139 TEST_ASSERT_VAL("wrong bp_type",
140 HW_BREAKPOINT_X == evsel->attr.bp_type);
141 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
142 return 0;
143}
144
145static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
146{
147 struct perf_evsel *evsel = perf_evlist__first(evlist);
148
149 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
150 TEST_ASSERT_VAL("wrong type",
151 PERF_TYPE_BREAKPOINT == evsel->attr.type);
152 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
153 TEST_ASSERT_VAL("wrong bp_type",
154 HW_BREAKPOINT_R == evsel->attr.bp_type);
155 TEST_ASSERT_VAL("wrong bp_len",
156 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
157 return 0;
158}
159
160static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
161{
162 struct perf_evsel *evsel = perf_evlist__first(evlist);
163
164 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
165 TEST_ASSERT_VAL("wrong type",
166 PERF_TYPE_BREAKPOINT == evsel->attr.type);
167 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
168 TEST_ASSERT_VAL("wrong bp_type",
169 HW_BREAKPOINT_W == evsel->attr.bp_type);
170 TEST_ASSERT_VAL("wrong bp_len",
171 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
172 return 0;
173}
174
175static int test__checkevent_breakpoint_rw(struct perf_evlist *evlist)
176{
177 struct perf_evsel *evsel = perf_evlist__first(evlist);
178
179 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
180 TEST_ASSERT_VAL("wrong type",
181 PERF_TYPE_BREAKPOINT == evsel->attr.type);
182 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
183 TEST_ASSERT_VAL("wrong bp_type",
184 (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->attr.bp_type);
185 TEST_ASSERT_VAL("wrong bp_len",
186 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
187 return 0;
188}
189
190static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
191{
192 struct perf_evsel *evsel = perf_evlist__first(evlist);
193
194 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
195 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
196 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
197 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
198
199 return test__checkevent_tracepoint(evlist);
200}
201
202static int
203test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
204{
205 struct perf_evsel *evsel;
206
207 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
208
209 list_for_each_entry(evsel, &evlist->entries, node) {
210 TEST_ASSERT_VAL("wrong exclude_user",
211 !evsel->attr.exclude_user);
212 TEST_ASSERT_VAL("wrong exclude_kernel",
213 evsel->attr.exclude_kernel);
214 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
215 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
216 }
217
218 return test__checkevent_tracepoint_multi(evlist);
219}
220
221static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
222{
223 struct perf_evsel *evsel = perf_evlist__first(evlist);
224
225 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
226 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
227 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
228 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
229
230 return test__checkevent_raw(evlist);
231}
232
233static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
234{
235 struct perf_evsel *evsel = perf_evlist__first(evlist);
236
237 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
238 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
239 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
240 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
241
242 return test__checkevent_numeric(evlist);
243}
244
245static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
246{
247 struct perf_evsel *evsel = perf_evlist__first(evlist);
248
249 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
250 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
251 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
252 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
253
254 return test__checkevent_symbolic_name(evlist);
255}
256
257static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
258{
259 struct perf_evsel *evsel = perf_evlist__first(evlist);
260
261 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
262 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
263
264 return test__checkevent_symbolic_name(evlist);
265}
266
267static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
268{
269 struct perf_evsel *evsel = perf_evlist__first(evlist);
270
271 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
272 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
273
274 return test__checkevent_symbolic_name(evlist);
275}
276
277static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
278{
279 struct perf_evsel *evsel = perf_evlist__first(evlist);
280
281 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
282 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
283 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
284 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
285
286 return test__checkevent_symbolic_alias(evlist);
287}
288
289static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
290{
291 struct perf_evsel *evsel = perf_evlist__first(evlist);
292
293 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
294 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
295 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
296 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
297
298 return test__checkevent_genhw(evlist);
299}
300
301static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
302{
303 struct perf_evsel *evsel = perf_evlist__first(evlist);
304
305
306 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
307 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
308 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
309 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
310 TEST_ASSERT_VAL("wrong name",
311 !strcmp(perf_evsel__name(evsel), "mem:0:u"));
312
313 return test__checkevent_breakpoint(evlist);
314}
315
316static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
317{
318 struct perf_evsel *evsel = perf_evlist__first(evlist);
319
320 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
321 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
322 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
323 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
324 TEST_ASSERT_VAL("wrong name",
325 !strcmp(perf_evsel__name(evsel), "mem:0:x:k"));
326
327 return test__checkevent_breakpoint_x(evlist);
328}
329
330static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
331{
332 struct perf_evsel *evsel = perf_evlist__first(evlist);
333
334 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
335 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
336 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
337 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
338 TEST_ASSERT_VAL("wrong name",
339 !strcmp(perf_evsel__name(evsel), "mem:0:r:hp"));
340
341 return test__checkevent_breakpoint_r(evlist);
342}
343
344static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
345{
346 struct perf_evsel *evsel = perf_evlist__first(evlist);
347
348 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
349 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
350 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
351 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
352 TEST_ASSERT_VAL("wrong name",
353 !strcmp(perf_evsel__name(evsel), "mem:0:w:up"));
354
355 return test__checkevent_breakpoint_w(evlist);
356}
357
358static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist)
359{
360 struct perf_evsel *evsel = perf_evlist__first(evlist);
361
362 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
363 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
364 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
365 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
366 TEST_ASSERT_VAL("wrong name",
367 !strcmp(perf_evsel__name(evsel), "mem:0:rw:kp"));
368
369 return test__checkevent_breakpoint_rw(evlist);
370}
371
372static int test__checkevent_pmu(struct perf_evlist *evlist)
373{
374
375 struct perf_evsel *evsel = perf_evlist__first(evlist);
376
377 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
378 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
379 TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
380 TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
381 TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
382 TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
383
384 return 0;
385}
386
387static int test__checkevent_list(struct perf_evlist *evlist)
388{
389 struct perf_evsel *evsel = perf_evlist__first(evlist);
390
391 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
392
393 /* r1 */
394 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
395 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
396 TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
397 TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
398 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
399 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
400 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
401 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
402
403 /* syscalls:sys_enter_open:k */
404 evsel = perf_evsel__next(evsel);
405 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
406 TEST_ASSERT_VAL("wrong sample_type",
407 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
408 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
409 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
410 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
411 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
412 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
413
414 /* 1:1:hp */
415 evsel = perf_evsel__next(evsel);
416 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
417 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
418 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
419 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
420 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
421 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
422
423 return 0;
424}
425
426static int test__checkevent_pmu_name(struct perf_evlist *evlist)
427{
428 struct perf_evsel *evsel = perf_evlist__first(evlist);
429
430 /* cpu/config=1,name=krava/u */
431 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
432 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
433 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
434 TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava"));
435
436 /* cpu/config=2/u" */
437 evsel = perf_evsel__next(evsel);
438 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
439 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
440 TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
441 TEST_ASSERT_VAL("wrong name",
442 !strcmp(perf_evsel__name(evsel), "cpu/config=2/u"));
443
444 return 0;
445}
446
447static int test__checkevent_pmu_events(struct perf_evlist *evlist)
448{
449 struct perf_evsel *evsel;
450
451 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
452 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
453 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
454 TEST_ASSERT_VAL("wrong exclude_user",
455 !evsel->attr.exclude_user);
456 TEST_ASSERT_VAL("wrong exclude_kernel",
457 evsel->attr.exclude_kernel);
458 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
459 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
460
461 return 0;
462}
463
464static int test__checkterms_simple(struct list_head *terms)
465{
466 struct parse_events__term *term;
467
468 /* config=10 */
469 term = list_entry(terms->next, struct parse_events__term, list);
470 TEST_ASSERT_VAL("wrong type term",
471 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
472 TEST_ASSERT_VAL("wrong type val",
473 term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
474 TEST_ASSERT_VAL("wrong val", term->val.num == 10);
475 TEST_ASSERT_VAL("wrong config", !term->config);
476
477 /* config1 */
478 term = list_entry(term->list.next, struct parse_events__term, list);
479 TEST_ASSERT_VAL("wrong type term",
480 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
481 TEST_ASSERT_VAL("wrong type val",
482 term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
483 TEST_ASSERT_VAL("wrong val", term->val.num == 1);
484 TEST_ASSERT_VAL("wrong config", !term->config);
485
486 /* config2=3 */
487 term = list_entry(term->list.next, struct parse_events__term, list);
488 TEST_ASSERT_VAL("wrong type term",
489 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
490 TEST_ASSERT_VAL("wrong type val",
491 term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
492 TEST_ASSERT_VAL("wrong val", term->val.num == 3);
493 TEST_ASSERT_VAL("wrong config", !term->config);
494
495 /* umask=1*/
496 term = list_entry(term->list.next, struct parse_events__term, list);
497 TEST_ASSERT_VAL("wrong type term",
498 term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
499 TEST_ASSERT_VAL("wrong type val",
500 term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
501 TEST_ASSERT_VAL("wrong val", term->val.num == 1);
502 TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask"));
503
504 return 0;
505}
506
507static int test__group1(struct perf_evlist *evlist)
508{
509 struct perf_evsel *evsel, *leader;
510
511 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
512
513 /* instructions:k */
514 evsel = leader = perf_evlist__first(evlist);
515 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
516 TEST_ASSERT_VAL("wrong config",
517 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
518 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
519 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
520 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
521 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
522 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
523 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
524 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
525
526 /* cycles:upp */
527 evsel = perf_evsel__next(evsel);
528 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
529 TEST_ASSERT_VAL("wrong config",
530 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
531 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
532 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
533 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
534 /* use of precise requires exclude_guest */
535 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
536 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
537 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
538 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
539
540 return 0;
541}
542
543static int test__group2(struct perf_evlist *evlist)
544{
545 struct perf_evsel *evsel, *leader;
546
547 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
548
549 /* faults + :ku modifier */
550 evsel = leader = perf_evlist__first(evlist);
551 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
552 TEST_ASSERT_VAL("wrong config",
553 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
554 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
555 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
556 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
557 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
558 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
559 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
560 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
561
562 /* cache-references + :u modifier */
563 evsel = perf_evsel__next(evsel);
564 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
565 TEST_ASSERT_VAL("wrong config",
566 PERF_COUNT_HW_CACHE_REFERENCES == evsel->attr.config);
567 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
568 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
569 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
570 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
571 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
572 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
573 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
574
575 /* cycles:k */
576 evsel = perf_evsel__next(evsel);
577 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
578 TEST_ASSERT_VAL("wrong config",
579 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
580 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
581 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
582 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
583 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
584 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
585 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
586 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
587
588 return 0;
589}
590
591static int test__group3(struct perf_evlist *evlist __maybe_unused)
592{
593 struct perf_evsel *evsel, *leader;
594
595 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
596
597 /* group1 syscalls:sys_enter_open:H */
598 evsel = leader = perf_evlist__first(evlist);
599 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
600 TEST_ASSERT_VAL("wrong sample_type",
601 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
602 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
603 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
604 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
605 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
606 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
607 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
608 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
609 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
610 TEST_ASSERT_VAL("wrong group name",
611 !strcmp(leader->group_name, "group1"));
612
613 /* group1 cycles:kppp */
614 evsel = perf_evsel__next(evsel);
615 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
616 TEST_ASSERT_VAL("wrong config",
617 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
618 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
619 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
620 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
621 /* use of precise requires exclude_guest */
622 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
623 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
624 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3);
625 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
626 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
627
628 /* group2 cycles + G modifier */
629 evsel = leader = perf_evsel__next(evsel);
630 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
631 TEST_ASSERT_VAL("wrong config",
632 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
633 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
634 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
635 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
636 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
637 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
638 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
639 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
640 TEST_ASSERT_VAL("wrong group name",
641 !strcmp(leader->group_name, "group2"));
642
643 /* group2 1:3 + G modifier */
644 evsel = perf_evsel__next(evsel);
645 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
646 TEST_ASSERT_VAL("wrong config", 3 == evsel->attr.config);
647 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
648 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
649 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
650 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
651 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
652 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
653 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
654
655 /* instructions:u */
656 evsel = perf_evsel__next(evsel);
657 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
658 TEST_ASSERT_VAL("wrong config",
659 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
660 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
661 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
662 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
663 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
664 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
665 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
666 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
667
668 return 0;
669}
670
671static int test__group4(struct perf_evlist *evlist __maybe_unused)
672{
673 struct perf_evsel *evsel, *leader;
674
675 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
676
677 /* cycles:u + p */
678 evsel = leader = perf_evlist__first(evlist);
679 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
680 TEST_ASSERT_VAL("wrong config",
681 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
682 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
683 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
684 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
685 /* use of precise requires exclude_guest */
686 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
687 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
688 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1);
689 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
690 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
691
692 /* instructions:kp + p */
693 evsel = perf_evsel__next(evsel);
694 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
695 TEST_ASSERT_VAL("wrong config",
696 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
697 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
698 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
699 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
700 /* use of precise requires exclude_guest */
701 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
702 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
703 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
704 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
705
706 return 0;
707}
708
709static int test__group5(struct perf_evlist *evlist __maybe_unused)
710{
711 struct perf_evsel *evsel, *leader;
712
713 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
714
715 /* cycles + G */
716 evsel = leader = perf_evlist__first(evlist);
717 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
718 TEST_ASSERT_VAL("wrong config",
719 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
720 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
721 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
722 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
723 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
724 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
725 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
726 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
727 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
728
729 /* instructions + G */
730 evsel = perf_evsel__next(evsel);
731 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
732 TEST_ASSERT_VAL("wrong config",
733 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
734 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
735 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
736 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
737 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
738 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
739 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
740 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
741
742 /* cycles:G */
743 evsel = leader = perf_evsel__next(evsel);
744 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
745 TEST_ASSERT_VAL("wrong config",
746 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
747 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
748 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
749 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
750 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
751 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
752 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
753 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
754 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
755
756 /* instructions:G */
757 evsel = perf_evsel__next(evsel);
758 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
759 TEST_ASSERT_VAL("wrong config",
760 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
761 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
762 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
763 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
764 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
765 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
766 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
767 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
768
769 /* cycles */
770 evsel = perf_evsel__next(evsel);
771 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
772 TEST_ASSERT_VAL("wrong config",
773 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
774 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
775 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
776 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
777 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
778 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
779 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
780 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
781
782 return 0;
783}
784
785struct test__event_st {
786 const char *name;
787 __u32 type;
788 int (*check)(struct perf_evlist *evlist);
789};
790
791static struct test__event_st test__events[] = {
792 [0] = {
793 .name = "syscalls:sys_enter_open",
794 .check = test__checkevent_tracepoint,
795 },
796 [1] = {
797 .name = "syscalls:*",
798 .check = test__checkevent_tracepoint_multi,
799 },
800 [2] = {
801 .name = "r1a",
802 .check = test__checkevent_raw,
803 },
804 [3] = {
805 .name = "1:1",
806 .check = test__checkevent_numeric,
807 },
808 [4] = {
809 .name = "instructions",
810 .check = test__checkevent_symbolic_name,
811 },
812 [5] = {
813 .name = "cycles/period=100000,config2/",
814 .check = test__checkevent_symbolic_name_config,
815 },
816 [6] = {
817 .name = "faults",
818 .check = test__checkevent_symbolic_alias,
819 },
820 [7] = {
821 .name = "L1-dcache-load-miss",
822 .check = test__checkevent_genhw,
823 },
824 [8] = {
825 .name = "mem:0",
826 .check = test__checkevent_breakpoint,
827 },
828 [9] = {
829 .name = "mem:0:x",
830 .check = test__checkevent_breakpoint_x,
831 },
832 [10] = {
833 .name = "mem:0:r",
834 .check = test__checkevent_breakpoint_r,
835 },
836 [11] = {
837 .name = "mem:0:w",
838 .check = test__checkevent_breakpoint_w,
839 },
840 [12] = {
841 .name = "syscalls:sys_enter_open:k",
842 .check = test__checkevent_tracepoint_modifier,
843 },
844 [13] = {
845 .name = "syscalls:*:u",
846 .check = test__checkevent_tracepoint_multi_modifier,
847 },
848 [14] = {
849 .name = "r1a:kp",
850 .check = test__checkevent_raw_modifier,
851 },
852 [15] = {
853 .name = "1:1:hp",
854 .check = test__checkevent_numeric_modifier,
855 },
856 [16] = {
857 .name = "instructions:h",
858 .check = test__checkevent_symbolic_name_modifier,
859 },
860 [17] = {
861 .name = "faults:u",
862 .check = test__checkevent_symbolic_alias_modifier,
863 },
864 [18] = {
865 .name = "L1-dcache-load-miss:kp",
866 .check = test__checkevent_genhw_modifier,
867 },
868 [19] = {
869 .name = "mem:0:u",
870 .check = test__checkevent_breakpoint_modifier,
871 },
872 [20] = {
873 .name = "mem:0:x:k",
874 .check = test__checkevent_breakpoint_x_modifier,
875 },
876 [21] = {
877 .name = "mem:0:r:hp",
878 .check = test__checkevent_breakpoint_r_modifier,
879 },
880 [22] = {
881 .name = "mem:0:w:up",
882 .check = test__checkevent_breakpoint_w_modifier,
883 },
884 [23] = {
885 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
886 .check = test__checkevent_list,
887 },
888 [24] = {
889 .name = "instructions:G",
890 .check = test__checkevent_exclude_host_modifier,
891 },
892 [25] = {
893 .name = "instructions:H",
894 .check = test__checkevent_exclude_guest_modifier,
895 },
896 [26] = {
897 .name = "mem:0:rw",
898 .check = test__checkevent_breakpoint_rw,
899 },
900 [27] = {
901 .name = "mem:0:rw:kp",
902 .check = test__checkevent_breakpoint_rw_modifier,
903 },
904 [28] = {
905 .name = "{instructions:k,cycles:upp}",
906 .check = test__group1,
907 },
908 [29] = {
909 .name = "{faults:k,cache-references}:u,cycles:k",
910 .check = test__group2,
911 },
912 [30] = {
913 .name = "group1{syscalls:sys_enter_open:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u",
914 .check = test__group3,
915 },
916 [31] = {
917 .name = "{cycles:u,instructions:kp}:p",
918 .check = test__group4,
919 },
920 [32] = {
921 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
922 .check = test__group5,
923 },
924};
925
926static struct test__event_st test__events_pmu[] = {
927 [0] = {
928 .name = "cpu/config=10,config1,config2=3,period=1000/u",
929 .check = test__checkevent_pmu,
930 },
931 [1] = {
932 .name = "cpu/config=1,name=krava/u,cpu/config=2/u",
933 .check = test__checkevent_pmu_name,
934 },
935};
936
937struct test__term {
938 const char *str;
939 __u32 type;
940 int (*check)(struct list_head *terms);
941};
942
943static struct test__term test__terms[] = {
944 [0] = {
945 .str = "config=10,config1,config2=3,umask=1",
946 .check = test__checkterms_simple,
947 },
948};
949
950static int test_event(struct test__event_st *e)
951{
952 struct perf_evlist *evlist;
953 int ret;
954
955 evlist = perf_evlist__new(NULL, NULL);
956 if (evlist == NULL)
957 return -ENOMEM;
958
959 ret = parse_events(evlist, e->name, 0);
960 if (ret) {
961 pr_debug("failed to parse event '%s', err %d\n",
962 e->name, ret);
963 return ret;
964 }
965
966 ret = e->check(evlist);
967 perf_evlist__delete(evlist);
968
969 return ret;
970}
971
972static int test_events(struct test__event_st *events, unsigned cnt)
973{
974 int ret1, ret2 = 0;
975 unsigned i;
976
977 for (i = 0; i < cnt; i++) {
978 struct test__event_st *e = &events[i];
979
980 pr_debug("running test %d '%s'\n", i, e->name);
981 ret1 = test_event(e);
982 if (ret1)
983 ret2 = ret1;
984 }
985
986 return ret2;
987}
988
989static int test_term(struct test__term *t)
990{
991 struct list_head *terms;
992 int ret;
993
994 terms = malloc(sizeof(*terms));
995 if (!terms)
996 return -ENOMEM;
997
998 INIT_LIST_HEAD(terms);
999
1000 ret = parse_events_terms(terms, t->str);
1001 if (ret) {
1002 pr_debug("failed to parse terms '%s', err %d\n",
1003 t->str , ret);
1004 return ret;
1005 }
1006
1007 ret = t->check(terms);
1008 parse_events__free_terms(terms);
1009
1010 return ret;
1011}
1012
1013static int test_terms(struct test__term *terms, unsigned cnt)
1014{
1015 int ret = 0;
1016 unsigned i;
1017
1018 for (i = 0; i < cnt; i++) {
1019 struct test__term *t = &terms[i];
1020
1021 pr_debug("running test %d '%s'\n", i, t->str);
1022 ret = test_term(t);
1023 if (ret)
1024 break;
1025 }
1026
1027 return ret;
1028}
1029
1030static int test_pmu(void)
1031{
1032 struct stat st;
1033 char path[PATH_MAX];
1034 int ret;
1035
1036 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
1037 sysfs_find_mountpoint());
1038
1039 ret = stat(path, &st);
1040 if (ret)
1041 pr_debug("omitting PMU cpu tests\n");
1042 return !ret;
1043}
1044
1045static int test_pmu_events(void)
1046{
1047 struct stat st;
1048 char path[PATH_MAX];
1049 struct dirent *ent;
1050 DIR *dir;
1051 int ret;
1052
1053 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/events/",
1054 sysfs_find_mountpoint());
1055
1056 ret = stat(path, &st);
1057 if (ret) {
1058 pr_debug("ommiting PMU cpu events tests\n");
1059 return 0;
1060 }
1061
1062 dir = opendir(path);
1063 if (!dir) {
1064 pr_debug("can't open pmu event dir");
1065 return -1;
1066 }
1067
1068 while (!ret && (ent = readdir(dir))) {
1069#define MAX_NAME 100
1070 struct test__event_st e;
1071 char name[MAX_NAME];
1072
1073 if (!strcmp(ent->d_name, ".") ||
1074 !strcmp(ent->d_name, ".."))
1075 continue;
1076
1077 snprintf(name, MAX_NAME, "cpu/event=%s/u", ent->d_name);
1078
1079 e.name = name;
1080 e.check = test__checkevent_pmu_events;
1081
1082 ret = test_event(&e);
1083#undef MAX_NAME
1084 }
1085
1086 closedir(dir);
1087 return ret;
1088}
1089
1090int test__parse_events(void)
1091{
1092 int ret1, ret2 = 0;
1093
1094#define TEST_EVENTS(tests) \
1095do { \
1096 ret1 = test_events(tests, ARRAY_SIZE(tests)); \
1097 if (!ret2) \
1098 ret2 = ret1; \
1099} while (0)
1100
1101 TEST_EVENTS(test__events);
1102
1103 if (test_pmu())
1104 TEST_EVENTS(test__events_pmu);
1105
1106 if (test_pmu()) {
1107 int ret = test_pmu_events();
1108 if (ret)
1109 return ret;
1110 }
1111
1112 ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms));
1113 if (!ret2)
1114 ret2 = ret1;
1115
1116 return ret2;
1117}
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
deleted file mode 100644
index 70e0d4421df..00000000000
--- a/tools/perf/tests/perf-record.c
+++ /dev/null
@@ -1,312 +0,0 @@
1#include <sched.h>
2#include "evlist.h"
3#include "evsel.h"
4#include "perf.h"
5#include "debug.h"
6#include "tests.h"
7
8static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp)
9{
10 int i, cpu = -1, nrcpus = 1024;
11realloc:
12 CPU_ZERO(maskp);
13
14 if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) {
15 if (errno == EINVAL && nrcpus < (1024 << 8)) {
16 nrcpus = nrcpus << 2;
17 goto realloc;
18 }
19 perror("sched_getaffinity");
20 return -1;
21 }
22
23 for (i = 0; i < nrcpus; i++) {
24 if (CPU_ISSET(i, maskp)) {
25 if (cpu == -1)
26 cpu = i;
27 else
28 CPU_CLR(i, maskp);
29 }
30 }
31
32 return cpu;
33}
34
35int test__PERF_RECORD(void)
36{
37 struct perf_record_opts opts = {
38 .target = {
39 .uid = UINT_MAX,
40 .uses_mmap = true,
41 },
42 .no_delay = true,
43 .freq = 10,
44 .mmap_pages = 256,
45 };
46 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
49 struct perf_evsel *evsel;
50 struct perf_sample sample;
51 const char *cmd = "sleep";
52 const char *argv[] = { cmd, "1", NULL, };
53 char *bname;
54 u64 prev_time = 0;
55 bool found_cmd_mmap = false,
56 found_libc_mmap = false,
57 found_vdso_mmap = false,
58 found_ld_mmap = false;
59 int err = -1, errs = 0, i, wakeups = 0;
60 u32 cpu;
61 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
62
63 if (evlist == NULL || argv == NULL) {
64 pr_debug("Not enough memory to create evlist\n");
65 goto out;
66 }
67
68 /*
69 * We need at least one evsel in the evlist, use the default
70 * one: "cycles".
71 */
72 err = perf_evlist__add_default(evlist);
73 if (err < 0) {
74 pr_debug("Not enough memory to create evsel\n");
75 goto out_delete_evlist;
76 }
77
78 /*
79 * Create maps of threads and cpus to monitor. In this case
80 * we start with all threads and cpus (-1, -1) but then in
81 * perf_evlist__prepare_workload we'll fill in the only thread
82 * we're monitoring, the one forked there.
83 */
84 err = perf_evlist__create_maps(evlist, &opts.target);
85 if (err < 0) {
86 pr_debug("Not enough memory to create thread/cpu maps\n");
87 goto out_delete_evlist;
88 }
89
90 /*
91 * Prepare the workload in argv[] to run, it'll fork it, and then wait
92 * for perf_evlist__start_workload() to exec it. This is done this way
93 * so that we have time to open the evlist (calling sys_perf_event_open
94 * on all the fds) and then mmap them.
95 */
96 err = perf_evlist__prepare_workload(evlist, &opts, argv);
97 if (err < 0) {
98 pr_debug("Couldn't run the workload!\n");
99 goto out_delete_evlist;
100 }
101
102 /*
103 * Config the evsels, setting attr->comm on the first one, etc.
104 */
105 evsel = perf_evlist__first(evlist);
106 evsel->attr.sample_type |= PERF_SAMPLE_CPU;
107 evsel->attr.sample_type |= PERF_SAMPLE_TID;
108 evsel->attr.sample_type |= PERF_SAMPLE_TIME;
109 perf_evlist__config_attrs(evlist, &opts);
110
111 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
112 if (err < 0) {
113 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
114 goto out_delete_evlist;
115 }
116
117 cpu = err;
118
119 /*
120 * So that we can check perf_sample.cpu on all the samples.
121 */
122 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
123 pr_debug("sched_setaffinity: %s\n", strerror(errno));
124 goto out_delete_evlist;
125 }
126
127 /*
128 * Call sys_perf_event_open on all the fds on all the evsels,
129 * grouping them if asked to.
130 */
131 err = perf_evlist__open(evlist);
132 if (err < 0) {
133 pr_debug("perf_evlist__open: %s\n", strerror(errno));
134 goto out_delete_evlist;
135 }
136
137 /*
138 * mmap the first fd on a given CPU and ask for events for the other
139 * fds in the same CPU to be injected in the same mmap ring buffer
140 * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
141 */
142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
143 if (err < 0) {
144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
145 goto out_delete_evlist;
146 }
147
148 /*
149 * Now that all is properly set up, enable the events, they will
150 * count just on workload.pid, which will start...
151 */
152 perf_evlist__enable(evlist);
153
154 /*
155 * Now!
156 */
157 perf_evlist__start_workload(evlist);
158
159 while (1) {
160 int before = total_events;
161
162 for (i = 0; i < evlist->nr_mmaps; i++) {
163 union perf_event *event;
164
165 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
166 const u32 type = event->header.type;
167 const char *name = perf_event__name(type);
168
169 ++total_events;
170 if (type < PERF_RECORD_MAX)
171 nr_events[type]++;
172
173 err = perf_evlist__parse_sample(evlist, event, &sample);
174 if (err < 0) {
175 if (verbose)
176 perf_event__fprintf(event, stderr);
177 pr_debug("Couldn't parse sample\n");
178 goto out_err;
179 }
180
181 if (verbose) {
182 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
183 perf_event__fprintf(event, stderr);
184 }
185
186 if (prev_time > sample.time) {
187 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
188 name, prev_time, sample.time);
189 ++errs;
190 }
191
192 prev_time = sample.time;
193
194 if (sample.cpu != cpu) {
195 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
196 name, cpu, sample.cpu);
197 ++errs;
198 }
199
200 if ((pid_t)sample.pid != evlist->workload.pid) {
201 pr_debug("%s with unexpected pid, expected %d, got %d\n",
202 name, evlist->workload.pid, sample.pid);
203 ++errs;
204 }
205
206 if ((pid_t)sample.tid != evlist->workload.pid) {
207 pr_debug("%s with unexpected tid, expected %d, got %d\n",
208 name, evlist->workload.pid, sample.tid);
209 ++errs;
210 }
211
212 if ((type == PERF_RECORD_COMM ||
213 type == PERF_RECORD_MMAP ||
214 type == PERF_RECORD_FORK ||
215 type == PERF_RECORD_EXIT) &&
216 (pid_t)event->comm.pid != evlist->workload.pid) {
217 pr_debug("%s with unexpected pid/tid\n", name);
218 ++errs;
219 }
220
221 if ((type == PERF_RECORD_COMM ||
222 type == PERF_RECORD_MMAP) &&
223 event->comm.pid != event->comm.tid) {
224 pr_debug("%s with different pid/tid!\n", name);
225 ++errs;
226 }
227
228 switch (type) {
229 case PERF_RECORD_COMM:
230 if (strcmp(event->comm.comm, cmd)) {
231 pr_debug("%s with unexpected comm!\n", name);
232 ++errs;
233 }
234 break;
235 case PERF_RECORD_EXIT:
236 goto found_exit;
237 case PERF_RECORD_MMAP:
238 bname = strrchr(event->mmap.filename, '/');
239 if (bname != NULL) {
240 if (!found_cmd_mmap)
241 found_cmd_mmap = !strcmp(bname + 1, cmd);
242 if (!found_libc_mmap)
243 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
244 if (!found_ld_mmap)
245 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
246 } else if (!found_vdso_mmap)
247 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
248 break;
249
250 case PERF_RECORD_SAMPLE:
251 /* Just ignore samples for now */
252 break;
253 default:
254 pr_debug("Unexpected perf_event->header.type %d!\n",
255 type);
256 ++errs;
257 }
258 }
259 }
260
261 /*
262 * We don't use poll here because at least at 3.1 times the
263 * PERF_RECORD_{!SAMPLE} events don't honour
264 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
265 */
266 if (total_events == before && false)
267 poll(evlist->pollfd, evlist->nr_fds, -1);
268
269 sleep(1);
270 if (++wakeups > 5) {
271 pr_debug("No PERF_RECORD_EXIT event!\n");
272 break;
273 }
274 }
275
276found_exit:
277 if (nr_events[PERF_RECORD_COMM] > 1) {
278 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
279 ++errs;
280 }
281
282 if (nr_events[PERF_RECORD_COMM] == 0) {
283 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
284 ++errs;
285 }
286
287 if (!found_cmd_mmap) {
288 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
289 ++errs;
290 }
291
292 if (!found_libc_mmap) {
293 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
294 ++errs;
295 }
296
297 if (!found_ld_mmap) {
298 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
299 ++errs;
300 }
301
302 if (!found_vdso_mmap) {
303 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
304 ++errs;
305 }
306out_err:
307 perf_evlist__munmap(evlist);
308out_delete_evlist:
309 perf_evlist__delete(evlist);
310out:
311 return (err < 0 || errs > 0) ? -1 : 0;
312}
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
deleted file mode 100644
index a5f379863b8..00000000000
--- a/tools/perf/tests/pmu.c
+++ /dev/null
@@ -1,178 +0,0 @@
1#include "parse-events.h"
2#include "pmu.h"
3#include "util.h"
4#include "tests.h"
5
6/* Simulated format definitions. */
7static struct test_format {
8 const char *name;
9 const char *value;
10} test_formats[] = {
11 { "krava01", "config:0-1,62-63\n", },
12 { "krava02", "config:10-17\n", },
13 { "krava03", "config:5\n", },
14 { "krava11", "config1:0,2,4,6,8,20-28\n", },
15 { "krava12", "config1:63\n", },
16 { "krava13", "config1:45-47\n", },
17 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
18 { "krava22", "config2:8,18,48,58\n", },
19 { "krava23", "config2:28-29,38\n", },
20};
21
22#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
23
24/* Simulated users input. */
25static struct parse_events__term test_terms[] = {
26 {
27 .config = (char *) "krava01",
28 .val.num = 15,
29 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
30 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
31 },
32 {
33 .config = (char *) "krava02",
34 .val.num = 170,
35 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
36 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
37 },
38 {
39 .config = (char *) "krava03",
40 .val.num = 1,
41 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
42 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
43 },
44 {
45 .config = (char *) "krava11",
46 .val.num = 27,
47 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
48 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
49 },
50 {
51 .config = (char *) "krava12",
52 .val.num = 1,
53 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
54 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
55 },
56 {
57 .config = (char *) "krava13",
58 .val.num = 2,
59 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
60 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
61 },
62 {
63 .config = (char *) "krava21",
64 .val.num = 119,
65 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
66 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
67 },
68 {
69 .config = (char *) "krava22",
70 .val.num = 11,
71 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
72 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
73 },
74 {
75 .config = (char *) "krava23",
76 .val.num = 2,
77 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
78 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
79 },
80};
81#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
82
83/*
84 * Prepare format directory data, exported by kernel
85 * at /sys/bus/event_source/devices/<dev>/format.
86 */
87static char *test_format_dir_get(void)
88{
89 static char dir[PATH_MAX];
90 unsigned int i;
91
92 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
93 if (!mkdtemp(dir))
94 return NULL;
95
96 for (i = 0; i < TEST_FORMATS_CNT; i++) {
97 static char name[PATH_MAX];
98 struct test_format *format = &test_formats[i];
99 FILE *file;
100
101 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
102
103 file = fopen(name, "w");
104 if (!file)
105 return NULL;
106
107 if (1 != fwrite(format->value, strlen(format->value), 1, file))
108 break;
109
110 fclose(file);
111 }
112
113 return dir;
114}
115
116/* Cleanup format directory. */
117static int test_format_dir_put(char *dir)
118{
119 char buf[PATH_MAX];
120 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
121 if (system(buf))
122 return -1;
123
124 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
125 return system(buf);
126}
127
128static struct list_head *test_terms_list(void)
129{
130 static LIST_HEAD(terms);
131 unsigned int i;
132
133 for (i = 0; i < TERMS_CNT; i++)
134 list_add_tail(&test_terms[i].list, &terms);
135
136 return &terms;
137}
138
139#undef TERMS_CNT
140
141int test__pmu(void)
142{
143 char *format = test_format_dir_get();
144 LIST_HEAD(formats);
145 struct list_head *terms = test_terms_list();
146 int ret;
147
148 if (!format)
149 return -EINVAL;
150
151 do {
152 struct perf_event_attr attr;
153
154 memset(&attr, 0, sizeof(attr));
155
156 ret = perf_pmu__format_parse(format, &formats);
157 if (ret)
158 break;
159
160 ret = perf_pmu__config_terms(&formats, &attr, terms);
161 if (ret)
162 break;
163
164 ret = -EINVAL;
165
166 if (attr.config != 0xc00000000002a823)
167 break;
168 if (attr.config1 != 0x8000400000000145)
169 break;
170 if (attr.config2 != 0x0400000020041d07)
171 break;
172
173 ret = 0;
174 } while (0);
175
176 test_format_dir_put(format);
177 return ret;
178}
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
deleted file mode 100644
index ff94886aad9..00000000000
--- a/tools/perf/tests/rdpmc.c
+++ /dev/null
@@ -1,175 +0,0 @@
1#include <unistd.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <sys/mman.h>
5#include "types.h"
6#include "perf.h"
7#include "debug.h"
8#include "tests.h"
9
10#if defined(__x86_64__) || defined(__i386__)
11
12#define barrier() asm volatile("" ::: "memory")
13
14static u64 rdpmc(unsigned int counter)
15{
16 unsigned int low, high;
17
18 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
19
20 return low | ((u64)high) << 32;
21}
22
23static u64 rdtsc(void)
24{
25 unsigned int low, high;
26
27 asm volatile("rdtsc" : "=a" (low), "=d" (high));
28
29 return low | ((u64)high) << 32;
30}
31
32static u64 mmap_read_self(void *addr)
33{
34 struct perf_event_mmap_page *pc = addr;
35 u32 seq, idx, time_mult = 0, time_shift = 0;
36 u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
37
38 do {
39 seq = pc->lock;
40 barrier();
41
42 enabled = pc->time_enabled;
43 running = pc->time_running;
44
45 if (enabled != running) {
46 cyc = rdtsc();
47 time_mult = pc->time_mult;
48 time_shift = pc->time_shift;
49 time_offset = pc->time_offset;
50 }
51
52 idx = pc->index;
53 count = pc->offset;
54 if (idx)
55 count += rdpmc(idx - 1);
56
57 barrier();
58 } while (pc->lock != seq);
59
60 if (enabled != running) {
61 u64 quot, rem;
62
63 quot = (cyc >> time_shift);
64 rem = cyc & ((1 << time_shift) - 1);
65 delta = time_offset + quot * time_mult +
66 ((rem * time_mult) >> time_shift);
67
68 enabled += delta;
69 if (idx)
70 running += delta;
71
72 quot = count / running;
73 rem = count % running;
74 count = quot * enabled + (rem * enabled) / running;
75 }
76
77 return count;
78}
79
80/*
81 * If the RDPMC instruction faults then signal this back to the test parent task:
82 */
83static void segfault_handler(int sig __maybe_unused,
84 siginfo_t *info __maybe_unused,
85 void *uc __maybe_unused)
86{
87 exit(-1);
88}
89
90static int __test__rdpmc(void)
91{
92 volatile int tmp = 0;
93 u64 i, loops = 1000;
94 int n;
95 int fd;
96 void *addr;
97 struct perf_event_attr attr = {
98 .type = PERF_TYPE_HARDWARE,
99 .config = PERF_COUNT_HW_INSTRUCTIONS,
100 .exclude_kernel = 1,
101 };
102 u64 delta_sum = 0;
103 struct sigaction sa;
104
105 sigfillset(&sa.sa_mask);
106 sa.sa_sigaction = segfault_handler;
107 sigaction(SIGSEGV, &sa, NULL);
108
109 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
110 if (fd < 0) {
111 pr_err("Error: sys_perf_event_open() syscall returned "
112 "with %d (%s)\n", fd, strerror(errno));
113 return -1;
114 }
115
116 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
117 if (addr == (void *)(-1)) {
118 pr_err("Error: mmap() syscall returned with (%s)\n",
119 strerror(errno));
120 goto out_close;
121 }
122
123 for (n = 0; n < 6; n++) {
124 u64 stamp, now, delta;
125
126 stamp = mmap_read_self(addr);
127
128 for (i = 0; i < loops; i++)
129 tmp++;
130
131 now = mmap_read_self(addr);
132 loops *= 10;
133
134 delta = now - stamp;
135 pr_debug("%14d: %14Lu\n", n, (long long)delta);
136
137 delta_sum += delta;
138 }
139
140 munmap(addr, page_size);
141 pr_debug(" ");
142out_close:
143 close(fd);
144
145 if (!delta_sum)
146 return -1;
147
148 return 0;
149}
150
151int test__rdpmc(void)
152{
153 int status = 0;
154 int wret = 0;
155 int ret;
156 int pid;
157
158 pid = fork();
159 if (pid < 0)
160 return -1;
161
162 if (!pid) {
163 ret = __test__rdpmc();
164
165 exit(ret);
166 }
167
168 wret = waitpid(pid, &status, 0);
169 if (wret < 0 || status)
170 return -1;
171
172 return 0;
173}
174
175#endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
deleted file mode 100644
index fc121edab01..00000000000
--- a/tools/perf/tests/tests.h
+++ /dev/null
@@ -1,22 +0,0 @@
1#ifndef TESTS_H
2#define TESTS_H
3
4/* Tests */
5int test__vmlinux_matches_kallsyms(void);
6int test__open_syscall_event(void);
7int test__open_syscall_event_on_all_cpus(void);
8int test__basic_mmap(void);
9int test__PERF_RECORD(void);
10int test__rdpmc(void);
11int test__perf_evsel__roundtrip_name_test(void);
12int test__perf_evsel__tp_sched_test(void);
13int test__syscall_open_tp_fields(void);
14int test__pmu(void);
15int test__attr(void);
16int test__dso_data(void);
17int test__parse_events(void);
18
19/* Util */
20int trace_event__id(const char *evname);
21
22#endif /* TESTS_H */
diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c
deleted file mode 100644
index 748f2e8f696..00000000000
--- a/tools/perf/tests/util.c
+++ /dev/null
@@ -1,30 +0,0 @@
1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include "tests.h"
8#include "debugfs.h"
9
10int trace_event__id(const char *evname)
11{
12 char *filename;
13 int err = -1, fd;
14
15 if (asprintf(&filename,
16 "%s/syscalls/%s/id",
17 tracing_events_path, evname) < 0)
18 return -1;
19
20 fd = open(filename, O_RDONLY);
21 if (fd >= 0) {
22 char id[16];
23 if (read(fd, id, sizeof(id)) > 0)
24 err = atoi(id);
25 close(fd);
26 }
27
28 free(filename);
29 return err;
30}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
deleted file mode 100644
index 4aeb7d5df93..00000000000
--- a/tools/perf/ui/browser.c
+++ /dev/null
@@ -1,714 +0,0 @@
1#include "../util.h"
2#include "../cache.h"
3#include "../../perf.h"
4#include "libslang.h"
5#include <newt.h>
6#include "ui.h"
7#include "util.h"
8#include <linux/compiler.h>
9#include <linux/list.h>
10#include <linux/rbtree.h>
11#include <stdlib.h>
12#include <sys/ttydefaults.h>
13#include "browser.h"
14#include "helpline.h"
15#include "keysyms.h"
16#include "../color.h"
17
18static int ui_browser__percent_color(struct ui_browser *browser,
19 double percent, bool current)
20{
21 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
22 return HE_COLORSET_SELECTED;
23 if (percent >= MIN_RED)
24 return HE_COLORSET_TOP;
25 if (percent >= MIN_GREEN)
26 return HE_COLORSET_MEDIUM;
27 return HE_COLORSET_NORMAL;
28}
29
30int ui_browser__set_color(struct ui_browser *browser, int color)
31{
32 int ret = browser->current_color;
33 browser->current_color = color;
34 SLsmg_set_color(color);
35 return ret;
36}
37
38void ui_browser__set_percent_color(struct ui_browser *browser,
39 double percent, bool current)
40{
41 int color = ui_browser__percent_color(browser, percent, current);
42 ui_browser__set_color(browser, color);
43}
44
45void ui_browser__gotorc(struct ui_browser *browser, int y, int x)
46{
47 SLsmg_gotorc(browser->y + y, browser->x + x);
48}
49
50static struct list_head *
51ui_browser__list_head_filter_entries(struct ui_browser *browser,
52 struct list_head *pos)
53{
54 do {
55 if (!browser->filter || !browser->filter(browser, pos))
56 return pos;
57 pos = pos->next;
58 } while (pos != browser->entries);
59
60 return NULL;
61}
62
63static struct list_head *
64ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
65 struct list_head *pos)
66{
67 do {
68 if (!browser->filter || !browser->filter(browser, pos))
69 return pos;
70 pos = pos->prev;
71 } while (pos != browser->entries);
72
73 return NULL;
74}
75
76void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence)
77{
78 struct list_head *head = browser->entries;
79 struct list_head *pos;
80
81 if (browser->nr_entries == 0)
82 return;
83
84 switch (whence) {
85 case SEEK_SET:
86 pos = ui_browser__list_head_filter_entries(browser, head->next);
87 break;
88 case SEEK_CUR:
89 pos = browser->top;
90 break;
91 case SEEK_END:
92 pos = ui_browser__list_head_filter_prev_entries(browser, head->prev);
93 break;
94 default:
95 return;
96 }
97
98 assert(pos != NULL);
99
100 if (offset > 0) {
101 while (offset-- != 0)
102 pos = ui_browser__list_head_filter_entries(browser, pos->next);
103 } else {
104 while (offset++ != 0)
105 pos = ui_browser__list_head_filter_prev_entries(browser, pos->prev);
106 }
107
108 browser->top = pos;
109}
110
111void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence)
112{
113 struct rb_root *root = browser->entries;
114 struct rb_node *nd;
115
116 switch (whence) {
117 case SEEK_SET:
118 nd = rb_first(root);
119 break;
120 case SEEK_CUR:
121 nd = browser->top;
122 break;
123 case SEEK_END:
124 nd = rb_last(root);
125 break;
126 default:
127 return;
128 }
129
130 if (offset > 0) {
131 while (offset-- != 0)
132 nd = rb_next(nd);
133 } else {
134 while (offset++ != 0)
135 nd = rb_prev(nd);
136 }
137
138 browser->top = nd;
139}
140
141unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
142{
143 struct rb_node *nd;
144 int row = 0;
145
146 if (browser->top == NULL)
147 browser->top = rb_first(browser->entries);
148
149 nd = browser->top;
150
151 while (nd != NULL) {
152 ui_browser__gotorc(browser, row, 0);
153 browser->write(browser, nd, row);
154 if (++row == browser->height)
155 break;
156 nd = rb_next(nd);
157 }
158
159 return row;
160}
161
162bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
163{
164 return browser->top_idx + row == browser->index;
165}
166
167void ui_browser__refresh_dimensions(struct ui_browser *browser)
168{
169 browser->width = SLtt_Screen_Cols - 1;
170 browser->height = SLtt_Screen_Rows - 2;
171 browser->y = 1;
172 browser->x = 0;
173}
174
175void ui_browser__handle_resize(struct ui_browser *browser)
176{
177 ui__refresh_dimensions(false);
178 ui_browser__show(browser, browser->title, ui_helpline__current);
179 ui_browser__refresh(browser);
180}
181
182int ui_browser__warning(struct ui_browser *browser, int timeout,
183 const char *format, ...)
184{
185 va_list args;
186 char *text;
187 int key = 0, err;
188
189 va_start(args, format);
190 err = vasprintf(&text, format, args);
191 va_end(args);
192
193 if (err < 0) {
194 va_start(args, format);
195 ui_helpline__vpush(format, args);
196 va_end(args);
197 } else {
198 while ((key == ui__question_window("Warning!", text,
199 "Press any key...",
200 timeout)) == K_RESIZE)
201 ui_browser__handle_resize(browser);
202 free(text);
203 }
204
205 return key;
206}
207
208int ui_browser__help_window(struct ui_browser *browser, const char *text)
209{
210 int key;
211
212 while ((key = ui__help_window(text)) == K_RESIZE)
213 ui_browser__handle_resize(browser);
214
215 return key;
216}
217
218bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
219{
220 int key;
221
222 while ((key = ui__dialog_yesno(text)) == K_RESIZE)
223 ui_browser__handle_resize(browser);
224
225 return key == K_ENTER || toupper(key) == 'Y';
226}
227
228void ui_browser__reset_index(struct ui_browser *browser)
229{
230 browser->index = browser->top_idx = 0;
231 browser->seek(browser, 0, SEEK_SET);
232}
233
234void __ui_browser__show_title(struct ui_browser *browser, const char *title)
235{
236 SLsmg_gotorc(0, 0);
237 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
238 slsmg_write_nstring(title, browser->width + 1);
239}
240
241void ui_browser__show_title(struct ui_browser *browser, const char *title)
242{
243 pthread_mutex_lock(&ui__lock);
244 __ui_browser__show_title(browser, title);
245 pthread_mutex_unlock(&ui__lock);
246}
247
248int ui_browser__show(struct ui_browser *browser, const char *title,
249 const char *helpline, ...)
250{
251 int err;
252 va_list ap;
253
254 ui_browser__refresh_dimensions(browser);
255
256 pthread_mutex_lock(&ui__lock);
257 __ui_browser__show_title(browser, title);
258
259 browser->title = title;
260 free(browser->helpline);
261 browser->helpline = NULL;
262
263 va_start(ap, helpline);
264 err = vasprintf(&browser->helpline, helpline, ap);
265 va_end(ap);
266 if (err > 0)
267 ui_helpline__push(browser->helpline);
268 pthread_mutex_unlock(&ui__lock);
269 return err ? 0 : -1;
270}
271
272void ui_browser__hide(struct ui_browser *browser __maybe_unused)
273{
274 pthread_mutex_lock(&ui__lock);
275 ui_helpline__pop();
276 pthread_mutex_unlock(&ui__lock);
277}
278
279static void ui_browser__scrollbar_set(struct ui_browser *browser)
280{
281 int height = browser->height, h = 0, pct = 0,
282 col = browser->width,
283 row = browser->y - 1;
284
285 if (browser->nr_entries > 1) {
286 pct = ((browser->index * (browser->height - 1)) /
287 (browser->nr_entries - 1));
288 }
289
290 SLsmg_set_char_set(1);
291
292 while (h < height) {
293 ui_browser__gotorc(browser, row++, col);
294 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
295 ++h;
296 }
297
298 SLsmg_set_char_set(0);
299}
300
301static int __ui_browser__refresh(struct ui_browser *browser)
302{
303 int row;
304 int width = browser->width;
305
306 row = browser->refresh(browser);
307 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
308
309 if (!browser->use_navkeypressed || browser->navkeypressed)
310 ui_browser__scrollbar_set(browser);
311 else
312 width += 1;
313
314 SLsmg_fill_region(browser->y + row, browser->x,
315 browser->height - row, width, ' ');
316
317 return 0;
318}
319
320int ui_browser__refresh(struct ui_browser *browser)
321{
322 pthread_mutex_lock(&ui__lock);
323 __ui_browser__refresh(browser);
324 pthread_mutex_unlock(&ui__lock);
325
326 return 0;
327}
328
329/*
330 * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
331 * forget about any reference to any entry in the underlying data structure,
332 * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
333 * after an output_resort and hist decay.
334 */
335void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
336{
337 off_t offset = nr_entries - browser->nr_entries;
338
339 browser->nr_entries = nr_entries;
340
341 if (offset < 0) {
342 if (browser->top_idx < (u64)-offset)
343 offset = -browser->top_idx;
344
345 browser->index += offset;
346 browser->top_idx += offset;
347 }
348
349 browser->top = NULL;
350 browser->seek(browser, browser->top_idx, SEEK_SET);
351}
352
353int ui_browser__run(struct ui_browser *browser, int delay_secs)
354{
355 int err, key;
356
357 while (1) {
358 off_t offset;
359
360 pthread_mutex_lock(&ui__lock);
361 err = __ui_browser__refresh(browser);
362 SLsmg_refresh();
363 pthread_mutex_unlock(&ui__lock);
364 if (err < 0)
365 break;
366
367 key = ui__getch(delay_secs);
368
369 if (key == K_RESIZE) {
370 ui__refresh_dimensions(false);
371 ui_browser__refresh_dimensions(browser);
372 __ui_browser__show_title(browser, browser->title);
373 ui_helpline__puts(browser->helpline);
374 continue;
375 }
376
377 if (browser->use_navkeypressed && !browser->navkeypressed) {
378 if (key == K_DOWN || key == K_UP ||
379 key == K_PGDN || key == K_PGUP ||
380 key == K_HOME || key == K_END ||
381 key == ' ') {
382 browser->navkeypressed = true;
383 continue;
384 } else
385 return key;
386 }
387
388 switch (key) {
389 case K_DOWN:
390 if (browser->index == browser->nr_entries - 1)
391 break;
392 ++browser->index;
393 if (browser->index == browser->top_idx + browser->height) {
394 ++browser->top_idx;
395 browser->seek(browser, +1, SEEK_CUR);
396 }
397 break;
398 case K_UP:
399 if (browser->index == 0)
400 break;
401 --browser->index;
402 if (browser->index < browser->top_idx) {
403 --browser->top_idx;
404 browser->seek(browser, -1, SEEK_CUR);
405 }
406 break;
407 case K_PGDN:
408 case ' ':
409 if (browser->top_idx + browser->height > browser->nr_entries - 1)
410 break;
411
412 offset = browser->height;
413 if (browser->index + offset > browser->nr_entries - 1)
414 offset = browser->nr_entries - 1 - browser->index;
415 browser->index += offset;
416 browser->top_idx += offset;
417 browser->seek(browser, +offset, SEEK_CUR);
418 break;
419 case K_PGUP:
420 if (browser->top_idx == 0)
421 break;
422
423 if (browser->top_idx < browser->height)
424 offset = browser->top_idx;
425 else
426 offset = browser->height;
427
428 browser->index -= offset;
429 browser->top_idx -= offset;
430 browser->seek(browser, -offset, SEEK_CUR);
431 break;
432 case K_HOME:
433 ui_browser__reset_index(browser);
434 break;
435 case K_END:
436 offset = browser->height - 1;
437 if (offset >= browser->nr_entries)
438 offset = browser->nr_entries - 1;
439
440 browser->index = browser->nr_entries - 1;
441 browser->top_idx = browser->index - offset;
442 browser->seek(browser, -offset, SEEK_END);
443 break;
444 default:
445 return key;
446 }
447 }
448 return -1;
449}
450
451unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
452{
453 struct list_head *pos;
454 struct list_head *head = browser->entries;
455 int row = 0;
456
457 if (browser->top == NULL || browser->top == browser->entries)
458 browser->top = ui_browser__list_head_filter_entries(browser, head->next);
459
460 pos = browser->top;
461
462 list_for_each_from(pos, head) {
463 if (!browser->filter || !browser->filter(browser, pos)) {
464 ui_browser__gotorc(browser, row, 0);
465 browser->write(browser, pos, row);
466 if (++row == browser->height)
467 break;
468 }
469 }
470
471 return row;
472}
473
474static struct ui_browser__colorset {
475 const char *name, *fg, *bg;
476 int colorset;
477} ui_browser__colorsets[] = {
478 {
479 .colorset = HE_COLORSET_TOP,
480 .name = "top",
481 .fg = "red",
482 .bg = "default",
483 },
484 {
485 .colorset = HE_COLORSET_MEDIUM,
486 .name = "medium",
487 .fg = "green",
488 .bg = "default",
489 },
490 {
491 .colorset = HE_COLORSET_NORMAL,
492 .name = "normal",
493 .fg = "default",
494 .bg = "default",
495 },
496 {
497 .colorset = HE_COLORSET_SELECTED,
498 .name = "selected",
499 .fg = "black",
500 .bg = "lightgray",
501 },
502 {
503 .colorset = HE_COLORSET_CODE,
504 .name = "code",
505 .fg = "blue",
506 .bg = "default",
507 },
508 {
509 .colorset = HE_COLORSET_ADDR,
510 .name = "addr",
511 .fg = "magenta",
512 .bg = "default",
513 },
514 {
515 .name = NULL,
516 }
517};
518
519
520static int ui_browser__color_config(const char *var, const char *value,
521 void *data __maybe_unused)
522{
523 char *fg = NULL, *bg;
524 int i;
525
526 /* same dir for all commands */
527 if (prefixcmp(var, "colors.") != 0)
528 return 0;
529
530 for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
531 const char *name = var + 7;
532
533 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
534 continue;
535
536 fg = strdup(value);
537 if (fg == NULL)
538 break;
539
540 bg = strchr(fg, ',');
541 if (bg == NULL)
542 break;
543
544 *bg = '\0';
545 while (isspace(*++bg));
546 ui_browser__colorsets[i].bg = bg;
547 ui_browser__colorsets[i].fg = fg;
548 return 0;
549 }
550
551 free(fg);
552 return -1;
553}
554
555void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
556{
557 switch (whence) {
558 case SEEK_SET:
559 browser->top = browser->entries;
560 break;
561 case SEEK_CUR:
562 browser->top = browser->top + browser->top_idx + offset;
563 break;
564 case SEEK_END:
565 browser->top = browser->top + browser->nr_entries + offset;
566 break;
567 default:
568 return;
569 }
570}
571
572unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
573{
574 unsigned int row = 0, idx = browser->top_idx;
575 char **pos;
576
577 if (browser->top == NULL)
578 browser->top = browser->entries;
579
580 pos = (char **)browser->top;
581 while (idx < browser->nr_entries) {
582 if (!browser->filter || !browser->filter(browser, *pos)) {
583 ui_browser__gotorc(browser, row, 0);
584 browser->write(browser, pos, row);
585 if (++row == browser->height)
586 break;
587 }
588
589 ++idx;
590 ++pos;
591 }
592
593 return row;
594}
595
596void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
597 u16 start, u16 end)
598{
599 SLsmg_set_char_set(1);
600 ui_browser__gotorc(browser, start, column);
601 SLsmg_draw_vline(end - start + 1);
602 SLsmg_set_char_set(0);
603}
604
605void ui_browser__write_graph(struct ui_browser *browser __maybe_unused,
606 int graph)
607{
608 SLsmg_set_char_set(1);
609 SLsmg_write_char(graph);
610 SLsmg_set_char_set(0);
611}
612
613static void __ui_browser__line_arrow_up(struct ui_browser *browser,
614 unsigned int column,
615 u64 start, u64 end)
616{
617 unsigned int row, end_row;
618
619 SLsmg_set_char_set(1);
620
621 if (start < browser->top_idx + browser->height) {
622 row = start - browser->top_idx;
623 ui_browser__gotorc(browser, row, column);
624 SLsmg_write_char(SLSMG_LLCORN_CHAR);
625 ui_browser__gotorc(browser, row, column + 1);
626 SLsmg_draw_hline(2);
627
628 if (row-- == 0)
629 goto out;
630 } else
631 row = browser->height - 1;
632
633 if (end > browser->top_idx)
634 end_row = end - browser->top_idx;
635 else
636 end_row = 0;
637
638 ui_browser__gotorc(browser, end_row, column);
639 SLsmg_draw_vline(row - end_row + 1);
640
641 ui_browser__gotorc(browser, end_row, column);
642 if (end >= browser->top_idx) {
643 SLsmg_write_char(SLSMG_ULCORN_CHAR);
644 ui_browser__gotorc(browser, end_row, column + 1);
645 SLsmg_write_char(SLSMG_HLINE_CHAR);
646 ui_browser__gotorc(browser, end_row, column + 2);
647 SLsmg_write_char(SLSMG_RARROW_CHAR);
648 }
649out:
650 SLsmg_set_char_set(0);
651}
652
653static void __ui_browser__line_arrow_down(struct ui_browser *browser,
654 unsigned int column,
655 u64 start, u64 end)
656{
657 unsigned int row, end_row;
658
659 SLsmg_set_char_set(1);
660
661 if (start >= browser->top_idx) {
662 row = start - browser->top_idx;
663 ui_browser__gotorc(browser, row, column);
664 SLsmg_write_char(SLSMG_ULCORN_CHAR);
665 ui_browser__gotorc(browser, row, column + 1);
666 SLsmg_draw_hline(2);
667
668 if (row++ == 0)
669 goto out;
670 } else
671 row = 0;
672
673 if (end >= browser->top_idx + browser->height)
674 end_row = browser->height - 1;
675 else
676 end_row = end - browser->top_idx;;
677
678 ui_browser__gotorc(browser, row, column);
679 SLsmg_draw_vline(end_row - row + 1);
680
681 ui_browser__gotorc(browser, end_row, column);
682 if (end < browser->top_idx + browser->height) {
683 SLsmg_write_char(SLSMG_LLCORN_CHAR);
684 ui_browser__gotorc(browser, end_row, column + 1);
685 SLsmg_write_char(SLSMG_HLINE_CHAR);
686 ui_browser__gotorc(browser, end_row, column + 2);
687 SLsmg_write_char(SLSMG_RARROW_CHAR);
688 }
689out:
690 SLsmg_set_char_set(0);
691}
692
693void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
694 u64 start, u64 end)
695{
696 if (start > end)
697 __ui_browser__line_arrow_up(browser, column, start, end);
698 else
699 __ui_browser__line_arrow_down(browser, column, start, end);
700}
701
702void ui_browser__init(void)
703{
704 int i = 0;
705
706 perf_config(ui_browser__color_config, NULL);
707
708 while (ui_browser__colorsets[i].name) {
709 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
710 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
711 }
712
713 annotate_browser__init();
714}
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
deleted file mode 100644
index af70314605e..00000000000
--- a/tools/perf/ui/browser.h
+++ /dev/null
@@ -1,73 +0,0 @@
1#ifndef _PERF_UI_BROWSER_H_
2#define _PERF_UI_BROWSER_H_ 1
3
4#include <stdbool.h>
5#include <sys/types.h>
6#include "../types.h"
7
8#define HE_COLORSET_TOP 50
9#define HE_COLORSET_MEDIUM 51
10#define HE_COLORSET_NORMAL 52
11#define HE_COLORSET_SELECTED 53
12#define HE_COLORSET_CODE 54
13#define HE_COLORSET_ADDR 55
14
15struct ui_browser {
16 u64 index, top_idx;
17 void *top, *entries;
18 u16 y, x, width, height;
19 int current_color;
20 void *priv;
21 const char *title;
22 char *helpline;
23 unsigned int (*refresh)(struct ui_browser *self);
24 void (*write)(struct ui_browser *self, void *entry, int row);
25 void (*seek)(struct ui_browser *self, off_t offset, int whence);
26 bool (*filter)(struct ui_browser *self, void *entry);
27 u32 nr_entries;
28 bool navkeypressed;
29 bool use_navkeypressed;
30};
31
32int ui_browser__set_color(struct ui_browser *browser, int color);
33void ui_browser__set_percent_color(struct ui_browser *self,
34 double percent, bool current);
35bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
36void ui_browser__refresh_dimensions(struct ui_browser *self);
37void ui_browser__reset_index(struct ui_browser *self);
38
39void ui_browser__gotorc(struct ui_browser *self, int y, int x);
40void ui_browser__write_graph(struct ui_browser *browser, int graph);
41void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
42 u64 start, u64 end);
43void __ui_browser__show_title(struct ui_browser *browser, const char *title);
44void ui_browser__show_title(struct ui_browser *browser, const char *title);
45int ui_browser__show(struct ui_browser *self, const char *title,
46 const char *helpline, ...);
47void ui_browser__hide(struct ui_browser *self);
48int ui_browser__refresh(struct ui_browser *self);
49int ui_browser__run(struct ui_browser *browser, int delay_secs);
50void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
51void ui_browser__handle_resize(struct ui_browser *browser);
52void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
53 u16 start, u16 end);
54
55int ui_browser__warning(struct ui_browser *browser, int timeout,
56 const char *format, ...);
57int ui_browser__help_window(struct ui_browser *browser, const char *text);
58bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
59int ui_browser__input_window(const char *title, const char *text, char *input,
60 const char *exit_msg, int delay_sec);
61
62void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
63unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
64
65void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
66unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
67
68void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
69unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
70
71void ui_browser__init(void);
72void annotate_browser__init(void);
73#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
deleted file mode 100644
index 5dab3ca9698..00000000000
--- a/tools/perf/ui/browsers/annotate.c
+++ /dev/null
@@ -1,970 +0,0 @@
1#include "../../util/util.h"
2#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
7#include "../../util/annotate.h"
8#include "../../util/hist.h"
9#include "../../util/sort.h"
10#include "../../util/symbol.h"
11#include <pthread.h>
12#include <newt.h>
13
14struct browser_disasm_line {
15 struct rb_node rb_node;
16 double percent;
17 u32 idx;
18 int idx_asm;
19 int jump_sources;
20};
21
22static struct annotate_browser_opt {
23 bool hide_src_code,
24 use_offset,
25 jump_arrows,
26 show_nr_jumps;
27} annotate_browser__opts = {
28 .use_offset = true,
29 .jump_arrows = true,
30};
31
32struct annotate_browser {
33 struct ui_browser b;
34 struct rb_root entries;
35 struct rb_node *curr_hot;
36 struct disasm_line *selection;
37 struct disasm_line **offsets;
38 u64 start;
39 int nr_asm_entries;
40 int nr_entries;
41 int max_jump_sources;
42 int nr_jumps;
43 bool searching_backwards;
44 u8 addr_width;
45 u8 jumps_width;
46 u8 target_width;
47 u8 min_addr_width;
48 u8 max_addr_width;
49 char search_bf[128];
50};
51
52static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
53{
54 return (struct browser_disasm_line *)(dl + 1);
55}
56
57static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
58 void *entry)
59{
60 if (annotate_browser__opts.hide_src_code) {
61 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
62 return dl->offset == -1;
63 }
64
65 return false;
66}
67
68static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
69 int nr, bool current)
70{
71 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
72 return HE_COLORSET_SELECTED;
73 if (nr == browser->max_jump_sources)
74 return HE_COLORSET_TOP;
75 if (nr > 1)
76 return HE_COLORSET_MEDIUM;
77 return HE_COLORSET_NORMAL;
78}
79
80static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
81 int nr, bool current)
82{
83 int color = annotate_browser__jumps_percent_color(browser, nr, current);
84 return ui_browser__set_color(&browser->b, color);
85}
86
87static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
88{
89 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
90 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
91 struct browser_disasm_line *bdl = disasm_line__browser(dl);
92 bool current_entry = ui_browser__is_current_entry(browser, row);
93 bool change_color = (!annotate_browser__opts.hide_src_code &&
94 (!current_entry || (browser->use_navkeypressed &&
95 !browser->navkeypressed)));
96 int width = browser->width, printed;
97 char bf[256];
98
99 if (dl->offset != -1 && bdl->percent != 0.0) {
100 ui_browser__set_percent_color(browser, bdl->percent, current_entry);
101 slsmg_printf("%6.2f ", bdl->percent);
102 } else {
103 ui_browser__set_percent_color(browser, 0, current_entry);
104 slsmg_write_nstring(" ", 7);
105 }
106
107 SLsmg_write_char(' ');
108
109 /* The scroll bar isn't being used */
110 if (!browser->navkeypressed)
111 width += 1;
112
113 if (!*dl->line)
114 slsmg_write_nstring(" ", width - 7);
115 else if (dl->offset == -1) {
116 printed = scnprintf(bf, sizeof(bf), "%*s ",
117 ab->addr_width, " ");
118 slsmg_write_nstring(bf, printed);
119 slsmg_write_nstring(dl->line, width - printed - 6);
120 } else {
121 u64 addr = dl->offset;
122 int color = -1;
123
124 if (!annotate_browser__opts.use_offset)
125 addr += ab->start;
126
127 if (!annotate_browser__opts.use_offset) {
128 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
129 } else {
130 if (bdl->jump_sources) {
131 if (annotate_browser__opts.show_nr_jumps) {
132 int prev;
133 printed = scnprintf(bf, sizeof(bf), "%*d ",
134 ab->jumps_width,
135 bdl->jump_sources);
136 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
137 current_entry);
138 slsmg_write_nstring(bf, printed);
139 ui_browser__set_color(browser, prev);
140 }
141
142 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
143 ab->target_width, addr);
144 } else {
145 printed = scnprintf(bf, sizeof(bf), "%*s ",
146 ab->addr_width, " ");
147 }
148 }
149
150 if (change_color)
151 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
152 slsmg_write_nstring(bf, printed);
153 if (change_color)
154 ui_browser__set_color(browser, color);
155 if (dl->ins && dl->ins->ops->scnprintf) {
156 if (ins__is_jump(dl->ins)) {
157 bool fwd = dl->ops.target.offset > (u64)dl->offset;
158
159 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
160 SLSMG_UARROW_CHAR);
161 SLsmg_write_char(' ');
162 } else if (ins__is_call(dl->ins)) {
163 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
164 SLsmg_write_char(' ');
165 } else {
166 slsmg_write_nstring(" ", 2);
167 }
168 } else {
169 if (strcmp(dl->name, "retq")) {
170 slsmg_write_nstring(" ", 2);
171 } else {
172 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
173 SLsmg_write_char(' ');
174 }
175 }
176
177 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
178 slsmg_write_nstring(bf, width - 10 - printed);
179 }
180
181 if (current_entry)
182 ab->selection = dl;
183}
184
185static void annotate_browser__draw_current_jump(struct ui_browser *browser)
186{
187 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
188 struct disasm_line *cursor = ab->selection, *target;
189 struct browser_disasm_line *btarget, *bcursor;
190 unsigned int from, to;
191 struct map_symbol *ms = ab->b.priv;
192 struct symbol *sym = ms->sym;
193
194 /* PLT symbols contain external offsets */
195 if (strstr(sym->name, "@plt"))
196 return;
197
198 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
199 !disasm_line__has_offset(cursor))
200 return;
201
202 target = ab->offsets[cursor->ops.target.offset];
203 if (!target)
204 return;
205
206 bcursor = disasm_line__browser(cursor);
207 btarget = disasm_line__browser(target);
208
209 if (annotate_browser__opts.hide_src_code) {
210 from = bcursor->idx_asm;
211 to = btarget->idx_asm;
212 } else {
213 from = (u64)bcursor->idx;
214 to = (u64)btarget->idx;
215 }
216
217 ui_browser__set_color(browser, HE_COLORSET_CODE);
218 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
219}
220
221static unsigned int annotate_browser__refresh(struct ui_browser *browser)
222{
223 int ret = ui_browser__list_head_refresh(browser);
224
225 if (annotate_browser__opts.jump_arrows)
226 annotate_browser__draw_current_jump(browser);
227
228 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
229 __ui_browser__vline(browser, 7, 0, browser->height - 1);
230 return ret;
231}
232
233static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
234{
235 double percent = 0.0;
236
237 if (dl->offset != -1) {
238 int len = sym->end - sym->start;
239 unsigned int hits = 0;
240 struct annotation *notes = symbol__annotation(sym);
241 struct source_line *src_line = notes->src->lines;
242 struct sym_hist *h = annotation__histogram(notes, evidx);
243 s64 offset = dl->offset;
244 struct disasm_line *next;
245
246 next = disasm__get_next_ip_line(&notes->src->source, dl);
247 while (offset < (s64)len &&
248 (next == NULL || offset < next->offset)) {
249 if (src_line) {
250 percent += src_line[offset].percent;
251 } else
252 hits += h->addr[offset];
253
254 ++offset;
255 }
256 /*
257 * If the percentage wasn't already calculated in
258 * symbol__get_source_line, do it now:
259 */
260 if (src_line == NULL && h->sum)
261 percent = 100.0 * hits / h->sum;
262 }
263
264 return percent;
265}
266
267static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
268{
269 struct rb_node **p = &root->rb_node;
270 struct rb_node *parent = NULL;
271 struct browser_disasm_line *l;
272
273 while (*p != NULL) {
274 parent = *p;
275 l = rb_entry(parent, struct browser_disasm_line, rb_node);
276 if (bdl->percent < l->percent)
277 p = &(*p)->rb_left;
278 else
279 p = &(*p)->rb_right;
280 }
281 rb_link_node(&bdl->rb_node, parent, p);
282 rb_insert_color(&bdl->rb_node, root);
283}
284
285static void annotate_browser__set_top(struct annotate_browser *browser,
286 struct disasm_line *pos, u32 idx)
287{
288 unsigned back;
289
290 ui_browser__refresh_dimensions(&browser->b);
291 back = browser->b.height / 2;
292 browser->b.top_idx = browser->b.index = idx;
293
294 while (browser->b.top_idx != 0 && back != 0) {
295 pos = list_entry(pos->node.prev, struct disasm_line, node);
296
297 if (disasm_line__filter(&browser->b, &pos->node))
298 continue;
299
300 --browser->b.top_idx;
301 --back;
302 }
303
304 browser->b.top = pos;
305 browser->b.navkeypressed = true;
306}
307
308static void annotate_browser__set_rb_top(struct annotate_browser *browser,
309 struct rb_node *nd)
310{
311 struct browser_disasm_line *bpos;
312 struct disasm_line *pos;
313 u32 idx;
314
315 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
316 pos = ((struct disasm_line *)bpos) - 1;
317 idx = bpos->idx;
318 if (annotate_browser__opts.hide_src_code)
319 idx = bpos->idx_asm;
320 annotate_browser__set_top(browser, pos, idx);
321 browser->curr_hot = nd;
322}
323
324static void annotate_browser__calc_percent(struct annotate_browser *browser,
325 int evidx)
326{
327 struct map_symbol *ms = browser->b.priv;
328 struct symbol *sym = ms->sym;
329 struct annotation *notes = symbol__annotation(sym);
330 struct disasm_line *pos;
331
332 browser->entries = RB_ROOT;
333
334 pthread_mutex_lock(&notes->lock);
335
336 list_for_each_entry(pos, &notes->src->source, node) {
337 struct browser_disasm_line *bpos = disasm_line__browser(pos);
338 bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
339 if (bpos->percent < 0.01) {
340 RB_CLEAR_NODE(&bpos->rb_node);
341 continue;
342 }
343 disasm_rb_tree__insert(&browser->entries, bpos);
344 }
345 pthread_mutex_unlock(&notes->lock);
346
347 browser->curr_hot = rb_last(&browser->entries);
348}
349
350static bool annotate_browser__toggle_source(struct annotate_browser *browser)
351{
352 struct disasm_line *dl;
353 struct browser_disasm_line *bdl;
354 off_t offset = browser->b.index - browser->b.top_idx;
355
356 browser->b.seek(&browser->b, offset, SEEK_CUR);
357 dl = list_entry(browser->b.top, struct disasm_line, node);
358 bdl = disasm_line__browser(dl);
359
360 if (annotate_browser__opts.hide_src_code) {
361 if (bdl->idx_asm < offset)
362 offset = bdl->idx;
363
364 browser->b.nr_entries = browser->nr_entries;
365 annotate_browser__opts.hide_src_code = false;
366 browser->b.seek(&browser->b, -offset, SEEK_CUR);
367 browser->b.top_idx = bdl->idx - offset;
368 browser->b.index = bdl->idx;
369 } else {
370 if (bdl->idx_asm < 0) {
371 ui_helpline__puts("Only available for assembly lines.");
372 browser->b.seek(&browser->b, -offset, SEEK_CUR);
373 return false;
374 }
375
376 if (bdl->idx_asm < offset)
377 offset = bdl->idx_asm;
378
379 browser->b.nr_entries = browser->nr_asm_entries;
380 annotate_browser__opts.hide_src_code = true;
381 browser->b.seek(&browser->b, -offset, SEEK_CUR);
382 browser->b.top_idx = bdl->idx_asm - offset;
383 browser->b.index = bdl->idx_asm;
384 }
385
386 return true;
387}
388
389static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
390{
391 ui_browser__reset_index(&browser->b);
392 browser->b.nr_entries = browser->nr_asm_entries;
393}
394
395static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
396 struct hist_browser_timer *hbt)
397{
398 struct map_symbol *ms = browser->b.priv;
399 struct disasm_line *dl = browser->selection;
400 struct symbol *sym = ms->sym;
401 struct annotation *notes;
402 struct symbol *target;
403 u64 ip;
404
405 if (!ins__is_call(dl->ins))
406 return false;
407
408 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
409 target = map__find_symbol(ms->map, ip, NULL);
410 if (target == NULL) {
411 ui_helpline__puts("The called function was not found.");
412 return true;
413 }
414
415 notes = symbol__annotation(target);
416 pthread_mutex_lock(&notes->lock);
417
418 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
419 pthread_mutex_unlock(&notes->lock);
420 ui__warning("Not enough memory for annotating '%s' symbol!\n",
421 target->name);
422 return true;
423 }
424
425 pthread_mutex_unlock(&notes->lock);
426 symbol__tui_annotate(target, ms->map, evidx, hbt);
427 ui_browser__show_title(&browser->b, sym->name);
428 return true;
429}
430
431static
432struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
433 s64 offset, s64 *idx)
434{
435 struct map_symbol *ms = browser->b.priv;
436 struct symbol *sym = ms->sym;
437 struct annotation *notes = symbol__annotation(sym);
438 struct disasm_line *pos;
439
440 *idx = 0;
441 list_for_each_entry(pos, &notes->src->source, node) {
442 if (pos->offset == offset)
443 return pos;
444 if (!disasm_line__filter(&browser->b, &pos->node))
445 ++*idx;
446 }
447
448 return NULL;
449}
450
451static bool annotate_browser__jump(struct annotate_browser *browser)
452{
453 struct disasm_line *dl = browser->selection;
454 s64 idx;
455
456 if (!ins__is_jump(dl->ins))
457 return false;
458
459 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
460 if (dl == NULL) {
461 ui_helpline__puts("Invallid jump offset");
462 return true;
463 }
464
465 annotate_browser__set_top(browser, dl, idx);
466
467 return true;
468}
469
470static
471struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
472 char *s, s64 *idx)
473{
474 struct map_symbol *ms = browser->b.priv;
475 struct symbol *sym = ms->sym;
476 struct annotation *notes = symbol__annotation(sym);
477 struct disasm_line *pos = browser->selection;
478
479 *idx = browser->b.index;
480 list_for_each_entry_continue(pos, &notes->src->source, node) {
481 if (disasm_line__filter(&browser->b, &pos->node))
482 continue;
483
484 ++*idx;
485
486 if (pos->line && strstr(pos->line, s) != NULL)
487 return pos;
488 }
489
490 return NULL;
491}
492
493static bool __annotate_browser__search(struct annotate_browser *browser)
494{
495 struct disasm_line *dl;
496 s64 idx;
497
498 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
499 if (dl == NULL) {
500 ui_helpline__puts("String not found!");
501 return false;
502 }
503
504 annotate_browser__set_top(browser, dl, idx);
505 browser->searching_backwards = false;
506 return true;
507}
508
509static
510struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
511 char *s, s64 *idx)
512{
513 struct map_symbol *ms = browser->b.priv;
514 struct symbol *sym = ms->sym;
515 struct annotation *notes = symbol__annotation(sym);
516 struct disasm_line *pos = browser->selection;
517
518 *idx = browser->b.index;
519 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
520 if (disasm_line__filter(&browser->b, &pos->node))
521 continue;
522
523 --*idx;
524
525 if (pos->line && strstr(pos->line, s) != NULL)
526 return pos;
527 }
528
529 return NULL;
530}
531
532static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
533{
534 struct disasm_line *dl;
535 s64 idx;
536
537 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
538 if (dl == NULL) {
539 ui_helpline__puts("String not found!");
540 return false;
541 }
542
543 annotate_browser__set_top(browser, dl, idx);
544 browser->searching_backwards = true;
545 return true;
546}
547
548static bool annotate_browser__search_window(struct annotate_browser *browser,
549 int delay_secs)
550{
551 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
552 "ENTER: OK, ESC: Cancel",
553 delay_secs * 2) != K_ENTER ||
554 !*browser->search_bf)
555 return false;
556
557 return true;
558}
559
560static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
561{
562 if (annotate_browser__search_window(browser, delay_secs))
563 return __annotate_browser__search(browser);
564
565 return false;
566}
567
568static bool annotate_browser__continue_search(struct annotate_browser *browser,
569 int delay_secs)
570{
571 if (!*browser->search_bf)
572 return annotate_browser__search(browser, delay_secs);
573
574 return __annotate_browser__search(browser);
575}
576
577static bool annotate_browser__search_reverse(struct annotate_browser *browser,
578 int delay_secs)
579{
580 if (annotate_browser__search_window(browser, delay_secs))
581 return __annotate_browser__search_reverse(browser);
582
583 return false;
584}
585
586static
587bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
588 int delay_secs)
589{
590 if (!*browser->search_bf)
591 return annotate_browser__search_reverse(browser, delay_secs);
592
593 return __annotate_browser__search_reverse(browser);
594}
595
596static void annotate_browser__update_addr_width(struct annotate_browser *browser)
597{
598 if (annotate_browser__opts.use_offset)
599 browser->target_width = browser->min_addr_width;
600 else
601 browser->target_width = browser->max_addr_width;
602
603 browser->addr_width = browser->target_width;
604
605 if (annotate_browser__opts.show_nr_jumps)
606 browser->addr_width += browser->jumps_width + 1;
607}
608
609static int annotate_browser__run(struct annotate_browser *browser, int evidx,
610 struct hist_browser_timer *hbt)
611{
612 struct rb_node *nd = NULL;
613 struct map_symbol *ms = browser->b.priv;
614 struct symbol *sym = ms->sym;
615 const char *help = "Press 'h' for help on key bindings";
616 int delay_secs = hbt ? hbt->refresh : 0;
617 int key;
618
619 if (ui_browser__show(&browser->b, sym->name, help) < 0)
620 return -1;
621
622 annotate_browser__calc_percent(browser, evidx);
623
624 if (browser->curr_hot) {
625 annotate_browser__set_rb_top(browser, browser->curr_hot);
626 browser->b.navkeypressed = false;
627 }
628
629 nd = browser->curr_hot;
630
631 while (1) {
632 key = ui_browser__run(&browser->b, delay_secs);
633
634 if (delay_secs != 0) {
635 annotate_browser__calc_percent(browser, evidx);
636 /*
637 * Current line focus got out of the list of most active
638 * lines, NULL it so that if TAB|UNTAB is pressed, we
639 * move to curr_hot (current hottest line).
640 */
641 if (nd != NULL && RB_EMPTY_NODE(nd))
642 nd = NULL;
643 }
644
645 switch (key) {
646 case K_TIMER:
647 if (hbt)
648 hbt->timer(hbt->arg);
649
650 if (delay_secs != 0)
651 symbol__annotate_decay_histogram(sym, evidx);
652 continue;
653 case K_TAB:
654 if (nd != NULL) {
655 nd = rb_prev(nd);
656 if (nd == NULL)
657 nd = rb_last(&browser->entries);
658 } else
659 nd = browser->curr_hot;
660 break;
661 case K_UNTAB:
662 if (nd != NULL)
663 nd = rb_next(nd);
664 if (nd == NULL)
665 nd = rb_first(&browser->entries);
666 else
667 nd = browser->curr_hot;
668 break;
669 case K_F1:
670 case 'h':
671 ui_browser__help_window(&browser->b,
672 "UP/DOWN/PGUP\n"
673 "PGDN/SPACE Navigate\n"
674 "q/ESC/CTRL+C Exit\n\n"
675 "-> Go to target\n"
676 "<- Exit\n"
677 "H Cycle thru hottest instructions\n"
678 "j Toggle showing jump to target arrows\n"
679 "J Toggle showing number of jump sources on targets\n"
680 "n Search next string\n"
681 "o Toggle disassembler output/simplified view\n"
682 "s Toggle source code view\n"
683 "/ Search string\n"
684 "r Run available scripts\n"
685 "? Search previous string\n");
686 continue;
687 case 'r':
688 {
689 script_browse(NULL);
690 continue;
691 }
692 case 'H':
693 nd = browser->curr_hot;
694 break;
695 case 's':
696 if (annotate_browser__toggle_source(browser))
697 ui_helpline__puts(help);
698 continue;
699 case 'o':
700 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
701 annotate_browser__update_addr_width(browser);
702 continue;
703 case 'j':
704 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
705 continue;
706 case 'J':
707 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
708 annotate_browser__update_addr_width(browser);
709 continue;
710 case '/':
711 if (annotate_browser__search(browser, delay_secs)) {
712show_help:
713 ui_helpline__puts(help);
714 }
715 continue;
716 case 'n':
717 if (browser->searching_backwards ?
718 annotate_browser__continue_search_reverse(browser, delay_secs) :
719 annotate_browser__continue_search(browser, delay_secs))
720 goto show_help;
721 continue;
722 case '?':
723 if (annotate_browser__search_reverse(browser, delay_secs))
724 goto show_help;
725 continue;
726 case 'D': {
727 static int seq;
728 ui_helpline__pop();
729 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
730 seq++, browser->b.nr_entries,
731 browser->b.height,
732 browser->b.index,
733 browser->b.top_idx,
734 browser->nr_asm_entries);
735 }
736 continue;
737 case K_ENTER:
738 case K_RIGHT:
739 if (browser->selection == NULL)
740 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
741 else if (browser->selection->offset == -1)
742 ui_helpline__puts("Actions are only available for assembly lines.");
743 else if (!browser->selection->ins) {
744 if (strcmp(browser->selection->name, "retq"))
745 goto show_sup_ins;
746 goto out;
747 } else if (!(annotate_browser__jump(browser) ||
748 annotate_browser__callq(browser, evidx, hbt))) {
749show_sup_ins:
750 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
751 }
752 continue;
753 case K_LEFT:
754 case K_ESC:
755 case 'q':
756 case CTRL('c'):
757 goto out;
758 default:
759 continue;
760 }
761
762 if (nd != NULL)
763 annotate_browser__set_rb_top(browser, nd);
764 }
765out:
766 ui_browser__hide(&browser->b);
767 return key;
768}
769
770int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
771 struct hist_browser_timer *hbt)
772{
773 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt);
774}
775
776static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
777 size_t size)
778{
779 u64 offset;
780 struct map_symbol *ms = browser->b.priv;
781 struct symbol *sym = ms->sym;
782
783 /* PLT symbols contain external offsets */
784 if (strstr(sym->name, "@plt"))
785 return;
786
787 for (offset = 0; offset < size; ++offset) {
788 struct disasm_line *dl = browser->offsets[offset], *dlt;
789 struct browser_disasm_line *bdlt;
790
791 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
792 !disasm_line__has_offset(dl))
793 continue;
794
795 if (dl->ops.target.offset >= size) {
796 ui__error("jump to after symbol!\n"
797 "size: %zx, jump target: %" PRIx64,
798 size, dl->ops.target.offset);
799 continue;
800 }
801
802 dlt = browser->offsets[dl->ops.target.offset];
803 /*
804 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
805 * have to adjust to the previous offset?
806 */
807 if (dlt == NULL)
808 continue;
809
810 bdlt = disasm_line__browser(dlt);
811 if (++bdlt->jump_sources > browser->max_jump_sources)
812 browser->max_jump_sources = bdlt->jump_sources;
813
814 ++browser->nr_jumps;
815 }
816
817}
818
819static inline int width_jumps(int n)
820{
821 if (n >= 100)
822 return 5;
823 if (n / 10)
824 return 2;
825 return 1;
826}
827
828int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
829 struct hist_browser_timer *hbt)
830{
831 struct disasm_line *pos, *n;
832 struct annotation *notes;
833 size_t size;
834 struct map_symbol ms = {
835 .map = map,
836 .sym = sym,
837 };
838 struct annotate_browser browser = {
839 .b = {
840 .refresh = annotate_browser__refresh,
841 .seek = ui_browser__list_head_seek,
842 .write = annotate_browser__write,
843 .filter = disasm_line__filter,
844 .priv = &ms,
845 .use_navkeypressed = true,
846 },
847 };
848 int ret = -1;
849
850 if (sym == NULL)
851 return -1;
852
853 size = symbol__size(sym);
854
855 if (map->dso->annotate_warned)
856 return -1;
857
858 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
859 if (browser.offsets == NULL) {
860 ui__error("Not enough memory!");
861 return -1;
862 }
863
864 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
865 ui__error("%s", ui_helpline__last_msg);
866 goto out_free_offsets;
867 }
868
869 ui_helpline__push("Press <- or ESC to exit");
870
871 notes = symbol__annotation(sym);
872 browser.start = map__rip_2objdump(map, sym->start);
873
874 list_for_each_entry(pos, &notes->src->source, node) {
875 struct browser_disasm_line *bpos;
876 size_t line_len = strlen(pos->line);
877
878 if (browser.b.width < line_len)
879 browser.b.width = line_len;
880 bpos = disasm_line__browser(pos);
881 bpos->idx = browser.nr_entries++;
882 if (pos->offset != -1) {
883 bpos->idx_asm = browser.nr_asm_entries++;
884 /*
885 * FIXME: short term bandaid to cope with assembly
886 * routines that comes with labels in the same column
887 * as the address in objdump, sigh.
888 *
889 * E.g. copy_user_generic_unrolled
890 */
891 if (pos->offset < (s64)size)
892 browser.offsets[pos->offset] = pos;
893 } else
894 bpos->idx_asm = -1;
895 }
896
897 annotate_browser__mark_jump_targets(&browser, size);
898
899 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
900 browser.max_addr_width = hex_width(sym->end);
901 browser.jumps_width = width_jumps(browser.max_jump_sources);
902 browser.b.nr_entries = browser.nr_entries;
903 browser.b.entries = &notes->src->source,
904 browser.b.width += 18; /* Percentage */
905
906 if (annotate_browser__opts.hide_src_code)
907 annotate_browser__init_asm_mode(&browser);
908
909 annotate_browser__update_addr_width(&browser);
910
911 ret = annotate_browser__run(&browser, evidx, hbt);
912 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
913 list_del(&pos->node);
914 disasm_line__free(pos);
915 }
916
917out_free_offsets:
918 free(browser.offsets);
919 return ret;
920}
921
922#define ANNOTATE_CFG(n) \
923 { .name = #n, .value = &annotate_browser__opts.n, }
924
925/*
926 * Keep the entries sorted, they are bsearch'ed
927 */
928static struct annotate__config {
929 const char *name;
930 bool *value;
931} annotate__configs[] = {
932 ANNOTATE_CFG(hide_src_code),
933 ANNOTATE_CFG(jump_arrows),
934 ANNOTATE_CFG(show_nr_jumps),
935 ANNOTATE_CFG(use_offset),
936};
937
938#undef ANNOTATE_CFG
939
940static int annotate_config__cmp(const void *name, const void *cfgp)
941{
942 const struct annotate__config *cfg = cfgp;
943
944 return strcmp(name, cfg->name);
945}
946
947static int annotate__config(const char *var, const char *value,
948 void *data __maybe_unused)
949{
950 struct annotate__config *cfg;
951 const char *name;
952
953 if (prefixcmp(var, "annotate.") != 0)
954 return 0;
955
956 name = var + 9;
957 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
958 sizeof(struct annotate__config), annotate_config__cmp);
959
960 if (cfg == NULL)
961 return -1;
962
963 *cfg->value = perf_config_bool(name, value);
964 return 0;
965}
966
967void annotate_browser__init(void)
968{
969 perf_config(annotate__config, NULL);
970}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
deleted file mode 100644
index ccc4bd16142..00000000000
--- a/tools/perf/ui/browsers/hists.c
+++ /dev/null
@@ -1,1651 +0,0 @@
1#include <stdio.h>
2#include "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
5#include <newt.h>
6#include <linux/rbtree.h>
7
8#include "../../util/evsel.h"
9#include "../../util/evlist.h"
10#include "../../util/hist.h"
11#include "../../util/pstack.h"
12#include "../../util/sort.h"
13#include "../../util/util.h"
14#include "../../arch/common.h"
15
16#include "../browser.h"
17#include "../helpline.h"
18#include "../util.h"
19#include "../ui.h"
20#include "map.h"
21
22struct hist_browser {
23 struct ui_browser b;
24 struct hists *hists;
25 struct hist_entry *he_selection;
26 struct map_symbol *selection;
27 int print_seq;
28 bool show_dso;
29 bool has_symbols;
30};
31
32extern void hist_browser__init_hpp(void);
33
34static int hists__browser_title(struct hists *hists, char *bf, size_t size,
35 const char *ev_name);
36
37static void hist_browser__refresh_dimensions(struct hist_browser *browser)
38{
39 /* 3 == +/- toggle symbol before actual hist_entry rendering */
40 browser->b.width = 3 + (hists__sort_list_width(browser->hists) +
41 sizeof("[k]"));
42}
43
44static void hist_browser__reset(struct hist_browser *browser)
45{
46 browser->b.nr_entries = browser->hists->nr_entries;
47 hist_browser__refresh_dimensions(browser);
48 ui_browser__reset_index(&browser->b);
49}
50
51static char tree__folded_sign(bool unfolded)
52{
53 return unfolded ? '-' : '+';
54}
55
56static char map_symbol__folded(const struct map_symbol *ms)
57{
58 return ms->has_children ? tree__folded_sign(ms->unfolded) : ' ';
59}
60
61static char hist_entry__folded(const struct hist_entry *he)
62{
63 return map_symbol__folded(&he->ms);
64}
65
66static char callchain_list__folded(const struct callchain_list *cl)
67{
68 return map_symbol__folded(&cl->ms);
69}
70
71static void map_symbol__set_folding(struct map_symbol *ms, bool unfold)
72{
73 ms->unfolded = unfold ? ms->has_children : false;
74}
75
76static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
77{
78 int n = 0;
79 struct rb_node *nd;
80
81 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
82 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
83 struct callchain_list *chain;
84 char folded_sign = ' '; /* No children */
85
86 list_for_each_entry(chain, &child->val, list) {
87 ++n;
88 /* We need this because we may not have children */
89 folded_sign = callchain_list__folded(chain);
90 if (folded_sign == '+')
91 break;
92 }
93
94 if (folded_sign == '-') /* Have children and they're unfolded */
95 n += callchain_node__count_rows_rb_tree(child);
96 }
97
98 return n;
99}
100
101static int callchain_node__count_rows(struct callchain_node *node)
102{
103 struct callchain_list *chain;
104 bool unfolded = false;
105 int n = 0;
106
107 list_for_each_entry(chain, &node->val, list) {
108 ++n;
109 unfolded = chain->ms.unfolded;
110 }
111
112 if (unfolded)
113 n += callchain_node__count_rows_rb_tree(node);
114
115 return n;
116}
117
118static int callchain__count_rows(struct rb_root *chain)
119{
120 struct rb_node *nd;
121 int n = 0;
122
123 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
124 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
125 n += callchain_node__count_rows(node);
126 }
127
128 return n;
129}
130
131static bool map_symbol__toggle_fold(struct map_symbol *ms)
132{
133 if (!ms)
134 return false;
135
136 if (!ms->has_children)
137 return false;
138
139 ms->unfolded = !ms->unfolded;
140 return true;
141}
142
143static void callchain_node__init_have_children_rb_tree(struct callchain_node *node)
144{
145 struct rb_node *nd = rb_first(&node->rb_root);
146
147 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
148 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
149 struct callchain_list *chain;
150 bool first = true;
151
152 list_for_each_entry(chain, &child->val, list) {
153 if (first) {
154 first = false;
155 chain->ms.has_children = chain->list.next != &child->val ||
156 !RB_EMPTY_ROOT(&child->rb_root);
157 } else
158 chain->ms.has_children = chain->list.next == &child->val &&
159 !RB_EMPTY_ROOT(&child->rb_root);
160 }
161
162 callchain_node__init_have_children_rb_tree(child);
163 }
164}
165
166static void callchain_node__init_have_children(struct callchain_node *node)
167{
168 struct callchain_list *chain;
169
170 list_for_each_entry(chain, &node->val, list)
171 chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
172
173 callchain_node__init_have_children_rb_tree(node);
174}
175
176static void callchain__init_have_children(struct rb_root *root)
177{
178 struct rb_node *nd;
179
180 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
181 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
182 callchain_node__init_have_children(node);
183 }
184}
185
186static void hist_entry__init_have_children(struct hist_entry *he)
187{
188 if (!he->init_have_children) {
189 he->ms.has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
190 callchain__init_have_children(&he->sorted_chain);
191 he->init_have_children = true;
192 }
193}
194
195static bool hist_browser__toggle_fold(struct hist_browser *browser)
196{
197 if (map_symbol__toggle_fold(browser->selection)) {
198 struct hist_entry *he = browser->he_selection;
199
200 hist_entry__init_have_children(he);
201 browser->hists->nr_entries -= he->nr_rows;
202
203 if (he->ms.unfolded)
204 he->nr_rows = callchain__count_rows(&he->sorted_chain);
205 else
206 he->nr_rows = 0;
207 browser->hists->nr_entries += he->nr_rows;
208 browser->b.nr_entries = browser->hists->nr_entries;
209
210 return true;
211 }
212
213 /* If it doesn't have children, no toggling performed */
214 return false;
215}
216
217static int callchain_node__set_folding_rb_tree(struct callchain_node *node, bool unfold)
218{
219 int n = 0;
220 struct rb_node *nd;
221
222 for (nd = rb_first(&node->rb_root); nd; nd = rb_next(nd)) {
223 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
224 struct callchain_list *chain;
225 bool has_children = false;
226
227 list_for_each_entry(chain, &child->val, list) {
228 ++n;
229 map_symbol__set_folding(&chain->ms, unfold);
230 has_children = chain->ms.has_children;
231 }
232
233 if (has_children)
234 n += callchain_node__set_folding_rb_tree(child, unfold);
235 }
236
237 return n;
238}
239
240static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
241{
242 struct callchain_list *chain;
243 bool has_children = false;
244 int n = 0;
245
246 list_for_each_entry(chain, &node->val, list) {
247 ++n;
248 map_symbol__set_folding(&chain->ms, unfold);
249 has_children = chain->ms.has_children;
250 }
251
252 if (has_children)
253 n += callchain_node__set_folding_rb_tree(node, unfold);
254
255 return n;
256}
257
258static int callchain__set_folding(struct rb_root *chain, bool unfold)
259{
260 struct rb_node *nd;
261 int n = 0;
262
263 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
264 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
265 n += callchain_node__set_folding(node, unfold);
266 }
267
268 return n;
269}
270
271static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
272{
273 hist_entry__init_have_children(he);
274 map_symbol__set_folding(&he->ms, unfold);
275
276 if (he->ms.has_children) {
277 int n = callchain__set_folding(&he->sorted_chain, unfold);
278 he->nr_rows = unfold ? n : 0;
279 } else
280 he->nr_rows = 0;
281}
282
283static void hists__set_folding(struct hists *hists, bool unfold)
284{
285 struct rb_node *nd;
286
287 hists->nr_entries = 0;
288
289 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
290 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
291 hist_entry__set_folding(he, unfold);
292 hists->nr_entries += 1 + he->nr_rows;
293 }
294}
295
296static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
297{
298 hists__set_folding(browser->hists, unfold);
299 browser->b.nr_entries = browser->hists->nr_entries;
300 /* Go to the start, we may be way after valid entries after a collapse */
301 ui_browser__reset_index(&browser->b);
302}
303
304static void ui_browser__warn_lost_events(struct ui_browser *browser)
305{
306 ui_browser__warning(browser, 4,
307 "Events are being lost, check IO/CPU overload!\n\n"
308 "You may want to run 'perf' using a RT scheduler policy:\n\n"
309 " perf top -r 80\n\n"
310 "Or reduce the sampling frequency.");
311}
312
313static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
314 struct hist_browser_timer *hbt)
315{
316 int key;
317 char title[160];
318 int delay_secs = hbt ? hbt->refresh : 0;
319
320 browser->b.entries = &browser->hists->entries;
321 browser->b.nr_entries = browser->hists->nr_entries;
322
323 hist_browser__refresh_dimensions(browser);
324 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
325
326 if (ui_browser__show(&browser->b, title,
327 "Press '?' for help on key bindings") < 0)
328 return -1;
329
330 while (1) {
331 key = ui_browser__run(&browser->b, delay_secs);
332
333 switch (key) {
334 case K_TIMER:
335 hbt->timer(hbt->arg);
336 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
337
338 if (browser->hists->stats.nr_lost_warned !=
339 browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
340 browser->hists->stats.nr_lost_warned =
341 browser->hists->stats.nr_events[PERF_RECORD_LOST];
342 ui_browser__warn_lost_events(&browser->b);
343 }
344
345 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
346 ui_browser__show_title(&browser->b, title);
347 continue;
348 case 'D': { /* Debug */
349 static int seq;
350 struct hist_entry *h = rb_entry(browser->b.top,
351 struct hist_entry, rb_node);
352 ui_helpline__pop();
353 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
354 seq++, browser->b.nr_entries,
355 browser->hists->nr_entries,
356 browser->b.height,
357 browser->b.index,
358 browser->b.top_idx,
359 h->row_offset, h->nr_rows);
360 }
361 break;
362 case 'C':
363 /* Collapse the whole world. */
364 hist_browser__set_folding(browser, false);
365 break;
366 case 'E':
367 /* Expand the whole world. */
368 hist_browser__set_folding(browser, true);
369 break;
370 case K_ENTER:
371 if (hist_browser__toggle_fold(browser))
372 break;
373 /* fall thru */
374 default:
375 goto out;
376 }
377 }
378out:
379 ui_browser__hide(&browser->b);
380 return key;
381}
382
383static char *callchain_list__sym_name(struct callchain_list *cl,
384 char *bf, size_t bfsize, bool show_dso)
385{
386 int printed;
387
388 if (cl->ms.sym)
389 printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
390 else
391 printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
392
393 if (show_dso)
394 scnprintf(bf + printed, bfsize - printed, " %s",
395 cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
396
397 return bf;
398}
399
400#define LEVEL_OFFSET_STEP 3
401
402static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser,
403 struct callchain_node *chain_node,
404 u64 total, int level,
405 unsigned short row,
406 off_t *row_offset,
407 bool *is_current_entry)
408{
409 struct rb_node *node;
410 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
411 u64 new_total, remaining;
412
413 if (callchain_param.mode == CHAIN_GRAPH_REL)
414 new_total = chain_node->children_hit;
415 else
416 new_total = total;
417
418 remaining = new_total;
419 node = rb_first(&chain_node->rb_root);
420 while (node) {
421 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
422 struct rb_node *next = rb_next(node);
423 u64 cumul = callchain_cumul_hits(child);
424 struct callchain_list *chain;
425 char folded_sign = ' ';
426 int first = true;
427 int extra_offset = 0;
428
429 remaining -= cumul;
430
431 list_for_each_entry(chain, &child->val, list) {
432 char bf[1024], *alloc_str;
433 const char *str;
434 int color;
435 bool was_first = first;
436
437 if (first)
438 first = false;
439 else
440 extra_offset = LEVEL_OFFSET_STEP;
441
442 folded_sign = callchain_list__folded(chain);
443 if (*row_offset != 0) {
444 --*row_offset;
445 goto do_next;
446 }
447
448 alloc_str = NULL;
449 str = callchain_list__sym_name(chain, bf, sizeof(bf),
450 browser->show_dso);
451 if (was_first) {
452 double percent = cumul * 100.0 / new_total;
453
454 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
455 str = "Not enough memory!";
456 else
457 str = alloc_str;
458 }
459
460 color = HE_COLORSET_NORMAL;
461 width = browser->b.width - (offset + extra_offset + 2);
462 if (ui_browser__is_current_entry(&browser->b, row)) {
463 browser->selection = &chain->ms;
464 color = HE_COLORSET_SELECTED;
465 *is_current_entry = true;
466 }
467
468 ui_browser__set_color(&browser->b, color);
469 ui_browser__gotorc(&browser->b, row, 0);
470 slsmg_write_nstring(" ", offset + extra_offset);
471 slsmg_printf("%c ", folded_sign);
472 slsmg_write_nstring(str, width);
473 free(alloc_str);
474
475 if (++row == browser->b.height)
476 goto out;
477do_next:
478 if (folded_sign == '+')
479 break;
480 }
481
482 if (folded_sign == '-') {
483 const int new_level = level + (extra_offset ? 2 : 1);
484 row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total,
485 new_level, row, row_offset,
486 is_current_entry);
487 }
488 if (row == browser->b.height)
489 goto out;
490 node = next;
491 }
492out:
493 return row - first_row;
494}
495
496static int hist_browser__show_callchain_node(struct hist_browser *browser,
497 struct callchain_node *node,
498 int level, unsigned short row,
499 off_t *row_offset,
500 bool *is_current_entry)
501{
502 struct callchain_list *chain;
503 int first_row = row,
504 offset = level * LEVEL_OFFSET_STEP,
505 width = browser->b.width - offset;
506 char folded_sign = ' ';
507
508 list_for_each_entry(chain, &node->val, list) {
509 char bf[1024], *s;
510 int color;
511
512 folded_sign = callchain_list__folded(chain);
513
514 if (*row_offset != 0) {
515 --*row_offset;
516 continue;
517 }
518
519 color = HE_COLORSET_NORMAL;
520 if (ui_browser__is_current_entry(&browser->b, row)) {
521 browser->selection = &chain->ms;
522 color = HE_COLORSET_SELECTED;
523 *is_current_entry = true;
524 }
525
526 s = callchain_list__sym_name(chain, bf, sizeof(bf),
527 browser->show_dso);
528 ui_browser__gotorc(&browser->b, row, 0);
529 ui_browser__set_color(&browser->b, color);
530 slsmg_write_nstring(" ", offset);
531 slsmg_printf("%c ", folded_sign);
532 slsmg_write_nstring(s, width - 2);
533
534 if (++row == browser->b.height)
535 goto out;
536 }
537
538 if (folded_sign == '-')
539 row += hist_browser__show_callchain_node_rb_tree(browser, node,
540 browser->hists->stats.total_period,
541 level + 1, row,
542 row_offset,
543 is_current_entry);
544out:
545 return row - first_row;
546}
547
548static int hist_browser__show_callchain(struct hist_browser *browser,
549 struct rb_root *chain,
550 int level, unsigned short row,
551 off_t *row_offset,
552 bool *is_current_entry)
553{
554 struct rb_node *nd;
555 int first_row = row;
556
557 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
558 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
559
560 row += hist_browser__show_callchain_node(browser, node, level,
561 row, row_offset,
562 is_current_entry);
563 if (row == browser->b.height)
564 break;
565 }
566
567 return row - first_row;
568}
569
570#define HPP__COLOR_FN(_name, _field) \
571static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
572 struct hist_entry *he) \
573{ \
574 struct hists *hists = he->hists; \
575 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
576 *(double *)hpp->ptr = percent; \
577 return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
578}
579
580HPP__COLOR_FN(overhead, period)
581HPP__COLOR_FN(overhead_sys, period_sys)
582HPP__COLOR_FN(overhead_us, period_us)
583HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
584HPP__COLOR_FN(overhead_guest_us, period_guest_us)
585
586#undef HPP__COLOR_FN
587
588void hist_browser__init_hpp(void)
589{
590 perf_hpp__init();
591
592 perf_hpp__format[PERF_HPP__OVERHEAD].color =
593 hist_browser__hpp_color_overhead;
594 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
595 hist_browser__hpp_color_overhead_sys;
596 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
597 hist_browser__hpp_color_overhead_us;
598 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
599 hist_browser__hpp_color_overhead_guest_sys;
600 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
601 hist_browser__hpp_color_overhead_guest_us;
602}
603
604static int hist_browser__show_entry(struct hist_browser *browser,
605 struct hist_entry *entry,
606 unsigned short row)
607{
608 char s[256];
609 double percent;
610 int i, printed = 0;
611 int width = browser->b.width;
612 char folded_sign = ' ';
613 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
614 off_t row_offset = entry->row_offset;
615 bool first = true;
616
617 if (current_entry) {
618 browser->he_selection = entry;
619 browser->selection = &entry->ms;
620 }
621
622 if (symbol_conf.use_callchain) {
623 hist_entry__init_have_children(entry);
624 folded_sign = hist_entry__folded(entry);
625 }
626
627 if (row_offset == 0) {
628 struct perf_hpp hpp = {
629 .buf = s,
630 .size = sizeof(s),
631 };
632
633 ui_browser__gotorc(&browser->b, row, 0);
634
635 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
636 if (!perf_hpp__format[i].cond)
637 continue;
638
639 if (!first) {
640 slsmg_printf(" ");
641 width -= 2;
642 }
643 first = false;
644
645 if (perf_hpp__format[i].color) {
646 hpp.ptr = &percent;
647 /* It will set percent for us. See HPP__COLOR_FN above. */
648 width -= perf_hpp__format[i].color(&hpp, entry);
649
650 ui_browser__set_percent_color(&browser->b, percent, current_entry);
651
652 if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) {
653 slsmg_printf("%c ", folded_sign);
654 width -= 2;
655 }
656
657 slsmg_printf("%s", s);
658
659 if (!current_entry || !browser->b.navkeypressed)
660 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
661 } else {
662 width -= perf_hpp__format[i].entry(&hpp, entry);
663 slsmg_printf("%s", s);
664 }
665 }
666
667 /* The scroll bar isn't being used */
668 if (!browser->b.navkeypressed)
669 width += 1;
670
671 hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists);
672 slsmg_write_nstring(s, width);
673 ++row;
674 ++printed;
675 } else
676 --row_offset;
677
678 if (folded_sign == '-' && row != browser->b.height) {
679 printed += hist_browser__show_callchain(browser, &entry->sorted_chain,
680 1, row, &row_offset,
681 &current_entry);
682 if (current_entry)
683 browser->he_selection = entry;
684 }
685
686 return printed;
687}
688
689static void ui_browser__hists_init_top(struct ui_browser *browser)
690{
691 if (browser->top == NULL) {
692 struct hist_browser *hb;
693
694 hb = container_of(browser, struct hist_browser, b);
695 browser->top = rb_first(&hb->hists->entries);
696 }
697}
698
699static unsigned int hist_browser__refresh(struct ui_browser *browser)
700{
701 unsigned row = 0;
702 struct rb_node *nd;
703 struct hist_browser *hb = container_of(browser, struct hist_browser, b);
704
705 ui_browser__hists_init_top(browser);
706
707 for (nd = browser->top; nd; nd = rb_next(nd)) {
708 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
709
710 if (h->filtered)
711 continue;
712
713 row += hist_browser__show_entry(hb, h, row);
714 if (row == browser->height)
715 break;
716 }
717
718 return row;
719}
720
721static struct rb_node *hists__filter_entries(struct rb_node *nd)
722{
723 while (nd != NULL) {
724 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
725 if (!h->filtered)
726 return nd;
727
728 nd = rb_next(nd);
729 }
730
731 return NULL;
732}
733
734static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
735{
736 while (nd != NULL) {
737 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
738 if (!h->filtered)
739 return nd;
740
741 nd = rb_prev(nd);
742 }
743
744 return NULL;
745}
746
747static void ui_browser__hists_seek(struct ui_browser *browser,
748 off_t offset, int whence)
749{
750 struct hist_entry *h;
751 struct rb_node *nd;
752 bool first = true;
753
754 if (browser->nr_entries == 0)
755 return;
756
757 ui_browser__hists_init_top(browser);
758
759 switch (whence) {
760 case SEEK_SET:
761 nd = hists__filter_entries(rb_first(browser->entries));
762 break;
763 case SEEK_CUR:
764 nd = browser->top;
765 goto do_offset;
766 case SEEK_END:
767 nd = hists__filter_prev_entries(rb_last(browser->entries));
768 first = false;
769 break;
770 default:
771 return;
772 }
773
774 /*
775 * Moves not relative to the first visible entry invalidates its
776 * row_offset:
777 */
778 h = rb_entry(browser->top, struct hist_entry, rb_node);
779 h->row_offset = 0;
780
781 /*
782 * Here we have to check if nd is expanded (+), if it is we can't go
783 * the next top level hist_entry, instead we must compute an offset of
784 * what _not_ to show and not change the first visible entry.
785 *
786 * This offset increments when we are going from top to bottom and
787 * decreases when we're going from bottom to top.
788 *
789 * As we don't have backpointers to the top level in the callchains
790 * structure, we need to always print the whole hist_entry callchain,
791 * skipping the first ones that are before the first visible entry
792 * and stop when we printed enough lines to fill the screen.
793 */
794do_offset:
795 if (offset > 0) {
796 do {
797 h = rb_entry(nd, struct hist_entry, rb_node);
798 if (h->ms.unfolded) {
799 u16 remaining = h->nr_rows - h->row_offset;
800 if (offset > remaining) {
801 offset -= remaining;
802 h->row_offset = 0;
803 } else {
804 h->row_offset += offset;
805 offset = 0;
806 browser->top = nd;
807 break;
808 }
809 }
810 nd = hists__filter_entries(rb_next(nd));
811 if (nd == NULL)
812 break;
813 --offset;
814 browser->top = nd;
815 } while (offset != 0);
816 } else if (offset < 0) {
817 while (1) {
818 h = rb_entry(nd, struct hist_entry, rb_node);
819 if (h->ms.unfolded) {
820 if (first) {
821 if (-offset > h->row_offset) {
822 offset += h->row_offset;
823 h->row_offset = 0;
824 } else {
825 h->row_offset += offset;
826 offset = 0;
827 browser->top = nd;
828 break;
829 }
830 } else {
831 if (-offset > h->nr_rows) {
832 offset += h->nr_rows;
833 h->row_offset = 0;
834 } else {
835 h->row_offset = h->nr_rows + offset;
836 offset = 0;
837 browser->top = nd;
838 break;
839 }
840 }
841 }
842
843 nd = hists__filter_prev_entries(rb_prev(nd));
844 if (nd == NULL)
845 break;
846 ++offset;
847 browser->top = nd;
848 if (offset == 0) {
849 /*
850 * Last unfiltered hist_entry, check if it is
851 * unfolded, if it is then we should have
852 * row_offset at its last entry.
853 */
854 h = rb_entry(nd, struct hist_entry, rb_node);
855 if (h->ms.unfolded)
856 h->row_offset = h->nr_rows;
857 break;
858 }
859 first = false;
860 }
861 } else {
862 browser->top = nd;
863 h = rb_entry(nd, struct hist_entry, rb_node);
864 h->row_offset = 0;
865 }
866}
867
868static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
869 struct callchain_node *chain_node,
870 u64 total, int level,
871 FILE *fp)
872{
873 struct rb_node *node;
874 int offset = level * LEVEL_OFFSET_STEP;
875 u64 new_total, remaining;
876 int printed = 0;
877
878 if (callchain_param.mode == CHAIN_GRAPH_REL)
879 new_total = chain_node->children_hit;
880 else
881 new_total = total;
882
883 remaining = new_total;
884 node = rb_first(&chain_node->rb_root);
885 while (node) {
886 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
887 struct rb_node *next = rb_next(node);
888 u64 cumul = callchain_cumul_hits(child);
889 struct callchain_list *chain;
890 char folded_sign = ' ';
891 int first = true;
892 int extra_offset = 0;
893
894 remaining -= cumul;
895
896 list_for_each_entry(chain, &child->val, list) {
897 char bf[1024], *alloc_str;
898 const char *str;
899 bool was_first = first;
900
901 if (first)
902 first = false;
903 else
904 extra_offset = LEVEL_OFFSET_STEP;
905
906 folded_sign = callchain_list__folded(chain);
907
908 alloc_str = NULL;
909 str = callchain_list__sym_name(chain, bf, sizeof(bf),
910 browser->show_dso);
911 if (was_first) {
912 double percent = cumul * 100.0 / new_total;
913
914 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
915 str = "Not enough memory!";
916 else
917 str = alloc_str;
918 }
919
920 printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
921 free(alloc_str);
922 if (folded_sign == '+')
923 break;
924 }
925
926 if (folded_sign == '-') {
927 const int new_level = level + (extra_offset ? 2 : 1);
928 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
929 new_level, fp);
930 }
931
932 node = next;
933 }
934
935 return printed;
936}
937
938static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
939 struct callchain_node *node,
940 int level, FILE *fp)
941{
942 struct callchain_list *chain;
943 int offset = level * LEVEL_OFFSET_STEP;
944 char folded_sign = ' ';
945 int printed = 0;
946
947 list_for_each_entry(chain, &node->val, list) {
948 char bf[1024], *s;
949
950 folded_sign = callchain_list__folded(chain);
951 s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso);
952 printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
953 }
954
955 if (folded_sign == '-')
956 printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
957 browser->hists->stats.total_period,
958 level + 1, fp);
959 return printed;
960}
961
962static int hist_browser__fprintf_callchain(struct hist_browser *browser,
963 struct rb_root *chain, int level, FILE *fp)
964{
965 struct rb_node *nd;
966 int printed = 0;
967
968 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
969 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
970
971 printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
972 }
973
974 return printed;
975}
976
977static int hist_browser__fprintf_entry(struct hist_browser *browser,
978 struct hist_entry *he, FILE *fp)
979{
980 char s[8192];
981 double percent;
982 int printed = 0;
983 char folded_sign = ' ';
984
985 if (symbol_conf.use_callchain)
986 folded_sign = hist_entry__folded(he);
987
988 hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
989 percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
990
991 if (symbol_conf.use_callchain)
992 printed += fprintf(fp, "%c ", folded_sign);
993
994 printed += fprintf(fp, " %5.2f%%", percent);
995
996 if (symbol_conf.show_nr_samples)
997 printed += fprintf(fp, " %11u", he->stat.nr_events);
998
999 if (symbol_conf.show_total_period)
1000 printed += fprintf(fp, " %12" PRIu64, he->stat.period);
1001
1002 printed += fprintf(fp, "%s\n", rtrim(s));
1003
1004 if (folded_sign == '-')
1005 printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
1006
1007 return printed;
1008}
1009
1010static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1011{
1012 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
1013 int printed = 0;
1014
1015 while (nd) {
1016 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1017
1018 printed += hist_browser__fprintf_entry(browser, h, fp);
1019 nd = hists__filter_entries(rb_next(nd));
1020 }
1021
1022 return printed;
1023}
1024
1025static int hist_browser__dump(struct hist_browser *browser)
1026{
1027 char filename[64];
1028 FILE *fp;
1029
1030 while (1) {
1031 scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
1032 if (access(filename, F_OK))
1033 break;
1034 /*
1035 * XXX: Just an arbitrary lazy upper limit
1036 */
1037 if (++browser->print_seq == 8192) {
1038 ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
1039 return -1;
1040 }
1041 }
1042
1043 fp = fopen(filename, "w");
1044 if (fp == NULL) {
1045 char bf[64];
1046 const char *err = strerror_r(errno, bf, sizeof(bf));
1047 ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
1048 return -1;
1049 }
1050
1051 ++browser->print_seq;
1052 hist_browser__fprintf(browser, fp);
1053 fclose(fp);
1054 ui_helpline__fpush("%s written!", filename);
1055
1056 return 0;
1057}
1058
1059static struct hist_browser *hist_browser__new(struct hists *hists)
1060{
1061 struct hist_browser *browser = zalloc(sizeof(*browser));
1062
1063 if (browser) {
1064 browser->hists = hists;
1065 browser->b.refresh = hist_browser__refresh;
1066 browser->b.seek = ui_browser__hists_seek;
1067 browser->b.use_navkeypressed = true;
1068 if (sort__branch_mode == 1)
1069 browser->has_symbols = sort_sym_from.list.next != NULL;
1070 else
1071 browser->has_symbols = sort_sym.list.next != NULL;
1072 }
1073
1074 return browser;
1075}
1076
1077static void hist_browser__delete(struct hist_browser *browser)
1078{
1079 free(browser);
1080}
1081
1082static struct hist_entry *hist_browser__selected_entry(struct hist_browser *browser)
1083{
1084 return browser->he_selection;
1085}
1086
1087static struct thread *hist_browser__selected_thread(struct hist_browser *browser)
1088{
1089 return browser->he_selection->thread;
1090}
1091
1092static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1093 const char *ev_name)
1094{
1095 char unit;
1096 int printed;
1097 const struct dso *dso = hists->dso_filter;
1098 const struct thread *thread = hists->thread_filter;
1099 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1100 u64 nr_events = hists->stats.total_period;
1101
1102 nr_samples = convert_unit(nr_samples, &unit);
1103 printed = scnprintf(bf, size,
1104 "Samples: %lu%c of event '%s', Event count (approx.): %lu",
1105 nr_samples, unit, ev_name, nr_events);
1106
1107
1108 if (hists->uid_filter_str)
1109 printed += snprintf(bf + printed, size - printed,
1110 ", UID: %s", hists->uid_filter_str);
1111 if (thread)
1112 printed += scnprintf(bf + printed, size - printed,
1113 ", Thread: %s(%d)",
1114 (thread->comm_set ? thread->comm : ""),
1115 thread->pid);
1116 if (dso)
1117 printed += scnprintf(bf + printed, size - printed,
1118 ", DSO: %s", dso->short_name);
1119 return printed;
1120}
1121
1122static inline void free_popup_options(char **options, int n)
1123{
1124 int i;
1125
1126 for (i = 0; i < n; ++i) {
1127 free(options[i]);
1128 options[i] = NULL;
1129 }
1130}
1131
1132/* Check whether the browser is for 'top' or 'report' */
1133static inline bool is_report_browser(void *timer)
1134{
1135 return timer == NULL;
1136}
1137
1138static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1139 const char *helpline, const char *ev_name,
1140 bool left_exits,
1141 struct hist_browser_timer *hbt,
1142 struct perf_session_env *env)
1143{
1144 struct hists *hists = &evsel->hists;
1145 struct hist_browser *browser = hist_browser__new(hists);
1146 struct branch_info *bi;
1147 struct pstack *fstack;
1148 char *options[16];
1149 int nr_options = 0;
1150 int key = -1;
1151 char buf[64];
1152 char script_opt[64];
1153 int delay_secs = hbt ? hbt->refresh : 0;
1154
1155 if (browser == NULL)
1156 return -1;
1157
1158 fstack = pstack__new(2);
1159 if (fstack == NULL)
1160 goto out;
1161
1162 ui_helpline__push(helpline);
1163
1164 memset(options, 0, sizeof(options));
1165
1166 while (1) {
1167 const struct thread *thread = NULL;
1168 const struct dso *dso = NULL;
1169 int choice = 0,
1170 annotate = -2, zoom_dso = -2, zoom_thread = -2,
1171 annotate_f = -2, annotate_t = -2, browse_map = -2;
1172 int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2;
1173
1174 nr_options = 0;
1175
1176 key = hist_browser__run(browser, ev_name, hbt);
1177
1178 if (browser->he_selection != NULL) {
1179 thread = hist_browser__selected_thread(browser);
1180 dso = browser->selection->map ? browser->selection->map->dso : NULL;
1181 }
1182 switch (key) {
1183 case K_TAB:
1184 case K_UNTAB:
1185 if (nr_events == 1)
1186 continue;
1187 /*
1188 * Exit the browser, let hists__browser_tree
1189 * go to the next or previous
1190 */
1191 goto out_free_stack;
1192 case 'a':
1193 if (!browser->has_symbols) {
1194 ui_browser__warning(&browser->b, delay_secs * 2,
1195 "Annotation is only available for symbolic views, "
1196 "include \"sym*\" in --sort to use it.");
1197 continue;
1198 }
1199
1200 if (browser->selection == NULL ||
1201 browser->selection->sym == NULL ||
1202 browser->selection->map->dso->annotate_warned)
1203 continue;
1204 goto do_annotate;
1205 case 'P':
1206 hist_browser__dump(browser);
1207 continue;
1208 case 'd':
1209 goto zoom_dso;
1210 case 'V':
1211 browser->show_dso = !browser->show_dso;
1212 continue;
1213 case 't':
1214 goto zoom_thread;
1215 case '/':
1216 if (ui_browser__input_window("Symbol to show",
1217 "Please enter the name of symbol you want to see",
1218 buf, "ENTER: OK, ESC: Cancel",
1219 delay_secs * 2) == K_ENTER) {
1220 hists->symbol_filter_str = *buf ? buf : NULL;
1221 hists__filter_by_symbol(hists);
1222 hist_browser__reset(browser);
1223 }
1224 continue;
1225 case 'r':
1226 if (is_report_browser(hbt))
1227 goto do_scripts;
1228 continue;
1229 case K_F1:
1230 case 'h':
1231 case '?':
1232 ui_browser__help_window(&browser->b,
1233 "h/?/F1 Show this window\n"
1234 "UP/DOWN/PGUP\n"
1235 "PGDN/SPACE Navigate\n"
1236 "q/ESC/CTRL+C Exit browser\n\n"
1237 "For multiple event sessions:\n\n"
1238 "TAB/UNTAB Switch events\n\n"
1239 "For symbolic views (--sort has sym):\n\n"
1240 "-> Zoom into DSO/Threads & Annotate current symbol\n"
1241 "<- Zoom out\n"
1242 "a Annotate current symbol\n"
1243 "C Collapse all callchains\n"
1244 "E Expand all callchains\n"
1245 "d Zoom into current DSO\n"
1246 "t Zoom into current Thread\n"
1247 "r Run available scripts('perf report' only)\n"
1248 "P Print histograms to perf.hist.N\n"
1249 "V Verbose (DSO names in callchains, etc)\n"
1250 "/ Filter symbol by name");
1251 continue;
1252 case K_ENTER:
1253 case K_RIGHT:
1254 /* menu */
1255 break;
1256 case K_LEFT: {
1257 const void *top;
1258
1259 if (pstack__empty(fstack)) {
1260 /*
1261 * Go back to the perf_evsel_menu__run or other user
1262 */
1263 if (left_exits)
1264 goto out_free_stack;
1265 continue;
1266 }
1267 top = pstack__pop(fstack);
1268 if (top == &browser->hists->dso_filter)
1269 goto zoom_out_dso;
1270 if (top == &browser->hists->thread_filter)
1271 goto zoom_out_thread;
1272 continue;
1273 }
1274 case K_ESC:
1275 if (!left_exits &&
1276 !ui_browser__dialog_yesno(&browser->b,
1277 "Do you really want to exit?"))
1278 continue;
1279 /* Fall thru */
1280 case 'q':
1281 case CTRL('c'):
1282 goto out_free_stack;
1283 default:
1284 continue;
1285 }
1286
1287 if (!browser->has_symbols)
1288 goto add_exit_option;
1289
1290 if (sort__branch_mode == 1) {
1291 bi = browser->he_selection->branch_info;
1292 if (browser->selection != NULL &&
1293 bi &&
1294 bi->from.sym != NULL &&
1295 !bi->from.map->dso->annotate_warned &&
1296 asprintf(&options[nr_options], "Annotate %s",
1297 bi->from.sym->name) > 0)
1298 annotate_f = nr_options++;
1299
1300 if (browser->selection != NULL &&
1301 bi &&
1302 bi->to.sym != NULL &&
1303 !bi->to.map->dso->annotate_warned &&
1304 (bi->to.sym != bi->from.sym ||
1305 bi->to.map->dso != bi->from.map->dso) &&
1306 asprintf(&options[nr_options], "Annotate %s",
1307 bi->to.sym->name) > 0)
1308 annotate_t = nr_options++;
1309 } else {
1310
1311 if (browser->selection != NULL &&
1312 browser->selection->sym != NULL &&
1313 !browser->selection->map->dso->annotate_warned &&
1314 asprintf(&options[nr_options], "Annotate %s",
1315 browser->selection->sym->name) > 0)
1316 annotate = nr_options++;
1317 }
1318
1319 if (thread != NULL &&
1320 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
1321 (browser->hists->thread_filter ? "out of" : "into"),
1322 (thread->comm_set ? thread->comm : ""),
1323 thread->pid) > 0)
1324 zoom_thread = nr_options++;
1325
1326 if (dso != NULL &&
1327 asprintf(&options[nr_options], "Zoom %s %s DSO",
1328 (browser->hists->dso_filter ? "out of" : "into"),
1329 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1330 zoom_dso = nr_options++;
1331
1332 if (browser->selection != NULL &&
1333 browser->selection->map != NULL &&
1334 asprintf(&options[nr_options], "Browse map details") > 0)
1335 browse_map = nr_options++;
1336
1337 /* perf script support */
1338 if (browser->he_selection) {
1339 struct symbol *sym;
1340
1341 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
1342 browser->he_selection->thread->comm) > 0)
1343 scripts_comm = nr_options++;
1344
1345 sym = browser->he_selection->ms.sym;
1346 if (sym && sym->namelen &&
1347 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1348 sym->name) > 0)
1349 scripts_symbol = nr_options++;
1350 }
1351
1352 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1353 scripts_all = nr_options++;
1354
1355add_exit_option:
1356 options[nr_options++] = (char *)"Exit";
1357retry_popup_menu:
1358 choice = ui__popup_menu(nr_options, options);
1359
1360 if (choice == nr_options - 1)
1361 break;
1362
1363 if (choice == -1) {
1364 free_popup_options(options, nr_options - 1);
1365 continue;
1366 }
1367
1368 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
1369 struct hist_entry *he;
1370 int err;
1371do_annotate:
1372 if (!objdump_path && perf_session_env__lookup_objdump(env))
1373 continue;
1374
1375 he = hist_browser__selected_entry(browser);
1376 if (he == NULL)
1377 continue;
1378
1379 /*
1380 * we stash the branch_info symbol + map into the
1381 * the ms so we don't have to rewrite all the annotation
1382 * code to use branch_info.
1383 * in branch mode, the ms struct is not used
1384 */
1385 if (choice == annotate_f) {
1386 he->ms.sym = he->branch_info->from.sym;
1387 he->ms.map = he->branch_info->from.map;
1388 } else if (choice == annotate_t) {
1389 he->ms.sym = he->branch_info->to.sym;
1390 he->ms.map = he->branch_info->to.map;
1391 }
1392
1393 /*
1394 * Don't let this be freed, say, by hists__decay_entry.
1395 */
1396 he->used = true;
1397 err = hist_entry__tui_annotate(he, evsel->idx, hbt);
1398 he->used = false;
1399 /*
1400 * offer option to annotate the other branch source or target
1401 * (if they exists) when returning from annotate
1402 */
1403 if ((err == 'q' || err == CTRL('c'))
1404 && annotate_t != -2 && annotate_f != -2)
1405 goto retry_popup_menu;
1406
1407 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1408 if (err)
1409 ui_browser__handle_resize(&browser->b);
1410
1411 } else if (choice == browse_map)
1412 map__browse(browser->selection->map);
1413 else if (choice == zoom_dso) {
1414zoom_dso:
1415 if (browser->hists->dso_filter) {
1416 pstack__remove(fstack, &browser->hists->dso_filter);
1417zoom_out_dso:
1418 ui_helpline__pop();
1419 browser->hists->dso_filter = NULL;
1420 sort_dso.elide = false;
1421 } else {
1422 if (dso == NULL)
1423 continue;
1424 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1425 dso->kernel ? "the Kernel" : dso->short_name);
1426 browser->hists->dso_filter = dso;
1427 sort_dso.elide = true;
1428 pstack__push(fstack, &browser->hists->dso_filter);
1429 }
1430 hists__filter_by_dso(hists);
1431 hist_browser__reset(browser);
1432 } else if (choice == zoom_thread) {
1433zoom_thread:
1434 if (browser->hists->thread_filter) {
1435 pstack__remove(fstack, &browser->hists->thread_filter);
1436zoom_out_thread:
1437 ui_helpline__pop();
1438 browser->hists->thread_filter = NULL;
1439 sort_thread.elide = false;
1440 } else {
1441 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1442 thread->comm_set ? thread->comm : "",
1443 thread->pid);
1444 browser->hists->thread_filter = thread;
1445 sort_thread.elide = true;
1446 pstack__push(fstack, &browser->hists->thread_filter);
1447 }
1448 hists__filter_by_thread(hists);
1449 hist_browser__reset(browser);
1450 }
1451 /* perf scripts support */
1452 else if (choice == scripts_all || choice == scripts_comm ||
1453 choice == scripts_symbol) {
1454do_scripts:
1455 memset(script_opt, 0, 64);
1456
1457 if (choice == scripts_comm)
1458 sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm);
1459
1460 if (choice == scripts_symbol)
1461 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1462
1463 script_browse(script_opt);
1464 }
1465 }
1466out_free_stack:
1467 pstack__delete(fstack);
1468out:
1469 hist_browser__delete(browser);
1470 free_popup_options(options, nr_options - 1);
1471 return key;
1472}
1473
1474struct perf_evsel_menu {
1475 struct ui_browser b;
1476 struct perf_evsel *selection;
1477 bool lost_events, lost_events_warned;
1478 struct perf_session_env *env;
1479};
1480
1481static void perf_evsel_menu__write(struct ui_browser *browser,
1482 void *entry, int row)
1483{
1484 struct perf_evsel_menu *menu = container_of(browser,
1485 struct perf_evsel_menu, b);
1486 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1487 bool current_entry = ui_browser__is_current_entry(browser, row);
1488 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1489 const char *ev_name = perf_evsel__name(evsel);
1490 char bf[256], unit;
1491 const char *warn = " ";
1492 size_t printed;
1493
1494 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1495 HE_COLORSET_NORMAL);
1496
1497 nr_events = convert_unit(nr_events, &unit);
1498 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1499 unit, unit == ' ' ? "" : " ", ev_name);
1500 slsmg_printf("%s", bf);
1501
1502 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1503 if (nr_events != 0) {
1504 menu->lost_events = true;
1505 if (!current_entry)
1506 ui_browser__set_color(browser, HE_COLORSET_TOP);
1507 nr_events = convert_unit(nr_events, &unit);
1508 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1509 nr_events, unit, unit == ' ' ? "" : " ");
1510 warn = bf;
1511 }
1512
1513 slsmg_write_nstring(warn, browser->width - printed);
1514
1515 if (current_entry)
1516 menu->selection = evsel;
1517}
1518
1519static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1520 int nr_events, const char *help,
1521 struct hist_browser_timer *hbt)
1522{
1523 struct perf_evlist *evlist = menu->b.priv;
1524 struct perf_evsel *pos;
1525 const char *ev_name, *title = "Available samples";
1526 int delay_secs = hbt ? hbt->refresh : 0;
1527 int key;
1528
1529 if (ui_browser__show(&menu->b, title,
1530 "ESC: exit, ENTER|->: Browse histograms") < 0)
1531 return -1;
1532
1533 while (1) {
1534 key = ui_browser__run(&menu->b, delay_secs);
1535
1536 switch (key) {
1537 case K_TIMER:
1538 hbt->timer(hbt->arg);
1539
1540 if (!menu->lost_events_warned && menu->lost_events) {
1541 ui_browser__warn_lost_events(&menu->b);
1542 menu->lost_events_warned = true;
1543 }
1544 continue;
1545 case K_RIGHT:
1546 case K_ENTER:
1547 if (!menu->selection)
1548 continue;
1549 pos = menu->selection;
1550browse_hists:
1551 perf_evlist__set_selected(evlist, pos);
1552 /*
1553 * Give the calling tool a chance to populate the non
1554 * default evsel resorted hists tree.
1555 */
1556 if (hbt)
1557 hbt->timer(hbt->arg);
1558 ev_name = perf_evsel__name(pos);
1559 key = perf_evsel__hists_browse(pos, nr_events, help,
1560 ev_name, true, hbt,
1561 menu->env);
1562 ui_browser__show_title(&menu->b, title);
1563 switch (key) {
1564 case K_TAB:
1565 if (pos->node.next == &evlist->entries)
1566 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1567 else
1568 pos = list_entry(pos->node.next, struct perf_evsel, node);
1569 goto browse_hists;
1570 case K_UNTAB:
1571 if (pos->node.prev == &evlist->entries)
1572 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1573 else
1574 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1575 goto browse_hists;
1576 case K_ESC:
1577 if (!ui_browser__dialog_yesno(&menu->b,
1578 "Do you really want to exit?"))
1579 continue;
1580 /* Fall thru */
1581 case 'q':
1582 case CTRL('c'):
1583 goto out;
1584 default:
1585 continue;
1586 }
1587 case K_LEFT:
1588 continue;
1589 case K_ESC:
1590 if (!ui_browser__dialog_yesno(&menu->b,
1591 "Do you really want to exit?"))
1592 continue;
1593 /* Fall thru */
1594 case 'q':
1595 case CTRL('c'):
1596 goto out;
1597 default:
1598 continue;
1599 }
1600 }
1601
1602out:
1603 ui_browser__hide(&menu->b);
1604 return key;
1605}
1606
1607static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1608 const char *help,
1609 struct hist_browser_timer *hbt,
1610 struct perf_session_env *env)
1611{
1612 struct perf_evsel *pos;
1613 struct perf_evsel_menu menu = {
1614 .b = {
1615 .entries = &evlist->entries,
1616 .refresh = ui_browser__list_head_refresh,
1617 .seek = ui_browser__list_head_seek,
1618 .write = perf_evsel_menu__write,
1619 .nr_entries = evlist->nr_entries,
1620 .priv = evlist,
1621 },
1622 .env = env,
1623 };
1624
1625 ui_helpline__push("Press ESC to exit");
1626
1627 list_for_each_entry(pos, &evlist->entries, node) {
1628 const char *ev_name = perf_evsel__name(pos);
1629 size_t line_len = strlen(ev_name) + 7;
1630
1631 if (menu.b.width < line_len)
1632 menu.b.width = line_len;
1633 }
1634
1635 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt);
1636}
1637
1638int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1639 struct hist_browser_timer *hbt,
1640 struct perf_session_env *env)
1641{
1642 if (evlist->nr_entries == 1) {
1643 struct perf_evsel *first = list_entry(evlist->entries.next,
1644 struct perf_evsel, node);
1645 const char *ev_name = perf_evsel__name(first);
1646 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1647 ev_name, false, hbt, env);
1648 }
1649
1650 return __perf_evlist__tui_browse_hists(evlist, help, hbt, env);
1651}
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
deleted file mode 100644
index 98851d55a53..00000000000
--- a/tools/perf/ui/browsers/map.c
+++ /dev/null
@@ -1,154 +0,0 @@
1#include "../libslang.h"
2#include <elf.h>
3#include <newt.h>
4#include <inttypes.h>
5#include <sys/ttydefaults.h>
6#include <string.h>
7#include <linux/bitops.h>
8#include "../../util/util.h"
9#include "../../util/debug.h"
10#include "../../util/symbol.h"
11#include "../browser.h"
12#include "../helpline.h"
13#include "map.h"
14
15static int ui_entry__read(const char *title, char *bf, size_t size, int width)
16{
17 struct newtExitStruct es;
18 newtComponent form, entry;
19 const char *result;
20 int err = -1;
21
22 newtCenteredWindow(width, 1, title);
23 form = newtForm(NULL, NULL, 0);
24 if (form == NULL)
25 return -1;
26
27 entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
28 if (entry == NULL)
29 goto out_free_form;
30
31 newtFormAddComponent(form, entry);
32 newtFormAddHotKey(form, NEWT_KEY_ENTER);
33 newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
34 newtFormAddHotKey(form, NEWT_KEY_LEFT);
35 newtFormAddHotKey(form, CTRL('c'));
36 newtFormRun(form, &es);
37
38 if (result != NULL) {
39 strncpy(bf, result, size);
40 err = 0;
41 }
42out_free_form:
43 newtPopWindow();
44 newtFormDestroy(form);
45 return err;
46}
47
48struct map_browser {
49 struct ui_browser b;
50 struct map *map;
51 u8 addrlen;
52};
53
54static void map_browser__write(struct ui_browser *self, void *nd, int row)
55{
56 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
57 struct map_browser *mb = container_of(self, struct map_browser, b);
58 bool current_entry = ui_browser__is_current_entry(self, row);
59 int width;
60
61 ui_browser__set_percent_color(self, 0, current_entry);
62 slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
63 mb->addrlen, sym->start, mb->addrlen, sym->end,
64 sym->binding == STB_GLOBAL ? 'g' :
65 sym->binding == STB_LOCAL ? 'l' : 'w');
66 width = self->width - ((mb->addrlen * 2) + 4);
67 if (width > 0)
68 slsmg_write_nstring(sym->name, width);
69}
70
71/* FIXME uber-kludgy, see comment on cmd_report... */
72static u32 *symbol__browser_index(struct symbol *self)
73{
74 return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
75}
76
77static int map_browser__search(struct map_browser *self)
78{
79 char target[512];
80 struct symbol *sym;
81 int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
82
83 if (err)
84 return err;
85
86 if (target[0] == '0' && tolower(target[1]) == 'x') {
87 u64 addr = strtoull(target, NULL, 16);
88 sym = map__find_symbol(self->map, addr, NULL);
89 } else
90 sym = map__find_symbol_by_name(self->map, target, NULL);
91
92 if (sym != NULL) {
93 u32 *idx = symbol__browser_index(sym);
94
95 self->b.top = &sym->rb_node;
96 self->b.index = self->b.top_idx = *idx;
97 } else
98 ui_helpline__fpush("%s not found!", target);
99
100 return 0;
101}
102
103static int map_browser__run(struct map_browser *self)
104{
105 int key;
106
107 if (ui_browser__show(&self->b, self->map->dso->long_name,
108 "Press <- or ESC to exit, %s / to search",
109 verbose ? "" : "restart with -v to use") < 0)
110 return -1;
111
112 while (1) {
113 key = ui_browser__run(&self->b, 0);
114
115 if (verbose && key == '/')
116 map_browser__search(self);
117 else
118 break;
119 }
120
121 ui_browser__hide(&self->b);
122 return key;
123}
124
125int map__browse(struct map *self)
126{
127 struct map_browser mb = {
128 .b = {
129 .entries = &self->dso->symbols[self->type],
130 .refresh = ui_browser__rb_tree_refresh,
131 .seek = ui_browser__rb_tree_seek,
132 .write = map_browser__write,
133 },
134 .map = self,
135 };
136 struct rb_node *nd;
137 char tmp[BITS_PER_LONG / 4];
138 u64 maxaddr = 0;
139
140 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
141 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
142
143 if (maxaddr < pos->end)
144 maxaddr = pos->end;
145 if (verbose) {
146 u32 *idx = symbol__browser_index(pos);
147 *idx = mb.b.nr_entries;
148 }
149 ++mb.b.nr_entries;
150 }
151
152 mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
153 return map_browser__run(&mb);
154}
diff --git a/tools/perf/ui/browsers/map.h b/tools/perf/ui/browsers/map.h
deleted file mode 100644
index df8581a43e1..00000000000
--- a/tools/perf/ui/browsers/map.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef _PERF_UI_MAP_BROWSER_H_
2#define _PERF_UI_MAP_BROWSER_H_ 1
3struct map;
4
5int map__browse(struct map *self);
6#endif /* _PERF_UI_MAP_BROWSER_H_ */
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
deleted file mode 100644
index cbbd44b0d93..00000000000
--- a/tools/perf/ui/browsers/scripts.c
+++ /dev/null
@@ -1,189 +0,0 @@
1#include <elf.h>
2#include <newt.h>
3#include <inttypes.h>
4#include <sys/ttydefaults.h>
5#include <string.h>
6#include "../../util/sort.h"
7#include "../../util/util.h"
8#include "../../util/hist.h"
9#include "../../util/debug.h"
10#include "../../util/symbol.h"
11#include "../browser.h"
12#include "../helpline.h"
13#include "../libslang.h"
14
15/* 2048 lines should be enough for a script output */
16#define MAX_LINES 2048
17
18/* 160 bytes for one output line */
19#define AVERAGE_LINE_LEN 160
20
21struct script_line {
22 struct list_head node;
23 char line[AVERAGE_LINE_LEN];
24};
25
26struct perf_script_browser {
27 struct ui_browser b;
28 struct list_head entries;
29 const char *script_name;
30 int nr_lines;
31};
32
33#define SCRIPT_NAMELEN 128
34#define SCRIPT_MAX_NO 64
35/*
36 * Usually the full path for a script is:
37 * /home/username/libexec/perf-core/scripts/python/xxx.py
38 * /home/username/libexec/perf-core/scripts/perl/xxx.pl
39 * So 256 should be long enough to contain the full path.
40 */
41#define SCRIPT_FULLPATH_LEN 256
42
43/*
44 * When success, will copy the full path of the selected script
45 * into the buffer pointed by script_name, and return 0.
46 * Return -1 on failure.
47 */
48static int list_scripts(char *script_name)
49{
50 char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO];
51 int i, num, choice, ret = -1;
52
53 /* Preset the script name to SCRIPT_NAMELEN */
54 buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
55 if (!buf)
56 return ret;
57
58 for (i = 0; i < SCRIPT_MAX_NO; i++) {
59 names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
60 paths[i] = names[i] + SCRIPT_NAMELEN;
61 }
62
63 num = find_scripts(names, paths);
64 if (num > 0) {
65 choice = ui__popup_menu(num, names);
66 if (choice < num && choice >= 0) {
67 strcpy(script_name, paths[choice]);
68 ret = 0;
69 }
70 }
71
72 free(buf);
73 return ret;
74}
75
76static void script_browser__write(struct ui_browser *browser,
77 void *entry, int row)
78{
79 struct script_line *sline = list_entry(entry, struct script_line, node);
80 bool current_entry = ui_browser__is_current_entry(browser, row);
81
82 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
83 HE_COLORSET_NORMAL);
84
85 slsmg_write_nstring(sline->line, browser->width);
86}
87
88static int script_browser__run(struct perf_script_browser *self)
89{
90 int key;
91
92 if (ui_browser__show(&self->b, self->script_name,
93 "Press <- or ESC to exit") < 0)
94 return -1;
95
96 while (1) {
97 key = ui_browser__run(&self->b, 0);
98
99 /* We can add some special key handling here if needed */
100 break;
101 }
102
103 ui_browser__hide(&self->b);
104 return key;
105}
106
107
108int script_browse(const char *script_opt)
109{
110 char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN];
111 char *line = NULL;
112 size_t len = 0;
113 ssize_t retlen;
114 int ret = -1, nr_entries = 0;
115 FILE *fp;
116 void *buf;
117 struct script_line *sline;
118
119 struct perf_script_browser script = {
120 .b = {
121 .refresh = ui_browser__list_head_refresh,
122 .seek = ui_browser__list_head_seek,
123 .write = script_browser__write,
124 },
125 .script_name = script_name,
126 };
127
128 INIT_LIST_HEAD(&script.entries);
129
130 /* Save each line of the output in one struct script_line object. */
131 buf = zalloc((sizeof(*sline)) * MAX_LINES);
132 if (!buf)
133 return -1;
134 sline = buf;
135
136 memset(script_name, 0, SCRIPT_FULLPATH_LEN);
137 if (list_scripts(script_name))
138 goto exit;
139
140 sprintf(cmd, "perf script -s %s ", script_name);
141
142 if (script_opt)
143 strcat(cmd, script_opt);
144
145 if (input_name) {
146 strcat(cmd, " -i ");
147 strcat(cmd, input_name);
148 }
149
150 strcat(cmd, " 2>&1");
151
152 fp = popen(cmd, "r");
153 if (!fp)
154 goto exit;
155
156 while ((retlen = getline(&line, &len, fp)) != -1) {
157 strncpy(sline->line, line, AVERAGE_LINE_LEN);
158
159 /* If one output line is very large, just cut it short */
160 if (retlen >= AVERAGE_LINE_LEN) {
161 sline->line[AVERAGE_LINE_LEN - 1] = '\0';
162 sline->line[AVERAGE_LINE_LEN - 2] = '\n';
163 }
164 list_add_tail(&sline->node, &script.entries);
165
166 if (script.b.width < retlen)
167 script.b.width = retlen;
168
169 if (nr_entries++ >= MAX_LINES - 1)
170 break;
171 sline++;
172 }
173
174 if (script.b.width > AVERAGE_LINE_LEN)
175 script.b.width = AVERAGE_LINE_LEN;
176
177 if (line)
178 free(line);
179 pclose(fp);
180
181 script.nr_lines = nr_entries;
182 script.b.nr_entries = nr_entries;
183 script.b.entries = &script.entries;
184
185 ret = script_browser__run(&script);
186exit:
187 free(buf);
188 return ret;
189}
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
deleted file mode 100644
index 253b6219a39..00000000000
--- a/tools/perf/ui/gtk/browser.c
+++ /dev/null
@@ -1,312 +0,0 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "../helpline.h"
7#include "gtk.h"
8
9#include <signal.h>
10
11#define MAX_COLUMNS 32
12
13static void perf_gtk__signal(int sig)
14{
15 perf_gtk__exit(false);
16 psignal(sig, "perf");
17}
18
19static void perf_gtk__resize_window(GtkWidget *window)
20{
21 GdkRectangle rect;
22 GdkScreen *screen;
23 int monitor;
24 int height;
25 int width;
26
27 screen = gtk_widget_get_screen(window);
28
29 monitor = gdk_screen_get_monitor_at_window(screen, window->window);
30
31 gdk_screen_get_monitor_geometry(screen, monitor, &rect);
32
33 width = rect.width * 3 / 4;
34 height = rect.height * 3 / 4;
35
36 gtk_window_resize(GTK_WINDOW(window), width, height);
37}
38
39static const char *perf_gtk__get_percent_color(double percent)
40{
41 if (percent >= MIN_RED)
42 return "<span fgcolor='red'>";
43 if (percent >= MIN_GREEN)
44 return "<span fgcolor='dark green'>";
45 return NULL;
46}
47
48#define HPP__COLOR_FN(_name, _field) \
49static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
50 struct hist_entry *he) \
51{ \
52 struct hists *hists = he->hists; \
53 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
54 const char *markup; \
55 int ret = 0; \
56 \
57 markup = perf_gtk__get_percent_color(percent); \
58 if (markup) \
59 ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
60 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \
61 if (markup) \
62 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
63 \
64 return ret; \
65}
66
67HPP__COLOR_FN(overhead, period)
68HPP__COLOR_FN(overhead_sys, period_sys)
69HPP__COLOR_FN(overhead_us, period_us)
70HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
71HPP__COLOR_FN(overhead_guest_us, period_guest_us)
72
73#undef HPP__COLOR_FN
74
75void perf_gtk__init_hpp(void)
76{
77 perf_hpp__init();
78
79 perf_hpp__format[PERF_HPP__OVERHEAD].color =
80 perf_gtk__hpp_color_overhead;
81 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
82 perf_gtk__hpp_color_overhead_sys;
83 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
84 perf_gtk__hpp_color_overhead_us;
85 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
86 perf_gtk__hpp_color_overhead_guest_sys;
87 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
88 perf_gtk__hpp_color_overhead_guest_us;
89}
90
91static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
92{
93 GType col_types[MAX_COLUMNS];
94 GtkCellRenderer *renderer;
95 struct sort_entry *se;
96 GtkListStore *store;
97 struct rb_node *nd;
98 GtkWidget *view;
99 int i, col_idx;
100 int nr_cols;
101 char s[512];
102
103 struct perf_hpp hpp = {
104 .buf = s,
105 .size = sizeof(s),
106 };
107
108 nr_cols = 0;
109
110 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
111 if (!perf_hpp__format[i].cond)
112 continue;
113
114 col_types[nr_cols++] = G_TYPE_STRING;
115 }
116
117 list_for_each_entry(se, &hist_entry__sort_list, list) {
118 if (se->elide)
119 continue;
120
121 col_types[nr_cols++] = G_TYPE_STRING;
122 }
123
124 store = gtk_list_store_newv(nr_cols, col_types);
125
126 view = gtk_tree_view_new();
127
128 renderer = gtk_cell_renderer_text_new();
129
130 col_idx = 0;
131
132 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
133 if (!perf_hpp__format[i].cond)
134 continue;
135
136 perf_hpp__format[i].header(&hpp);
137
138 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
139 -1, s,
140 renderer, "markup",
141 col_idx++, NULL);
142 }
143
144 list_for_each_entry(se, &hist_entry__sort_list, list) {
145 if (se->elide)
146 continue;
147
148 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
149 -1, se->se_header,
150 renderer, "text",
151 col_idx++, NULL);
152 }
153
154 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
155
156 g_object_unref(GTK_TREE_MODEL(store));
157
158 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
159 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
160 GtkTreeIter iter;
161
162 if (h->filtered)
163 continue;
164
165 gtk_list_store_append(store, &iter);
166
167 col_idx = 0;
168
169 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
170 if (!perf_hpp__format[i].cond)
171 continue;
172
173 if (perf_hpp__format[i].color)
174 perf_hpp__format[i].color(&hpp, h);
175 else
176 perf_hpp__format[i].entry(&hpp, h);
177
178 gtk_list_store_set(store, &iter, col_idx++, s, -1);
179 }
180
181 list_for_each_entry(se, &hist_entry__sort_list, list) {
182 if (se->elide)
183 continue;
184
185 se->se_snprintf(h, s, ARRAY_SIZE(s),
186 hists__col_len(hists, se->se_width_idx));
187
188 gtk_list_store_set(store, &iter, col_idx++, s, -1);
189 }
190 }
191
192 gtk_container_add(GTK_CONTAINER(window), view);
193}
194
195#ifdef HAVE_GTK_INFO_BAR
196static GtkWidget *perf_gtk__setup_info_bar(void)
197{
198 GtkWidget *info_bar;
199 GtkWidget *label;
200 GtkWidget *content_area;
201
202 info_bar = gtk_info_bar_new();
203 gtk_widget_set_no_show_all(info_bar, TRUE);
204
205 label = gtk_label_new("");
206 gtk_widget_show(label);
207
208 content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar));
209 gtk_container_add(GTK_CONTAINER(content_area), label);
210
211 gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK,
212 GTK_RESPONSE_OK);
213 g_signal_connect(info_bar, "response",
214 G_CALLBACK(gtk_widget_hide), NULL);
215
216 pgctx->info_bar = info_bar;
217 pgctx->message_label = label;
218
219 return info_bar;
220}
221#endif
222
223static GtkWidget *perf_gtk__setup_statusbar(void)
224{
225 GtkWidget *stbar;
226 unsigned ctxid;
227
228 stbar = gtk_statusbar_new();
229
230 ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar),
231 "perf report");
232 pgctx->statbar = stbar;
233 pgctx->statbar_ctx_id = ctxid;
234
235 return stbar;
236}
237
238int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
239 const char *help,
240 struct hist_browser_timer *hbt __maybe_unused)
241{
242 struct perf_evsel *pos;
243 GtkWidget *vbox;
244 GtkWidget *notebook;
245 GtkWidget *info_bar;
246 GtkWidget *statbar;
247 GtkWidget *window;
248
249 signal(SIGSEGV, perf_gtk__signal);
250 signal(SIGFPE, perf_gtk__signal);
251 signal(SIGINT, perf_gtk__signal);
252 signal(SIGQUIT, perf_gtk__signal);
253 signal(SIGTERM, perf_gtk__signal);
254
255 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
256
257 gtk_window_set_title(GTK_WINDOW(window), "perf report");
258
259 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
260
261 pgctx = perf_gtk__activate_context(window);
262 if (!pgctx)
263 return -1;
264
265 vbox = gtk_vbox_new(FALSE, 0);
266
267 notebook = gtk_notebook_new();
268
269 list_for_each_entry(pos, &evlist->entries, node) {
270 struct hists *hists = &pos->hists;
271 const char *evname = perf_evsel__name(pos);
272 GtkWidget *scrolled_window;
273 GtkWidget *tab_label;
274
275 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
276
277 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
278 GTK_POLICY_AUTOMATIC,
279 GTK_POLICY_AUTOMATIC);
280
281 perf_gtk__show_hists(scrolled_window, hists);
282
283 tab_label = gtk_label_new(evname);
284
285 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
286 }
287
288 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
289
290 info_bar = perf_gtk__setup_info_bar();
291 if (info_bar)
292 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
293
294 statbar = perf_gtk__setup_statusbar();
295 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
296
297 gtk_container_add(GTK_CONTAINER(window), vbox);
298
299 gtk_widget_show_all(window);
300
301 perf_gtk__resize_window(window);
302
303 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
304
305 ui_helpline__push(help);
306
307 gtk_main();
308
309 perf_gtk__deactivate_context(&pgctx);
310
311 return 0;
312}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
deleted file mode 100644
index 856320e2cc0..00000000000
--- a/tools/perf/ui/gtk/gtk.h
+++ /dev/null
@@ -1,43 +0,0 @@
1#ifndef _PERF_GTK_H_
2#define _PERF_GTK_H_ 1
3
4#include <stdbool.h>
5
6#pragma GCC diagnostic ignored "-Wstrict-prototypes"
7#include <gtk/gtk.h>
8#pragma GCC diagnostic error "-Wstrict-prototypes"
9
10
11struct perf_gtk_context {
12 GtkWidget *main_window;
13
14#ifdef HAVE_GTK_INFO_BAR
15 GtkWidget *info_bar;
16 GtkWidget *message_label;
17#endif
18 GtkWidget *statbar;
19 guint statbar_ctx_id;
20};
21
22extern struct perf_gtk_context *pgctx;
23
24static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
25{
26 return ctx && ctx->main_window;
27}
28
29struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
30int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
31
32void perf_gtk__init_helpline(void);
33void perf_gtk__init_progress(void);
34void perf_gtk__init_hpp(void);
35
36#ifndef HAVE_GTK_INFO_BAR
37static inline GtkWidget *perf_gtk__setup_info_bar(void)
38{
39 return NULL;
40}
41#endif
42
43#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c
deleted file mode 100644
index 5db4432ff12..00000000000
--- a/tools/perf/ui/gtk/helpline.c
+++ /dev/null
@@ -1,56 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3
4#include "gtk.h"
5#include "../ui.h"
6#include "../helpline.h"
7#include "../../util/debug.h"
8
9static void gtk_helpline_pop(void)
10{
11 if (!perf_gtk__is_active_context(pgctx))
12 return;
13
14 gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
15 pgctx->statbar_ctx_id);
16}
17
18static void gtk_helpline_push(const char *msg)
19{
20 if (!perf_gtk__is_active_context(pgctx))
21 return;
22
23 gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
24 pgctx->statbar_ctx_id, msg);
25}
26
27static struct ui_helpline gtk_helpline_fns = {
28 .pop = gtk_helpline_pop,
29 .push = gtk_helpline_push,
30};
31
32void perf_gtk__init_helpline(void)
33{
34 helpline_fns = &gtk_helpline_fns;
35}
36
37int perf_gtk__show_helpline(const char *fmt, va_list ap)
38{
39 int ret;
40 char *ptr;
41 static int backlog;
42
43 ret = vscnprintf(ui_helpline__current + backlog,
44 sizeof(ui_helpline__current) - backlog, fmt, ap);
45 backlog += ret;
46
47 /* only first line can be displayed */
48 ptr = strchr(ui_helpline__current, '\n');
49 if (ptr && (ptr - ui_helpline__current) <= backlog) {
50 *ptr = '\0';
51 ui_helpline__puts(ui_helpline__current);
52 backlog = 0;
53 }
54
55 return ret;
56}
diff --git a/tools/perf/ui/gtk/progress.c b/tools/perf/ui/gtk/progress.c
deleted file mode 100644
index 482bcf3df9b..00000000000
--- a/tools/perf/ui/gtk/progress.c
+++ /dev/null
@@ -1,59 +0,0 @@
1#include <inttypes.h>
2
3#include "gtk.h"
4#include "../progress.h"
5#include "util.h"
6
7static GtkWidget *dialog;
8static GtkWidget *progress;
9
10static void gtk_progress_update(u64 curr, u64 total, const char *title)
11{
12 double fraction = total ? 1.0 * curr / total : 0.0;
13 char buf[1024];
14
15 if (dialog == NULL) {
16 GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
17 GtkWidget *label = gtk_label_new(title);
18
19 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
20 progress = gtk_progress_bar_new();
21
22 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, FALSE, 3);
23 gtk_box_pack_start(GTK_BOX(vbox), progress, TRUE, TRUE, 3);
24
25 gtk_container_add(GTK_CONTAINER(dialog), vbox);
26
27 gtk_window_set_title(GTK_WINDOW(dialog), "perf");
28 gtk_window_resize(GTK_WINDOW(dialog), 300, 80);
29 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
30
31 gtk_widget_show_all(dialog);
32 }
33
34 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
35 snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, curr, total);
36 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf);
37
38 /* we didn't call gtk_main yet, so do it manually */
39 while (gtk_events_pending())
40 gtk_main_iteration();
41}
42
43static void gtk_progress_finish(void)
44{
45 /* this will also destroy all of its children */
46 gtk_widget_destroy(dialog);
47
48 dialog = NULL;
49}
50
51static struct ui_progress gtk_progress_fns = {
52 .update = gtk_progress_update,
53 .finish = gtk_progress_finish,
54};
55
56void perf_gtk__init_progress(void)
57{
58 progress_fns = &gtk_progress_fns;
59}
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
deleted file mode 100644
index 6c2dd2e423f..00000000000
--- a/tools/perf/ui/gtk/setup.c
+++ /dev/null
@@ -1,23 +0,0 @@
1#include "gtk.h"
2#include "../../util/cache.h"
3#include "../../util/debug.h"
4
5extern struct perf_error_ops perf_gtk_eops;
6
7int perf_gtk__init(void)
8{
9 perf_error__register(&perf_gtk_eops);
10 perf_gtk__init_helpline();
11 perf_gtk__init_progress();
12 perf_gtk__init_hpp();
13
14 return gtk_init_check(NULL, NULL) ? 0 : -1;
15}
16
17void perf_gtk__exit(bool wait_for_ok __maybe_unused)
18{
19 if (!perf_gtk__is_active_context(pgctx))
20 return;
21 perf_error__unregister(&perf_gtk_eops);
22 gtk_main_quit();
23}
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
deleted file mode 100644
index c06942a41c7..00000000000
--- a/tools/perf/ui/gtk/util.c
+++ /dev/null
@@ -1,113 +0,0 @@
1#include "../util.h"
2#include "../../util/debug.h"
3#include "gtk.h"
4
5#include <string.h>
6
7
8struct perf_gtk_context *pgctx;
9
10struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window)
11{
12 struct perf_gtk_context *ctx;
13
14 ctx = malloc(sizeof(*pgctx));
15 if (ctx)
16 ctx->main_window = window;
17
18 return ctx;
19}
20
21int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
22{
23 if (!perf_gtk__is_active_context(*ctx))
24 return -1;
25
26 free(*ctx);
27 *ctx = NULL;
28 return 0;
29}
30
31static int perf_gtk__error(const char *format, va_list args)
32{
33 char *msg;
34 GtkWidget *dialog;
35
36 if (!perf_gtk__is_active_context(pgctx) ||
37 vasprintf(&msg, format, args) < 0) {
38 fprintf(stderr, "Error:\n");
39 vfprintf(stderr, format, args);
40 fprintf(stderr, "\n");
41 return -1;
42 }
43
44 dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_window),
45 GTK_DIALOG_DESTROY_WITH_PARENT,
46 GTK_MESSAGE_ERROR,
47 GTK_BUTTONS_CLOSE,
48 "<b>Error</b>\n\n%s", msg);
49 gtk_dialog_run(GTK_DIALOG(dialog));
50
51 gtk_widget_destroy(dialog);
52 free(msg);
53 return 0;
54}
55
56#ifdef HAVE_GTK_INFO_BAR
57static int perf_gtk__warning_info_bar(const char *format, va_list args)
58{
59 char *msg;
60
61 if (!perf_gtk__is_active_context(pgctx) ||
62 vasprintf(&msg, format, args) < 0) {
63 fprintf(stderr, "Warning:\n");
64 vfprintf(stderr, format, args);
65 fprintf(stderr, "\n");
66 return -1;
67 }
68
69 gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg);
70 gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar),
71 GTK_MESSAGE_WARNING);
72 gtk_widget_show(pgctx->info_bar);
73
74 free(msg);
75 return 0;
76}
77#else
78static int perf_gtk__warning_statusbar(const char *format, va_list args)
79{
80 char *msg, *p;
81
82 if (!perf_gtk__is_active_context(pgctx) ||
83 vasprintf(&msg, format, args) < 0) {
84 fprintf(stderr, "Warning:\n");
85 vfprintf(stderr, format, args);
86 fprintf(stderr, "\n");
87 return -1;
88 }
89
90 gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
91 pgctx->statbar_ctx_id);
92
93 /* Only first line can be displayed */
94 p = strchr(msg, '\n');
95 if (p)
96 *p = '\0';
97
98 gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
99 pgctx->statbar_ctx_id, msg);
100
101 free(msg);
102 return 0;
103}
104#endif
105
106struct perf_error_ops perf_gtk_eops = {
107 .error = perf_gtk__error,
108#ifdef HAVE_GTK_INFO_BAR
109 .warning = perf_gtk__warning_info_bar,
110#else
111 .warning = perf_gtk__warning_statusbar,
112#endif
113};
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c
deleted file mode 100644
index a49bcf3c190..00000000000
--- a/tools/perf/ui/helpline.c
+++ /dev/null
@@ -1,61 +0,0 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "../debug.h"
6#include "helpline.h"
7#include "ui.h"
8
9char ui_helpline__current[512];
10
11static void nop_helpline__pop(void)
12{
13}
14
15static void nop_helpline__push(const char *msg __maybe_unused)
16{
17}
18
19static struct ui_helpline default_helpline_fns = {
20 .pop = nop_helpline__pop,
21 .push = nop_helpline__push,
22};
23
24struct ui_helpline *helpline_fns = &default_helpline_fns;
25
26void ui_helpline__pop(void)
27{
28 helpline_fns->pop();
29}
30
31void ui_helpline__push(const char *msg)
32{
33 helpline_fns->push(msg);
34}
35
36void ui_helpline__vpush(const char *fmt, va_list ap)
37{
38 char *s;
39
40 if (vasprintf(&s, fmt, ap) < 0)
41 vfprintf(stderr, fmt, ap);
42 else {
43 ui_helpline__push(s);
44 free(s);
45 }
46}
47
48void ui_helpline__fpush(const char *fmt, ...)
49{
50 va_list ap;
51
52 va_start(ap, fmt);
53 ui_helpline__vpush(fmt, ap);
54 va_end(ap);
55}
56
57void ui_helpline__puts(const char *msg)
58{
59 ui_helpline__pop();
60 ui_helpline__push(msg);
61}
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h
deleted file mode 100644
index baa28a4d16b..00000000000
--- a/tools/perf/ui/helpline.h
+++ /dev/null
@@ -1,47 +0,0 @@
1#ifndef _PERF_UI_HELPLINE_H_
2#define _PERF_UI_HELPLINE_H_ 1
3
4#include <stdio.h>
5#include <stdarg.h>
6
7#include "../util/cache.h"
8
9struct ui_helpline {
10 void (*pop)(void);
11 void (*push)(const char *msg);
12};
13
14extern struct ui_helpline *helpline_fns;
15
16void ui_helpline__init(void);
17
18void ui_helpline__pop(void);
19void ui_helpline__push(const char *msg);
20void ui_helpline__vpush(const char *fmt, va_list ap);
21void ui_helpline__fpush(const char *fmt, ...);
22void ui_helpline__puts(const char *msg);
23
24extern char ui_helpline__current[512];
25
26#ifdef NEWT_SUPPORT
27extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap);
29#else
30static inline int ui_helpline__show_help(const char *format __maybe_unused,
31 va_list ap __maybe_unused)
32{
33 return 0;
34}
35#endif /* NEWT_SUPPORT */
36
37#ifdef GTK2_SUPPORT
38int perf_gtk__show_helpline(const char *format, va_list ap);
39#else
40static inline int perf_gtk__show_helpline(const char *format __maybe_unused,
41 va_list ap __maybe_unused)
42{
43 return 0;
44}
45#endif /* GTK2_SUPPORT */
46
47#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
deleted file mode 100644
index aa84130024d..00000000000
--- a/tools/perf/ui/hist.c
+++ /dev/null
@@ -1,527 +0,0 @@
1#include <math.h>
2
3#include "../util/hist.h"
4#include "../util/util.h"
5#include "../util/sort.h"
6
7
8/* hist period print (hpp) functions */
9static int hpp__header_overhead(struct perf_hpp *hpp)
10{
11 return scnprintf(hpp->buf, hpp->size, "Overhead");
12}
13
14static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
15{
16 return 8;
17}
18
19static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
20{
21 struct hists *hists = he->hists;
22 double percent = 100.0 * he->stat.period / hists->stats.total_period;
23
24 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
25}
26
27static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
28{
29 struct hists *hists = he->hists;
30 double percent = 100.0 * he->stat.period / hists->stats.total_period;
31 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
32
33 return scnprintf(hpp->buf, hpp->size, fmt, percent);
34}
35
36static int hpp__header_overhead_sys(struct perf_hpp *hpp)
37{
38 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
39
40 return scnprintf(hpp->buf, hpp->size, fmt, "sys");
41}
42
43static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
44{
45 return 7;
46}
47
48static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
49{
50 struct hists *hists = he->hists;
51 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
52
53 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
54}
55
56static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
57{
58 struct hists *hists = he->hists;
59 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
60 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
61
62 return scnprintf(hpp->buf, hpp->size, fmt, percent);
63}
64
65static int hpp__header_overhead_us(struct perf_hpp *hpp)
66{
67 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
68
69 return scnprintf(hpp->buf, hpp->size, fmt, "user");
70}
71
72static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
73{
74 return 7;
75}
76
77static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
78{
79 struct hists *hists = he->hists;
80 double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
81
82 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
83}
84
85static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
86{
87 struct hists *hists = he->hists;
88 double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
89 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
90
91 return scnprintf(hpp->buf, hpp->size, fmt, percent);
92}
93
94static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
95{
96 return scnprintf(hpp->buf, hpp->size, "guest sys");
97}
98
99static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
100{
101 return 9;
102}
103
104static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
105 struct hist_entry *he)
106{
107 struct hists *hists = he->hists;
108 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
109
110 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
111}
112
113static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
114 struct hist_entry *he)
115{
116 struct hists *hists = he->hists;
117 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
118 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
119
120 return scnprintf(hpp->buf, hpp->size, fmt, percent);
121}
122
123static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
124{
125 return scnprintf(hpp->buf, hpp->size, "guest usr");
126}
127
128static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
129{
130 return 9;
131}
132
133static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
134 struct hist_entry *he)
135{
136 struct hists *hists = he->hists;
137 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
138
139 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
140}
141
142static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
143 struct hist_entry *he)
144{
145 struct hists *hists = he->hists;
146 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
147 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
148
149 return scnprintf(hpp->buf, hpp->size, fmt, percent);
150}
151
152static int hpp__header_baseline(struct perf_hpp *hpp)
153{
154 return scnprintf(hpp->buf, hpp->size, "Baseline");
155}
156
157static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
158{
159 return 8;
160}
161
162static double baseline_percent(struct hist_entry *he)
163{
164 struct hist_entry *pair = hist_entry__next_pair(he);
165 struct hists *pair_hists = pair ? pair->hists : NULL;
166 double percent = 0.0;
167
168 if (pair) {
169 u64 total_period = pair_hists->stats.total_period;
170 u64 base_period = pair->stat.period;
171
172 percent = 100.0 * base_period / total_period;
173 }
174
175 return percent;
176}
177
178static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
179{
180 double percent = baseline_percent(he);
181
182 if (hist_entry__has_pairs(he))
183 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
184 else
185 return scnprintf(hpp->buf, hpp->size, " ");
186}
187
188static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
189{
190 double percent = baseline_percent(he);
191 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
192
193 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
194 return scnprintf(hpp->buf, hpp->size, fmt, percent);
195 else
196 return scnprintf(hpp->buf, hpp->size, " ");
197}
198
199static int hpp__header_samples(struct perf_hpp *hpp)
200{
201 const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
202
203 return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
204}
205
206static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
207{
208 return 11;
209}
210
211static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
212{
213 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
214
215 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
216}
217
218static int hpp__header_period(struct perf_hpp *hpp)
219{
220 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
221
222 return scnprintf(hpp->buf, hpp->size, fmt, "Period");
223}
224
225static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
226{
227 return 12;
228}
229
230static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
231{
232 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
233
234 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
235}
236
237static int hpp__header_period_baseline(struct perf_hpp *hpp)
238{
239 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
240
241 return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
242}
243
244static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
245{
246 return 12;
247}
248
249static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
250{
251 struct hist_entry *pair = hist_entry__next_pair(he);
252 u64 period = pair ? pair->stat.period : 0;
253 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
254
255 return scnprintf(hpp->buf, hpp->size, fmt, period);
256}
257static int hpp__header_delta(struct perf_hpp *hpp)
258{
259 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
260
261 return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
262}
263
264static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
265{
266 return 7;
267}
268
269static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
270{
271 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
272 char buf[32] = " ";
273 double diff;
274
275 if (he->diff.computed)
276 diff = he->diff.period_ratio_delta;
277 else
278 diff = perf_diff__compute_delta(he);
279
280 if (fabs(diff) >= 0.01)
281 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
282
283 return scnprintf(hpp->buf, hpp->size, fmt, buf);
284}
285
286static int hpp__header_ratio(struct perf_hpp *hpp)
287{
288 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
289
290 return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
291}
292
293static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
294{
295 return 14;
296}
297
298static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
299{
300 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
301 char buf[32] = " ";
302 double ratio;
303
304 if (he->diff.computed)
305 ratio = he->diff.period_ratio;
306 else
307 ratio = perf_diff__compute_ratio(he);
308
309 if (ratio > 0.0)
310 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
311
312 return scnprintf(hpp->buf, hpp->size, fmt, buf);
313}
314
315static int hpp__header_wdiff(struct perf_hpp *hpp)
316{
317 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
318
319 return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
320}
321
322static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
323{
324 return 14;
325}
326
327static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
328{
329 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
330 char buf[32] = " ";
331 s64 wdiff;
332
333 if (he->diff.computed)
334 wdiff = he->diff.wdiff;
335 else
336 wdiff = perf_diff__compute_wdiff(he);
337
338 if (wdiff != 0)
339 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
340
341 return scnprintf(hpp->buf, hpp->size, fmt, buf);
342}
343
344static int hpp__header_displ(struct perf_hpp *hpp)
345{
346 return scnprintf(hpp->buf, hpp->size, "Displ.");
347}
348
349static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
350{
351 return 6;
352}
353
354static int hpp__entry_displ(struct perf_hpp *hpp,
355 struct hist_entry *he)
356{
357 struct hist_entry *pair = hist_entry__next_pair(he);
358 long displacement = pair ? pair->position - he->position : 0;
359 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
360 char buf[32] = " ";
361
362 if (displacement)
363 scnprintf(buf, sizeof(buf), "%+4ld", displacement);
364
365 return scnprintf(hpp->buf, hpp->size, fmt, buf);
366}
367
368static int hpp__header_formula(struct perf_hpp *hpp)
369{
370 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
371
372 return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
373}
374
375static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
376{
377 return 70;
378}
379
380static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
381{
382 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
383 char buf[96] = " ";
384
385 perf_diff__formula(buf, sizeof(buf), he);
386 return scnprintf(hpp->buf, hpp->size, fmt, buf);
387}
388
389#define HPP__COLOR_PRINT_FNS(_name) \
390 .header = hpp__header_ ## _name, \
391 .width = hpp__width_ ## _name, \
392 .color = hpp__color_ ## _name, \
393 .entry = hpp__entry_ ## _name
394
395#define HPP__PRINT_FNS(_name) \
396 .header = hpp__header_ ## _name, \
397 .width = hpp__width_ ## _name, \
398 .entry = hpp__entry_ ## _name
399
400struct perf_hpp_fmt perf_hpp__format[] = {
401 { .cond = false, HPP__COLOR_PRINT_FNS(baseline) },
402 { .cond = true, HPP__COLOR_PRINT_FNS(overhead) },
403 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) },
404 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) },
405 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) },
406 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
407 { .cond = false, HPP__PRINT_FNS(samples) },
408 { .cond = false, HPP__PRINT_FNS(period) },
409 { .cond = false, HPP__PRINT_FNS(period_baseline) },
410 { .cond = false, HPP__PRINT_FNS(delta) },
411 { .cond = false, HPP__PRINT_FNS(ratio) },
412 { .cond = false, HPP__PRINT_FNS(wdiff) },
413 { .cond = false, HPP__PRINT_FNS(displ) },
414 { .cond = false, HPP__PRINT_FNS(formula) }
415};
416
417#undef HPP__COLOR_PRINT_FNS
418#undef HPP__PRINT_FNS
419
420void perf_hpp__init(void)
421{
422 if (symbol_conf.show_cpu_utilization) {
423 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
424 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true;
425
426 if (perf_guest) {
427 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true;
428 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true;
429 }
430 }
431
432 if (symbol_conf.show_nr_samples)
433 perf_hpp__format[PERF_HPP__SAMPLES].cond = true;
434
435 if (symbol_conf.show_total_period)
436 perf_hpp__format[PERF_HPP__PERIOD].cond = true;
437}
438
439void perf_hpp__column_enable(unsigned col, bool enable)
440{
441 BUG_ON(col >= PERF_HPP__MAX_INDEX);
442 perf_hpp__format[col].cond = enable;
443}
444
445static inline void advance_hpp(struct perf_hpp *hpp, int inc)
446{
447 hpp->buf += inc;
448 hpp->size -= inc;
449}
450
451int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
452 bool color)
453{
454 const char *sep = symbol_conf.field_sep;
455 char *start = hpp->buf;
456 int i, ret;
457 bool first = true;
458
459 if (symbol_conf.exclude_other && !he->parent)
460 return 0;
461
462 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
463 if (!perf_hpp__format[i].cond)
464 continue;
465
466 if (!sep || !first) {
467 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
468 advance_hpp(hpp, ret);
469 first = false;
470 }
471
472 if (color && perf_hpp__format[i].color)
473 ret = perf_hpp__format[i].color(hpp, he);
474 else
475 ret = perf_hpp__format[i].entry(hpp, he);
476
477 advance_hpp(hpp, ret);
478 }
479
480 return hpp->buf - start;
481}
482
483int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
484 struct hists *hists)
485{
486 const char *sep = symbol_conf.field_sep;
487 struct sort_entry *se;
488 int ret = 0;
489
490 list_for_each_entry(se, &hist_entry__sort_list, list) {
491 if (se->elide)
492 continue;
493
494 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " ");
495 ret += se->se_snprintf(he, s + ret, size - ret,
496 hists__col_len(hists, se->se_width_idx));
497 }
498
499 return ret;
500}
501
502/*
503 * See hists__fprintf to match the column widths
504 */
505unsigned int hists__sort_list_width(struct hists *hists)
506{
507 struct sort_entry *se;
508 int i, ret = 0;
509
510 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
511 if (!perf_hpp__format[i].cond)
512 continue;
513 if (i)
514 ret += 2;
515
516 ret += perf_hpp__format[i].width(NULL);
517 }
518
519 list_for_each_entry(se, &hist_entry__sort_list, list)
520 if (!se->elide)
521 ret += 2 + hists__col_len(hists, se->se_width_idx);
522
523 if (verbose) /* Addr + origin */
524 ret += 3 + BITS_PER_LONG / 4;
525
526 return ret;
527}
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h
deleted file mode 100644
index 809eca5707f..00000000000
--- a/tools/perf/ui/keysyms.h
+++ /dev/null
@@ -1,27 +0,0 @@
1#ifndef _PERF_KEYSYMS_H_
2#define _PERF_KEYSYMS_H_ 1
3
4#include "libslang.h"
5
6#define K_DOWN SL_KEY_DOWN
7#define K_END SL_KEY_END
8#define K_ENTER '\r'
9#define K_ESC 033
10#define K_F1 SL_KEY_F(1)
11#define K_HOME SL_KEY_HOME
12#define K_LEFT SL_KEY_LEFT
13#define K_PGDN SL_KEY_NPAGE
14#define K_PGUP SL_KEY_PPAGE
15#define K_RIGHT SL_KEY_RIGHT
16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP
19#define K_BKSPC 0x7f
20#define K_DEL SL_KEY_DELETE
21
22/* Not really keys */
23#define K_TIMER -1
24#define K_ERROR -2
25#define K_RESIZE -3
26
27#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/ui/libslang.h b/tools/perf/ui/libslang.h
deleted file mode 100644
index 4d54b6450f5..00000000000
--- a/tools/perf/ui/libslang.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef _PERF_UI_SLANG_H_
2#define _PERF_UI_SLANG_H_ 1
3/*
4 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
5 * the build if it isn't defined. Use the equivalent one that glibc
6 * has on features.h.
7 */
8#include <features.h>
9#ifndef HAVE_LONG_LONG
10#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
11#endif
12#include <slang.h>
13
14#if SLANG_VERSION < 20104
15#define slsmg_printf(msg, args...) \
16 SLsmg_printf((char *)(msg), ##args)
17#define slsmg_write_nstring(msg, len) \
18 SLsmg_write_nstring((char *)(msg), len)
19#define sltt_set_color(obj, name, fg, bg) \
20 SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
21#else
22#define slsmg_printf SLsmg_printf
23#define slsmg_write_nstring SLsmg_write_nstring
24#define sltt_set_color SLtt_set_color
25#endif
26
27#define SL_KEY_UNTAB 0x1000
28
29#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c
deleted file mode 100644
index 3ec695607a4..00000000000
--- a/tools/perf/ui/progress.c
+++ /dev/null
@@ -1,26 +0,0 @@
1#include "../cache.h"
2#include "progress.h"
3
4static void nop_progress_update(u64 curr __maybe_unused,
5 u64 total __maybe_unused,
6 const char *title __maybe_unused)
7{
8}
9
10static struct ui_progress default_progress_fns =
11{
12 .update = nop_progress_update,
13};
14
15struct ui_progress *progress_fns = &default_progress_fns;
16
17void ui_progress__update(u64 curr, u64 total, const char *title)
18{
19 return progress_fns->update(curr, total, title);
20}
21
22void ui_progress__finish(void)
23{
24 if (progress_fns->finish)
25 progress_fns->finish();
26}
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
deleted file mode 100644
index 257cc224f9c..00000000000
--- a/tools/perf/ui/progress.h
+++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef _PERF_UI_PROGRESS_H_
2#define _PERF_UI_PROGRESS_H_ 1
3
4#include <../types.h>
5
6struct ui_progress {
7 void (*update)(u64, u64, const char *);
8 void (*finish)(void);
9};
10
11extern struct ui_progress *progress_fns;
12
13void ui_progress__init(void);
14
15void ui_progress__update(u64 curr, u64 total, const char *title);
16void ui_progress__finish(void);
17
18#endif
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
deleted file mode 100644
index ebb4cc10787..00000000000
--- a/tools/perf/ui/setup.c
+++ /dev/null
@@ -1,52 +0,0 @@
1#include <pthread.h>
2
3#include "../util/cache.h"
4#include "../util/debug.h"
5#include "../util/hist.h"
6
7pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
8
9void setup_browser(bool fallback_to_pager)
10{
11 if (!isatty(1) || dump_trace)
12 use_browser = 0;
13
14 /* default to TUI */
15 if (use_browser < 0)
16 use_browser = 1;
17
18 switch (use_browser) {
19 case 2:
20 if (perf_gtk__init() == 0)
21 break;
22 /* fall through */
23 case 1:
24 use_browser = 1;
25 if (ui__init() == 0)
26 break;
27 /* fall through */
28 default:
29 use_browser = 0;
30 if (fallback_to_pager)
31 setup_pager();
32
33 perf_hpp__init();
34 break;
35 }
36}
37
38void exit_browser(bool wait_for_ok)
39{
40 switch (use_browser) {
41 case 2:
42 perf_gtk__exit(wait_for_ok);
43 break;
44
45 case 1:
46 ui__exit(wait_for_ok);
47 break;
48
49 default:
50 break;
51 }
52}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
deleted file mode 100644
index f0ee204f99b..00000000000
--- a/tools/perf/ui/stdio/hist.c
+++ /dev/null
@@ -1,485 +0,0 @@
1#include <stdio.h>
2
3#include "../../util/util.h"
4#include "../../util/hist.h"
5#include "../../util/sort.h"
6
7
8static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
9{
10 int i;
11 int ret = fprintf(fp, " ");
12
13 for (i = 0; i < left_margin; i++)
14 ret += fprintf(fp, " ");
15
16 return ret;
17}
18
19static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
20 int left_margin)
21{
22 int i;
23 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
24
25 for (i = 0; i < depth; i++)
26 if (depth_mask & (1 << i))
27 ret += fprintf(fp, "| ");
28 else
29 ret += fprintf(fp, " ");
30
31 ret += fprintf(fp, "\n");
32
33 return ret;
34}
35
36static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
37 int depth, int depth_mask, int period,
38 u64 total_samples, u64 hits,
39 int left_margin)
40{
41 int i;
42 size_t ret = 0;
43
44 ret += callchain__fprintf_left_margin(fp, left_margin);
45 for (i = 0; i < depth; i++) {
46 if (depth_mask & (1 << i))
47 ret += fprintf(fp, "|");
48 else
49 ret += fprintf(fp, " ");
50 if (!period && i == depth - 1) {
51 double percent;
52
53 percent = hits * 100.0 / total_samples;
54 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
55 } else
56 ret += fprintf(fp, "%s", " ");
57 }
58 if (chain->ms.sym)
59 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
60 else
61 ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
62
63 return ret;
64}
65
66static struct symbol *rem_sq_bracket;
67static struct callchain_list rem_hits;
68
69static void init_rem_hits(void)
70{
71 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
72 if (!rem_sq_bracket) {
73 fprintf(stderr, "Not enough memory to display remaining hits\n");
74 return;
75 }
76
77 strcpy(rem_sq_bracket->name, "[...]");
78 rem_hits.ms.sym = rem_sq_bracket;
79}
80
81static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
82 u64 total_samples, int depth,
83 int depth_mask, int left_margin)
84{
85 struct rb_node *node, *next;
86 struct callchain_node *child;
87 struct callchain_list *chain;
88 int new_depth_mask = depth_mask;
89 u64 remaining;
90 size_t ret = 0;
91 int i;
92 uint entries_printed = 0;
93
94 remaining = total_samples;
95
96 node = rb_first(root);
97 while (node) {
98 u64 new_total;
99 u64 cumul;
100
101 child = rb_entry(node, struct callchain_node, rb_node);
102 cumul = callchain_cumul_hits(child);
103 remaining -= cumul;
104
105 /*
106 * The depth mask manages the output of pipes that show
107 * the depth. We don't want to keep the pipes of the current
108 * level for the last child of this depth.
109 * Except if we have remaining filtered hits. They will
110 * supersede the last child
111 */
112 next = rb_next(node);
113 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
114 new_depth_mask &= ~(1 << (depth - 1));
115
116 /*
117 * But we keep the older depth mask for the line separator
118 * to keep the level link until we reach the last child
119 */
120 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
121 left_margin);
122 i = 0;
123 list_for_each_entry(chain, &child->val, list) {
124 ret += ipchain__fprintf_graph(fp, chain, depth,
125 new_depth_mask, i++,
126 total_samples,
127 cumul,
128 left_margin);
129 }
130
131 if (callchain_param.mode == CHAIN_GRAPH_REL)
132 new_total = child->children_hit;
133 else
134 new_total = total_samples;
135
136 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
137 depth + 1,
138 new_depth_mask | (1 << depth),
139 left_margin);
140 node = next;
141 if (++entries_printed == callchain_param.print_limit)
142 break;
143 }
144
145 if (callchain_param.mode == CHAIN_GRAPH_REL &&
146 remaining && remaining != total_samples) {
147
148 if (!rem_sq_bracket)
149 return ret;
150
151 new_depth_mask &= ~(1 << (depth - 1));
152 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
153 new_depth_mask, 0, total_samples,
154 remaining, left_margin);
155 }
156
157 return ret;
158}
159
160static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
161 u64 total_samples, int left_margin)
162{
163 struct callchain_node *cnode;
164 struct callchain_list *chain;
165 u32 entries_printed = 0;
166 bool printed = false;
167 struct rb_node *node;
168 int i = 0;
169 int ret = 0;
170
171 /*
172 * If have one single callchain root, don't bother printing
173 * its percentage (100 % in fractal mode and the same percentage
174 * than the hist in graph mode). This also avoid one level of column.
175 */
176 node = rb_first(root);
177 if (node && !rb_next(node)) {
178 cnode = rb_entry(node, struct callchain_node, rb_node);
179 list_for_each_entry(chain, &cnode->val, list) {
180 /*
181 * If we sort by symbol, the first entry is the same than
182 * the symbol. No need to print it otherwise it appears as
183 * displayed twice.
184 */
185 if (!i++ && sort__first_dimension == SORT_SYM)
186 continue;
187 if (!printed) {
188 ret += callchain__fprintf_left_margin(fp, left_margin);
189 ret += fprintf(fp, "|\n");
190 ret += callchain__fprintf_left_margin(fp, left_margin);
191 ret += fprintf(fp, "---");
192 left_margin += 3;
193 printed = true;
194 } else
195 ret += callchain__fprintf_left_margin(fp, left_margin);
196
197 if (chain->ms.sym)
198 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
199 else
200 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
201
202 if (++entries_printed == callchain_param.print_limit)
203 break;
204 }
205 root = &cnode->rb_root;
206 }
207
208 ret += __callchain__fprintf_graph(fp, root, total_samples,
209 1, 1, left_margin);
210 ret += fprintf(fp, "\n");
211
212 return ret;
213}
214
215static size_t __callchain__fprintf_flat(FILE *fp,
216 struct callchain_node *self,
217 u64 total_samples)
218{
219 struct callchain_list *chain;
220 size_t ret = 0;
221
222 if (!self)
223 return 0;
224
225 ret += __callchain__fprintf_flat(fp, self->parent, total_samples);
226
227
228 list_for_each_entry(chain, &self->val, list) {
229 if (chain->ip >= PERF_CONTEXT_MAX)
230 continue;
231 if (chain->ms.sym)
232 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
233 else
234 ret += fprintf(fp, " %p\n",
235 (void *)(long)chain->ip);
236 }
237
238 return ret;
239}
240
241static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self,
242 u64 total_samples)
243{
244 size_t ret = 0;
245 u32 entries_printed = 0;
246 struct rb_node *rb_node;
247 struct callchain_node *chain;
248
249 rb_node = rb_first(self);
250 while (rb_node) {
251 double percent;
252
253 chain = rb_entry(rb_node, struct callchain_node, rb_node);
254 percent = chain->hit * 100.0 / total_samples;
255
256 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent);
257 ret += __callchain__fprintf_flat(fp, chain, total_samples);
258 ret += fprintf(fp, "\n");
259 if (++entries_printed == callchain_param.print_limit)
260 break;
261
262 rb_node = rb_next(rb_node);
263 }
264
265 return ret;
266}
267
268static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
269 u64 total_samples, int left_margin,
270 FILE *fp)
271{
272 switch (callchain_param.mode) {
273 case CHAIN_GRAPH_REL:
274 return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period,
275 left_margin);
276 break;
277 case CHAIN_GRAPH_ABS:
278 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
279 left_margin);
280 break;
281 case CHAIN_FLAT:
282 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
283 break;
284 case CHAIN_NONE:
285 break;
286 default:
287 pr_err("Bad callchain mode\n");
288 }
289
290 return 0;
291}
292
293static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
294 struct hists *hists,
295 FILE *fp)
296{
297 int left_margin = 0;
298 u64 total_period = hists->stats.total_period;
299
300 if (sort__first_dimension == SORT_COMM) {
301 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
302 typeof(*se), list);
303 left_margin = hists__col_len(hists, se->se_width_idx);
304 left_margin -= thread__comm_len(he->thread);
305 }
306
307 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
308}
309
310static int hist_entry__fprintf(struct hist_entry *he, size_t size,
311 struct hists *hists, FILE *fp)
312{
313 char bf[512];
314 int ret;
315 struct perf_hpp hpp = {
316 .buf = bf,
317 .size = size,
318 };
319 bool color = !symbol_conf.field_sep;
320
321 if (size == 0 || size > sizeof(bf))
322 size = hpp.size = sizeof(bf);
323
324 ret = hist_entry__period_snprintf(&hpp, he, color);
325 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
326
327 ret = fprintf(fp, "%s\n", bf);
328
329 if (symbol_conf.use_callchain)
330 ret += hist_entry__callchain_fprintf(he, hists, fp);
331
332 return ret;
333}
334
335size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
336 int max_cols, FILE *fp)
337{
338 struct sort_entry *se;
339 struct rb_node *nd;
340 size_t ret = 0;
341 unsigned int width;
342 const char *sep = symbol_conf.field_sep;
343 const char *col_width = symbol_conf.col_width_list_str;
344 int idx, nr_rows = 0;
345 char bf[96];
346 struct perf_hpp dummy_hpp = {
347 .buf = bf,
348 .size = sizeof(bf),
349 };
350 bool first = true;
351
352 init_rem_hits();
353
354 if (!show_header)
355 goto print_entries;
356
357 fprintf(fp, "# ");
358 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
359 if (!perf_hpp__format[idx].cond)
360 continue;
361
362 if (!first)
363 fprintf(fp, "%s", sep ?: " ");
364 else
365 first = false;
366
367 perf_hpp__format[idx].header(&dummy_hpp);
368 fprintf(fp, "%s", bf);
369 }
370
371 list_for_each_entry(se, &hist_entry__sort_list, list) {
372 if (se->elide)
373 continue;
374 if (sep) {
375 fprintf(fp, "%c%s", *sep, se->se_header);
376 continue;
377 }
378 width = strlen(se->se_header);
379 if (symbol_conf.col_width_list_str) {
380 if (col_width) {
381 hists__set_col_len(hists, se->se_width_idx,
382 atoi(col_width));
383 col_width = strchr(col_width, ',');
384 if (col_width)
385 ++col_width;
386 }
387 }
388 if (!hists__new_col_len(hists, se->se_width_idx, width))
389 width = hists__col_len(hists, se->se_width_idx);
390 fprintf(fp, " %*s", width, se->se_header);
391 }
392
393 fprintf(fp, "\n");
394 if (max_rows && ++nr_rows >= max_rows)
395 goto out;
396
397 if (sep)
398 goto print_entries;
399
400 first = true;
401
402 fprintf(fp, "# ");
403 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
404 unsigned int i;
405
406 if (!perf_hpp__format[idx].cond)
407 continue;
408
409 if (!first)
410 fprintf(fp, "%s", sep ?: " ");
411 else
412 first = false;
413
414 width = perf_hpp__format[idx].width(&dummy_hpp);
415 for (i = 0; i < width; i++)
416 fprintf(fp, ".");
417 }
418
419 list_for_each_entry(se, &hist_entry__sort_list, list) {
420 unsigned int i;
421
422 if (se->elide)
423 continue;
424
425 fprintf(fp, " ");
426 width = hists__col_len(hists, se->se_width_idx);
427 if (width == 0)
428 width = strlen(se->se_header);
429 for (i = 0; i < width; i++)
430 fprintf(fp, ".");
431 }
432
433 fprintf(fp, "\n");
434 if (max_rows && ++nr_rows >= max_rows)
435 goto out;
436
437 fprintf(fp, "#\n");
438 if (max_rows && ++nr_rows >= max_rows)
439 goto out;
440
441print_entries:
442 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
443 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
444
445 if (h->filtered)
446 continue;
447
448 ret += hist_entry__fprintf(h, max_cols, hists, fp);
449
450 if (max_rows && ++nr_rows >= max_rows)
451 goto out;
452
453 if (h->ms.map == NULL && verbose > 1) {
454 __map_groups__fprintf_maps(&h->thread->mg,
455 MAP__FUNCTION, verbose, fp);
456 fprintf(fp, "%.10s end\n", graph_dotted_line);
457 }
458 }
459out:
460 free(rem_sq_bracket);
461
462 return ret;
463}
464
465size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
466{
467 int i;
468 size_t ret = 0;
469
470 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
471 const char *name;
472
473 if (hists->stats.nr_events[i] == 0)
474 continue;
475
476 name = perf_event__name(i);
477 if (!strcmp(name, "UNKNOWN"))
478 continue;
479
480 ret += fprintf(fp, "%16s events: %10d\n", name,
481 hists->stats.nr_events[i]);
482 }
483
484 return ret;
485}
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c
deleted file mode 100644
index 2884d2f41e3..00000000000
--- a/tools/perf/ui/tui/helpline.c
+++ /dev/null
@@ -1,57 +0,0 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <pthread.h>
5
6#include "../../util/debug.h"
7#include "../helpline.h"
8#include "../ui.h"
9#include "../libslang.h"
10
11static void tui_helpline__pop(void)
12{
13}
14
15static void tui_helpline__push(const char *msg)
16{
17 const size_t sz = sizeof(ui_helpline__current);
18
19 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
20 SLsmg_set_color(0);
21 SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
22 SLsmg_refresh();
23 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
24}
25
26struct ui_helpline tui_helpline_fns = {
27 .pop = tui_helpline__pop,
28 .push = tui_helpline__push,
29};
30
31void ui_helpline__init(void)
32{
33 helpline_fns = &tui_helpline_fns;
34 ui_helpline__puts(" ");
35}
36
37char ui_helpline__last_msg[1024];
38
39int ui_helpline__show_help(const char *format, va_list ap)
40{
41 int ret;
42 static int backlog;
43
44 pthread_mutex_lock(&ui__lock);
45 ret = vscnprintf(ui_helpline__last_msg + backlog,
46 sizeof(ui_helpline__last_msg) - backlog, format, ap);
47 backlog += ret;
48
49 if (ui_helpline__last_msg[backlog - 1] == '\n') {
50 ui_helpline__puts(ui_helpline__last_msg);
51 SLsmg_refresh();
52 backlog = 0;
53 }
54 pthread_mutex_unlock(&ui__lock);
55
56 return ret;
57}
diff --git a/tools/perf/ui/tui/progress.c b/tools/perf/ui/tui/progress.c
deleted file mode 100644
index 6c2184d53cb..00000000000
--- a/tools/perf/ui/tui/progress.c
+++ /dev/null
@@ -1,42 +0,0 @@
1#include "../cache.h"
2#include "../progress.h"
3#include "../libslang.h"
4#include "../ui.h"
5#include "../browser.h"
6
7static void tui_progress__update(u64 curr, u64 total, const char *title)
8{
9 int bar, y;
10 /*
11 * FIXME: We should have a per UI backend way of showing progress,
12 * stdio will just show a percentage as NN%, etc.
13 */
14 if (use_browser <= 0)
15 return;
16
17 if (total == 0)
18 return;
19
20 ui__refresh_dimensions(true);
21 pthread_mutex_lock(&ui__lock);
22 y = SLtt_Screen_Rows / 2 - 2;
23 SLsmg_set_color(0);
24 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
25 SLsmg_gotorc(y++, 1);
26 SLsmg_write_string((char *)title);
27 SLsmg_set_color(HE_COLORSET_SELECTED);
28 bar = ((SLtt_Screen_Cols - 2) * curr) / total;
29 SLsmg_fill_region(y, 1, 1, bar, ' ');
30 SLsmg_refresh();
31 pthread_mutex_unlock(&ui__lock);
32}
33
34static struct ui_progress tui_progress_fns =
35{
36 .update = tui_progress__update,
37};
38
39void ui_progress__init(void)
40{
41 progress_fns = &tui_progress_fns;
42}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
deleted file mode 100644
index 81efa192e86..00000000000
--- a/tools/perf/ui/tui/setup.c
+++ /dev/null
@@ -1,149 +0,0 @@
1#include <newt.h>
2#include <signal.h>
3#include <stdbool.h>
4
5#include "../../util/cache.h"
6#include "../../util/debug.h"
7#include "../browser.h"
8#include "../helpline.h"
9#include "../ui.h"
10#include "../util.h"
11#include "../libslang.h"
12#include "../keysyms.h"
13
14static volatile int ui__need_resize;
15
16extern struct perf_error_ops perf_tui_eops;
17
18extern void hist_browser__init_hpp(void);
19
20void ui__refresh_dimensions(bool force)
21{
22 if (force || ui__need_resize) {
23 ui__need_resize = 0;
24 pthread_mutex_lock(&ui__lock);
25 SLtt_get_screen_size();
26 SLsmg_reinit_smg();
27 pthread_mutex_unlock(&ui__lock);
28 }
29}
30
31static void ui__sigwinch(int sig __maybe_unused)
32{
33 ui__need_resize = 1;
34}
35
36static void ui__setup_sigwinch(void)
37{
38 static bool done;
39
40 if (done)
41 return;
42
43 done = true;
44 pthread__unblock_sigwinch();
45 signal(SIGWINCH, ui__sigwinch);
46}
47
48int ui__getch(int delay_secs)
49{
50 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
51 fd_set read_set;
52 int err, key;
53
54 ui__setup_sigwinch();
55
56 FD_ZERO(&read_set);
57 FD_SET(0, &read_set);
58
59 if (delay_secs) {
60 timeout.tv_sec = delay_secs;
61 timeout.tv_usec = 0;
62 }
63
64 err = select(1, &read_set, NULL, NULL, ptimeout);
65
66 if (err == 0)
67 return K_TIMER;
68
69 if (err == -1) {
70 if (errno == EINTR)
71 return K_RESIZE;
72 return K_ERROR;
73 }
74
75 key = SLang_getkey();
76 if (key != K_ESC)
77 return key;
78
79 FD_ZERO(&read_set);
80 FD_SET(0, &read_set);
81 timeout.tv_sec = 0;
82 timeout.tv_usec = 20;
83 err = select(1, &read_set, NULL, NULL, &timeout);
84 if (err == 0)
85 return K_ESC;
86
87 SLang_ungetkey(key);
88 return SLkp_getkey();
89}
90
91static void newt_suspend(void *d __maybe_unused)
92{
93 newtSuspend();
94 raise(SIGTSTP);
95 newtResume();
96}
97
98static void ui__signal(int sig)
99{
100 ui__exit(false);
101 psignal(sig, "perf");
102 exit(0);
103}
104
105int ui__init(void)
106{
107 int err;
108
109 newtInit();
110 err = SLkp_init();
111 if (err < 0) {
112 pr_err("TUI initialization failed.\n");
113 goto out;
114 }
115
116 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
117
118 newtSetSuspendCallback(newt_suspend, NULL);
119 ui_helpline__init();
120 ui_browser__init();
121 ui_progress__init();
122
123 signal(SIGSEGV, ui__signal);
124 signal(SIGFPE, ui__signal);
125 signal(SIGINT, ui__signal);
126 signal(SIGQUIT, ui__signal);
127 signal(SIGTERM, ui__signal);
128
129 perf_error__register(&perf_tui_eops);
130
131 hist_browser__init_hpp();
132out:
133 return err;
134}
135
136void ui__exit(bool wait_for_ok)
137{
138 if (wait_for_ok)
139 ui__question_window("Fatal Error",
140 ui_helpline__last_msg,
141 "Press any key...", 0);
142
143 SLtt_set_cursor_visibility(1);
144 SLsmg_refresh();
145 SLsmg_reset_smg();
146 SLang_reset_tty();
147
148 perf_error__unregister(&perf_tui_eops);
149}
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
deleted file mode 100644
index 092902e30ce..00000000000
--- a/tools/perf/ui/tui/util.c
+++ /dev/null
@@ -1,243 +0,0 @@
1#include "../../util/util.h"
2#include <signal.h>
3#include <stdbool.h>
4#include <string.h>
5#include <sys/ttydefaults.h>
6
7#include "../../util/cache.h"
8#include "../../util/debug.h"
9#include "../browser.h"
10#include "../keysyms.h"
11#include "../helpline.h"
12#include "../ui.h"
13#include "../util.h"
14#include "../libslang.h"
15
16static void ui_browser__argv_write(struct ui_browser *browser,
17 void *entry, int row)
18{
19 char **arg = entry;
20 bool current_entry = ui_browser__is_current_entry(browser, row);
21
22 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
23 HE_COLORSET_NORMAL);
24 slsmg_write_nstring(*arg, browser->width);
25}
26
27static int popup_menu__run(struct ui_browser *menu)
28{
29 int key;
30
31 if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
32 return -1;
33
34 while (1) {
35 key = ui_browser__run(menu, 0);
36
37 switch (key) {
38 case K_RIGHT:
39 case K_ENTER:
40 key = menu->index;
41 break;
42 case K_LEFT:
43 case K_ESC:
44 case 'q':
45 case CTRL('c'):
46 key = -1;
47 break;
48 default:
49 continue;
50 }
51
52 break;
53 }
54
55 ui_browser__hide(menu);
56 return key;
57}
58
59int ui__popup_menu(int argc, char * const argv[])
60{
61 struct ui_browser menu = {
62 .entries = (void *)argv,
63 .refresh = ui_browser__argv_refresh,
64 .seek = ui_browser__argv_seek,
65 .write = ui_browser__argv_write,
66 .nr_entries = argc,
67 };
68
69 return popup_menu__run(&menu);
70}
71
72int ui_browser__input_window(const char *title, const char *text, char *input,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y, len, key;
76 int max_len = 60, nr_lines = 0;
77 static char buf[50];
78 const char *t;
79
80 t = text;
81 while (1) {
82 const char *sep = strchr(t, '\n');
83
84 if (sep == NULL)
85 sep = strchr(t, '\0');
86 len = sep - t;
87 if (max_len < len)
88 max_len = len;
89 ++nr_lines;
90 if (*sep == '\0')
91 break;
92 t = sep + 1;
93 }
94
95 max_len += 2;
96 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
98 x = SLtt_Screen_Cols / 2 - max_len / 2;
99
100 SLsmg_set_color(0);
101 SLsmg_draw_box(y, x++, nr_lines, max_len);
102 if (title) {
103 SLsmg_gotorc(y, x + 1);
104 SLsmg_write_string((char *)title);
105 }
106 SLsmg_gotorc(++y, x);
107 nr_lines -= 7;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 y += nr_lines;
112 len = 5;
113 while (len--) {
114 SLsmg_gotorc(y + len - 1, x);
115 SLsmg_write_nstring((char *)" ", max_len);
116 }
117 SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
118
119 SLsmg_gotorc(y + 3, x);
120 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh();
122
123 x += 2;
124 len = 0;
125 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
127 if (key == K_BKSPC) {
128 if (len == 0)
129 goto next_key;
130 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' ');
132 } else {
133 buf[len] = key;
134 SLsmg_gotorc(y, x + len++);
135 SLsmg_write_char(key);
136 }
137 SLsmg_refresh();
138
139 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!");
142 key = K_ENTER;
143 break;
144 }
145next_key:
146 key = ui__getch(delay_secs);
147 }
148
149 buf[len] = '\0';
150 strncpy(input, buf, len+1);
151 return key;
152}
153
154int ui__question_window(const char *title, const char *text,
155 const char *exit_msg, int delay_secs)
156{
157 int x, y;
158 int max_len = 0, nr_lines = 0;
159 const char *t;
160
161 t = text;
162 while (1) {
163 const char *sep = strchr(t, '\n');
164 int len;
165
166 if (sep == NULL)
167 sep = strchr(t, '\0');
168 len = sep - t;
169 if (max_len < len)
170 max_len = len;
171 ++nr_lines;
172 if (*sep == '\0')
173 break;
174 t = sep + 1;
175 }
176
177 max_len += 2;
178 nr_lines += 4;
179 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
180 x = SLtt_Screen_Cols / 2 - max_len / 2;
181
182 SLsmg_set_color(0);
183 SLsmg_draw_box(y, x++, nr_lines, max_len);
184 if (title) {
185 SLsmg_gotorc(y, x + 1);
186 SLsmg_write_string((char *)title);
187 }
188 SLsmg_gotorc(++y, x);
189 nr_lines -= 2;
190 max_len -= 2;
191 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
192 nr_lines, max_len, 1);
193 SLsmg_gotorc(y + nr_lines - 2, x);
194 SLsmg_write_nstring((char *)" ", max_len);
195 SLsmg_gotorc(y + nr_lines - 1, x);
196 SLsmg_write_nstring((char *)exit_msg, max_len);
197 SLsmg_refresh();
198 return ui__getch(delay_secs);
199}
200
201int ui__help_window(const char *text)
202{
203 return ui__question_window("Help", text, "Press any key...", 0);
204}
205
206int ui__dialog_yesno(const char *msg)
207{
208 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
209}
210
211static int __ui__warning(const char *title, const char *format, va_list args)
212{
213 char *s;
214
215 if (vasprintf(&s, format, args) > 0) {
216 int key;
217
218 pthread_mutex_lock(&ui__lock);
219 key = ui__question_window(title, s, "Press any key...", 0);
220 pthread_mutex_unlock(&ui__lock);
221 free(s);
222 return key;
223 }
224
225 fprintf(stderr, "%s\n", title);
226 vfprintf(stderr, format, args);
227 return K_ESC;
228}
229
230static int perf_tui__error(const char *format, va_list args)
231{
232 return __ui__warning("Error:", format, args);
233}
234
235static int perf_tui__warning(const char *format, va_list args)
236{
237 return __ui__warning("Warning:", format, args);
238}
239
240struct perf_error_ops perf_tui_eops = {
241 .error = perf_tui__error,
242 .warning = perf_tui__warning,
243};
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
deleted file mode 100644
index d86359c9990..00000000000
--- a/tools/perf/ui/ui.h
+++ /dev/null
@@ -1,39 +0,0 @@
1#ifndef _PERF_UI_H_
2#define _PERF_UI_H_ 1
3
4#include <pthread.h>
5#include <stdbool.h>
6#include <linux/compiler.h>
7
8extern pthread_mutex_t ui__lock;
9
10extern int use_browser;
11
12void setup_browser(bool fallback_to_pager);
13void exit_browser(bool wait_for_ok);
14
15#ifdef NEWT_SUPPORT
16int ui__init(void);
17void ui__exit(bool wait_for_ok);
18#else
19static inline int ui__init(void)
20{
21 return -1;
22}
23static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
24#endif
25
26#ifdef GTK2_SUPPORT
27int perf_gtk__init(void);
28void perf_gtk__exit(bool wait_for_ok);
29#else
30static inline int perf_gtk__init(void)
31{
32 return -1;
33}
34static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
35#endif
36
37void ui__refresh_dimensions(bool force);
38
39#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
deleted file mode 100644
index 4f989774c8c..00000000000
--- a/tools/perf/ui/util.c
+++ /dev/null
@@ -1,85 +0,0 @@
1#include "util.h"
2#include "../debug.h"
3
4
5/*
6 * Default error logging functions
7 */
8static int perf_stdio__error(const char *format, va_list args)
9{
10 fprintf(stderr, "Error:\n");
11 vfprintf(stderr, format, args);
12 return 0;
13}
14
15static int perf_stdio__warning(const char *format, va_list args)
16{
17 fprintf(stderr, "Warning:\n");
18 vfprintf(stderr, format, args);
19 return 0;
20}
21
22static struct perf_error_ops default_eops =
23{
24 .error = perf_stdio__error,
25 .warning = perf_stdio__warning,
26};
27
28static struct perf_error_ops *perf_eops = &default_eops;
29
30
31int ui__error(const char *format, ...)
32{
33 int ret;
34 va_list args;
35
36 va_start(args, format);
37 ret = perf_eops->error(format, args);
38 va_end(args);
39
40 return ret;
41}
42
43int ui__warning(const char *format, ...)
44{
45 int ret;
46 va_list args;
47
48 va_start(args, format);
49 ret = perf_eops->warning(format, args);
50 va_end(args);
51
52 return ret;
53}
54
55
56/**
57 * perf_error__register - Register error logging functions
58 * @eops: The pointer to error logging function struct
59 *
60 * Register UI-specific error logging functions. Before calling this,
61 * other logging functions should be unregistered, if any.
62 */
63int perf_error__register(struct perf_error_ops *eops)
64{
65 if (perf_eops != &default_eops)
66 return -1;
67
68 perf_eops = eops;
69 return 0;
70}
71
72/**
73 * perf_error__unregister - Unregister error logging functions
74 * @eops: The pointer to error logging function struct
75 *
76 * Unregister already registered error logging functions.
77 */
78int perf_error__unregister(struct perf_error_ops *eops)
79{
80 if (perf_eops != eops)
81 return -1;
82
83 perf_eops = &default_eops;
84 return 0;
85}
diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h
deleted file mode 100644
index 361f08c52d3..00000000000
--- a/tools/perf/ui/util.h
+++ /dev/null
@@ -1,21 +0,0 @@
1#ifndef _PERF_UI_UTIL_H_
2#define _PERF_UI_UTIL_H_ 1
3
4#include <stdarg.h>
5
6int ui__getch(int delay_secs);
7int ui__popup_menu(int argc, char * const argv[]);
8int ui__help_window(const char *text);
9int ui__dialog_yesno(const char *msg);
10int ui__question_window(const char *title, const char *text,
11 const char *exit_msg, int delay_secs);
12
13struct perf_error_ops {
14 int (*error)(const char *format, va_list args);
15 int (*warning)(const char *format, va_list args);
16};
17
18int perf_error__register(struct perf_error_ops *eops);
19int perf_error__unregister(struct perf_error_ops *eops);
20
21#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 6aa34e5afdc..ad73300f7ba 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -9,14 +9,18 @@ GVF=${OUTPUT}PERF-VERSION-FILE
9LF=' 9LF='
10' 10'
11 11
12#
13# First check if there is a .git to get the version from git describe 12# First check if there is a .git to get the version from git describe
14# otherwise try to get the version from the kernel Makefile 13# otherwise try to get the version from the kernel makefile
15#
16if test -d ../../.git -o -f ../../.git && 14if test -d ../../.git -o -f ../../.git &&
17 VN=$(git tag 2>/dev/null | tail -1 | grep -E "v[0-9].[0-9]*") 15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
16 case "$VN" in
17 *$LF*) (exit 1) ;;
18 v[0-9]*)
19 git update-index -q --refresh
20 test -z "$(git diff-index --name-only HEAD --)" ||
21 VN="$VN-dirty" ;;
22 esac
18then 23then
19 VN=$(echo $VN"-g"$(git log -1 --abbrev=4 --pretty=format:"%h" HEAD))
20 VN=$(echo "$VN" | sed -e 's/-/./g'); 24 VN=$(echo "$VN" | sed -e 's/-/./g');
21else 25else
22 VN=$(MAKEFLAGS= make -sC ../.. kernelversion) 26 VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
index e6d134773d0..b8144e80bb1 100644
--- a/tools/perf/util/alias.c
+++ b/tools/perf/util/alias.c
@@ -3,8 +3,7 @@
3static const char *alias_key; 3static const char *alias_key;
4static char *alias_val; 4static char *alias_val;
5 5
6static int alias_lookup_cb(const char *k, const char *v, 6static int alias_lookup_cb(const char *k, const char *v, void *cb __used)
7 void *cb __maybe_unused)
8{ 7{
9 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) { 8 if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
10 if (!v) 9 if (!v)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 07aaeea6000..e01af2b1a46 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -15,439 +15,25 @@
15#include "debug.h" 15#include "debug.h"
16#include "annotate.h" 16#include "annotate.h"
17#include <pthread.h> 17#include <pthread.h>
18#include <linux/bitops.h>
19 18
20const char *disassembler_style; 19int symbol__annotate_init(struct map *map __used, struct symbol *sym)
21const char *objdump_path;
22
23static struct ins *ins__find(const char *name);
24static int disasm_line__parse(char *line, char **namep, char **rawp);
25
26static void ins__delete(struct ins_operands *ops)
27{
28 free(ops->source.raw);
29 free(ops->source.name);
30 free(ops->target.raw);
31 free(ops->target.name);
32}
33
34static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
35 struct ins_operands *ops)
36{
37 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
38}
39
40int ins__scnprintf(struct ins *ins, char *bf, size_t size,
41 struct ins_operands *ops)
42{
43 if (ins->ops->scnprintf)
44 return ins->ops->scnprintf(ins, bf, size, ops);
45
46 return ins__raw_scnprintf(ins, bf, size, ops);
47}
48
49static int call__parse(struct ins_operands *ops)
50{
51 char *endptr, *tok, *name;
52
53 ops->target.addr = strtoull(ops->raw, &endptr, 16);
54
55 name = strchr(endptr, '<');
56 if (name == NULL)
57 goto indirect_call;
58
59 name++;
60
61 tok = strchr(name, '>');
62 if (tok == NULL)
63 return -1;
64
65 *tok = '\0';
66 ops->target.name = strdup(name);
67 *tok = '>';
68
69 return ops->target.name == NULL ? -1 : 0;
70
71indirect_call:
72 tok = strchr(endptr, '(');
73 if (tok != NULL) {
74 ops->target.addr = 0;
75 return 0;
76 }
77
78 tok = strchr(endptr, '*');
79 if (tok == NULL)
80 return -1;
81
82 ops->target.addr = strtoull(tok + 1, NULL, 16);
83 return 0;
84}
85
86static int call__scnprintf(struct ins *ins, char *bf, size_t size,
87 struct ins_operands *ops)
88{
89 if (ops->target.name)
90 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
91
92 if (ops->target.addr == 0)
93 return ins__raw_scnprintf(ins, bf, size, ops);
94
95 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
96}
97
98static struct ins_ops call_ops = {
99 .parse = call__parse,
100 .scnprintf = call__scnprintf,
101};
102
103bool ins__is_call(const struct ins *ins)
104{
105 return ins->ops == &call_ops;
106}
107
108static int jump__parse(struct ins_operands *ops)
109{
110 const char *s = strchr(ops->raw, '+');
111
112 ops->target.addr = strtoll(ops->raw, NULL, 16);
113
114 if (s++ != NULL)
115 ops->target.offset = strtoll(s, NULL, 16);
116 else
117 ops->target.offset = UINT64_MAX;
118
119 return 0;
120}
121
122static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
123 struct ins_operands *ops)
124{
125 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
126}
127
128static struct ins_ops jump_ops = {
129 .parse = jump__parse,
130 .scnprintf = jump__scnprintf,
131};
132
133bool ins__is_jump(const struct ins *ins)
134{
135 return ins->ops == &jump_ops;
136}
137
138static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
139{
140 char *endptr, *name, *t;
141
142 if (strstr(raw, "(%rip)") == NULL)
143 return 0;
144
145 *addrp = strtoull(comment, &endptr, 16);
146 name = strchr(endptr, '<');
147 if (name == NULL)
148 return -1;
149
150 name++;
151
152 t = strchr(name, '>');
153 if (t == NULL)
154 return 0;
155
156 *t = '\0';
157 *namep = strdup(name);
158 *t = '>';
159
160 return 0;
161}
162
163static int lock__parse(struct ins_operands *ops)
164{
165 char *name;
166
167 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
168 if (ops->locked.ops == NULL)
169 return 0;
170
171 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
172 goto out_free_ops;
173
174 ops->locked.ins = ins__find(name);
175 if (ops->locked.ins == NULL)
176 goto out_free_ops;
177
178 if (!ops->locked.ins->ops)
179 return 0;
180
181 if (ops->locked.ins->ops->parse)
182 ops->locked.ins->ops->parse(ops->locked.ops);
183
184 return 0;
185
186out_free_ops:
187 free(ops->locked.ops);
188 ops->locked.ops = NULL;
189 return 0;
190}
191
192static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
193 struct ins_operands *ops)
194{
195 int printed;
196
197 if (ops->locked.ins == NULL)
198 return ins__raw_scnprintf(ins, bf, size, ops);
199
200 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
201 return printed + ins__scnprintf(ops->locked.ins, bf + printed,
202 size - printed, ops->locked.ops);
203}
204
205static void lock__delete(struct ins_operands *ops)
206{
207 free(ops->locked.ops);
208 free(ops->target.raw);
209 free(ops->target.name);
210}
211
212static struct ins_ops lock_ops = {
213 .free = lock__delete,
214 .parse = lock__parse,
215 .scnprintf = lock__scnprintf,
216};
217
218static int mov__parse(struct ins_operands *ops)
219{
220 char *s = strchr(ops->raw, ','), *target, *comment, prev;
221
222 if (s == NULL)
223 return -1;
224
225 *s = '\0';
226 ops->source.raw = strdup(ops->raw);
227 *s = ',';
228
229 if (ops->source.raw == NULL)
230 return -1;
231
232 target = ++s;
233
234 while (s[0] != '\0' && !isspace(s[0]))
235 ++s;
236 prev = *s;
237 *s = '\0';
238
239 ops->target.raw = strdup(target);
240 *s = prev;
241
242 if (ops->target.raw == NULL)
243 goto out_free_source;
244
245 comment = strchr(s, '#');
246 if (comment == NULL)
247 return 0;
248
249 while (comment[0] != '\0' && isspace(comment[0]))
250 ++comment;
251
252 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
253 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
254
255 return 0;
256
257out_free_source:
258 free(ops->source.raw);
259 ops->source.raw = NULL;
260 return -1;
261}
262
263static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
264 struct ins_operands *ops)
265{
266 return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
267 ops->source.name ?: ops->source.raw,
268 ops->target.name ?: ops->target.raw);
269}
270
271static struct ins_ops mov_ops = {
272 .parse = mov__parse,
273 .scnprintf = mov__scnprintf,
274};
275
276static int dec__parse(struct ins_operands *ops)
277{
278 char *target, *comment, *s, prev;
279
280 target = s = ops->raw;
281
282 while (s[0] != '\0' && !isspace(s[0]))
283 ++s;
284 prev = *s;
285 *s = '\0';
286
287 ops->target.raw = strdup(target);
288 *s = prev;
289
290 if (ops->target.raw == NULL)
291 return -1;
292
293 comment = strchr(s, '#');
294 if (comment == NULL)
295 return 0;
296
297 while (comment[0] != '\0' && isspace(comment[0]))
298 ++comment;
299
300 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
301
302 return 0;
303}
304
305static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
306 struct ins_operands *ops)
307{
308 return scnprintf(bf, size, "%-6.6s %s", ins->name,
309 ops->target.name ?: ops->target.raw);
310}
311
312static struct ins_ops dec_ops = {
313 .parse = dec__parse,
314 .scnprintf = dec__scnprintf,
315};
316
317static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
318 struct ins_operands *ops __maybe_unused)
319{
320 return scnprintf(bf, size, "%-6.6s", "nop");
321}
322
323static struct ins_ops nop_ops = {
324 .scnprintf = nop__scnprintf,
325};
326
327/*
328 * Must be sorted by name!
329 */
330static struct ins instructions[] = {
331 { .name = "add", .ops = &mov_ops, },
332 { .name = "addl", .ops = &mov_ops, },
333 { .name = "addq", .ops = &mov_ops, },
334 { .name = "addw", .ops = &mov_ops, },
335 { .name = "and", .ops = &mov_ops, },
336 { .name = "bts", .ops = &mov_ops, },
337 { .name = "call", .ops = &call_ops, },
338 { .name = "callq", .ops = &call_ops, },
339 { .name = "cmp", .ops = &mov_ops, },
340 { .name = "cmpb", .ops = &mov_ops, },
341 { .name = "cmpl", .ops = &mov_ops, },
342 { .name = "cmpq", .ops = &mov_ops, },
343 { .name = "cmpw", .ops = &mov_ops, },
344 { .name = "cmpxch", .ops = &mov_ops, },
345 { .name = "dec", .ops = &dec_ops, },
346 { .name = "decl", .ops = &dec_ops, },
347 { .name = "imul", .ops = &mov_ops, },
348 { .name = "inc", .ops = &dec_ops, },
349 { .name = "incl", .ops = &dec_ops, },
350 { .name = "ja", .ops = &jump_ops, },
351 { .name = "jae", .ops = &jump_ops, },
352 { .name = "jb", .ops = &jump_ops, },
353 { .name = "jbe", .ops = &jump_ops, },
354 { .name = "jc", .ops = &jump_ops, },
355 { .name = "jcxz", .ops = &jump_ops, },
356 { .name = "je", .ops = &jump_ops, },
357 { .name = "jecxz", .ops = &jump_ops, },
358 { .name = "jg", .ops = &jump_ops, },
359 { .name = "jge", .ops = &jump_ops, },
360 { .name = "jl", .ops = &jump_ops, },
361 { .name = "jle", .ops = &jump_ops, },
362 { .name = "jmp", .ops = &jump_ops, },
363 { .name = "jmpq", .ops = &jump_ops, },
364 { .name = "jna", .ops = &jump_ops, },
365 { .name = "jnae", .ops = &jump_ops, },
366 { .name = "jnb", .ops = &jump_ops, },
367 { .name = "jnbe", .ops = &jump_ops, },
368 { .name = "jnc", .ops = &jump_ops, },
369 { .name = "jne", .ops = &jump_ops, },
370 { .name = "jng", .ops = &jump_ops, },
371 { .name = "jnge", .ops = &jump_ops, },
372 { .name = "jnl", .ops = &jump_ops, },
373 { .name = "jnle", .ops = &jump_ops, },
374 { .name = "jno", .ops = &jump_ops, },
375 { .name = "jnp", .ops = &jump_ops, },
376 { .name = "jns", .ops = &jump_ops, },
377 { .name = "jnz", .ops = &jump_ops, },
378 { .name = "jo", .ops = &jump_ops, },
379 { .name = "jp", .ops = &jump_ops, },
380 { .name = "jpe", .ops = &jump_ops, },
381 { .name = "jpo", .ops = &jump_ops, },
382 { .name = "jrcxz", .ops = &jump_ops, },
383 { .name = "js", .ops = &jump_ops, },
384 { .name = "jz", .ops = &jump_ops, },
385 { .name = "lea", .ops = &mov_ops, },
386 { .name = "lock", .ops = &lock_ops, },
387 { .name = "mov", .ops = &mov_ops, },
388 { .name = "movb", .ops = &mov_ops, },
389 { .name = "movdqa",.ops = &mov_ops, },
390 { .name = "movl", .ops = &mov_ops, },
391 { .name = "movq", .ops = &mov_ops, },
392 { .name = "movslq", .ops = &mov_ops, },
393 { .name = "movzbl", .ops = &mov_ops, },
394 { .name = "movzwl", .ops = &mov_ops, },
395 { .name = "nop", .ops = &nop_ops, },
396 { .name = "nopl", .ops = &nop_ops, },
397 { .name = "nopw", .ops = &nop_ops, },
398 { .name = "or", .ops = &mov_ops, },
399 { .name = "orl", .ops = &mov_ops, },
400 { .name = "test", .ops = &mov_ops, },
401 { .name = "testb", .ops = &mov_ops, },
402 { .name = "testl", .ops = &mov_ops, },
403 { .name = "xadd", .ops = &mov_ops, },
404 { .name = "xbeginl", .ops = &jump_ops, },
405 { .name = "xbeginq", .ops = &jump_ops, },
406};
407
408static int ins__cmp(const void *name, const void *insp)
409{
410 const struct ins *ins = insp;
411
412 return strcmp(name, ins->name);
413}
414
415static struct ins *ins__find(const char *name)
416{
417 const int nmemb = ARRAY_SIZE(instructions);
418
419 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
420}
421
422int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym)
423{ 20{
424 struct annotation *notes = symbol__annotation(sym); 21 struct annotation *notes = symbol__annotation(sym);
425 pthread_mutex_init(&notes->lock, NULL); 22 pthread_mutex_init(&notes->lock, NULL);
426 return 0; 23 return 0;
427} 24}
428 25
429int symbol__alloc_hist(struct symbol *sym) 26int symbol__alloc_hist(struct symbol *sym, int nevents)
430{ 27{
431 struct annotation *notes = symbol__annotation(sym); 28 struct annotation *notes = symbol__annotation(sym);
432 const size_t size = symbol__size(sym); 29 size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
433 size_t sizeof_sym_hist; 30 (sym->end - sym->start) * sizeof(u64));
434
435 /* Check for overflow when calculating sizeof_sym_hist */
436 if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64))
437 return -1;
438
439 sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
440 31
441 /* Check for overflow in zalloc argument */ 32 notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist);
442 if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src))
443 / symbol_conf.nr_events)
444 return -1;
445
446 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
447 if (notes->src == NULL) 33 if (notes->src == NULL)
448 return -1; 34 return -1;
449 notes->src->sizeof_sym_hist = sizeof_sym_hist; 35 notes->src->sizeof_sym_hist = sizeof_sym_hist;
450 notes->src->nr_histograms = symbol_conf.nr_events; 36 notes->src->nr_histograms = nevents;
451 INIT_LIST_HEAD(&notes->src->source); 37 INIT_LIST_HEAD(&notes->src->source);
452 return 0; 38 return 0;
453} 39}
@@ -476,8 +62,8 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
476 62
477 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 63 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
478 64
479 if (addr < sym->start || addr > sym->end) 65 if (addr >= sym->end)
480 return -ERANGE; 66 return 0;
481 67
482 offset = addr - sym->start; 68 offset = addr - sym->start;
483 h = annotation__histogram(notes, evidx); 69 h = annotation__histogram(notes, evidx);
@@ -490,110 +76,31 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
490 return 0; 76 return 0;
491} 77}
492 78
493static void disasm_line__init_ins(struct disasm_line *dl) 79static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
494{ 80{
495 dl->ins = ins__find(dl->name); 81 struct objdump_line *self = malloc(sizeof(*self) + privsize);
496 82
497 if (dl->ins == NULL) 83 if (self != NULL) {
498 return; 84 self->offset = offset;
499 85 self->line = line;
500 if (!dl->ins->ops)
501 return;
502
503 if (dl->ins->ops->parse)
504 dl->ins->ops->parse(&dl->ops);
505}
506
507static int disasm_line__parse(char *line, char **namep, char **rawp)
508{
509 char *name = line, tmp;
510
511 while (isspace(name[0]))
512 ++name;
513
514 if (name[0] == '\0')
515 return -1;
516
517 *rawp = name + 1;
518
519 while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
520 ++*rawp;
521
522 tmp = (*rawp)[0];
523 (*rawp)[0] = '\0';
524 *namep = strdup(name);
525
526 if (*namep == NULL)
527 goto out_free_name;
528
529 (*rawp)[0] = tmp;
530
531 if ((*rawp)[0] != '\0') {
532 (*rawp)++;
533 while (isspace((*rawp)[0]))
534 ++(*rawp);
535 } 86 }
536 87
537 return 0; 88 return self;
538
539out_free_name:
540 free(*namep);
541 *namep = NULL;
542 return -1;
543} 89}
544 90
545static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) 91void objdump_line__free(struct objdump_line *self)
546{ 92{
547 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); 93 free(self->line);
548 94 free(self);
549 if (dl != NULL) {
550 dl->offset = offset;
551 dl->line = strdup(line);
552 if (dl->line == NULL)
553 goto out_delete;
554
555 if (offset != -1) {
556 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
557 goto out_free_line;
558
559 disasm_line__init_ins(dl);
560 }
561 }
562
563 return dl;
564
565out_free_line:
566 free(dl->line);
567out_delete:
568 free(dl);
569 return NULL;
570}
571
572void disasm_line__free(struct disasm_line *dl)
573{
574 free(dl->line);
575 free(dl->name);
576 if (dl->ins && dl->ins->ops->free)
577 dl->ins->ops->free(&dl->ops);
578 else
579 ins__delete(&dl->ops);
580 free(dl);
581} 95}
582 96
583int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) 97static void objdump__add_line(struct list_head *head, struct objdump_line *line)
584{
585 if (raw || !dl->ins)
586 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
587
588 return ins__scnprintf(dl->ins, bf, size, &dl->ops);
589}
590
591static void disasm__add(struct list_head *head, struct disasm_line *line)
592{ 98{
593 list_add_tail(&line->node, head); 99 list_add_tail(&line->node, head);
594} 100}
595 101
596struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) 102struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
103 struct objdump_line *pos)
597{ 104{
598 list_for_each_entry_continue(pos, head, node) 105 list_for_each_entry_continue(pos, head, node)
599 if (pos->offset >= 0) 106 if (pos->offset >= 0)
@@ -602,14 +109,15 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
602 return NULL; 109 return NULL;
603} 110}
604 111
605static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 112static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
606 int evidx, u64 len, int min_pcnt, int printed, 113 int evidx, u64 len, int min_pcnt,
607 int max_lines, struct disasm_line *queue) 114 int printed, int max_lines,
115 struct objdump_line *queue)
608{ 116{
609 static const char *prev_line; 117 static const char *prev_line;
610 static const char *prev_color; 118 static const char *prev_color;
611 119
612 if (dl->offset != -1) { 120 if (oline->offset != -1) {
613 const char *path = NULL; 121 const char *path = NULL;
614 unsigned int hits = 0; 122 unsigned int hits = 0;
615 double percent = 0.0; 123 double percent = 0.0;
@@ -617,11 +125,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
617 struct annotation *notes = symbol__annotation(sym); 125 struct annotation *notes = symbol__annotation(sym);
618 struct source_line *src_line = notes->src->lines; 126 struct source_line *src_line = notes->src->lines;
619 struct sym_hist *h = annotation__histogram(notes, evidx); 127 struct sym_hist *h = annotation__histogram(notes, evidx);
620 s64 offset = dl->offset; 128 s64 offset = oline->offset;
621 const u64 addr = start + offset; 129 struct objdump_line *next;
622 struct disasm_line *next;
623 130
624 next = disasm__get_next_ip_line(&notes->src->source, dl); 131 next = objdump__get_next_ip_line(&notes->src->source, oline);
625 132
626 while (offset < (s64)len && 133 while (offset < (s64)len &&
627 (next == NULL || offset < next->offset)) { 134 (next == NULL || offset < next->offset)) {
@@ -646,9 +153,9 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
646 153
647 if (queue != NULL) { 154 if (queue != NULL) {
648 list_for_each_entry_from(queue, &notes->src->source, node) { 155 list_for_each_entry_from(queue, &notes->src->source, node) {
649 if (queue == dl) 156 if (queue == oline)
650 break; 157 break;
651 disasm_line__print(queue, sym, start, evidx, len, 158 objdump_line__print(queue, sym, evidx, len,
652 0, 0, 1, NULL); 159 0, 0, 1, NULL);
653 } 160 }
654 } 161 }
@@ -671,18 +178,17 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
671 178
672 color_fprintf(stdout, color, " %7.2f", percent); 179 color_fprintf(stdout, color, " %7.2f", percent);
673 printf(" : "); 180 printf(" : ");
674 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 181 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
675 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
676 } else if (max_lines && printed >= max_lines) 182 } else if (max_lines && printed >= max_lines)
677 return 1; 183 return 1;
678 else { 184 else {
679 if (queue) 185 if (queue)
680 return -1; 186 return -1;
681 187
682 if (!*dl->line) 188 if (!*oline->line)
683 printf(" :\n"); 189 printf(" :\n");
684 else 190 else
685 printf(" : %s\n", dl->line); 191 printf(" : %s\n", oline->line);
686 } 192 }
687 193
688 return 0; 194 return 0;
@@ -692,8 +198,8 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
692 FILE *file, size_t privsize) 198 FILE *file, size_t privsize)
693{ 199{
694 struct annotation *notes = symbol__annotation(sym); 200 struct annotation *notes = symbol__annotation(sym);
695 struct disasm_line *dl; 201 struct objdump_line *objdump_line;
696 char *line = NULL, *parsed_line, *tmp, *tmp2, *c; 202 char *line = NULL, *tmp, *tmp2, *c;
697 size_t line_len; 203 size_t line_len;
698 s64 line_ip, offset = -1; 204 s64 line_ip, offset = -1;
699 205
@@ -711,7 +217,6 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
711 *c = 0; 217 *c = 0;
712 218
713 line_ip = -1; 219 line_ip = -1;
714 parsed_line = line;
715 220
716 /* 221 /*
717 * Strip leading spaces: 222 * Strip leading spaces:
@@ -739,17 +244,14 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
739 offset = line_ip - start; 244 offset = line_ip - start;
740 if (offset < 0 || (u64)line_ip > end) 245 if (offset < 0 || (u64)line_ip > end)
741 offset = -1; 246 offset = -1;
742 else
743 parsed_line = tmp2 + 1;
744 } 247 }
745 248
746 dl = disasm_line__new(offset, parsed_line, privsize); 249 objdump_line = objdump_line__new(offset, line, privsize);
747 free(line); 250 if (objdump_line == NULL) {
748 251 free(line);
749 if (dl == NULL)
750 return -1; 252 return -1;
751 253 }
752 disasm__add(&notes->src->source, dl); 254 objdump__add_line(&notes->src->source, objdump_line);
753 255
754 return 0; 256 return 0;
755} 257}
@@ -792,7 +294,7 @@ fallback:
792 free_filename = false; 294 free_filename = false;
793 } 295 }
794 296
795 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { 297 if (dso->symtab_type == SYMTAB__KALLSYMS) {
796 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; 298 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
797 char *build_id_msg = NULL; 299 char *build_id_msg = NULL;
798 300
@@ -806,12 +308,9 @@ fallback:
806 } 308 }
807 err = -ENOENT; 309 err = -ENOENT;
808 dso->annotate_warned = 1; 310 dso->annotate_warned = 1;
809 pr_err("Can't annotate %s:\n\n" 311 pr_err("Can't annotate %s: No vmlinux file%s was found in the "
810 "No vmlinux file%s\nwas found in the path.\n\n" 312 "path.\nPlease use 'perf buildid-cache -av vmlinux' or "
811 "Please use:\n\n" 313 "--vmlinux vmlinux.\n",
812 " perf buildid-cache -av vmlinux\n\n"
813 "or:\n\n"
814 " --vmlinux vmlinux\n",
815 sym->name, build_id_msg ?: ""); 314 sym->name, build_id_msg ?: "");
816 goto out_free_filename; 315 goto out_free_filename;
817 } 316 }
@@ -824,16 +323,10 @@ fallback:
824 dso, dso->long_name, sym, sym->name); 323 dso, dso->long_name, sym, sym->name);
825 324
826 snprintf(command, sizeof(command), 325 snprintf(command, sizeof(command),
827 "%s %s%s --start-address=0x%016" PRIx64 326 "objdump --start-address=0x%016" PRIx64
828 " --stop-address=0x%016" PRIx64 327 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
829 " -d %s %s -C %s|grep -v %s|expand",
830 objdump_path ? objdump_path : "objdump",
831 disassembler_style ? "-M " : "",
832 disassembler_style ? disassembler_style : "",
833 map__rip_2objdump(map, sym->start), 328 map__rip_2objdump(map, sym->start),
834 map__rip_2objdump(map, sym->end+1), 329 map__rip_2objdump(map, sym->end),
835 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
836 symbol_conf.annotate_src ? "-S" : "",
837 symfs_filename, filename); 330 symfs_filename, filename);
838 331
839 pr_debug("Executing: %s\n", command); 332 pr_debug("Executing: %s\n", command);
@@ -858,41 +351,12 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
858 struct source_line *iter; 351 struct source_line *iter;
859 struct rb_node **p = &root->rb_node; 352 struct rb_node **p = &root->rb_node;
860 struct rb_node *parent = NULL; 353 struct rb_node *parent = NULL;
861 int ret;
862
863 while (*p != NULL) {
864 parent = *p;
865 iter = rb_entry(parent, struct source_line, node);
866
867 ret = strcmp(iter->path, src_line->path);
868 if (ret == 0) {
869 iter->percent_sum += src_line->percent;
870 return;
871 }
872
873 if (ret < 0)
874 p = &(*p)->rb_left;
875 else
876 p = &(*p)->rb_right;
877 }
878
879 src_line->percent_sum = src_line->percent;
880
881 rb_link_node(&src_line->node, parent, p);
882 rb_insert_color(&src_line->node, root);
883}
884
885static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
886{
887 struct source_line *iter;
888 struct rb_node **p = &root->rb_node;
889 struct rb_node *parent = NULL;
890 354
891 while (*p != NULL) { 355 while (*p != NULL) {
892 parent = *p; 356 parent = *p;
893 iter = rb_entry(parent, struct source_line, node); 357 iter = rb_entry(parent, struct source_line, node);
894 358
895 if (src_line->percent_sum > iter->percent_sum) 359 if (src_line->percent > iter->percent)
896 p = &(*p)->rb_left; 360 p = &(*p)->rb_left;
897 else 361 else
898 p = &(*p)->rb_right; 362 p = &(*p)->rb_right;
@@ -902,24 +366,6 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l
902 rb_insert_color(&src_line->node, root); 366 rb_insert_color(&src_line->node, root);
903} 367}
904 368
905static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
906{
907 struct source_line *src_line;
908 struct rb_node *node;
909
910 node = rb_first(src_root);
911 while (node) {
912 struct rb_node *next;
913
914 src_line = rb_entry(node, struct source_line, node);
915 next = rb_next(node);
916 rb_erase(node, src_root);
917
918 __resort_source_line(dest_root, src_line);
919 node = next;
920 }
921}
922
923static void symbol__free_source_line(struct symbol *sym, int len) 369static void symbol__free_source_line(struct symbol *sym, int len)
924{ 370{
925 struct annotation *notes = symbol__annotation(sym); 371 struct annotation *notes = symbol__annotation(sym);
@@ -944,7 +390,6 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
944 struct source_line *src_line; 390 struct source_line *src_line;
945 struct annotation *notes = symbol__annotation(sym); 391 struct annotation *notes = symbol__annotation(sym);
946 struct sym_hist *h = annotation__histogram(notes, evidx); 392 struct sym_hist *h = annotation__histogram(notes, evidx);
947 struct rb_root tmp_root = RB_ROOT;
948 393
949 if (!h->sum) 394 if (!h->sum)
950 return 0; 395 return 0;
@@ -953,7 +398,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
953 if (!notes->src->lines) 398 if (!notes->src->lines)
954 return -1; 399 return -1;
955 400
956 start = map__rip_2objdump(map, sym->start); 401 start = map->unmap_ip(map, sym->start);
957 402
958 for (i = 0; i < len; i++) { 403 for (i = 0; i < len; i++) {
959 char *path = NULL; 404 char *path = NULL;
@@ -979,13 +424,12 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
979 goto next; 424 goto next;
980 425
981 strcpy(src_line[i].path, path); 426 strcpy(src_line[i].path, path);
982 insert_source_line(&tmp_root, &src_line[i]); 427 insert_source_line(root, &src_line[i]);
983 428
984 next: 429 next:
985 pclose(fp); 430 pclose(fp);
986 } 431 }
987 432
988 resort_source_line(root, &tmp_root);
989 return 0; 433 return 0;
990} 434}
991 435
@@ -1009,7 +453,7 @@ static void print_summary(struct rb_root *root, const char *filename)
1009 char *path; 453 char *path;
1010 454
1011 src_line = rb_entry(node, struct source_line, node); 455 src_line = rb_entry(node, struct source_line, node);
1012 percent = src_line->percent_sum; 456 percent = src_line->percent;
1013 color = get_percent_color(percent); 457 color = get_percent_color(percent);
1014 path = src_line->path; 458 path = src_line->path;
1015 459
@@ -1022,7 +466,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
1022{ 466{
1023 struct annotation *notes = symbol__annotation(sym); 467 struct annotation *notes = symbol__annotation(sym);
1024 struct sym_hist *h = annotation__histogram(notes, evidx); 468 struct sym_hist *h = annotation__histogram(notes, evidx);
1025 u64 len = symbol__size(sym), offset; 469 u64 len = sym->end - sym->start, offset;
1026 470
1027 for (offset = 0; offset < len; ++offset) 471 for (offset = 0; offset < len; ++offset)
1028 if (h->addr[offset] != 0) 472 if (h->addr[offset] != 0)
@@ -1036,25 +480,19 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1036 int context) 480 int context)
1037{ 481{
1038 struct dso *dso = map->dso; 482 struct dso *dso = map->dso;
1039 char *filename; 483 const char *filename = dso->long_name, *d_filename;
1040 const char *d_filename;
1041 struct annotation *notes = symbol__annotation(sym); 484 struct annotation *notes = symbol__annotation(sym);
1042 struct disasm_line *pos, *queue = NULL; 485 struct objdump_line *pos, *queue = NULL;
1043 u64 start = map__rip_2objdump(map, sym->start);
1044 int printed = 2, queue_len = 0; 486 int printed = 2, queue_len = 0;
1045 int more = 0; 487 int more = 0;
1046 u64 len; 488 u64 len;
1047 489
1048 filename = strdup(dso->long_name);
1049 if (!filename)
1050 return -ENOMEM;
1051
1052 if (full_paths) 490 if (full_paths)
1053 d_filename = filename; 491 d_filename = filename;
1054 else 492 else
1055 d_filename = basename(filename); 493 d_filename = basename(filename);
1056 494
1057 len = symbol__size(sym); 495 len = sym->end - sym->start;
1058 496
1059 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 497 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
1060 printf("------------------------------------------------\n"); 498 printf("------------------------------------------------\n");
@@ -1068,9 +506,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1068 queue_len = 0; 506 queue_len = 0;
1069 } 507 }
1070 508
1071 switch (disasm_line__print(pos, sym, start, evidx, len, 509 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
1072 min_pcnt, printed, max_lines, 510 printed, max_lines, queue)) {
1073 queue)) {
1074 case 0: 511 case 0:
1075 ++printed; 512 ++printed;
1076 if (context) { 513 if (context) {
@@ -1099,8 +536,6 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1099 } 536 }
1100 } 537 }
1101 538
1102 free(filename);
1103
1104 return more; 539 return more;
1105} 540}
1106 541
@@ -1116,51 +551,27 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
1116{ 551{
1117 struct annotation *notes = symbol__annotation(sym); 552 struct annotation *notes = symbol__annotation(sym);
1118 struct sym_hist *h = annotation__histogram(notes, evidx); 553 struct sym_hist *h = annotation__histogram(notes, evidx);
1119 int len = symbol__size(sym), offset; 554 struct objdump_line *pos;
555 int len = sym->end - sym->start;
1120 556
1121 h->sum = 0; 557 h->sum = 0;
1122 for (offset = 0; offset < len; ++offset) { 558
1123 h->addr[offset] = h->addr[offset] * 7 / 8; 559 list_for_each_entry(pos, &notes->src->source, node) {
1124 h->sum += h->addr[offset]; 560 if (pos->offset != -1 && pos->offset < len) {
561 h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8;
562 h->sum += h->addr[pos->offset];
563 }
1125 } 564 }
1126} 565}
1127 566
1128void disasm__purge(struct list_head *head) 567void objdump_line_list__purge(struct list_head *head)
1129{ 568{
1130 struct disasm_line *pos, *n; 569 struct objdump_line *pos, *n;
1131 570
1132 list_for_each_entry_safe(pos, n, head, node) { 571 list_for_each_entry_safe(pos, n, head, node) {
1133 list_del(&pos->node); 572 list_del(&pos->node);
1134 disasm_line__free(pos); 573 objdump_line__free(pos);
1135 }
1136}
1137
1138static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
1139{
1140 size_t printed;
1141
1142 if (dl->offset == -1)
1143 return fprintf(fp, "%s\n", dl->line);
1144
1145 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
1146
1147 if (dl->ops.raw[0] != '\0') {
1148 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
1149 dl->ops.raw);
1150 } 574 }
1151
1152 return printed + fprintf(fp, "\n");
1153}
1154
1155size_t disasm__fprintf(struct list_head *head, FILE *fp)
1156{
1157 struct disasm_line *pos;
1158 size_t printed = 0;
1159
1160 list_for_each_entry(pos, head, node)
1161 printed += disasm_line__fprintf(pos, fp);
1162
1163 return printed;
1164} 575}
1165 576
1166int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 577int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
@@ -1175,7 +586,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
1175 if (symbol__annotate(sym, map, 0) < 0) 586 if (symbol__annotate(sym, map, 0) < 0)
1176 return -1; 587 return -1;
1177 588
1178 len = symbol__size(sym); 589 len = sym->end - sym->start;
1179 590
1180 if (print_lines) { 591 if (print_lines) {
1181 symbol__get_source_line(sym, map, evidx, &source_line, 592 symbol__get_source_line(sym, map, evidx, &source_line,
@@ -1188,7 +599,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
1188 if (print_lines) 599 if (print_lines)
1189 symbol__free_source_line(sym, len); 600 symbol__free_source_line(sym, len);
1190 601
1191 disasm__purge(&symbol__annotation(sym)->src->source); 602 objdump_line_list__purge(&symbol__annotation(sym)->src->source);
1192 603
1193 return 0; 604 return 0;
1194} 605}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 8eec94358a4..c2c28689680 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -2,71 +2,20 @@
2#define __PERF_ANNOTATE_H 2#define __PERF_ANNOTATE_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h>
6#include "types.h" 5#include "types.h"
7#include "symbol.h" 6#include "symbol.h"
8#include "hist.h"
9#include <linux/list.h> 7#include <linux/list.h>
10#include <linux/rbtree.h> 8#include <linux/rbtree.h>
11#include <pthread.h>
12 9
13struct ins; 10struct objdump_line {
14 11 struct list_head node;
15struct ins_operands { 12 s64 offset;
16 char *raw; 13 char *line;
17 struct {
18 char *raw;
19 char *name;
20 u64 addr;
21 u64 offset;
22 } target;
23 union {
24 struct {
25 char *raw;
26 char *name;
27 u64 addr;
28 } source;
29 struct {
30 struct ins *ins;
31 struct ins_operands *ops;
32 } locked;
33 };
34};
35
36struct ins_ops {
37 void (*free)(struct ins_operands *ops);
38 int (*parse)(struct ins_operands *ops);
39 int (*scnprintf)(struct ins *ins, char *bf, size_t size,
40 struct ins_operands *ops);
41};
42
43struct ins {
44 const char *name;
45 struct ins_ops *ops;
46};
47
48bool ins__is_jump(const struct ins *ins);
49bool ins__is_call(const struct ins *ins);
50int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
51
52struct disasm_line {
53 struct list_head node;
54 s64 offset;
55 char *line;
56 char *name;
57 struct ins *ins;
58 struct ins_operands ops;
59}; 14};
60 15
61static inline bool disasm_line__has_offset(const struct disasm_line *dl) 16void objdump_line__free(struct objdump_line *self);
62{ 17struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
63 return dl->ops.target.offset != UINT64_MAX; 18 struct objdump_line *pos);
64}
65
66void disasm_line__free(struct disasm_line *dl);
67struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
68int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
69size_t disasm__fprintf(struct list_head *head, FILE *fp);
70 19
71struct sym_hist { 20struct sym_hist {
72 u64 sum; 21 u64 sum;
@@ -76,7 +25,6 @@ struct sym_hist {
76struct source_line { 25struct source_line {
77 struct rb_node node; 26 struct rb_node node;
78 double percent; 27 double percent;
79 double percent_sum;
80 char *path; 28 char *path;
81}; 29};
82 30
@@ -84,7 +32,7 @@ struct source_line {
84 * 32 *
85 * @histogram: Array of addr hit histograms per event being monitored 33 * @histogram: Array of addr hit histograms per event being monitored
86 * @lines: If 'print_lines' is specified, per source code line percentages 34 * @lines: If 'print_lines' is specified, per source code line percentages
87 * @source: source parsed from a disassembler like objdump -dS 35 * @source: source parsed from objdump -dS
88 * 36 *
89 * lines is allocated, percentages calculated and all sorted by percentage 37 * lines is allocated, percentages calculated and all sorted by percentage
90 * when the annotation is about to be presented, so the percentages are for 38 * when the annotation is about to be presented, so the percentages are for
@@ -124,36 +72,32 @@ static inline struct annotation *symbol__annotation(struct symbol *sym)
124 72
125int symbol__inc_addr_samples(struct symbol *sym, struct map *map, 73int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
126 int evidx, u64 addr); 74 int evidx, u64 addr);
127int symbol__alloc_hist(struct symbol *sym); 75int symbol__alloc_hist(struct symbol *sym, int nevents);
128void symbol__annotate_zero_histograms(struct symbol *sym); 76void symbol__annotate_zero_histograms(struct symbol *sym);
129 77
130int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 78int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
131int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 79int symbol__annotate_init(struct map *map __used, struct symbol *sym);
132int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 80int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
133 bool full_paths, int min_pcnt, int max_lines, 81 bool full_paths, int min_pcnt, int max_lines,
134 int context); 82 int context);
135void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 83void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
136void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 84void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
137void disasm__purge(struct list_head *head); 85void objdump_line_list__purge(struct list_head *head);
138 86
139int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 87int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
140 bool print_lines, bool full_paths, int min_pcnt, 88 bool print_lines, bool full_paths, int min_pcnt,
141 int max_lines); 89 int max_lines);
142 90
143#ifdef NEWT_SUPPORT 91#ifdef NO_NEWT_SUPPORT
144int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 92static inline int symbol__tui_annotate(struct symbol *sym __used,
145 struct hist_browser_timer *hbt); 93 struct map *map __used,
146#else 94 int evidx __used, int refresh __used)
147static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
148 struct map *map __maybe_unused,
149 int evidx __maybe_unused,
150 struct hist_browser_timer *hbt
151 __maybe_unused)
152{ 95{
153 return 0; 96 return 0;
154} 97}
98#else
99int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
100 int refresh);
155#endif 101#endif
156 102
157extern const char *disassembler_style;
158
159#endif /* __PERF_ANNOTATE_H */ 103#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
index 0a1adc1111f..5e230acae1e 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/perf/util/bitmap.c
@@ -19,13 +19,3 @@ int __bitmap_weight(const unsigned long *bitmap, int bits)
19 19
20 return w; 20 return w;
21} 21}
22
23void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
24 const unsigned long *bitmap2, int bits)
25{
26 int k;
27 int nr = BITS_TO_LONGS(bits);
28
29 for (k = 0; k < nr; k++)
30 dst[k] = bitmap1[k] | bitmap2[k];
31}
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 5295625c0c0..a91cd99f26e 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -13,18 +13,15 @@
13#include "symbol.h" 13#include "symbol.h"
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include "debug.h" 15#include "debug.h"
16#include "session.h"
17#include "tool.h"
18 16
19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 17static int build_id__mark_dso_hit(union perf_event *event,
20 union perf_event *event, 18 struct perf_sample *sample __used,
21 struct perf_sample *sample __maybe_unused, 19 struct perf_evsel *evsel __used,
22 struct perf_evsel *evsel __maybe_unused, 20 struct perf_session *session)
23 struct machine *machine)
24{ 21{
25 struct addr_location al; 22 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 23 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
27 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 24 struct thread *thread = perf_session__findnew(session, event->ip.pid);
28 25
29 if (thread == NULL) { 26 if (thread == NULL) {
30 pr_err("problem processing %d event, skipping it.\n", 27 pr_err("problem processing %d event, skipping it.\n",
@@ -32,8 +29,8 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
32 return -1; 29 return -1;
33 } 30 }
34 31
35 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 32 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
36 event->ip.ip, &al); 33 event->ip.pid, event->ip.ip, &al);
37 34
38 if (al.map != NULL) 35 if (al.map != NULL)
39 al.map->dso->hit = 1; 36 al.map->dso->hit = 1;
@@ -41,50 +38,31 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
41 return 0; 38 return 0;
42} 39}
43 40
44static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused, 41static int perf_event__exit_del_thread(union perf_event *event,
45 union perf_event *event, 42 struct perf_sample *sample __used,
46 struct perf_sample *sample 43 struct perf_session *session)
47 __maybe_unused,
48 struct machine *machine)
49{ 44{
50 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 45 struct thread *thread = perf_session__findnew(session, event->fork.tid);
51 46
52 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 47 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
53 event->fork.ppid, event->fork.ptid); 48 event->fork.ppid, event->fork.ptid);
54 49
55 if (thread) { 50 if (thread) {
56 rb_erase(&thread->rb_node, &machine->threads); 51 rb_erase(&thread->rb_node, &session->threads);
57 machine->last_match = NULL; 52 session->last_match = NULL;
58 thread__delete(thread); 53 thread__delete(thread);
59 } 54 }
60 55
61 return 0; 56 return 0;
62} 57}
63 58
64struct perf_tool build_id__mark_dso_hit_ops = { 59struct perf_event_ops build_id__mark_dso_hit_ops = {
65 .sample = build_id__mark_dso_hit, 60 .sample = build_id__mark_dso_hit,
66 .mmap = perf_event__process_mmap, 61 .mmap = perf_event__process_mmap,
67 .fork = perf_event__process_fork, 62 .fork = perf_event__process_task,
68 .exit = perf_event__exit_del_thread, 63 .exit = perf_event__exit_del_thread,
69 .attr = perf_event__process_attr,
70 .build_id = perf_event__process_build_id,
71}; 64};
72 65
73int build_id__sprintf(const u8 *build_id, int len, char *bf)
74{
75 char *bid = bf;
76 const u8 *raw = build_id;
77 int i;
78
79 for (i = 0; i < len; ++i) {
80 sprintf(bid, "%02x", *raw);
81 ++raw;
82 bid += 2;
83 }
84
85 return raw - build_id;
86}
87
88char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 66char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
89{ 67{
90 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 68 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index a811f5c62e1..5dafb00eaa0 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -1,19 +1,10 @@
1#ifndef PERF_BUILD_ID_H_ 1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1 2#define PERF_BUILD_ID_H_ 1
3 3
4#define BUILD_ID_SIZE 20 4#include "session.h"
5 5
6#include "tool.h" 6extern struct perf_event_ops build_id__mark_dso_hit_ops;
7#include "types.h"
8 7
9extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso;
11
12int build_id__sprintf(const u8 *build_id, int len, char *bf);
13char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 8char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
14 9
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel,
17 struct machine *machine);
18
19#endif 10#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 26e36723987..fc5e5a09d5b 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -5,7 +5,6 @@
5#include "util.h" 5#include "util.h"
6#include "strbuf.h" 6#include "strbuf.h"
7#include "../perf.h" 7#include "../perf.h"
8#include "../ui/ui.h"
9 8
10#define CMD_EXEC_PATH "--exec-path" 9#define CMD_EXEC_PATH "--exec-path"
11#define CMD_PERF_DIR "--perf-dir=" 10#define CMD_PERF_DIR "--perf-dir="
@@ -32,6 +31,20 @@ extern const char *pager_program;
32extern int pager_in_use(void); 31extern int pager_in_use(void);
33extern int pager_use_color; 32extern int pager_use_color;
34 33
34extern int use_browser;
35
36#ifdef NO_NEWT_SUPPORT
37static inline void setup_browser(bool fallback_to_pager)
38{
39 if (fallback_to_pager)
40 setup_pager();
41}
42static inline void exit_browser(bool wait_for_ok __used) {}
43#else
44void setup_browser(bool fallback_to_pager);
45void exit_browser(bool wait_for_ok);
46#endif
47
35char *alias_lookup(const char *alias); 48char *alias_lookup(const char *alias);
36int split_cmdline(char *cmdline, const char ***argv); 49int split_cmdline(char *cmdline, const char ***argv);
37 50
@@ -70,7 +83,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
70extern char *perf_pathdup(const char *fmt, ...) 83extern char *perf_pathdup(const char *fmt, ...)
71 __attribute__((format (printf, 1, 2))); 84 __attribute__((format (printf, 1, 2)));
72 85
73#ifndef HAVE_STRLCPY 86#ifdef NO_STRLCPY
74extern size_t strlcpy(char *dest, const char *src, size_t size); 87extern size_t strlcpy(char *dest, const char *src, size_t size);
75#endif 88#endif
76 89
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index d3b3f5d8213..9f7106a8d9a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -18,8 +18,6 @@
18#include "util.h" 18#include "util.h"
19#include "callchain.h" 19#include "callchain.h"
20 20
21__thread struct callchain_cursor callchain_cursor;
22
23bool ip_callchain__valid(struct ip_callchain *chain, 21bool ip_callchain__valid(struct ip_callchain *chain,
24 const union perf_event *event) 22 const union perf_event *event)
25{ 23{
@@ -93,7 +91,7 @@ __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
93 */ 91 */
94static void 92static void
95sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root, 93sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
96 u64 min_hit, struct callchain_param *param __maybe_unused) 94 u64 min_hit, struct callchain_param *param __used)
97{ 95{
98 __sort_chain_flat(rb_root, &root->node, min_hit); 96 __sort_chain_flat(rb_root, &root->node, min_hit);
99} 97}
@@ -115,7 +113,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
115 113
116static void 114static void
117sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root, 115sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
118 u64 min_hit, struct callchain_param *param __maybe_unused) 116 u64 min_hit, struct callchain_param *param __used)
119{ 117{
120 __sort_chain_graph_abs(&chain_root->node, min_hit); 118 __sort_chain_graph_abs(&chain_root->node, min_hit);
121 rb_root->rb_node = chain_root->node.rb_root.rb_node; 119 rb_root->rb_node = chain_root->node.rb_root.rb_node;
@@ -140,7 +138,7 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
140 138
141static void 139static void
142sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root, 140sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
143 u64 min_hit __maybe_unused, struct callchain_param *param) 141 u64 min_hit __used, struct callchain_param *param)
144{ 142{
145 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0); 143 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
146 rb_root->rb_node = chain_root->node.rb_root.rb_node; 144 rb_root->rb_node = chain_root->node.rb_root.rb_node;
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index eb340571e7d..9b4ff16cac9 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,7 +58,7 @@ struct callchain_list {
58/* 58/*
59 * A callchain cursor is a single linked list that 59 * A callchain cursor is a single linked list that
60 * let one feed a callchain progressively. 60 * let one feed a callchain progressively.
61 * It keeps persistent allocated entries to minimize 61 * It keeps persitent allocated entries to minimize
62 * allocations. 62 * allocations.
63 */ 63 */
64struct callchain_cursor_node { 64struct callchain_cursor_node {
@@ -76,8 +76,6 @@ struct callchain_cursor {
76 struct callchain_cursor_node *curr; 76 struct callchain_cursor_node *curr;
77}; 77};
78 78
79extern __thread struct callchain_cursor callchain_cursor;
80
81static inline void callchain_init(struct callchain_root *root) 79static inline void callchain_init(struct callchain_root *root)
82{ 80{
83 INIT_LIST_HEAD(&root->node.siblings); 81 INIT_LIST_HEAD(&root->node.siblings);
@@ -103,9 +101,6 @@ int callchain_append(struct callchain_root *root,
103int callchain_merge(struct callchain_cursor *cursor, 101int callchain_merge(struct callchain_cursor *cursor,
104 struct callchain_root *dst, struct callchain_root *src); 102 struct callchain_root *dst, struct callchain_root *src);
105 103
106struct ip_callchain;
107union perf_event;
108
109bool ip_callchain__valid(struct ip_callchain *chain, 104bool ip_callchain__valid(struct ip_callchain *chain,
110 const union perf_event *event); 105 const union perf_event *event);
111/* 106/*
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 96bbda1ddb8..96bee5c4600 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -3,6 +3,7 @@
3#include "parse-options.h" 3#include "parse-options.h"
4#include "evsel.h" 4#include "evsel.h"
5#include "cgroup.h" 5#include "cgroup.h"
6#include "debugfs.h" /* MAX_PATH, STR() */
6#include "evlist.h" 7#include "evlist.h"
7 8
8int nr_cgroups; 9int nr_cgroups;
@@ -11,7 +12,7 @@ static int
11cgroupfs_find_mountpoint(char *buf, size_t maxlen) 12cgroupfs_find_mountpoint(char *buf, size_t maxlen)
12{ 13{
13 FILE *fp; 14 FILE *fp;
14 char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1]; 15 char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1];
15 char *token, *saved_ptr = NULL; 16 char *token, *saved_ptr = NULL;
16 int found = 0; 17 int found = 0;
17 18
@@ -24,8 +25,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
24 * and inspect every cgroupfs mount point to find one that has 25 * and inspect every cgroupfs mount point to find one that has
25 * perf_event subsystem 26 * perf_event subsystem
26 */ 27 */
27 while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %" 28 while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %"
28 STR(PATH_MAX)"s %*d %*d\n", 29 STR(MAX_PATH)"s %*d %*d\n",
29 mountpoint, type, tokens) == 3) { 30 mountpoint, type, tokens) == 3) {
30 31
31 if (!strcmp(type, "cgroup")) { 32 if (!strcmp(type, "cgroup")) {
@@ -56,15 +57,15 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
56 57
57static int open_cgroup(char *name) 58static int open_cgroup(char *name)
58{ 59{
59 char path[PATH_MAX + 1]; 60 char path[MAX_PATH+1];
60 char mnt[PATH_MAX + 1]; 61 char mnt[MAX_PATH+1];
61 int fd; 62 int fd;
62 63
63 64
64 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1)) 65 if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1))
65 return -1; 66 return -1;
66 67
67 snprintf(path, PATH_MAX, "%s/%s", mnt, name); 68 snprintf(path, MAX_PATH, "%s/%s", mnt, name);
68 69
69 fd = open(path, O_RDONLY); 70 fd = open(path, O_RDONLY);
70 if (fd == -1) 71 if (fd == -1)
@@ -138,8 +139,8 @@ void close_cgroup(struct cgroup_sel *cgrp)
138 } 139 }
139} 140}
140 141
141int parse_cgroups(const struct option *opt __maybe_unused, const char *str, 142int parse_cgroups(const struct option *opt __used, const char *str,
142 int unset __maybe_unused) 143 int unset __used)
143{ 144{
144 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 145 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
145 const char *p, *e, *eos = str + strlen(str); 146 const char *p, *e, *eos = str + strlen(str);
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 11e46da17bb..e191eb9a667 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -1,4 +1,3 @@
1#include <linux/kernel.h>
2#include "cache.h" 1#include "cache.h"
3#include "color.h" 2#include "color.h"
4 3
@@ -183,12 +182,12 @@ static int __color_vsnprintf(char *bf, size_t size, const char *color,
183 } 182 }
184 183
185 if (perf_use_color_default && *color) 184 if (perf_use_color_default && *color)
186 r += scnprintf(bf, size, "%s", color); 185 r += snprintf(bf, size, "%s", color);
187 r += vscnprintf(bf + r, size - r, fmt, args); 186 r += vsnprintf(bf + r, size - r, fmt, args);
188 if (perf_use_color_default && *color) 187 if (perf_use_color_default && *color)
189 r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET); 188 r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
190 if (trail) 189 if (trail)
191 r += scnprintf(bf + r, size - r, "%s", trail); 190 r += snprintf(bf + r, size - r, "%s", trail);
192 return r; 191 return r;
193} 192}
194 193
@@ -201,7 +200,7 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
201 * Auto-detect: 200 * Auto-detect:
202 */ 201 */
203 if (perf_use_color_default < 0) { 202 if (perf_use_color_default < 0) {
204 if (isatty(fileno(fp)) || pager_in_use()) 203 if (isatty(1) || pager_in_use())
205 perf_use_color_default = 1; 204 perf_use_color_default = 1;
206 else 205 else
207 perf_use_color_default = 0; 206 perf_use_color_default = 0;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3e0fdd369cc..fe02903f7d0 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -1,8 +1,5 @@
1/* 1/*
2 * config.c 2 * GIT - The information manager from hell
3 *
4 * Helper functions for parsing config items.
5 * Originally copied from GIT source.
6 * 3 *
7 * Copyright (C) Linus Torvalds, 2005 4 * Copyright (C) Linus Torvalds, 2005
8 * Copyright (C) Johannes Schindelin, 2005 5 * Copyright (C) Johannes Schindelin, 2005
@@ -120,7 +117,7 @@ static char *parse_value(void)
120 117
121static inline int iskeychar(int c) 118static inline int iskeychar(int c)
122{ 119{
123 return isalnum(c) || c == '-' || c == '_'; 120 return isalnum(c) || c == '-';
124} 121}
125 122
126static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 123static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
@@ -342,20 +339,18 @@ const char *perf_config_dirname(const char *name, const char *value)
342 return value; 339 return value;
343} 340}
344 341
345static int perf_default_core_config(const char *var __maybe_unused, 342static int perf_default_core_config(const char *var __used, const char *value __used)
346 const char *value __maybe_unused)
347{ 343{
348 /* Add other config variables here. */ 344 /* Add other config variables here and to Documentation/config.txt. */
349 return 0; 345 return 0;
350} 346}
351 347
352int perf_default_config(const char *var, const char *value, 348int perf_default_config(const char *var, const char *value, void *dummy __used)
353 void *dummy __maybe_unused)
354{ 349{
355 if (!prefixcmp(var, "core.")) 350 if (!prefixcmp(var, "core."))
356 return perf_default_core_config(var, value); 351 return perf_default_core_config(var, value);
357 352
358 /* Add other config variables here. */ 353 /* Add other config variables here and to Documentation/config.txt. */
359 return 0; 354 return 0;
360} 355}
361 356
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 2b32ffa9ebd..6893eec693a 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -38,19 +38,24 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
38 return cpus; 38 return cpus;
39} 39}
40 40
41struct cpu_map *cpu_map__read(FILE *file) 41static struct cpu_map *cpu_map__read_all_cpu_map(void)
42{ 42{
43 struct cpu_map *cpus = NULL; 43 struct cpu_map *cpus = NULL;
44 FILE *onlnf;
44 int nr_cpus = 0; 45 int nr_cpus = 0;
45 int *tmp_cpus = NULL, *tmp; 46 int *tmp_cpus = NULL, *tmp;
46 int max_entries = 0; 47 int max_entries = 0;
47 int n, cpu, prev; 48 int n, cpu, prev;
48 char sep; 49 char sep;
49 50
51 onlnf = fopen("/sys/devices/system/cpu/online", "r");
52 if (!onlnf)
53 return cpu_map__default_new();
54
50 sep = 0; 55 sep = 0;
51 prev = -1; 56 prev = -1;
52 for (;;) { 57 for (;;) {
53 n = fscanf(file, "%u%c", &cpu, &sep); 58 n = fscanf(onlnf, "%u%c", &cpu, &sep);
54 if (n <= 0) 59 if (n <= 0)
55 break; 60 break;
56 if (prev >= 0) { 61 if (prev >= 0) {
@@ -90,19 +95,6 @@ struct cpu_map *cpu_map__read(FILE *file)
90 cpus = cpu_map__default_new(); 95 cpus = cpu_map__default_new();
91out_free_tmp: 96out_free_tmp:
92 free(tmp_cpus); 97 free(tmp_cpus);
93 return cpus;
94}
95
96static struct cpu_map *cpu_map__read_all_cpu_map(void)
97{
98 struct cpu_map *cpus = NULL;
99 FILE *onlnf;
100
101 onlnf = fopen("/sys/devices/system/cpu/online", "r");
102 if (!onlnf)
103 return cpu_map__default_new();
104
105 cpus = cpu_map__read(onlnf);
106 fclose(onlnf); 98 fclose(onlnf);
107 return cpus; 99 return cpus;
108} 100}
@@ -174,17 +166,6 @@ out:
174 return cpus; 166 return cpus;
175} 167}
176 168
177size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
178{
179 int i;
180 size_t printed = fprintf(fp, "%d cpu%s: ",
181 map->nr, map->nr > 1 ? "s" : "");
182 for (i = 0; i < map->nr; ++i)
183 printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
184
185 return printed + fprintf(fp, "\n");
186}
187
188struct cpu_map *cpu_map__dummy_new(void) 169struct cpu_map *cpu_map__dummy_new(void)
189{ 170{
190 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); 171 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 2f68a3b8c28..072c0a37479 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -1,9 +1,6 @@
1#ifndef __PERF_CPUMAP_H 1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H 2#define __PERF_CPUMAP_H
3 3
4#include <stdio.h>
5#include <stdbool.h>
6
7struct cpu_map { 4struct cpu_map {
8 int nr; 5 int nr;
9 int map[]; 6 int map[];
@@ -12,17 +9,5 @@ struct cpu_map {
12struct cpu_map *cpu_map__new(const char *cpu_list); 9struct cpu_map *cpu_map__new(const char *cpu_list);
13struct cpu_map *cpu_map__dummy_new(void); 10struct cpu_map *cpu_map__dummy_new(void);
14void cpu_map__delete(struct cpu_map *map); 11void cpu_map__delete(struct cpu_map *map);
15struct cpu_map *cpu_map__read(FILE *file);
16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
17
18static inline int cpu_map__nr(const struct cpu_map *map)
19{
20 return map ? map->nr : 1;
21}
22
23static inline bool cpu_map__all(const struct cpu_map *map)
24{
25 return map ? map->map[0] == -1 : true;
26}
27 12
28#endif /* __PERF_CPUMAP_H */ 13#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index aada3ac5e89..35073621e5d 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 "cache.h"
7 7
8enum { 8enum {
9 S = GIT_SPACE, 9 S = GIT_SPACE,
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 03f830b4814..155749d7435 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -11,7 +11,6 @@
11#include "event.h" 11#include "event.h"
12#include "debug.h" 12#include "debug.h"
13#include "util.h" 13#include "util.h"
14#include "target.h"
15 14
16int verbose; 15int verbose;
17bool dump_trace = false, quiet = false; 16bool dump_trace = false, quiet = false;
@@ -23,10 +22,8 @@ int eprintf(int level, const char *fmt, ...)
23 22
24 if (verbose >= level) { 23 if (verbose >= level) {
25 va_start(args, fmt); 24 va_start(args, fmt);
26 if (use_browser == 1) 25 if (use_browser > 0)
27 ret = ui_helpline__show_help(fmt, args); 26 ret = ui_helpline__show_help(fmt, args);
28 else if (use_browser == 2)
29 ret = perf_gtk__show_helpline(fmt, args);
30 else 27 else
31 ret = vfprintf(stderr, fmt, args); 28 ret = vfprintf(stderr, fmt, args);
32 va_end(args); 29 va_end(args);
@@ -49,21 +46,20 @@ int dump_printf(const char *fmt, ...)
49 return ret; 46 return ret;
50} 47}
51 48
52#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT) 49#ifdef NO_NEWT_SUPPORT
53int ui__warning(const char *format, ...) 50void ui__warning(const char *format, ...)
54{ 51{
55 va_list args; 52 va_list args;
56 53
57 va_start(args, format); 54 va_start(args, format);
58 vfprintf(stderr, format, args); 55 vfprintf(stderr, format, args);
59 va_end(args); 56 va_end(args);
60 return 0;
61} 57}
62#endif 58#endif
63 59
64int ui__error_paranoid(void) 60void ui__warning_paranoid(void)
65{ 61{
66 return ui__error("Permission error - are you root?\n" 62 ui__warning("Permission error - are you root?\n"
67 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" 63 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
68 " -1 - Not paranoid at all\n" 64 " -1 - Not paranoid at all\n"
69 " 0 - Disallow raw tracepoint access for unpriv\n" 65 " 0 - Disallow raw tracepoint access for unpriv\n"
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 83e8d234af6..fd53db47e3d 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -4,7 +4,6 @@
4 4
5#include <stdbool.h> 5#include <stdbool.h>
6#include "event.h" 6#include "event.h"
7#include "../ui/helpline.h"
8 7
9extern int verbose; 8extern int verbose;
10extern bool quiet, dump_trace; 9extern bool quiet, dump_trace;
@@ -13,38 +12,30 @@ int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(union perf_event *event); 12void trace_event(union perf_event *event);
14 13
15struct ui_progress; 14struct ui_progress;
16struct perf_error_ops;
17 15
18#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT) 16#ifdef NO_NEWT_SUPPORT
19 17static inline int ui_helpline__show_help(const char *format __used, va_list ap __used)
20#include "../ui/progress.h"
21int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
22#include "../ui/util.h"
23
24#else
25
26static inline void ui_progress__update(u64 curr __maybe_unused,
27 u64 total __maybe_unused,
28 const char *title __maybe_unused) {}
29static inline void ui_progress__finish(void) {}
30
31#define ui__error(format, arg...) ui__warning(format, ##arg)
32
33static inline int
34perf_error__register(struct perf_error_ops *eops __maybe_unused)
35{ 18{
36 return 0; 19 return 0;
37} 20}
38 21
39static inline int 22static inline struct ui_progress *ui_progress__new(const char *title __used,
40perf_error__unregister(struct perf_error_ops *eops __maybe_unused) 23 u64 total __used)
41{ 24{
42 return 0; 25 return (struct ui_progress *)1;
43} 26}
44 27
45#endif /* NEWT_SUPPORT || GTK2_SUPPORT */ 28static inline void ui_progress__update(struct ui_progress *self __used,
29 u64 curr __used) {}
30
31static inline void ui_progress__delete(struct ui_progress *self __used) {}
32#else
33extern char ui_helpline__last_msg[];
34int ui_helpline__show_help(const char *format, va_list ap);
35#include "ui/progress.h"
36#endif
46 37
47int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
48int ui__error_paranoid(void); 39void ui__warning_paranoid(void);
49 40
50#endif /* __PERF_DEBUG_H */ 41#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index dd8b19319c0..a88fefc0cc0 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -2,12 +2,8 @@
2#include "debugfs.h" 2#include "debugfs.h"
3#include "cache.h" 3#include "cache.h"
4 4
5#include <linux/kernel.h>
6#include <sys/mount.h>
7
8static int debugfs_premounted; 5static int debugfs_premounted;
9char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; 6static char debugfs_mountpoint[MAX_PATH+1];
10char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
11 7
12static const char *debugfs_known_mountpoints[] = { 8static const char *debugfs_known_mountpoints[] = {
13 "/sys/kernel/debug/", 9 "/sys/kernel/debug/",
@@ -15,6 +11,32 @@ static const char *debugfs_known_mountpoints[] = {
15 0, 11 0,
16}; 12};
17 13
14/* use this to force a umount */
15void debugfs_force_cleanup(void)
16{
17 debugfs_find_mountpoint();
18 debugfs_premounted = 0;
19 debugfs_umount();
20}
21
22/* construct a full path to a debugfs element */
23int debugfs_make_path(const char *element, char *buffer, int size)
24{
25 int len;
26
27 if (strlen(debugfs_mountpoint) == 0) {
28 buffer[0] = '\0';
29 return -1;
30 }
31
32 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
33 if (len >= size)
34 return len+1;
35
36 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
37 return 0;
38}
39
18static int debugfs_found; 40static int debugfs_found;
19 41
20/* find the path to the mounted debugfs */ 42/* find the path to the mounted debugfs */
@@ -40,9 +62,11 @@ const char *debugfs_find_mountpoint(void)
40 /* give up and parse /proc/mounts */ 62 /* give up and parse /proc/mounts */
41 fp = fopen("/proc/mounts", "r"); 63 fp = fopen("/proc/mounts", "r");
42 if (fp == NULL) 64 if (fp == NULL)
43 return NULL; 65 die("Can't open /proc/mounts for read");
44 66
45 while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", 67 while (fscanf(fp, "%*s %"
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
46 debugfs_mountpoint, type) == 2) { 70 debugfs_mountpoint, type) == 2) {
47 if (strcmp(type, "debugfs") == 0) 71 if (strcmp(type, "debugfs") == 0)
48 break; 72 break;
@@ -71,10 +95,15 @@ int debugfs_valid_mountpoint(const char *debugfs)
71 return 0; 95 return 0;
72} 96}
73 97
74static void debugfs_set_tracing_events_path(const char *mountpoint) 98
99int debugfs_valid_entry(const char *path)
75{ 100{
76 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", 101 struct stat st;
77 mountpoint, "tracing/events"); 102
103 if (stat(path, &st))
104 return -errno;
105
106 return 0;
78} 107}
79 108
80/* mount the debugfs somewhere if it's not mounted */ 109/* mount the debugfs somewhere if it's not mounted */
@@ -84,7 +113,7 @@ char *debugfs_mount(const char *mountpoint)
84 /* see if it's already mounted */ 113 /* see if it's already mounted */
85 if (debugfs_find_mountpoint()) { 114 if (debugfs_find_mountpoint()) {
86 debugfs_premounted = 1; 115 debugfs_premounted = 1;
87 goto out; 116 return debugfs_mountpoint;
88 } 117 }
89 118
90 /* if not mounted and no argument */ 119 /* if not mounted and no argument */
@@ -100,15 +129,112 @@ char *debugfs_mount(const char *mountpoint)
100 return NULL; 129 return NULL;
101 130
102 /* save the mountpoint */ 131 /* save the mountpoint */
103 debugfs_found = 1;
104 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
105out: 133 debugfs_found = 1;
106 debugfs_set_tracing_events_path(debugfs_mountpoint); 134
107 return debugfs_mountpoint; 135 return debugfs_mountpoint;
108} 136}
109 137
110void debugfs_set_path(const char *mountpoint) 138/* umount the debugfs */
139
140int debugfs_umount(void)
141{
142 char umountcmd[128];
143 int ret;
144
145 /* if it was already mounted, leave it */
146 if (debugfs_premounted)
147 return 0;
148
149 /* make sure it's a valid mount point */
150 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
151 if (ret)
152 return ret;
153
154 snprintf(umountcmd, sizeof(umountcmd),
155 "/bin/umount %s", debugfs_mountpoint);
156 return system(umountcmd);
157}
158
159int debugfs_write(const char *entry, const char *value)
111{ 160{
112 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); 161 char path[MAX_PATH+1];
113 debugfs_set_tracing_events_path(mountpoint); 162 int ret, count;
163 int fd;
164
165 /* construct the path */
166 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
167
168 /* verify that it exists */
169 ret = debugfs_valid_entry(path);
170 if (ret)
171 return ret;
172
173 /* get how many chars we're going to write */
174 count = strlen(value);
175
176 /* open the debugfs entry */
177 fd = open(path, O_RDWR);
178 if (fd < 0)
179 return -errno;
180
181 while (count > 0) {
182 /* write it */
183 ret = write(fd, value, count);
184 if (ret <= 0) {
185 if (ret == EAGAIN)
186 continue;
187 close(fd);
188 return -errno;
189 }
190 count -= ret;
191 }
192
193 /* close it */
194 close(fd);
195
196 /* return success */
197 return 0;
198}
199
200/*
201 * read a debugfs entry
202 * returns the number of chars read or a negative errno
203 */
204int debugfs_read(const char *entry, char *buffer, size_t size)
205{
206 char path[MAX_PATH+1];
207 int ret;
208 int fd;
209
210 /* construct the path */
211 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
212
213 /* verify that it exists */
214 ret = debugfs_valid_entry(path);
215 if (ret)
216 return ret;
217
218 /* open the debugfs entry */
219 fd = open(path, O_RDONLY);
220 if (fd < 0)
221 return -errno;
222
223 do {
224 /* read it */
225 ret = read(fd, buffer, size);
226 if (ret == 0) {
227 close(fd);
228 return EOF;
229 }
230 } while (ret < 0 && errno == EAGAIN);
231
232 /* close it */
233 close(fd);
234
235 /* make *sure* there's a null character at the end */
236 buffer[ret] = '\0';
237
238 /* return the number of chars read */
239 return ret;
114} 240}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 68f3e87ec57..83a02879745 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -1,12 +1,25 @@
1#ifndef __DEBUGFS_H__ 1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__ 2#define __DEBUGFS_H__
3 3
4const char *debugfs_find_mountpoint(void); 4#include <sys/mount.h>
5int debugfs_valid_mountpoint(const char *debugfs);
6char *debugfs_mount(const char *mountpoint);
7void debugfs_set_path(const char *mountpoint);
8 5
9extern char debugfs_mountpoint[]; 6#ifndef MAX_PATH
10extern char tracing_events_path[]; 7# define MAX_PATH 256
8#endif
9
10#ifndef STR
11# define _STR(x) #x
12# define STR(x) _STR(x)
13#endif
14
15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path);
18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size);
22extern void debugfs_force_cleanup(void);
23extern int debugfs_make_path(const char *element, char *buffer, int size);
11 24
12#endif /* __DEBUGFS_H__ */ 25#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
deleted file mode 100644
index d6d9a465acd..00000000000
--- a/tools/perf/util/dso.c
+++ /dev/null
@@ -1,595 +0,0 @@
1#include "symbol.h"
2#include "dso.h"
3#include "machine.h"
4#include "util.h"
5#include "debug.h"
6
7char dso__symtab_origin(const struct dso *dso)
8{
9 static const char origin[] = {
10 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
11 [DSO_BINARY_TYPE__VMLINUX] = 'v',
12 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
13 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
14 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
15 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
16 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
17 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
18 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
19 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
20 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
21 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
22 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
23 };
24
25 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
26 return '!';
27 return origin[dso->symtab_type];
28}
29
30int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
31 char *root_dir, char *file, size_t size)
32{
33 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
34 int ret = 0;
35
36 switch (type) {
37 case DSO_BINARY_TYPE__DEBUGLINK: {
38 char *debuglink;
39
40 strncpy(file, dso->long_name, size);
41 debuglink = file + dso->long_name_len;
42 while (debuglink != file && *debuglink != '/')
43 debuglink--;
44 if (*debuglink == '/')
45 debuglink++;
46 filename__read_debuglink(dso->long_name, debuglink,
47 size - (debuglink - file));
48 }
49 break;
50 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
51 /* skip the locally configured cache if a symfs is given */
52 if (symbol_conf.symfs[0] ||
53 (dso__build_id_filename(dso, file, size) == NULL))
54 ret = -1;
55 break;
56
57 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
58 snprintf(file, size, "%s/usr/lib/debug%s.debug",
59 symbol_conf.symfs, dso->long_name);
60 break;
61
62 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
63 snprintf(file, size, "%s/usr/lib/debug%s",
64 symbol_conf.symfs, dso->long_name);
65 break;
66
67 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
68 if (!dso->has_build_id) {
69 ret = -1;
70 break;
71 }
72
73 build_id__sprintf(dso->build_id,
74 sizeof(dso->build_id),
75 build_id_hex);
76 snprintf(file, size,
77 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
78 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
79 break;
80
81 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
82 snprintf(file, size, "%s%s",
83 symbol_conf.symfs, dso->long_name);
84 break;
85
86 case DSO_BINARY_TYPE__GUEST_KMODULE:
87 snprintf(file, size, "%s%s%s", symbol_conf.symfs,
88 root_dir, dso->long_name);
89 break;
90
91 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
92 snprintf(file, size, "%s%s", symbol_conf.symfs,
93 dso->long_name);
94 break;
95
96 default:
97 case DSO_BINARY_TYPE__KALLSYMS:
98 case DSO_BINARY_TYPE__VMLINUX:
99 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
100 case DSO_BINARY_TYPE__GUEST_VMLINUX:
101 case DSO_BINARY_TYPE__JAVA_JIT:
102 case DSO_BINARY_TYPE__NOT_FOUND:
103 ret = -1;
104 break;
105 }
106
107 return ret;
108}
109
110static int open_dso(struct dso *dso, struct machine *machine)
111{
112 char *root_dir = (char *) "";
113 char *name;
114 int fd;
115
116 name = malloc(PATH_MAX);
117 if (!name)
118 return -ENOMEM;
119
120 if (machine)
121 root_dir = machine->root_dir;
122
123 if (dso__binary_type_file(dso, dso->data_type,
124 root_dir, name, PATH_MAX)) {
125 free(name);
126 return -EINVAL;
127 }
128
129 fd = open(name, O_RDONLY);
130 free(name);
131 return fd;
132}
133
134int dso__data_fd(struct dso *dso, struct machine *machine)
135{
136 static enum dso_binary_type binary_type_data[] = {
137 DSO_BINARY_TYPE__BUILD_ID_CACHE,
138 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
139 DSO_BINARY_TYPE__NOT_FOUND,
140 };
141 int i = 0;
142
143 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
144 return open_dso(dso, machine);
145
146 do {
147 int fd;
148
149 dso->data_type = binary_type_data[i++];
150
151 fd = open_dso(dso, machine);
152 if (fd >= 0)
153 return fd;
154
155 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
156
157 return -EINVAL;
158}
159
160static void
161dso_cache__free(struct rb_root *root)
162{
163 struct rb_node *next = rb_first(root);
164
165 while (next) {
166 struct dso_cache *cache;
167
168 cache = rb_entry(next, struct dso_cache, rb_node);
169 next = rb_next(&cache->rb_node);
170 rb_erase(&cache->rb_node, root);
171 free(cache);
172 }
173}
174
175static struct dso_cache*
176dso_cache__find(struct rb_root *root, u64 offset)
177{
178 struct rb_node **p = &root->rb_node;
179 struct rb_node *parent = NULL;
180 struct dso_cache *cache;
181
182 while (*p != NULL) {
183 u64 end;
184
185 parent = *p;
186 cache = rb_entry(parent, struct dso_cache, rb_node);
187 end = cache->offset + DSO__DATA_CACHE_SIZE;
188
189 if (offset < cache->offset)
190 p = &(*p)->rb_left;
191 else if (offset >= end)
192 p = &(*p)->rb_right;
193 else
194 return cache;
195 }
196 return NULL;
197}
198
199static void
200dso_cache__insert(struct rb_root *root, struct dso_cache *new)
201{
202 struct rb_node **p = &root->rb_node;
203 struct rb_node *parent = NULL;
204 struct dso_cache *cache;
205 u64 offset = new->offset;
206
207 while (*p != NULL) {
208 u64 end;
209
210 parent = *p;
211 cache = rb_entry(parent, struct dso_cache, rb_node);
212 end = cache->offset + DSO__DATA_CACHE_SIZE;
213
214 if (offset < cache->offset)
215 p = &(*p)->rb_left;
216 else if (offset >= end)
217 p = &(*p)->rb_right;
218 }
219
220 rb_link_node(&new->rb_node, parent, p);
221 rb_insert_color(&new->rb_node, root);
222}
223
224static ssize_t
225dso_cache__memcpy(struct dso_cache *cache, u64 offset,
226 u8 *data, u64 size)
227{
228 u64 cache_offset = offset - cache->offset;
229 u64 cache_size = min(cache->size - cache_offset, size);
230
231 memcpy(data, cache->data + cache_offset, cache_size);
232 return cache_size;
233}
234
235static ssize_t
236dso_cache__read(struct dso *dso, struct machine *machine,
237 u64 offset, u8 *data, ssize_t size)
238{
239 struct dso_cache *cache;
240 ssize_t ret;
241 int fd;
242
243 fd = dso__data_fd(dso, machine);
244 if (fd < 0)
245 return -1;
246
247 do {
248 u64 cache_offset;
249
250 ret = -ENOMEM;
251
252 cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
253 if (!cache)
254 break;
255
256 cache_offset = offset & DSO__DATA_CACHE_MASK;
257 ret = -EINVAL;
258
259 if (-1 == lseek(fd, cache_offset, SEEK_SET))
260 break;
261
262 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
263 if (ret <= 0)
264 break;
265
266 cache->offset = cache_offset;
267 cache->size = ret;
268 dso_cache__insert(&dso->cache, cache);
269
270 ret = dso_cache__memcpy(cache, offset, data, size);
271
272 } while (0);
273
274 if (ret <= 0)
275 free(cache);
276
277 close(fd);
278 return ret;
279}
280
281static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
282 u64 offset, u8 *data, ssize_t size)
283{
284 struct dso_cache *cache;
285
286 cache = dso_cache__find(&dso->cache, offset);
287 if (cache)
288 return dso_cache__memcpy(cache, offset, data, size);
289 else
290 return dso_cache__read(dso, machine, offset, data, size);
291}
292
293ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
294 u64 offset, u8 *data, ssize_t size)
295{
296 ssize_t r = 0;
297 u8 *p = data;
298
299 do {
300 ssize_t ret;
301
302 ret = dso_cache_read(dso, machine, offset, p, size);
303 if (ret < 0)
304 return ret;
305
306 /* Reached EOF, return what we have. */
307 if (!ret)
308 break;
309
310 BUG_ON(ret > size);
311
312 r += ret;
313 p += ret;
314 offset += ret;
315 size -= ret;
316
317 } while (size);
318
319 return r;
320}
321
322ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
323 struct machine *machine, u64 addr,
324 u8 *data, ssize_t size)
325{
326 u64 offset = map->map_ip(map, addr);
327 return dso__data_read_offset(dso, machine, offset, data, size);
328}
329
330struct map *dso__new_map(const char *name)
331{
332 struct map *map = NULL;
333 struct dso *dso = dso__new(name);
334
335 if (dso)
336 map = map__new2(0, dso, MAP__FUNCTION);
337
338 return map;
339}
340
341struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
342 const char *short_name, int dso_type)
343{
344 /*
345 * The kernel dso could be created by build_id processing.
346 */
347 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
348
349 /*
350 * We need to run this in all cases, since during the build_id
351 * processing we had no idea this was the kernel dso.
352 */
353 if (dso != NULL) {
354 dso__set_short_name(dso, short_name);
355 dso->kernel = dso_type;
356 }
357
358 return dso;
359}
360
361void dso__set_long_name(struct dso *dso, char *name)
362{
363 if (name == NULL)
364 return;
365 dso->long_name = name;
366 dso->long_name_len = strlen(name);
367}
368
369void dso__set_short_name(struct dso *dso, const char *name)
370{
371 if (name == NULL)
372 return;
373 dso->short_name = name;
374 dso->short_name_len = strlen(name);
375}
376
377static void dso__set_basename(struct dso *dso)
378{
379 dso__set_short_name(dso, basename(dso->long_name));
380}
381
382int dso__name_len(const struct dso *dso)
383{
384 if (!dso)
385 return strlen("[unknown]");
386 if (verbose)
387 return dso->long_name_len;
388
389 return dso->short_name_len;
390}
391
392bool dso__loaded(const struct dso *dso, enum map_type type)
393{
394 return dso->loaded & (1 << type);
395}
396
397bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
398{
399 return dso->sorted_by_name & (1 << type);
400}
401
402void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
403{
404 dso->sorted_by_name |= (1 << type);
405}
406
407struct dso *dso__new(const char *name)
408{
409 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
410
411 if (dso != NULL) {
412 int i;
413 strcpy(dso->name, name);
414 dso__set_long_name(dso, dso->name);
415 dso__set_short_name(dso, dso->name);
416 for (i = 0; i < MAP__NR_TYPES; ++i)
417 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
418 dso->cache = RB_ROOT;
419 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
420 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
421 dso->loaded = 0;
422 dso->sorted_by_name = 0;
423 dso->has_build_id = 0;
424 dso->kernel = DSO_TYPE_USER;
425 dso->needs_swap = DSO_SWAP__UNSET;
426 INIT_LIST_HEAD(&dso->node);
427 }
428
429 return dso;
430}
431
432void dso__delete(struct dso *dso)
433{
434 int i;
435 for (i = 0; i < MAP__NR_TYPES; ++i)
436 symbols__delete(&dso->symbols[i]);
437 if (dso->sname_alloc)
438 free((char *)dso->short_name);
439 if (dso->lname_alloc)
440 free(dso->long_name);
441 dso_cache__free(&dso->cache);
442 free(dso);
443}
444
445void dso__set_build_id(struct dso *dso, void *build_id)
446{
447 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
448 dso->has_build_id = 1;
449}
450
451bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
452{
453 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
454}
455
456void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
457{
458 char path[PATH_MAX];
459
460 if (machine__is_default_guest(machine))
461 return;
462 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
463 if (sysfs__read_build_id(path, dso->build_id,
464 sizeof(dso->build_id)) == 0)
465 dso->has_build_id = true;
466}
467
468int dso__kernel_module_get_build_id(struct dso *dso,
469 const char *root_dir)
470{
471 char filename[PATH_MAX];
472 /*
473 * kernel module short names are of the form "[module]" and
474 * we need just "module" here.
475 */
476 const char *name = dso->short_name + 1;
477
478 snprintf(filename, sizeof(filename),
479 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
480 root_dir, (int)strlen(name) - 1, name);
481
482 if (sysfs__read_build_id(filename, dso->build_id,
483 sizeof(dso->build_id)) == 0)
484 dso->has_build_id = true;
485
486 return 0;
487}
488
489bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
490{
491 bool have_build_id = false;
492 struct dso *pos;
493
494 list_for_each_entry(pos, head, node) {
495 if (with_hits && !pos->hit)
496 continue;
497 if (pos->has_build_id) {
498 have_build_id = true;
499 continue;
500 }
501 if (filename__read_build_id(pos->long_name, pos->build_id,
502 sizeof(pos->build_id)) > 0) {
503 have_build_id = true;
504 pos->has_build_id = true;
505 }
506 }
507
508 return have_build_id;
509}
510
511void dsos__add(struct list_head *head, struct dso *dso)
512{
513 list_add_tail(&dso->node, head);
514}
515
516struct dso *dsos__find(struct list_head *head, const char *name)
517{
518 struct dso *pos;
519
520 list_for_each_entry(pos, head, node)
521 if (strcmp(pos->long_name, name) == 0)
522 return pos;
523 return NULL;
524}
525
526struct dso *__dsos__findnew(struct list_head *head, const char *name)
527{
528 struct dso *dso = dsos__find(head, name);
529
530 if (!dso) {
531 dso = dso__new(name);
532 if (dso != NULL) {
533 dsos__add(head, dso);
534 dso__set_basename(dso);
535 }
536 }
537
538 return dso;
539}
540
541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
542 bool with_hits)
543{
544 struct dso *pos;
545 size_t ret = 0;
546
547 list_for_each_entry(pos, head, node) {
548 if (with_hits && !pos->hit)
549 continue;
550 ret += dso__fprintf_buildid(pos, fp);
551 ret += fprintf(fp, " %s\n", pos->long_name);
552 }
553 return ret;
554}
555
556size_t __dsos__fprintf(struct list_head *head, FILE *fp)
557{
558 struct dso *pos;
559 size_t ret = 0;
560
561 list_for_each_entry(pos, head, node) {
562 int i;
563 for (i = 0; i < MAP__NR_TYPES; ++i)
564 ret += dso__fprintf(pos, i, fp);
565 }
566
567 return ret;
568}
569
570size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
571{
572 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
573
574 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
575 return fprintf(fp, "%s", sbuild_id);
576}
577
578size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
579{
580 struct rb_node *nd;
581 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
582
583 if (dso->short_name != dso->long_name)
584 ret += fprintf(fp, "%s, ", dso->long_name);
585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
586 dso->loaded ? "" : "NOT ");
587 ret += dso__fprintf_buildid(dso, fp);
588 ret += fprintf(fp, ")\n");
589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
590 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
591 ret += symbol__fprintf(pos, fp);
592 }
593
594 return ret;
595}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
deleted file mode 100644
index e03276940b9..00000000000
--- a/tools/perf/util/dso.h
+++ /dev/null
@@ -1,148 +0,0 @@
1#ifndef __PERF_DSO
2#define __PERF_DSO
3
4#include <linux/types.h>
5#include <linux/rbtree.h>
6#include "types.h"
7#include "map.h"
8
9enum dso_binary_type {
10 DSO_BINARY_TYPE__KALLSYMS = 0,
11 DSO_BINARY_TYPE__GUEST_KALLSYMS,
12 DSO_BINARY_TYPE__VMLINUX,
13 DSO_BINARY_TYPE__GUEST_VMLINUX,
14 DSO_BINARY_TYPE__JAVA_JIT,
15 DSO_BINARY_TYPE__DEBUGLINK,
16 DSO_BINARY_TYPE__BUILD_ID_CACHE,
17 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
18 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
19 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
20 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
21 DSO_BINARY_TYPE__GUEST_KMODULE,
22 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
23 DSO_BINARY_TYPE__NOT_FOUND,
24};
25
26enum dso_kernel_type {
27 DSO_TYPE_USER = 0,
28 DSO_TYPE_KERNEL,
29 DSO_TYPE_GUEST_KERNEL
30};
31
32enum dso_swap_type {
33 DSO_SWAP__UNSET,
34 DSO_SWAP__NO,
35 DSO_SWAP__YES,
36};
37
38#define DSO__SWAP(dso, type, val) \
39({ \
40 type ____r = val; \
41 BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \
42 if (dso->needs_swap == DSO_SWAP__YES) { \
43 switch (sizeof(____r)) { \
44 case 2: \
45 ____r = bswap_16(val); \
46 break; \
47 case 4: \
48 ____r = bswap_32(val); \
49 break; \
50 case 8: \
51 ____r = bswap_64(val); \
52 break; \
53 default: \
54 BUG_ON(1); \
55 } \
56 } \
57 ____r; \
58})
59
60#define DSO__DATA_CACHE_SIZE 4096
61#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
62
63struct dso_cache {
64 struct rb_node rb_node;
65 u64 offset;
66 u64 size;
67 char data[0];
68};
69
70struct dso {
71 struct list_head node;
72 struct rb_root symbols[MAP__NR_TYPES];
73 struct rb_root symbol_names[MAP__NR_TYPES];
74 struct rb_root cache;
75 enum dso_kernel_type kernel;
76 enum dso_swap_type needs_swap;
77 enum dso_binary_type symtab_type;
78 enum dso_binary_type data_type;
79 u8 adjust_symbols:1;
80 u8 has_build_id:1;
81 u8 hit:1;
82 u8 annotate_warned:1;
83 u8 sname_alloc:1;
84 u8 lname_alloc:1;
85 u8 sorted_by_name;
86 u8 loaded;
87 u8 build_id[BUILD_ID_SIZE];
88 const char *short_name;
89 char *long_name;
90 u16 long_name_len;
91 u16 short_name_len;
92 char name[0];
93};
94
95static inline void dso__set_loaded(struct dso *dso, enum map_type type)
96{
97 dso->loaded |= (1 << type);
98}
99
100struct dso *dso__new(const char *name);
101void dso__delete(struct dso *dso);
102
103void dso__set_short_name(struct dso *dso, const char *name);
104void dso__set_long_name(struct dso *dso, char *name);
105
106int dso__name_len(const struct dso *dso);
107
108bool dso__loaded(const struct dso *dso, enum map_type type);
109
110bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
111void dso__set_sorted_by_name(struct dso *dso, enum map_type type);
112void dso__sort_by_name(struct dso *dso, enum map_type type);
113
114void dso__set_build_id(struct dso *dso, void *build_id);
115bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
116void dso__read_running_kernel_build_id(struct dso *dso,
117 struct machine *machine);
118int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
119
120char dso__symtab_origin(const struct dso *dso);
121int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
122 char *root_dir, char *file, size_t size);
123
124int dso__data_fd(struct dso *dso, struct machine *machine);
125ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
126 u64 offset, u8 *data, ssize_t size);
127ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
128 struct machine *machine, u64 addr,
129 u8 *data, ssize_t size);
130
131struct map *dso__new_map(const char *name);
132struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
133 const char *short_name, int dso_type);
134
135void dsos__add(struct list_head *head, struct dso *dso);
136struct dso *dsos__find(struct list_head *head, const char *name);
137struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139
140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
141 bool with_hits);
142size_t __dsos__fprintf(struct list_head *head, FILE *fp);
143
144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
145size_t dso__fprintf_symbols_by_name(struct dso *dso,
146 enum map_type type, FILE *fp);
147size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
148#endif /* __PERF_DSO */
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 3e5f5430a28..ee51e9b4dc0 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -804,8 +804,6 @@ int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
804 tmp = "union "; 804 tmp = "union ";
805 else if (tag == DW_TAG_structure_type) 805 else if (tag == DW_TAG_structure_type)
806 tmp = "struct "; 806 tmp = "struct ";
807 else if (tag == DW_TAG_enumeration_type)
808 tmp = "enum ";
809 /* Write a base name */ 807 /* Write a base name */
810 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); 808 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
811 return (ret >= len) ? -E2BIG : ret; 809 return (ret >= len) ? -E2BIG : ret;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3cf2c3e0605..437f8ca679a 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,7 +1,7 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "machine.h" 4#include "session.h"
5#include "sort.h" 5#include "sort.h"
6#include "string.h" 6#include "string.h"
7#include "strlist.h" 7#include "strlist.h"
@@ -44,27 +44,36 @@ static struct perf_sample synth_sample = {
44 .period = 1, 44 .period = 1,
45}; 45};
46 46
47static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) 47static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
48 int full, perf_event__handler_t process,
49 struct perf_session *session)
48{ 50{
49 char filename[PATH_MAX]; 51 char filename[PATH_MAX];
50 char bf[BUFSIZ]; 52 char bf[BUFSIZ];
51 FILE *fp; 53 FILE *fp;
52 size_t size = 0; 54 size_t size = 0;
53 pid_t tgid = -1; 55 DIR *tasks;
56 struct dirent dirent, *next;
57 pid_t tgid = 0;
54 58
55 snprintf(filename, sizeof(filename), "/proc/%d/status", pid); 59 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
56 60
57 fp = fopen(filename, "r"); 61 fp = fopen(filename, "r");
58 if (fp == NULL) { 62 if (fp == NULL) {
63out_race:
64 /*
65 * We raced with a task exiting - just return:
66 */
59 pr_debug("couldn't open %s\n", filename); 67 pr_debug("couldn't open %s\n", filename);
60 return 0; 68 return 0;
61 } 69 }
62 70
63 while (!comm[0] || (tgid < 0)) { 71 memset(&event->comm, 0, sizeof(event->comm));
72
73 while (!event->comm.comm[0] || !event->comm.pid) {
64 if (fgets(bf, sizeof(bf), fp) == NULL) { 74 if (fgets(bf, sizeof(bf), fp) == NULL) {
65 pr_warning("couldn't get COMM and pgid, malformed %s\n", 75 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
66 filename); 76 goto out;
67 break;
68 } 77 }
69 78
70 if (memcmp(bf, "Name:", 5) == 0) { 79 if (memcmp(bf, "Name:", 5) == 0) {
@@ -72,68 +81,33 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
72 while (*name && isspace(*name)) 81 while (*name && isspace(*name))
73 ++name; 82 ++name;
74 size = strlen(name) - 1; 83 size = strlen(name) - 1;
75 if (size >= len) 84 memcpy(event->comm.comm, name, size++);
76 size = len - 1;
77 memcpy(comm, name, size);
78 comm[size] = '\0';
79
80 } else if (memcmp(bf, "Tgid:", 5) == 0) { 85 } else if (memcmp(bf, "Tgid:", 5) == 0) {
81 char *tgids = bf + 5; 86 char *tgids = bf + 5;
82 while (*tgids && isspace(*tgids)) 87 while (*tgids && isspace(*tgids))
83 ++tgids; 88 ++tgids;
84 tgid = atoi(tgids); 89 tgid = event->comm.pid = atoi(tgids);
85 } 90 }
86 } 91 }
87 92
88 fclose(fp);
89
90 return tgid;
91}
92
93static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
94 union perf_event *event, pid_t pid,
95 int full,
96 perf_event__handler_t process,
97 struct machine *machine)
98{
99 char filename[PATH_MAX];
100 size_t size;
101 DIR *tasks;
102 struct dirent dirent, *next;
103 pid_t tgid;
104
105 memset(&event->comm, 0, sizeof(event->comm));
106
107 tgid = perf_event__get_comm_tgid(pid, event->comm.comm,
108 sizeof(event->comm.comm));
109 if (tgid < 0)
110 goto out;
111
112 event->comm.pid = tgid;
113 event->comm.header.type = PERF_RECORD_COMM; 93 event->comm.header.type = PERF_RECORD_COMM;
114 94 size = ALIGN(size, sizeof(u64));
115 size = strlen(event->comm.comm) + 1; 95 memset(event->comm.comm + size, 0, session->id_hdr_size);
116 size = PERF_ALIGN(size, sizeof(u64));
117 memset(event->comm.comm + size, 0, machine->id_hdr_size);
118 event->comm.header.size = (sizeof(event->comm) - 96 event->comm.header.size = (sizeof(event->comm) -
119 (sizeof(event->comm.comm) - size) + 97 (sizeof(event->comm.comm) - size) +
120 machine->id_hdr_size); 98 session->id_hdr_size);
121 if (!full) { 99 if (!full) {
122 event->comm.tid = pid; 100 event->comm.tid = pid;
123 101
124 if (process(tool, event, &synth_sample, machine) != 0) 102 process(event, &synth_sample, session);
125 return -1;
126
127 goto out; 103 goto out;
128 } 104 }
129 105
130 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 106 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
131 107
132 tasks = opendir(filename); 108 tasks = opendir(filename);
133 if (tasks == NULL) { 109 if (tasks == NULL)
134 pr_debug("couldn't open %s\n", filename); 110 goto out_race;
135 return 0;
136 }
137 111
138 while (!readdir_r(tasks, &dirent, &next) && next) { 112 while (!readdir_r(tasks, &dirent, &next) && next) {
139 char *end; 113 char *end;
@@ -141,39 +115,25 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
141 if (*end) 115 if (*end)
142 continue; 116 continue;
143 117
144 /* already have tgid; jut want to update the comm */
145 (void) perf_event__get_comm_tgid(pid, event->comm.comm,
146 sizeof(event->comm.comm));
147
148 size = strlen(event->comm.comm) + 1;
149 size = PERF_ALIGN(size, sizeof(u64));
150 memset(event->comm.comm + size, 0, machine->id_hdr_size);
151 event->comm.header.size = (sizeof(event->comm) -
152 (sizeof(event->comm.comm) - size) +
153 machine->id_hdr_size);
154
155 event->comm.tid = pid; 118 event->comm.tid = pid;
156 119
157 if (process(tool, event, &synth_sample, machine) != 0) { 120 process(event, &synth_sample, session);
158 tgid = -1;
159 break;
160 }
161 } 121 }
162 122
163 closedir(tasks); 123 closedir(tasks);
164out: 124out:
125 fclose(fp);
126
165 return tgid; 127 return tgid;
166} 128}
167 129
168static int perf_event__synthesize_mmap_events(struct perf_tool *tool, 130static int perf_event__synthesize_mmap_events(union perf_event *event,
169 union perf_event *event,
170 pid_t pid, pid_t tgid, 131 pid_t pid, pid_t tgid,
171 perf_event__handler_t process, 132 perf_event__handler_t process,
172 struct machine *machine) 133 struct perf_session *session)
173{ 134{
174 char filename[PATH_MAX]; 135 char filename[PATH_MAX];
175 FILE *fp; 136 FILE *fp;
176 int rc = 0;
177 137
178 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); 138 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
179 139
@@ -193,59 +153,67 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
193 event->header.misc = PERF_RECORD_MISC_USER; 153 event->header.misc = PERF_RECORD_MISC_USER;
194 154
195 while (1) { 155 while (1) {
196 char bf[BUFSIZ]; 156 char bf[BUFSIZ], *pbf = bf;
197 char prot[5]; 157 int n;
198 char execname[PATH_MAX];
199 char anonstr[] = "//anon";
200 size_t size; 158 size_t size;
201
202 if (fgets(bf, sizeof(bf), fp) == NULL) 159 if (fgets(bf, sizeof(bf), fp) == NULL)
203 break; 160 break;
204 161
205 /* ensure null termination since stack will be reused. */
206 strcpy(execname, "");
207
208 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 162 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
209 sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 163 n = hex2u64(pbf, &event->mmap.start);
210 &event->mmap.start, &event->mmap.len, prot, 164 if (n < 0)
211 &event->mmap.pgoff, execname);
212
213 if (prot[2] != 'x')
214 continue; 165 continue;
215 166 pbf += n + 1;
216 if (!strcmp(execname, "")) 167 n = hex2u64(pbf, &event->mmap.len);
217 strcpy(execname, anonstr); 168 if (n < 0)
218 169 continue;
219 size = strlen(execname) + 1; 170 pbf += n + 3;
220 memcpy(event->mmap.filename, execname, size); 171 if (*pbf == 'x') { /* vm_exec */
221 size = PERF_ALIGN(size, sizeof(u64)); 172 char anonstr[] = "//anon\n";
222 event->mmap.len -= event->mmap.start; 173 char *execname = strchr(bf, '/');
223 event->mmap.header.size = (sizeof(event->mmap) - 174
224 (sizeof(event->mmap.filename) - size)); 175 /* Catch VDSO */
225 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 176 if (execname == NULL)
226 event->mmap.header.size += machine->id_hdr_size; 177 execname = strstr(bf, "[vdso]");
227 event->mmap.pid = tgid; 178
228 event->mmap.tid = pid; 179 /* Catch anonymous mmaps */
229 180 if ((execname == NULL) && !strstr(bf, "["))
230 if (process(tool, event, &synth_sample, machine) != 0) { 181 execname = anonstr;
231 rc = -1; 182
232 break; 183 if (execname == NULL)
184 continue;
185
186 pbf += 3;
187 n = hex2u64(pbf, &event->mmap.pgoff);
188
189 size = strlen(execname);
190 execname[size - 1] = '\0'; /* Remove \n */
191 memcpy(event->mmap.filename, execname, size);
192 size = ALIGN(size, sizeof(u64));
193 event->mmap.len -= event->mmap.start;
194 event->mmap.header.size = (sizeof(event->mmap) -
195 (sizeof(event->mmap.filename) - size));
196 memset(event->mmap.filename + size, 0, session->id_hdr_size);
197 event->mmap.header.size += session->id_hdr_size;
198 event->mmap.pid = tgid;
199 event->mmap.tid = pid;
200
201 process(event, &synth_sample, session);
233 } 202 }
234 } 203 }
235 204
236 fclose(fp); 205 fclose(fp);
237 return rc; 206 return 0;
238} 207}
239 208
240int perf_event__synthesize_modules(struct perf_tool *tool, 209int perf_event__synthesize_modules(perf_event__handler_t process,
241 perf_event__handler_t process, 210 struct perf_session *session,
242 struct machine *machine) 211 struct machine *machine)
243{ 212{
244 int rc = 0;
245 struct rb_node *nd; 213 struct rb_node *nd;
246 struct map_groups *kmaps = &machine->kmaps; 214 struct map_groups *kmaps = &machine->kmaps;
247 union perf_event *event = zalloc((sizeof(event->mmap) + 215 union perf_event *event = zalloc((sizeof(event->mmap) +
248 machine->id_hdr_size)); 216 session->id_hdr_size));
249 if (event == NULL) { 217 if (event == NULL) {
250 pr_debug("Not enough memory synthesizing mmap event " 218 pr_debug("Not enough memory synthesizing mmap event "
251 "for kernel modules\n"); 219 "for kernel modules\n");
@@ -271,93 +239,61 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
271 if (pos->dso->kernel) 239 if (pos->dso->kernel)
272 continue; 240 continue;
273 241
274 size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 242 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
275 event->mmap.header.type = PERF_RECORD_MMAP; 243 event->mmap.header.type = PERF_RECORD_MMAP;
276 event->mmap.header.size = (sizeof(event->mmap) - 244 event->mmap.header.size = (sizeof(event->mmap) -
277 (sizeof(event->mmap.filename) - size)); 245 (sizeof(event->mmap.filename) - size));
278 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 246 memset(event->mmap.filename + size, 0, session->id_hdr_size);
279 event->mmap.header.size += machine->id_hdr_size; 247 event->mmap.header.size += session->id_hdr_size;
280 event->mmap.start = pos->start; 248 event->mmap.start = pos->start;
281 event->mmap.len = pos->end - pos->start; 249 event->mmap.len = pos->end - pos->start;
282 event->mmap.pid = machine->pid; 250 event->mmap.pid = machine->pid;
283 251
284 memcpy(event->mmap.filename, pos->dso->long_name, 252 memcpy(event->mmap.filename, pos->dso->long_name,
285 pos->dso->long_name_len + 1); 253 pos->dso->long_name_len + 1);
286 if (process(tool, event, &synth_sample, machine) != 0) { 254 process(event, &synth_sample, session);
287 rc = -1;
288 break;
289 }
290 } 255 }
291 256
292 free(event); 257 free(event);
293 return rc; 258 return 0;
294} 259}
295 260
296static int __event__synthesize_thread(union perf_event *comm_event, 261static int __event__synthesize_thread(union perf_event *comm_event,
297 union perf_event *mmap_event, 262 union perf_event *mmap_event,
298 pid_t pid, int full, 263 pid_t pid, perf_event__handler_t process,
299 perf_event__handler_t process, 264 struct perf_session *session)
300 struct perf_tool *tool,
301 struct machine *machine)
302{ 265{
303 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, 266 pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process,
304 process, machine); 267 session);
305 if (tgid == -1) 268 if (tgid == -1)
306 return -1; 269 return -1;
307 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 270 return perf_event__synthesize_mmap_events(mmap_event, pid, tgid,
308 process, machine); 271 process, session);
309} 272}
310 273
311int perf_event__synthesize_thread_map(struct perf_tool *tool, 274int perf_event__synthesize_thread_map(struct thread_map *threads,
312 struct thread_map *threads,
313 perf_event__handler_t process, 275 perf_event__handler_t process,
314 struct machine *machine) 276 struct perf_session *session)
315{ 277{
316 union perf_event *comm_event, *mmap_event; 278 union perf_event *comm_event, *mmap_event;
317 int err = -1, thread, j; 279 int err = -1, thread;
318 280
319 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 281 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
320 if (comm_event == NULL) 282 if (comm_event == NULL)
321 goto out; 283 goto out;
322 284
323 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 285 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
324 if (mmap_event == NULL) 286 if (mmap_event == NULL)
325 goto out_free_comm; 287 goto out_free_comm;
326 288
327 err = 0; 289 err = 0;
328 for (thread = 0; thread < threads->nr; ++thread) { 290 for (thread = 0; thread < threads->nr; ++thread) {
329 if (__event__synthesize_thread(comm_event, mmap_event, 291 if (__event__synthesize_thread(comm_event, mmap_event,
330 threads->map[thread], 0, 292 threads->map[thread],
331 process, tool, machine)) { 293 process, session)) {
332 err = -1; 294 err = -1;
333 break; 295 break;
334 } 296 }
335
336 /*
337 * comm.pid is set to thread group id by
338 * perf_event__synthesize_comm
339 */
340 if ((int) comm_event->comm.pid != threads->map[thread]) {
341 bool need_leader = true;
342
343 /* is thread group leader in thread_map? */
344 for (j = 0; j < threads->nr; ++j) {
345 if ((int) comm_event->comm.pid == threads->map[j]) {
346 need_leader = false;
347 break;
348 }
349 }
350
351 /* if not, generate events for it */
352 if (need_leader &&
353 __event__synthesize_thread(comm_event,
354 mmap_event,
355 comm_event->comm.pid, 0,
356 process, tool, machine)) {
357 err = -1;
358 break;
359 }
360 }
361 } 297 }
362 free(mmap_event); 298 free(mmap_event);
363out_free_comm: 299out_free_comm:
@@ -366,20 +302,19 @@ out:
366 return err; 302 return err;
367} 303}
368 304
369int perf_event__synthesize_threads(struct perf_tool *tool, 305int perf_event__synthesize_threads(perf_event__handler_t process,
370 perf_event__handler_t process, 306 struct perf_session *session)
371 struct machine *machine)
372{ 307{
373 DIR *proc; 308 DIR *proc;
374 struct dirent dirent, *next; 309 struct dirent dirent, *next;
375 union perf_event *comm_event, *mmap_event; 310 union perf_event *comm_event, *mmap_event;
376 int err = -1; 311 int err = -1;
377 312
378 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 313 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
379 if (comm_event == NULL) 314 if (comm_event == NULL)
380 goto out; 315 goto out;
381 316
382 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 317 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
383 if (mmap_event == NULL) 318 if (mmap_event == NULL)
384 goto out_free_comm; 319 goto out_free_comm;
385 320
@@ -393,16 +328,13 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
393 328
394 if (*end) /* only interested in proper numerical dirents */ 329 if (*end) /* only interested in proper numerical dirents */
395 continue; 330 continue;
396 /* 331
397 * We may race with exiting thread, so don't stop just because 332 __event__synthesize_thread(comm_event, mmap_event, pid,
398 * one thread couldn't be synthesized. 333 process, session);
399 */
400 __event__synthesize_thread(comm_event, mmap_event, pid, 1,
401 process, tool, machine);
402 } 334 }
403 335
404 err = 0;
405 closedir(proc); 336 closedir(proc);
337 err = 0;
406out_free_mmap: 338out_free_mmap:
407 free(mmap_event); 339 free(mmap_event);
408out_free_comm: 340out_free_comm:
@@ -417,7 +349,7 @@ struct process_symbol_args {
417}; 349};
418 350
419static int find_symbol_cb(void *arg, const char *name, char type, 351static int find_symbol_cb(void *arg, const char *name, char type,
420 u64 start) 352 u64 start, u64 end __used)
421{ 353{
422 struct process_symbol_args *args = arg; 354 struct process_symbol_args *args = arg;
423 355
@@ -433,8 +365,8 @@ static int find_symbol_cb(void *arg, const char *name, char type,
433 return 1; 365 return 1;
434} 366}
435 367
436int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 368int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
437 perf_event__handler_t process, 369 struct perf_session *session,
438 struct machine *machine, 370 struct machine *machine,
439 const char *symbol_name) 371 const char *symbol_name)
440{ 372{
@@ -451,7 +383,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
451 */ 383 */
452 struct process_symbol_args args = { .name = symbol_name, }; 384 struct process_symbol_args args = { .name = symbol_name, };
453 union perf_event *event = zalloc((sizeof(event->mmap) + 385 union perf_event *event = zalloc((sizeof(event->mmap) +
454 machine->id_hdr_size)); 386 session->id_hdr_size));
455 if (event == NULL) { 387 if (event == NULL) {
456 pr_debug("Not enough memory synthesizing mmap event " 388 pr_debug("Not enough memory synthesizing mmap event "
457 "for kernel modules\n"); 389 "for kernel modules\n");
@@ -482,135 +414,280 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
482 map = machine->vmlinux_maps[MAP__FUNCTION]; 414 map = machine->vmlinux_maps[MAP__FUNCTION];
483 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 415 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
484 "%s%s", mmap_name, symbol_name) + 1; 416 "%s%s", mmap_name, symbol_name) + 1;
485 size = PERF_ALIGN(size, sizeof(u64)); 417 size = ALIGN(size, sizeof(u64));
486 event->mmap.header.type = PERF_RECORD_MMAP; 418 event->mmap.header.type = PERF_RECORD_MMAP;
487 event->mmap.header.size = (sizeof(event->mmap) - 419 event->mmap.header.size = (sizeof(event->mmap) -
488 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 420 (sizeof(event->mmap.filename) - size) + session->id_hdr_size);
489 event->mmap.pgoff = args.start; 421 event->mmap.pgoff = args.start;
490 event->mmap.start = map->start; 422 event->mmap.start = map->start;
491 event->mmap.len = map->end - event->mmap.start; 423 event->mmap.len = map->end - event->mmap.start;
492 event->mmap.pid = machine->pid; 424 event->mmap.pid = machine->pid;
493 425
494 err = process(tool, event, &synth_sample, machine); 426 err = process(event, &synth_sample, session);
495 free(event); 427 free(event);
496 428
497 return err; 429 return err;
498} 430}
499 431
500size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 432int perf_event__process_comm(union perf_event *event,
433 struct perf_sample *sample __used,
434 struct perf_session *session)
501{ 435{
502 return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); 436 struct thread *thread = perf_session__findnew(session, event->comm.tid);
503}
504 437
505int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 438 dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
506 union perf_event *event,
507 struct perf_sample *sample __maybe_unused,
508 struct machine *machine)
509{
510 return machine__process_comm_event(machine, event);
511}
512 439
513int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 440 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
514 union perf_event *event, 441 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
515 struct perf_sample *sample __maybe_unused, 442 return -1;
516 struct machine *machine) 443 }
517{ 444
518 return machine__process_lost_event(machine, event); 445 return 0;
519} 446}
520 447
521size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 448int perf_event__process_lost(union perf_event *event,
449 struct perf_sample *sample __used,
450 struct perf_session *session)
522{ 451{
523 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 452 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
524 event->mmap.pid, event->mmap.tid, event->mmap.start, 453 event->lost.id, event->lost.lost);
525 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 454 session->hists.stats.total_lost += event->lost.lost;
455 return 0;
526} 456}
527 457
528int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 458static void perf_event__set_kernel_mmap_len(union perf_event *event,
529 union perf_event *event, 459 struct map **maps)
530 struct perf_sample *sample __maybe_unused,
531 struct machine *machine)
532{ 460{
533 return machine__process_mmap_event(machine, event); 461 maps[MAP__FUNCTION]->start = event->mmap.start;
462 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
463 /*
464 * Be a bit paranoid here, some perf.data file came with
465 * a zero sized synthesized MMAP event for the kernel.
466 */
467 if (maps[MAP__FUNCTION]->end == 0)
468 maps[MAP__FUNCTION]->end = ~0ULL;
534} 469}
535 470
536size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 471static int perf_event__process_kernel_mmap(union perf_event *event,
472 struct perf_session *session)
537{ 473{
538 return fprintf(fp, "(%d:%d):(%d:%d)\n", 474 struct map *map;
539 event->fork.pid, event->fork.tid, 475 char kmmap_prefix[PATH_MAX];
540 event->fork.ppid, event->fork.ptid); 476 struct machine *machine;
477 enum dso_kernel_type kernel_type;
478 bool is_kernel_mmap;
479
480 machine = perf_session__findnew_machine(session, event->mmap.pid);
481 if (!machine) {
482 pr_err("Can't find id %d's machine\n", event->mmap.pid);
483 goto out_problem;
484 }
485
486 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
487 if (machine__is_host(machine))
488 kernel_type = DSO_TYPE_KERNEL;
489 else
490 kernel_type = DSO_TYPE_GUEST_KERNEL;
491
492 is_kernel_mmap = memcmp(event->mmap.filename,
493 kmmap_prefix,
494 strlen(kmmap_prefix)) == 0;
495 if (event->mmap.filename[0] == '/' ||
496 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
497
498 char short_module_name[1024];
499 char *name, *dot;
500
501 if (event->mmap.filename[0] == '/') {
502 name = strrchr(event->mmap.filename, '/');
503 if (name == NULL)
504 goto out_problem;
505
506 ++name; /* skip / */
507 dot = strrchr(name, '.');
508 if (dot == NULL)
509 goto out_problem;
510 snprintf(short_module_name, sizeof(short_module_name),
511 "[%.*s]", (int)(dot - name), name);
512 strxfrchar(short_module_name, '-', '_');
513 } else
514 strcpy(short_module_name, event->mmap.filename);
515
516 map = machine__new_module(machine, event->mmap.start,
517 event->mmap.filename);
518 if (map == NULL)
519 goto out_problem;
520
521 name = strdup(short_module_name);
522 if (name == NULL)
523 goto out_problem;
524
525 map->dso->short_name = name;
526 map->dso->sname_alloc = 1;
527 map->end = map->start + event->mmap.len;
528 } else if (is_kernel_mmap) {
529 const char *symbol_name = (event->mmap.filename +
530 strlen(kmmap_prefix));
531 /*
532 * Should be there already, from the build-id table in
533 * the header.
534 */
535 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
536 kmmap_prefix);
537 if (kernel == NULL)
538 goto out_problem;
539
540 kernel->kernel = kernel_type;
541 if (__machine__create_kernel_maps(machine, kernel) < 0)
542 goto out_problem;
543
544 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
545
546 /*
547 * Avoid using a zero address (kptr_restrict) for the ref reloc
548 * symbol. Effectively having zero here means that at record
549 * time /proc/sys/kernel/kptr_restrict was non zero.
550 */
551 if (event->mmap.pgoff != 0) {
552 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
553 symbol_name,
554 event->mmap.pgoff);
555 }
556
557 if (machine__is_default_guest(machine)) {
558 /*
559 * preload dso of guest kernel and modules
560 */
561 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
562 NULL);
563 }
564 }
565 return 0;
566out_problem:
567 return -1;
541} 568}
542 569
543int perf_event__process_fork(struct perf_tool *tool __maybe_unused, 570int perf_event__process_mmap(union perf_event *event,
544 union perf_event *event, 571 struct perf_sample *sample __used,
545 struct perf_sample *sample __maybe_unused, 572 struct perf_session *session)
546 struct machine *machine)
547{ 573{
548 return machine__process_fork_event(machine, event); 574 struct machine *machine;
575 struct thread *thread;
576 struct map *map;
577 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
578 int ret = 0;
579
580 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
581 event->mmap.pid, event->mmap.tid, event->mmap.start,
582 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
583
584 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
585 cpumode == PERF_RECORD_MISC_KERNEL) {
586 ret = perf_event__process_kernel_mmap(event, session);
587 if (ret < 0)
588 goto out_problem;
589 return 0;
590 }
591
592 machine = perf_session__find_host_machine(session);
593 if (machine == NULL)
594 goto out_problem;
595 thread = perf_session__findnew(session, event->mmap.pid);
596 if (thread == NULL)
597 goto out_problem;
598 map = map__new(&machine->user_dsos, event->mmap.start,
599 event->mmap.len, event->mmap.pgoff,
600 event->mmap.pid, event->mmap.filename,
601 MAP__FUNCTION);
602 if (map == NULL)
603 goto out_problem;
604
605 thread__insert_map(thread, map);
606 return 0;
607
608out_problem:
609 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
610 return 0;
549} 611}
550 612
551int perf_event__process_exit(struct perf_tool *tool __maybe_unused, 613int perf_event__process_task(union perf_event *event,
552 union perf_event *event, 614 struct perf_sample *sample __used,
553 struct perf_sample *sample __maybe_unused, 615 struct perf_session *session)
554 struct machine *machine)
555{ 616{
556 return machine__process_exit_event(machine, event); 617 struct thread *thread = perf_session__findnew(session, event->fork.tid);
618 struct thread *parent = perf_session__findnew(session, event->fork.ptid);
619
620 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
621 event->fork.ppid, event->fork.ptid);
622
623 if (event->header.type == PERF_RECORD_EXIT) {
624 perf_session__remove_thread(session, thread);
625 return 0;
626 }
627
628 if (thread == NULL || parent == NULL ||
629 thread__fork(thread, parent) < 0) {
630 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
631 return -1;
632 }
633
634 return 0;
557} 635}
558 636
559size_t perf_event__fprintf(union perf_event *event, FILE *fp) 637int perf_event__process(union perf_event *event, struct perf_sample *sample,
638 struct perf_session *session)
560{ 639{
561 size_t ret = fprintf(fp, "PERF_RECORD_%s",
562 perf_event__name(event->header.type));
563
564 switch (event->header.type) { 640 switch (event->header.type) {
565 case PERF_RECORD_COMM: 641 case PERF_RECORD_COMM:
566 ret += perf_event__fprintf_comm(event, fp); 642 perf_event__process_comm(event, sample, session);
643 break;
644 case PERF_RECORD_MMAP:
645 perf_event__process_mmap(event, sample, session);
567 break; 646 break;
568 case PERF_RECORD_FORK: 647 case PERF_RECORD_FORK:
569 case PERF_RECORD_EXIT: 648 case PERF_RECORD_EXIT:
570 ret += perf_event__fprintf_task(event, fp); 649 perf_event__process_task(event, sample, session);
571 break;
572 case PERF_RECORD_MMAP:
573 ret += perf_event__fprintf_mmap(event, fp);
574 break; 650 break;
651 case PERF_RECORD_LOST:
652 perf_event__process_lost(event, sample, session);
575 default: 653 default:
576 ret += fprintf(fp, "\n"); 654 break;
577 } 655 }
578 656
579 return ret; 657 return 0;
580}
581
582int perf_event__process(struct perf_tool *tool __maybe_unused,
583 union perf_event *event,
584 struct perf_sample *sample __maybe_unused,
585 struct machine *machine)
586{
587 return machine__process_event(machine, event);
588} 658}
589 659
590void thread__find_addr_map(struct thread *self, 660void thread__find_addr_map(struct thread *self,
591 struct machine *machine, u8 cpumode, 661 struct perf_session *session, u8 cpumode,
592 enum map_type type, u64 addr, 662 enum map_type type, pid_t pid, u64 addr,
593 struct addr_location *al) 663 struct addr_location *al)
594{ 664{
595 struct map_groups *mg = &self->mg; 665 struct map_groups *mg = &self->mg;
666 struct machine *machine = NULL;
596 667
597 al->thread = self; 668 al->thread = self;
598 al->addr = addr; 669 al->addr = addr;
599 al->cpumode = cpumode; 670 al->cpumode = cpumode;
600 al->filtered = false; 671 al->filtered = false;
601 672
602 if (machine == NULL) {
603 al->map = NULL;
604 return;
605 }
606
607 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 673 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
608 al->level = 'k'; 674 al->level = 'k';
675 machine = perf_session__find_host_machine(session);
676 if (machine == NULL) {
677 al->map = NULL;
678 return;
679 }
609 mg = &machine->kmaps; 680 mg = &machine->kmaps;
610 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 681 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
611 al->level = '.'; 682 al->level = '.';
683 machine = perf_session__find_host_machine(session);
612 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 684 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
613 al->level = 'g'; 685 al->level = 'g';
686 machine = perf_session__find_machine(session, pid);
687 if (machine == NULL) {
688 al->map = NULL;
689 return;
690 }
614 mg = &machine->kmaps; 691 mg = &machine->kmaps;
615 } else { 692 } else {
616 /* 693 /*
@@ -656,12 +733,13 @@ try_again:
656 al->addr = al->map->map_ip(al->map, al->addr); 733 al->addr = al->map->map_ip(al->map, al->addr);
657} 734}
658 735
659void thread__find_addr_location(struct thread *thread, struct machine *machine, 736void thread__find_addr_location(struct thread *self,
660 u8 cpumode, enum map_type type, u64 addr, 737 struct perf_session *session, u8 cpumode,
738 enum map_type type, pid_t pid, u64 addr,
661 struct addr_location *al, 739 struct addr_location *al,
662 symbol_filter_t filter) 740 symbol_filter_t filter)
663{ 741{
664 thread__find_addr_map(thread, machine, cpumode, type, addr, al); 742 thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
665 if (al->map != NULL) 743 if (al->map != NULL)
666 al->sym = map__find_symbol(al->map, al->addr, filter); 744 al->sym = map__find_symbol(al->map, al->addr, filter);
667 else 745 else
@@ -669,13 +747,13 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine,
669} 747}
670 748
671int perf_event__preprocess_sample(const union perf_event *event, 749int perf_event__preprocess_sample(const union perf_event *event,
672 struct machine *machine, 750 struct perf_session *session,
673 struct addr_location *al, 751 struct addr_location *al,
674 struct perf_sample *sample, 752 struct perf_sample *sample,
675 symbol_filter_t filter) 753 symbol_filter_t filter)
676{ 754{
677 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 755 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
678 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 756 struct thread *thread = perf_session__findnew(session, event->ip.pid);
679 757
680 if (thread == NULL) 758 if (thread == NULL)
681 return -1; 759 return -1;
@@ -686,18 +764,18 @@ int perf_event__preprocess_sample(const union perf_event *event,
686 764
687 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 765 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
688 /* 766 /*
689 * Have we already created the kernel maps for this machine? 767 * Have we already created the kernel maps for the host machine?
690 * 768 *
691 * This should have happened earlier, when we processed the kernel MMAP 769 * This should have happened earlier, when we processed the kernel MMAP
692 * events, but for older perf.data files there was no such thing, so do 770 * events, but for older perf.data files there was no such thing, so do
693 * it now. 771 * it now.
694 */ 772 */
695 if (cpumode == PERF_RECORD_MISC_KERNEL && 773 if (cpumode == PERF_RECORD_MISC_KERNEL &&
696 machine->vmlinux_maps[MAP__FUNCTION] == NULL) 774 session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL)
697 machine__create_kernel_maps(machine); 775 machine__create_kernel_maps(&session->host_machine);
698 776
699 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 777 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
700 event->ip.ip, al); 778 event->ip.pid, event->ip.ip, al);
701 dump_printf(" ...... dso: %s\n", 779 dump_printf(" ...... dso: %s\n",
702 al->map ? al->map->dso->long_name : 780 al->map ? al->map->dso->long_name :
703 al->level == 'H' ? "[hypervisor]" : "<not found>"); 781 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -705,22 +783,20 @@ int perf_event__preprocess_sample(const union perf_event *event,
705 al->cpu = sample->cpu; 783 al->cpu = sample->cpu;
706 784
707 if (al->map) { 785 if (al->map) {
708 struct dso *dso = al->map->dso;
709
710 if (symbol_conf.dso_list && 786 if (symbol_conf.dso_list &&
711 (!dso || !(strlist__has_entry(symbol_conf.dso_list, 787 (!al->map || !al->map->dso ||
712 dso->short_name) || 788 !(strlist__has_entry(symbol_conf.dso_list,
713 (dso->short_name != dso->long_name && 789 al->map->dso->short_name) ||
714 strlist__has_entry(symbol_conf.dso_list, 790 (al->map->dso->short_name != al->map->dso->long_name &&
715 dso->long_name))))) 791 strlist__has_entry(symbol_conf.dso_list,
792 al->map->dso->long_name)))))
716 goto out_filtered; 793 goto out_filtered;
717 794
718 al->sym = map__find_symbol(al->map, al->addr, filter); 795 al->sym = map__find_symbol(al->map, al->addr, filter);
719 } 796 }
720 797
721 if (symbol_conf.sym_list && 798 if (symbol_conf.sym_list && al->sym &&
722 (!al->sym || !strlist__has_entry(symbol_conf.sym_list, 799 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
723 al->sym->name)))
724 goto out_filtered; 800 goto out_filtered;
725 801
726 return 0; 802 return 0;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 0d573ff4771..357a85b8524 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -2,11 +2,9 @@
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h> 4#include <limits.h>
5#include <stdio.h>
6 5
7#include "../perf.h" 6#include "../perf.h"
8#include "map.h" 7#include "map.h"
9#include "build-id.h"
10 8
11/* 9/*
12 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -70,16 +68,6 @@ struct sample_event {
70 u64 array[]; 68 u64 array[];
71}; 69};
72 70
73struct regs_dump {
74 u64 *regs;
75};
76
77struct stack_dump {
78 u16 offset;
79 u64 size;
80 char *data;
81};
82
83struct perf_sample { 71struct perf_sample {
84 u64 ip; 72 u64 ip;
85 u32 pid, tid; 73 u32 pid, tid;
@@ -92,15 +80,14 @@ struct perf_sample {
92 u32 raw_size; 80 u32 raw_size;
93 void *raw_data; 81 void *raw_data;
94 struct ip_callchain *callchain; 82 struct ip_callchain *callchain;
95 struct branch_stack *branch_stack;
96 struct regs_dump user_regs;
97 struct stack_dump user_stack;
98}; 83};
99 84
85#define BUILD_ID_SIZE 20
86
100struct build_id_event { 87struct build_id_event {
101 struct perf_event_header header; 88 struct perf_event_header header;
102 pid_t pid; 89 pid_t pid;
103 u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; 90 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
104 char filename[]; 91 char filename[];
105}; 92};
106 93
@@ -154,71 +141,51 @@ union perf_event {
154 141
155void perf_event__print_totals(void); 142void perf_event__print_totals(void);
156 143
157struct perf_tool; 144struct perf_session;
158struct thread_map; 145struct thread_map;
159 146
160typedef int (*perf_event__handler_t)(struct perf_tool *tool, 147typedef int (*perf_event__handler_synth_t)(union perf_event *event,
161 union perf_event *event, 148 struct perf_session *session);
149typedef int (*perf_event__handler_t)(union perf_event *event,
162 struct perf_sample *sample, 150 struct perf_sample *sample,
163 struct machine *machine); 151 struct perf_session *session);
164 152
165int perf_event__synthesize_thread_map(struct perf_tool *tool, 153int perf_event__synthesize_thread_map(struct thread_map *threads,
166 struct thread_map *threads,
167 perf_event__handler_t process, 154 perf_event__handler_t process,
168 struct machine *machine); 155 struct perf_session *session);
169int perf_event__synthesize_threads(struct perf_tool *tool, 156int perf_event__synthesize_threads(perf_event__handler_t process,
170 perf_event__handler_t process, 157 struct perf_session *session);
171 struct machine *machine); 158int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
172int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 159 struct perf_session *session,
173 perf_event__handler_t process,
174 struct machine *machine, 160 struct machine *machine,
175 const char *symbol_name); 161 const char *symbol_name);
176 162
177int perf_event__synthesize_modules(struct perf_tool *tool, 163int perf_event__synthesize_modules(perf_event__handler_t process,
178 perf_event__handler_t process, 164 struct perf_session *session,
179 struct machine *machine); 165 struct machine *machine);
180 166
181int perf_event__process_comm(struct perf_tool *tool, 167int perf_event__process_comm(union perf_event *event, struct perf_sample *sample,
182 union perf_event *event, 168 struct perf_session *session);
183 struct perf_sample *sample, 169int perf_event__process_lost(union perf_event *event, struct perf_sample *sample,
184 struct machine *machine); 170 struct perf_session *session);
185int perf_event__process_lost(struct perf_tool *tool, 171int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample,
186 union perf_event *event, 172 struct perf_session *session);
187 struct perf_sample *sample, 173int perf_event__process_task(union perf_event *event, struct perf_sample *sample,
188 struct machine *machine); 174 struct perf_session *session);
189int perf_event__process_mmap(struct perf_tool *tool, 175int perf_event__process(union perf_event *event, struct perf_sample *sample,
190 union perf_event *event, 176 struct perf_session *session);
191 struct perf_sample *sample,
192 struct machine *machine);
193int perf_event__process_fork(struct perf_tool *tool,
194 union perf_event *event,
195 struct perf_sample *sample,
196 struct machine *machine);
197int perf_event__process_exit(struct perf_tool *tool,
198 union perf_event *event,
199 struct perf_sample *sample,
200 struct machine *machine);
201int perf_event__process(struct perf_tool *tool,
202 union perf_event *event,
203 struct perf_sample *sample,
204 struct machine *machine);
205 177
206struct addr_location; 178struct addr_location;
207int perf_event__preprocess_sample(const union perf_event *self, 179int perf_event__preprocess_sample(const union perf_event *self,
208 struct machine *machine, 180 struct perf_session *session,
209 struct addr_location *al, 181 struct addr_location *al,
210 struct perf_sample *sample, 182 struct perf_sample *sample,
211 symbol_filter_t filter); 183 symbol_filter_t filter);
212 184
213const char *perf_event__name(unsigned int id); 185const char *perf_event__name(unsigned int id);
214 186
215int perf_event__synthesize_sample(union perf_event *event, u64 type, 187int perf_event__parse_sample(const union perf_event *event, u64 type,
216 const struct perf_sample *sample, 188 int sample_size, bool sample_id_all,
217 bool swapped); 189 struct perf_sample *sample, bool swapped);
218
219size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
220size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
221size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
222size_t perf_event__fprintf(union perf_event *event, FILE *fp);
223 190
224#endif /* __PERF_RECORD_H */ 191#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 705293489e3..72e9f4886b6 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -6,17 +6,12 @@
6 * 6 *
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#include "util.h"
10#include "debugfs.h"
11#include <poll.h> 9#include <poll.h>
12#include "cpumap.h" 10#include "cpumap.h"
13#include "thread_map.h" 11#include "thread_map.h"
14#include "target.h"
15#include "evlist.h" 12#include "evlist.h"
16#include "evsel.h" 13#include "evsel.h"
17#include <unistd.h> 14#include "util.h"
18
19#include "parse-events.h"
20 15
21#include <sys/mman.h> 16#include <sys/mman.h>
22 17
@@ -35,7 +30,6 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
35 INIT_HLIST_HEAD(&evlist->heads[i]); 30 INIT_HLIST_HEAD(&evlist->heads[i]);
36 INIT_LIST_HEAD(&evlist->entries); 31 INIT_LIST_HEAD(&evlist->entries);
37 perf_evlist__set_maps(evlist, cpus, threads); 32 perf_evlist__set_maps(evlist, cpus, threads);
38 evlist->workload.pid = -1;
39} 33}
40 34
41struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 35struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -49,22 +43,6 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
49 return evlist; 43 return evlist;
50} 44}
51 45
52void perf_evlist__config_attrs(struct perf_evlist *evlist,
53 struct perf_record_opts *opts)
54{
55 struct perf_evsel *evsel;
56
57 if (evlist->cpus->map[0] < 0)
58 opts->no_inherit = true;
59
60 list_for_each_entry(evsel, &evlist->entries, node) {
61 perf_evsel__config(evsel, opts);
62
63 if (evlist->nr_entries > 1)
64 evsel->attr.sample_type |= PERF_SAMPLE_ID;
65 }
66}
67
68static void perf_evlist__purge(struct perf_evlist *evlist) 46static void perf_evlist__purge(struct perf_evlist *evlist)
69{ 47{
70 struct perf_evsel *pos, *n; 48 struct perf_evsel *pos, *n;
@@ -98,44 +76,14 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
98 ++evlist->nr_entries; 76 ++evlist->nr_entries;
99} 77}
100 78
101void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
102 struct list_head *list,
103 int nr_entries)
104{
105 list_splice_tail(list, &evlist->entries);
106 evlist->nr_entries += nr_entries;
107}
108
109void __perf_evlist__set_leader(struct list_head *list)
110{
111 struct perf_evsel *evsel, *leader;
112
113 leader = list_entry(list->next, struct perf_evsel, node);
114 leader->leader = NULL;
115
116 list_for_each_entry(evsel, list, node) {
117 if (evsel != leader)
118 evsel->leader = leader;
119 }
120}
121
122void perf_evlist__set_leader(struct perf_evlist *evlist)
123{
124 if (evlist->nr_entries)
125 __perf_evlist__set_leader(&evlist->entries);
126}
127
128int perf_evlist__add_default(struct perf_evlist *evlist) 79int perf_evlist__add_default(struct perf_evlist *evlist)
129{ 80{
130 struct perf_event_attr attr = { 81 struct perf_event_attr attr = {
131 .type = PERF_TYPE_HARDWARE, 82 .type = PERF_TYPE_HARDWARE,
132 .config = PERF_COUNT_HW_CPU_CYCLES, 83 .config = PERF_COUNT_HW_CPU_CYCLES,
133 }; 84 };
134 struct perf_evsel *evsel; 85 struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
135 86
136 event_attr_init(&attr);
137
138 evsel = perf_evsel__new(&attr, 0);
139 if (evsel == NULL) 87 if (evsel == NULL)
140 goto error; 88 goto error;
141 89
@@ -152,69 +100,6 @@ error:
152 return -ENOMEM; 100 return -ENOMEM;
153} 101}
154 102
155static int perf_evlist__add_attrs(struct perf_evlist *evlist,
156 struct perf_event_attr *attrs, size_t nr_attrs)
157{
158 struct perf_evsel *evsel, *n;
159 LIST_HEAD(head);
160 size_t i;
161
162 for (i = 0; i < nr_attrs; i++) {
163 evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i);
164 if (evsel == NULL)
165 goto out_delete_partial_list;
166 list_add_tail(&evsel->node, &head);
167 }
168
169 perf_evlist__splice_list_tail(evlist, &head, nr_attrs);
170
171 return 0;
172
173out_delete_partial_list:
174 list_for_each_entry_safe(evsel, n, &head, node)
175 perf_evsel__delete(evsel);
176 return -1;
177}
178
179int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
180 struct perf_event_attr *attrs, size_t nr_attrs)
181{
182 size_t i;
183
184 for (i = 0; i < nr_attrs; i++)
185 event_attr_init(attrs + i);
186
187 return perf_evlist__add_attrs(evlist, attrs, nr_attrs);
188}
189
190struct perf_evsel *
191perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
192{
193 struct perf_evsel *evsel;
194
195 list_for_each_entry(evsel, &evlist->entries, node) {
196 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
197 (int)evsel->attr.config == id)
198 return evsel;
199 }
200
201 return NULL;
202}
203
204int perf_evlist__add_newtp(struct perf_evlist *evlist,
205 const char *sys, const char *name, void *handler)
206{
207 struct perf_evsel *evsel;
208
209 evsel = perf_evsel__newtp(sys, name, evlist->nr_entries);
210 if (evsel == NULL)
211 return -1;
212
213 evsel->handler.func = handler;
214 perf_evlist__add(evlist, evsel);
215 return 0;
216}
217
218void perf_evlist__disable(struct perf_evlist *evlist) 103void perf_evlist__disable(struct perf_evlist *evlist)
219{ 104{
220 int cpu, thread; 105 int cpu, thread;
@@ -222,11 +107,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)
222 107
223 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 108 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
224 list_for_each_entry(pos, &evlist->entries, node) { 109 list_for_each_entry(pos, &evlist->entries, node) {
225 if (perf_evsel__is_group_member(pos))
226 continue;
227 for (thread = 0; thread < evlist->threads->nr; thread++) 110 for (thread = 0; thread < evlist->threads->nr; thread++)
228 ioctl(FD(pos, cpu, thread), 111 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE);
229 PERF_EVENT_IOC_DISABLE, 0);
230 } 112 }
231 } 113 }
232} 114}
@@ -236,20 +118,17 @@ void perf_evlist__enable(struct perf_evlist *evlist)
236 int cpu, thread; 118 int cpu, thread;
237 struct perf_evsel *pos; 119 struct perf_evsel *pos;
238 120
239 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 121 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
240 list_for_each_entry(pos, &evlist->entries, node) { 122 list_for_each_entry(pos, &evlist->entries, node) {
241 if (perf_evsel__is_group_member(pos))
242 continue;
243 for (thread = 0; thread < evlist->threads->nr; thread++) 123 for (thread = 0; thread < evlist->threads->nr; thread++)
244 ioctl(FD(pos, cpu, thread), 124 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE);
245 PERF_EVENT_IOC_ENABLE, 0);
246 } 125 }
247 } 126 }
248} 127}
249 128
250static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 129int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
251{ 130{
252 int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries; 131 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
253 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 132 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
254 return evlist->pollfd != NULL ? 0 : -ENOMEM; 133 return evlist->pollfd != NULL ? 0 : -ENOMEM;
255} 134}
@@ -310,7 +189,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
310 int hash; 189 int hash;
311 190
312 if (evlist->nr_entries == 1) 191 if (evlist->nr_entries == 1)
313 return perf_evlist__first(evlist); 192 return list_entry(evlist->entries.next, struct perf_evsel, node);
314 193
315 hash = hash_64(id, PERF_EVLIST__HLIST_BITS); 194 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
316 head = &evlist->heads[hash]; 195 head = &evlist->heads[hash];
@@ -318,15 +197,13 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
318 hlist_for_each_entry(sid, pos, head, node) 197 hlist_for_each_entry(sid, pos, head, node)
319 if (sid->id == id) 198 if (sid->id == id)
320 return sid->evsel; 199 return sid->evsel;
321
322 if (!perf_evlist__sample_id_all(evlist))
323 return perf_evlist__first(evlist);
324
325 return NULL; 200 return NULL;
326} 201}
327 202
328union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 203union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
329{ 204{
205 /* XXX Move this to perf.c, making it generally available */
206 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
330 struct perf_mmap *md = &evlist->mmap[idx]; 207 struct perf_mmap *md = &evlist->mmap[idx];
331 unsigned int head = perf_mmap__read_head(md); 208 unsigned int head = perf_mmap__read_head(md);
332 unsigned int old = md->prev; 209 unsigned int old = md->prev;
@@ -405,10 +282,10 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
405 evlist->mmap = NULL; 282 evlist->mmap = NULL;
406} 283}
407 284
408static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 285int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
409{ 286{
410 evlist->nr_mmaps = cpu_map__nr(evlist->cpus); 287 evlist->nr_mmaps = evlist->cpus->nr;
411 if (cpu_map__all(evlist->cpus)) 288 if (evlist->cpus->map[0] == -1)
412 evlist->nr_mmaps = evlist->threads->nr; 289 evlist->nr_mmaps = evlist->threads->nr;
413 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 290 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
414 return evlist->mmap != NULL ? 0 : -ENOMEM; 291 return evlist->mmap != NULL ? 0 : -ENOMEM;
@@ -421,10 +298,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
421 evlist->mmap[idx].mask = mask; 298 evlist->mmap[idx].mask = mask;
422 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 299 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
423 MAP_SHARED, fd, 0); 300 MAP_SHARED, fd, 0);
424 if (evlist->mmap[idx].base == MAP_FAILED) { 301 if (evlist->mmap[idx].base == MAP_FAILED)
425 evlist->mmap[idx].base = NULL;
426 return -1; 302 return -1;
427 }
428 303
429 perf_evlist__add_pollfd(evlist, fd); 304 perf_evlist__add_pollfd(evlist, fd);
430 return 0; 305 return 0;
@@ -525,21 +400,14 @@ out_unmap:
525 * 400 *
526 * Using perf_evlist__read_on_cpu does this automatically. 401 * Using perf_evlist__read_on_cpu does this automatically.
527 */ 402 */
528int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 403int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
529 bool overwrite)
530{ 404{
405 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
406 int mask = pages * page_size - 1;
531 struct perf_evsel *evsel; 407 struct perf_evsel *evsel;
532 const struct cpu_map *cpus = evlist->cpus; 408 const struct cpu_map *cpus = evlist->cpus;
533 const struct thread_map *threads = evlist->threads; 409 const struct thread_map *threads = evlist->threads;
534 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; 410 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
535
536 /* 512 kiB: default amount of unprivileged mlocked memory */
537 if (pages == UINT_MAX)
538 pages = (512 * 1024) / page_size;
539 else if (!is_power_of_2(pages))
540 return -EINVAL;
541
542 mask = pages * page_size - 1;
543 411
544 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 412 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
545 return -ENOMEM; 413 return -ENOMEM;
@@ -553,31 +421,28 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
553 list_for_each_entry(evsel, &evlist->entries, node) { 421 list_for_each_entry(evsel, &evlist->entries, node) {
554 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 422 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
555 evsel->sample_id == NULL && 423 evsel->sample_id == NULL &&
556 perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) 424 perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
557 return -ENOMEM; 425 return -ENOMEM;
558 } 426 }
559 427
560 if (cpu_map__all(cpus)) 428 if (evlist->cpus->map[0] == -1)
561 return perf_evlist__mmap_per_thread(evlist, prot, mask); 429 return perf_evlist__mmap_per_thread(evlist, prot, mask);
562 430
563 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 431 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
564} 432}
565 433
566int perf_evlist__create_maps(struct perf_evlist *evlist, 434int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
567 struct perf_target *target) 435 pid_t target_tid, const char *cpu_list)
568{ 436{
569 evlist->threads = thread_map__new_str(target->pid, target->tid, 437 evlist->threads = thread_map__new(target_pid, target_tid);
570 target->uid);
571 438
572 if (evlist->threads == NULL) 439 if (evlist->threads == NULL)
573 return -1; 440 return -1;
574 441
575 if (perf_target__has_task(target)) 442 if (cpu_list == NULL && target_tid != -1)
576 evlist->cpus = cpu_map__dummy_new();
577 else if (!perf_target__has_cpu(target) && !target->uses_mmap)
578 evlist->cpus = cpu_map__dummy_new(); 443 evlist->cpus = cpu_map__dummy_new();
579 else 444 else
580 evlist->cpus = cpu_map__new(target->cpu_list); 445 evlist->cpus = cpu_map__new(cpu_list);
581 446
582 if (evlist->cpus == NULL) 447 if (evlist->cpus == NULL)
583 goto out_delete_threads; 448 goto out_delete_threads;
@@ -597,44 +462,39 @@ void perf_evlist__delete_maps(struct perf_evlist *evlist)
597 evlist->threads = NULL; 462 evlist->threads = NULL;
598} 463}
599 464
600int perf_evlist__apply_filters(struct perf_evlist *evlist) 465int perf_evlist__set_filters(struct perf_evlist *evlist)
601{ 466{
467 const struct thread_map *threads = evlist->threads;
468 const struct cpu_map *cpus = evlist->cpus;
602 struct perf_evsel *evsel; 469 struct perf_evsel *evsel;
603 int err = 0; 470 char *filter;
604 const int ncpus = cpu_map__nr(evlist->cpus), 471 int thread;
605 nthreads = evlist->threads->nr; 472 int cpu;
473 int err;
474 int fd;
606 475
607 list_for_each_entry(evsel, &evlist->entries, node) { 476 list_for_each_entry(evsel, &evlist->entries, node) {
608 if (evsel->filter == NULL) 477 filter = evsel->filter;
478 if (!filter)
609 continue; 479 continue;
610 480 for (cpu = 0; cpu < cpus->nr; cpu++) {
611 err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter); 481 for (thread = 0; thread < threads->nr; thread++) {
612 if (err) 482 fd = FD(evsel, cpu, thread);
613 break; 483 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
484 if (err)
485 return err;
486 }
487 }
614 } 488 }
615 489
616 return err; 490 return 0;
617} 491}
618 492
619int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) 493bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist)
620{ 494{
621 struct perf_evsel *evsel; 495 struct perf_evsel *pos, *first;
622 int err = 0;
623 const int ncpus = cpu_map__nr(evlist->cpus),
624 nthreads = evlist->threads->nr;
625
626 list_for_each_entry(evsel, &evlist->entries, node) {
627 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
628 if (err)
629 break;
630 }
631 496
632 return err; 497 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
633}
634
635bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
636{
637 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
638 498
639 list_for_each_entry_continue(pos, &evlist->entries, node) { 499 list_for_each_entry_continue(pos, &evlist->entries, node) {
640 if (first->attr.sample_type != pos->attr.sample_type) 500 if (first->attr.sample_type != pos->attr.sample_type)
@@ -644,45 +504,19 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
644 return true; 504 return true;
645} 505}
646 506
647u64 perf_evlist__sample_type(struct perf_evlist *evlist) 507u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
648{ 508{
649 struct perf_evsel *first = perf_evlist__first(evlist); 509 struct perf_evsel *first;
510
511 first = list_entry(evlist->entries.next, struct perf_evsel, node);
650 return first->attr.sample_type; 512 return first->attr.sample_type;
651} 513}
652 514
653u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist) 515bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
654{ 516{
655 struct perf_evsel *first = perf_evlist__first(evlist); 517 struct perf_evsel *pos, *first;
656 struct perf_sample *data;
657 u64 sample_type;
658 u16 size = 0;
659
660 if (!first->attr.sample_id_all)
661 goto out;
662
663 sample_type = first->attr.sample_type;
664
665 if (sample_type & PERF_SAMPLE_TID)
666 size += sizeof(data->tid) * 2;
667
668 if (sample_type & PERF_SAMPLE_TIME)
669 size += sizeof(data->time);
670
671 if (sample_type & PERF_SAMPLE_ID)
672 size += sizeof(data->id);
673
674 if (sample_type & PERF_SAMPLE_STREAM_ID)
675 size += sizeof(data->stream_id);
676 518
677 if (sample_type & PERF_SAMPLE_CPU) 519 pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
678 size += sizeof(data->cpu) * 2;
679out:
680 return size;
681}
682
683bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist)
684{
685 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
686 520
687 list_for_each_entry_continue(pos, &evlist->entries, node) { 521 list_for_each_entry_continue(pos, &evlist->entries, node) {
688 if (first->attr.sample_id_all != pos->attr.sample_id_all) 522 if (first->attr.sample_id_all != pos->attr.sample_id_all)
@@ -692,151 +526,10 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist)
692 return true; 526 return true;
693} 527}
694 528
695bool perf_evlist__sample_id_all(struct perf_evlist *evlist) 529bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
696{
697 struct perf_evsel *first = perf_evlist__first(evlist);
698 return first->attr.sample_id_all;
699}
700
701void perf_evlist__set_selected(struct perf_evlist *evlist,
702 struct perf_evsel *evsel)
703{
704 evlist->selected = evsel;
705}
706
707int perf_evlist__open(struct perf_evlist *evlist)
708{ 530{
709 struct perf_evsel *evsel; 531 struct perf_evsel *first;
710 int err, ncpus, nthreads;
711
712 list_for_each_entry(evsel, &evlist->entries, node) {
713 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
714 if (err < 0)
715 goto out_err;
716 }
717
718 return 0;
719out_err:
720 ncpus = evlist->cpus ? evlist->cpus->nr : 1;
721 nthreads = evlist->threads ? evlist->threads->nr : 1;
722
723 list_for_each_entry_reverse(evsel, &evlist->entries, node)
724 perf_evsel__close(evsel, ncpus, nthreads);
725
726 errno = -err;
727 return err;
728}
729
730int perf_evlist__prepare_workload(struct perf_evlist *evlist,
731 struct perf_record_opts *opts,
732 const char *argv[])
733{
734 int child_ready_pipe[2], go_pipe[2];
735 char bf;
736
737 if (pipe(child_ready_pipe) < 0) {
738 perror("failed to create 'ready' pipe");
739 return -1;
740 }
741
742 if (pipe(go_pipe) < 0) {
743 perror("failed to create 'go' pipe");
744 goto out_close_ready_pipe;
745 }
746
747 evlist->workload.pid = fork();
748 if (evlist->workload.pid < 0) {
749 perror("failed to fork");
750 goto out_close_pipes;
751 }
752
753 if (!evlist->workload.pid) {
754 if (opts->pipe_output)
755 dup2(2, 1);
756 532
757 close(child_ready_pipe[0]); 533 first = list_entry(evlist->entries.next, struct perf_evsel, node);
758 close(go_pipe[1]); 534 return first->attr.sample_id_all;
759 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
760
761 /*
762 * Do a dummy execvp to get the PLT entry resolved,
763 * so we avoid the resolver overhead on the real
764 * execvp call.
765 */
766 execvp("", (char **)argv);
767
768 /*
769 * Tell the parent we're ready to go
770 */
771 close(child_ready_pipe[1]);
772
773 /*
774 * Wait until the parent tells us to go.
775 */
776 if (read(go_pipe[0], &bf, 1) == -1)
777 perror("unable to read pipe");
778
779 execvp(argv[0], (char **)argv);
780
781 perror(argv[0]);
782 kill(getppid(), SIGUSR1);
783 exit(-1);
784 }
785
786 if (perf_target__none(&opts->target))
787 evlist->threads->map[0] = evlist->workload.pid;
788
789 close(child_ready_pipe[1]);
790 close(go_pipe[0]);
791 /*
792 * wait for child to settle
793 */
794 if (read(child_ready_pipe[0], &bf, 1) == -1) {
795 perror("unable to read pipe");
796 goto out_close_pipes;
797 }
798
799 evlist->workload.cork_fd = go_pipe[1];
800 close(child_ready_pipe[0]);
801 return 0;
802
803out_close_pipes:
804 close(go_pipe[0]);
805 close(go_pipe[1]);
806out_close_ready_pipe:
807 close(child_ready_pipe[0]);
808 close(child_ready_pipe[1]);
809 return -1;
810}
811
812int perf_evlist__start_workload(struct perf_evlist *evlist)
813{
814 if (evlist->workload.cork_fd > 0) {
815 /*
816 * Remove the cork, let it rip!
817 */
818 return close(evlist->workload.cork_fd);
819 }
820
821 return 0;
822}
823
824int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
825 struct perf_sample *sample)
826{
827 struct perf_evsel *evsel = perf_evlist__first(evlist);
828 return perf_evsel__parse_sample(evsel, event, sample);
829}
830
831size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
832{
833 struct perf_evsel *evsel;
834 size_t printed = 0;
835
836 list_for_each_entry(evsel, &evlist->entries, node) {
837 printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "",
838 perf_evsel__name(evsel));
839 }
840
841 return printed + fprintf(fp, "\n");;
842} 535}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 56003f779e6..f3491500274 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -2,17 +2,12 @@
2#define __PERF_EVLIST_H 1 2#define __PERF_EVLIST_H 1
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include <stdio.h>
6#include "../perf.h" 5#include "../perf.h"
7#include "event.h" 6#include "event.h"
8#include "evsel.h"
9#include "util.h"
10#include <unistd.h>
11 7
12struct pollfd; 8struct pollfd;
13struct thread_map; 9struct thread_map;
14struct cpu_map; 10struct cpu_map;
15struct perf_record_opts;
16 11
17#define PERF_EVLIST__HLIST_BITS 8 12#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 13#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
@@ -24,23 +19,15 @@ struct perf_evlist {
24 int nr_fds; 19 int nr_fds;
25 int nr_mmaps; 20 int nr_mmaps;
26 int mmap_len; 21 int mmap_len;
27 struct {
28 int cork_fd;
29 pid_t pid;
30 } workload;
31 bool overwrite; 22 bool overwrite;
32 union perf_event event_copy; 23 union perf_event event_copy;
33 struct perf_mmap *mmap; 24 struct perf_mmap *mmap;
34 struct pollfd *pollfd; 25 struct pollfd *pollfd;
35 struct thread_map *threads; 26 struct thread_map *threads;
36 struct cpu_map *cpus; 27 struct cpu_map *cpus;
37 struct perf_evsel *selected;
38}; 28};
39 29
40struct perf_evsel_str_handler { 30struct perf_evsel;
41 const char *name;
42 void *handler;
43};
44 31
45struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 32struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
46 struct thread_map *threads); 33 struct thread_map *threads);
@@ -51,49 +38,24 @@ void perf_evlist__delete(struct perf_evlist *evlist);
51 38
52void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); 39void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
53int perf_evlist__add_default(struct perf_evlist *evlist); 40int perf_evlist__add_default(struct perf_evlist *evlist);
54int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
55 struct perf_event_attr *attrs, size_t nr_attrs);
56
57#define perf_evlist__add_default_attrs(evlist, array) \
58 __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
59
60int perf_evlist__add_newtp(struct perf_evlist *evlist,
61 const char *sys, const char *name, void *handler);
62
63int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
64
65struct perf_evsel *
66perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
67 41
68void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 42void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
69 int cpu, int thread, u64 id); 43 int cpu, int thread, u64 id);
70 44
45int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
71void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); 46void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
72 47
73struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); 48struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
74 49
75union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 50union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
76 51
77int perf_evlist__open(struct perf_evlist *evlist); 52int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
78 53int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
79void perf_evlist__config_attrs(struct perf_evlist *evlist,
80 struct perf_record_opts *opts);
81
82int perf_evlist__prepare_workload(struct perf_evlist *evlist,
83 struct perf_record_opts *opts,
84 const char *argv[]);
85int perf_evlist__start_workload(struct perf_evlist *evlist);
86
87int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
88 bool overwrite);
89void perf_evlist__munmap(struct perf_evlist *evlist); 54void perf_evlist__munmap(struct perf_evlist *evlist);
90 55
91void perf_evlist__disable(struct perf_evlist *evlist); 56void perf_evlist__disable(struct perf_evlist *evlist);
92void perf_evlist__enable(struct perf_evlist *evlist); 57void perf_evlist__enable(struct perf_evlist *evlist);
93 58
94void perf_evlist__set_selected(struct perf_evlist *evlist,
95 struct perf_evsel *evsel);
96
97static inline void perf_evlist__set_maps(struct perf_evlist *evlist, 59static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
98 struct cpu_map *cpus, 60 struct cpu_map *cpus,
99 struct thread_map *threads) 61 struct thread_map *threads)
@@ -102,37 +64,14 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
102 evlist->threads = threads; 64 evlist->threads = threads;
103} 65}
104 66
105int perf_evlist__create_maps(struct perf_evlist *evlist, 67int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
106 struct perf_target *target); 68 pid_t target_tid, const char *cpu_list);
107void perf_evlist__delete_maps(struct perf_evlist *evlist); 69void perf_evlist__delete_maps(struct perf_evlist *evlist);
108int perf_evlist__apply_filters(struct perf_evlist *evlist); 70int perf_evlist__set_filters(struct perf_evlist *evlist);
109
110void __perf_evlist__set_leader(struct list_head *list);
111void perf_evlist__set_leader(struct perf_evlist *evlist);
112 71
113u64 perf_evlist__sample_type(struct perf_evlist *evlist); 72u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
114bool perf_evlist__sample_id_all(struct perf_evlist *evlist); 73bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
115u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
116
117int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
118 struct perf_sample *sample);
119
120bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
121bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
122
123void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
124 struct list_head *list,
125 int nr_entries);
126
127static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist)
128{
129 return list_entry(evlist->entries.next, struct perf_evsel, node);
130}
131
132static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
133{
134 return list_entry(evlist->entries.prev, struct perf_evsel, node);
135}
136 74
137size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 75bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
76bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
138#endif /* __PERF_EVLIST_H */ 77#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1b16dd1edc8..e389815078d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -8,23 +8,16 @@
8 */ 8 */
9 9
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h>
12#include "asm/bug.h" 11#include "asm/bug.h"
13#include "debugfs.h"
14#include "event-parse.h"
15#include "evsel.h" 12#include "evsel.h"
16#include "evlist.h" 13#include "evlist.h"
17#include "util.h" 14#include "util.h"
18#include "cpumap.h" 15#include "cpumap.h"
19#include "thread_map.h" 16#include "thread_map.h"
20#include "target.h"
21#include <linux/hw_breakpoint.h>
22#include <linux/perf_event.h>
23#include "perf_regs.h"
24 17
25#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 18#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
26 19
27static int __perf_evsel__sample_size(u64 sample_type) 20int __perf_evsel__sample_size(u64 sample_type)
28{ 21{
29 u64 mask = sample_type & PERF_SAMPLE_MASK; 22 u64 mask = sample_type & PERF_SAMPLE_MASK;
30 int size = 0; 23 int size = 0;
@@ -40,24 +33,12 @@ static int __perf_evsel__sample_size(u64 sample_type)
40 return size; 33 return size;
41} 34}
42 35
43void hists__init(struct hists *hists)
44{
45 memset(hists, 0, sizeof(*hists));
46 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
47 hists->entries_in = &hists->entries_in_array[0];
48 hists->entries_collapsed = RB_ROOT;
49 hists->entries = RB_ROOT;
50 pthread_mutex_init(&hists->lock, NULL);
51}
52
53void perf_evsel__init(struct perf_evsel *evsel, 36void perf_evsel__init(struct perf_evsel *evsel,
54 struct perf_event_attr *attr, int idx) 37 struct perf_event_attr *attr, int idx)
55{ 38{
56 evsel->idx = idx; 39 evsel->idx = idx;
57 evsel->attr = *attr; 40 evsel->attr = *attr;
58 INIT_LIST_HEAD(&evsel->node); 41 INIT_LIST_HEAD(&evsel->node);
59 hists__init(&evsel->hists);
60 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
61} 42}
62 43
63struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 44struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -70,466 +51,6 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
70 return evsel; 51 return evsel;
71} 52}
72 53
73struct event_format *event_format__new(const char *sys, const char *name)
74{
75 int fd, n;
76 char *filename;
77 void *bf = NULL, *nbf;
78 size_t size = 0, alloc_size = 0;
79 struct event_format *format = NULL;
80
81 if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0)
82 goto out;
83
84 fd = open(filename, O_RDONLY);
85 if (fd < 0)
86 goto out_free_filename;
87
88 do {
89 if (size == alloc_size) {
90 alloc_size += BUFSIZ;
91 nbf = realloc(bf, alloc_size);
92 if (nbf == NULL)
93 goto out_free_bf;
94 bf = nbf;
95 }
96
97 n = read(fd, bf + size, BUFSIZ);
98 if (n < 0)
99 goto out_free_bf;
100 size += n;
101 } while (n > 0);
102
103 pevent_parse_format(&format, bf, size, sys);
104
105out_free_bf:
106 free(bf);
107 close(fd);
108out_free_filename:
109 free(filename);
110out:
111 return format;
112}
113
114struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx)
115{
116 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
117
118 if (evsel != NULL) {
119 struct perf_event_attr attr = {
120 .type = PERF_TYPE_TRACEPOINT,
121 .sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
122 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD),
123 };
124
125 if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
126 goto out_free;
127
128 evsel->tp_format = event_format__new(sys, name);
129 if (evsel->tp_format == NULL)
130 goto out_free;
131
132 event_attr_init(&attr);
133 attr.config = evsel->tp_format->id;
134 attr.sample_period = 1;
135 perf_evsel__init(evsel, &attr, idx);
136 }
137
138 return evsel;
139
140out_free:
141 free(evsel->name);
142 free(evsel);
143 return NULL;
144}
145
146const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
147 "cycles",
148 "instructions",
149 "cache-references",
150 "cache-misses",
151 "branches",
152 "branch-misses",
153 "bus-cycles",
154 "stalled-cycles-frontend",
155 "stalled-cycles-backend",
156 "ref-cycles",
157};
158
159static const char *__perf_evsel__hw_name(u64 config)
160{
161 if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
162 return perf_evsel__hw_names[config];
163
164 return "unknown-hardware";
165}
166
167static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size)
168{
169 int colon = 0, r = 0;
170 struct perf_event_attr *attr = &evsel->attr;
171 bool exclude_guest_default = false;
172
173#define MOD_PRINT(context, mod) do { \
174 if (!attr->exclude_##context) { \
175 if (!colon) colon = ++r; \
176 r += scnprintf(bf + r, size - r, "%c", mod); \
177 } } while(0)
178
179 if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) {
180 MOD_PRINT(kernel, 'k');
181 MOD_PRINT(user, 'u');
182 MOD_PRINT(hv, 'h');
183 exclude_guest_default = true;
184 }
185
186 if (attr->precise_ip) {
187 if (!colon)
188 colon = ++r;
189 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
190 exclude_guest_default = true;
191 }
192
193 if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) {
194 MOD_PRINT(host, 'H');
195 MOD_PRINT(guest, 'G');
196 }
197#undef MOD_PRINT
198 if (colon)
199 bf[colon - 1] = ':';
200 return r;
201}
202
203static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
204{
205 int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config));
206 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
207}
208
209const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
210 "cpu-clock",
211 "task-clock",
212 "page-faults",
213 "context-switches",
214 "cpu-migrations",
215 "minor-faults",
216 "major-faults",
217 "alignment-faults",
218 "emulation-faults",
219};
220
221static const char *__perf_evsel__sw_name(u64 config)
222{
223 if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
224 return perf_evsel__sw_names[config];
225 return "unknown-software";
226}
227
228static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size)
229{
230 int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config));
231 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
232}
233
234static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)
235{
236 int r;
237
238 r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr);
239
240 if (type & HW_BREAKPOINT_R)
241 r += scnprintf(bf + r, size - r, "r");
242
243 if (type & HW_BREAKPOINT_W)
244 r += scnprintf(bf + r, size - r, "w");
245
246 if (type & HW_BREAKPOINT_X)
247 r += scnprintf(bf + r, size - r, "x");
248
249 return r;
250}
251
252static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size)
253{
254 struct perf_event_attr *attr = &evsel->attr;
255 int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type);
256 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
257}
258
259const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
260 [PERF_EVSEL__MAX_ALIASES] = {
261 { "L1-dcache", "l1-d", "l1d", "L1-data", },
262 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
263 { "LLC", "L2", },
264 { "dTLB", "d-tlb", "Data-TLB", },
265 { "iTLB", "i-tlb", "Instruction-TLB", },
266 { "branch", "branches", "bpu", "btb", "bpc", },
267 { "node", },
268};
269
270const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
271 [PERF_EVSEL__MAX_ALIASES] = {
272 { "load", "loads", "read", },
273 { "store", "stores", "write", },
274 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
275};
276
277const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
278 [PERF_EVSEL__MAX_ALIASES] = {
279 { "refs", "Reference", "ops", "access", },
280 { "misses", "miss", },
281};
282
283#define C(x) PERF_COUNT_HW_CACHE_##x
284#define CACHE_READ (1 << C(OP_READ))
285#define CACHE_WRITE (1 << C(OP_WRITE))
286#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
287#define COP(x) (1 << x)
288
289/*
290 * cache operartion stat
291 * L1I : Read and prefetch only
292 * ITLB and BPU : Read-only
293 */
294static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
295 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
296 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
297 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
298 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
299 [C(ITLB)] = (CACHE_READ),
300 [C(BPU)] = (CACHE_READ),
301 [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
302};
303
304bool perf_evsel__is_cache_op_valid(u8 type, u8 op)
305{
306 if (perf_evsel__hw_cache_stat[type] & COP(op))
307 return true; /* valid */
308 else
309 return false; /* invalid */
310}
311
312int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
313 char *bf, size_t size)
314{
315 if (result) {
316 return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
317 perf_evsel__hw_cache_op[op][0],
318 perf_evsel__hw_cache_result[result][0]);
319 }
320
321 return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
322 perf_evsel__hw_cache_op[op][1]);
323}
324
325static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
326{
327 u8 op, result, type = (config >> 0) & 0xff;
328 const char *err = "unknown-ext-hardware-cache-type";
329
330 if (type > PERF_COUNT_HW_CACHE_MAX)
331 goto out_err;
332
333 op = (config >> 8) & 0xff;
334 err = "unknown-ext-hardware-cache-op";
335 if (op > PERF_COUNT_HW_CACHE_OP_MAX)
336 goto out_err;
337
338 result = (config >> 16) & 0xff;
339 err = "unknown-ext-hardware-cache-result";
340 if (result > PERF_COUNT_HW_CACHE_RESULT_MAX)
341 goto out_err;
342
343 err = "invalid-cache";
344 if (!perf_evsel__is_cache_op_valid(type, op))
345 goto out_err;
346
347 return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size);
348out_err:
349 return scnprintf(bf, size, "%s", err);
350}
351
352static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size)
353{
354 int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size);
355 return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
356}
357
358static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size)
359{
360 int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
361 return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
362}
363
364const char *perf_evsel__name(struct perf_evsel *evsel)
365{
366 char bf[128];
367
368 if (evsel->name)
369 return evsel->name;
370
371 switch (evsel->attr.type) {
372 case PERF_TYPE_RAW:
373 perf_evsel__raw_name(evsel, bf, sizeof(bf));
374 break;
375
376 case PERF_TYPE_HARDWARE:
377 perf_evsel__hw_name(evsel, bf, sizeof(bf));
378 break;
379
380 case PERF_TYPE_HW_CACHE:
381 perf_evsel__hw_cache_name(evsel, bf, sizeof(bf));
382 break;
383
384 case PERF_TYPE_SOFTWARE:
385 perf_evsel__sw_name(evsel, bf, sizeof(bf));
386 break;
387
388 case PERF_TYPE_TRACEPOINT:
389 scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint");
390 break;
391
392 case PERF_TYPE_BREAKPOINT:
393 perf_evsel__bp_name(evsel, bf, sizeof(bf));
394 break;
395
396 default:
397 scnprintf(bf, sizeof(bf), "unknown attr type: %d",
398 evsel->attr.type);
399 break;
400 }
401
402 evsel->name = strdup(bf);
403
404 return evsel->name ?: "unknown";
405}
406
407/*
408 * The enable_on_exec/disabled value strategy:
409 *
410 * 1) For any type of traced program:
411 * - all independent events and group leaders are disabled
412 * - all group members are enabled
413 *
414 * Group members are ruled by group leaders. They need to
415 * be enabled, because the group scheduling relies on that.
416 *
417 * 2) For traced programs executed by perf:
418 * - all independent events and group leaders have
419 * enable_on_exec set
420 * - we don't specifically enable or disable any event during
421 * the record command
422 *
423 * Independent events and group leaders are initially disabled
424 * and get enabled by exec. Group members are ruled by group
425 * leaders as stated in 1).
426 *
427 * 3) For traced programs attached by perf (pid/tid):
428 * - we specifically enable or disable all events during
429 * the record command
430 *
431 * When attaching events to already running traced we
432 * enable/disable events specifically, as there's no
433 * initial traced exec call.
434 */
435void perf_evsel__config(struct perf_evsel *evsel,
436 struct perf_record_opts *opts)
437{
438 struct perf_event_attr *attr = &evsel->attr;
439 int track = !evsel->idx; /* only the first counter needs these */
440
441 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
442 attr->inherit = !opts->no_inherit;
443 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
444 PERF_FORMAT_TOTAL_TIME_RUNNING |
445 PERF_FORMAT_ID;
446
447 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
448
449 /*
450 * We default some events to a 1 default interval. But keep
451 * it a weak assumption overridable by the user.
452 */
453 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
454 opts->user_interval != ULLONG_MAX)) {
455 if (opts->freq) {
456 attr->sample_type |= PERF_SAMPLE_PERIOD;
457 attr->freq = 1;
458 attr->sample_freq = opts->freq;
459 } else {
460 attr->sample_period = opts->default_interval;
461 }
462 }
463
464 if (opts->no_samples)
465 attr->sample_freq = 0;
466
467 if (opts->inherit_stat)
468 attr->inherit_stat = 1;
469
470 if (opts->sample_address) {
471 attr->sample_type |= PERF_SAMPLE_ADDR;
472 attr->mmap_data = track;
473 }
474
475 if (opts->call_graph) {
476 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
477
478 if (opts->call_graph == CALLCHAIN_DWARF) {
479 attr->sample_type |= PERF_SAMPLE_REGS_USER |
480 PERF_SAMPLE_STACK_USER;
481 attr->sample_regs_user = PERF_REGS_MASK;
482 attr->sample_stack_user = opts->stack_dump_size;
483 attr->exclude_callchain_user = 1;
484 }
485 }
486
487 if (perf_target__has_cpu(&opts->target))
488 attr->sample_type |= PERF_SAMPLE_CPU;
489
490 if (opts->period)
491 attr->sample_type |= PERF_SAMPLE_PERIOD;
492
493 if (!opts->sample_id_all_missing &&
494 (opts->sample_time || !opts->no_inherit ||
495 perf_target__has_cpu(&opts->target)))
496 attr->sample_type |= PERF_SAMPLE_TIME;
497
498 if (opts->raw_samples) {
499 attr->sample_type |= PERF_SAMPLE_TIME;
500 attr->sample_type |= PERF_SAMPLE_RAW;
501 attr->sample_type |= PERF_SAMPLE_CPU;
502 }
503
504 if (opts->no_delay) {
505 attr->watermark = 0;
506 attr->wakeup_events = 1;
507 }
508 if (opts->branch_stack) {
509 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK;
510 attr->branch_sample_type = opts->branch_stack;
511 }
512
513 attr->mmap = track;
514 attr->comm = track;
515
516 /*
517 * XXX see the function comment above
518 *
519 * Disabling only independent events or group leaders,
520 * keeping group members enabled.
521 */
522 if (!perf_evsel__is_group_member(evsel))
523 attr->disabled = 1;
524
525 /*
526 * Setting enable_on_exec for independent events and
527 * group leaders for traced executed by perf.
528 */
529 if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel))
530 attr->enable_on_exec = 1;
531}
532
533int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 54int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
534{ 55{
535 int cpu, thread; 56 int cpu, thread;
@@ -546,24 +67,6 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
546 return evsel->fd != NULL ? 0 : -ENOMEM; 67 return evsel->fd != NULL ? 0 : -ENOMEM;
547} 68}
548 69
549int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
550 const char *filter)
551{
552 int cpu, thread;
553
554 for (cpu = 0; cpu < ncpus; cpu++) {
555 for (thread = 0; thread < nthreads; thread++) {
556 int fd = FD(evsel, cpu, thread),
557 err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
558
559 if (err)
560 return err;
561 }
562 }
563
564 return 0;
565}
566
567int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 70int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
568{ 71{
569 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); 72 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
@@ -624,9 +127,6 @@ void perf_evsel__delete(struct perf_evsel *evsel)
624{ 127{
625 perf_evsel__exit(evsel); 128 perf_evsel__exit(evsel);
626 close_cgroup(evsel->cgrp); 129 close_cgroup(evsel->cgrp);
627 free(evsel->group_name);
628 if (evsel->tp_format)
629 pevent_free_format(evsel->tp_format);
630 free(evsel->name); 130 free(evsel->name);
631 free(evsel); 131 free(evsel);
632} 132}
@@ -702,36 +202,16 @@ int __perf_evsel__read(struct perf_evsel *evsel,
702 return 0; 202 return 0;
703} 203}
704 204
705static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
706{
707 struct perf_evsel *leader = evsel->leader;
708 int fd;
709
710 if (!perf_evsel__is_group_member(evsel))
711 return -1;
712
713 /*
714 * Leader must be already processed/open,
715 * if not it's a bug.
716 */
717 BUG_ON(!leader->fd);
718
719 fd = FD(leader, cpu, thread);
720 BUG_ON(fd == -1);
721
722 return fd;
723}
724
725static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 205static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
726 struct thread_map *threads) 206 struct thread_map *threads, bool group)
727{ 207{
728 int cpu, thread; 208 int cpu, thread;
729 unsigned long flags = 0; 209 unsigned long flags = 0;
730 int pid = -1, err; 210 int pid = -1;
731 211
732 if (evsel->fd == NULL && 212 if (evsel->fd == NULL &&
733 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 213 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
734 return -ENOMEM; 214 return -1;
735 215
736 if (evsel->cgrp) { 216 if (evsel->cgrp) {
737 flags = PERF_FLAG_PID_CGROUP; 217 flags = PERF_FLAG_PID_CGROUP;
@@ -739,23 +219,22 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
739 } 219 }
740 220
741 for (cpu = 0; cpu < cpus->nr; cpu++) { 221 for (cpu = 0; cpu < cpus->nr; cpu++) {
222 int group_fd = -1;
742 223
743 for (thread = 0; thread < threads->nr; thread++) { 224 for (thread = 0; thread < threads->nr; thread++) {
744 int group_fd;
745 225
746 if (!evsel->cgrp) 226 if (!evsel->cgrp)
747 pid = threads->map[thread]; 227 pid = threads->map[thread];
748 228
749 group_fd = get_group_fd(evsel, cpu, thread);
750
751 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 229 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
752 pid, 230 pid,
753 cpus->map[cpu], 231 cpus->map[cpu],
754 group_fd, flags); 232 group_fd, flags);
755 if (FD(evsel, cpu, thread) < 0) { 233 if (FD(evsel, cpu, thread) < 0)
756 err = -errno;
757 goto out_close; 234 goto out_close;
758 } 235
236 if (group && group_fd == -1)
237 group_fd = FD(evsel, cpu, thread);
759 } 238 }
760 } 239 }
761 240
@@ -769,17 +248,7 @@ out_close:
769 } 248 }
770 thread = threads->nr; 249 thread = threads->nr;
771 } while (--cpu >= 0); 250 } while (--cpu >= 0);
772 return err; 251 return -1;
773}
774
775void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
776{
777 if (evsel->fd == NULL)
778 return;
779
780 perf_evsel__close_fd(evsel, ncpus, nthreads);
781 perf_evsel__free_fd(evsel);
782 evsel->fd = NULL;
783} 252}
784 253
785static struct { 254static struct {
@@ -799,7 +268,7 @@ static struct {
799}; 268};
800 269
801int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 270int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
802 struct thread_map *threads) 271 struct thread_map *threads, bool group)
803{ 272{
804 if (cpus == NULL) { 273 if (cpus == NULL) {
805 /* Work around old compiler warnings about strict aliasing */ 274 /* Work around old compiler warnings about strict aliasing */
@@ -809,42 +278,32 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
809 if (threads == NULL) 278 if (threads == NULL)
810 threads = &empty_thread_map.map; 279 threads = &empty_thread_map.map;
811 280
812 return __perf_evsel__open(evsel, cpus, threads); 281 return __perf_evsel__open(evsel, cpus, threads, group);
813} 282}
814 283
815int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 284int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
816 struct cpu_map *cpus) 285 struct cpu_map *cpus, bool group)
817{ 286{
818 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); 287 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group);
819} 288}
820 289
821int perf_evsel__open_per_thread(struct perf_evsel *evsel, 290int perf_evsel__open_per_thread(struct perf_evsel *evsel,
822 struct thread_map *threads) 291 struct thread_map *threads, bool group)
823{ 292{
824 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); 293 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group);
825} 294}
826 295
827static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, 296static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
828 const union perf_event *event,
829 struct perf_sample *sample) 297 struct perf_sample *sample)
830{ 298{
831 u64 type = evsel->attr.sample_type;
832 const u64 *array = event->sample.array; 299 const u64 *array = event->sample.array;
833 bool swapped = evsel->needs_swap;
834 union u64_swap u;
835 300
836 array += ((event->header.size - 301 array += ((event->header.size -
837 sizeof(event->header)) / sizeof(u64)) - 1; 302 sizeof(event->header)) / sizeof(u64)) - 1;
838 303
839 if (type & PERF_SAMPLE_CPU) { 304 if (type & PERF_SAMPLE_CPU) {
840 u.val64 = *array; 305 u32 *p = (u32 *)array;
841 if (swapped) { 306 sample->cpu = *p;
842 /* undo swap of u64, then swap on individual u32s */
843 u.val64 = bswap_64(u.val64);
844 u.val32[0] = bswap_32(u.val32[0]);
845 }
846
847 sample->cpu = u.val32[0];
848 array--; 307 array--;
849 } 308 }
850 309
@@ -864,16 +323,9 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
864 } 323 }
865 324
866 if (type & PERF_SAMPLE_TID) { 325 if (type & PERF_SAMPLE_TID) {
867 u.val64 = *array; 326 u32 *p = (u32 *)array;
868 if (swapped) { 327 sample->pid = p[0];
869 /* undo swap of u64, then swap on individual u32s */ 328 sample->tid = p[1];
870 u.val64 = bswap_64(u.val64);
871 u.val32[0] = bswap_32(u.val32[0]);
872 u.val32[1] = bswap_32(u.val32[1]);
873 }
874
875 sample->pid = u.val32[0];
876 sample->tid = u.val32[1];
877 } 329 }
878 330
879 return 0; 331 return 0;
@@ -890,34 +342,34 @@ static bool sample_overlap(const union perf_event *event,
890 return false; 342 return false;
891} 343}
892 344
893int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, 345int perf_event__parse_sample(const union perf_event *event, u64 type,
894 struct perf_sample *data) 346 int sample_size, bool sample_id_all,
347 struct perf_sample *data, bool swapped)
895{ 348{
896 u64 type = evsel->attr.sample_type;
897 u64 regs_user = evsel->attr.sample_regs_user;
898 bool swapped = evsel->needs_swap;
899 const u64 *array; 349 const u64 *array;
900 350
901 /* 351 /*
902 * used for cross-endian analysis. See git commit 65014ab3 352 * used for cross-endian analysis. See git commit 65014ab3
903 * for why this goofiness is needed. 353 * for why this goofiness is needed.
904 */ 354 */
905 union u64_swap u; 355 union {
356 u64 val64;
357 u32 val32[2];
358 } u;
359
906 360
907 memset(data, 0, sizeof(*data));
908 data->cpu = data->pid = data->tid = -1; 361 data->cpu = data->pid = data->tid = -1;
909 data->stream_id = data->id = data->time = -1ULL; 362 data->stream_id = data->id = data->time = -1ULL;
910 data->period = 1;
911 363
912 if (event->header.type != PERF_RECORD_SAMPLE) { 364 if (event->header.type != PERF_RECORD_SAMPLE) {
913 if (!evsel->attr.sample_id_all) 365 if (!sample_id_all)
914 return 0; 366 return 0;
915 return perf_evsel__parse_id_sample(evsel, event, data); 367 return perf_event__parse_id_sample(event, type, data);
916 } 368 }
917 369
918 array = event->sample.array; 370 array = event->sample.array;
919 371
920 if (evsel->sample_size + sizeof(event->header) > event->header.size) 372 if (sample_size + sizeof(event->header) > event->header.size)
921 return -EFAULT; 373 return -EFAULT;
922 374
923 if (type & PERF_SAMPLE_IP) { 375 if (type & PERF_SAMPLE_IP) {
@@ -980,7 +432,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
980 } 432 }
981 433
982 if (type & PERF_SAMPLE_READ) { 434 if (type & PERF_SAMPLE_READ) {
983 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); 435 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n");
984 return -1; 436 return -1;
985 } 437 }
986 438
@@ -1018,189 +470,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1018 return -EFAULT; 470 return -EFAULT;
1019 471
1020 data->raw_data = (void *) pdata; 472 data->raw_data = (void *) pdata;
1021
1022 array = (void *)array + data->raw_size + sizeof(u32);
1023 }
1024
1025 if (type & PERF_SAMPLE_BRANCH_STACK) {
1026 u64 sz;
1027
1028 data->branch_stack = (struct branch_stack *)array;
1029 array++; /* nr */
1030
1031 sz = data->branch_stack->nr * sizeof(struct branch_entry);
1032 sz /= sizeof(u64);
1033 array += sz;
1034 }
1035
1036 if (type & PERF_SAMPLE_REGS_USER) {
1037 /* First u64 tells us if we have any regs in sample. */
1038 u64 avail = *array++;
1039
1040 if (avail) {
1041 data->user_regs.regs = (u64 *)array;
1042 array += hweight_long(regs_user);
1043 }
1044 }
1045
1046 if (type & PERF_SAMPLE_STACK_USER) {
1047 u64 size = *array++;
1048
1049 data->user_stack.offset = ((char *)(array - 1)
1050 - (char *) event);
1051
1052 if (!size) {
1053 data->user_stack.size = 0;
1054 } else {
1055 data->user_stack.data = (char *)array;
1056 array += size / sizeof(*array);
1057 data->user_stack.size = *array;
1058 }
1059 }
1060
1061 return 0;
1062}
1063
1064int perf_event__synthesize_sample(union perf_event *event, u64 type,
1065 const struct perf_sample *sample,
1066 bool swapped)
1067{
1068 u64 *array;
1069
1070 /*
1071 * used for cross-endian analysis. See git commit 65014ab3
1072 * for why this goofiness is needed.
1073 */
1074 union u64_swap u;
1075
1076 array = event->sample.array;
1077
1078 if (type & PERF_SAMPLE_IP) {
1079 event->ip.ip = sample->ip;
1080 array++;
1081 }
1082
1083 if (type & PERF_SAMPLE_TID) {
1084 u.val32[0] = sample->pid;
1085 u.val32[1] = sample->tid;
1086 if (swapped) {
1087 /*
1088 * Inverse of what is done in perf_evsel__parse_sample
1089 */
1090 u.val32[0] = bswap_32(u.val32[0]);
1091 u.val32[1] = bswap_32(u.val32[1]);
1092 u.val64 = bswap_64(u.val64);
1093 }
1094
1095 *array = u.val64;
1096 array++;
1097 }
1098
1099 if (type & PERF_SAMPLE_TIME) {
1100 *array = sample->time;
1101 array++;
1102 }
1103
1104 if (type & PERF_SAMPLE_ADDR) {
1105 *array = sample->addr;
1106 array++;
1107 }
1108
1109 if (type & PERF_SAMPLE_ID) {
1110 *array = sample->id;
1111 array++;
1112 }
1113
1114 if (type & PERF_SAMPLE_STREAM_ID) {
1115 *array = sample->stream_id;
1116 array++;
1117 }
1118
1119 if (type & PERF_SAMPLE_CPU) {
1120 u.val32[0] = sample->cpu;
1121 if (swapped) {
1122 /*
1123 * Inverse of what is done in perf_evsel__parse_sample
1124 */
1125 u.val32[0] = bswap_32(u.val32[0]);
1126 u.val64 = bswap_64(u.val64);
1127 }
1128 *array = u.val64;
1129 array++;
1130 }
1131
1132 if (type & PERF_SAMPLE_PERIOD) {
1133 *array = sample->period;
1134 array++;
1135 }
1136
1137 return 0;
1138}
1139
1140struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name)
1141{
1142 return pevent_find_field(evsel->tp_format, name);
1143}
1144
1145void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
1146 const char *name)
1147{
1148 struct format_field *field = perf_evsel__field(evsel, name);
1149 int offset;
1150
1151 if (!field)
1152 return NULL;
1153
1154 offset = field->offset;
1155
1156 if (field->flags & FIELD_IS_DYNAMIC) {
1157 offset = *(int *)(sample->raw_data + field->offset);
1158 offset &= 0xffff;
1159 }
1160
1161 return sample->raw_data + offset;
1162}
1163
1164u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
1165 const char *name)
1166{
1167 struct format_field *field = perf_evsel__field(evsel, name);
1168 void *ptr;
1169 u64 value;
1170
1171 if (!field)
1172 return 0;
1173
1174 ptr = sample->raw_data + field->offset;
1175
1176 switch (field->size) {
1177 case 1:
1178 return *(u8 *)ptr;
1179 case 2:
1180 value = *(u16 *)ptr;
1181 break;
1182 case 4:
1183 value = *(u32 *)ptr;
1184 break;
1185 case 8:
1186 value = *(u64 *)ptr;
1187 break;
1188 default:
1189 return 0;
1190 }
1191
1192 if (!evsel->needs_swap)
1193 return value;
1194
1195 switch (field->size) {
1196 case 2:
1197 return bswap_16(value);
1198 case 4:
1199 return bswap_32(value);
1200 case 8:
1201 return bswap_64(value);
1202 default:
1203 return 0;
1204 } 473 }
1205 474
1206 return 0; 475 return 0;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3d2b8017438..e9a31554e26 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -3,8 +3,7 @@
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include <stddef.h> 6#include "../../../include/linux/perf_event.h"
7#include <linux/perf_event.h>
8#include "types.h" 7#include "types.h"
9#include "xyarray.h" 8#include "xyarray.h"
10#include "cgroup.h" 9#include "cgroup.h"
@@ -54,63 +53,27 @@ struct perf_evsel {
54 u64 *id; 53 u64 *id;
55 struct perf_counts *counts; 54 struct perf_counts *counts;
56 int idx; 55 int idx;
57 u32 ids; 56 int ids;
58 struct hists hists; 57 struct hists hists;
59 char *name; 58 char *name;
60 struct event_format *tp_format;
61 union { 59 union {
62 void *priv; 60 void *priv;
63 off_t id_offset; 61 off_t id_offset;
64 }; 62 };
65 struct cgroup_sel *cgrp; 63 struct cgroup_sel *cgrp;
66 struct {
67 void *func;
68 void *data;
69 } handler;
70 struct cpu_map *cpus;
71 unsigned int sample_size;
72 bool supported; 64 bool supported;
73 bool needs_swap;
74 /* parse modifier helper */
75 int exclude_GH;
76 struct perf_evsel *leader;
77 char *group_name;
78}; 65};
79 66
80struct cpu_map; 67struct cpu_map;
81struct thread_map; 68struct thread_map;
82struct perf_evlist; 69struct perf_evlist;
83struct perf_record_opts;
84 70
85struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 71struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
86struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx);
87
88struct event_format *event_format__new(const char *sys, const char *name);
89
90void perf_evsel__init(struct perf_evsel *evsel, 72void perf_evsel__init(struct perf_evsel *evsel,
91 struct perf_event_attr *attr, int idx); 73 struct perf_event_attr *attr, int idx);
92void perf_evsel__exit(struct perf_evsel *evsel); 74void perf_evsel__exit(struct perf_evsel *evsel);
93void perf_evsel__delete(struct perf_evsel *evsel); 75void perf_evsel__delete(struct perf_evsel *evsel);
94 76
95void perf_evsel__config(struct perf_evsel *evsel,
96 struct perf_record_opts *opts);
97
98bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
99
100#define PERF_EVSEL__MAX_ALIASES 8
101
102extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
103 [PERF_EVSEL__MAX_ALIASES];
104extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
105 [PERF_EVSEL__MAX_ALIASES];
106extern const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
107 [PERF_EVSEL__MAX_ALIASES];
108extern const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX];
109extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
110int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
111 char *bf, size_t size);
112const char *perf_evsel__name(struct perf_evsel *evsel);
113
114int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 77int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
115int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 78int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
116int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 79int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
@@ -118,46 +81,17 @@ void perf_evsel__free_fd(struct perf_evsel *evsel);
118void perf_evsel__free_id(struct perf_evsel *evsel); 81void perf_evsel__free_id(struct perf_evsel *evsel);
119void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 82void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
120 83
121int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
122 const char *filter);
123
124int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 84int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
125 struct cpu_map *cpus); 85 struct cpu_map *cpus, bool group);
126int perf_evsel__open_per_thread(struct perf_evsel *evsel, 86int perf_evsel__open_per_thread(struct perf_evsel *evsel,
127 struct thread_map *threads); 87 struct thread_map *threads, bool group);
128int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 88int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
129 struct thread_map *threads); 89 struct thread_map *threads, bool group);
130void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
131
132struct perf_sample;
133
134void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
135 const char *name);
136u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
137 const char *name);
138
139static inline char *perf_evsel__strval(struct perf_evsel *evsel,
140 struct perf_sample *sample,
141 const char *name)
142{
143 return perf_evsel__rawptr(evsel, sample, name);
144}
145
146struct format_field;
147
148struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name);
149 90
150#define perf_evsel__match(evsel, t, c) \ 91#define perf_evsel__match(evsel, t, c) \
151 (evsel->attr.type == PERF_TYPE_##t && \ 92 (evsel->attr.type == PERF_TYPE_##t && \
152 evsel->attr.config == PERF_COUNT_##c) 93 evsel->attr.config == PERF_COUNT_##c)
153 94
154static inline bool perf_evsel__match2(struct perf_evsel *e1,
155 struct perf_evsel *e2)
156{
157 return (e1->attr.type == e2->attr.type) &&
158 (e1->attr.config == e2->attr.config);
159}
160
161int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 95int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
162 int cpu, int thread, bool scale); 96 int cpu, int thread, bool scale);
163 97
@@ -216,18 +150,11 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
216 return __perf_evsel__read(evsel, ncpus, nthreads, true); 150 return __perf_evsel__read(evsel, ncpus, nthreads, true);
217} 151}
218 152
219void hists__init(struct hists *hists); 153int __perf_evsel__sample_size(u64 sample_type);
220
221int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
222 struct perf_sample *sample);
223 154
224static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) 155static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
225{ 156{
226 return list_entry(evsel->node.next, struct perf_evsel, node); 157 return __perf_evsel__sample_size(evsel->attr.sample_type);
227} 158}
228 159
229static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel)
230{
231 return evsel->leader != NULL;
232}
233#endif /* __PERF_EVSEL_H */ 160#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index 3ac38031d53..f06f6fd148f 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -21,19 +21,4 @@ do
21 p 21 p
22 }' "Documentation/perf-$cmd.txt" 22 }' "Documentation/perf-$cmd.txt"
23done 23done
24
25echo "#ifdef LIBELF_SUPPORT"
26sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt |
27sort |
28while read cmd
29do
30 sed -n '
31 /^NAME/,/perf-'"$cmd"'/H
32 ${
33 x
34 s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/
35 p
36 }' "Documentation/perf-$cmd.txt"
37done
38echo "#endif /* LIBELF_SUPPORT */"
39echo "};" 24echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b7da4634a04..b6c1ad123ca 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,6 +1,5 @@
1#define _FILE_OFFSET_BITS 64 1#define _FILE_OFFSET_BITS 64
2 2
3#include "util.h"
4#include <sys/types.h> 3#include <sys/types.h>
5#include <byteswap.h> 4#include <byteswap.h>
6#include <unistd.h> 5#include <unistd.h>
@@ -8,74 +7,59 @@
8#include <stdlib.h> 7#include <stdlib.h>
9#include <linux/list.h> 8#include <linux/list.h>
10#include <linux/kernel.h> 9#include <linux/kernel.h>
11#include <linux/bitops.h>
12#include <sys/utsname.h>
13 10
14#include "evlist.h" 11#include "evlist.h"
15#include "evsel.h" 12#include "evsel.h"
13#include "util.h"
16#include "header.h" 14#include "header.h"
17#include "../perf.h" 15#include "../perf.h"
18#include "trace-event.h" 16#include "trace-event.h"
19#include "session.h" 17#include "session.h"
20#include "symbol.h" 18#include "symbol.h"
21#include "debug.h" 19#include "debug.h"
22#include "cpumap.h"
23#include "pmu.h"
24#include "vdso.h"
25#include "strbuf.h"
26#include "build-id.h"
27 20
28static bool no_buildid_cache = false; 21static bool no_buildid_cache = false;
29 22
30static int trace_event_count; 23static int event_count;
31static struct perf_trace_event_type *trace_events; 24static struct perf_trace_event_type *events;
32
33static u32 header_argc;
34static const char **header_argv;
35 25
36int perf_header__push_event(u64 id, const char *name) 26int perf_header__push_event(u64 id, const char *name)
37{ 27{
38 struct perf_trace_event_type *nevents;
39
40 if (strlen(name) > MAX_EVENT_NAME) 28 if (strlen(name) > MAX_EVENT_NAME)
41 pr_warning("Event %s will be truncated\n", name); 29 pr_warning("Event %s will be truncated\n", name);
42 30
43 nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events)); 31 if (!events) {
44 if (nevents == NULL) 32 events = malloc(sizeof(struct perf_trace_event_type));
45 return -ENOMEM; 33 if (events == NULL)
46 trace_events = nevents; 34 return -ENOMEM;
35 } else {
36 struct perf_trace_event_type *nevents;
47 37
48 memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type)); 38 nevents = realloc(events, (event_count + 1) * sizeof(*events));
49 trace_events[trace_event_count].event_id = id; 39 if (nevents == NULL)
50 strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1); 40 return -ENOMEM;
51 trace_event_count++; 41 events = nevents;
42 }
43 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
44 events[event_count].event_id = id;
45 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
46 event_count++;
52 return 0; 47 return 0;
53} 48}
54 49
55char *perf_header__find_event(u64 id) 50char *perf_header__find_event(u64 id)
56{ 51{
57 int i; 52 int i;
58 for (i = 0 ; i < trace_event_count; i++) { 53 for (i = 0 ; i < event_count; i++) {
59 if (trace_events[i].event_id == id) 54 if (events[i].event_id == id)
60 return trace_events[i].name; 55 return events[i].name;
61 } 56 }
62 return NULL; 57 return NULL;
63} 58}
64 59
65/* 60static const char *__perf_magic = "PERFFILE";
66 * magic2 = "PERFILE2" 61
67 * must be a numerical value to let the endianness 62#define PERF_MAGIC (*(u64 *)__perf_magic)
68 * determine the memory layout. That way we are able
69 * to detect endianness when reading the perf.data file
70 * back.
71 *
72 * we check for legacy (PERFFILE) format.
73 */
74static const char *__perf_magic1 = "PERFFILE";
75static const u64 __perf_magic2 = 0x32454c4946524550ULL;
76static const u64 __perf_magic2_sw = 0x50455246494c4532ULL;
77
78#define PERF_MAGIC __perf_magic2
79 63
80struct perf_file_attr { 64struct perf_file_attr {
81 struct perf_event_attr attr; 65 struct perf_event_attr attr;
@@ -126,113 +110,12 @@ static int write_padded(int fd, const void *bf, size_t count,
126 return err; 110 return err;
127} 111}
128 112
129static int do_write_string(int fd, const char *str)
130{
131 u32 len, olen;
132 int ret;
133
134 olen = strlen(str) + 1;
135 len = PERF_ALIGN(olen, NAME_ALIGN);
136
137 /* write len, incl. \0 */
138 ret = do_write(fd, &len, sizeof(len));
139 if (ret < 0)
140 return ret;
141
142 return write_padded(fd, str, olen, len);
143}
144
145static char *do_read_string(int fd, struct perf_header *ph)
146{
147 ssize_t sz, ret;
148 u32 len;
149 char *buf;
150
151 sz = read(fd, &len, sizeof(len));
152 if (sz < (ssize_t)sizeof(len))
153 return NULL;
154
155 if (ph->needs_swap)
156 len = bswap_32(len);
157
158 buf = malloc(len);
159 if (!buf)
160 return NULL;
161
162 ret = read(fd, buf, len);
163 if (ret == (ssize_t)len) {
164 /*
165 * strings are padded by zeroes
166 * thus the actual strlen of buf
167 * may be less than len
168 */
169 return buf;
170 }
171
172 free(buf);
173 return NULL;
174}
175
176int
177perf_header__set_cmdline(int argc, const char **argv)
178{
179 int i;
180
181 /*
182 * If header_argv has already been set, do not override it.
183 * This allows a command to set the cmdline, parse args and
184 * then call another builtin function that implements a
185 * command -- e.g, cmd_kvm calling cmd_record.
186 */
187 if (header_argv)
188 return 0;
189
190 header_argc = (u32)argc;
191
192 /* do not include NULL termination */
193 header_argv = calloc(argc, sizeof(char *));
194 if (!header_argv)
195 return -ENOMEM;
196
197 /*
198 * must copy argv contents because it gets moved
199 * around during option parsing
200 */
201 for (i = 0; i < argc ; i++)
202 header_argv[i] = argv[i];
203
204 return 0;
205}
206
207#define dsos__for_each_with_build_id(pos, head) \ 113#define dsos__for_each_with_build_id(pos, head) \
208 list_for_each_entry(pos, head, node) \ 114 list_for_each_entry(pos, head, node) \
209 if (!pos->has_build_id) \ 115 if (!pos->has_build_id) \
210 continue; \ 116 continue; \
211 else 117 else
212 118
213static int write_buildid(char *name, size_t name_len, u8 *build_id,
214 pid_t pid, u16 misc, int fd)
215{
216 int err;
217 struct build_id_event b;
218 size_t len;
219
220 len = name_len + 1;
221 len = PERF_ALIGN(len, NAME_ALIGN);
222
223 memset(&b, 0, sizeof(b));
224 memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
225 b.pid = pid;
226 b.header.misc = misc;
227 b.header.size = sizeof(b) + len;
228
229 err = do_write(fd, &b, sizeof(b));
230 if (err < 0)
231 return err;
232
233 return write_padded(fd, name, name_len + 1, len);
234}
235
236static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, 119static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
237 u16 misc, int fd) 120 u16 misc, int fd)
238{ 121{
@@ -240,23 +123,24 @@ static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
240 123
241 dsos__for_each_with_build_id(pos, head) { 124 dsos__for_each_with_build_id(pos, head) {
242 int err; 125 int err;
243 char *name; 126 struct build_id_event b;
244 size_t name_len; 127 size_t len;
245 128
246 if (!pos->hit) 129 if (!pos->hit)
247 continue; 130 continue;
248 131 len = pos->long_name_len + 1;
249 if (is_vdso_map(pos->short_name)) { 132 len = ALIGN(len, NAME_ALIGN);
250 name = (char *) VDSO__MAP_NAME; 133 memset(&b, 0, sizeof(b));
251 name_len = sizeof(VDSO__MAP_NAME) + 1; 134 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
252 } else { 135 b.pid = pid;
253 name = pos->long_name; 136 b.header.misc = misc;
254 name_len = pos->long_name_len + 1; 137 b.header.size = sizeof(b) + len;
255 } 138 err = do_write(fd, &b, sizeof(b));
256 139 if (err < 0)
257 err = write_buildid(name, name_len, pos->build_id, 140 return err;
258 pid, misc, fd); 141 err = write_padded(fd, pos->long_name,
259 if (err) 142 pos->long_name_len + 1, len);
143 if (err < 0)
260 return err; 144 return err;
261 } 145 }
262 146
@@ -302,33 +186,31 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
302} 186}
303 187
304int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, 188int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
305 const char *name, bool is_kallsyms, bool is_vdso) 189 const char *name, bool is_kallsyms)
306{ 190{
307 const size_t size = PATH_MAX; 191 const size_t size = PATH_MAX;
308 char *realname, *filename = zalloc(size), 192 char *realname, *filename = zalloc(size),
309 *linkname = zalloc(size), *targetname; 193 *linkname = zalloc(size), *targetname;
310 int len, err = -1; 194 int len, err = -1;
311 bool slash = is_kallsyms || is_vdso;
312 195
313 if (is_kallsyms) { 196 if (is_kallsyms) {
314 if (symbol_conf.kptr_restrict) { 197 if (symbol_conf.kptr_restrict) {
315 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); 198 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
316 return 0; 199 return 0;
317 } 200 }
318 realname = (char *) name; 201 realname = (char *)name;
319 } else 202 } else
320 realname = realpath(name, NULL); 203 realname = realpath(name, NULL);
321 204
322 if (realname == NULL || filename == NULL || linkname == NULL) 205 if (realname == NULL || filename == NULL || linkname == NULL)
323 goto out_free; 206 goto out_free;
324 207
325 len = scnprintf(filename, size, "%s%s%s", 208 len = snprintf(filename, size, "%s%s%s",
326 debugdir, slash ? "/" : "", 209 debugdir, is_kallsyms ? "/" : "", realname);
327 is_vdso ? VDSO__MAP_NAME : realname);
328 if (mkdir_p(filename, 0755)) 210 if (mkdir_p(filename, 0755))
329 goto out_free; 211 goto out_free;
330 212
331 snprintf(filename + len, size - len, "/%s", sbuild_id); 213 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
332 214
333 if (access(filename, F_OK)) { 215 if (access(filename, F_OK)) {
334 if (is_kallsyms) { 216 if (is_kallsyms) {
@@ -338,7 +220,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
338 goto out_free; 220 goto out_free;
339 } 221 }
340 222
341 len = scnprintf(linkname, size, "%s/.build-id/%.2s", 223 len = snprintf(linkname, size, "%s/.build-id/%.2s",
342 debugdir, sbuild_id); 224 debugdir, sbuild_id);
343 225
344 if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) 226 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
@@ -360,14 +242,13 @@ out_free:
360 242
361static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, 243static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
362 const char *name, const char *debugdir, 244 const char *name, const char *debugdir,
363 bool is_kallsyms, bool is_vdso) 245 bool is_kallsyms)
364{ 246{
365 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 247 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
366 248
367 build_id__sprintf(build_id, build_id_size, sbuild_id); 249 build_id__sprintf(build_id, build_id_size, sbuild_id);
368 250
369 return build_id_cache__add_s(sbuild_id, debugdir, name, 251 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
370 is_kallsyms, is_vdso);
371} 252}
372 253
373int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) 254int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
@@ -386,7 +267,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
386 if (access(linkname, F_OK)) 267 if (access(linkname, F_OK))
387 goto out_free; 268 goto out_free;
388 269
389 if (readlink(linkname, filename, size - 1) < 0) 270 if (readlink(linkname, filename, size) < 0)
390 goto out_free; 271 goto out_free;
391 272
392 if (unlink(linkname)) 273 if (unlink(linkname))
@@ -411,11 +292,9 @@ out_free:
411static int dso__cache_build_id(struct dso *dso, const char *debugdir) 292static int dso__cache_build_id(struct dso *dso, const char *debugdir)
412{ 293{
413 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 294 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
414 bool is_vdso = is_vdso_map(dso->short_name);
415 295
416 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), 296 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
417 dso->long_name, debugdir, 297 dso->long_name, debugdir, is_kallsyms);
418 is_kallsyms, is_vdso);
419} 298}
420 299
421static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) 300static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
@@ -477,962 +356,292 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
477 return ret; 356 return ret;
478} 357}
479 358
480static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, 359static int perf_header__adds_write(struct perf_header *header,
481 struct perf_evlist *evlist) 360 struct perf_evlist *evlist, int fd)
482{
483 return read_tracing_data(fd, &evlist->entries);
484}
485
486
487static int write_build_id(int fd, struct perf_header *h,
488 struct perf_evlist *evlist __maybe_unused)
489{ 361{
362 int nr_sections;
490 struct perf_session *session; 363 struct perf_session *session;
491 int err; 364 struct perf_file_section *feat_sec;
492 365 int sec_size;
493 session = container_of(h, struct perf_session, header); 366 u64 sec_start;
494 367 int idx = 0, err;
495 if (!perf_session__read_build_ids(session, true))
496 return -1;
497
498 err = dsos__write_buildid_table(h, fd);
499 if (err < 0) {
500 pr_debug("failed to write buildid table\n");
501 return err;
502 }
503 if (!no_buildid_cache)
504 perf_session__cache_build_ids(session);
505
506 return 0;
507}
508
509static int write_hostname(int fd, struct perf_header *h __maybe_unused,
510 struct perf_evlist *evlist __maybe_unused)
511{
512 struct utsname uts;
513 int ret;
514
515 ret = uname(&uts);
516 if (ret < 0)
517 return -1;
518 368
519 return do_write_string(fd, uts.nodename); 369 session = container_of(header, struct perf_session, header);
520}
521 370
522static int write_osrelease(int fd, struct perf_header *h __maybe_unused, 371 if (perf_header__has_feat(header, HEADER_BUILD_ID &&
523 struct perf_evlist *evlist __maybe_unused) 372 !perf_session__read_build_ids(session, true)))
524{ 373 perf_header__clear_feat(header, HEADER_BUILD_ID);
525 struct utsname uts;
526 int ret;
527 374
528 ret = uname(&uts); 375 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
529 if (ret < 0) 376 if (!nr_sections)
530 return -1; 377 return 0;
531 378
532 return do_write_string(fd, uts.release); 379 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
533} 380 if (feat_sec == NULL)
381 return -ENOMEM;
534 382
535static int write_arch(int fd, struct perf_header *h __maybe_unused, 383 sec_size = sizeof(*feat_sec) * nr_sections;
536 struct perf_evlist *evlist __maybe_unused)
537{
538 struct utsname uts;
539 int ret;
540 384
541 ret = uname(&uts); 385 sec_start = header->data_offset + header->data_size;
542 if (ret < 0) 386 lseek(fd, sec_start + sec_size, SEEK_SET);
543 return -1;
544 387
545 return do_write_string(fd, uts.machine); 388 if (perf_header__has_feat(header, HEADER_TRACE_INFO)) {
546} 389 struct perf_file_section *trace_sec;
547 390
548static int write_version(int fd, struct perf_header *h __maybe_unused, 391 trace_sec = &feat_sec[idx++];
549 struct perf_evlist *evlist __maybe_unused)
550{
551 return do_write_string(fd, perf_version_string);
552}
553 392
554static int write_cpudesc(int fd, struct perf_header *h __maybe_unused, 393 /* Write trace info */
555 struct perf_evlist *evlist __maybe_unused) 394 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
556{ 395 read_tracing_data(fd, &evlist->entries);
557#ifndef CPUINFO_PROC 396 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
558#define CPUINFO_PROC NULL 397 }
559#endif
560 FILE *file;
561 char *buf = NULL;
562 char *s, *p;
563 const char *search = CPUINFO_PROC;
564 size_t len = 0;
565 int ret = -1;
566
567 if (!search)
568 return -1;
569 398
570 file = fopen("/proc/cpuinfo", "r"); 399 if (perf_header__has_feat(header, HEADER_BUILD_ID)) {
571 if (!file) 400 struct perf_file_section *buildid_sec;
572 return -1;
573 401
574 while (getline(&buf, &len, file) > 0) { 402 buildid_sec = &feat_sec[idx++];
575 ret = strncmp(buf, search, strlen(search));
576 if (!ret)
577 break;
578 }
579 403
580 if (ret) 404 /* Write build-ids */
581 goto done; 405 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
582 406 err = dsos__write_buildid_table(header, fd);
583 s = buf; 407 if (err < 0) {
584 408 pr_debug("failed to write buildid table\n");
585 p = strchr(buf, ':'); 409 goto out_free;
586 if (p && *(p+1) == ' ' && *(p+2))
587 s = p + 2;
588 p = strchr(s, '\n');
589 if (p)
590 *p = '\0';
591
592 /* squash extra space characters (branding string) */
593 p = s;
594 while (*p) {
595 if (isspace(*p)) {
596 char *r = p + 1;
597 char *q = r;
598 *p = ' ';
599 while (*q && isspace(*q))
600 q++;
601 if (q != (p+1))
602 while ((*r++ = *q++));
603 } 410 }
604 p++; 411 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
412 buildid_sec->offset;
413 if (!no_buildid_cache)
414 perf_session__cache_build_ids(session);
605 } 415 }
606 ret = do_write_string(fd, s);
607done:
608 free(buf);
609 fclose(file);
610 return ret;
611}
612
613static int write_nrcpus(int fd, struct perf_header *h __maybe_unused,
614 struct perf_evlist *evlist __maybe_unused)
615{
616 long nr;
617 u32 nrc, nra;
618 int ret;
619
620 nr = sysconf(_SC_NPROCESSORS_CONF);
621 if (nr < 0)
622 return -1;
623 416
624 nrc = (u32)(nr & UINT_MAX); 417 lseek(fd, sec_start, SEEK_SET);
625 418 err = do_write(fd, feat_sec, sec_size);
626 nr = sysconf(_SC_NPROCESSORS_ONLN); 419 if (err < 0)
627 if (nr < 0) 420 pr_debug("failed to write feature section\n");
628 return -1; 421out_free:
629 422 free(feat_sec);
630 nra = (u32)(nr & UINT_MAX); 423 return err;
631
632 ret = do_write(fd, &nrc, sizeof(nrc));
633 if (ret < 0)
634 return ret;
635
636 return do_write(fd, &nra, sizeof(nra));
637} 424}
638 425
639static int write_event_desc(int fd, struct perf_header *h __maybe_unused, 426int perf_header__write_pipe(int fd)
640 struct perf_evlist *evlist)
641{ 427{
642 struct perf_evsel *evsel; 428 struct perf_pipe_file_header f_header;
643 u32 nre, nri, sz; 429 int err;
644 int ret;
645
646 nre = evlist->nr_entries;
647
648 /*
649 * write number of events
650 */
651 ret = do_write(fd, &nre, sizeof(nre));
652 if (ret < 0)
653 return ret;
654
655 /*
656 * size of perf_event_attr struct
657 */
658 sz = (u32)sizeof(evsel->attr);
659 ret = do_write(fd, &sz, sizeof(sz));
660 if (ret < 0)
661 return ret;
662
663 list_for_each_entry(evsel, &evlist->entries, node) {
664 430
665 ret = do_write(fd, &evsel->attr, sz); 431 f_header = (struct perf_pipe_file_header){
666 if (ret < 0) 432 .magic = PERF_MAGIC,
667 return ret; 433 .size = sizeof(f_header),
668 /* 434 };
669 * write number of unique id per event
670 * there is one id per instance of an event
671 *
672 * copy into an nri to be independent of the
673 * type of ids,
674 */
675 nri = evsel->ids;
676 ret = do_write(fd, &nri, sizeof(nri));
677 if (ret < 0)
678 return ret;
679 435
680 /* 436 err = do_write(fd, &f_header, sizeof(f_header));
681 * write event string as passed on cmdline 437 if (err < 0) {
682 */ 438 pr_debug("failed to write perf pipe header\n");
683 ret = do_write_string(fd, perf_evsel__name(evsel)); 439 return err;
684 if (ret < 0)
685 return ret;
686 /*
687 * write unique ids for this event
688 */
689 ret = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
690 if (ret < 0)
691 return ret;
692 } 440 }
693 return 0;
694}
695 441
696static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
697 struct perf_evlist *evlist __maybe_unused)
698{
699 char buf[MAXPATHLEN];
700 char proc[32];
701 u32 i, n;
702 int ret;
703
704 /*
705 * actual atual path to perf binary
706 */
707 sprintf(proc, "/proc/%d/exe", getpid());
708 ret = readlink(proc, buf, sizeof(buf));
709 if (ret <= 0)
710 return -1;
711
712 /* readlink() does not add null termination */
713 buf[ret] = '\0';
714
715 /* account for binary path */
716 n = header_argc + 1;
717
718 ret = do_write(fd, &n, sizeof(n));
719 if (ret < 0)
720 return ret;
721
722 ret = do_write_string(fd, buf);
723 if (ret < 0)
724 return ret;
725
726 for (i = 0 ; i < header_argc; i++) {
727 ret = do_write_string(fd, header_argv[i]);
728 if (ret < 0)
729 return ret;
730 }
731 return 0; 442 return 0;
732} 443}
733 444
734#define CORE_SIB_FMT \ 445int perf_session__write_header(struct perf_session *session,
735 "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list" 446 struct perf_evlist *evlist,
736#define THRD_SIB_FMT \ 447 int fd, bool at_exit)
737 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list"
738
739struct cpu_topo {
740 u32 core_sib;
741 u32 thread_sib;
742 char **core_siblings;
743 char **thread_siblings;
744};
745
746static int build_cpu_topo(struct cpu_topo *tp, int cpu)
747{
748 FILE *fp;
749 char filename[MAXPATHLEN];
750 char *buf = NULL, *p;
751 size_t len = 0;
752 u32 i = 0;
753 int ret = -1;
754
755 sprintf(filename, CORE_SIB_FMT, cpu);
756 fp = fopen(filename, "r");
757 if (!fp)
758 return -1;
759
760 if (getline(&buf, &len, fp) <= 0)
761 goto done;
762
763 fclose(fp);
764
765 p = strchr(buf, '\n');
766 if (p)
767 *p = '\0';
768
769 for (i = 0; i < tp->core_sib; i++) {
770 if (!strcmp(buf, tp->core_siblings[i]))
771 break;
772 }
773 if (i == tp->core_sib) {
774 tp->core_siblings[i] = buf;
775 tp->core_sib++;
776 buf = NULL;
777 len = 0;
778 }
779
780 sprintf(filename, THRD_SIB_FMT, cpu);
781 fp = fopen(filename, "r");
782 if (!fp)
783 goto done;
784
785 if (getline(&buf, &len, fp) <= 0)
786 goto done;
787
788 p = strchr(buf, '\n');
789 if (p)
790 *p = '\0';
791
792 for (i = 0; i < tp->thread_sib; i++) {
793 if (!strcmp(buf, tp->thread_siblings[i]))
794 break;
795 }
796 if (i == tp->thread_sib) {
797 tp->thread_siblings[i] = buf;
798 tp->thread_sib++;
799 buf = NULL;
800 }
801 ret = 0;
802done:
803 if(fp)
804 fclose(fp);
805 free(buf);
806 return ret;
807}
808
809static void free_cpu_topo(struct cpu_topo *tp)
810{
811 u32 i;
812
813 if (!tp)
814 return;
815
816 for (i = 0 ; i < tp->core_sib; i++)
817 free(tp->core_siblings[i]);
818
819 for (i = 0 ; i < tp->thread_sib; i++)
820 free(tp->thread_siblings[i]);
821
822 free(tp);
823}
824
825static struct cpu_topo *build_cpu_topology(void)
826{
827 struct cpu_topo *tp;
828 void *addr;
829 u32 nr, i;
830 size_t sz;
831 long ncpus;
832 int ret = -1;
833
834 ncpus = sysconf(_SC_NPROCESSORS_CONF);
835 if (ncpus < 0)
836 return NULL;
837
838 nr = (u32)(ncpus & UINT_MAX);
839
840 sz = nr * sizeof(char *);
841
842 addr = calloc(1, sizeof(*tp) + 2 * sz);
843 if (!addr)
844 return NULL;
845
846 tp = addr;
847
848 addr += sizeof(*tp);
849 tp->core_siblings = addr;
850 addr += sz;
851 tp->thread_siblings = addr;
852
853 for (i = 0; i < nr; i++) {
854 ret = build_cpu_topo(tp, i);
855 if (ret < 0)
856 break;
857 }
858 if (ret) {
859 free_cpu_topo(tp);
860 tp = NULL;
861 }
862 return tp;
863}
864
865static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
866 struct perf_evlist *evlist __maybe_unused)
867{ 448{
868 struct cpu_topo *tp; 449 struct perf_file_header f_header;
869 u32 i; 450 struct perf_file_attr f_attr;
870 int ret; 451 struct perf_header *header = &session->header;
871 452 struct perf_evsel *attr, *pair = NULL;
872 tp = build_cpu_topology(); 453 int err;
873 if (!tp)
874 return -1;
875 454
876 ret = do_write(fd, &tp->core_sib, sizeof(tp->core_sib)); 455 lseek(fd, sizeof(f_header), SEEK_SET);
877 if (ret < 0)
878 goto done;
879 456
880 for (i = 0; i < tp->core_sib; i++) { 457 if (session->evlist != evlist)
881 ret = do_write_string(fd, tp->core_siblings[i]); 458 pair = list_entry(session->evlist->entries.next, struct perf_evsel, node);
882 if (ret < 0)
883 goto done;
884 }
885 ret = do_write(fd, &tp->thread_sib, sizeof(tp->thread_sib));
886 if (ret < 0)
887 goto done;
888 459
889 for (i = 0; i < tp->thread_sib; i++) { 460 list_for_each_entry(attr, &evlist->entries, node) {
890 ret = do_write_string(fd, tp->thread_siblings[i]); 461 attr->id_offset = lseek(fd, 0, SEEK_CUR);
891 if (ret < 0) 462 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
892 break; 463 if (err < 0) {
464out_err_write:
465 pr_debug("failed to write perf header\n");
466 return err;
467 }
468 if (session->evlist != evlist) {
469 err = do_write(fd, pair->id, pair->ids * sizeof(u64));
470 if (err < 0)
471 goto out_err_write;
472 attr->ids += pair->ids;
473 pair = list_entry(pair->node.next, struct perf_evsel, node);
474 }
893 } 475 }
894done:
895 free_cpu_topo(tp);
896 return ret;
897}
898
899 476
477 header->attr_offset = lseek(fd, 0, SEEK_CUR);
900 478
901static int write_total_mem(int fd, struct perf_header *h __maybe_unused, 479 list_for_each_entry(attr, &evlist->entries, node) {
902 struct perf_evlist *evlist __maybe_unused) 480 f_attr = (struct perf_file_attr){
903{ 481 .attr = attr->attr,
904 char *buf = NULL; 482 .ids = {
905 FILE *fp; 483 .offset = attr->id_offset,
906 size_t len = 0; 484 .size = attr->ids * sizeof(u64),
907 int ret = -1, n; 485 }
908 uint64_t mem; 486 };
909 487 err = do_write(fd, &f_attr, sizeof(f_attr));
910 fp = fopen("/proc/meminfo", "r"); 488 if (err < 0) {
911 if (!fp) 489 pr_debug("failed to write perf header attribute\n");
912 return -1; 490 return err;
913 491 }
914 while (getline(&buf, &len, fp) > 0) {
915 ret = strncmp(buf, "MemTotal:", 9);
916 if (!ret)
917 break;
918 }
919 if (!ret) {
920 n = sscanf(buf, "%*s %"PRIu64, &mem);
921 if (n == 1)
922 ret = do_write(fd, &mem, sizeof(mem));
923 } 492 }
924 free(buf);
925 fclose(fp);
926 return ret;
927}
928
929static int write_topo_node(int fd, int node)
930{
931 char str[MAXPATHLEN];
932 char field[32];
933 char *buf = NULL, *p;
934 size_t len = 0;
935 FILE *fp;
936 u64 mem_total, mem_free, mem;
937 int ret = -1;
938
939 sprintf(str, "/sys/devices/system/node/node%d/meminfo", node);
940 fp = fopen(str, "r");
941 if (!fp)
942 return -1;
943 493
944 while (getline(&buf, &len, fp) > 0) { 494 header->event_offset = lseek(fd, 0, SEEK_CUR);
945 /* skip over invalid lines */ 495 header->event_size = event_count * sizeof(struct perf_trace_event_type);
946 if (!strchr(buf, ':')) 496 if (events) {
947 continue; 497 err = do_write(fd, events, header->event_size);
948 if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2) 498 if (err < 0) {
949 goto done; 499 pr_debug("failed to write perf header events\n");
950 if (!strcmp(field, "MemTotal:")) 500 return err;
951 mem_total = mem; 501 }
952 if (!strcmp(field, "MemFree:"))
953 mem_free = mem;
954 } 502 }
955 503
956 fclose(fp); 504 header->data_offset = lseek(fd, 0, SEEK_CUR);
957
958 ret = do_write(fd, &mem_total, sizeof(u64));
959 if (ret)
960 goto done;
961
962 ret = do_write(fd, &mem_free, sizeof(u64));
963 if (ret)
964 goto done;
965
966 ret = -1;
967 sprintf(str, "/sys/devices/system/node/node%d/cpulist", node);
968
969 fp = fopen(str, "r");
970 if (!fp)
971 goto done;
972
973 if (getline(&buf, &len, fp) <= 0)
974 goto done;
975
976 p = strchr(buf, '\n');
977 if (p)
978 *p = '\0';
979
980 ret = do_write_string(fd, buf);
981done:
982 free(buf);
983 fclose(fp);
984 return ret;
985}
986
987static int write_numa_topology(int fd, struct perf_header *h __maybe_unused,
988 struct perf_evlist *evlist __maybe_unused)
989{
990 char *buf = NULL;
991 size_t len = 0;
992 FILE *fp;
993 struct cpu_map *node_map = NULL;
994 char *c;
995 u32 nr, i, j;
996 int ret = -1;
997
998 fp = fopen("/sys/devices/system/node/online", "r");
999 if (!fp)
1000 return -1;
1001
1002 if (getline(&buf, &len, fp) <= 0)
1003 goto done;
1004
1005 c = strchr(buf, '\n');
1006 if (c)
1007 *c = '\0';
1008
1009 node_map = cpu_map__new(buf);
1010 if (!node_map)
1011 goto done;
1012
1013 nr = (u32)node_map->nr;
1014
1015 ret = do_write(fd, &nr, sizeof(nr));
1016 if (ret < 0)
1017 goto done;
1018
1019 for (i = 0; i < nr; i++) {
1020 j = (u32)node_map->map[i];
1021 ret = do_write(fd, &j, sizeof(j));
1022 if (ret < 0)
1023 break;
1024 505
1025 ret = write_topo_node(fd, i); 506 if (at_exit) {
1026 if (ret < 0) 507 err = perf_header__adds_write(header, evlist, fd);
1027 break; 508 if (err < 0)
509 return err;
1028 } 510 }
1029done:
1030 free(buf);
1031 fclose(fp);
1032 free(node_map);
1033 return ret;
1034}
1035
1036/*
1037 * File format:
1038 *
1039 * struct pmu_mappings {
1040 * u32 pmu_num;
1041 * struct pmu_map {
1042 * u32 type;
1043 * char name[];
1044 * }[pmu_num];
1045 * };
1046 */
1047
1048static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1049 struct perf_evlist *evlist __maybe_unused)
1050{
1051 struct perf_pmu *pmu = NULL;
1052 off_t offset = lseek(fd, 0, SEEK_CUR);
1053 __u32 pmu_num = 0;
1054 511
1055 /* write real pmu_num later */ 512 f_header = (struct perf_file_header){
1056 do_write(fd, &pmu_num, sizeof(pmu_num)); 513 .magic = PERF_MAGIC,
514 .size = sizeof(f_header),
515 .attr_size = sizeof(f_attr),
516 .attrs = {
517 .offset = header->attr_offset,
518 .size = evlist->nr_entries * sizeof(f_attr),
519 },
520 .data = {
521 .offset = header->data_offset,
522 .size = header->data_size,
523 },
524 .event_types = {
525 .offset = header->event_offset,
526 .size = header->event_size,
527 },
528 };
1057 529
1058 while ((pmu = perf_pmu__scan(pmu))) { 530 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
1059 if (!pmu->name)
1060 continue;
1061 pmu_num++;
1062 do_write(fd, &pmu->type, sizeof(pmu->type));
1063 do_write_string(fd, pmu->name);
1064 }
1065 531
1066 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { 532 lseek(fd, 0, SEEK_SET);
1067 /* discard all */ 533 err = do_write(fd, &f_header, sizeof(f_header));
1068 lseek(fd, offset, SEEK_SET); 534 if (err < 0) {
1069 return -1; 535 pr_debug("failed to write perf header\n");
536 return err;
1070 } 537 }
538 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
1071 539
540 header->frozen = 1;
1072 return 0; 541 return 0;
1073} 542}
1074 543
1075/* 544static int perf_header__getbuffer64(struct perf_header *header,
1076 * default get_cpuid(): nothing gets recorded 545 int fd, void *buf, size_t size)
1077 * actual implementation must be in arch/$(ARCH)/util/header.c
1078 */
1079int __attribute__ ((weak)) get_cpuid(char *buffer __maybe_unused,
1080 size_t sz __maybe_unused)
1081{
1082 return -1;
1083}
1084
1085static int write_cpuid(int fd, struct perf_header *h __maybe_unused,
1086 struct perf_evlist *evlist __maybe_unused)
1087{ 546{
1088 char buffer[64]; 547 if (readn(fd, buf, size) <= 0)
1089 int ret; 548 return -1;
1090
1091 ret = get_cpuid(buffer, sizeof(buffer));
1092 if (!ret)
1093 goto write_it;
1094 549
1095 return -1; 550 if (header->needs_swap)
1096write_it: 551 mem_bswap_64(buf, size);
1097 return do_write_string(fd, buffer);
1098}
1099 552
1100static int write_branch_stack(int fd __maybe_unused,
1101 struct perf_header *h __maybe_unused,
1102 struct perf_evlist *evlist __maybe_unused)
1103{
1104 return 0; 553 return 0;
1105} 554}
1106 555
1107static void print_hostname(struct perf_header *ph, int fd __maybe_unused, 556int perf_header__process_sections(struct perf_header *header, int fd,
1108 FILE *fp) 557 int (*process)(struct perf_file_section *section,
1109{ 558 struct perf_header *ph,
1110 fprintf(fp, "# hostname : %s\n", ph->env.hostname); 559 int feat, int fd))
1111}
1112
1113static void print_osrelease(struct perf_header *ph, int fd __maybe_unused,
1114 FILE *fp)
1115{
1116 fprintf(fp, "# os release : %s\n", ph->env.os_release);
1117}
1118
1119static void print_arch(struct perf_header *ph, int fd __maybe_unused, FILE *fp)
1120{
1121 fprintf(fp, "# arch : %s\n", ph->env.arch);
1122}
1123
1124static void print_cpudesc(struct perf_header *ph, int fd __maybe_unused,
1125 FILE *fp)
1126{
1127 fprintf(fp, "# cpudesc : %s\n", ph->env.cpu_desc);
1128}
1129
1130static void print_nrcpus(struct perf_header *ph, int fd __maybe_unused,
1131 FILE *fp)
1132{
1133 fprintf(fp, "# nrcpus online : %u\n", ph->env.nr_cpus_online);
1134 fprintf(fp, "# nrcpus avail : %u\n", ph->env.nr_cpus_avail);
1135}
1136
1137static void print_version(struct perf_header *ph, int fd __maybe_unused,
1138 FILE *fp)
1139{
1140 fprintf(fp, "# perf version : %s\n", ph->env.version);
1141}
1142
1143static void print_cmdline(struct perf_header *ph, int fd __maybe_unused,
1144 FILE *fp)
1145{
1146 int nr, i;
1147 char *str;
1148
1149 nr = ph->env.nr_cmdline;
1150 str = ph->env.cmdline;
1151
1152 fprintf(fp, "# cmdline : ");
1153
1154 for (i = 0; i < nr; i++) {
1155 fprintf(fp, "%s ", str);
1156 str += strlen(str) + 1;
1157 }
1158 fputc('\n', fp);
1159}
1160
1161static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused,
1162 FILE *fp)
1163{
1164 int nr, i;
1165 char *str;
1166
1167 nr = ph->env.nr_sibling_cores;
1168 str = ph->env.sibling_cores;
1169
1170 for (i = 0; i < nr; i++) {
1171 fprintf(fp, "# sibling cores : %s\n", str);
1172 str += strlen(str) + 1;
1173 }
1174
1175 nr = ph->env.nr_sibling_threads;
1176 str = ph->env.sibling_threads;
1177
1178 for (i = 0; i < nr; i++) {
1179 fprintf(fp, "# sibling threads : %s\n", str);
1180 str += strlen(str) + 1;
1181 }
1182}
1183
1184static void free_event_desc(struct perf_evsel *events)
1185{
1186 struct perf_evsel *evsel;
1187
1188 if (!events)
1189 return;
1190
1191 for (evsel = events; evsel->attr.size; evsel++) {
1192 if (evsel->name)
1193 free(evsel->name);
1194 if (evsel->id)
1195 free(evsel->id);
1196 }
1197
1198 free(events);
1199}
1200
1201static struct perf_evsel *
1202read_event_desc(struct perf_header *ph, int fd)
1203{ 560{
1204 struct perf_evsel *evsel, *events = NULL; 561 struct perf_file_section *feat_sec;
1205 u64 *id; 562 int nr_sections;
1206 void *buf = NULL; 563 int sec_size;
1207 u32 nre, sz, nr, i, j; 564 int idx = 0;
1208 ssize_t ret; 565 int err = -1, feat = 1;
1209 size_t msz;
1210
1211 /* number of events */
1212 ret = read(fd, &nre, sizeof(nre));
1213 if (ret != (ssize_t)sizeof(nre))
1214 goto error;
1215
1216 if (ph->needs_swap)
1217 nre = bswap_32(nre);
1218
1219 ret = read(fd, &sz, sizeof(sz));
1220 if (ret != (ssize_t)sizeof(sz))
1221 goto error;
1222
1223 if (ph->needs_swap)
1224 sz = bswap_32(sz);
1225
1226 /* buffer to hold on file attr struct */
1227 buf = malloc(sz);
1228 if (!buf)
1229 goto error;
1230
1231 /* the last event terminates with evsel->attr.size == 0: */
1232 events = calloc(nre + 1, sizeof(*events));
1233 if (!events)
1234 goto error;
1235
1236 msz = sizeof(evsel->attr);
1237 if (sz < msz)
1238 msz = sz;
1239
1240 for (i = 0, evsel = events; i < nre; evsel++, i++) {
1241 evsel->idx = i;
1242
1243 /*
1244 * must read entire on-file attr struct to
1245 * sync up with layout.
1246 */
1247 ret = read(fd, buf, sz);
1248 if (ret != (ssize_t)sz)
1249 goto error;
1250 566
1251 if (ph->needs_swap) 567 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
1252 perf_event__attr_swap(buf); 568 if (!nr_sections)
569 return 0;
1253 570
1254 memcpy(&evsel->attr, buf, msz); 571 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
572 if (!feat_sec)
573 return -1;
1255 574
1256 ret = read(fd, &nr, sizeof(nr)); 575 sec_size = sizeof(*feat_sec) * nr_sections;
1257 if (ret != (ssize_t)sizeof(nr))
1258 goto error;
1259 576
1260 if (ph->needs_swap) { 577 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
1261 nr = bswap_32(nr);
1262 evsel->needs_swap = true;
1263 }
1264 578
1265 evsel->name = do_read_string(fd, ph); 579 if (perf_header__getbuffer64(header, fd, feat_sec, sec_size))
580 goto out_free;
1266 581
1267 if (!nr) 582 err = 0;
1268 continue; 583 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
584 if (perf_header__has_feat(header, feat)) {
585 struct perf_file_section *sec = &feat_sec[idx++];
1269 586
1270 id = calloc(nr, sizeof(*id)); 587 err = process(sec, header, feat, fd);
1271 if (!id) 588 if (err < 0)
1272 goto error; 589 break;
1273 evsel->ids = nr;
1274 evsel->id = id;
1275
1276 for (j = 0 ; j < nr; j++) {
1277 ret = read(fd, id, sizeof(*id));
1278 if (ret != (ssize_t)sizeof(*id))
1279 goto error;
1280 if (ph->needs_swap)
1281 *id = bswap_64(*id);
1282 id++;
1283 } 590 }
591 ++feat;
1284 } 592 }
1285out: 593out_free:
1286 if (buf) 594 free(feat_sec);
1287 free(buf); 595 return err;
1288 return events;
1289error:
1290 if (events)
1291 free_event_desc(events);
1292 events = NULL;
1293 goto out;
1294} 596}
1295 597
1296static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) 598int perf_file_header__read(struct perf_file_header *header,
599 struct perf_header *ph, int fd)
1297{ 600{
1298 struct perf_evsel *evsel, *events = read_event_desc(ph, fd); 601 lseek(fd, 0, SEEK_SET);
1299 u32 j;
1300 u64 *id;
1301
1302 if (!events) {
1303 fprintf(fp, "# event desc: not available or unable to read\n");
1304 return;
1305 }
1306
1307 for (evsel = events; evsel->attr.size; evsel++) {
1308 fprintf(fp, "# event : name = %s, ", evsel->name);
1309
1310 fprintf(fp, "type = %d, config = 0x%"PRIx64
1311 ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64,
1312 evsel->attr.type,
1313 (u64)evsel->attr.config,
1314 (u64)evsel->attr.config1,
1315 (u64)evsel->attr.config2);
1316
1317 fprintf(fp, ", excl_usr = %d, excl_kern = %d",
1318 evsel->attr.exclude_user,
1319 evsel->attr.exclude_kernel);
1320
1321 fprintf(fp, ", excl_host = %d, excl_guest = %d",
1322 evsel->attr.exclude_host,
1323 evsel->attr.exclude_guest);
1324
1325 fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);
1326
1327 if (evsel->ids) {
1328 fprintf(fp, ", id = {");
1329 for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) {
1330 if (j)
1331 fputc(',', fp);
1332 fprintf(fp, " %"PRIu64, *id);
1333 }
1334 fprintf(fp, " }");
1335 }
1336 602
1337 fputc('\n', fp); 603 if (readn(fd, header, sizeof(*header)) <= 0 ||
1338 } 604 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
605 return -1;
1339 606
1340 free_event_desc(events); 607 if (header->attr_size != sizeof(struct perf_file_attr)) {
1341} 608 u64 attr_size = bswap_64(header->attr_size);
1342 609
1343static void print_total_mem(struct perf_header *ph, int fd __maybe_unused, 610 if (attr_size != sizeof(struct perf_file_attr))
1344 FILE *fp) 611 return -1;
1345{
1346 fprintf(fp, "# total memory : %Lu kB\n", ph->env.total_mem);
1347}
1348 612
1349static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused, 613 mem_bswap_64(header, offsetof(struct perf_file_header,
1350 FILE *fp) 614 adds_features));
1351{ 615 ph->needs_swap = true;
1352 u32 nr, c, i;
1353 char *str, *tmp;
1354 uint64_t mem_total, mem_free;
1355
1356 /* nr nodes */
1357 nr = ph->env.nr_numa_nodes;
1358 str = ph->env.numa_nodes;
1359
1360 for (i = 0; i < nr; i++) {
1361 /* node number */
1362 c = strtoul(str, &tmp, 0);
1363 if (*tmp != ':')
1364 goto error;
1365
1366 str = tmp + 1;
1367 mem_total = strtoull(str, &tmp, 0);
1368 if (*tmp != ':')
1369 goto error;
1370
1371 str = tmp + 1;
1372 mem_free = strtoull(str, &tmp, 0);
1373 if (*tmp != ':')
1374 goto error;
1375
1376 fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB,"
1377 " free = %"PRIu64" kB\n",
1378 c, mem_total, mem_free);
1379
1380 str = tmp + 1;
1381 fprintf(fp, "# node%u cpu list : %s\n", c, str);
1382
1383 str += strlen(str) + 1;
1384 } 616 }
1385 return;
1386error:
1387 fprintf(fp, "# numa topology : not available\n");
1388}
1389
1390static void print_cpuid(struct perf_header *ph, int fd __maybe_unused, FILE *fp)
1391{
1392 fprintf(fp, "# cpuid : %s\n", ph->env.cpuid);
1393}
1394
1395static void print_branch_stack(struct perf_header *ph __maybe_unused,
1396 int fd __maybe_unused, FILE *fp)
1397{
1398 fprintf(fp, "# contains samples with branch stack\n");
1399}
1400 617
1401static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, 618 if (header->size != sizeof(*header)) {
1402 FILE *fp) 619 /* Support the previous format */
1403{ 620 if (header->size == offsetof(typeof(*header), adds_features))
1404 const char *delimiter = "# pmu mappings: "; 621 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
1405 char *str, *tmp; 622 else
1406 u32 pmu_num; 623 return -1;
1407 u32 type;
1408
1409 pmu_num = ph->env.nr_pmu_mappings;
1410 if (!pmu_num) {
1411 fprintf(fp, "# pmu mappings: not available\n");
1412 return;
1413 } 624 }
1414 625
1415 str = ph->env.pmu_mappings; 626 memcpy(&ph->adds_features, &header->adds_features,
1416 627 sizeof(ph->adds_features));
1417 while (pmu_num) { 628 /*
1418 type = strtoul(str, &tmp, 0); 629 * FIXME: hack that assumes that if we need swap the perf.data file
1419 if (*tmp != ':') 630 * may be coming from an arch with a different word-size, ergo different
1420 goto error; 631 * DEFINE_BITMAP format, investigate more later, but for now its mostly
1421 632 * safe to assume that we have a build-id section. Trace files probably
1422 str = tmp + 1; 633 * have several other issues in this realm anyway...
1423 fprintf(fp, "%s%s = %" PRIu32, delimiter, str, type); 634 */
1424 635 if (ph->needs_swap) {
1425 delimiter = ", "; 636 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
1426 str += strlen(str) + 1; 637 perf_header__set_feat(ph, HEADER_BUILD_ID);
1427 pmu_num--;
1428 } 638 }
1429 639
1430 fprintf(fp, "\n"); 640 ph->event_offset = header->event_types.offset;
1431 641 ph->event_size = header->event_types.size;
1432 if (!pmu_num) 642 ph->data_offset = header->data.offset;
1433 return; 643 ph->data_size = header->data.size;
1434error: 644 return 0;
1435 fprintf(fp, "# pmu mappings: unable to read\n");
1436} 645}
1437 646
1438static int __event_process_build_id(struct build_id_event *bev, 647static int __event_process_build_id(struct build_id_event *bev,
@@ -1496,7 +705,7 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1496 struct perf_session *session = container_of(header, struct perf_session, header); 705 struct perf_session *session = container_of(header, struct perf_session, header);
1497 struct { 706 struct {
1498 struct perf_event_header header; 707 struct perf_event_header header;
1499 u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; 708 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
1500 char filename[0]; 709 char filename[0];
1501 } old_bev; 710 } old_bev;
1502 struct build_id_event bev; 711 struct build_id_event bev;
@@ -1585,883 +794,9 @@ out:
1585 return err; 794 return err;
1586} 795}
1587 796
1588static int process_tracing_data(struct perf_file_section *section __maybe_unused,
1589 struct perf_header *ph __maybe_unused,
1590 int fd, void *data)
1591{
1592 trace_report(fd, data, false);
1593 return 0;
1594}
1595
1596static int process_build_id(struct perf_file_section *section,
1597 struct perf_header *ph, int fd,
1598 void *data __maybe_unused)
1599{
1600 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
1601 pr_debug("Failed to read buildids, continuing...\n");
1602 return 0;
1603}
1604
1605static int process_hostname(struct perf_file_section *section __maybe_unused,
1606 struct perf_header *ph, int fd,
1607 void *data __maybe_unused)
1608{
1609 ph->env.hostname = do_read_string(fd, ph);
1610 return ph->env.hostname ? 0 : -ENOMEM;
1611}
1612
1613static int process_osrelease(struct perf_file_section *section __maybe_unused,
1614 struct perf_header *ph, int fd,
1615 void *data __maybe_unused)
1616{
1617 ph->env.os_release = do_read_string(fd, ph);
1618 return ph->env.os_release ? 0 : -ENOMEM;
1619}
1620
1621static int process_version(struct perf_file_section *section __maybe_unused,
1622 struct perf_header *ph, int fd,
1623 void *data __maybe_unused)
1624{
1625 ph->env.version = do_read_string(fd, ph);
1626 return ph->env.version ? 0 : -ENOMEM;
1627}
1628
1629static int process_arch(struct perf_file_section *section __maybe_unused,
1630 struct perf_header *ph, int fd,
1631 void *data __maybe_unused)
1632{
1633 ph->env.arch = do_read_string(fd, ph);
1634 return ph->env.arch ? 0 : -ENOMEM;
1635}
1636
1637static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1638 struct perf_header *ph, int fd,
1639 void *data __maybe_unused)
1640{
1641 size_t ret;
1642 u32 nr;
1643
1644 ret = read(fd, &nr, sizeof(nr));
1645 if (ret != sizeof(nr))
1646 return -1;
1647
1648 if (ph->needs_swap)
1649 nr = bswap_32(nr);
1650
1651 ph->env.nr_cpus_online = nr;
1652
1653 ret = read(fd, &nr, sizeof(nr));
1654 if (ret != sizeof(nr))
1655 return -1;
1656
1657 if (ph->needs_swap)
1658 nr = bswap_32(nr);
1659
1660 ph->env.nr_cpus_avail = nr;
1661 return 0;
1662}
1663
1664static int process_cpudesc(struct perf_file_section *section __maybe_unused,
1665 struct perf_header *ph, int fd,
1666 void *data __maybe_unused)
1667{
1668 ph->env.cpu_desc = do_read_string(fd, ph);
1669 return ph->env.cpu_desc ? 0 : -ENOMEM;
1670}
1671
1672static int process_cpuid(struct perf_file_section *section __maybe_unused,
1673 struct perf_header *ph, int fd,
1674 void *data __maybe_unused)
1675{
1676 ph->env.cpuid = do_read_string(fd, ph);
1677 return ph->env.cpuid ? 0 : -ENOMEM;
1678}
1679
1680static int process_total_mem(struct perf_file_section *section __maybe_unused,
1681 struct perf_header *ph, int fd,
1682 void *data __maybe_unused)
1683{
1684 uint64_t mem;
1685 size_t ret;
1686
1687 ret = read(fd, &mem, sizeof(mem));
1688 if (ret != sizeof(mem))
1689 return -1;
1690
1691 if (ph->needs_swap)
1692 mem = bswap_64(mem);
1693
1694 ph->env.total_mem = mem;
1695 return 0;
1696}
1697
1698static struct perf_evsel *
1699perf_evlist__find_by_index(struct perf_evlist *evlist, int idx)
1700{
1701 struct perf_evsel *evsel;
1702
1703 list_for_each_entry(evsel, &evlist->entries, node) {
1704 if (evsel->idx == idx)
1705 return evsel;
1706 }
1707
1708 return NULL;
1709}
1710
1711static void
1712perf_evlist__set_event_name(struct perf_evlist *evlist,
1713 struct perf_evsel *event)
1714{
1715 struct perf_evsel *evsel;
1716
1717 if (!event->name)
1718 return;
1719
1720 evsel = perf_evlist__find_by_index(evlist, event->idx);
1721 if (!evsel)
1722 return;
1723
1724 if (evsel->name)
1725 return;
1726
1727 evsel->name = strdup(event->name);
1728}
1729
1730static int
1731process_event_desc(struct perf_file_section *section __maybe_unused,
1732 struct perf_header *header, int fd,
1733 void *data __maybe_unused)
1734{
1735 struct perf_session *session;
1736 struct perf_evsel *evsel, *events = read_event_desc(header, fd);
1737
1738 if (!events)
1739 return 0;
1740
1741 session = container_of(header, struct perf_session, header);
1742 for (evsel = events; evsel->attr.size; evsel++)
1743 perf_evlist__set_event_name(session->evlist, evsel);
1744
1745 free_event_desc(events);
1746
1747 return 0;
1748}
1749
1750static int process_cmdline(struct perf_file_section *section __maybe_unused,
1751 struct perf_header *ph, int fd,
1752 void *data __maybe_unused)
1753{
1754 size_t ret;
1755 char *str;
1756 u32 nr, i;
1757 struct strbuf sb;
1758
1759 ret = read(fd, &nr, sizeof(nr));
1760 if (ret != sizeof(nr))
1761 return -1;
1762
1763 if (ph->needs_swap)
1764 nr = bswap_32(nr);
1765
1766 ph->env.nr_cmdline = nr;
1767 strbuf_init(&sb, 128);
1768
1769 for (i = 0; i < nr; i++) {
1770 str = do_read_string(fd, ph);
1771 if (!str)
1772 goto error;
1773
1774 /* include a NULL character at the end */
1775 strbuf_add(&sb, str, strlen(str) + 1);
1776 free(str);
1777 }
1778 ph->env.cmdline = strbuf_detach(&sb, NULL);
1779 return 0;
1780
1781error:
1782 strbuf_release(&sb);
1783 return -1;
1784}
1785
1786static int process_cpu_topology(struct perf_file_section *section __maybe_unused,
1787 struct perf_header *ph, int fd,
1788 void *data __maybe_unused)
1789{
1790 size_t ret;
1791 u32 nr, i;
1792 char *str;
1793 struct strbuf sb;
1794
1795 ret = read(fd, &nr, sizeof(nr));
1796 if (ret != sizeof(nr))
1797 return -1;
1798
1799 if (ph->needs_swap)
1800 nr = bswap_32(nr);
1801
1802 ph->env.nr_sibling_cores = nr;
1803 strbuf_init(&sb, 128);
1804
1805 for (i = 0; i < nr; i++) {
1806 str = do_read_string(fd, ph);
1807 if (!str)
1808 goto error;
1809
1810 /* include a NULL character at the end */
1811 strbuf_add(&sb, str, strlen(str) + 1);
1812 free(str);
1813 }
1814 ph->env.sibling_cores = strbuf_detach(&sb, NULL);
1815
1816 ret = read(fd, &nr, sizeof(nr));
1817 if (ret != sizeof(nr))
1818 return -1;
1819
1820 if (ph->needs_swap)
1821 nr = bswap_32(nr);
1822
1823 ph->env.nr_sibling_threads = nr;
1824
1825 for (i = 0; i < nr; i++) {
1826 str = do_read_string(fd, ph);
1827 if (!str)
1828 goto error;
1829
1830 /* include a NULL character at the end */
1831 strbuf_add(&sb, str, strlen(str) + 1);
1832 free(str);
1833 }
1834 ph->env.sibling_threads = strbuf_detach(&sb, NULL);
1835 return 0;
1836
1837error:
1838 strbuf_release(&sb);
1839 return -1;
1840}
1841
1842static int process_numa_topology(struct perf_file_section *section __maybe_unused,
1843 struct perf_header *ph, int fd,
1844 void *data __maybe_unused)
1845{
1846 size_t ret;
1847 u32 nr, node, i;
1848 char *str;
1849 uint64_t mem_total, mem_free;
1850 struct strbuf sb;
1851
1852 /* nr nodes */
1853 ret = read(fd, &nr, sizeof(nr));
1854 if (ret != sizeof(nr))
1855 goto error;
1856
1857 if (ph->needs_swap)
1858 nr = bswap_32(nr);
1859
1860 ph->env.nr_numa_nodes = nr;
1861 strbuf_init(&sb, 256);
1862
1863 for (i = 0; i < nr; i++) {
1864 /* node number */
1865 ret = read(fd, &node, sizeof(node));
1866 if (ret != sizeof(node))
1867 goto error;
1868
1869 ret = read(fd, &mem_total, sizeof(u64));
1870 if (ret != sizeof(u64))
1871 goto error;
1872
1873 ret = read(fd, &mem_free, sizeof(u64));
1874 if (ret != sizeof(u64))
1875 goto error;
1876
1877 if (ph->needs_swap) {
1878 node = bswap_32(node);
1879 mem_total = bswap_64(mem_total);
1880 mem_free = bswap_64(mem_free);
1881 }
1882
1883 strbuf_addf(&sb, "%u:%"PRIu64":%"PRIu64":",
1884 node, mem_total, mem_free);
1885
1886 str = do_read_string(fd, ph);
1887 if (!str)
1888 goto error;
1889
1890 /* include a NULL character at the end */
1891 strbuf_add(&sb, str, strlen(str) + 1);
1892 free(str);
1893 }
1894 ph->env.numa_nodes = strbuf_detach(&sb, NULL);
1895 return 0;
1896
1897error:
1898 strbuf_release(&sb);
1899 return -1;
1900}
1901
1902static int process_pmu_mappings(struct perf_file_section *section __maybe_unused,
1903 struct perf_header *ph, int fd,
1904 void *data __maybe_unused)
1905{
1906 size_t ret;
1907 char *name;
1908 u32 pmu_num;
1909 u32 type;
1910 struct strbuf sb;
1911
1912 ret = read(fd, &pmu_num, sizeof(pmu_num));
1913 if (ret != sizeof(pmu_num))
1914 return -1;
1915
1916 if (ph->needs_swap)
1917 pmu_num = bswap_32(pmu_num);
1918
1919 if (!pmu_num) {
1920 pr_debug("pmu mappings not available\n");
1921 return 0;
1922 }
1923
1924 ph->env.nr_pmu_mappings = pmu_num;
1925 strbuf_init(&sb, 128);
1926
1927 while (pmu_num) {
1928 if (read(fd, &type, sizeof(type)) != sizeof(type))
1929 goto error;
1930 if (ph->needs_swap)
1931 type = bswap_32(type);
1932
1933 name = do_read_string(fd, ph);
1934 if (!name)
1935 goto error;
1936
1937 strbuf_addf(&sb, "%u:%s", type, name);
1938 /* include a NULL character at the end */
1939 strbuf_add(&sb, "", 1);
1940
1941 free(name);
1942 pmu_num--;
1943 }
1944 ph->env.pmu_mappings = strbuf_detach(&sb, NULL);
1945 return 0;
1946
1947error:
1948 strbuf_release(&sb);
1949 return -1;
1950}
1951
1952struct feature_ops {
1953 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1954 void (*print)(struct perf_header *h, int fd, FILE *fp);
1955 int (*process)(struct perf_file_section *section,
1956 struct perf_header *h, int fd, void *data);
1957 const char *name;
1958 bool full_only;
1959};
1960
1961#define FEAT_OPA(n, func) \
1962 [n] = { .name = #n, .write = write_##func, .print = print_##func }
1963#define FEAT_OPP(n, func) \
1964 [n] = { .name = #n, .write = write_##func, .print = print_##func, \
1965 .process = process_##func }
1966#define FEAT_OPF(n, func) \
1967 [n] = { .name = #n, .write = write_##func, .print = print_##func, \
1968 .process = process_##func, .full_only = true }
1969
1970/* feature_ops not implemented: */
1971#define print_tracing_data NULL
1972#define print_build_id NULL
1973
1974static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1975 FEAT_OPP(HEADER_TRACING_DATA, tracing_data),
1976 FEAT_OPP(HEADER_BUILD_ID, build_id),
1977 FEAT_OPP(HEADER_HOSTNAME, hostname),
1978 FEAT_OPP(HEADER_OSRELEASE, osrelease),
1979 FEAT_OPP(HEADER_VERSION, version),
1980 FEAT_OPP(HEADER_ARCH, arch),
1981 FEAT_OPP(HEADER_NRCPUS, nrcpus),
1982 FEAT_OPP(HEADER_CPUDESC, cpudesc),
1983 FEAT_OPP(HEADER_CPUID, cpuid),
1984 FEAT_OPP(HEADER_TOTAL_MEM, total_mem),
1985 FEAT_OPP(HEADER_EVENT_DESC, event_desc),
1986 FEAT_OPP(HEADER_CMDLINE, cmdline),
1987 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
1988 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1989 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1990 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
1991};
1992
1993struct header_print_data {
1994 FILE *fp;
1995 bool full; /* extended list of headers */
1996};
1997
1998static int perf_file_section__fprintf_info(struct perf_file_section *section,
1999 struct perf_header *ph,
2000 int feat, int fd, void *data)
2001{
2002 struct header_print_data *hd = data;
2003
2004 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
2005 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
2006 "%d, continuing...\n", section->offset, feat);
2007 return 0;
2008 }
2009 if (feat >= HEADER_LAST_FEATURE) {
2010 pr_warning("unknown feature %d\n", feat);
2011 return 0;
2012 }
2013 if (!feat_ops[feat].print)
2014 return 0;
2015
2016 if (!feat_ops[feat].full_only || hd->full)
2017 feat_ops[feat].print(ph, fd, hd->fp);
2018 else
2019 fprintf(hd->fp, "# %s info available, use -I to display\n",
2020 feat_ops[feat].name);
2021
2022 return 0;
2023}
2024
2025int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
2026{
2027 struct header_print_data hd;
2028 struct perf_header *header = &session->header;
2029 int fd = session->fd;
2030 hd.fp = fp;
2031 hd.full = full;
2032
2033 perf_header__process_sections(header, fd, &hd,
2034 perf_file_section__fprintf_info);
2035 return 0;
2036}
2037
2038static int do_write_feat(int fd, struct perf_header *h, int type,
2039 struct perf_file_section **p,
2040 struct perf_evlist *evlist)
2041{
2042 int err;
2043 int ret = 0;
2044
2045 if (perf_header__has_feat(h, type)) {
2046 if (!feat_ops[type].write)
2047 return -1;
2048
2049 (*p)->offset = lseek(fd, 0, SEEK_CUR);
2050
2051 err = feat_ops[type].write(fd, h, evlist);
2052 if (err < 0) {
2053 pr_debug("failed to write feature %d\n", type);
2054
2055 /* undo anything written */
2056 lseek(fd, (*p)->offset, SEEK_SET);
2057
2058 return -1;
2059 }
2060 (*p)->size = lseek(fd, 0, SEEK_CUR) - (*p)->offset;
2061 (*p)++;
2062 }
2063 return ret;
2064}
2065
2066static int perf_header__adds_write(struct perf_header *header,
2067 struct perf_evlist *evlist, int fd)
2068{
2069 int nr_sections;
2070 struct perf_file_section *feat_sec, *p;
2071 int sec_size;
2072 u64 sec_start;
2073 int feat;
2074 int err;
2075
2076 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
2077 if (!nr_sections)
2078 return 0;
2079
2080 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections);
2081 if (feat_sec == NULL)
2082 return -ENOMEM;
2083
2084 sec_size = sizeof(*feat_sec) * nr_sections;
2085
2086 sec_start = header->data_offset + header->data_size;
2087 lseek(fd, sec_start + sec_size, SEEK_SET);
2088
2089 for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
2090 if (do_write_feat(fd, header, feat, &p, evlist))
2091 perf_header__clear_feat(header, feat);
2092 }
2093
2094 lseek(fd, sec_start, SEEK_SET);
2095 /*
2096 * may write more than needed due to dropped feature, but
2097 * this is okay, reader will skip the mising entries
2098 */
2099 err = do_write(fd, feat_sec, sec_size);
2100 if (err < 0)
2101 pr_debug("failed to write feature section\n");
2102 free(feat_sec);
2103 return err;
2104}
2105
2106int perf_header__write_pipe(int fd)
2107{
2108 struct perf_pipe_file_header f_header;
2109 int err;
2110
2111 f_header = (struct perf_pipe_file_header){
2112 .magic = PERF_MAGIC,
2113 .size = sizeof(f_header),
2114 };
2115
2116 err = do_write(fd, &f_header, sizeof(f_header));
2117 if (err < 0) {
2118 pr_debug("failed to write perf pipe header\n");
2119 return err;
2120 }
2121
2122 return 0;
2123}
2124
2125int perf_session__write_header(struct perf_session *session,
2126 struct perf_evlist *evlist,
2127 int fd, bool at_exit)
2128{
2129 struct perf_file_header f_header;
2130 struct perf_file_attr f_attr;
2131 struct perf_header *header = &session->header;
2132 struct perf_evsel *evsel, *pair = NULL;
2133 int err;
2134
2135 lseek(fd, sizeof(f_header), SEEK_SET);
2136
2137 if (session->evlist != evlist)
2138 pair = perf_evlist__first(session->evlist);
2139
2140 list_for_each_entry(evsel, &evlist->entries, node) {
2141 evsel->id_offset = lseek(fd, 0, SEEK_CUR);
2142 err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
2143 if (err < 0) {
2144out_err_write:
2145 pr_debug("failed to write perf header\n");
2146 return err;
2147 }
2148 if (session->evlist != evlist) {
2149 err = do_write(fd, pair->id, pair->ids * sizeof(u64));
2150 if (err < 0)
2151 goto out_err_write;
2152 evsel->ids += pair->ids;
2153 pair = perf_evsel__next(pair);
2154 }
2155 }
2156
2157 header->attr_offset = lseek(fd, 0, SEEK_CUR);
2158
2159 list_for_each_entry(evsel, &evlist->entries, node) {
2160 f_attr = (struct perf_file_attr){
2161 .attr = evsel->attr,
2162 .ids = {
2163 .offset = evsel->id_offset,
2164 .size = evsel->ids * sizeof(u64),
2165 }
2166 };
2167 err = do_write(fd, &f_attr, sizeof(f_attr));
2168 if (err < 0) {
2169 pr_debug("failed to write perf header attribute\n");
2170 return err;
2171 }
2172 }
2173
2174 header->event_offset = lseek(fd, 0, SEEK_CUR);
2175 header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
2176 if (trace_events) {
2177 err = do_write(fd, trace_events, header->event_size);
2178 if (err < 0) {
2179 pr_debug("failed to write perf header events\n");
2180 return err;
2181 }
2182 }
2183
2184 header->data_offset = lseek(fd, 0, SEEK_CUR);
2185
2186 if (at_exit) {
2187 err = perf_header__adds_write(header, evlist, fd);
2188 if (err < 0)
2189 return err;
2190 }
2191
2192 f_header = (struct perf_file_header){
2193 .magic = PERF_MAGIC,
2194 .size = sizeof(f_header),
2195 .attr_size = sizeof(f_attr),
2196 .attrs = {
2197 .offset = header->attr_offset,
2198 .size = evlist->nr_entries * sizeof(f_attr),
2199 },
2200 .data = {
2201 .offset = header->data_offset,
2202 .size = header->data_size,
2203 },
2204 .event_types = {
2205 .offset = header->event_offset,
2206 .size = header->event_size,
2207 },
2208 };
2209
2210 memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
2211
2212 lseek(fd, 0, SEEK_SET);
2213 err = do_write(fd, &f_header, sizeof(f_header));
2214 if (err < 0) {
2215 pr_debug("failed to write perf header\n");
2216 return err;
2217 }
2218 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
2219
2220 header->frozen = 1;
2221 return 0;
2222}
2223
2224static int perf_header__getbuffer64(struct perf_header *header,
2225 int fd, void *buf, size_t size)
2226{
2227 if (readn(fd, buf, size) <= 0)
2228 return -1;
2229
2230 if (header->needs_swap)
2231 mem_bswap_64(buf, size);
2232
2233 return 0;
2234}
2235
2236int perf_header__process_sections(struct perf_header *header, int fd,
2237 void *data,
2238 int (*process)(struct perf_file_section *section,
2239 struct perf_header *ph,
2240 int feat, int fd, void *data))
2241{
2242 struct perf_file_section *feat_sec, *sec;
2243 int nr_sections;
2244 int sec_size;
2245 int feat;
2246 int err;
2247
2248 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
2249 if (!nr_sections)
2250 return 0;
2251
2252 feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections);
2253 if (!feat_sec)
2254 return -1;
2255
2256 sec_size = sizeof(*feat_sec) * nr_sections;
2257
2258 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
2259
2260 err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
2261 if (err < 0)
2262 goto out_free;
2263
2264 for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) {
2265 err = process(sec++, header, feat, fd, data);
2266 if (err < 0)
2267 goto out_free;
2268 }
2269 err = 0;
2270out_free:
2271 free(feat_sec);
2272 return err;
2273}
2274
2275static const int attr_file_abi_sizes[] = {
2276 [0] = PERF_ATTR_SIZE_VER0,
2277 [1] = PERF_ATTR_SIZE_VER1,
2278 [2] = PERF_ATTR_SIZE_VER2,
2279 [3] = PERF_ATTR_SIZE_VER3,
2280 0,
2281};
2282
2283/*
2284 * In the legacy file format, the magic number is not used to encode endianness.
2285 * hdr_sz was used to encode endianness. But given that hdr_sz can vary based
2286 * on ABI revisions, we need to try all combinations for all endianness to
2287 * detect the endianness.
2288 */
2289static int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
2290{
2291 uint64_t ref_size, attr_size;
2292 int i;
2293
2294 for (i = 0 ; attr_file_abi_sizes[i]; i++) {
2295 ref_size = attr_file_abi_sizes[i]
2296 + sizeof(struct perf_file_section);
2297 if (hdr_sz != ref_size) {
2298 attr_size = bswap_64(hdr_sz);
2299 if (attr_size != ref_size)
2300 continue;
2301
2302 ph->needs_swap = true;
2303 }
2304 pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
2305 i,
2306 ph->needs_swap);
2307 return 0;
2308 }
2309 /* could not determine endianness */
2310 return -1;
2311}
2312
2313#define PERF_PIPE_HDR_VER0 16
2314
2315static const size_t attr_pipe_abi_sizes[] = {
2316 [0] = PERF_PIPE_HDR_VER0,
2317 0,
2318};
2319
2320/*
2321 * In the legacy pipe format, there is an implicit assumption that endiannesss
2322 * between host recording the samples, and host parsing the samples is the
2323 * same. This is not always the case given that the pipe output may always be
2324 * redirected into a file and analyzed on a different machine with possibly a
2325 * different endianness and perf_event ABI revsions in the perf tool itself.
2326 */
2327static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
2328{
2329 u64 attr_size;
2330 int i;
2331
2332 for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
2333 if (hdr_sz != attr_pipe_abi_sizes[i]) {
2334 attr_size = bswap_64(hdr_sz);
2335 if (attr_size != hdr_sz)
2336 continue;
2337
2338 ph->needs_swap = true;
2339 }
2340 pr_debug("Pipe ABI%d perf.data file detected\n", i);
2341 return 0;
2342 }
2343 return -1;
2344}
2345
2346bool is_perf_magic(u64 magic)
2347{
2348 if (!memcmp(&magic, __perf_magic1, sizeof(magic))
2349 || magic == __perf_magic2
2350 || magic == __perf_magic2_sw)
2351 return true;
2352
2353 return false;
2354}
2355
2356static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2357 bool is_pipe, struct perf_header *ph)
2358{
2359 int ret;
2360
2361 /* check for legacy format */
2362 ret = memcmp(&magic, __perf_magic1, sizeof(magic));
2363 if (ret == 0) {
2364 pr_debug("legacy perf.data format\n");
2365 if (is_pipe)
2366 return try_all_pipe_abis(hdr_sz, ph);
2367
2368 return try_all_file_abis(hdr_sz, ph);
2369 }
2370 /*
2371 * the new magic number serves two purposes:
2372 * - unique number to identify actual perf.data files
2373 * - encode endianness of file
2374 */
2375
2376 /* check magic number with one endianness */
2377 if (magic == __perf_magic2)
2378 return 0;
2379
2380 /* check magic number with opposite endianness */
2381 if (magic != __perf_magic2_sw)
2382 return -1;
2383
2384 ph->needs_swap = true;
2385
2386 return 0;
2387}
2388
2389int perf_file_header__read(struct perf_file_header *header,
2390 struct perf_header *ph, int fd)
2391{
2392 int ret;
2393
2394 lseek(fd, 0, SEEK_SET);
2395
2396 ret = readn(fd, header, sizeof(*header));
2397 if (ret <= 0)
2398 return -1;
2399
2400 if (check_magic_endian(header->magic,
2401 header->attr_size, false, ph) < 0) {
2402 pr_debug("magic/endian check failed\n");
2403 return -1;
2404 }
2405
2406 if (ph->needs_swap) {
2407 mem_bswap_64(header, offsetof(struct perf_file_header,
2408 adds_features));
2409 }
2410
2411 if (header->size != sizeof(*header)) {
2412 /* Support the previous format */
2413 if (header->size == offsetof(typeof(*header), adds_features))
2414 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
2415 else
2416 return -1;
2417 } else if (ph->needs_swap) {
2418 /*
2419 * feature bitmap is declared as an array of unsigned longs --
2420 * not good since its size can differ between the host that
2421 * generated the data file and the host analyzing the file.
2422 *
2423 * We need to handle endianness, but we don't know the size of
2424 * the unsigned long where the file was generated. Take a best
2425 * guess at determining it: try 64-bit swap first (ie., file
2426 * created on a 64-bit host), and check if the hostname feature
2427 * bit is set (this feature bit is forced on as of fbe96f2).
2428 * If the bit is not, undo the 64-bit swap and try a 32-bit
2429 * swap. If the hostname bit is still not set (e.g., older data
2430 * file), punt and fallback to the original behavior --
2431 * clearing all feature bits and setting buildid.
2432 */
2433 mem_bswap_64(&header->adds_features,
2434 BITS_TO_U64(HEADER_FEAT_BITS));
2435
2436 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
2437 /* unswap as u64 */
2438 mem_bswap_64(&header->adds_features,
2439 BITS_TO_U64(HEADER_FEAT_BITS));
2440
2441 /* unswap as u32 */
2442 mem_bswap_32(&header->adds_features,
2443 BITS_TO_U32(HEADER_FEAT_BITS));
2444 }
2445
2446 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
2447 bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
2448 set_bit(HEADER_BUILD_ID, header->adds_features);
2449 }
2450 }
2451
2452 memcpy(&ph->adds_features, &header->adds_features,
2453 sizeof(ph->adds_features));
2454
2455 ph->event_offset = header->event_types.offset;
2456 ph->event_size = header->event_types.size;
2457 ph->data_offset = header->data.offset;
2458 ph->data_size = header->data.size;
2459 return 0;
2460}
2461
2462static int perf_file_section__process(struct perf_file_section *section, 797static int perf_file_section__process(struct perf_file_section *section,
2463 struct perf_header *ph, 798 struct perf_header *ph,
2464 int feat, int fd, void *data) 799 int feat, int fd)
2465{ 800{
2466 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 801 if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
2467 pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 802 pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -2469,37 +804,41 @@ static int perf_file_section__process(struct perf_file_section *section,
2469 return 0; 804 return 0;
2470 } 805 }
2471 806
2472 if (feat >= HEADER_LAST_FEATURE) { 807 switch (feat) {
808 case HEADER_TRACE_INFO:
809 trace_report(fd, false);
810 break;
811
812 case HEADER_BUILD_ID:
813 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
814 pr_debug("Failed to read buildids, continuing...\n");
815 break;
816 default:
2473 pr_debug("unknown feature %d, continuing...\n", feat); 817 pr_debug("unknown feature %d, continuing...\n", feat);
2474 return 0;
2475 } 818 }
2476 819
2477 if (!feat_ops[feat].process) 820 return 0;
2478 return 0;
2479
2480 return feat_ops[feat].process(section, ph, fd, data);
2481} 821}
2482 822
2483static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, 823static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
2484 struct perf_header *ph, int fd, 824 struct perf_header *ph, int fd,
2485 bool repipe) 825 bool repipe)
2486{ 826{
2487 int ret; 827 if (readn(fd, header, sizeof(*header)) <= 0 ||
2488 828 memcmp(&header->magic, __perf_magic, sizeof(header->magic)))
2489 ret = readn(fd, header, sizeof(*header));
2490 if (ret <= 0)
2491 return -1; 829 return -1;
2492 830
2493 if (check_magic_endian(header->magic, header->size, true, ph) < 0) { 831 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0)
2494 pr_debug("endian/magic failed\n");
2495 return -1; 832 return -1;
2496 }
2497 833
2498 if (ph->needs_swap) 834 if (header->size != sizeof(*header)) {
2499 header->size = bswap_64(header->size); 835 u64 size = bswap_64(header->size);
2500 836
2501 if (repipe && do_write(STDOUT_FILENO, header, sizeof(*header)) < 0) 837 if (size != sizeof(*header))
2502 return -1; 838 return -1;
839
840 ph->needs_swap = true;
841 }
2503 842
2504 return 0; 843 return 0;
2505} 844}
@@ -2520,91 +859,6 @@ static int perf_header__read_pipe(struct perf_session *session, int fd)
2520 return 0; 859 return 0;
2521} 860}
2522 861
2523static int read_attr(int fd, struct perf_header *ph,
2524 struct perf_file_attr *f_attr)
2525{
2526 struct perf_event_attr *attr = &f_attr->attr;
2527 size_t sz, left;
2528 size_t our_sz = sizeof(f_attr->attr);
2529 int ret;
2530
2531 memset(f_attr, 0, sizeof(*f_attr));
2532
2533 /* read minimal guaranteed structure */
2534 ret = readn(fd, attr, PERF_ATTR_SIZE_VER0);
2535 if (ret <= 0) {
2536 pr_debug("cannot read %d bytes of header attr\n",
2537 PERF_ATTR_SIZE_VER0);
2538 return -1;
2539 }
2540
2541 /* on file perf_event_attr size */
2542 sz = attr->size;
2543
2544 if (ph->needs_swap)
2545 sz = bswap_32(sz);
2546
2547 if (sz == 0) {
2548 /* assume ABI0 */
2549 sz = PERF_ATTR_SIZE_VER0;
2550 } else if (sz > our_sz) {
2551 pr_debug("file uses a more recent and unsupported ABI"
2552 " (%zu bytes extra)\n", sz - our_sz);
2553 return -1;
2554 }
2555 /* what we have not yet read and that we know about */
2556 left = sz - PERF_ATTR_SIZE_VER0;
2557 if (left) {
2558 void *ptr = attr;
2559 ptr += PERF_ATTR_SIZE_VER0;
2560
2561 ret = readn(fd, ptr, left);
2562 }
2563 /* read perf_file_section, ids are read in caller */
2564 ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids));
2565
2566 return ret <= 0 ? -1 : 0;
2567}
2568
2569static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
2570 struct pevent *pevent)
2571{
2572 struct event_format *event;
2573 char bf[128];
2574
2575 /* already prepared */
2576 if (evsel->tp_format)
2577 return 0;
2578
2579 event = pevent_find_event(pevent, evsel->attr.config);
2580 if (event == NULL)
2581 return -1;
2582
2583 if (!evsel->name) {
2584 snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
2585 evsel->name = strdup(bf);
2586 if (evsel->name == NULL)
2587 return -1;
2588 }
2589
2590 evsel->tp_format = event;
2591 return 0;
2592}
2593
2594static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2595 struct pevent *pevent)
2596{
2597 struct perf_evsel *pos;
2598
2599 list_for_each_entry(pos, &evlist->entries, node) {
2600 if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
2601 perf_evsel__prepare_tracepoint_event(pos, pevent))
2602 return -1;
2603 }
2604
2605 return 0;
2606}
2607
2608int perf_session__read_header(struct perf_session *session, int fd) 862int perf_session__read_header(struct perf_session *session, int fd)
2609{ 863{
2610 struct perf_header *header = &session->header; 864 struct perf_header *header = &session->header;
@@ -2620,17 +874,19 @@ int perf_session__read_header(struct perf_session *session, int fd)
2620 if (session->fd_pipe) 874 if (session->fd_pipe)
2621 return perf_header__read_pipe(session, fd); 875 return perf_header__read_pipe(session, fd);
2622 876
2623 if (perf_file_header__read(&f_header, header, fd) < 0) 877 if (perf_file_header__read(&f_header, header, fd) < 0) {
878 pr_debug("incompatible file format\n");
2624 return -EINVAL; 879 return -EINVAL;
880 }
2625 881
2626 nr_attrs = f_header.attrs.size / f_header.attr_size; 882 nr_attrs = f_header.attrs.size / sizeof(f_attr);
2627 lseek(fd, f_header.attrs.offset, SEEK_SET); 883 lseek(fd, f_header.attrs.offset, SEEK_SET);
2628 884
2629 for (i = 0; i < nr_attrs; i++) { 885 for (i = 0; i < nr_attrs; i++) {
2630 struct perf_evsel *evsel; 886 struct perf_evsel *evsel;
2631 off_t tmp; 887 off_t tmp;
2632 888
2633 if (read_attr(fd, header, &f_attr) < 0) 889 if (readn(fd, &f_attr, sizeof(f_attr)) <= 0)
2634 goto out_errno; 890 goto out_errno;
2635 891
2636 if (header->needs_swap) 892 if (header->needs_swap)
@@ -2641,8 +897,6 @@ int perf_session__read_header(struct perf_session *session, int fd)
2641 897
2642 if (evsel == NULL) 898 if (evsel == NULL)
2643 goto out_delete_evlist; 899 goto out_delete_evlist;
2644
2645 evsel->needs_swap = header->needs_swap;
2646 /* 900 /*
2647 * Do it before so that if perf_evsel__alloc_id fails, this 901 * Do it before so that if perf_evsel__alloc_id fails, this
2648 * entry gets purged too at perf_evlist__delete(). 902 * entry gets purged too at perf_evlist__delete().
@@ -2670,28 +924,21 @@ int perf_session__read_header(struct perf_session *session, int fd)
2670 lseek(fd, tmp, SEEK_SET); 924 lseek(fd, tmp, SEEK_SET);
2671 } 925 }
2672 926
2673 symbol_conf.nr_events = nr_attrs;
2674
2675 if (f_header.event_types.size) { 927 if (f_header.event_types.size) {
2676 lseek(fd, f_header.event_types.offset, SEEK_SET); 928 lseek(fd, f_header.event_types.offset, SEEK_SET);
2677 trace_events = malloc(f_header.event_types.size); 929 events = malloc(f_header.event_types.size);
2678 if (trace_events == NULL) 930 if (events == NULL)
2679 return -ENOMEM; 931 return -ENOMEM;
2680 if (perf_header__getbuffer64(header, fd, trace_events, 932 if (perf_header__getbuffer64(header, fd, events,
2681 f_header.event_types.size)) 933 f_header.event_types.size))
2682 goto out_errno; 934 goto out_errno;
2683 trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 935 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
2684 } 936 }
2685 937
2686 perf_header__process_sections(header, fd, &session->pevent, 938 perf_header__process_sections(header, fd, perf_file_section__process);
2687 perf_file_section__process);
2688 939
2689 lseek(fd, header->data_offset, SEEK_SET); 940 lseek(fd, header->data_offset, SEEK_SET);
2690 941
2691 if (perf_evlist__prepare_tracepoint_events(session->evlist,
2692 session->pevent))
2693 goto out_delete_evlist;
2694
2695 header->frozen = 1; 942 header->frozen = 1;
2696 return 0; 943 return 0;
2697out_errno: 944out_errno:
@@ -2703,16 +950,16 @@ out_delete_evlist:
2703 return -ENOMEM; 950 return -ENOMEM;
2704} 951}
2705 952
2706int perf_event__synthesize_attr(struct perf_tool *tool, 953int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
2707 struct perf_event_attr *attr, u32 ids, u64 *id, 954 perf_event__handler_t process,
2708 perf_event__handler_t process) 955 struct perf_session *session)
2709{ 956{
2710 union perf_event *ev; 957 union perf_event *ev;
2711 size_t size; 958 size_t size;
2712 int err; 959 int err;
2713 960
2714 size = sizeof(struct perf_event_attr); 961 size = sizeof(struct perf_event_attr);
2715 size = PERF_ALIGN(size, sizeof(u64)); 962 size = ALIGN(size, sizeof(u64));
2716 size += sizeof(struct perf_event_header); 963 size += sizeof(struct perf_event_header);
2717 size += ids * sizeof(u64); 964 size += ids * sizeof(u64);
2718 965
@@ -2725,28 +972,24 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
2725 memcpy(ev->attr.id, id, ids * sizeof(u64)); 972 memcpy(ev->attr.id, id, ids * sizeof(u64));
2726 973
2727 ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 974 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
2728 ev->attr.header.size = (u16)size; 975 ev->attr.header.size = size;
2729 976
2730 if (ev->attr.header.size == size) 977 err = process(ev, NULL, session);
2731 err = process(tool, ev, NULL, NULL);
2732 else
2733 err = -E2BIG;
2734 978
2735 free(ev); 979 free(ev);
2736 980
2737 return err; 981 return err;
2738} 982}
2739 983
2740int perf_event__synthesize_attrs(struct perf_tool *tool, 984int perf_session__synthesize_attrs(struct perf_session *session,
2741 struct perf_session *session,
2742 perf_event__handler_t process) 985 perf_event__handler_t process)
2743{ 986{
2744 struct perf_evsel *evsel; 987 struct perf_evsel *attr;
2745 int err = 0; 988 int err = 0;
2746 989
2747 list_for_each_entry(evsel, &session->evlist->entries, node) { 990 list_for_each_entry(attr, &session->evlist->entries, node) {
2748 err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, 991 err = perf_event__synthesize_attr(&attr->attr, attr->ids,
2749 evsel->id, process); 992 attr->id, process, session);
2750 if (err) { 993 if (err) {
2751 pr_debug("failed to create perf header attribute\n"); 994 pr_debug("failed to create perf header attribute\n");
2752 return err; 995 return err;
@@ -2757,23 +1000,23 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
2757} 1000}
2758 1001
2759int perf_event__process_attr(union perf_event *event, 1002int perf_event__process_attr(union perf_event *event,
2760 struct perf_evlist **pevlist) 1003 struct perf_session *session)
2761{ 1004{
2762 u32 i, ids, n_ids; 1005 unsigned int i, ids, n_ids;
2763 struct perf_evsel *evsel; 1006 struct perf_evsel *evsel;
2764 struct perf_evlist *evlist = *pevlist;
2765 1007
2766 if (evlist == NULL) { 1008 if (session->evlist == NULL) {
2767 *pevlist = evlist = perf_evlist__new(NULL, NULL); 1009 session->evlist = perf_evlist__new(NULL, NULL);
2768 if (evlist == NULL) 1010 if (session->evlist == NULL)
2769 return -ENOMEM; 1011 return -ENOMEM;
2770 } 1012 }
2771 1013
2772 evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries); 1014 evsel = perf_evsel__new(&event->attr.attr,
1015 session->evlist->nr_entries);
2773 if (evsel == NULL) 1016 if (evsel == NULL)
2774 return -ENOMEM; 1017 return -ENOMEM;
2775 1018
2776 perf_evlist__add(evlist, evsel); 1019 perf_evlist__add(session->evlist, evsel);
2777 1020
2778 ids = event->header.size; 1021 ids = event->header.size;
2779 ids -= (void *)&event->attr.id - (void *)event; 1022 ids -= (void *)&event->attr.id - (void *)event;
@@ -2787,16 +1030,18 @@ int perf_event__process_attr(union perf_event *event,
2787 return -ENOMEM; 1030 return -ENOMEM;
2788 1031
2789 for (i = 0; i < n_ids; i++) { 1032 for (i = 0; i < n_ids; i++) {
2790 perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); 1033 perf_evlist__id_add(session->evlist, evsel, 0, i,
1034 event->attr.id[i]);
2791 } 1035 }
2792 1036
1037 perf_session__update_sample_type(session);
1038
2793 return 0; 1039 return 0;
2794} 1040}
2795 1041
2796int perf_event__synthesize_event_type(struct perf_tool *tool, 1042int perf_event__synthesize_event_type(u64 event_id, char *name,
2797 u64 event_id, char *name,
2798 perf_event__handler_t process, 1043 perf_event__handler_t process,
2799 struct machine *machine) 1044 struct perf_session *session)
2800{ 1045{
2801 union perf_event ev; 1046 union perf_event ev;
2802 size_t size = 0; 1047 size_t size = 0;
@@ -2809,29 +1054,28 @@ int perf_event__synthesize_event_type(struct perf_tool *tool,
2809 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1); 1054 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
2810 1055
2811 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE; 1056 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
2812 size = strlen(ev.event_type.event_type.name); 1057 size = strlen(name);
2813 size = PERF_ALIGN(size, sizeof(u64)); 1058 size = ALIGN(size, sizeof(u64));
2814 ev.event_type.header.size = sizeof(ev.event_type) - 1059 ev.event_type.header.size = sizeof(ev.event_type) -
2815 (sizeof(ev.event_type.event_type.name) - size); 1060 (sizeof(ev.event_type.event_type.name) - size);
2816 1061
2817 err = process(tool, &ev, NULL, machine); 1062 err = process(&ev, NULL, session);
2818 1063
2819 return err; 1064 return err;
2820} 1065}
2821 1066
2822int perf_event__synthesize_event_types(struct perf_tool *tool, 1067int perf_event__synthesize_event_types(perf_event__handler_t process,
2823 perf_event__handler_t process, 1068 struct perf_session *session)
2824 struct machine *machine)
2825{ 1069{
2826 struct perf_trace_event_type *type; 1070 struct perf_trace_event_type *type;
2827 int i, err = 0; 1071 int i, err = 0;
2828 1072
2829 for (i = 0; i < trace_event_count; i++) { 1073 for (i = 0; i < event_count; i++) {
2830 type = &trace_events[i]; 1074 type = &events[i];
2831 1075
2832 err = perf_event__synthesize_event_type(tool, type->event_id, 1076 err = perf_event__synthesize_event_type(type->event_id,
2833 type->name, process, 1077 type->name, process,
2834 machine); 1078 session);
2835 if (err) { 1079 if (err) {
2836 pr_debug("failed to create perf header event type\n"); 1080 pr_debug("failed to create perf header event type\n");
2837 return err; 1081 return err;
@@ -2841,8 +1085,8 @@ int perf_event__synthesize_event_types(struct perf_tool *tool,
2841 return err; 1085 return err;
2842} 1086}
2843 1087
2844int perf_event__process_event_type(struct perf_tool *tool __maybe_unused, 1088int perf_event__process_event_type(union perf_event *event,
2845 union perf_event *event) 1089 struct perf_session *session __unused)
2846{ 1090{
2847 if (perf_header__push_event(event->event_type.event_type.event_id, 1091 if (perf_header__push_event(event->event_type.event_type.event_id,
2848 event->event_type.event_type.name) < 0) 1092 event->event_type.event_type.name) < 0)
@@ -2851,47 +1095,28 @@ int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
2851 return 0; 1095 return 0;
2852} 1096}
2853 1097
2854int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, 1098int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
2855 struct perf_evlist *evlist, 1099 perf_event__handler_t process,
2856 perf_event__handler_t process) 1100 struct perf_session *session __unused)
2857{ 1101{
2858 union perf_event ev; 1102 union perf_event ev;
2859 struct tracing_data *tdata;
2860 ssize_t size = 0, aligned_size = 0, padding; 1103 ssize_t size = 0, aligned_size = 0, padding;
2861 int err __maybe_unused = 0; 1104 int err __used = 0;
2862
2863 /*
2864 * We are going to store the size of the data followed
2865 * by the data contents. Since the fd descriptor is a pipe,
2866 * we cannot seek back to store the size of the data once
2867 * we know it. Instead we:
2868 *
2869 * - write the tracing data to the temp file
2870 * - get/write the data size to pipe
2871 * - write the tracing data from the temp file
2872 * to the pipe
2873 */
2874 tdata = tracing_data_get(&evlist->entries, fd, true);
2875 if (!tdata)
2876 return -1;
2877 1105
2878 memset(&ev, 0, sizeof(ev)); 1106 memset(&ev, 0, sizeof(ev));
2879 1107
2880 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; 1108 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
2881 size = tdata->size; 1109 size = read_tracing_data_size(fd, &evlist->entries);
2882 aligned_size = PERF_ALIGN(size, sizeof(u64)); 1110 if (size <= 0)
1111 return size;
1112 aligned_size = ALIGN(size, sizeof(u64));
2883 padding = aligned_size - size; 1113 padding = aligned_size - size;
2884 ev.tracing_data.header.size = sizeof(ev.tracing_data); 1114 ev.tracing_data.header.size = sizeof(ev.tracing_data);
2885 ev.tracing_data.size = aligned_size; 1115 ev.tracing_data.size = aligned_size;
2886 1116
2887 process(tool, &ev, NULL, NULL); 1117 process(&ev, NULL, session);
2888
2889 /*
2890 * The put function will copy all the tracing data
2891 * stored in temp file to the pipe.
2892 */
2893 tracing_data_put(tdata);
2894 1118
1119 err = read_tracing_data(fd, &evlist->entries);
2895 write_padded(fd, NULL, 0, padding); 1120 write_padded(fd, NULL, 0, padding);
2896 1121
2897 return aligned_size; 1122 return aligned_size;
@@ -2908,9 +1133,9 @@ int perf_event__process_tracing_data(union perf_event *event,
2908 lseek(session->fd, offset + sizeof(struct tracing_data_event), 1133 lseek(session->fd, offset + sizeof(struct tracing_data_event),
2909 SEEK_SET); 1134 SEEK_SET);
2910 1135
2911 size_read = trace_report(session->fd, &session->pevent, 1136 size_read = trace_report(session->fd, session->repipe);
2912 session->repipe); 1137
2913 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 1138 padding = ALIGN(size_read, sizeof(u64)) - size_read;
2914 1139
2915 if (read(session->fd, buf, padding) < 0) 1140 if (read(session->fd, buf, padding) < 0)
2916 die("reading input file"); 1141 die("reading input file");
@@ -2923,16 +1148,13 @@ int perf_event__process_tracing_data(union perf_event *event,
2923 if (size_read + padding != size) 1148 if (size_read + padding != size)
2924 die("tracing data size mismatch"); 1149 die("tracing data size mismatch");
2925 1150
2926 perf_evlist__prepare_tracepoint_events(session->evlist,
2927 session->pevent);
2928
2929 return size_read + padding; 1151 return size_read + padding;
2930} 1152}
2931 1153
2932int perf_event__synthesize_build_id(struct perf_tool *tool, 1154int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
2933 struct dso *pos, u16 misc,
2934 perf_event__handler_t process, 1155 perf_event__handler_t process,
2935 struct machine *machine) 1156 struct machine *machine,
1157 struct perf_session *session)
2936{ 1158{
2937 union perf_event ev; 1159 union perf_event ev;
2938 size_t len; 1160 size_t len;
@@ -2944,7 +1166,7 @@ int perf_event__synthesize_build_id(struct perf_tool *tool,
2944 memset(&ev, 0, sizeof(ev)); 1166 memset(&ev, 0, sizeof(ev));
2945 1167
2946 len = pos->long_name_len + 1; 1168 len = pos->long_name_len + 1;
2947 len = PERF_ALIGN(len, NAME_ALIGN); 1169 len = ALIGN(len, NAME_ALIGN);
2948 memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); 1170 memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
2949 ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; 1171 ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
2950 ev.build_id.header.misc = misc; 1172 ev.build_id.header.misc = misc;
@@ -2952,13 +1174,12 @@ int perf_event__synthesize_build_id(struct perf_tool *tool,
2952 ev.build_id.header.size = sizeof(ev.build_id) + len; 1174 ev.build_id.header.size = sizeof(ev.build_id) + len;
2953 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 1175 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
2954 1176
2955 err = process(tool, &ev, NULL, machine); 1177 err = process(&ev, NULL, session);
2956 1178
2957 return err; 1179 return err;
2958} 1180}
2959 1181
2960int perf_event__process_build_id(struct perf_tool *tool __maybe_unused, 1182int perf_event__process_build_id(union perf_event *event,
2961 union perf_event *event,
2962 struct perf_session *session) 1183 struct perf_session *session)
2963{ 1184{
2964 __event_process_build_id(&event->build_id, 1185 __event_process_build_id(&event->build_id,
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 20f0344accb..1886256768a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_HEADER_H 1#ifndef __PERF_HEADER_H
2#define __PERF_HEADER_H 2#define __PERF_HEADER_H
3 3
4#include <linux/perf_event.h> 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
@@ -10,29 +10,13 @@
10#include <linux/bitmap.h> 10#include <linux/bitmap.h>
11 11
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_TRACE_INFO = 1,
14 HEADER_FIRST_FEATURE = 1,
15 HEADER_TRACING_DATA = 1,
16 HEADER_BUILD_ID, 14 HEADER_BUILD_ID,
17
18 HEADER_HOSTNAME,
19 HEADER_OSRELEASE,
20 HEADER_VERSION,
21 HEADER_ARCH,
22 HEADER_NRCPUS,
23 HEADER_CPUDESC,
24 HEADER_CPUID,
25 HEADER_TOTAL_MEM,
26 HEADER_CMDLINE,
27 HEADER_EVENT_DESC,
28 HEADER_CPU_TOPOLOGY,
29 HEADER_NUMA_TOPOLOGY,
30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS,
32 HEADER_LAST_FEATURE, 15 HEADER_LAST_FEATURE,
33 HEADER_FEAT_BITS = 256,
34}; 16};
35 17
18#define HEADER_FEAT_BITS 256
19
36struct perf_file_section { 20struct perf_file_section {
37 u64 offset; 21 u64 offset;
38 u64 size; 22 u64 size;
@@ -58,29 +42,6 @@ struct perf_header;
58int perf_file_header__read(struct perf_file_header *header, 42int perf_file_header__read(struct perf_file_header *header,
59 struct perf_header *ph, int fd); 43 struct perf_header *ph, int fd);
60 44
61struct perf_session_env {
62 char *hostname;
63 char *os_release;
64 char *version;
65 char *arch;
66 int nr_cpus_online;
67 int nr_cpus_avail;
68 char *cpu_desc;
69 char *cpuid;
70 unsigned long long total_mem;
71
72 int nr_cmdline;
73 char *cmdline;
74 int nr_sibling_cores;
75 char *sibling_cores;
76 int nr_sibling_threads;
77 char *sibling_threads;
78 int nr_numa_nodes;
79 char *numa_nodes;
80 int nr_pmu_mappings;
81 char *pmu_mappings;
82};
83
84struct perf_header { 45struct perf_header {
85 int frozen; 46 int frozen;
86 bool needs_swap; 47 bool needs_swap;
@@ -90,11 +51,9 @@ struct perf_header {
90 u64 event_offset; 51 u64 event_offset;
91 u64 event_size; 52 u64 event_size;
92 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 53 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
93 struct perf_session_env env;
94}; 54};
95 55
96struct perf_evlist; 56struct perf_evlist;
97struct perf_session;
98 57
99int perf_session__read_header(struct perf_session *session, int fd); 58int perf_session__read_header(struct perf_session *session, int fd);
100int perf_session__write_header(struct perf_session *session, 59int perf_session__write_header(struct perf_session *session,
@@ -109,56 +68,40 @@ void perf_header__set_feat(struct perf_header *header, int feat);
109void perf_header__clear_feat(struct perf_header *header, int feat); 68void perf_header__clear_feat(struct perf_header *header, int feat);
110bool perf_header__has_feat(const struct perf_header *header, int feat); 69bool perf_header__has_feat(const struct perf_header *header, int feat);
111 70
112int perf_header__set_cmdline(int argc, const char **argv);
113
114int perf_header__process_sections(struct perf_header *header, int fd, 71int perf_header__process_sections(struct perf_header *header, int fd,
115 void *data,
116 int (*process)(struct perf_file_section *section, 72 int (*process)(struct perf_file_section *section,
117 struct perf_header *ph, 73 struct perf_header *ph,
118 int feat, int fd, void *data)); 74 int feat, int fd));
119
120int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
121 75
122int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, 76int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
123 const char *name, bool is_kallsyms, bool is_vdso); 77 const char *name, bool is_kallsyms);
124int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 78int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
125 79
126int perf_event__synthesize_attr(struct perf_tool *tool, 80int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
127 struct perf_event_attr *attr, u32 ids, u64 *id, 81 perf_event__handler_t process,
128 perf_event__handler_t process); 82 struct perf_session *session);
129int perf_event__synthesize_attrs(struct perf_tool *tool, 83int perf_session__synthesize_attrs(struct perf_session *session,
130 struct perf_session *session, 84 perf_event__handler_t process);
131 perf_event__handler_t process); 85int perf_event__process_attr(union perf_event *event, struct perf_session *session);
132int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
133 86
134int perf_event__synthesize_event_type(struct perf_tool *tool, 87int perf_event__synthesize_event_type(u64 event_id, char *name,
135 u64 event_id, char *name,
136 perf_event__handler_t process, 88 perf_event__handler_t process,
137 struct machine *machine); 89 struct perf_session *session);
138int perf_event__synthesize_event_types(struct perf_tool *tool, 90int perf_event__synthesize_event_types(perf_event__handler_t process,
139 perf_event__handler_t process, 91 struct perf_session *session);
140 struct machine *machine); 92int perf_event__process_event_type(union perf_event *event,
141int perf_event__process_event_type(struct perf_tool *tool, 93 struct perf_session *session);
142 union perf_event *event); 94
143 95int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
144int perf_event__synthesize_tracing_data(struct perf_tool *tool, 96 perf_event__handler_t process,
145 int fd, struct perf_evlist *evlist, 97 struct perf_session *session);
146 perf_event__handler_t process);
147int perf_event__process_tracing_data(union perf_event *event, 98int perf_event__process_tracing_data(union perf_event *event,
148 struct perf_session *session); 99 struct perf_session *session);
149 100
150int perf_event__synthesize_build_id(struct perf_tool *tool, 101int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
151 struct dso *pos, u16 misc,
152 perf_event__handler_t process, 102 perf_event__handler_t process,
153 struct machine *machine); 103 struct machine *machine,
154int perf_event__process_build_id(struct perf_tool *tool, 104 struct perf_session *session);
155 union perf_event *event, 105int perf_event__process_build_id(union perf_event *event,
156 struct perf_session *session); 106 struct perf_session *session);
157bool is_perf_magic(u64 magic);
158
159/*
160 * arch specific callback
161 */
162int get_cpuid(char *buffer, size_t sz);
163
164#endif /* __PERF_HEADER_H */ 107#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index 8b1f6e891b8..6f2975a0035 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -3,7 +3,6 @@
3#include "exec_cmd.h" 3#include "exec_cmd.h"
4#include "levenshtein.h" 4#include "levenshtein.h"
5#include "help.h" 5#include "help.h"
6#include <termios.h>
7 6
8void add_cmdname(struct cmdnames *cmds, const char *name, size_t len) 7void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
9{ 8{
@@ -332,8 +331,7 @@ const char *help_unknown_cmd(const char *cmd)
332 exit(1); 331 exit(1);
333} 332}
334 333
335int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused, 334int cmd_version(int argc __used, const char **argv __used, const char *prefix __used)
336 const char *prefix __maybe_unused)
337{ 335{
338 printf("perf version %s\n", perf_version_string); 336 printf("perf version %s\n", perf_version_string);
339 return 0; 337 return 0;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index cb17e2a8c6e..677e1da6bb3 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -6,18 +6,10 @@
6#include "sort.h" 6#include "sort.h"
7#include <math.h> 7#include <math.h>
8 8
9static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he);
13static bool hists__filter_entry_by_symbol(struct hists *hists,
14 struct hist_entry *he);
15
16enum hist_filter { 9enum hist_filter {
17 HIST_FILTER__DSO, 10 HIST_FILTER__DSO,
18 HIST_FILTER__THREAD, 11 HIST_FILTER__THREAD,
19 HIST_FILTER__PARENT, 12 HIST_FILTER__PARENT,
20 HIST_FILTER__SYMBOL,
21}; 13};
22 14
23struct callchain_param callchain_param = { 15struct callchain_param callchain_param = {
@@ -26,208 +18,80 @@ struct callchain_param callchain_param = {
26 .order = ORDER_CALLEE 18 .order = ORDER_CALLEE
27}; 19};
28 20
29u16 hists__col_len(struct hists *hists, enum hist_column col) 21u16 hists__col_len(struct hists *self, enum hist_column col)
30{ 22{
31 return hists->col_len[col]; 23 return self->col_len[col];
32} 24}
33 25
34void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len) 26void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
35{ 27{
36 hists->col_len[col] = len; 28 self->col_len[col] = len;
37} 29}
38 30
39bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len) 31bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
40{ 32{
41 if (len > hists__col_len(hists, col)) { 33 if (len > hists__col_len(self, col)) {
42 hists__set_col_len(hists, col, len); 34 hists__set_col_len(self, col, len);
43 return true; 35 return true;
44 } 36 }
45 return false; 37 return false;
46} 38}
47 39
48void hists__reset_col_len(struct hists *hists) 40static void hists__reset_col_len(struct hists *self)
49{ 41{
50 enum hist_column col; 42 enum hist_column col;
51 43
52 for (col = 0; col < HISTC_NR_COLS; ++col) 44 for (col = 0; col < HISTC_NR_COLS; ++col)
53 hists__set_col_len(hists, col, 0); 45 hists__set_col_len(self, col, 0);
54}
55
56static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
57{
58 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
59
60 if (hists__col_len(hists, dso) < unresolved_col_width &&
61 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
62 !symbol_conf.dso_list)
63 hists__set_col_len(hists, dso, unresolved_col_width);
64} 46}
65 47
66void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 48static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
67{ 49{
68 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
69 u16 len; 50 u16 len;
70 51
71 if (h->ms.sym) 52 if (h->ms.sym)
72 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); 53 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
73 else 54 else {
74 hists__set_unres_dso_col_len(hists, HISTC_DSO); 55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
56
57 if (hists__col_len(self, HISTC_DSO) < unresolved_col_width &&
58 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
59 !symbol_conf.dso_list)
60 hists__set_col_len(self, HISTC_DSO,
61 unresolved_col_width);
62 }
75 63
76 len = thread__comm_len(h->thread); 64 len = thread__comm_len(h->thread);
77 if (hists__new_col_len(hists, HISTC_COMM, len)) 65 if (hists__new_col_len(self, HISTC_COMM, len))
78 hists__set_col_len(hists, HISTC_THREAD, len + 6); 66 hists__set_col_len(self, HISTC_THREAD, len + 6);
79 67
80 if (h->ms.map) { 68 if (h->ms.map) {
81 len = dso__name_len(h->ms.map->dso); 69 len = dso__name_len(h->ms.map->dso);
82 hists__new_col_len(hists, HISTC_DSO, len); 70 hists__new_col_len(self, HISTC_DSO, len);
83 }
84
85 if (h->branch_info) {
86 int symlen;
87 /*
88 * +4 accounts for '[x] ' priv level info
89 * +2 account of 0x prefix on raw addresses
90 */
91 if (h->branch_info->from.sym) {
92 symlen = (int)h->branch_info->from.sym->namelen + 4;
93 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
94
95 symlen = dso__name_len(h->branch_info->from.map->dso);
96 hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
97 } else {
98 symlen = unresolved_col_width + 4 + 2;
99 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
100 hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
101 }
102
103 if (h->branch_info->to.sym) {
104 symlen = (int)h->branch_info->to.sym->namelen + 4;
105 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
106
107 symlen = dso__name_len(h->branch_info->to.map->dso);
108 hists__new_col_len(hists, HISTC_DSO_TO, symlen);
109 } else {
110 symlen = unresolved_col_width + 4 + 2;
111 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
112 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
113 }
114 }
115}
116
117void hists__output_recalc_col_len(struct hists *hists, int max_rows)
118{
119 struct rb_node *next = rb_first(&hists->entries);
120 struct hist_entry *n;
121 int row = 0;
122
123 hists__reset_col_len(hists);
124
125 while (next && row++ < max_rows) {
126 n = rb_entry(next, struct hist_entry, rb_node);
127 if (!n->filtered)
128 hists__calc_col_len(hists, n);
129 next = rb_next(&n->rb_node);
130 } 71 }
131} 72}
132 73
133static void hist_entry__add_cpumode_period(struct hist_entry *he, 74static void hist_entry__add_cpumode_period(struct hist_entry *self,
134 unsigned int cpumode, u64 period) 75 unsigned int cpumode, u64 period)
135{ 76{
136 switch (cpumode) { 77 switch (cpumode) {
137 case PERF_RECORD_MISC_KERNEL: 78 case PERF_RECORD_MISC_KERNEL:
138 he->stat.period_sys += period; 79 self->period_sys += period;
139 break; 80 break;
140 case PERF_RECORD_MISC_USER: 81 case PERF_RECORD_MISC_USER:
141 he->stat.period_us += period; 82 self->period_us += period;
142 break; 83 break;
143 case PERF_RECORD_MISC_GUEST_KERNEL: 84 case PERF_RECORD_MISC_GUEST_KERNEL:
144 he->stat.period_guest_sys += period; 85 self->period_guest_sys += period;
145 break; 86 break;
146 case PERF_RECORD_MISC_GUEST_USER: 87 case PERF_RECORD_MISC_GUEST_USER:
147 he->stat.period_guest_us += period; 88 self->period_guest_us += period;
148 break; 89 break;
149 default: 90 default:
150 break; 91 break;
151 } 92 }
152} 93}
153 94
154static void he_stat__add_period(struct he_stat *he_stat, u64 period)
155{
156 he_stat->period += period;
157 he_stat->nr_events += 1;
158}
159
160static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
161{
162 dest->period += src->period;
163 dest->period_sys += src->period_sys;
164 dest->period_us += src->period_us;
165 dest->period_guest_sys += src->period_guest_sys;
166 dest->period_guest_us += src->period_guest_us;
167 dest->nr_events += src->nr_events;
168}
169
170static void hist_entry__decay(struct hist_entry *he)
171{
172 he->stat.period = (he->stat.period * 7) / 8;
173 he->stat.nr_events = (he->stat.nr_events * 7) / 8;
174}
175
176static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
177{
178 u64 prev_period = he->stat.period;
179
180 if (prev_period == 0)
181 return true;
182
183 hist_entry__decay(he);
184
185 if (!he->filtered)
186 hists->stats.total_period -= prev_period - he->stat.period;
187
188 return he->stat.period == 0;
189}
190
191static void __hists__decay_entries(struct hists *hists, bool zap_user,
192 bool zap_kernel, bool threaded)
193{
194 struct rb_node *next = rb_first(&hists->entries);
195 struct hist_entry *n;
196
197 while (next) {
198 n = rb_entry(next, struct hist_entry, rb_node);
199 next = rb_next(&n->rb_node);
200 /*
201 * We may be annotating this, for instance, so keep it here in
202 * case some it gets new samples, we'll eventually free it when
203 * the user stops browsing and it agains gets fully decayed.
204 */
205 if (((zap_user && n->level == '.') ||
206 (zap_kernel && n->level != '.') ||
207 hists__decay_entry(hists, n)) &&
208 !n->used) {
209 rb_erase(&n->rb_node, &hists->entries);
210
211 if (sort__need_collapse || threaded)
212 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
213
214 hist_entry__free(n);
215 --hists->nr_entries;
216 }
217 }
218}
219
220void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
221{
222 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
223}
224
225void hists__decay_entries_threaded(struct hists *hists,
226 bool zap_user, bool zap_kernel)
227{
228 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
229}
230
231/* 95/*
232 * histogram, sorted on item, collects periods 96 * histogram, sorted on item, collects periods
233 */ 97 */
@@ -235,28 +99,25 @@ void hists__decay_entries_threaded(struct hists *hists,
235static struct hist_entry *hist_entry__new(struct hist_entry *template) 99static struct hist_entry *hist_entry__new(struct hist_entry *template)
236{ 100{
237 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 101 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
238 struct hist_entry *he = malloc(sizeof(*he) + callchain_size); 102 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
239 103
240 if (he != NULL) { 104 if (self != NULL) {
241 *he = *template; 105 *self = *template;
242 106 self->nr_events = 1;
243 if (he->ms.map) 107 if (self->ms.map)
244 he->ms.map->referenced = true; 108 self->ms.map->referenced = true;
245 if (symbol_conf.use_callchain) 109 if (symbol_conf.use_callchain)
246 callchain_init(he->callchain); 110 callchain_init(self->callchain);
247
248 INIT_LIST_HEAD(&he->pairs.node);
249 } 111 }
250 112
251 return he; 113 return self;
252} 114}
253 115
254static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) 116static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
255{ 117{
256 if (!h->filtered) { 118 if (!h->filtered) {
257 hists__calc_col_len(hists, h); 119 hists__calc_col_len(self, h);
258 ++hists->nr_entries; 120 ++self->nr_entries;
259 hists->stats.total_period += h->stat.period;
260 } 121 }
261} 122}
262 123
@@ -267,40 +128,37 @@ static u8 symbol__parent_filter(const struct symbol *parent)
267 return 0; 128 return 0;
268} 129}
269 130
270static struct hist_entry *add_hist_entry(struct hists *hists, 131struct hist_entry *__hists__add_entry(struct hists *self,
271 struct hist_entry *entry,
272 struct addr_location *al, 132 struct addr_location *al,
273 u64 period) 133 struct symbol *sym_parent, u64 period)
274{ 134{
275 struct rb_node **p; 135 struct rb_node **p = &self->entries.rb_node;
276 struct rb_node *parent = NULL; 136 struct rb_node *parent = NULL;
277 struct hist_entry *he; 137 struct hist_entry *he;
138 struct hist_entry entry = {
139 .thread = al->thread,
140 .ms = {
141 .map = al->map,
142 .sym = al->sym,
143 },
144 .cpu = al->cpu,
145 .ip = al->addr,
146 .level = al->level,
147 .period = period,
148 .parent = sym_parent,
149 .filtered = symbol__parent_filter(sym_parent),
150 };
278 int cmp; 151 int cmp;
279 152
280 pthread_mutex_lock(&hists->lock);
281
282 p = &hists->entries_in->rb_node;
283
284 while (*p != NULL) { 153 while (*p != NULL) {
285 parent = *p; 154 parent = *p;
286 he = rb_entry(parent, struct hist_entry, rb_node_in); 155 he = rb_entry(parent, struct hist_entry, rb_node);
287 156
288 cmp = hist_entry__cmp(entry, he); 157 cmp = hist_entry__cmp(&entry, he);
289 158
290 if (!cmp) { 159 if (!cmp) {
291 he_stat__add_period(&he->stat, period); 160 he->period += period;
292 161 ++he->nr_events;
293 /* If the map of an existing hist_entry has
294 * become out-of-date due to an exec() or
295 * similar, update it. Otherwise we will
296 * mis-adjust symbol addresses when computing
297 * the history counter to increment.
298 */
299 if (he->ms.map != entry->ms.map) {
300 he->ms.map = entry->ms.map;
301 if (he->ms.map)
302 he->ms.map->referenced = true;
303 }
304 goto out; 162 goto out;
305 } 163 }
306 164
@@ -310,72 +168,17 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
310 p = &(*p)->rb_right; 168 p = &(*p)->rb_right;
311 } 169 }
312 170
313 he = hist_entry__new(entry); 171 he = hist_entry__new(&entry);
314 if (!he) 172 if (!he)
315 goto out_unlock; 173 return NULL;
316 174 rb_link_node(&he->rb_node, parent, p);
317 rb_link_node(&he->rb_node_in, parent, p); 175 rb_insert_color(&he->rb_node, &self->entries);
318 rb_insert_color(&he->rb_node_in, hists->entries_in); 176 hists__inc_nr_entries(self, he);
319out: 177out:
320 hist_entry__add_cpumode_period(he, al->cpumode, period); 178 hist_entry__add_cpumode_period(he, al->cpumode, period);
321out_unlock:
322 pthread_mutex_unlock(&hists->lock);
323 return he; 179 return he;
324} 180}
325 181
326struct hist_entry *__hists__add_branch_entry(struct hists *self,
327 struct addr_location *al,
328 struct symbol *sym_parent,
329 struct branch_info *bi,
330 u64 period)
331{
332 struct hist_entry entry = {
333 .thread = al->thread,
334 .ms = {
335 .map = bi->to.map,
336 .sym = bi->to.sym,
337 },
338 .cpu = al->cpu,
339 .ip = bi->to.addr,
340 .level = al->level,
341 .stat = {
342 .period = period,
343 .nr_events = 1,
344 },
345 .parent = sym_parent,
346 .filtered = symbol__parent_filter(sym_parent),
347 .branch_info = bi,
348 .hists = self,
349 };
350
351 return add_hist_entry(self, &entry, al, period);
352}
353
354struct hist_entry *__hists__add_entry(struct hists *self,
355 struct addr_location *al,
356 struct symbol *sym_parent, u64 period)
357{
358 struct hist_entry entry = {
359 .thread = al->thread,
360 .ms = {
361 .map = al->map,
362 .sym = al->sym,
363 },
364 .cpu = al->cpu,
365 .ip = al->addr,
366 .level = al->level,
367 .stat = {
368 .period = period,
369 .nr_events = 1,
370 },
371 .parent = sym_parent,
372 .filtered = symbol__parent_filter(sym_parent),
373 .hists = self,
374 };
375
376 return add_hist_entry(self, &entry, al, period);
377}
378
379int64_t 182int64_t
380hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 183hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
381{ 184{
@@ -412,7 +215,6 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
412 215
413void hist_entry__free(struct hist_entry *he) 216void hist_entry__free(struct hist_entry *he)
414{ 217{
415 free(he->branch_info);
416 free(he); 218 free(he);
417} 219}
418 220
@@ -420,7 +222,7 @@ void hist_entry__free(struct hist_entry *he)
420 * collapse the histogram 222 * collapse the histogram
421 */ 223 */
422 224
423static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 225static bool hists__collapse_insert_entry(struct hists *self,
424 struct rb_root *root, 226 struct rb_root *root,
425 struct hist_entry *he) 227 struct hist_entry *he)
426{ 228{
@@ -431,17 +233,15 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
431 233
432 while (*p != NULL) { 234 while (*p != NULL) {
433 parent = *p; 235 parent = *p;
434 iter = rb_entry(parent, struct hist_entry, rb_node_in); 236 iter = rb_entry(parent, struct hist_entry, rb_node);
435 237
436 cmp = hist_entry__collapse(iter, he); 238 cmp = hist_entry__collapse(iter, he);
437 239
438 if (!cmp) { 240 if (!cmp) {
439 he_stat__add_stat(&iter->stat, &he->stat); 241 iter->period += he->period;
440
441 if (symbol_conf.use_callchain) { 242 if (symbol_conf.use_callchain) {
442 callchain_cursor_reset(&callchain_cursor); 243 callchain_cursor_reset(&self->callchain_cursor);
443 callchain_merge(&callchain_cursor, 244 callchain_merge(&self->callchain_cursor, iter->callchain,
444 iter->callchain,
445 he->callchain); 245 he->callchain);
446 } 246 }
447 hist_entry__free(he); 247 hist_entry__free(he);
@@ -454,69 +254,35 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
454 p = &(*p)->rb_right; 254 p = &(*p)->rb_right;
455 } 255 }
456 256
457 rb_link_node(&he->rb_node_in, parent, p); 257 rb_link_node(&he->rb_node, parent, p);
458 rb_insert_color(&he->rb_node_in, root); 258 rb_insert_color(&he->rb_node, root);
459 return true; 259 return true;
460} 260}
461 261
462static struct rb_root *hists__get_rotate_entries_in(struct hists *hists) 262void hists__collapse_resort(struct hists *self)
463{
464 struct rb_root *root;
465
466 pthread_mutex_lock(&hists->lock);
467
468 root = hists->entries_in;
469 if (++hists->entries_in > &hists->entries_in_array[1])
470 hists->entries_in = &hists->entries_in_array[0];
471
472 pthread_mutex_unlock(&hists->lock);
473
474 return root;
475}
476
477static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
478{
479 hists__filter_entry_by_dso(hists, he);
480 hists__filter_entry_by_thread(hists, he);
481 hists__filter_entry_by_symbol(hists, he);
482}
483
484static void __hists__collapse_resort(struct hists *hists, bool threaded)
485{ 263{
486 struct rb_root *root; 264 struct rb_root tmp;
487 struct rb_node *next; 265 struct rb_node *next;
488 struct hist_entry *n; 266 struct hist_entry *n;
489 267
490 if (!sort__need_collapse && !threaded) 268 if (!sort__need_collapse)
491 return; 269 return;
492 270
493 root = hists__get_rotate_entries_in(hists); 271 tmp = RB_ROOT;
494 next = rb_first(root); 272 next = rb_first(&self->entries);
273 self->nr_entries = 0;
274 hists__reset_col_len(self);
495 275
496 while (next) { 276 while (next) {
497 n = rb_entry(next, struct hist_entry, rb_node_in); 277 n = rb_entry(next, struct hist_entry, rb_node);
498 next = rb_next(&n->rb_node_in); 278 next = rb_next(&n->rb_node);
499
500 rb_erase(&n->rb_node_in, root);
501 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
502 /*
503 * If it wasn't combined with one of the entries already
504 * collapsed, we need to apply the filters that may have
505 * been set by, say, the hist_browser.
506 */
507 hists__apply_filters(hists, n);
508 }
509 }
510}
511 279
512void hists__collapse_resort(struct hists *hists) 280 rb_erase(&n->rb_node, &self->entries);
513{ 281 if (hists__collapse_insert_entry(self, &tmp, n))
514 return __hists__collapse_resort(hists, false); 282 hists__inc_nr_entries(self, n);
515} 283 }
516 284
517void hists__collapse_resort_threaded(struct hists *hists) 285 self->entries = tmp;
518{
519 return __hists__collapse_resort(hists, true);
520} 286}
521 287
522/* 288/*
@@ -539,7 +305,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
539 parent = *p; 305 parent = *p;
540 iter = rb_entry(parent, struct hist_entry, rb_node); 306 iter = rb_entry(parent, struct hist_entry, rb_node);
541 307
542 if (he->stat.period > iter->stat.period) 308 if (he->period > iter->period)
543 p = &(*p)->rb_left; 309 p = &(*p)->rb_left;
544 else 310 else
545 p = &(*p)->rb_right; 311 p = &(*p)->rb_right;
@@ -549,266 +315,691 @@ static void __hists__insert_output_entry(struct rb_root *entries,
549 rb_insert_color(&he->rb_node, entries); 315 rb_insert_color(&he->rb_node, entries);
550} 316}
551 317
552static void __hists__output_resort(struct hists *hists, bool threaded) 318void hists__output_resort(struct hists *self)
553{ 319{
554 struct rb_root *root; 320 struct rb_root tmp;
555 struct rb_node *next; 321 struct rb_node *next;
556 struct hist_entry *n; 322 struct hist_entry *n;
557 u64 min_callchain_hits; 323 u64 min_callchain_hits;
558 324
559 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 325 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100);
560
561 if (sort__need_collapse || threaded)
562 root = &hists->entries_collapsed;
563 else
564 root = hists->entries_in;
565 326
566 next = rb_first(root); 327 tmp = RB_ROOT;
567 hists->entries = RB_ROOT; 328 next = rb_first(&self->entries);
568 329
569 hists->nr_entries = 0; 330 self->nr_entries = 0;
570 hists->stats.total_period = 0; 331 hists__reset_col_len(self);
571 hists__reset_col_len(hists);
572 332
573 while (next) { 333 while (next) {
574 n = rb_entry(next, struct hist_entry, rb_node_in); 334 n = rb_entry(next, struct hist_entry, rb_node);
575 next = rb_next(&n->rb_node_in); 335 next = rb_next(&n->rb_node);
576 336
577 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); 337 rb_erase(&n->rb_node, &self->entries);
578 hists__inc_nr_entries(hists, n); 338 __hists__insert_output_entry(&tmp, n, min_callchain_hits);
339 hists__inc_nr_entries(self, n);
579 } 340 }
341
342 self->entries = tmp;
580} 343}
581 344
582void hists__output_resort(struct hists *hists) 345static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
583{ 346{
584 return __hists__output_resort(hists, false); 347 int i;
348 int ret = fprintf(fp, " ");
349
350 for (i = 0; i < left_margin; i++)
351 ret += fprintf(fp, " ");
352
353 return ret;
585} 354}
586 355
587void hists__output_resort_threaded(struct hists *hists) 356static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
357 int left_margin)
588{ 358{
589 return __hists__output_resort(hists, true); 359 int i;
360 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
361
362 for (i = 0; i < depth; i++)
363 if (depth_mask & (1 << i))
364 ret += fprintf(fp, "| ");
365 else
366 ret += fprintf(fp, " ");
367
368 ret += fprintf(fp, "\n");
369
370 return ret;
590} 371}
591 372
592static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, 373static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
593 enum hist_filter filter) 374 int depth, int depth_mask, int period,
375 u64 total_samples, u64 hits,
376 int left_margin)
594{ 377{
595 h->filtered &= ~(1 << filter); 378 int i;
596 if (h->filtered) 379 size_t ret = 0;
597 return;
598 380
599 ++hists->nr_entries; 381 ret += callchain__fprintf_left_margin(fp, left_margin);
600 if (h->ms.unfolded) 382 for (i = 0; i < depth; i++) {
601 hists->nr_entries += h->nr_rows; 383 if (depth_mask & (1 << i))
602 h->row_offset = 0; 384 ret += fprintf(fp, "|");
603 hists->stats.total_period += h->stat.period; 385 else
604 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events; 386 ret += fprintf(fp, " ");
387 if (!period && i == depth - 1) {
388 double percent;
389
390 percent = hits * 100.0 / total_samples;
391 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
392 } else
393 ret += fprintf(fp, "%s", " ");
394 }
395 if (chain->ms.sym)
396 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
397 else
398 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
605 399
606 hists__calc_col_len(hists, h); 400 return ret;
607} 401}
608 402
403static struct symbol *rem_sq_bracket;
404static struct callchain_list rem_hits;
609 405
610static bool hists__filter_entry_by_dso(struct hists *hists, 406static void init_rem_hits(void)
611 struct hist_entry *he)
612{ 407{
613 if (hists->dso_filter != NULL && 408 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
614 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) { 409 if (!rem_sq_bracket) {
615 he->filtered |= (1 << HIST_FILTER__DSO); 410 fprintf(stderr, "Not enough memory to display remaining hits\n");
616 return true; 411 return;
617 } 412 }
618 413
619 return false; 414 strcpy(rem_sq_bracket->name, "[...]");
415 rem_hits.ms.sym = rem_sq_bracket;
620} 416}
621 417
622void hists__filter_by_dso(struct hists *hists) 418static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
419 u64 total_samples, int depth,
420 int depth_mask, int left_margin)
623{ 421{
624 struct rb_node *nd; 422 struct rb_node *node, *next;
423 struct callchain_node *child;
424 struct callchain_list *chain;
425 int new_depth_mask = depth_mask;
426 u64 new_total;
427 u64 remaining;
428 size_t ret = 0;
429 int i;
430 uint entries_printed = 0;
625 431
626 hists->nr_entries = hists->stats.total_period = 0; 432 if (callchain_param.mode == CHAIN_GRAPH_REL)
627 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 433 new_total = self->children_hit;
628 hists__reset_col_len(hists); 434 else
435 new_total = total_samples;
629 436
630 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 437 remaining = new_total;
631 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
632 438
633 if (symbol_conf.exclude_other && !h->parent) 439 node = rb_first(&self->rb_root);
634 continue; 440 while (node) {
441 u64 cumul;
635 442
636 if (hists__filter_entry_by_dso(hists, h)) 443 child = rb_entry(node, struct callchain_node, rb_node);
637 continue; 444 cumul = callchain_cumul_hits(child);
445 remaining -= cumul;
638 446
639 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO); 447 /*
448 * The depth mask manages the output of pipes that show
449 * the depth. We don't want to keep the pipes of the current
450 * level for the last child of this depth.
451 * Except if we have remaining filtered hits. They will
452 * supersede the last child
453 */
454 next = rb_next(node);
455 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
456 new_depth_mask &= ~(1 << (depth - 1));
457
458 /*
459 * But we keep the older depth mask for the line separator
460 * to keep the level link until we reach the last child
461 */
462 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
463 left_margin);
464 i = 0;
465 list_for_each_entry(chain, &child->val, list) {
466 ret += ipchain__fprintf_graph(fp, chain, depth,
467 new_depth_mask, i++,
468 new_total,
469 cumul,
470 left_margin);
471 }
472 ret += __callchain__fprintf_graph(fp, child, new_total,
473 depth + 1,
474 new_depth_mask | (1 << depth),
475 left_margin);
476 node = next;
477 if (++entries_printed == callchain_param.print_limit)
478 break;
479 }
480
481 if (callchain_param.mode == CHAIN_GRAPH_REL &&
482 remaining && remaining != new_total) {
483
484 if (!rem_sq_bracket)
485 return ret;
486
487 new_depth_mask &= ~(1 << (depth - 1));
488
489 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
490 new_depth_mask, 0, new_total,
491 remaining, left_margin);
640 } 492 }
493
494 return ret;
641} 495}
642 496
643static bool hists__filter_entry_by_thread(struct hists *hists, 497static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
644 struct hist_entry *he) 498 u64 total_samples, int left_margin)
645{ 499{
646 if (hists->thread_filter != NULL && 500 struct callchain_list *chain;
647 he->thread != hists->thread_filter) { 501 bool printed = false;
648 he->filtered |= (1 << HIST_FILTER__THREAD); 502 int i = 0;
649 return true; 503 int ret = 0;
504 u32 entries_printed = 0;
505
506 list_for_each_entry(chain, &self->val, list) {
507 if (!i++ && sort__first_dimension == SORT_SYM)
508 continue;
509
510 if (!printed) {
511 ret += callchain__fprintf_left_margin(fp, left_margin);
512 ret += fprintf(fp, "|\n");
513 ret += callchain__fprintf_left_margin(fp, left_margin);
514 ret += fprintf(fp, "---");
515
516 left_margin += 3;
517 printed = true;
518 } else
519 ret += callchain__fprintf_left_margin(fp, left_margin);
520
521 if (chain->ms.sym)
522 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
523 else
524 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
525
526 if (++entries_printed == callchain_param.print_limit)
527 break;
650 } 528 }
651 529
652 return false; 530 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
531
532 return ret;
653} 533}
654 534
655void hists__filter_by_thread(struct hists *hists) 535static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
536 u64 total_samples)
656{ 537{
657 struct rb_node *nd; 538 struct callchain_list *chain;
539 size_t ret = 0;
658 540
659 hists->nr_entries = hists->stats.total_period = 0; 541 if (!self)
660 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 542 return 0;
661 hists__reset_col_len(hists);
662 543
663 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 544 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
664 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
665 545
666 if (hists__filter_entry_by_thread(hists, h))
667 continue;
668 546
669 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD); 547 list_for_each_entry(chain, &self->val, list) {
548 if (chain->ip >= PERF_CONTEXT_MAX)
549 continue;
550 if (chain->ms.sym)
551 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
552 else
553 ret += fprintf(fp, " %p\n",
554 (void *)(long)chain->ip);
670 } 555 }
556
557 return ret;
671} 558}
672 559
673static bool hists__filter_entry_by_symbol(struct hists *hists, 560static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
674 struct hist_entry *he) 561 u64 total_samples, int left_margin)
675{ 562{
676 if (hists->symbol_filter_str != NULL && 563 struct rb_node *rb_node;
677 (!he->ms.sym || strstr(he->ms.sym->name, 564 struct callchain_node *chain;
678 hists->symbol_filter_str) == NULL)) { 565 size_t ret = 0;
679 he->filtered |= (1 << HIST_FILTER__SYMBOL); 566 u32 entries_printed = 0;
680 return true; 567
568 rb_node = rb_first(&self->sorted_chain);
569 while (rb_node) {
570 double percent;
571
572 chain = rb_entry(rb_node, struct callchain_node, rb_node);
573 percent = chain->hit * 100.0 / total_samples;
574 switch (callchain_param.mode) {
575 case CHAIN_FLAT:
576 ret += percent_color_fprintf(fp, " %6.2f%%\n",
577 percent);
578 ret += callchain__fprintf_flat(fp, chain, total_samples);
579 break;
580 case CHAIN_GRAPH_ABS: /* Falldown */
581 case CHAIN_GRAPH_REL:
582 ret += callchain__fprintf_graph(fp, chain, total_samples,
583 left_margin);
584 case CHAIN_NONE:
585 default:
586 break;
587 }
588 ret += fprintf(fp, "\n");
589 if (++entries_printed == callchain_param.print_limit)
590 break;
591 rb_node = rb_next(rb_node);
681 } 592 }
682 593
683 return false; 594 return ret;
684} 595}
685 596
686void hists__filter_by_symbol(struct hists *hists) 597int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
598 struct hists *hists, struct hists *pair_hists,
599 bool show_displacement, long displacement,
600 bool color, u64 session_total)
687{ 601{
688 struct rb_node *nd; 602 struct sort_entry *se;
603 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
604 u64 nr_events;
605 const char *sep = symbol_conf.field_sep;
606 int ret;
607
608 if (symbol_conf.exclude_other && !self->parent)
609 return 0;
610
611 if (pair_hists) {
612 period = self->pair ? self->pair->period : 0;
613 nr_events = self->pair ? self->pair->nr_events : 0;
614 total = pair_hists->stats.total_period;
615 period_sys = self->pair ? self->pair->period_sys : 0;
616 period_us = self->pair ? self->pair->period_us : 0;
617 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
618 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
619 } else {
620 period = self->period;
621 nr_events = self->nr_events;
622 total = session_total;
623 period_sys = self->period_sys;
624 period_us = self->period_us;
625 period_guest_sys = self->period_guest_sys;
626 period_guest_us = self->period_guest_us;
627 }
628
629 if (total) {
630 if (color)
631 ret = percent_color_snprintf(s, size,
632 sep ? "%.2f" : " %6.2f%%",
633 (period * 100.0) / total);
634 else
635 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
636 (period * 100.0) / total);
637 if (symbol_conf.show_cpu_utilization) {
638 ret += percent_color_snprintf(s + ret, size - ret,
639 sep ? "%.2f" : " %6.2f%%",
640 (period_sys * 100.0) / total);
641 ret += percent_color_snprintf(s + ret, size - ret,
642 sep ? "%.2f" : " %6.2f%%",
643 (period_us * 100.0) / total);
644 if (perf_guest) {
645 ret += percent_color_snprintf(s + ret,
646 size - ret,
647 sep ? "%.2f" : " %6.2f%%",
648 (period_guest_sys * 100.0) /
649 total);
650 ret += percent_color_snprintf(s + ret,
651 size - ret,
652 sep ? "%.2f" : " %6.2f%%",
653 (period_guest_us * 100.0) /
654 total);
655 }
656 }
657 } else
658 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
659
660 if (symbol_conf.show_nr_samples) {
661 if (sep)
662 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
663 else
664 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
665 }
689 666
690 hists->nr_entries = hists->stats.total_period = 0; 667 if (pair_hists) {
691 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 668 char bf[32];
692 hists__reset_col_len(hists); 669 double old_percent = 0, new_percent = 0, diff;
693 670
694 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 671 if (total > 0)
695 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 672 old_percent = (period * 100.0) / total;
673 if (session_total > 0)
674 new_percent = (self->period * 100.0) / session_total;
675
676 diff = new_percent - old_percent;
677
678 if (fabs(diff) >= 0.01)
679 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
680 else
681 snprintf(bf, sizeof(bf), " ");
682
683 if (sep)
684 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
685 else
686 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
687
688 if (show_displacement) {
689 if (displacement)
690 snprintf(bf, sizeof(bf), "%+4ld", displacement);
691 else
692 snprintf(bf, sizeof(bf), " ");
693
694 if (sep)
695 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
696 else
697 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
698 }
699 }
696 700
697 if (hists__filter_entry_by_symbol(hists, h)) 701 list_for_each_entry(se, &hist_entry__sort_list, list) {
702 if (se->elide)
698 continue; 703 continue;
699 704
700 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL); 705 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
706 ret += se->se_snprintf(self, s + ret, size - ret,
707 hists__col_len(hists, se->se_width_idx));
701 } 708 }
702}
703 709
704int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) 710 return ret;
705{
706 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
707} 711}
708 712
709int hist_entry__annotate(struct hist_entry *he, size_t privsize) 713int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
714 struct hists *pair_hists, bool show_displacement,
715 long displacement, FILE *fp, u64 session_total)
710{ 716{
711 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 717 char bf[512];
718 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
719 show_displacement, displacement,
720 true, session_total);
721 return fprintf(fp, "%s\n", bf);
712} 722}
713 723
714void hists__inc_nr_events(struct hists *hists, u32 type) 724static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
725 struct hists *hists, FILE *fp,
726 u64 session_total)
715{ 727{
716 ++hists->stats.nr_events[0]; 728 int left_margin = 0;
717 ++hists->stats.nr_events[type]; 729
730 if (sort__first_dimension == SORT_COMM) {
731 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
732 typeof(*se), list);
733 left_margin = hists__col_len(hists, se->se_width_idx);
734 left_margin -= thread__comm_len(self->thread);
735 }
736
737 return hist_entry_callchain__fprintf(fp, self, session_total,
738 left_margin);
718} 739}
719 740
720static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 741size_t hists__fprintf(struct hists *self, struct hists *pair,
721 struct hist_entry *pair) 742 bool show_displacement, FILE *fp)
722{ 743{
723 struct rb_node **p = &hists->entries.rb_node; 744 struct sort_entry *se;
724 struct rb_node *parent = NULL; 745 struct rb_node *nd;
725 struct hist_entry *he; 746 size_t ret = 0;
726 int cmp; 747 unsigned long position = 1;
748 long displacement = 0;
749 unsigned int width;
750 const char *sep = symbol_conf.field_sep;
751 const char *col_width = symbol_conf.col_width_list_str;
727 752
728 while (*p != NULL) { 753 init_rem_hits();
729 parent = *p;
730 he = rb_entry(parent, struct hist_entry, rb_node);
731 754
732 cmp = hist_entry__cmp(pair, he); 755 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
733 756
734 if (!cmp) 757 if (symbol_conf.show_nr_samples) {
735 goto out; 758 if (sep)
759 fprintf(fp, "%cSamples", *sep);
760 else
761 fputs(" Samples ", fp);
762 }
736 763
737 if (cmp < 0) 764 if (symbol_conf.show_cpu_utilization) {
738 p = &(*p)->rb_left; 765 if (sep) {
766 ret += fprintf(fp, "%csys", *sep);
767 ret += fprintf(fp, "%cus", *sep);
768 if (perf_guest) {
769 ret += fprintf(fp, "%cguest sys", *sep);
770 ret += fprintf(fp, "%cguest us", *sep);
771 }
772 } else {
773 ret += fprintf(fp, " sys ");
774 ret += fprintf(fp, " us ");
775 if (perf_guest) {
776 ret += fprintf(fp, " guest sys ");
777 ret += fprintf(fp, " guest us ");
778 }
779 }
780 }
781
782 if (pair) {
783 if (sep)
784 ret += fprintf(fp, "%cDelta", *sep);
739 else 785 else
740 p = &(*p)->rb_right; 786 ret += fprintf(fp, " Delta ");
787
788 if (show_displacement) {
789 if (sep)
790 ret += fprintf(fp, "%cDisplacement", *sep);
791 else
792 ret += fprintf(fp, " Displ");
793 }
741 } 794 }
742 795
743 he = hist_entry__new(pair); 796 list_for_each_entry(se, &hist_entry__sort_list, list) {
744 if (he) { 797 if (se->elide)
745 memset(&he->stat, 0, sizeof(he->stat)); 798 continue;
746 he->hists = hists; 799 if (sep) {
747 rb_link_node(&he->rb_node, parent, p); 800 fprintf(fp, "%c%s", *sep, se->se_header);
748 rb_insert_color(&he->rb_node, &hists->entries); 801 continue;
749 hists__inc_nr_entries(hists, he); 802 }
803 width = strlen(se->se_header);
804 if (symbol_conf.col_width_list_str) {
805 if (col_width) {
806 hists__set_col_len(self, se->se_width_idx,
807 atoi(col_width));
808 col_width = strchr(col_width, ',');
809 if (col_width)
810 ++col_width;
811 }
812 }
813 if (!hists__new_col_len(self, se->se_width_idx, width))
814 width = hists__col_len(self, se->se_width_idx);
815 fprintf(fp, " %*s", width, se->se_header);
750 } 816 }
751out: 817 fprintf(fp, "\n");
752 return he; 818
753} 819 if (sep)
820 goto print_entries;
821
822 fprintf(fp, "# ........");
823 if (symbol_conf.show_nr_samples)
824 fprintf(fp, " ..........");
825 if (pair) {
826 fprintf(fp, " ..........");
827 if (show_displacement)
828 fprintf(fp, " .....");
829 }
830 list_for_each_entry(se, &hist_entry__sort_list, list) {
831 unsigned int i;
754 832
755static struct hist_entry *hists__find_entry(struct hists *hists, 833 if (se->elide)
756 struct hist_entry *he) 834 continue;
757{
758 struct rb_node *n = hists->entries.rb_node;
759 835
760 while (n) { 836 fprintf(fp, " ");
761 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 837 width = hists__col_len(self, se->se_width_idx);
762 int64_t cmp = hist_entry__cmp(he, iter); 838 if (width == 0)
839 width = strlen(se->se_header);
840 for (i = 0; i < width; i++)
841 fprintf(fp, ".");
842 }
763 843
764 if (cmp < 0) 844 fprintf(fp, "\n#\n");
765 n = n->rb_left; 845
766 else if (cmp > 0) 846print_entries:
767 n = n->rb_right; 847 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
768 else 848 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
769 return iter; 849
850 if (h->filtered)
851 continue;
852
853 if (show_displacement) {
854 if (h->pair != NULL)
855 displacement = ((long)h->pair->position -
856 (long)position);
857 else
858 displacement = 0;
859 ++position;
860 }
861 ret += hist_entry__fprintf(h, self, pair, show_displacement,
862 displacement, fp, self->stats.total_period);
863
864 if (symbol_conf.use_callchain)
865 ret += hist_entry__fprintf_callchain(h, self, fp,
866 self->stats.total_period);
867 if (h->ms.map == NULL && verbose > 1) {
868 __map_groups__fprintf_maps(&h->thread->mg,
869 MAP__FUNCTION, verbose, fp);
870 fprintf(fp, "%.10s end\n", graph_dotted_line);
871 }
770 } 872 }
771 873
772 return NULL; 874 free(rem_sq_bracket);
875
876 return ret;
773} 877}
774 878
775/* 879/*
776 * Look for pairs to link to the leader buckets (hist_entries): 880 * See hists__fprintf to match the column widths
777 */ 881 */
778void hists__match(struct hists *leader, struct hists *other) 882unsigned int hists__sort_list_width(struct hists *self)
883{
884 struct sort_entry *se;
885 int ret = 9; /* total % */
886
887 if (symbol_conf.show_cpu_utilization) {
888 ret += 7; /* count_sys % */
889 ret += 6; /* count_us % */
890 if (perf_guest) {
891 ret += 13; /* count_guest_sys % */
892 ret += 12; /* count_guest_us % */
893 }
894 }
895
896 if (symbol_conf.show_nr_samples)
897 ret += 11;
898
899 list_for_each_entry(se, &hist_entry__sort_list, list)
900 if (!se->elide)
901 ret += 2 + hists__col_len(self, se->se_width_idx);
902
903 if (verbose) /* Addr + origin */
904 ret += 3 + BITS_PER_LONG / 4;
905
906 return ret;
907}
908
909static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
910 enum hist_filter filter)
911{
912 h->filtered &= ~(1 << filter);
913 if (h->filtered)
914 return;
915
916 ++self->nr_entries;
917 if (h->ms.unfolded)
918 self->nr_entries += h->nr_rows;
919 h->row_offset = 0;
920 self->stats.total_period += h->period;
921 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
922
923 hists__calc_col_len(self, h);
924}
925
926void hists__filter_by_dso(struct hists *self, const struct dso *dso)
779{ 927{
780 struct rb_node *nd; 928 struct rb_node *nd;
781 struct hist_entry *pos, *pair;
782 929
783 for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { 930 self->nr_entries = self->stats.total_period = 0;
784 pos = rb_entry(nd, struct hist_entry, rb_node); 931 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
785 pair = hists__find_entry(other, pos); 932 hists__reset_col_len(self);
933
934 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
935 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
936
937 if (symbol_conf.exclude_other && !h->parent)
938 continue;
939
940 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
941 h->filtered |= (1 << HIST_FILTER__DSO);
942 continue;
943 }
786 944
787 if (pair) 945 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
788 hist__entry_add_pair(pos, pair);
789 } 946 }
790} 947}
791 948
792/* 949void hists__filter_by_thread(struct hists *self, const struct thread *thread)
793 * Look for entries in the other hists that are not present in the leader, if
794 * we find them, just add a dummy entry on the leader hists, with period=0,
795 * nr_events=0, to serve as the list header.
796 */
797int hists__link(struct hists *leader, struct hists *other)
798{ 950{
799 struct rb_node *nd; 951 struct rb_node *nd;
800 struct hist_entry *pos, *pair;
801 952
802 for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { 953 self->nr_entries = self->stats.total_period = 0;
803 pos = rb_entry(nd, struct hist_entry, rb_node); 954 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
955 hists__reset_col_len(self);
956
957 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
958 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
804 959
805 if (!hist_entry__has_pairs(pos)) { 960 if (thread != NULL && h->thread != thread) {
806 pair = hists__add_dummy_entry(leader, pos); 961 h->filtered |= (1 << HIST_FILTER__THREAD);
807 if (pair == NULL) 962 continue;
808 return -1;
809 hist__entry_add_pair(pair, pos);
810 } 963 }
964
965 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
811 } 966 }
967}
812 968
813 return 0; 969int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
970{
971 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
972}
973
974int hist_entry__annotate(struct hist_entry *he, size_t privsize)
975{
976 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
977}
978
979void hists__inc_nr_events(struct hists *self, u32 type)
980{
981 ++self->stats.nr_events[0];
982 ++self->stats.nr_events[type];
983}
984
985size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
986{
987 int i;
988 size_t ret = 0;
989
990 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
991 const char *name;
992
993 if (self->stats.nr_events[i] == 0)
994 continue;
995
996 name = perf_event__name(i);
997 if (!strcmp(name, "UNKNOWN"))
998 continue;
999
1000 ret += fprintf(fp, "%16s events: %10d\n", name,
1001 self->stats.nr_events[i]);
1002 }
1003
1004 return ret;
814} 1005}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8b091a51e4a..3beb97c4d82 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -2,9 +2,7 @@
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h>
6#include "callchain.h" 5#include "callchain.h"
7#include "header.h"
8 6
9extern struct callchain_param callchain_param; 7extern struct callchain_param callchain_param;
10 8
@@ -29,11 +27,9 @@ struct events_stats {
29 u64 total_lost; 27 u64 total_lost;
30 u64 total_invalid_chains; 28 u64 total_invalid_chains;
31 u32 nr_events[PERF_RECORD_HEADER_MAX]; 29 u32 nr_events[PERF_RECORD_HEADER_MAX];
32 u32 nr_lost_warned;
33 u32 nr_unknown_events; 30 u32 nr_unknown_events;
34 u32 nr_invalid_chains; 31 u32 nr_invalid_chains;
35 u32 nr_unknown_id; 32 u32 nr_unknown_id;
36 u32 nr_unprocessable_samples;
37}; 33};
38 34
39enum hist_column { 35enum hist_column {
@@ -43,184 +39,79 @@ enum hist_column {
43 HISTC_COMM, 39 HISTC_COMM,
44 HISTC_PARENT, 40 HISTC_PARENT,
45 HISTC_CPU, 41 HISTC_CPU,
46 HISTC_MISPREDICT,
47 HISTC_SYMBOL_FROM,
48 HISTC_SYMBOL_TO,
49 HISTC_DSO_FROM,
50 HISTC_DSO_TO,
51 HISTC_SRCLINE,
52 HISTC_NR_COLS, /* Last entry */ 42 HISTC_NR_COLS, /* Last entry */
53}; 43};
54 44
55struct thread;
56struct dso;
57
58struct hists { 45struct hists {
59 struct rb_root entries_in_array[2];
60 struct rb_root *entries_in;
61 struct rb_root entries; 46 struct rb_root entries;
62 struct rb_root entries_collapsed;
63 u64 nr_entries; 47 u64 nr_entries;
64 const struct thread *thread_filter;
65 const struct dso *dso_filter;
66 const char *uid_filter_str;
67 const char *symbol_filter_str;
68 pthread_mutex_t lock;
69 struct events_stats stats; 48 struct events_stats stats;
70 u64 event_stream; 49 u64 event_stream;
71 u16 col_len[HISTC_NR_COLS]; 50 u16 col_len[HISTC_NR_COLS];
51 /* Best would be to reuse the session callchain cursor */
52 struct callchain_cursor callchain_cursor;
72}; 53};
73 54
74struct hist_entry *__hists__add_entry(struct hists *self, 55struct hist_entry *__hists__add_entry(struct hists *self,
75 struct addr_location *al, 56 struct addr_location *al,
76 struct symbol *parent, u64 period); 57 struct symbol *parent, u64 period);
77int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 58extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
78int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 59extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
79int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, 60int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
80 struct hists *hists); 61 struct hists *pair_hists, bool show_displacement,
62 long displacement, FILE *fp, u64 total);
63int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
64 struct hists *hists, struct hists *pair_hists,
65 bool show_displacement, long displacement,
66 bool color, u64 total);
81void hist_entry__free(struct hist_entry *); 67void hist_entry__free(struct hist_entry *);
82 68
83struct hist_entry *__hists__add_branch_entry(struct hists *self,
84 struct addr_location *al,
85 struct symbol *sym_parent,
86 struct branch_info *bi,
87 u64 period);
88
89void hists__output_resort(struct hists *self); 69void hists__output_resort(struct hists *self);
90void hists__output_resort_threaded(struct hists *hists);
91void hists__collapse_resort(struct hists *self); 70void hists__collapse_resort(struct hists *self);
92void hists__collapse_resort_threaded(struct hists *hists);
93
94void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
95void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
96 bool zap_kernel);
97void hists__output_recalc_col_len(struct hists *hists, int max_rows);
98 71
99void hists__inc_nr_events(struct hists *self, u32 type); 72void hists__inc_nr_events(struct hists *self, u32 type);
100size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 73size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
101 74
102size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 75size_t hists__fprintf(struct hists *self, struct hists *pair,
103 int max_cols, FILE *fp); 76 bool show_displacement, FILE *fp);
104 77
105int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 78int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
106int hist_entry__annotate(struct hist_entry *self, size_t privsize); 79int hist_entry__annotate(struct hist_entry *self, size_t privsize);
107 80
108void hists__filter_by_dso(struct hists *hists); 81void hists__filter_by_dso(struct hists *self, const struct dso *dso);
109void hists__filter_by_thread(struct hists *hists); 82void hists__filter_by_thread(struct hists *self, const struct thread *thread);
110void hists__filter_by_symbol(struct hists *hists);
111 83
112u16 hists__col_len(struct hists *self, enum hist_column col); 84u16 hists__col_len(struct hists *self, enum hist_column col);
113void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 85void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
114bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); 86bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
115void hists__reset_col_len(struct hists *hists);
116void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
117
118void hists__match(struct hists *leader, struct hists *other);
119int hists__link(struct hists *leader, struct hists *other);
120
121struct perf_hpp {
122 char *buf;
123 size_t size;
124 const char *sep;
125 void *ptr;
126};
127
128struct perf_hpp_fmt {
129 bool cond;
130 int (*header)(struct perf_hpp *hpp);
131 int (*width)(struct perf_hpp *hpp);
132 int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
133 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
134};
135
136extern struct perf_hpp_fmt perf_hpp__format[];
137
138enum {
139 PERF_HPP__BASELINE,
140 PERF_HPP__OVERHEAD,
141 PERF_HPP__OVERHEAD_SYS,
142 PERF_HPP__OVERHEAD_US,
143 PERF_HPP__OVERHEAD_GUEST_SYS,
144 PERF_HPP__OVERHEAD_GUEST_US,
145 PERF_HPP__SAMPLES,
146 PERF_HPP__PERIOD,
147 PERF_HPP__PERIOD_BASELINE,
148 PERF_HPP__DELTA,
149 PERF_HPP__RATIO,
150 PERF_HPP__WEIGHTED_DIFF,
151 PERF_HPP__DISPL,
152 PERF_HPP__FORMULA,
153
154 PERF_HPP__MAX_INDEX
155};
156
157void perf_hpp__init(void);
158void perf_hpp__column_enable(unsigned col, bool enable);
159int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
160 bool color);
161 87
162struct perf_evlist; 88struct perf_evlist;
163 89
164struct hist_browser_timer { 90#ifdef NO_NEWT_SUPPORT
165 void (*timer)(void *arg);
166 void *arg;
167 int refresh;
168};
169
170#ifdef NEWT_SUPPORT
171#include "../ui/keysyms.h"
172int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
173 struct hist_browser_timer *hbt);
174
175int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
176 struct hist_browser_timer *hbt,
177 struct perf_session_env *env);
178int script_browse(const char *script_opt);
179#else
180static inline 91static inline
181int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, 92int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
182 const char *help __maybe_unused, 93 const char *help __used)
183 struct hist_browser_timer *hbt __maybe_unused,
184 struct perf_session_env *env __maybe_unused)
185{ 94{
186 return 0; 95 return 0;
187} 96}
188 97
189static inline int hist_entry__tui_annotate(struct hist_entry *self 98static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
190 __maybe_unused, 99 int evidx __used)
191 int evidx __maybe_unused,
192 struct hist_browser_timer *hbt
193 __maybe_unused)
194{ 100{
195 return 0; 101 return 0;
196} 102}
103#define KEY_LEFT -1
104#define KEY_RIGHT -2
105#else
106#include <newt.h>
107int hist_entry__tui_annotate(struct hist_entry *self, int evidx);
197 108
198static inline int script_browse(const char *script_opt __maybe_unused) 109#define KEY_LEFT NEWT_KEY_LEFT
199{ 110#define KEY_RIGHT NEWT_KEY_RIGHT
200 return 0;
201}
202 111
203#define K_LEFT -1 112int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help);
204#define K_RIGHT -2
205#endif
206
207#ifdef GTK2_SUPPORT
208int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
209 struct hist_browser_timer *hbt __maybe_unused);
210#else
211static inline
212int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
213 const char *help __maybe_unused,
214 struct hist_browser_timer *hbt __maybe_unused)
215{
216 return 0;
217}
218#endif 113#endif
219 114
220unsigned int hists__sort_list_width(struct hists *self); 115unsigned int hists__sort_list_width(struct hists *self);
221 116
222double perf_diff__compute_delta(struct hist_entry *he);
223double perf_diff__compute_ratio(struct hist_entry *he);
224s64 perf_diff__compute_wdiff(struct hist_entry *he);
225int perf_diff__formula(char *buf, size_t size, struct hist_entry *he);
226#endif /* __PERF_HIST_H */ 117#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
index 2a9bdc06630..b722abe3a62 100644
--- a/tools/perf/util/include/asm/byteorder.h
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -1,2 +1,2 @@
1#include <asm/types.h> 1#include <asm/types.h>
2#include "../../../../include/uapi/linux/swab.h" 2#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/dwarf2.h b/tools/perf/util/include/asm/dwarf2.h
index afe38199e92..bb4198e7837 100644
--- a/tools/perf/util/include/asm/dwarf2.h
+++ b/tools/perf/util/include/asm/dwarf2.h
@@ -2,12 +2,10 @@
2#ifndef PERF_DWARF2_H 2#ifndef PERF_DWARF2_H
3#define PERF_DWARF2_H 3#define PERF_DWARF2_H
4 4
5/* dwarf2.h ... dummy header file for including arch/x86/lib/mem{cpy,set}_64.S */ 5/* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */
6 6
7#define CFI_STARTPROC 7#define CFI_STARTPROC
8#define CFI_ENDPROC 8#define CFI_ENDPROC
9#define CFI_REMEMBER_STATE
10#define CFI_RESTORE_STATE
11 9
12#endif /* PERF_DWARF2_H */ 10#endif /* PERF_DWARF2_H */
13 11
diff --git a/tools/perf/util/include/asm/unistd_32.h b/tools/perf/util/include/asm/unistd_32.h
deleted file mode 100644
index 8b137891791..00000000000
--- a/tools/perf/util/include/asm/unistd_32.h
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/tools/perf/util/include/asm/unistd_64.h b/tools/perf/util/include/asm/unistd_64.h
deleted file mode 100644
index 8b137891791..00000000000
--- a/tools/perf/util/include/asm/unistd_64.h
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index bb162e40c76..eda4416efa0 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -5,8 +5,6 @@
5#include <linux/bitops.h> 5#include <linux/bitops.h>
6 6
7int __bitmap_weight(const unsigned long *bitmap, int bits); 7int __bitmap_weight(const unsigned long *bitmap, int bits);
8void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
9 const unsigned long *bitmap2, int bits);
10 8
11#define BITMAP_LAST_WORD_MASK(nbits) \ 9#define BITMAP_LAST_WORD_MASK(nbits) \
12( \ 10( \
@@ -34,13 +32,4 @@ static inline int bitmap_weight(const unsigned long *src, int nbits)
34 return __bitmap_weight(src, nbits); 32 return __bitmap_weight(src, nbits);
35} 33}
36 34
37static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
38 const unsigned long *src2, int nbits)
39{
40 if (small_const_nbits(nbits))
41 *dst = *src1 | *src2;
42 else
43 __bitmap_or(dst, src1, src2, nbits);
44}
45
46#endif /* _PERF_BITOPS_H */ 35#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index a55d8cf083c..305c8484f20 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -5,26 +5,9 @@
5#include <linux/compiler.h> 5#include <linux/compiler.h>
6#include <asm/hweight.h> 6#include <asm/hweight.h>
7 7
8#ifndef __WORDSIZE
9#define __WORDSIZE (__SIZEOF_LONG__ * 8)
10#endif
11
12#define BITS_PER_LONG __WORDSIZE 8#define BITS_PER_LONG __WORDSIZE
13#define BITS_PER_BYTE 8 9#define BITS_PER_BYTE 8
14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 10#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
17
18#define for_each_set_bit(bit, addr, size) \
19 for ((bit) = find_first_bit((addr), (size)); \
20 (bit) < (size); \
21 (bit) = find_next_bit((addr), (size), (bit) + 1))
22
23/* same as for_each_set_bit() but use bit as value to start with */
24#define for_each_set_bit_from(bit, addr, size) \
25 for ((bit) = find_next_bit((addr), (size), (bit)); \
26 (bit) < (size); \
27 (bit) = find_next_bit((addr), (size), (bit) + 1))
28 11
29static inline void set_bit(int nr, unsigned long *addr) 12static inline void set_bit(int nr, unsigned long *addr)
30{ 13{
@@ -47,111 +30,4 @@ static inline unsigned long hweight_long(unsigned long w)
47 return sizeof(w) == 4 ? hweight32(w) : hweight64(w); 30 return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
48} 31}
49 32
50#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
51
52/**
53 * __ffs - find first bit in word.
54 * @word: The word to search
55 *
56 * Undefined if no bit exists, so code should check against 0 first.
57 */
58static __always_inline unsigned long __ffs(unsigned long word)
59{
60 int num = 0;
61
62#if BITS_PER_LONG == 64
63 if ((word & 0xffffffff) == 0) {
64 num += 32;
65 word >>= 32;
66 }
67#endif
68 if ((word & 0xffff) == 0) {
69 num += 16;
70 word >>= 16;
71 }
72 if ((word & 0xff) == 0) {
73 num += 8;
74 word >>= 8;
75 }
76 if ((word & 0xf) == 0) {
77 num += 4;
78 word >>= 4;
79 }
80 if ((word & 0x3) == 0) {
81 num += 2;
82 word >>= 2;
83 }
84 if ((word & 0x1) == 0)
85 num += 1;
86 return num;
87}
88
89/*
90 * Find the first set bit in a memory region.
91 */
92static inline unsigned long
93find_first_bit(const unsigned long *addr, unsigned long size)
94{
95 const unsigned long *p = addr;
96 unsigned long result = 0;
97 unsigned long tmp;
98
99 while (size & ~(BITS_PER_LONG-1)) {
100 if ((tmp = *(p++)))
101 goto found;
102 result += BITS_PER_LONG;
103 size -= BITS_PER_LONG;
104 }
105 if (!size)
106 return result;
107
108 tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
109 if (tmp == 0UL) /* Are any bits set? */
110 return result + size; /* Nope. */
111found:
112 return result + __ffs(tmp);
113}
114
115/*
116 * Find the next set bit in a memory region.
117 */
118static inline unsigned long
119find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
120{
121 const unsigned long *p = addr + BITOP_WORD(offset);
122 unsigned long result = offset & ~(BITS_PER_LONG-1);
123 unsigned long tmp;
124
125 if (offset >= size)
126 return size;
127 size -= result;
128 offset %= BITS_PER_LONG;
129 if (offset) {
130 tmp = *(p++);
131 tmp &= (~0UL << offset);
132 if (size < BITS_PER_LONG)
133 goto found_first;
134 if (tmp)
135 goto found_middle;
136 size -= BITS_PER_LONG;
137 result += BITS_PER_LONG;
138 }
139 while (size & ~(BITS_PER_LONG-1)) {
140 if ((tmp = *(p++)))
141 goto found_middle;
142 result += BITS_PER_LONG;
143 size -= BITS_PER_LONG;
144 }
145 if (!size)
146 return result;
147 tmp = *p;
148
149found_first:
150 tmp &= (~0UL >> (BITS_PER_LONG - size));
151 if (tmp == 0UL) /* Are any bits set? */
152 return result + size; /* Nope. */
153found_middle:
154 return result + __ffs(tmp);
155}
156
157#endif 33#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index 96b919dae11..547628e97f3 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -9,13 +9,6 @@
9#define __attribute_const__ 9#define __attribute_const__
10#endif 10#endif
11 11
12#ifndef __maybe_unused 12#define __used __attribute__((__unused__))
13#define __maybe_unused __attribute__((unused))
14#endif
15#define __packed __attribute__((__packed__))
16
17#ifndef __force
18#define __force
19#endif
20 13
21#endif 14#endif
diff --git a/tools/perf/util/include/linux/const.h b/tools/perf/util/include/linux/const.h
index c10a35e1afb..1b476c9ae64 100644
--- a/tools/perf/util/include/linux/const.h
+++ b/tools/perf/util/include/linux/const.h
@@ -1 +1 @@
#include "../../../../include/uapi/linux/const.h" #include "../../../../include/linux/const.h"
diff --git a/tools/perf/util/include/linux/export.h b/tools/perf/util/include/linux/export.h
deleted file mode 100644
index b43e2dc21e0..00000000000
--- a/tools/perf/util/include/linux/export.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index d8c927c868e..1eb804fd3fb 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -8,8 +8,8 @@
8 8
9#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) 9#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
10 10
11#define PERF_ALIGN(x, a) __PERF_ALIGN_MASK(x, (typeof(x))(a)-1) 11#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
12#define __PERF_ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) 12#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
13 13
14#ifndef offsetof 14#ifndef offsetof
15#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 15#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
@@ -46,22 +46,9 @@
46 _min1 < _min2 ? _min1 : _min2; }) 46 _min1 < _min2 ? _min1 : _min2; })
47#endif 47#endif
48 48
49#ifndef roundup
50#define roundup(x, y) ( \
51{ \
52 const typeof(y) __y = y; \
53 (((x) + (__y - 1)) / __y) * __y; \
54} \
55)
56#endif
57
58#ifndef BUG_ON 49#ifndef BUG_ON
59#ifdef NDEBUG
60#define BUG_ON(cond) do { if (cond) {} } while (0)
61#else
62#define BUG_ON(cond) assert(!(cond)) 50#define BUG_ON(cond) assert(!(cond))
63#endif 51#endif
64#endif
65 52
66/* 53/*
67 * Both need more care to handle endianness 54 * Both need more care to handle endianness
@@ -121,14 +108,4 @@ int eprintf(int level,
121#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 108#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
122#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) 109#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
123 110
124/*
125 * This looks more complex than it should be. But we need to
126 * get the type for the ~ right in round_down (it needs to be
127 * as wide as the result!), and we want to evaluate the macro
128 * arguments just once each.
129 */
130#define __round_mask(x, y) ((__typeof__(x))((y)-1))
131#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
132#define round_down(x, y) ((x) & ~__round_mask(x, y))
133
134#endif 111#endif
diff --git a/tools/perf/util/include/linux/magic.h b/tools/perf/util/include/linux/magic.h
deleted file mode 100644
index 58b64ed4da1..00000000000
--- a/tools/perf/util/include/linux/magic.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef _PERF_LINUX_MAGIC_H_
2#define _PERF_LINUX_MAGIC_H_
3
4#ifndef DEBUGFS_MAGIC
5#define DEBUGFS_MAGIC 0x64626720
6#endif
7
8#ifndef SYSFS_MAGIC
9#define SYSFS_MAGIC 0x62656572
10#endif
11
12#endif
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
index 2a030c5af3a..7a243a14303 100644
--- a/tools/perf/util/include/linux/rbtree.h
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -1,2 +1 @@
1#include <stdbool.h>
2#include "../../../../include/linux/rbtree.h" #include "../../../../include/linux/rbtree.h"
diff --git a/tools/perf/util/include/linux/rbtree_augmented.h b/tools/perf/util/include/linux/rbtree_augmented.h
deleted file mode 100644
index 9d6fcdf1788..00000000000
--- a/tools/perf/util/include/linux/rbtree_augmented.h
+++ /dev/null
@@ -1,2 +0,0 @@
1#include <stdbool.h>
2#include "../../../../include/linux/rbtree_augmented.h"
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
index 6f19c548ecc..3b2f5900276 100644
--- a/tools/perf/util/include/linux/string.h
+++ b/tools/perf/util/include/linux/string.h
@@ -1,3 +1 @@
1#include <string.h> #include <string.h>
2
3void *memdup(const void *src, size_t len);
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
index eb464786c08..12de3b8112f 100644
--- a/tools/perf/util/include/linux/types.h
+++ b/tools/perf/util/include/linux/types.h
@@ -3,14 +3,6 @@
3 3
4#include <asm/types.h> 4#include <asm/types.h>
5 5
6#ifndef __bitwise
7#define __bitwise
8#endif
9
10#ifndef __le32
11typedef __u32 __bitwise __le32;
12#endif
13
14#define DECLARE_BITMAP(name,bits) \ 6#define DECLARE_BITMAP(name,bits) \
15 unsigned long name[BITS_TO_LONGS(bits)] 7 unsigned long name[BITS_TO_LONGS(bits)]
16 8
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
deleted file mode 100644
index 9d0740024ba..00000000000
--- a/tools/perf/util/intlist.c
+++ /dev/null
@@ -1,101 +0,0 @@
1/*
2 * Based on intlist.c by:
3 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
4 *
5 * Licensed under the GPLv2.
6 */
7
8#include <errno.h>
9#include <stdlib.h>
10#include <linux/compiler.h>
11
12#include "intlist.h"
13
14static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused,
15 const void *entry)
16{
17 int i = (int)((long)entry);
18 struct rb_node *rc = NULL;
19 struct int_node *node = malloc(sizeof(*node));
20
21 if (node != NULL) {
22 node->i = i;
23 rc = &node->rb_node;
24 }
25
26 return rc;
27}
28
29static void int_node__delete(struct int_node *ilist)
30{
31 free(ilist);
32}
33
34static void intlist__node_delete(struct rblist *rblist __maybe_unused,
35 struct rb_node *rb_node)
36{
37 struct int_node *node = container_of(rb_node, struct int_node, rb_node);
38
39 int_node__delete(node);
40}
41
42static int intlist__node_cmp(struct rb_node *rb_node, const void *entry)
43{
44 int i = (int)((long)entry);
45 struct int_node *node = container_of(rb_node, struct int_node, rb_node);
46
47 return node->i - i;
48}
49
50int intlist__add(struct intlist *ilist, int i)
51{
52 return rblist__add_node(&ilist->rblist, (void *)((long)i));
53}
54
55void intlist__remove(struct intlist *ilist, struct int_node *node)
56{
57 rblist__remove_node(&ilist->rblist, &node->rb_node);
58}
59
60struct int_node *intlist__find(struct intlist *ilist, int i)
61{
62 struct int_node *node = NULL;
63 struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
64
65 if (rb_node)
66 node = container_of(rb_node, struct int_node, rb_node);
67
68 return node;
69}
70
71struct intlist *intlist__new(void)
72{
73 struct intlist *ilist = malloc(sizeof(*ilist));
74
75 if (ilist != NULL) {
76 rblist__init(&ilist->rblist);
77 ilist->rblist.node_cmp = intlist__node_cmp;
78 ilist->rblist.node_new = intlist__node_new;
79 ilist->rblist.node_delete = intlist__node_delete;
80 }
81
82 return ilist;
83}
84
85void intlist__delete(struct intlist *ilist)
86{
87 if (ilist != NULL)
88 rblist__delete(&ilist->rblist);
89}
90
91struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx)
92{
93 struct int_node *node = NULL;
94 struct rb_node *rb_node;
95
96 rb_node = rblist__entry(&ilist->rblist, idx);
97 if (rb_node)
98 node = container_of(rb_node, struct int_node, rb_node);
99
100 return node;
101}
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
deleted file mode 100644
index 6d63ab90db5..00000000000
--- a/tools/perf/util/intlist.h
+++ /dev/null
@@ -1,75 +0,0 @@
1#ifndef __PERF_INTLIST_H
2#define __PERF_INTLIST_H
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7#include "rblist.h"
8
9struct int_node {
10 struct rb_node rb_node;
11 int i;
12};
13
14struct intlist {
15 struct rblist rblist;
16};
17
18struct intlist *intlist__new(void);
19void intlist__delete(struct intlist *ilist);
20
21void intlist__remove(struct intlist *ilist, struct int_node *in);
22int intlist__add(struct intlist *ilist, int i);
23
24struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
25struct int_node *intlist__find(struct intlist *ilist, int i);
26
27static inline bool intlist__has_entry(struct intlist *ilist, int i)
28{
29 return intlist__find(ilist, i) != NULL;
30}
31
32static inline bool intlist__empty(const struct intlist *ilist)
33{
34 return rblist__empty(&ilist->rblist);
35}
36
37static inline unsigned int intlist__nr_entries(const struct intlist *ilist)
38{
39 return rblist__nr_entries(&ilist->rblist);
40}
41
42/* For intlist iteration */
43static inline struct int_node *intlist__first(struct intlist *ilist)
44{
45 struct rb_node *rn = rb_first(&ilist->rblist.entries);
46 return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
47}
48static inline struct int_node *intlist__next(struct int_node *in)
49{
50 struct rb_node *rn;
51 if (!in)
52 return NULL;
53 rn = rb_next(&in->rb_node);
54 return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
55}
56
57/**
58 * intlist_for_each - iterate over a intlist
59 * @pos: the &struct int_node to use as a loop cursor.
60 * @ilist: the &struct intlist for loop.
61 */
62#define intlist__for_each(pos, ilist) \
63 for (pos = intlist__first(ilist); pos; pos = intlist__next(pos))
64
65/**
66 * intlist_for_each_safe - iterate over a intlist safe against removal of
67 * int_node
68 * @pos: the &struct int_node to use as a loop cursor.
69 * @n: another &struct int_node to use as temporary storage.
70 * @ilist: the &struct intlist for loop.
71 */
72#define intlist__for_each_safe(pos, n, ilist) \
73 for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\
74 pos = n, n = intlist__next(n))
75#endif /* __PERF_INTLIST_H */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
deleted file mode 100644
index 1f09d0581e6..00000000000
--- a/tools/perf/util/machine.c
+++ /dev/null
@@ -1,464 +0,0 @@
1#include "debug.h"
2#include "event.h"
3#include "machine.h"
4#include "map.h"
5#include "strlist.h"
6#include "thread.h"
7#include <stdbool.h>
8
9int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
10{
11 map_groups__init(&machine->kmaps);
12 RB_CLEAR_NODE(&machine->rb_node);
13 INIT_LIST_HEAD(&machine->user_dsos);
14 INIT_LIST_HEAD(&machine->kernel_dsos);
15
16 machine->threads = RB_ROOT;
17 INIT_LIST_HEAD(&machine->dead_threads);
18 machine->last_match = NULL;
19
20 machine->kmaps.machine = machine;
21 machine->pid = pid;
22
23 machine->root_dir = strdup(root_dir);
24 if (machine->root_dir == NULL)
25 return -ENOMEM;
26
27 if (pid != HOST_KERNEL_ID) {
28 struct thread *thread = machine__findnew_thread(machine, pid);
29 char comm[64];
30
31 if (thread == NULL)
32 return -ENOMEM;
33
34 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
35 thread__set_comm(thread, comm);
36 }
37
38 return 0;
39}
40
41static void dsos__delete(struct list_head *dsos)
42{
43 struct dso *pos, *n;
44
45 list_for_each_entry_safe(pos, n, dsos, node) {
46 list_del(&pos->node);
47 dso__delete(pos);
48 }
49}
50
51void machine__exit(struct machine *machine)
52{
53 map_groups__exit(&machine->kmaps);
54 dsos__delete(&machine->user_dsos);
55 dsos__delete(&machine->kernel_dsos);
56 free(machine->root_dir);
57 machine->root_dir = NULL;
58}
59
60void machine__delete(struct machine *machine)
61{
62 machine__exit(machine);
63 free(machine);
64}
65
66struct machine *machines__add(struct rb_root *machines, pid_t pid,
67 const char *root_dir)
68{
69 struct rb_node **p = &machines->rb_node;
70 struct rb_node *parent = NULL;
71 struct machine *pos, *machine = malloc(sizeof(*machine));
72
73 if (machine == NULL)
74 return NULL;
75
76 if (machine__init(machine, root_dir, pid) != 0) {
77 free(machine);
78 return NULL;
79 }
80
81 while (*p != NULL) {
82 parent = *p;
83 pos = rb_entry(parent, struct machine, rb_node);
84 if (pid < pos->pid)
85 p = &(*p)->rb_left;
86 else
87 p = &(*p)->rb_right;
88 }
89
90 rb_link_node(&machine->rb_node, parent, p);
91 rb_insert_color(&machine->rb_node, machines);
92
93 return machine;
94}
95
96struct machine *machines__find(struct rb_root *machines, pid_t pid)
97{
98 struct rb_node **p = &machines->rb_node;
99 struct rb_node *parent = NULL;
100 struct machine *machine;
101 struct machine *default_machine = NULL;
102
103 while (*p != NULL) {
104 parent = *p;
105 machine = rb_entry(parent, struct machine, rb_node);
106 if (pid < machine->pid)
107 p = &(*p)->rb_left;
108 else if (pid > machine->pid)
109 p = &(*p)->rb_right;
110 else
111 return machine;
112 if (!machine->pid)
113 default_machine = machine;
114 }
115
116 return default_machine;
117}
118
119struct machine *machines__findnew(struct rb_root *machines, pid_t pid)
120{
121 char path[PATH_MAX];
122 const char *root_dir = "";
123 struct machine *machine = machines__find(machines, pid);
124
125 if (machine && (machine->pid == pid))
126 goto out;
127
128 if ((pid != HOST_KERNEL_ID) &&
129 (pid != DEFAULT_GUEST_KERNEL_ID) &&
130 (symbol_conf.guestmount)) {
131 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
132 if (access(path, R_OK)) {
133 static struct strlist *seen;
134
135 if (!seen)
136 seen = strlist__new(true, NULL);
137
138 if (!strlist__has_entry(seen, path)) {
139 pr_err("Can't access file %s\n", path);
140 strlist__add(seen, path);
141 }
142 machine = NULL;
143 goto out;
144 }
145 root_dir = path;
146 }
147
148 machine = machines__add(machines, pid, root_dir);
149out:
150 return machine;
151}
152
153void machines__process(struct rb_root *machines,
154 machine__process_t process, void *data)
155{
156 struct rb_node *nd;
157
158 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
159 struct machine *pos = rb_entry(nd, struct machine, rb_node);
160 process(pos, data);
161 }
162}
163
164char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
165{
166 if (machine__is_host(machine))
167 snprintf(bf, size, "[%s]", "kernel.kallsyms");
168 else if (machine__is_default_guest(machine))
169 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
170 else {
171 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms",
172 machine->pid);
173 }
174
175 return bf;
176}
177
178void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
179{
180 struct rb_node *node;
181 struct machine *machine;
182
183 for (node = rb_first(machines); node; node = rb_next(node)) {
184 machine = rb_entry(node, struct machine, rb_node);
185 machine->id_hdr_size = id_hdr_size;
186 }
187
188 return;
189}
190
191static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid,
192 bool create)
193{
194 struct rb_node **p = &machine->threads.rb_node;
195 struct rb_node *parent = NULL;
196 struct thread *th;
197
198 /*
199 * Font-end cache - PID lookups come in blocks,
200 * so most of the time we dont have to look up
201 * the full rbtree:
202 */
203 if (machine->last_match && machine->last_match->pid == pid)
204 return machine->last_match;
205
206 while (*p != NULL) {
207 parent = *p;
208 th = rb_entry(parent, struct thread, rb_node);
209
210 if (th->pid == pid) {
211 machine->last_match = th;
212 return th;
213 }
214
215 if (pid < th->pid)
216 p = &(*p)->rb_left;
217 else
218 p = &(*p)->rb_right;
219 }
220
221 if (!create)
222 return NULL;
223
224 th = thread__new(pid);
225 if (th != NULL) {
226 rb_link_node(&th->rb_node, parent, p);
227 rb_insert_color(&th->rb_node, &machine->threads);
228 machine->last_match = th;
229 }
230
231 return th;
232}
233
234struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
235{
236 return __machine__findnew_thread(machine, pid, true);
237}
238
239struct thread *machine__find_thread(struct machine *machine, pid_t pid)
240{
241 return __machine__findnew_thread(machine, pid, false);
242}
243
244int machine__process_comm_event(struct machine *machine, union perf_event *event)
245{
246 struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
247
248 if (dump_trace)
249 perf_event__fprintf_comm(event, stdout);
250
251 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
252 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
253 return -1;
254 }
255
256 return 0;
257}
258
259int machine__process_lost_event(struct machine *machine __maybe_unused,
260 union perf_event *event)
261{
262 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
263 event->lost.id, event->lost.lost);
264 return 0;
265}
266
267static void machine__set_kernel_mmap_len(struct machine *machine,
268 union perf_event *event)
269{
270 int i;
271
272 for (i = 0; i < MAP__NR_TYPES; i++) {
273 machine->vmlinux_maps[i]->start = event->mmap.start;
274 machine->vmlinux_maps[i]->end = (event->mmap.start +
275 event->mmap.len);
276 /*
277 * Be a bit paranoid here, some perf.data file came with
278 * a zero sized synthesized MMAP event for the kernel.
279 */
280 if (machine->vmlinux_maps[i]->end == 0)
281 machine->vmlinux_maps[i]->end = ~0ULL;
282 }
283}
284
285static int machine__process_kernel_mmap_event(struct machine *machine,
286 union perf_event *event)
287{
288 struct map *map;
289 char kmmap_prefix[PATH_MAX];
290 enum dso_kernel_type kernel_type;
291 bool is_kernel_mmap;
292
293 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
294 if (machine__is_host(machine))
295 kernel_type = DSO_TYPE_KERNEL;
296 else
297 kernel_type = DSO_TYPE_GUEST_KERNEL;
298
299 is_kernel_mmap = memcmp(event->mmap.filename,
300 kmmap_prefix,
301 strlen(kmmap_prefix) - 1) == 0;
302 if (event->mmap.filename[0] == '/' ||
303 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
304
305 char short_module_name[1024];
306 char *name, *dot;
307
308 if (event->mmap.filename[0] == '/') {
309 name = strrchr(event->mmap.filename, '/');
310 if (name == NULL)
311 goto out_problem;
312
313 ++name; /* skip / */
314 dot = strrchr(name, '.');
315 if (dot == NULL)
316 goto out_problem;
317 snprintf(short_module_name, sizeof(short_module_name),
318 "[%.*s]", (int)(dot - name), name);
319 strxfrchar(short_module_name, '-', '_');
320 } else
321 strcpy(short_module_name, event->mmap.filename);
322
323 map = machine__new_module(machine, event->mmap.start,
324 event->mmap.filename);
325 if (map == NULL)
326 goto out_problem;
327
328 name = strdup(short_module_name);
329 if (name == NULL)
330 goto out_problem;
331
332 map->dso->short_name = name;
333 map->dso->sname_alloc = 1;
334 map->end = map->start + event->mmap.len;
335 } else if (is_kernel_mmap) {
336 const char *symbol_name = (event->mmap.filename +
337 strlen(kmmap_prefix));
338 /*
339 * Should be there already, from the build-id table in
340 * the header.
341 */
342 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
343 kmmap_prefix);
344 if (kernel == NULL)
345 goto out_problem;
346
347 kernel->kernel = kernel_type;
348 if (__machine__create_kernel_maps(machine, kernel) < 0)
349 goto out_problem;
350
351 machine__set_kernel_mmap_len(machine, event);
352
353 /*
354 * Avoid using a zero address (kptr_restrict) for the ref reloc
355 * symbol. Effectively having zero here means that at record
356 * time /proc/sys/kernel/kptr_restrict was non zero.
357 */
358 if (event->mmap.pgoff != 0) {
359 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
360 symbol_name,
361 event->mmap.pgoff);
362 }
363
364 if (machine__is_default_guest(machine)) {
365 /*
366 * preload dso of guest kernel and modules
367 */
368 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
369 NULL);
370 }
371 }
372 return 0;
373out_problem:
374 return -1;
375}
376
377int machine__process_mmap_event(struct machine *machine, union perf_event *event)
378{
379 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
380 struct thread *thread;
381 struct map *map;
382 int ret = 0;
383
384 if (dump_trace)
385 perf_event__fprintf_mmap(event, stdout);
386
387 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
388 cpumode == PERF_RECORD_MISC_KERNEL) {
389 ret = machine__process_kernel_mmap_event(machine, event);
390 if (ret < 0)
391 goto out_problem;
392 return 0;
393 }
394
395 thread = machine__findnew_thread(machine, event->mmap.pid);
396 if (thread == NULL)
397 goto out_problem;
398 map = map__new(&machine->user_dsos, event->mmap.start,
399 event->mmap.len, event->mmap.pgoff,
400 event->mmap.pid, event->mmap.filename,
401 MAP__FUNCTION);
402 if (map == NULL)
403 goto out_problem;
404
405 thread__insert_map(thread, map);
406 return 0;
407
408out_problem:
409 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
410 return 0;
411}
412
413int machine__process_fork_event(struct machine *machine, union perf_event *event)
414{
415 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
416 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
417
418 if (dump_trace)
419 perf_event__fprintf_task(event, stdout);
420
421 if (thread == NULL || parent == NULL ||
422 thread__fork(thread, parent) < 0) {
423 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
424 return -1;
425 }
426
427 return 0;
428}
429
430int machine__process_exit_event(struct machine *machine, union perf_event *event)
431{
432 struct thread *thread = machine__find_thread(machine, event->fork.tid);
433
434 if (dump_trace)
435 perf_event__fprintf_task(event, stdout);
436
437 if (thread != NULL)
438 machine__remove_thread(machine, thread);
439
440 return 0;
441}
442
443int machine__process_event(struct machine *machine, union perf_event *event)
444{
445 int ret;
446
447 switch (event->header.type) {
448 case PERF_RECORD_COMM:
449 ret = machine__process_comm_event(machine, event); break;
450 case PERF_RECORD_MMAP:
451 ret = machine__process_mmap_event(machine, event); break;
452 case PERF_RECORD_FORK:
453 ret = machine__process_fork_event(machine, event); break;
454 case PERF_RECORD_EXIT:
455 ret = machine__process_exit_event(machine, event); break;
456 case PERF_RECORD_LOST:
457 ret = machine__process_lost_event(machine, event); break;
458 default:
459 ret = -1;
460 break;
461 }
462
463 return ret;
464}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
deleted file mode 100644
index b7cde7467d5..00000000000
--- a/tools/perf/util/machine.h
+++ /dev/null
@@ -1,148 +0,0 @@
1#ifndef __PERF_MACHINE_H
2#define __PERF_MACHINE_H
3
4#include <sys/types.h>
5#include <linux/rbtree.h>
6#include "map.h"
7
8struct branch_stack;
9struct perf_evsel;
10struct perf_sample;
11struct symbol;
12struct thread;
13union perf_event;
14
15/* Native host kernel uses -1 as pid index in machine */
16#define HOST_KERNEL_ID (-1)
17#define DEFAULT_GUEST_KERNEL_ID (0)
18
19struct machine {
20 struct rb_node rb_node;
21 pid_t pid;
22 u16 id_hdr_size;
23 char *root_dir;
24 struct rb_root threads;
25 struct list_head dead_threads;
26 struct thread *last_match;
27 struct list_head user_dsos;
28 struct list_head kernel_dsos;
29 struct map_groups kmaps;
30 struct map *vmlinux_maps[MAP__NR_TYPES];
31};
32
33static inline
34struct map *machine__kernel_map(struct machine *machine, enum map_type type)
35{
36 return machine->vmlinux_maps[type];
37}
38
39struct thread *machine__find_thread(struct machine *machine, pid_t pid);
40
41int machine__process_comm_event(struct machine *machine, union perf_event *event);
42int machine__process_exit_event(struct machine *machine, union perf_event *event);
43int machine__process_fork_event(struct machine *machine, union perf_event *event);
44int machine__process_lost_event(struct machine *machine, union perf_event *event);
45int machine__process_mmap_event(struct machine *machine, union perf_event *event);
46int machine__process_event(struct machine *machine, union perf_event *event);
47
48typedef void (*machine__process_t)(struct machine *machine, void *data);
49
50void machines__process(struct rb_root *machines,
51 machine__process_t process, void *data);
52
53struct machine *machines__add(struct rb_root *machines, pid_t pid,
54 const char *root_dir);
55struct machine *machines__find_host(struct rb_root *machines);
56struct machine *machines__find(struct rb_root *machines, pid_t pid);
57struct machine *machines__findnew(struct rb_root *machines, pid_t pid);
58
59void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size);
60char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
61
62int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
63void machine__exit(struct machine *machine);
64void machine__delete(struct machine *machine);
65
66
67struct branch_info *machine__resolve_bstack(struct machine *machine,
68 struct thread *thread,
69 struct branch_stack *bs);
70int machine__resolve_callchain(struct machine *machine,
71 struct perf_evsel *evsel,
72 struct thread *thread,
73 struct perf_sample *sample,
74 struct symbol **parent);
75
76/*
77 * Default guest kernel is defined by parameter --guestkallsyms
78 * and --guestmodules
79 */
80static inline bool machine__is_default_guest(struct machine *machine)
81{
82 return machine ? machine->pid == DEFAULT_GUEST_KERNEL_ID : false;
83}
84
85static inline bool machine__is_host(struct machine *machine)
86{
87 return machine ? machine->pid == HOST_KERNEL_ID : false;
88}
89
90struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
91void machine__remove_thread(struct machine *machine, struct thread *th);
92
93size_t machine__fprintf(struct machine *machine, FILE *fp);
94
95static inline
96struct symbol *machine__find_kernel_symbol(struct machine *machine,
97 enum map_type type, u64 addr,
98 struct map **mapp,
99 symbol_filter_t filter)
100{
101 return map_groups__find_symbol(&machine->kmaps, type, addr,
102 mapp, filter);
103}
104
105static inline
106struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr,
107 struct map **mapp,
108 symbol_filter_t filter)
109{
110 return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr,
111 mapp, filter);
112}
113
114static inline
115struct symbol *machine__find_kernel_function_by_name(struct machine *machine,
116 const char *name,
117 struct map **mapp,
118 symbol_filter_t filter)
119{
120 return map_groups__find_function_by_name(&machine->kmaps, name, mapp,
121 filter);
122}
123
124struct map *machine__new_module(struct machine *machine, u64 start,
125 const char *filename);
126
127int machine__load_kallsyms(struct machine *machine, const char *filename,
128 enum map_type type, symbol_filter_t filter);
129int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
130 symbol_filter_t filter);
131
132size_t machine__fprintf_dsos_buildid(struct machine *machine,
133 FILE *fp, bool with_hits);
134size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
135size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
136 FILE *fp, bool with_hits);
137
138void machine__destroy_kernel_maps(struct machine *machine);
139int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
140int machine__create_kernel_maps(struct machine *machine);
141
142int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
143int machines__create_guest_kernel_maps(struct rb_root *machines);
144void machines__destroy_guest_kernel_maps(struct rb_root *machines);
145
146size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
147
148#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 0328d45c4f2..a16ecab5229 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -7,10 +7,6 @@
7#include <stdio.h> 7#include <stdio.h>
8#include <unistd.h> 8#include <unistd.h>
9#include "map.h" 9#include "map.h"
10#include "thread.h"
11#include "strlist.h"
12#include "vdso.h"
13#include "build-id.h"
14 10
15const char *map_type__name[MAP__NR_TYPES] = { 11const char *map_type__name[MAP__NR_TYPES] = {
16 [MAP__FUNCTION] = "Functions", 12 [MAP__FUNCTION] = "Functions",
@@ -22,12 +18,6 @@ static inline int is_anon_memory(const char *filename)
22 return strcmp(filename, "//anon") == 0; 18 return strcmp(filename, "//anon") == 0;
23} 19}
24 20
25static inline int is_no_dso_memory(const char *filename)
26{
27 return !strncmp(filename, "[stack", 6) ||
28 !strcmp(filename, "[heap]");
29}
30
31void map__init(struct map *self, enum map_type type, 21void map__init(struct map *self, enum map_type type,
32 u64 start, u64 end, u64 pgoff, struct dso *dso) 22 u64 start, u64 end, u64 pgoff, struct dso *dso)
33{ 23{
@@ -41,7 +31,6 @@ void map__init(struct map *self, enum map_type type,
41 RB_CLEAR_NODE(&self->rb_node); 31 RB_CLEAR_NODE(&self->rb_node);
42 self->groups = NULL; 32 self->groups = NULL;
43 self->referenced = false; 33 self->referenced = false;
44 self->erange_warned = false;
45} 34}
46 35
47struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 36struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
@@ -53,38 +42,27 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
53 if (self != NULL) { 42 if (self != NULL) {
54 char newfilename[PATH_MAX]; 43 char newfilename[PATH_MAX];
55 struct dso *dso; 44 struct dso *dso;
56 int anon, no_dso, vdso; 45 int anon;
57 46
58 anon = is_anon_memory(filename); 47 anon = is_anon_memory(filename);
59 vdso = is_vdso_map(filename);
60 no_dso = is_no_dso_memory(filename);
61 48
62 if (anon) { 49 if (anon) {
63 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 50 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
64 filename = newfilename; 51 filename = newfilename;
65 } 52 }
66 53
67 if (vdso) { 54 dso = __dsos__findnew(dsos__list, filename);
68 pgoff = 0;
69 dso = vdso__dso_findnew(dsos__list);
70 } else
71 dso = __dsos__findnew(dsos__list, filename);
72
73 if (dso == NULL) 55 if (dso == NULL)
74 goto out_delete; 56 goto out_delete;
75 57
76 map__init(self, type, start, start + len, pgoff, dso); 58 map__init(self, type, start, start + len, pgoff, dso);
77 59
78 if (anon || no_dso) { 60 if (anon) {
61set_identity:
79 self->map_ip = self->unmap_ip = identity__map_ip; 62 self->map_ip = self->unmap_ip = identity__map_ip;
80 63 } else if (strcmp(filename, "[vdso]") == 0) {
81 /* 64 dso__set_loaded(dso, self->type);
82 * Set memory without DSO as loaded. All map__find_* 65 goto set_identity;
83 * functions still return NULL, and we avoid the
84 * unnecessary map__load warning.
85 */
86 if (no_dso)
87 dso__set_loaded(dso, self->type);
88 } 66 }
89 } 67 }
90 return self; 68 return self;
@@ -93,25 +71,6 @@ out_delete:
93 return NULL; 71 return NULL;
94} 72}
95 73
96/*
97 * Constructor variant for modules (where we know from /proc/modules where
98 * they are loaded) and for vmlinux, where only after we load all the
99 * symbols we'll know where it starts and ends.
100 */
101struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
102{
103 struct map *map = calloc(1, (sizeof(*map) +
104 (dso->kernel ? sizeof(struct kmap) : 0)));
105 if (map != NULL) {
106 /*
107 * ->end will be filled after we load all the symbols
108 */
109 map__init(map, type, start, 0, 0, dso);
110 }
111
112 return map;
113}
114
115void map__delete(struct map *self) 74void map__delete(struct map *self)
116{ 75{
117 free(self); 76 free(self);
@@ -163,20 +122,19 @@ int map__load(struct map *self, symbol_filter_t filter)
163 pr_warning(", continuing without symbols\n"); 122 pr_warning(", continuing without symbols\n");
164 return -1; 123 return -1;
165 } else if (nr == 0) { 124 } else if (nr == 0) {
166#ifdef LIBELF_SUPPORT
167 const size_t len = strlen(name); 125 const size_t len = strlen(name);
168 const size_t real_len = len - sizeof(DSO__DELETED); 126 const size_t real_len = len - sizeof(DSO__DELETED);
169 127
170 if (len > sizeof(DSO__DELETED) && 128 if (len > sizeof(DSO__DELETED) &&
171 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 129 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
172 pr_warning("%.*s was updated (is prelink enabled?). " 130 pr_warning("%.*s was updated, restart the long "
173 "Restart the long running apps that use it!\n", 131 "running apps that use it!\n",
174 (int)real_len, name); 132 (int)real_len, name);
175 } else { 133 } else {
176 pr_warning("no symbols found in %s, maybe install " 134 pr_warning("no symbols found in %s, maybe install "
177 "a debug package?\n", name); 135 "a debug package?\n", name);
178 } 136 }
179#endif 137
180 return -1; 138 return -1;
181 } 139 }
182 /* 140 /*
@@ -242,20 +200,6 @@ size_t map__fprintf(struct map *self, FILE *fp)
242 self->start, self->end, self->pgoff, self->dso->name); 200 self->start, self->end, self->pgoff, self->dso->name);
243} 201}
244 202
245size_t map__fprintf_dsoname(struct map *map, FILE *fp)
246{
247 const char *dsoname = "[unknown]";
248
249 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
250 if (symbol_conf.show_kernel_path && map->dso->long_name)
251 dsoname = map->dso->long_name;
252 else if (map->dso->name)
253 dsoname = map->dso->name;
254 }
255
256 return fprintf(fp, "%s", dsoname);
257}
258
259/* 203/*
260 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 204 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
261 * map->dso->adjust_symbols==1 for ET_EXEC-like cases. 205 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
@@ -268,55 +212,63 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
268 return addr; 212 return addr;
269} 213}
270 214
271void map_groups__init(struct map_groups *mg) 215u64 map__objdump_2ip(struct map *map, u64 addr)
216{
217 u64 ip = map->dso->adjust_symbols ?
218 addr :
219 map->unmap_ip(map, addr); /* RIP -> IP */
220 return ip;
221}
222
223void map_groups__init(struct map_groups *self)
272{ 224{
273 int i; 225 int i;
274 for (i = 0; i < MAP__NR_TYPES; ++i) { 226 for (i = 0; i < MAP__NR_TYPES; ++i) {
275 mg->maps[i] = RB_ROOT; 227 self->maps[i] = RB_ROOT;
276 INIT_LIST_HEAD(&mg->removed_maps[i]); 228 INIT_LIST_HEAD(&self->removed_maps[i]);
277 } 229 }
278 mg->machine = NULL; 230 self->machine = NULL;
279} 231}
280 232
281static void maps__delete(struct rb_root *maps) 233static void maps__delete(struct rb_root *self)
282{ 234{
283 struct rb_node *next = rb_first(maps); 235 struct rb_node *next = rb_first(self);
284 236
285 while (next) { 237 while (next) {
286 struct map *pos = rb_entry(next, struct map, rb_node); 238 struct map *pos = rb_entry(next, struct map, rb_node);
287 239
288 next = rb_next(&pos->rb_node); 240 next = rb_next(&pos->rb_node);
289 rb_erase(&pos->rb_node, maps); 241 rb_erase(&pos->rb_node, self);
290 map__delete(pos); 242 map__delete(pos);
291 } 243 }
292} 244}
293 245
294static void maps__delete_removed(struct list_head *maps) 246static void maps__delete_removed(struct list_head *self)
295{ 247{
296 struct map *pos, *n; 248 struct map *pos, *n;
297 249
298 list_for_each_entry_safe(pos, n, maps, node) { 250 list_for_each_entry_safe(pos, n, self, node) {
299 list_del(&pos->node); 251 list_del(&pos->node);
300 map__delete(pos); 252 map__delete(pos);
301 } 253 }
302} 254}
303 255
304void map_groups__exit(struct map_groups *mg) 256void map_groups__exit(struct map_groups *self)
305{ 257{
306 int i; 258 int i;
307 259
308 for (i = 0; i < MAP__NR_TYPES; ++i) { 260 for (i = 0; i < MAP__NR_TYPES; ++i) {
309 maps__delete(&mg->maps[i]); 261 maps__delete(&self->maps[i]);
310 maps__delete_removed(&mg->removed_maps[i]); 262 maps__delete_removed(&self->removed_maps[i]);
311 } 263 }
312} 264}
313 265
314void map_groups__flush(struct map_groups *mg) 266void map_groups__flush(struct map_groups *self)
315{ 267{
316 int type; 268 int type;
317 269
318 for (type = 0; type < MAP__NR_TYPES; type++) { 270 for (type = 0; type < MAP__NR_TYPES; type++) {
319 struct rb_root *root = &mg->maps[type]; 271 struct rb_root *root = &self->maps[type];
320 struct rb_node *next = rb_first(root); 272 struct rb_node *next = rb_first(root);
321 273
322 while (next) { 274 while (next) {
@@ -328,17 +280,17 @@ void map_groups__flush(struct map_groups *mg)
328 * instance in some hist_entry instances, so 280 * instance in some hist_entry instances, so
329 * just move them to a separate list. 281 * just move them to a separate list.
330 */ 282 */
331 list_add_tail(&pos->node, &mg->removed_maps[pos->type]); 283 list_add_tail(&pos->node, &self->removed_maps[pos->type]);
332 } 284 }
333 } 285 }
334} 286}
335 287
336struct symbol *map_groups__find_symbol(struct map_groups *mg, 288struct symbol *map_groups__find_symbol(struct map_groups *self,
337 enum map_type type, u64 addr, 289 enum map_type type, u64 addr,
338 struct map **mapp, 290 struct map **mapp,
339 symbol_filter_t filter) 291 symbol_filter_t filter)
340{ 292{
341 struct map *map = map_groups__find(mg, type, addr); 293 struct map *map = map_groups__find(self, type, addr);
342 294
343 if (map != NULL) { 295 if (map != NULL) {
344 if (mapp != NULL) 296 if (mapp != NULL)
@@ -349,7 +301,7 @@ struct symbol *map_groups__find_symbol(struct map_groups *mg,
349 return NULL; 301 return NULL;
350} 302}
351 303
352struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, 304struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
353 enum map_type type, 305 enum map_type type,
354 const char *name, 306 const char *name,
355 struct map **mapp, 307 struct map **mapp,
@@ -357,7 +309,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
357{ 309{
358 struct rb_node *nd; 310 struct rb_node *nd;
359 311
360 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 312 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
361 struct map *pos = rb_entry(nd, struct map, rb_node); 313 struct map *pos = rb_entry(nd, struct map, rb_node);
362 struct symbol *sym = map__find_symbol_by_name(pos, name, filter); 314 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
363 315
@@ -371,13 +323,13 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
371 return NULL; 323 return NULL;
372} 324}
373 325
374size_t __map_groups__fprintf_maps(struct map_groups *mg, 326size_t __map_groups__fprintf_maps(struct map_groups *self,
375 enum map_type type, int verbose, FILE *fp) 327 enum map_type type, int verbose, FILE *fp)
376{ 328{
377 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 329 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
378 struct rb_node *nd; 330 struct rb_node *nd;
379 331
380 for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 332 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
381 struct map *pos = rb_entry(nd, struct map, rb_node); 333 struct map *pos = rb_entry(nd, struct map, rb_node);
382 printed += fprintf(fp, "Map:"); 334 printed += fprintf(fp, "Map:");
383 printed += map__fprintf(pos, fp); 335 printed += map__fprintf(pos, fp);
@@ -390,22 +342,22 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg,
390 return printed; 342 return printed;
391} 343}
392 344
393size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) 345size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp)
394{ 346{
395 size_t printed = 0, i; 347 size_t printed = 0, i;
396 for (i = 0; i < MAP__NR_TYPES; ++i) 348 for (i = 0; i < MAP__NR_TYPES; ++i)
397 printed += __map_groups__fprintf_maps(mg, i, verbose, fp); 349 printed += __map_groups__fprintf_maps(self, i, verbose, fp);
398 return printed; 350 return printed;
399} 351}
400 352
401static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, 353static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
402 enum map_type type, 354 enum map_type type,
403 int verbose, FILE *fp) 355 int verbose, FILE *fp)
404{ 356{
405 struct map *pos; 357 struct map *pos;
406 size_t printed = 0; 358 size_t printed = 0;
407 359
408 list_for_each_entry(pos, &mg->removed_maps[type], node) { 360 list_for_each_entry(pos, &self->removed_maps[type], node) {
409 printed += fprintf(fp, "Map:"); 361 printed += fprintf(fp, "Map:");
410 printed += map__fprintf(pos, fp); 362 printed += map__fprintf(pos, fp);
411 if (verbose > 1) { 363 if (verbose > 1) {
@@ -416,26 +368,26 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
416 return printed; 368 return printed;
417} 369}
418 370
419static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, 371static size_t map_groups__fprintf_removed_maps(struct map_groups *self,
420 int verbose, FILE *fp) 372 int verbose, FILE *fp)
421{ 373{
422 size_t printed = 0, i; 374 size_t printed = 0, i;
423 for (i = 0; i < MAP__NR_TYPES; ++i) 375 for (i = 0; i < MAP__NR_TYPES; ++i)
424 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); 376 printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp);
425 return printed; 377 return printed;
426} 378}
427 379
428size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) 380size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp)
429{ 381{
430 size_t printed = map_groups__fprintf_maps(mg, verbose, fp); 382 size_t printed = map_groups__fprintf_maps(self, verbose, fp);
431 printed += fprintf(fp, "Removed maps:\n"); 383 printed += fprintf(fp, "Removed maps:\n");
432 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); 384 return printed + map_groups__fprintf_removed_maps(self, verbose, fp);
433} 385}
434 386
435int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 387int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
436 int verbose, FILE *fp) 388 int verbose, FILE *fp)
437{ 389{
438 struct rb_root *root = &mg->maps[map->type]; 390 struct rb_root *root = &self->maps[map->type];
439 struct rb_node *next = rb_first(root); 391 struct rb_node *next = rb_first(root);
440 int err = 0; 392 int err = 0;
441 393
@@ -466,7 +418,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
466 } 418 }
467 419
468 before->end = map->start - 1; 420 before->end = map->start - 1;
469 map_groups__insert(mg, before); 421 map_groups__insert(self, before);
470 if (verbose >= 2) 422 if (verbose >= 2)
471 map__fprintf(before, fp); 423 map__fprintf(before, fp);
472 } 424 }
@@ -480,7 +432,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
480 } 432 }
481 433
482 after->start = map->end + 1; 434 after->start = map->end + 1;
483 map_groups__insert(mg, after); 435 map_groups__insert(self, after);
484 if (verbose >= 2) 436 if (verbose >= 2)
485 map__fprintf(after, fp); 437 map__fprintf(after, fp);
486 } 438 }
@@ -489,7 +441,7 @@ move_map:
489 * If we have references, just move them to a separate list. 441 * If we have references, just move them to a separate list.
490 */ 442 */
491 if (pos->referenced) 443 if (pos->referenced)
492 list_add_tail(&pos->node, &mg->removed_maps[map->type]); 444 list_add_tail(&pos->node, &self->removed_maps[map->type]);
493 else 445 else
494 map__delete(pos); 446 map__delete(pos);
495 447
@@ -503,7 +455,7 @@ move_map:
503/* 455/*
504 * XXX This should not really _copy_ te maps, but refcount them. 456 * XXX This should not really _copy_ te maps, but refcount them.
505 */ 457 */
506int map_groups__clone(struct map_groups *mg, 458int map_groups__clone(struct map_groups *self,
507 struct map_groups *parent, enum map_type type) 459 struct map_groups *parent, enum map_type type)
508{ 460{
509 struct rb_node *nd; 461 struct rb_node *nd;
@@ -512,7 +464,7 @@ int map_groups__clone(struct map_groups *mg,
512 struct map *new = map__clone(map); 464 struct map *new = map__clone(map);
513 if (new == NULL) 465 if (new == NULL)
514 return -ENOMEM; 466 return -ENOMEM;
515 map_groups__insert(mg, new); 467 map_groups__insert(self, new);
516 } 468 }
517 return 0; 469 return 0;
518} 470}
@@ -590,3 +542,142 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
590 542
591 return NULL; 543 return NULL;
592} 544}
545
546int machine__init(struct machine *self, const char *root_dir, pid_t pid)
547{
548 map_groups__init(&self->kmaps);
549 RB_CLEAR_NODE(&self->rb_node);
550 INIT_LIST_HEAD(&self->user_dsos);
551 INIT_LIST_HEAD(&self->kernel_dsos);
552
553 self->kmaps.machine = self;
554 self->pid = pid;
555 self->root_dir = strdup(root_dir);
556 return self->root_dir == NULL ? -ENOMEM : 0;
557}
558
559static void dsos__delete(struct list_head *self)
560{
561 struct dso *pos, *n;
562
563 list_for_each_entry_safe(pos, n, self, node) {
564 list_del(&pos->node);
565 dso__delete(pos);
566 }
567}
568
569void machine__exit(struct machine *self)
570{
571 map_groups__exit(&self->kmaps);
572 dsos__delete(&self->user_dsos);
573 dsos__delete(&self->kernel_dsos);
574 free(self->root_dir);
575 self->root_dir = NULL;
576}
577
578void machine__delete(struct machine *self)
579{
580 machine__exit(self);
581 free(self);
582}
583
584struct machine *machines__add(struct rb_root *self, pid_t pid,
585 const char *root_dir)
586{
587 struct rb_node **p = &self->rb_node;
588 struct rb_node *parent = NULL;
589 struct machine *pos, *machine = malloc(sizeof(*machine));
590
591 if (!machine)
592 return NULL;
593
594 if (machine__init(machine, root_dir, pid) != 0) {
595 free(machine);
596 return NULL;
597 }
598
599 while (*p != NULL) {
600 parent = *p;
601 pos = rb_entry(parent, struct machine, rb_node);
602 if (pid < pos->pid)
603 p = &(*p)->rb_left;
604 else
605 p = &(*p)->rb_right;
606 }
607
608 rb_link_node(&machine->rb_node, parent, p);
609 rb_insert_color(&machine->rb_node, self);
610
611 return machine;
612}
613
614struct machine *machines__find(struct rb_root *self, pid_t pid)
615{
616 struct rb_node **p = &self->rb_node;
617 struct rb_node *parent = NULL;
618 struct machine *machine;
619 struct machine *default_machine = NULL;
620
621 while (*p != NULL) {
622 parent = *p;
623 machine = rb_entry(parent, struct machine, rb_node);
624 if (pid < machine->pid)
625 p = &(*p)->rb_left;
626 else if (pid > machine->pid)
627 p = &(*p)->rb_right;
628 else
629 return machine;
630 if (!machine->pid)
631 default_machine = machine;
632 }
633
634 return default_machine;
635}
636
637struct machine *machines__findnew(struct rb_root *self, pid_t pid)
638{
639 char path[PATH_MAX];
640 const char *root_dir;
641 struct machine *machine = machines__find(self, pid);
642
643 if (!machine || machine->pid != pid) {
644 if (pid == HOST_KERNEL_ID || pid == DEFAULT_GUEST_KERNEL_ID)
645 root_dir = "";
646 else {
647 if (!symbol_conf.guestmount)
648 goto out;
649 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
650 if (access(path, R_OK)) {
651 pr_err("Can't access file %s\n", path);
652 goto out;
653 }
654 root_dir = path;
655 }
656 machine = machines__add(self, pid, root_dir);
657 }
658
659out:
660 return machine;
661}
662
663void machines__process(struct rb_root *self, machine__process_t process, void *data)
664{
665 struct rb_node *nd;
666
667 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
668 struct machine *pos = rb_entry(nd, struct machine, rb_node);
669 process(pos, data);
670 }
671}
672
673char *machine__mmap_name(struct machine *self, char *bf, size_t size)
674{
675 if (machine__is_host(self))
676 snprintf(bf, size, "[%s]", "kernel.kallsyms");
677 else if (machine__is_default_guest(self))
678 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
679 else
680 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
681
682 return bf;
683}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index bcb39e2a696..b397c038372 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -18,11 +18,9 @@ enum map_type {
18extern const char *map_type__name[MAP__NR_TYPES]; 18extern const char *map_type__name[MAP__NR_TYPES];
19 19
20struct dso; 20struct dso;
21struct ip_callchain;
22struct ref_reloc_sym; 21struct ref_reloc_sym;
23struct map_groups; 22struct map_groups;
24struct machine; 23struct machine;
25struct perf_evsel;
26 24
27struct map { 25struct map {
28 union { 26 union {
@@ -33,7 +31,6 @@ struct map {
33 u64 end; 31 u64 end;
34 u8 /* enum map_type */ type; 32 u8 /* enum map_type */ type;
35 bool referenced; 33 bool referenced;
36 bool erange_warned;
37 u32 priv; 34 u32 priv;
38 u64 pgoff; 35 u64 pgoff;
39 36
@@ -57,6 +54,26 @@ struct map_groups {
57 struct machine *machine; 54 struct machine *machine;
58}; 55};
59 56
57/* Native host kernel uses -1 as pid index in machine */
58#define HOST_KERNEL_ID (-1)
59#define DEFAULT_GUEST_KERNEL_ID (0)
60
61struct machine {
62 struct rb_node rb_node;
63 pid_t pid;
64 char *root_dir;
65 struct list_head user_dsos;
66 struct list_head kernel_dsos;
67 struct map_groups kmaps;
68 struct map *vmlinux_maps[MAP__NR_TYPES];
69};
70
71static inline
72struct map *machine__kernel_map(struct machine *self, enum map_type type)
73{
74 return self->vmlinux_maps[type];
75}
76
60static inline struct kmap *map__kmap(struct map *self) 77static inline struct kmap *map__kmap(struct map *self)
61{ 78{
62 return (struct kmap *)(self + 1); 79 return (struct kmap *)(self + 1);
@@ -72,7 +89,7 @@ static inline u64 map__unmap_ip(struct map *map, u64 ip)
72 return ip + map->start - map->pgoff; 89 return ip + map->start - map->pgoff;
73} 90}
74 91
75static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip) 92static inline u64 identity__map_ip(struct map *map __used, u64 ip)
76{ 93{
77 return ip; 94 return ip;
78} 95}
@@ -80,6 +97,7 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip)
80 97
81/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ 98/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
82u64 map__rip_2objdump(struct map *map, u64 rip); 99u64 map__rip_2objdump(struct map *map, u64 rip);
100u64 map__objdump_2ip(struct map *map, u64 addr);
83 101
84struct symbol; 102struct symbol;
85 103
@@ -90,12 +108,10 @@ void map__init(struct map *self, enum map_type type,
90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 108struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
91 u64 pgoff, u32 pid, char *filename, 109 u64 pgoff, u32 pid, char *filename,
92 enum map_type type); 110 enum map_type type);
93struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
94void map__delete(struct map *self); 111void map__delete(struct map *self);
95struct map *map__clone(struct map *self); 112struct map *map__clone(struct map *self);
96int map__overlap(struct map *l, struct map *r); 113int map__overlap(struct map *l, struct map *r);
97size_t map__fprintf(struct map *self, FILE *fp); 114size_t map__fprintf(struct map *self, FILE *fp);
98size_t map__fprintf_dsoname(struct map *map, FILE *fp);
99 115
100int map__load(struct map *self, symbol_filter_t filter); 116int map__load(struct map *self, symbol_filter_t filter);
101struct symbol *map__find_symbol(struct map *self, 117struct symbol *map__find_symbol(struct map *self,
@@ -107,63 +123,115 @@ void map__fixup_end(struct map *self);
107 123
108void map__reloc_vmlinux(struct map *self); 124void map__reloc_vmlinux(struct map *self);
109 125
110size_t __map_groups__fprintf_maps(struct map_groups *mg, 126size_t __map_groups__fprintf_maps(struct map_groups *self,
111 enum map_type type, int verbose, FILE *fp); 127 enum map_type type, int verbose, FILE *fp);
112void maps__insert(struct rb_root *maps, struct map *map); 128void maps__insert(struct rb_root *maps, struct map *map);
113void maps__remove(struct rb_root *maps, struct map *map); 129void maps__remove(struct rb_root *self, struct map *map);
114struct map *maps__find(struct rb_root *maps, u64 addr); 130struct map *maps__find(struct rb_root *maps, u64 addr);
115void map_groups__init(struct map_groups *mg); 131void map_groups__init(struct map_groups *self);
116void map_groups__exit(struct map_groups *mg); 132void map_groups__exit(struct map_groups *self);
117int map_groups__clone(struct map_groups *mg, 133int map_groups__clone(struct map_groups *self,
118 struct map_groups *parent, enum map_type type); 134 struct map_groups *parent, enum map_type type);
119size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 135size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
120size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); 136size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
137
138typedef void (*machine__process_t)(struct machine *self, void *data);
139
140void machines__process(struct rb_root *self, machine__process_t process, void *data);
141struct machine *machines__add(struct rb_root *self, pid_t pid,
142 const char *root_dir);
143struct machine *machines__find_host(struct rb_root *self);
144struct machine *machines__find(struct rb_root *self, pid_t pid);
145struct machine *machines__findnew(struct rb_root *self, pid_t pid);
146char *machine__mmap_name(struct machine *self, char *bf, size_t size);
147int machine__init(struct machine *self, const char *root_dir, pid_t pid);
148void machine__exit(struct machine *self);
149void machine__delete(struct machine *self);
150
151/*
152 * Default guest kernel is defined by parameter --guestkallsyms
153 * and --guestmodules
154 */
155static inline bool machine__is_default_guest(struct machine *self)
156{
157 return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false;
158}
121 159
122int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 160static inline bool machine__is_host(struct machine *self)
123 u64 addr); 161{
162 return self ? self->pid == HOST_KERNEL_ID : false;
163}
124 164
125static inline void map_groups__insert(struct map_groups *mg, struct map *map) 165static inline void map_groups__insert(struct map_groups *self, struct map *map)
126{ 166{
127 maps__insert(&mg->maps[map->type], map); 167 maps__insert(&self->maps[map->type], map);
128 map->groups = mg; 168 map->groups = self;
129} 169}
130 170
131static inline void map_groups__remove(struct map_groups *mg, struct map *map) 171static inline void map_groups__remove(struct map_groups *self, struct map *map)
132{ 172{
133 maps__remove(&mg->maps[map->type], map); 173 maps__remove(&self->maps[map->type], map);
134} 174}
135 175
136static inline struct map *map_groups__find(struct map_groups *mg, 176static inline struct map *map_groups__find(struct map_groups *self,
137 enum map_type type, u64 addr) 177 enum map_type type, u64 addr)
138{ 178{
139 return maps__find(&mg->maps[type], addr); 179 return maps__find(&self->maps[type], addr);
140} 180}
141 181
142struct symbol *map_groups__find_symbol(struct map_groups *mg, 182struct symbol *map_groups__find_symbol(struct map_groups *self,
143 enum map_type type, u64 addr, 183 enum map_type type, u64 addr,
144 struct map **mapp, 184 struct map **mapp,
145 symbol_filter_t filter); 185 symbol_filter_t filter);
146 186
147struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, 187struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
148 enum map_type type, 188 enum map_type type,
149 const char *name, 189 const char *name,
150 struct map **mapp, 190 struct map **mapp,
151 symbol_filter_t filter); 191 symbol_filter_t filter);
152 192
153static inline 193static inline
154struct symbol *map_groups__find_function_by_name(struct map_groups *mg, 194struct symbol *machine__find_kernel_symbol(struct machine *self,
195 enum map_type type, u64 addr,
196 struct map **mapp,
197 symbol_filter_t filter)
198{
199 return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter);
200}
201
202static inline
203struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
204 struct map **mapp,
205 symbol_filter_t filter)
206{
207 return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter);
208}
209
210static inline
211struct symbol *map_groups__find_function_by_name(struct map_groups *self,
155 const char *name, struct map **mapp, 212 const char *name, struct map **mapp,
156 symbol_filter_t filter) 213 symbol_filter_t filter)
157{ 214{
158 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); 215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
216}
217
218static inline
219struct symbol *machine__find_kernel_function_by_name(struct machine *self,
220 const char *name,
221 struct map **mapp,
222 symbol_filter_t filter)
223{
224 return map_groups__find_function_by_name(&self->kmaps, name, mapp,
225 filter);
159} 226}
160 227
161int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
162 int verbose, FILE *fp); 229 int verbose, FILE *fp);
163 230
164struct map *map_groups__find_by_name(struct map_groups *mg, 231struct map *map_groups__find_by_name(struct map_groups *self,
165 enum map_type type, const char *name); 232 enum map_type type, const char *name);
233struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
166 234
167void map_groups__flush(struct map_groups *mg); 235void map_groups__flush(struct map_groups *self);
168 236
169#endif /* __PERF_MAP_H */ 237#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
index 3322b8446e8..1915de20dca 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -57,10 +57,6 @@ void setup_pager(void)
57 } 57 }
58 if (!pager) 58 if (!pager)
59 pager = getenv("PAGER"); 59 pager = getenv("PAGER");
60 if (!pager) {
61 if (!access("/usr/bin/pager", X_OK))
62 pager = "/usr/bin/pager";
63 }
64 if (!pager) 60 if (!pager)
65 pager = "less"; 61 pager = "less";
66 else if (!*pager || !strcmp(pager, "cat")) 62 else if (!*pager || !strcmp(pager, "cat"))
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d8d53bec17..928918b796b 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,4 +1,4 @@
1#include <linux/hw_breakpoint.h> 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "evlist.h" 4#include "evlist.h"
@@ -11,103 +11,45 @@
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include "debugfs.h" 13#include "debugfs.h"
14#include "parse-events-bison.h"
15#define YY_EXTRA_TYPE int
16#include "parse-events-flex.h"
17#include "pmu.h"
18
19#define MAX_NAME_LEN 100
20 14
21struct event_symbol { 15struct event_symbol {
16 u8 type;
17 u64 config;
22 const char *symbol; 18 const char *symbol;
23 const char *alias; 19 const char *alias;
24}; 20};
25 21
26#ifdef PARSER_DEBUG 22enum event_result {
27extern int parse_events_debug; 23 EVT_FAILED,
28#endif 24 EVT_HANDLED,
29int parse_events_parse(void *data, void *scanner); 25 EVT_HANDLED_ALL
30
31static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
32 [PERF_COUNT_HW_CPU_CYCLES] = {
33 .symbol = "cpu-cycles",
34 .alias = "cycles",
35 },
36 [PERF_COUNT_HW_INSTRUCTIONS] = {
37 .symbol = "instructions",
38 .alias = "",
39 },
40 [PERF_COUNT_HW_CACHE_REFERENCES] = {
41 .symbol = "cache-references",
42 .alias = "",
43 },
44 [PERF_COUNT_HW_CACHE_MISSES] = {
45 .symbol = "cache-misses",
46 .alias = "",
47 },
48 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = {
49 .symbol = "branch-instructions",
50 .alias = "branches",
51 },
52 [PERF_COUNT_HW_BRANCH_MISSES] = {
53 .symbol = "branch-misses",
54 .alias = "",
55 },
56 [PERF_COUNT_HW_BUS_CYCLES] = {
57 .symbol = "bus-cycles",
58 .alias = "",
59 },
60 [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = {
61 .symbol = "stalled-cycles-frontend",
62 .alias = "idle-cycles-frontend",
63 },
64 [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = {
65 .symbol = "stalled-cycles-backend",
66 .alias = "idle-cycles-backend",
67 },
68 [PERF_COUNT_HW_REF_CPU_CYCLES] = {
69 .symbol = "ref-cycles",
70 .alias = "",
71 },
72}; 26};
73 27
74static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { 28char debugfs_path[MAXPATHLEN];
75 [PERF_COUNT_SW_CPU_CLOCK] = { 29
76 .symbol = "cpu-clock", 30#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
77 .alias = "", 31#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
78 }, 32
79 [PERF_COUNT_SW_TASK_CLOCK] = { 33static struct event_symbol event_symbols[] = {
80 .symbol = "task-clock", 34 { CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
81 .alias = "", 35 { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" },
82 }, 36 { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" },
83 [PERF_COUNT_SW_PAGE_FAULTS] = { 37 { CHW(INSTRUCTIONS), "instructions", "" },
84 .symbol = "page-faults", 38 { CHW(CACHE_REFERENCES), "cache-references", "" },
85 .alias = "faults", 39 { CHW(CACHE_MISSES), "cache-misses", "" },
86 }, 40 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
87 [PERF_COUNT_SW_CONTEXT_SWITCHES] = { 41 { CHW(BRANCH_MISSES), "branch-misses", "" },
88 .symbol = "context-switches", 42 { CHW(BUS_CYCLES), "bus-cycles", "" },
89 .alias = "cs", 43
90 }, 44 { CSW(CPU_CLOCK), "cpu-clock", "" },
91 [PERF_COUNT_SW_CPU_MIGRATIONS] = { 45 { CSW(TASK_CLOCK), "task-clock", "" },
92 .symbol = "cpu-migrations", 46 { CSW(PAGE_FAULTS), "page-faults", "faults" },
93 .alias = "migrations", 47 { CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
94 }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
95 [PERF_COUNT_SW_PAGE_FAULTS_MIN] = { 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
96 .symbol = "minor-faults", 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
97 .alias = "", 51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
98 }, 52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
99 [PERF_COUNT_SW_PAGE_FAULTS_MAJ] = {
100 .symbol = "major-faults",
101 .alias = "",
102 },
103 [PERF_COUNT_SW_ALIGNMENT_FAULTS] = {
104 .symbol = "alignment-faults",
105 .alias = "",
106 },
107 [PERF_COUNT_SW_EMULATION_FAULTS] = {
108 .symbol = "emulation-faults",
109 .alias = "",
110 },
111}; 53};
112 54
113#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
@@ -118,6 +60,75 @@ static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
118#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 60#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
119#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 61#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
120 62
63static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
64 "cycles",
65 "instructions",
66 "cache-references",
67 "cache-misses",
68 "branches",
69 "branch-misses",
70 "bus-cycles",
71 "stalled-cycles-frontend",
72 "stalled-cycles-backend",
73};
74
75static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
76 "cpu-clock",
77 "task-clock",
78 "page-faults",
79 "context-switches",
80 "CPU-migrations",
81 "minor-faults",
82 "major-faults",
83 "alignment-faults",
84 "emulation-faults",
85};
86
87#define MAX_ALIASES 8
88
89static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
90 { "L1-dcache", "l1-d", "l1d", "L1-data", },
91 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
92 { "LLC", "L2", },
93 { "dTLB", "d-tlb", "Data-TLB", },
94 { "iTLB", "i-tlb", "Instruction-TLB", },
95 { "branch", "branches", "bpu", "btb", "bpc", },
96 { "node", },
97};
98
99static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
100 { "load", "loads", "read", },
101 { "store", "stores", "write", },
102 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
103};
104
105static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
106 [MAX_ALIASES] = {
107 { "refs", "Reference", "ops", "access", },
108 { "misses", "miss", },
109};
110
111#define C(x) PERF_COUNT_HW_CACHE_##x
112#define CACHE_READ (1 << C(OP_READ))
113#define CACHE_WRITE (1 << C(OP_WRITE))
114#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
115#define COP(x) (1 << x)
116
117/*
118 * cache operartion stat
119 * L1I : Read and prefetch only
120 * ITLB and BPU : Read-only
121 */
122static unsigned long hw_cache_stat[C(MAX)] = {
123 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
124 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
125 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
126 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
127 [C(ITLB)] = (CACHE_READ),
128 [C(BPU)] = (CACHE_READ),
129 [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
130};
131
121#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ 132#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
122 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 133 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
123 if (sys_dirent.d_type == DT_DIR && \ 134 if (sys_dirent.d_type == DT_DIR && \
@@ -129,7 +140,7 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
129 char evt_path[MAXPATHLEN]; 140 char evt_path[MAXPATHLEN];
130 int fd; 141 int fd;
131 142
132 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, 143 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
133 sys_dir->d_name, evt_dir->d_name); 144 sys_dir->d_name, evt_dir->d_name);
134 fd = open(evt_path, O_RDONLY); 145 fd = open(evt_path, O_RDONLY);
135 if (fd < 0) 146 if (fd < 0)
@@ -154,22 +165,22 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
154 struct tracepoint_path *path = NULL; 165 struct tracepoint_path *path = NULL;
155 DIR *sys_dir, *evt_dir; 166 DIR *sys_dir, *evt_dir;
156 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 167 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
157 char id_buf[24]; 168 char id_buf[4];
158 int fd; 169 int fd;
159 u64 id; 170 u64 id;
160 char evt_path[MAXPATHLEN]; 171 char evt_path[MAXPATHLEN];
161 char dir_path[MAXPATHLEN]; 172 char dir_path[MAXPATHLEN];
162 173
163 if (debugfs_valid_mountpoint(tracing_events_path)) 174 if (debugfs_valid_mountpoint(debugfs_path))
164 return NULL; 175 return NULL;
165 176
166 sys_dir = opendir(tracing_events_path); 177 sys_dir = opendir(debugfs_path);
167 if (!sys_dir) 178 if (!sys_dir)
168 return NULL; 179 return NULL;
169 180
170 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 181 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
171 182
172 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, 183 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
173 sys_dirent.d_name); 184 sys_dirent.d_name);
174 evt_dir = opendir(dir_path); 185 evt_dir = opendir(dir_path);
175 if (!evt_dir) 186 if (!evt_dir)
@@ -217,6 +228,48 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
217 return NULL; 228 return NULL;
218} 229}
219 230
231#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
232static const char *tracepoint_id_to_name(u64 config)
233{
234 static char buf[TP_PATH_LEN];
235 struct tracepoint_path *path;
236
237 path = tracepoint_id_to_path(config);
238 if (path) {
239 snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
240 free(path->name);
241 free(path->system);
242 free(path);
243 } else
244 snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
245
246 return buf;
247}
248
249static int is_cache_op_valid(u8 cache_type, u8 cache_op)
250{
251 if (hw_cache_stat[cache_type] & COP(cache_op))
252 return 1; /* valid */
253 else
254 return 0; /* invalid */
255}
256
257static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
258{
259 static char name[50];
260
261 if (cache_result) {
262 sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
263 hw_cache_op[cache_op][0],
264 hw_cache_result[cache_result][0]);
265 } else {
266 sprintf(name, "%s-%s", hw_cache[cache_type][0],
267 hw_cache_op[cache_op][1]);
268 }
269
270 return name;
271}
272
220const char *event_type(int type) 273const char *event_type(int type)
221{ 274{
222 switch (type) { 275 switch (type) {
@@ -239,103 +292,128 @@ const char *event_type(int type)
239 return "unknown"; 292 return "unknown";
240} 293}
241 294
295const char *event_name(struct perf_evsel *evsel)
296{
297 u64 config = evsel->attr.config;
298 int type = evsel->attr.type;
242 299
300 if (evsel->name)
301 return evsel->name;
243 302
244static int __add_event(struct list_head **_list, int *idx, 303 return __event_name(type, config);
245 struct perf_event_attr *attr, 304}
246 char *name, struct cpu_map *cpus) 305
306const char *__event_name(int type, u64 config)
247{ 307{
248 struct perf_evsel *evsel; 308 static char buf[32];
249 struct list_head *list = *_list; 309
250 310 if (type == PERF_TYPE_RAW) {
251 if (!list) { 311 sprintf(buf, "raw 0x%" PRIx64, config);
252 list = malloc(sizeof(*list)); 312 return buf;
253 if (!list)
254 return -ENOMEM;
255 INIT_LIST_HEAD(list);
256 } 313 }
257 314
258 event_attr_init(attr); 315 switch (type) {
316 case PERF_TYPE_HARDWARE:
317 if (config < PERF_COUNT_HW_MAX && hw_event_names[config])
318 return hw_event_names[config];
319 return "unknown-hardware";
320
321 case PERF_TYPE_HW_CACHE: {
322 u8 cache_type, cache_op, cache_result;
323
324 cache_type = (config >> 0) & 0xff;
325 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
326 return "unknown-ext-hardware-cache-type";
259 327
260 evsel = perf_evsel__new(attr, (*idx)++); 328 cache_op = (config >> 8) & 0xff;
261 if (!evsel) { 329 if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
262 free(list); 330 return "unknown-ext-hardware-cache-op";
263 return -ENOMEM; 331
332 cache_result = (config >> 16) & 0xff;
333 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
334 return "unknown-ext-hardware-cache-result";
335
336 if (!is_cache_op_valid(cache_type, cache_op))
337 return "invalid-cache";
338
339 return event_cache_name(cache_type, cache_op, cache_result);
264 } 340 }
265 341
266 evsel->cpus = cpus; 342 case PERF_TYPE_SOFTWARE:
267 if (name) 343 if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
268 evsel->name = strdup(name); 344 return sw_event_names[config];
269 list_add_tail(&evsel->node, list); 345 return "unknown-software";
270 *_list = list;
271 return 0;
272}
273 346
274static int add_event(struct list_head **_list, int *idx, 347 case PERF_TYPE_TRACEPOINT:
275 struct perf_event_attr *attr, char *name) 348 return tracepoint_id_to_name(config);
276{ 349
277 return __add_event(_list, idx, attr, name, NULL); 350 default:
351 break;
352 }
353
354 return "unknown";
278} 355}
279 356
280static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) 357static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
281{ 358{
282 int i, j; 359 int i, j;
283 int n, longest = -1; 360 int n, longest = -1;
284 361
285 for (i = 0; i < size; i++) { 362 for (i = 0; i < size; i++) {
286 for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) { 363 for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
287 n = strlen(names[i][j]); 364 n = strlen(names[i][j]);
288 if (n > longest && !strncasecmp(str, names[i][j], n)) 365 if (n > longest && !strncasecmp(*str, names[i][j], n))
289 longest = n; 366 longest = n;
290 } 367 }
291 if (longest > 0) 368 if (longest > 0) {
369 *str += longest;
292 return i; 370 return i;
371 }
293 } 372 }
294 373
295 return -1; 374 return -1;
296} 375}
297 376
298int parse_events_add_cache(struct list_head **list, int *idx, 377static enum event_result
299 char *type, char *op_result1, char *op_result2) 378parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
300{ 379{
301 struct perf_event_attr attr; 380 const char *s = *str;
302 char name[MAX_NAME_LEN];
303 int cache_type = -1, cache_op = -1, cache_result = -1; 381 int cache_type = -1, cache_op = -1, cache_result = -1;
304 char *op_result[2] = { op_result1, op_result2 };
305 int i, n;
306 382
383 cache_type = parse_aliases(&s, hw_cache, PERF_COUNT_HW_CACHE_MAX);
307 /* 384 /*
308 * No fallback - if we cannot get a clear cache type 385 * No fallback - if we cannot get a clear cache type
309 * then bail out: 386 * then bail out:
310 */ 387 */
311 cache_type = parse_aliases(type, perf_evsel__hw_cache,
312 PERF_COUNT_HW_CACHE_MAX);
313 if (cache_type == -1) 388 if (cache_type == -1)
314 return -EINVAL; 389 return EVT_FAILED;
315
316 n = snprintf(name, MAX_NAME_LEN, "%s", type);
317 390
318 for (i = 0; (i < 2) && (op_result[i]); i++) { 391 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
319 char *str = op_result[i]; 392 ++s;
320
321 n += snprintf(name + n, MAX_NAME_LEN - n, "-%s", str);
322 393
323 if (cache_op == -1) { 394 if (cache_op == -1) {
324 cache_op = parse_aliases(str, perf_evsel__hw_cache_op, 395 cache_op = parse_aliases(&s, hw_cache_op,
325 PERF_COUNT_HW_CACHE_OP_MAX); 396 PERF_COUNT_HW_CACHE_OP_MAX);
326 if (cache_op >= 0) { 397 if (cache_op >= 0) {
327 if (!perf_evsel__is_cache_op_valid(cache_type, cache_op)) 398 if (!is_cache_op_valid(cache_type, cache_op))
328 return -EINVAL; 399 return EVT_FAILED;
329 continue; 400 continue;
330 } 401 }
331 } 402 }
332 403
333 if (cache_result == -1) { 404 if (cache_result == -1) {
334 cache_result = parse_aliases(str, perf_evsel__hw_cache_result, 405 cache_result = parse_aliases(&s, hw_cache_result,
335 PERF_COUNT_HW_CACHE_RESULT_MAX); 406 PERF_COUNT_HW_CACHE_RESULT_MAX);
336 if (cache_result >= 0) 407 if (cache_result >= 0)
337 continue; 408 continue;
338 } 409 }
410
411 /*
412 * Can't parse this as a cache op or result, so back up
413 * to the '-'.
414 */
415 --s;
416 break;
339 } 417 }
340 418
341 /* 419 /*
@@ -350,322 +428,324 @@ int parse_events_add_cache(struct list_head **list, int *idx,
350 if (cache_result == -1) 428 if (cache_result == -1)
351 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; 429 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
352 430
353 memset(&attr, 0, sizeof(attr)); 431 attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
354 attr.config = cache_type | (cache_op << 8) | (cache_result << 16); 432 attr->type = PERF_TYPE_HW_CACHE;
355 attr.type = PERF_TYPE_HW_CACHE; 433
356 return add_event(list, idx, &attr, name); 434 *str = s;
435 return EVT_HANDLED;
357} 436}
358 437
359static int add_tracepoint(struct list_head **listp, int *idx, 438static enum event_result
360 char *sys_name, char *evt_name) 439parse_single_tracepoint_event(char *sys_name,
440 const char *evt_name,
441 unsigned int evt_length,
442 struct perf_event_attr *attr,
443 const char **strp)
361{ 444{
362 struct perf_evsel *evsel; 445 char evt_path[MAXPATHLEN];
363 struct list_head *list = *listp; 446 char id_buf[4];
364 447 u64 id;
365 if (!list) { 448 int fd;
366 list = malloc(sizeof(*list)); 449
367 if (!list) 450 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
368 return -ENOMEM; 451 sys_name, evt_name);
369 INIT_LIST_HEAD(list); 452
370 } 453 fd = open(evt_path, O_RDONLY);
454 if (fd < 0)
455 return EVT_FAILED;
371 456
372 evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); 457 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
373 if (!evsel) { 458 close(fd);
374 free(list); 459 return EVT_FAILED;
375 return -ENOMEM;
376 } 460 }
377 461
378 list_add_tail(&evsel->node, list); 462 close(fd);
379 *listp = list; 463 id = atoll(id_buf);
380 return 0; 464 attr->config = id;
465 attr->type = PERF_TYPE_TRACEPOINT;
466 *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
467
468 attr->sample_type |= PERF_SAMPLE_RAW;
469 attr->sample_type |= PERF_SAMPLE_TIME;
470 attr->sample_type |= PERF_SAMPLE_CPU;
471
472 attr->sample_period = 1;
473
474
475 return EVT_HANDLED;
381} 476}
382 477
383static int add_tracepoint_multi(struct list_head **list, int *idx, 478/* sys + ':' + event + ':' + flags*/
384 char *sys_name, char *evt_name) 479#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
480static enum event_result
481parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
482 const char *evt_exp, char *flags)
385{ 483{
386 char evt_path[MAXPATHLEN]; 484 char evt_path[MAXPATHLEN];
387 struct dirent *evt_ent; 485 struct dirent *evt_ent;
388 DIR *evt_dir; 486 DIR *evt_dir;
389 int ret = 0;
390 487
391 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); 488 snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name);
392 evt_dir = opendir(evt_path); 489 evt_dir = opendir(evt_path);
490
393 if (!evt_dir) { 491 if (!evt_dir) {
394 perror("Can't open event dir"); 492 perror("Can't open event dir");
395 return -1; 493 return EVT_FAILED;
396 } 494 }
397 495
398 while (!ret && (evt_ent = readdir(evt_dir))) { 496 while ((evt_ent = readdir(evt_dir))) {
497 char event_opt[MAX_EVOPT_LEN + 1];
498 int len;
499
399 if (!strcmp(evt_ent->d_name, ".") 500 if (!strcmp(evt_ent->d_name, ".")
400 || !strcmp(evt_ent->d_name, "..") 501 || !strcmp(evt_ent->d_name, "..")
401 || !strcmp(evt_ent->d_name, "enable") 502 || !strcmp(evt_ent->d_name, "enable")
402 || !strcmp(evt_ent->d_name, "filter")) 503 || !strcmp(evt_ent->d_name, "filter"))
403 continue; 504 continue;
404 505
405 if (!strglobmatch(evt_ent->d_name, evt_name)) 506 if (!strglobmatch(evt_ent->d_name, evt_exp))
406 continue; 507 continue;
407 508
408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); 509 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
510 evt_ent->d_name, flags ? ":" : "",
511 flags ?: "");
512 if (len < 0)
513 return EVT_FAILED;
514
515 if (parse_events(evlist, event_opt, 0))
516 return EVT_FAILED;
409 } 517 }
410 518
411 return ret; 519 return EVT_HANDLED_ALL;
412} 520}
413 521
414int parse_events_add_tracepoint(struct list_head **list, int *idx, 522static enum event_result
415 char *sys, char *event) 523parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
524 struct perf_event_attr *attr)
416{ 525{
417 int ret; 526 const char *evt_name;
527 char *flags = NULL, *comma_loc;
528 char sys_name[MAX_EVENT_LENGTH];
529 unsigned int sys_length, evt_length;
418 530
419 ret = debugfs_valid_mountpoint(tracing_events_path); 531 if (debugfs_valid_mountpoint(debugfs_path))
420 if (ret) 532 return 0;
421 return ret;
422 533
423 return strpbrk(event, "*?") ? 534 evt_name = strchr(*strp, ':');
424 add_tracepoint_multi(list, idx, sys, event) : 535 if (!evt_name)
425 add_tracepoint(list, idx, sys, event); 536 return EVT_FAILED;
537
538 sys_length = evt_name - *strp;
539 if (sys_length >= MAX_EVENT_LENGTH)
540 return 0;
541
542 strncpy(sys_name, *strp, sys_length);
543 sys_name[sys_length] = '\0';
544 evt_name = evt_name + 1;
545
546 comma_loc = strchr(evt_name, ',');
547 if (comma_loc) {
548 /* take the event name up to the comma */
549 evt_name = strndup(evt_name, comma_loc - evt_name);
550 }
551 flags = strchr(evt_name, ':');
552 if (flags) {
553 /* split it out: */
554 evt_name = strndup(evt_name, flags - evt_name);
555 flags++;
556 }
557
558 evt_length = strlen(evt_name);
559 if (evt_length >= MAX_EVENT_LENGTH)
560 return EVT_FAILED;
561 if (strpbrk(evt_name, "*?")) {
562 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
563 return parse_multiple_tracepoint_event(evlist, sys_name,
564 evt_name, flags);
565 } else {
566 return parse_single_tracepoint_event(sys_name, evt_name,
567 evt_length, attr, strp);
568 }
426} 569}
427 570
428static int 571static enum event_result
429parse_breakpoint_type(const char *type, struct perf_event_attr *attr) 572parse_breakpoint_type(const char *type, const char **strp,
573 struct perf_event_attr *attr)
430{ 574{
431 int i; 575 int i;
432 576
433 for (i = 0; i < 3; i++) { 577 for (i = 0; i < 3; i++) {
434 if (!type || !type[i]) 578 if (!type[i])
435 break; 579 break;
436 580
437#define CHECK_SET_TYPE(bit) \
438do { \
439 if (attr->bp_type & bit) \
440 return -EINVAL; \
441 else \
442 attr->bp_type |= bit; \
443} while (0)
444
445 switch (type[i]) { 581 switch (type[i]) {
446 case 'r': 582 case 'r':
447 CHECK_SET_TYPE(HW_BREAKPOINT_R); 583 attr->bp_type |= HW_BREAKPOINT_R;
448 break; 584 break;
449 case 'w': 585 case 'w':
450 CHECK_SET_TYPE(HW_BREAKPOINT_W); 586 attr->bp_type |= HW_BREAKPOINT_W;
451 break; 587 break;
452 case 'x': 588 case 'x':
453 CHECK_SET_TYPE(HW_BREAKPOINT_X); 589 attr->bp_type |= HW_BREAKPOINT_X;
454 break; 590 break;
455 default: 591 default:
456 return -EINVAL; 592 return EVT_FAILED;
457 } 593 }
458 } 594 }
459
460#undef CHECK_SET_TYPE
461
462 if (!attr->bp_type) /* Default */ 595 if (!attr->bp_type) /* Default */
463 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; 596 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
464 597
465 return 0; 598 *strp = type + i;
466}
467
468int parse_events_add_breakpoint(struct list_head **list, int *idx,
469 void *ptr, char *type)
470{
471 struct perf_event_attr attr;
472
473 memset(&attr, 0, sizeof(attr));
474 attr.bp_addr = (unsigned long) ptr;
475
476 if (parse_breakpoint_type(type, &attr))
477 return -EINVAL;
478
479 /*
480 * We should find a nice way to override the access length
481 * Provide some defaults for now
482 */
483 if (attr.bp_type == HW_BREAKPOINT_X)
484 attr.bp_len = sizeof(long);
485 else
486 attr.bp_len = HW_BREAKPOINT_LEN_4;
487
488 attr.type = PERF_TYPE_BREAKPOINT;
489 attr.sample_period = 1;
490
491 return add_event(list, idx, &attr, NULL);
492}
493
494static int config_term(struct perf_event_attr *attr,
495 struct parse_events__term *term)
496{
497#define CHECK_TYPE_VAL(type) \
498do { \
499 if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \
500 return -EINVAL; \
501} while (0)
502
503 switch (term->type_term) {
504 case PARSE_EVENTS__TERM_TYPE_CONFIG:
505 CHECK_TYPE_VAL(NUM);
506 attr->config = term->val.num;
507 break;
508 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
509 CHECK_TYPE_VAL(NUM);
510 attr->config1 = term->val.num;
511 break;
512 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
513 CHECK_TYPE_VAL(NUM);
514 attr->config2 = term->val.num;
515 break;
516 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
517 CHECK_TYPE_VAL(NUM);
518 attr->sample_period = term->val.num;
519 break;
520 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
521 /*
522 * TODO uncomment when the field is available
523 * attr->branch_sample_type = term->val.num;
524 */
525 break;
526 case PARSE_EVENTS__TERM_TYPE_NAME:
527 CHECK_TYPE_VAL(STR);
528 break;
529 default:
530 return -EINVAL;
531 }
532 599
533 return 0; 600 return EVT_HANDLED;
534#undef CHECK_TYPE_VAL
535} 601}
536 602
537static int config_attr(struct perf_event_attr *attr, 603static enum event_result
538 struct list_head *head, int fail) 604parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
539{ 605{
540 struct parse_events__term *term; 606 const char *target;
607 const char *type;
608 char *endaddr;
609 u64 addr;
610 enum event_result err;
541 611
542 list_for_each_entry(term, head, list) 612 target = strchr(*strp, ':');
543 if (config_term(attr, term) && fail) 613 if (!target)
544 return -EINVAL; 614 return EVT_FAILED;
545 615
546 return 0; 616 if (strncmp(*strp, "mem", target - *strp) != 0)
547} 617 return EVT_FAILED;
548 618
549int parse_events_add_numeric(struct list_head **list, int *idx, 619 target++;
550 u32 type, u64 config,
551 struct list_head *head_config)
552{
553 struct perf_event_attr attr;
554 620
555 memset(&attr, 0, sizeof(attr)); 621 addr = strtoull(target, &endaddr, 0);
556 attr.type = type; 622 if (target == endaddr)
557 attr.config = config; 623 return EVT_FAILED;
558 624
559 if (head_config && 625 attr->bp_addr = addr;
560 config_attr(&attr, head_config, 1)) 626 *strp = endaddr;
561 return -EINVAL;
562 627
563 return add_event(list, idx, &attr, NULL); 628 type = strchr(target, ':');
564}
565 629
566static int parse_events__is_name_term(struct parse_events__term *term) 630 /* If no type is defined, just rw as default */
567{ 631 if (!type) {
568 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; 632 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
569} 633 } else {
634 err = parse_breakpoint_type(++type, strp, attr);
635 if (err == EVT_FAILED)
636 return EVT_FAILED;
637 }
570 638
571static char *pmu_event_name(struct list_head *head_terms) 639 /*
572{ 640 * We should find a nice way to override the access length
573 struct parse_events__term *term; 641 * Provide some defaults for now
642 */
643 if (attr->bp_type == HW_BREAKPOINT_X)
644 attr->bp_len = sizeof(long);
645 else
646 attr->bp_len = HW_BREAKPOINT_LEN_4;
574 647
575 list_for_each_entry(term, head_terms, list) 648 attr->type = PERF_TYPE_BREAKPOINT;
576 if (parse_events__is_name_term(term))
577 return term->val.str;
578 649
579 return NULL; 650 return EVT_HANDLED;
580} 651}
581 652
582int parse_events_add_pmu(struct list_head **list, int *idx, 653static int check_events(const char *str, unsigned int i)
583 char *name, struct list_head *head_config)
584{ 654{
585 struct perf_event_attr attr; 655 int n;
586 struct perf_pmu *pmu;
587
588 pmu = perf_pmu__find(name);
589 if (!pmu)
590 return -EINVAL;
591
592 memset(&attr, 0, sizeof(attr));
593
594 if (perf_pmu__check_alias(pmu, head_config))
595 return -EINVAL;
596 656
597 /* 657 n = strlen(event_symbols[i].symbol);
598 * Configure hardcoded terms first, no need to check 658 if (!strncasecmp(str, event_symbols[i].symbol, n))
599 * return value when called with fail == 0 ;) 659 return n;
600 */
601 config_attr(&attr, head_config, 0);
602 660
603 if (perf_pmu__config(pmu, &attr, head_config)) 661 n = strlen(event_symbols[i].alias);
604 return -EINVAL; 662 if (n) {
663 if (!strncasecmp(str, event_symbols[i].alias, n))
664 return n;
665 }
605 666
606 return __add_event(list, idx, &attr, pmu_event_name(head_config), 667 return 0;
607 pmu->cpus);
608} 668}
609 669
610int parse_events__modifier_group(struct list_head *list, 670static enum event_result
611 char *event_mod) 671parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
612{ 672{
613 return parse_events__modifier_event(list, event_mod, true); 673 const char *str = *strp;
674 unsigned int i;
675 int n;
676
677 for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
678 n = check_events(str, i);
679 if (n > 0) {
680 attr->type = event_symbols[i].type;
681 attr->config = event_symbols[i].config;
682 *strp = str + n;
683 return EVT_HANDLED;
684 }
685 }
686 return EVT_FAILED;
614} 687}
615 688
616void parse_events__set_leader(char *name, struct list_head *list) 689static enum event_result
690parse_raw_event(const char **strp, struct perf_event_attr *attr)
617{ 691{
618 struct perf_evsel *leader; 692 const char *str = *strp;
619 693 u64 config;
620 __perf_evlist__set_leader(list); 694 int n;
621 leader = list_entry(list->next, struct perf_evsel, node); 695
622 leader->group_name = name ? strdup(name) : NULL; 696 if (*str != 'r')
697 return EVT_FAILED;
698 n = hex2u64(str + 1, &config);
699 if (n > 0) {
700 const char *end = str + n + 1;
701 if (*end != '\0' && *end != ',' && *end != ':')
702 return EVT_FAILED;
703
704 *strp = end;
705 attr->type = PERF_TYPE_RAW;
706 attr->config = config;
707 return EVT_HANDLED;
708 }
709 return EVT_FAILED;
623} 710}
624 711
625void parse_events_update_lists(struct list_head *list_event, 712static enum event_result
626 struct list_head *list_all) 713parse_numeric_event(const char **strp, struct perf_event_attr *attr)
627{ 714{
628 /* 715 const char *str = *strp;
629 * Called for single event definition. Update the 716 char *endp;
630 * 'all event' list, and reinit the 'single event' 717 unsigned long type;
631 * list, for next event definition. 718 u64 config;
632 */ 719
633 list_splice_tail(list_event, list_all); 720 type = strtoul(str, &endp, 0);
634 free(list_event); 721 if (endp > str && type < PERF_TYPE_MAX && *endp == ':') {
722 str = endp + 1;
723 config = strtoul(str, &endp, 0);
724 if (endp > str) {
725 attr->type = type;
726 attr->config = config;
727 *strp = endp;
728 return EVT_HANDLED;
729 }
730 }
731 return EVT_FAILED;
635} 732}
636 733
637struct event_modifier { 734static int
638 int eu; 735parse_event_modifier(const char **strp, struct perf_event_attr *attr)
639 int ek;
640 int eh;
641 int eH;
642 int eG;
643 int precise;
644 int exclude_GH;
645};
646
647static int get_event_modifier(struct event_modifier *mod, char *str,
648 struct perf_evsel *evsel)
649{ 736{
650 int eu = evsel ? evsel->attr.exclude_user : 0; 737 const char *str = *strp;
651 int ek = evsel ? evsel->attr.exclude_kernel : 0; 738 int exclude = 0;
652 int eh = evsel ? evsel->attr.exclude_hv : 0; 739 int eu = 0, ek = 0, eh = 0, precise = 0;
653 int eH = evsel ? evsel->attr.exclude_host : 0;
654 int eG = evsel ? evsel->attr.exclude_guest : 0;
655 int precise = evsel ? evsel->attr.precise_ip : 0;
656 740
657 int exclude = eu | ek | eh; 741 if (!*str)
658 int exclude_GH = evsel ? evsel->exclude_GH : 0; 742 return 0;
659 743
660 /* 744 if (*str == ',')
661 * We are here for group and 'GH' was not set as event 745 return 0;
662 * modifier and whatever event/group modifier override
663 * default 'GH' setup.
664 */
665 if (evsel && !exclude_GH)
666 eH = eG = 0;
667 746
668 memset(mod, 0, sizeof(*mod)); 747 if (*str++ != ':')
748 return -1;
669 749
670 while (*str) { 750 while (*str) {
671 if (*str == 'u') { 751 if (*str == 'u') {
@@ -680,201 +760,130 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
680 if (!exclude) 760 if (!exclude)
681 exclude = eu = ek = eh = 1; 761 exclude = eu = ek = eh = 1;
682 eh = 0; 762 eh = 0;
683 } else if (*str == 'G') {
684 if (!exclude_GH)
685 exclude_GH = eG = eH = 1;
686 eG = 0;
687 } else if (*str == 'H') {
688 if (!exclude_GH)
689 exclude_GH = eG = eH = 1;
690 eH = 0;
691 } else if (*str == 'p') { 763 } else if (*str == 'p') {
692 precise++; 764 precise++;
693 /* use of precise requires exclude_guest */
694 if (!exclude_GH)
695 eG = 1;
696 } else 765 } else
697 break; 766 break;
698 767
699 ++str; 768 ++str;
700 } 769 }
770 if (str < *strp + 2)
771 return -1;
701 772
702 /* 773 *strp = str;
703 * precise ip: 774
704 * 775 attr->exclude_user = eu;
705 * 0 - SAMPLE_IP can have arbitrary skid 776 attr->exclude_kernel = ek;
706 * 1 - SAMPLE_IP must have constant skid 777 attr->exclude_hv = eh;
707 * 2 - SAMPLE_IP requested to have 0 skid 778 attr->precise_ip = precise;
708 * 3 - SAMPLE_IP must have 0 skid
709 *
710 * See also PERF_RECORD_MISC_EXACT_IP
711 */
712 if (precise > 3)
713 return -EINVAL;
714 779
715 mod->eu = eu;
716 mod->ek = ek;
717 mod->eh = eh;
718 mod->eH = eH;
719 mod->eG = eG;
720 mod->precise = precise;
721 mod->exclude_GH = exclude_GH;
722 return 0; 780 return 0;
723} 781}
724 782
725/* 783/*
726 * Basic modifier sanity check to validate it contains only one 784 * Each event can have multiple symbolic names.
727 * instance of any modifier (apart from 'p') present. 785 * Symbolic names are (almost) exactly matched.
728 */ 786 */
729static int check_modifier(char *str) 787static enum event_result
788parse_event_symbols(struct perf_evlist *evlist, const char **str,
789 struct perf_event_attr *attr)
730{ 790{
731 char *p = str; 791 enum event_result ret;
732 792
733 /* The sizeof includes 0 byte as well. */ 793 ret = parse_tracepoint_event(evlist, str, attr);
734 if (strlen(str) > (sizeof("ukhGHppp") - 1)) 794 if (ret != EVT_FAILED)
735 return -1; 795 goto modifier;
736 796
737 while (*p) { 797 ret = parse_raw_event(str, attr);
738 if (*p != 'p' && strchr(p + 1, *p)) 798 if (ret != EVT_FAILED)
739 return -1; 799 goto modifier;
740 p++;
741 }
742 800
743 return 0; 801 ret = parse_numeric_event(str, attr);
744} 802 if (ret != EVT_FAILED)
803 goto modifier;
745 804
746int parse_events__modifier_event(struct list_head *list, char *str, bool add) 805 ret = parse_symbolic_event(str, attr);
747{ 806 if (ret != EVT_FAILED)
748 struct perf_evsel *evsel; 807 goto modifier;
749 struct event_modifier mod;
750 808
751 if (str == NULL) 809 ret = parse_generic_hw_event(str, attr);
752 return 0; 810 if (ret != EVT_FAILED)
811 goto modifier;
753 812
754 if (check_modifier(str)) 813 ret = parse_breakpoint_event(str, attr);
755 return -EINVAL; 814 if (ret != EVT_FAILED)
815 goto modifier;
756 816
757 if (!add && get_event_modifier(&mod, str, NULL)) 817 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
758 return -EINVAL; 818 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
759 819 return EVT_FAILED;
760 list_for_each_entry(evsel, list, node) {
761 820
762 if (add && get_event_modifier(&mod, str, evsel)) 821modifier:
763 return -EINVAL; 822 if (parse_event_modifier(str, attr) < 0) {
823 fprintf(stderr, "invalid event modifier: '%s'\n", *str);
824 fprintf(stderr, "Run 'perf list' for a list of valid events and modifiers\n");
764 825
765 evsel->attr.exclude_user = mod.eu; 826 return EVT_FAILED;
766 evsel->attr.exclude_kernel = mod.ek;
767 evsel->attr.exclude_hv = mod.eh;
768 evsel->attr.precise_ip = mod.precise;
769 evsel->attr.exclude_host = mod.eH;
770 evsel->attr.exclude_guest = mod.eG;
771 evsel->exclude_GH = mod.exclude_GH;
772 } 827 }
773 828
774 return 0;
775}
776
777int parse_events_name(struct list_head *list, char *name)
778{
779 struct perf_evsel *evsel;
780
781 list_for_each_entry(evsel, list, node) {
782 if (!evsel->name)
783 evsel->name = strdup(name);
784 }
785
786 return 0;
787}
788
789static int parse_events__scanner(const char *str, void *data, int start_token)
790{
791 YY_BUFFER_STATE buffer;
792 void *scanner;
793 int ret;
794
795 ret = parse_events_lex_init_extra(start_token, &scanner);
796 if (ret)
797 return ret;
798
799 buffer = parse_events__scan_string(str, scanner);
800
801#ifdef PARSER_DEBUG
802 parse_events_debug = 1;
803#endif
804 ret = parse_events_parse(data, scanner);
805
806 parse_events__flush_buffer(buffer, scanner);
807 parse_events__delete_buffer(buffer, scanner);
808 parse_events_lex_destroy(scanner);
809 return ret; 829 return ret;
810} 830}
811 831
812/* 832int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
813 * parse event config string, return a list of event terms.
814 */
815int parse_events_terms(struct list_head *terms, const char *str)
816{ 833{
817 struct parse_events_data__terms data = { 834 struct perf_event_attr attr;
818 .terms = NULL, 835 enum event_result ret;
819 }; 836 const char *ostr;
820 int ret; 837
821 838 for (;;) {
822 ret = parse_events__scanner(str, &data, PE_START_TERMS); 839 ostr = str;
823 if (!ret) { 840 memset(&attr, 0, sizeof(attr));
824 list_splice(data.terms, terms); 841 ret = parse_event_symbols(evlist, &str, &attr);
825 free(data.terms); 842 if (ret == EVT_FAILED)
826 return 0; 843 return -1;
827 }
828 844
829 parse_events__free_terms(data.terms); 845 if (!(*str == 0 || *str == ',' || isspace(*str)))
830 return ret; 846 return -1;
831}
832 847
833int parse_events(struct perf_evlist *evlist, const char *str, 848 if (ret != EVT_HANDLED_ALL) {
834 int unset __maybe_unused) 849 struct perf_evsel *evsel;
835{ 850 evsel = perf_evsel__new(&attr, evlist->nr_entries);
836 struct parse_events_data__events data = { 851 if (evsel == NULL)
837 .list = LIST_HEAD_INIT(data.list), 852 return -1;
838 .idx = evlist->nr_entries, 853 perf_evlist__add(evlist, evsel);
839 }; 854
840 int ret; 855 evsel->name = calloc(str - ostr + 1, 1);
841 856 if (!evsel->name)
842 ret = parse_events__scanner(str, &data, PE_START_EVENTS); 857 return -1;
843 if (!ret) { 858 strncpy(evsel->name, ostr, str - ostr);
844 int entries = data.idx - evlist->nr_entries; 859 }
845 perf_evlist__splice_list_tail(evlist, &data.list, entries); 860
846 return 0; 861 if (*str == 0)
862 break;
863 if (*str == ',')
864 ++str;
865 while (isspace(*str))
866 ++str;
847 } 867 }
848 868
849 /* 869 return 0;
850 * There are 2 users - builtin-record and builtin-test objects.
851 * Both call perf_evlist__delete in case of error, so we dont
852 * need to bother.
853 */
854 return ret;
855} 870}
856 871
857int parse_events_option(const struct option *opt, const char *str, 872int parse_events_option(const struct option *opt, const char *str,
858 int unset __maybe_unused) 873 int unset __used)
859{ 874{
860 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 875 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
861 int ret = parse_events(evlist, str, unset); 876 return parse_events(evlist, str, unset);
862
863 if (ret) {
864 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
865 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
866 }
867 return ret;
868} 877}
869 878
870int parse_filter(const struct option *opt, const char *str, 879int parse_filter(const struct option *opt, const char *str,
871 int unset __maybe_unused) 880 int unset __used)
872{ 881{
873 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 882 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
874 struct perf_evsel *last = NULL; 883 struct perf_evsel *last = NULL;
875 884
876 if (evlist->nr_entries > 0) 885 if (evlist->nr_entries > 0)
877 last = perf_evlist__last(evlist); 886 last = list_entry(evlist->entries.prev, struct perf_evsel, node);
878 887
879 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { 888 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
880 fprintf(stderr, 889 fprintf(stderr,
@@ -904,18 +913,17 @@ static const char * const event_type_descriptors[] = {
904 * Print the events from <debugfs_mount_point>/tracing/events 913 * Print the events from <debugfs_mount_point>/tracing/events
905 */ 914 */
906 915
907void print_tracepoint_events(const char *subsys_glob, const char *event_glob, 916void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
908 bool name_only)
909{ 917{
910 DIR *sys_dir, *evt_dir; 918 DIR *sys_dir, *evt_dir;
911 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 919 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
912 char evt_path[MAXPATHLEN]; 920 char evt_path[MAXPATHLEN];
913 char dir_path[MAXPATHLEN]; 921 char dir_path[MAXPATHLEN];
914 922
915 if (debugfs_valid_mountpoint(tracing_events_path)) 923 if (debugfs_valid_mountpoint(debugfs_path))
916 return; 924 return;
917 925
918 sys_dir = opendir(tracing_events_path); 926 sys_dir = opendir(debugfs_path);
919 if (!sys_dir) 927 if (!sys_dir)
920 return; 928 return;
921 929
@@ -924,7 +932,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
924 !strglobmatch(sys_dirent.d_name, subsys_glob)) 932 !strglobmatch(sys_dirent.d_name, subsys_glob))
925 continue; 933 continue;
926 934
927 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, 935 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
928 sys_dirent.d_name); 936 sys_dirent.d_name);
929 evt_dir = opendir(dir_path); 937 evt_dir = opendir(dir_path);
930 if (!evt_dir) 938 if (!evt_dir)
@@ -935,11 +943,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
935 !strglobmatch(evt_dirent.d_name, event_glob)) 943 !strglobmatch(evt_dirent.d_name, event_glob))
936 continue; 944 continue;
937 945
938 if (name_only) {
939 printf("%s:%s ", sys_dirent.d_name, evt_dirent.d_name);
940 continue;
941 }
942
943 snprintf(evt_path, MAXPATHLEN, "%s:%s", 946 snprintf(evt_path, MAXPATHLEN, "%s:%s",
944 sys_dirent.d_name, evt_dirent.d_name); 947 sys_dirent.d_name, evt_dirent.d_name);
945 printf(" %-50s [%s]\n", evt_path, 948 printf(" %-50s [%s]\n", evt_path,
@@ -961,16 +964,16 @@ int is_valid_tracepoint(const char *event_string)
961 char evt_path[MAXPATHLEN]; 964 char evt_path[MAXPATHLEN];
962 char dir_path[MAXPATHLEN]; 965 char dir_path[MAXPATHLEN];
963 966
964 if (debugfs_valid_mountpoint(tracing_events_path)) 967 if (debugfs_valid_mountpoint(debugfs_path))
965 return 0; 968 return 0;
966 969
967 sys_dir = opendir(tracing_events_path); 970 sys_dir = opendir(debugfs_path);
968 if (!sys_dir) 971 if (!sys_dir)
969 return 0; 972 return 0;
970 973
971 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 974 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
972 975
973 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, 976 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
974 sys_dirent.d_name); 977 sys_dirent.d_name);
975 evt_dir = opendir(dir_path); 978 evt_dir = opendir(dir_path);
976 if (!evt_dir) 979 if (!evt_dir)
@@ -991,13 +994,16 @@ int is_valid_tracepoint(const char *event_string)
991 return 0; 994 return 0;
992} 995}
993 996
994static void __print_events_type(u8 type, struct event_symbol *syms, 997void print_events_type(u8 type)
995 unsigned max)
996{ 998{
999 struct event_symbol *syms = event_symbols;
1000 unsigned int i;
997 char name[64]; 1001 char name[64];
998 unsigned i;
999 1002
1000 for (i = 0; i < max ; i++, syms++) { 1003 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
1004 if (type != syms->type)
1005 continue;
1006
1001 if (strlen(syms->alias)) 1007 if (strlen(syms->alias))
1002 snprintf(name, sizeof(name), "%s OR %s", 1008 snprintf(name, sizeof(name), "%s OR %s",
1003 syms->symbol, syms->alias); 1009 syms->symbol, syms->alias);
@@ -1009,36 +1015,24 @@ static void __print_events_type(u8 type, struct event_symbol *syms,
1009 } 1015 }
1010} 1016}
1011 1017
1012void print_events_type(u8 type) 1018int print_hwcache_events(const char *event_glob)
1013{
1014 if (type == PERF_TYPE_SOFTWARE)
1015 __print_events_type(type, event_symbols_sw, PERF_COUNT_SW_MAX);
1016 else
1017 __print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX);
1018}
1019
1020int print_hwcache_events(const char *event_glob, bool name_only)
1021{ 1019{
1022 unsigned int type, op, i, printed = 0; 1020 unsigned int type, op, i, printed = 0;
1023 char name[64];
1024 1021
1025 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 1022 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
1026 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 1023 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
1027 /* skip invalid cache type */ 1024 /* skip invalid cache type */
1028 if (!perf_evsel__is_cache_op_valid(type, op)) 1025 if (!is_cache_op_valid(type, op))
1029 continue; 1026 continue;
1030 1027
1031 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 1028 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
1032 __perf_evsel__hw_cache_type_op_res_name(type, op, i, 1029 char *name = event_cache_name(type, op, i);
1033 name, sizeof(name)); 1030
1034 if (event_glob != NULL && !strglobmatch(name, event_glob)) 1031 if (event_glob != NULL && !strglobmatch(name, event_glob))
1035 continue; 1032 continue;
1036 1033
1037 if (name_only) 1034 printf(" %-50s [%s]\n", name,
1038 printf("%s ", name); 1035 event_type_descriptors[PERF_TYPE_HW_CACHE]);
1039 else
1040 printf(" %-50s [%s]\n", name,
1041 event_type_descriptors[PERF_TYPE_HW_CACHE]);
1042 ++printed; 1036 ++printed;
1043 } 1037 }
1044 } 1038 }
@@ -1047,160 +1041,64 @@ int print_hwcache_events(const char *event_glob, bool name_only)
1047 return printed; 1041 return printed;
1048} 1042}
1049 1043
1050static void print_symbol_events(const char *event_glob, unsigned type, 1044#define MAX_NAME_LEN 100
1051 struct event_symbol *syms, unsigned max, 1045
1052 bool name_only) 1046/*
1047 * Print the help text for the event symbols:
1048 */
1049void print_events(const char *event_glob)
1053{ 1050{
1054 unsigned i, printed = 0; 1051 unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
1052 struct event_symbol *syms = event_symbols;
1055 char name[MAX_NAME_LEN]; 1053 char name[MAX_NAME_LEN];
1056 1054
1057 for (i = 0; i < max; i++, syms++) { 1055 printf("\n");
1056 printf("List of pre-defined events (to be used in -e):\n");
1057
1058 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
1059 type = syms->type;
1060
1061 if (type != prev_type && printed) {
1062 printf("\n");
1063 printed = 0;
1064 ntypes_printed++;
1065 }
1058 1066
1059 if (event_glob != NULL && 1067 if (event_glob != NULL &&
1060 !(strglobmatch(syms->symbol, event_glob) || 1068 !(strglobmatch(syms->symbol, event_glob) ||
1061 (syms->alias && strglobmatch(syms->alias, event_glob)))) 1069 (syms->alias && strglobmatch(syms->alias, event_glob))))
1062 continue; 1070 continue;
1063 1071
1064 if (name_only) {
1065 printf("%s ", syms->symbol);
1066 continue;
1067 }
1068
1069 if (strlen(syms->alias)) 1072 if (strlen(syms->alias))
1070 snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); 1073 snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
1071 else 1074 else
1072 strncpy(name, syms->symbol, MAX_NAME_LEN); 1075 strncpy(name, syms->symbol, MAX_NAME_LEN);
1076 printf(" %-50s [%s]\n", name,
1077 event_type_descriptors[type]);
1073 1078
1074 printf(" %-50s [%s]\n", name, event_type_descriptors[type]); 1079 prev_type = type;
1075 1080 ++printed;
1076 printed++;
1077 } 1081 }
1078 1082
1079 if (printed) 1083 if (ntypes_printed) {
1080 printf("\n"); 1084 printed = 0;
1081}
1082
1083/*
1084 * Print the help text for the event symbols:
1085 */
1086void print_events(const char *event_glob, bool name_only)
1087{
1088 if (!name_only) {
1089 printf("\n"); 1085 printf("\n");
1090 printf("List of pre-defined events (to be used in -e):\n");
1091 } 1086 }
1092 1087 print_hwcache_events(event_glob);
1093 print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
1094 event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
1095
1096 print_symbol_events(event_glob, PERF_TYPE_SOFTWARE,
1097 event_symbols_sw, PERF_COUNT_SW_MAX, name_only);
1098
1099 print_hwcache_events(event_glob, name_only);
1100 1088
1101 if (event_glob != NULL) 1089 if (event_glob != NULL)
1102 return; 1090 return;
1103 1091
1104 if (!name_only) { 1092 printf("\n");
1105 printf("\n"); 1093 printf(" %-50s [%s]\n",
1106 printf(" %-50s [%s]\n", 1094 "rNNN (see 'perf list --help' on how to encode it)",
1107 "rNNN", 1095 event_type_descriptors[PERF_TYPE_RAW]);
1108 event_type_descriptors[PERF_TYPE_RAW]); 1096 printf("\n");
1109 printf(" %-50s [%s]\n",
1110 "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
1111 event_type_descriptors[PERF_TYPE_RAW]);
1112 printf(" (see 'man perf-list' on how to encode it)\n");
1113 printf("\n");
1114 1097
1115 printf(" %-50s [%s]\n", 1098 printf(" %-50s [%s]\n",
1116 "mem:<addr>[:access]", 1099 "mem:<addr>[:access]",
1117 event_type_descriptors[PERF_TYPE_BREAKPOINT]); 1100 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
1118 printf("\n"); 1101 printf("\n");
1119 }
1120
1121 print_tracepoint_events(NULL, NULL, name_only);
1122}
1123
1124int parse_events__is_hardcoded_term(struct parse_events__term *term)
1125{
1126 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1127}
1128
1129static int new_term(struct parse_events__term **_term, int type_val,
1130 int type_term, char *config,
1131 char *str, u64 num)
1132{
1133 struct parse_events__term *term;
1134
1135 term = zalloc(sizeof(*term));
1136 if (!term)
1137 return -ENOMEM;
1138
1139 INIT_LIST_HEAD(&term->list);
1140 term->type_val = type_val;
1141 term->type_term = type_term;
1142 term->config = config;
1143
1144 switch (type_val) {
1145 case PARSE_EVENTS__TERM_TYPE_NUM:
1146 term->val.num = num;
1147 break;
1148 case PARSE_EVENTS__TERM_TYPE_STR:
1149 term->val.str = str;
1150 break;
1151 default:
1152 return -EINVAL;
1153 }
1154
1155 *_term = term;
1156 return 0;
1157}
1158
1159int parse_events__term_num(struct parse_events__term **term,
1160 int type_term, char *config, u64 num)
1161{
1162 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1163 config, NULL, num);
1164}
1165
1166int parse_events__term_str(struct parse_events__term **term,
1167 int type_term, char *config, char *str)
1168{
1169 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1170 config, str, 0);
1171}
1172
1173int parse_events__term_sym_hw(struct parse_events__term **term,
1174 char *config, unsigned idx)
1175{
1176 struct event_symbol *sym;
1177
1178 BUG_ON(idx >= PERF_COUNT_HW_MAX);
1179 sym = &event_symbols_hw[idx];
1180
1181 if (config)
1182 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1183 PARSE_EVENTS__TERM_TYPE_USER, config,
1184 (char *) sym->symbol, 0);
1185 else
1186 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1187 PARSE_EVENTS__TERM_TYPE_USER,
1188 (char *) "event", (char *) sym->symbol, 0);
1189}
1190
1191int parse_events__term_clone(struct parse_events__term **new,
1192 struct parse_events__term *term)
1193{
1194 return new_term(new, term->type_val, term->type_term, term->config,
1195 term->val.str, term->val.num);
1196}
1197
1198void parse_events__free_terms(struct list_head *terms)
1199{
1200 struct parse_events__term *term, *h;
1201
1202 list_for_each_entry_safe(term, h, terms, list)
1203 free(term);
1204 1102
1205 free(terms); 1103 print_tracepoint_events(NULL, NULL);
1206} 1104}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b7af80b8bdd..2f8e375e038 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,11 +4,7 @@
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
6 6
7#include <linux/list.h> 7#include "../../../include/linux/perf_event.h"
8#include <stdbool.h>
9#include "types.h"
10#include <linux/perf_event.h>
11#include "types.h"
12 8
13struct list_head; 9struct list_head;
14struct perf_evsel; 10struct perf_evsel;
@@ -26,87 +22,24 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern bool have_tracepoints(struct list_head *evlist); 22extern bool have_tracepoints(struct list_head *evlist);
27 23
28const char *event_type(int type); 24const char *event_type(int type);
25const char *event_name(struct perf_evsel *event);
26extern const char *__event_name(int type, u64 config);
29 27
30extern int parse_events_option(const struct option *opt, const char *str, 28extern int parse_events_option(const struct option *opt, const char *str,
31 int unset); 29 int unset);
32extern int parse_events(struct perf_evlist *evlist, const char *str, 30extern int parse_events(struct perf_evlist *evlist, const char *str,
33 int unset); 31 int unset);
34extern int parse_events_terms(struct list_head *terms, const char *str);
35extern int parse_filter(const struct option *opt, const char *str, int unset); 32extern int parse_filter(const struct option *opt, const char *str, int unset);
36 33
37#define EVENTS_HELP_MAX (128*1024) 34#define EVENTS_HELP_MAX (128*1024)
38 35
39enum { 36void print_events(const char *event_glob);
40 PARSE_EVENTS__TERM_TYPE_NUM,
41 PARSE_EVENTS__TERM_TYPE_STR,
42};
43
44enum {
45 PARSE_EVENTS__TERM_TYPE_USER,
46 PARSE_EVENTS__TERM_TYPE_CONFIG,
47 PARSE_EVENTS__TERM_TYPE_CONFIG1,
48 PARSE_EVENTS__TERM_TYPE_CONFIG2,
49 PARSE_EVENTS__TERM_TYPE_NAME,
50 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
51 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
52};
53
54struct parse_events__term {
55 char *config;
56 union {
57 char *str;
58 u64 num;
59 } val;
60 int type_val;
61 int type_term;
62 struct list_head list;
63};
64
65struct parse_events_data__events {
66 struct list_head list;
67 int idx;
68};
69
70struct parse_events_data__terms {
71 struct list_head *terms;
72};
73
74int parse_events__is_hardcoded_term(struct parse_events__term *term);
75int parse_events__term_num(struct parse_events__term **_term,
76 int type_term, char *config, u64 num);
77int parse_events__term_str(struct parse_events__term **_term,
78 int type_term, char *config, char *str);
79int parse_events__term_sym_hw(struct parse_events__term **term,
80 char *config, unsigned idx);
81int parse_events__term_clone(struct parse_events__term **new,
82 struct parse_events__term *term);
83void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod);
86int parse_events_name(struct list_head *list, char *name);
87int parse_events_add_tracepoint(struct list_head **list, int *idx,
88 char *sys, char *event);
89int parse_events_add_numeric(struct list_head **list, int *idx,
90 u32 type, u64 config,
91 struct list_head *head_config);
92int parse_events_add_cache(struct list_head **list, int *idx,
93 char *type, char *op_result1, char *op_result2);
94int parse_events_add_breakpoint(struct list_head **list, int *idx,
95 void *ptr, char *type);
96int parse_events_add_pmu(struct list_head **list, int *idx,
97 char *pmu , struct list_head *head_config);
98void parse_events__set_leader(char *name, struct list_head *list);
99void parse_events_update_lists(struct list_head *list_event,
100 struct list_head *list_all);
101void parse_events_error(void *data, void *scanner, char const *msg);
102
103void print_events(const char *event_glob, bool name_only);
104void print_events_type(u8 type); 37void print_events_type(u8 type);
105void print_tracepoint_events(const char *subsys_glob, const char *event_glob, 38void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
106 bool name_only); 39int print_hwcache_events(const char *event_glob);
107int print_hwcache_events(const char *event_glob, bool name_only);
108extern int is_valid_tracepoint(const char *event_string); 40extern int is_valid_tracepoint(const char *event_string);
109 41
42extern char debugfs_path[];
110extern int valid_debugfs_mount(const char *debugfs); 43extern int valid_debugfs_mount(const char *debugfs);
111 44
112#endif /* __PERF_PARSE_EVENTS_H */ 45#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
deleted file mode 100644
index e9d1134c2c6..00000000000
--- a/tools/perf/util/parse-events.l
+++ /dev/null
@@ -1,215 +0,0 @@
1
2%option reentrant
3%option bison-bridge
4%option prefix="parse_events_"
5%option stack
6
7%{
8#include <errno.h>
9#include "../perf.h"
10#include "parse-events-bison.h"
11#include "parse-events.h"
12
13char *parse_events_get_text(yyscan_t yyscanner);
14YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
15
16static int __value(YYSTYPE *yylval, char *str, int base, int token)
17{
18 u64 num;
19
20 errno = 0;
21 num = strtoull(str, NULL, base);
22 if (errno)
23 return PE_ERROR;
24
25 yylval->num = num;
26 return token;
27}
28
29static int value(yyscan_t scanner, int base)
30{
31 YYSTYPE *yylval = parse_events_get_lval(scanner);
32 char *text = parse_events_get_text(scanner);
33
34 return __value(yylval, text, base, PE_VALUE);
35}
36
37static int raw(yyscan_t scanner)
38{
39 YYSTYPE *yylval = parse_events_get_lval(scanner);
40 char *text = parse_events_get_text(scanner);
41
42 return __value(yylval, text + 1, 16, PE_RAW);
43}
44
45static int str(yyscan_t scanner, int token)
46{
47 YYSTYPE *yylval = parse_events_get_lval(scanner);
48 char *text = parse_events_get_text(scanner);
49
50 yylval->str = strdup(text);
51 return token;
52}
53
54static int sym(yyscan_t scanner, int type, int config)
55{
56 YYSTYPE *yylval = parse_events_get_lval(scanner);
57
58 yylval->num = (type << 16) + config;
59 return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW;
60}
61
62static int term(yyscan_t scanner, int type)
63{
64 YYSTYPE *yylval = parse_events_get_lval(scanner);
65
66 yylval->num = type;
67 return PE_TERM;
68}
69
70%}
71
72%x mem
73%s config
74%x event
75
76group [^,{}/]*[{][^}]*[}][^,{}/]*
77event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
78event [^,{}/]+
79
80num_dec [0-9]+
81num_hex 0x[a-fA-F0-9]+
82num_raw_hex [a-fA-F0-9]+
83name [a-zA-Z_*?][a-zA-Z0-9_*?]*
84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]*
85modifier_event [ukhpGH]+
86modifier_bp [rwx]{1,3}
87
88%%
89
90%{
91 {
92 int start_token;
93
94 start_token = parse_events_get_extra(yyscanner);
95
96 if (start_token == PE_START_TERMS)
97 BEGIN(config);
98 else if (start_token == PE_START_EVENTS)
99 BEGIN(event);
100
101 if (start_token) {
102 parse_events_set_extra(NULL, yyscanner);
103 return start_token;
104 }
105 }
106%}
107
108<event>{
109
110{group} {
111 BEGIN(INITIAL); yyless(0);
112 }
113
114{event_pmu} |
115{event} {
116 str(yyscanner, PE_EVENT_NAME);
117 BEGIN(INITIAL); yyless(0);
118 return PE_EVENT_NAME;
119 }
120
121. |
122<<EOF>> {
123 BEGIN(INITIAL); yyless(0);
124 }
125
126}
127
128cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
129stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
130stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
131instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
132cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
133cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
134branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
135branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
136bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
137ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
138cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
139task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
140page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
141minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
142major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
143context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
144cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
145alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
146emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
147
148L1-dcache|l1-d|l1d|L1-data |
149L1-icache|l1-i|l1i|L1-instruction |
150LLC|L2 |
151dTLB|d-tlb|Data-TLB |
152iTLB|i-tlb|Instruction-TLB |
153branch|branches|bpu|btb|bpc |
154node { return str(yyscanner, PE_NAME_CACHE_TYPE); }
155
156load|loads|read |
157store|stores|write |
158prefetch|prefetches |
159speculative-read|speculative-load |
160refs|Reference|ops|access |
161misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }
162
163<config>{
164config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
165config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
166config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
167name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
168period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
169branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
170, { return ','; }
171"/" { BEGIN(INITIAL); return '/'; }
172{name_minus} { return str(yyscanner, PE_NAME); }
173}
174
175mem: { BEGIN(mem); return PE_PREFIX_MEM; }
176r{num_raw_hex} { return raw(yyscanner); }
177{num_dec} { return value(yyscanner, 10); }
178{num_hex} { return value(yyscanner, 16); }
179
180{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
181{name} { return str(yyscanner, PE_NAME); }
182"/" { BEGIN(config); return '/'; }
183- { return '-'; }
184, { BEGIN(event); return ','; }
185: { return ':'; }
186"{" { BEGIN(event); return '{'; }
187"}" { return '}'; }
188= { return '='; }
189\n { }
190
191<mem>{
192{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
193: { return ':'; }
194{num_dec} { return value(yyscanner, 10); }
195{num_hex} { return value(yyscanner, 16); }
196 /*
197 * We need to separate 'mem:' scanner part, in order to get specific
198 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
199 * and we'd need to parse it manually. During the escape from <mem>
200 * state we need to put the escaping char back, so we dont miss it.
201 */
202. { unput(*yytext); BEGIN(INITIAL); }
203 /*
204 * We destroy the scanner after reaching EOF,
205 * but anyway just to be sure get back to INIT state.
206 */
207<<EOF>> { BEGIN(INITIAL); }
208}
209
210%%
211
212int parse_events_wrap(void *scanner __maybe_unused)
213{
214 return 1;
215}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
deleted file mode 100644
index 0f9914ae6ba..00000000000
--- a/tools/perf/util/parse-events.y
+++ /dev/null
@@ -1,415 +0,0 @@
1%pure-parser
2%name-prefix "parse_events_"
3%parse-param {void *_data}
4%parse-param {void *scanner}
5%lex-param {void* scanner}
6
7%{
8
9#define YYDEBUG 1
10
11#include <linux/compiler.h>
12#include <linux/list.h>
13#include "types.h"
14#include "util.h"
15#include "parse-events.h"
16#include "parse-events-bison.h"
17
18extern int parse_events_lex (YYSTYPE* lvalp, void* scanner);
19
20#define ABORT_ON(val) \
21do { \
22 if (val) \
23 YYABORT; \
24} while (0)
25
26%}
27
28%token PE_START_EVENTS PE_START_TERMS
29%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
30%token PE_EVENT_NAME
31%token PE_NAME
32%token PE_MODIFIER_EVENT PE_MODIFIER_BP
33%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
34%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
35%token PE_ERROR
36%type <num> PE_VALUE
37%type <num> PE_VALUE_SYM_HW
38%type <num> PE_VALUE_SYM_SW
39%type <num> PE_RAW
40%type <num> PE_TERM
41%type <str> PE_NAME
42%type <str> PE_NAME_CACHE_TYPE
43%type <str> PE_NAME_CACHE_OP_RESULT
44%type <str> PE_MODIFIER_EVENT
45%type <str> PE_MODIFIER_BP
46%type <str> PE_EVENT_NAME
47%type <num> value_sym
48%type <head> event_config
49%type <term> event_term
50%type <head> event_pmu
51%type <head> event_legacy_symbol
52%type <head> event_legacy_cache
53%type <head> event_legacy_mem
54%type <head> event_legacy_tracepoint
55%type <head> event_legacy_numeric
56%type <head> event_legacy_raw
57%type <head> event_def
58%type <head> event_mod
59%type <head> event_name
60%type <head> event
61%type <head> events
62%type <head> group_def
63%type <head> group
64%type <head> groups
65
66%union
67{
68 char *str;
69 u64 num;
70 struct list_head *head;
71 struct parse_events__term *term;
72}
73%%
74
75start:
76PE_START_EVENTS start_events
77|
78PE_START_TERMS start_terms
79
80start_events: groups
81{
82 struct parse_events_data__events *data = _data;
83
84 parse_events_update_lists($1, &data->list);
85}
86
87groups:
88groups ',' group
89{
90 struct list_head *list = $1;
91 struct list_head *group = $3;
92
93 parse_events_update_lists(group, list);
94 $$ = list;
95}
96|
97groups ',' event
98{
99 struct list_head *list = $1;
100 struct list_head *event = $3;
101
102 parse_events_update_lists(event, list);
103 $$ = list;
104}
105|
106group
107|
108event
109
110group:
111group_def ':' PE_MODIFIER_EVENT
112{
113 struct list_head *list = $1;
114
115 ABORT_ON(parse_events__modifier_group(list, $3));
116 $$ = list;
117}
118|
119group_def
120
121group_def:
122PE_NAME '{' events '}'
123{
124 struct list_head *list = $3;
125
126 parse_events__set_leader($1, list);
127 $$ = list;
128}
129|
130'{' events '}'
131{
132 struct list_head *list = $2;
133
134 parse_events__set_leader(NULL, list);
135 $$ = list;
136}
137
138events:
139events ',' event
140{
141 struct list_head *event = $3;
142 struct list_head *list = $1;
143
144 parse_events_update_lists(event, list);
145 $$ = list;
146}
147|
148event
149
150event: event_mod
151
152event_mod:
153event_name PE_MODIFIER_EVENT
154{
155 struct list_head *list = $1;
156
157 /*
158 * Apply modifier on all events added by single event definition
159 * (there could be more events added for multiple tracepoint
160 * definitions via '*?'.
161 */
162 ABORT_ON(parse_events__modifier_event(list, $2, false));
163 $$ = list;
164}
165|
166event_name
167
168event_name:
169PE_EVENT_NAME event_def
170{
171 ABORT_ON(parse_events_name($2, $1));
172 free($1);
173 $$ = $2;
174}
175|
176event_def
177
178event_def: event_pmu |
179 event_legacy_symbol |
180 event_legacy_cache sep_dc |
181 event_legacy_mem |
182 event_legacy_tracepoint sep_dc |
183 event_legacy_numeric sep_dc |
184 event_legacy_raw sep_dc
185
186event_pmu:
187PE_NAME '/' event_config '/'
188{
189 struct parse_events_data__events *data = _data;
190 struct list_head *list = NULL;
191
192 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
193 parse_events__free_terms($3);
194 $$ = list;
195}
196
197value_sym:
198PE_VALUE_SYM_HW
199|
200PE_VALUE_SYM_SW
201
202event_legacy_symbol:
203value_sym '/' event_config '/'
204{
205 struct parse_events_data__events *data = _data;
206 struct list_head *list = NULL;
207 int type = $1 >> 16;
208 int config = $1 & 255;
209
210 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
211 type, config, $3));
212 parse_events__free_terms($3);
213 $$ = list;
214}
215|
216value_sym sep_slash_dc
217{
218 struct parse_events_data__events *data = _data;
219 struct list_head *list = NULL;
220 int type = $1 >> 16;
221 int config = $1 & 255;
222
223 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
224 type, config, NULL));
225 $$ = list;
226}
227
228event_legacy_cache:
229PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
230{
231 struct parse_events_data__events *data = _data;
232 struct list_head *list = NULL;
233
234 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
235 $$ = list;
236}
237|
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
239{
240 struct parse_events_data__events *data = _data;
241 struct list_head *list = NULL;
242
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
244 $$ = list;
245}
246|
247PE_NAME_CACHE_TYPE
248{
249 struct parse_events_data__events *data = _data;
250 struct list_head *list = NULL;
251
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
253 $$ = list;
254}
255
256event_legacy_mem:
257PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
258{
259 struct parse_events_data__events *data = _data;
260 struct list_head *list = NULL;
261
262 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
263 (void *) $2, $4));
264 $$ = list;
265}
266|
267PE_PREFIX_MEM PE_VALUE sep_dc
268{
269 struct parse_events_data__events *data = _data;
270 struct list_head *list = NULL;
271
272 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
273 (void *) $2, NULL));
274 $$ = list;
275}
276
277event_legacy_tracepoint:
278PE_NAME ':' PE_NAME
279{
280 struct parse_events_data__events *data = _data;
281 struct list_head *list = NULL;
282
283 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
284 $$ = list;
285}
286
287event_legacy_numeric:
288PE_VALUE ':' PE_VALUE
289{
290 struct parse_events_data__events *data = _data;
291 struct list_head *list = NULL;
292
293 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
294 $$ = list;
295}
296
297event_legacy_raw:
298PE_RAW
299{
300 struct parse_events_data__events *data = _data;
301 struct list_head *list = NULL;
302
303 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
304 PERF_TYPE_RAW, $1, NULL));
305 $$ = list;
306}
307
308start_terms: event_config
309{
310 struct parse_events_data__terms *data = _data;
311 data->terms = $1;
312}
313
314event_config:
315event_config ',' event_term
316{
317 struct list_head *head = $1;
318 struct parse_events__term *term = $3;
319
320 ABORT_ON(!head);
321 list_add_tail(&term->list, head);
322 $$ = $1;
323}
324|
325event_term
326{
327 struct list_head *head = malloc(sizeof(*head));
328 struct parse_events__term *term = $1;
329
330 ABORT_ON(!head);
331 INIT_LIST_HEAD(head);
332 list_add_tail(&term->list, head);
333 $$ = head;
334}
335
336event_term:
337PE_NAME '=' PE_NAME
338{
339 struct parse_events__term *term;
340
341 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
342 $1, $3));
343 $$ = term;
344}
345|
346PE_NAME '=' PE_VALUE
347{
348 struct parse_events__term *term;
349
350 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
351 $1, $3));
352 $$ = term;
353}
354|
355PE_NAME '=' PE_VALUE_SYM_HW
356{
357 struct parse_events__term *term;
358 int config = $3 & 255;
359
360 ABORT_ON(parse_events__term_sym_hw(&term, $1, config));
361 $$ = term;
362}
363|
364PE_NAME
365{
366 struct parse_events__term *term;
367
368 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
369 $1, 1));
370 $$ = term;
371}
372|
373PE_VALUE_SYM_HW
374{
375 struct parse_events__term *term;
376 int config = $1 & 255;
377
378 ABORT_ON(parse_events__term_sym_hw(&term, NULL, config));
379 $$ = term;
380}
381|
382PE_TERM '=' PE_NAME
383{
384 struct parse_events__term *term;
385
386 ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3));
387 $$ = term;
388}
389|
390PE_TERM '=' PE_VALUE
391{
392 struct parse_events__term *term;
393
394 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3));
395 $$ = term;
396}
397|
398PE_TERM
399{
400 struct parse_events__term *term;
401
402 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1));
403 $$ = term;
404}
405
406sep_dc: ':' |
407
408sep_slash_dc: '/' | ':' |
409
410%%
411
412void parse_events_error(void *data __maybe_unused, void *scanner __maybe_unused,
413 char const *msg __maybe_unused)
414{
415}
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 2bc9e70df7e..99d02aa57db 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -1,7 +1,6 @@
1#include "util.h" 1#include "util.h"
2#include "parse-options.h" 2#include "parse-options.h"
3#include "cache.h" 3#include "cache.h"
4#include "header.h"
5 4
6#define OPT_SHORT 1 5#define OPT_SHORT 1
7#define OPT_UNSET 2 6#define OPT_UNSET 2
@@ -384,8 +383,6 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
384 return usage_with_options_internal(usagestr, options, 1); 383 return usage_with_options_internal(usagestr, options, 1);
385 if (internal_help && !strcmp(arg + 2, "help")) 384 if (internal_help && !strcmp(arg + 2, "help"))
386 return parse_options_usage(usagestr, options); 385 return parse_options_usage(usagestr, options);
387 if (!strcmp(arg + 2, "list-opts"))
388 return PARSE_OPT_LIST;
389 switch (parse_long_opt(ctx, arg + 2, options)) { 386 switch (parse_long_opt(ctx, arg + 2, options)) {
390 case -1: 387 case -1:
391 return parse_options_usage(usagestr, options); 388 return parse_options_usage(usagestr, options);
@@ -416,20 +413,12 @@ int parse_options(int argc, const char **argv, const struct option *options,
416{ 413{
417 struct parse_opt_ctx_t ctx; 414 struct parse_opt_ctx_t ctx;
418 415
419 perf_header__set_cmdline(argc, argv);
420
421 parse_options_start(&ctx, argc, argv, flags); 416 parse_options_start(&ctx, argc, argv, flags);
422 switch (parse_options_step(&ctx, options, usagestr)) { 417 switch (parse_options_step(&ctx, options, usagestr)) {
423 case PARSE_OPT_HELP: 418 case PARSE_OPT_HELP:
424 exit(129); 419 exit(129);
425 case PARSE_OPT_DONE: 420 case PARSE_OPT_DONE:
426 break; 421 break;
427 case PARSE_OPT_LIST:
428 while (options->type != OPTION_END) {
429 printf("--%s ", options->long_name);
430 options++;
431 }
432 exit(130);
433 default: /* PARSE_OPT_UNKNOWN */ 422 default: /* PARSE_OPT_UNKNOWN */
434 if (ctx.argv[0][1] == '-') { 423 if (ctx.argv[0][1] == '-') {
435 error("unknown option `%s'", ctx.argv[0] + 2); 424 error("unknown option `%s'", ctx.argv[0] + 2);
@@ -565,8 +554,7 @@ int parse_options_usage(const char * const *usagestr,
565} 554}
566 555
567 556
568int parse_opt_verbosity_cb(const struct option *opt, 557int parse_opt_verbosity_cb(const struct option *opt, const char *arg __used,
569 const char *arg __maybe_unused,
570 int unset) 558 int unset)
571{ 559{
572 int *target = opt->value; 560 int *target = opt->value;
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 7bb5999940c..abc31a1dac1 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -140,7 +140,6 @@ extern NORETURN void usage_with_options(const char * const *usagestr,
140enum { 140enum {
141 PARSE_OPT_HELP = -1, 141 PARSE_OPT_HELP = -1,
142 PARSE_OPT_DONE, 142 PARSE_OPT_DONE,
143 PARSE_OPT_LIST,
144 PARSE_OPT_UNKNOWN, 143 PARSE_OPT_UNKNOWN,
145}; 144};
146 145
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index a8c49548ca4..bd749771142 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,7 +22,7 @@ static const char *get_perf_dir(void)
22 return "."; 22 return ".";
23} 23}
24 24
25#ifndef HAVE_STRLCPY 25#ifdef NO_STRLCPY
26size_t strlcpy(char *dest, const char *src, size_t size) 26size_t strlcpy(char *dest, const char *src, size_t size)
27{ 27{
28 size_t ret = strlen(src); 28 size_t ret = strlen(src);
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
deleted file mode 100644
index 5a4f2b6f373..00000000000
--- a/tools/perf/util/perf_regs.h
+++ /dev/null
@@ -1,14 +0,0 @@
1#ifndef __PERF_REGS_H
2#define __PERF_REGS_H
3
4#ifdef HAVE_PERF_REGS
5#include <perf_regs.h>
6#else
7#define PERF_REGS_MASK 0
8
9static inline const char *perf_reg_name(int id __maybe_unused)
10{
11 return NULL;
12}
13#endif /* HAVE_PERF_REGS */
14#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
deleted file mode 100644
index 9bdc60c6f13..00000000000
--- a/tools/perf/util/pmu.c
+++ /dev/null
@@ -1,554 +0,0 @@
1
2#include <linux/list.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <stdio.h>
7#include <dirent.h>
8#include "sysfs.h"
9#include "util.h"
10#include "pmu.h"
11#include "parse-events.h"
12#include "cpumap.h"
13
14#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
15
16int perf_pmu_parse(struct list_head *list, char *name);
17extern FILE *perf_pmu_in;
18
19static LIST_HEAD(pmus);
20
21/*
22 * Parse & process all the sysfs attributes located under
23 * the directory specified in 'dir' parameter.
24 */
25int perf_pmu__format_parse(char *dir, struct list_head *head)
26{
27 struct dirent *evt_ent;
28 DIR *format_dir;
29 int ret = 0;
30
31 format_dir = opendir(dir);
32 if (!format_dir)
33 return -EINVAL;
34
35 while (!ret && (evt_ent = readdir(format_dir))) {
36 char path[PATH_MAX];
37 char *name = evt_ent->d_name;
38 FILE *file;
39
40 if (!strcmp(name, ".") || !strcmp(name, ".."))
41 continue;
42
43 snprintf(path, PATH_MAX, "%s/%s", dir, name);
44
45 ret = -EINVAL;
46 file = fopen(path, "r");
47 if (!file)
48 break;
49
50 perf_pmu_in = file;
51 ret = perf_pmu_parse(head, name);
52 fclose(file);
53 }
54
55 closedir(format_dir);
56 return ret;
57}
58
59/*
60 * Reading/parsing the default pmu format definition, which should be
61 * located at:
62 * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
63 */
64static int pmu_format(char *name, struct list_head *format)
65{
66 struct stat st;
67 char path[PATH_MAX];
68 const char *sysfs;
69
70 sysfs = sysfs_find_mountpoint();
71 if (!sysfs)
72 return -1;
73
74 snprintf(path, PATH_MAX,
75 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
76
77 if (stat(path, &st) < 0)
78 return 0; /* no error if format does not exist */
79
80 if (perf_pmu__format_parse(path, format))
81 return -1;
82
83 return 0;
84}
85
86static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
87{
88 struct perf_pmu__alias *alias;
89 char buf[256];
90 int ret;
91
92 ret = fread(buf, 1, sizeof(buf), file);
93 if (ret == 0)
94 return -EINVAL;
95 buf[ret] = 0;
96
97 alias = malloc(sizeof(*alias));
98 if (!alias)
99 return -ENOMEM;
100
101 INIT_LIST_HEAD(&alias->terms);
102 ret = parse_events_terms(&alias->terms, buf);
103 if (ret) {
104 free(alias);
105 return ret;
106 }
107
108 alias->name = strdup(name);
109 list_add_tail(&alias->list, list);
110 return 0;
111}
112
113/*
114 * Process all the sysfs attributes located under the directory
115 * specified in 'dir' parameter.
116 */
117static int pmu_aliases_parse(char *dir, struct list_head *head)
118{
119 struct dirent *evt_ent;
120 DIR *event_dir;
121 int ret = 0;
122
123 event_dir = opendir(dir);
124 if (!event_dir)
125 return -EINVAL;
126
127 while (!ret && (evt_ent = readdir(event_dir))) {
128 char path[PATH_MAX];
129 char *name = evt_ent->d_name;
130 FILE *file;
131
132 if (!strcmp(name, ".") || !strcmp(name, ".."))
133 continue;
134
135 snprintf(path, PATH_MAX, "%s/%s", dir, name);
136
137 ret = -EINVAL;
138 file = fopen(path, "r");
139 if (!file)
140 break;
141 ret = perf_pmu__new_alias(head, name, file);
142 fclose(file);
143 }
144
145 closedir(event_dir);
146 return ret;
147}
148
149/*
150 * Reading the pmu event aliases definition, which should be located at:
151 * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
152 */
153static int pmu_aliases(char *name, struct list_head *head)
154{
155 struct stat st;
156 char path[PATH_MAX];
157 const char *sysfs;
158
159 sysfs = sysfs_find_mountpoint();
160 if (!sysfs)
161 return -1;
162
163 snprintf(path, PATH_MAX,
164 "%s/bus/event_source/devices/%s/events", sysfs, name);
165
166 if (stat(path, &st) < 0)
167 return 0; /* no error if 'events' does not exist */
168
169 if (pmu_aliases_parse(path, head))
170 return -1;
171
172 return 0;
173}
174
175static int pmu_alias_terms(struct perf_pmu__alias *alias,
176 struct list_head *terms)
177{
178 struct parse_events__term *term, *clone;
179 LIST_HEAD(list);
180 int ret;
181
182 list_for_each_entry(term, &alias->terms, list) {
183 ret = parse_events__term_clone(&clone, term);
184 if (ret) {
185 parse_events__free_terms(&list);
186 return ret;
187 }
188 list_add_tail(&clone->list, &list);
189 }
190 list_splice(&list, terms);
191 return 0;
192}
193
194/*
195 * Reading/parsing the default pmu type value, which should be
196 * located at:
197 * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
198 */
199static int pmu_type(char *name, __u32 *type)
200{
201 struct stat st;
202 char path[PATH_MAX];
203 const char *sysfs;
204 FILE *file;
205 int ret = 0;
206
207 sysfs = sysfs_find_mountpoint();
208 if (!sysfs)
209 return -1;
210
211 snprintf(path, PATH_MAX,
212 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
213
214 if (stat(path, &st) < 0)
215 return -1;
216
217 file = fopen(path, "r");
218 if (!file)
219 return -EINVAL;
220
221 if (1 != fscanf(file, "%u", type))
222 ret = -1;
223
224 fclose(file);
225 return ret;
226}
227
228/* Add all pmus in sysfs to pmu list: */
229static void pmu_read_sysfs(void)
230{
231 char path[PATH_MAX];
232 const char *sysfs;
233 DIR *dir;
234 struct dirent *dent;
235
236 sysfs = sysfs_find_mountpoint();
237 if (!sysfs)
238 return;
239
240 snprintf(path, PATH_MAX,
241 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
242
243 dir = opendir(path);
244 if (!dir)
245 return;
246
247 while ((dent = readdir(dir))) {
248 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
249 continue;
250 /* add to static LIST_HEAD(pmus): */
251 perf_pmu__find(dent->d_name);
252 }
253
254 closedir(dir);
255}
256
257static struct cpu_map *pmu_cpumask(char *name)
258{
259 struct stat st;
260 char path[PATH_MAX];
261 const char *sysfs;
262 FILE *file;
263 struct cpu_map *cpus;
264
265 sysfs = sysfs_find_mountpoint();
266 if (!sysfs)
267 return NULL;
268
269 snprintf(path, PATH_MAX,
270 "%s/bus/event_source/devices/%s/cpumask", sysfs, name);
271
272 if (stat(path, &st) < 0)
273 return NULL;
274
275 file = fopen(path, "r");
276 if (!file)
277 return NULL;
278
279 cpus = cpu_map__read(file);
280 fclose(file);
281 return cpus;
282}
283
284static struct perf_pmu *pmu_lookup(char *name)
285{
286 struct perf_pmu *pmu;
287 LIST_HEAD(format);
288 LIST_HEAD(aliases);
289 __u32 type;
290
291 /*
292 * The pmu data we store & need consists of the pmu
293 * type value and format definitions. Load both right
294 * now.
295 */
296 if (pmu_format(name, &format))
297 return NULL;
298
299 if (pmu_aliases(name, &aliases))
300 return NULL;
301
302 if (pmu_type(name, &type))
303 return NULL;
304
305 pmu = zalloc(sizeof(*pmu));
306 if (!pmu)
307 return NULL;
308
309 pmu->cpus = pmu_cpumask(name);
310
311 INIT_LIST_HEAD(&pmu->format);
312 INIT_LIST_HEAD(&pmu->aliases);
313 list_splice(&format, &pmu->format);
314 list_splice(&aliases, &pmu->aliases);
315 pmu->name = strdup(name);
316 pmu->type = type;
317 list_add_tail(&pmu->list, &pmus);
318 return pmu;
319}
320
321static struct perf_pmu *pmu_find(char *name)
322{
323 struct perf_pmu *pmu;
324
325 list_for_each_entry(pmu, &pmus, list)
326 if (!strcmp(pmu->name, name))
327 return pmu;
328
329 return NULL;
330}
331
332struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
333{
334 /*
335 * pmu iterator: If pmu is NULL, we start at the begin,
336 * otherwise return the next pmu. Returns NULL on end.
337 */
338 if (!pmu) {
339 pmu_read_sysfs();
340 pmu = list_prepare_entry(pmu, &pmus, list);
341 }
342 list_for_each_entry_continue(pmu, &pmus, list)
343 return pmu;
344 return NULL;
345}
346
347struct perf_pmu *perf_pmu__find(char *name)
348{
349 struct perf_pmu *pmu;
350
351 /*
352 * Once PMU is loaded it stays in the list,
353 * so we keep us from multiple reading/parsing
354 * the pmu format definitions.
355 */
356 pmu = pmu_find(name);
357 if (pmu)
358 return pmu;
359
360 return pmu_lookup(name);
361}
362
363static struct perf_pmu__format*
364pmu_find_format(struct list_head *formats, char *name)
365{
366 struct perf_pmu__format *format;
367
368 list_for_each_entry(format, formats, list)
369 if (!strcmp(format->name, name))
370 return format;
371
372 return NULL;
373}
374
375/*
376 * Returns value based on the format definition (format parameter)
377 * and unformated value (value parameter).
378 *
379 * TODO maybe optimize a little ;)
380 */
381static __u64 pmu_format_value(unsigned long *format, __u64 value)
382{
383 unsigned long fbit, vbit;
384 __u64 v = 0;
385
386 for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) {
387
388 if (!test_bit(fbit, format))
389 continue;
390
391 if (!(value & (1llu << vbit++)))
392 continue;
393
394 v |= (1llu << fbit);
395 }
396
397 return v;
398}
399
400/*
401 * Setup one of config[12] attr members based on the
402 * user input data - temr parameter.
403 */
404static int pmu_config_term(struct list_head *formats,
405 struct perf_event_attr *attr,
406 struct parse_events__term *term)
407{
408 struct perf_pmu__format *format;
409 __u64 *vp;
410
411 /*
412 * Support only for hardcoded and numnerial terms.
413 * Hardcoded terms should be already in, so nothing
414 * to be done for them.
415 */
416 if (parse_events__is_hardcoded_term(term))
417 return 0;
418
419 if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
420 return -EINVAL;
421
422 format = pmu_find_format(formats, term->config);
423 if (!format)
424 return -EINVAL;
425
426 switch (format->value) {
427 case PERF_PMU_FORMAT_VALUE_CONFIG:
428 vp = &attr->config;
429 break;
430 case PERF_PMU_FORMAT_VALUE_CONFIG1:
431 vp = &attr->config1;
432 break;
433 case PERF_PMU_FORMAT_VALUE_CONFIG2:
434 vp = &attr->config2;
435 break;
436 default:
437 return -EINVAL;
438 }
439
440 /*
441 * XXX If we ever decide to go with string values for
442 * non-hardcoded terms, here's the place to translate
443 * them into value.
444 */
445 *vp |= pmu_format_value(format->bits, term->val.num);
446 return 0;
447}
448
449int perf_pmu__config_terms(struct list_head *formats,
450 struct perf_event_attr *attr,
451 struct list_head *head_terms)
452{
453 struct parse_events__term *term;
454
455 list_for_each_entry(term, head_terms, list)
456 if (pmu_config_term(formats, attr, term))
457 return -EINVAL;
458
459 return 0;
460}
461
462/*
463 * Configures event's 'attr' parameter based on the:
464 * 1) users input - specified in terms parameter
465 * 2) pmu format definitions - specified by pmu parameter
466 */
467int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
468 struct list_head *head_terms)
469{
470 attr->type = pmu->type;
471 return perf_pmu__config_terms(&pmu->format, attr, head_terms);
472}
473
474static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
475 struct parse_events__term *term)
476{
477 struct perf_pmu__alias *alias;
478 char *name;
479
480 if (parse_events__is_hardcoded_term(term))
481 return NULL;
482
483 if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
484 if (term->val.num != 1)
485 return NULL;
486 if (pmu_find_format(&pmu->format, term->config))
487 return NULL;
488 name = term->config;
489 } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
490 if (strcasecmp(term->config, "event"))
491 return NULL;
492 name = term->val.str;
493 } else {
494 return NULL;
495 }
496
497 list_for_each_entry(alias, &pmu->aliases, list) {
498 if (!strcasecmp(alias->name, name))
499 return alias;
500 }
501 return NULL;
502}
503
504/*
505 * Find alias in the terms list and replace it with the terms
506 * defined for the alias
507 */
508int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
509{
510 struct parse_events__term *term, *h;
511 struct perf_pmu__alias *alias;
512 int ret;
513
514 list_for_each_entry_safe(term, h, head_terms, list) {
515 alias = pmu_find_alias(pmu, term);
516 if (!alias)
517 continue;
518 ret = pmu_alias_terms(alias, &term->list);
519 if (ret)
520 return ret;
521 list_del(&term->list);
522 free(term);
523 }
524 return 0;
525}
526
527int perf_pmu__new_format(struct list_head *list, char *name,
528 int config, unsigned long *bits)
529{
530 struct perf_pmu__format *format;
531
532 format = zalloc(sizeof(*format));
533 if (!format)
534 return -ENOMEM;
535
536 format->name = strdup(name);
537 format->value = config;
538 memcpy(format->bits, bits, sizeof(format->bits));
539
540 list_add_tail(&format->list, list);
541 return 0;
542}
543
544void perf_pmu__set_format(unsigned long *bits, long from, long to)
545{
546 long b;
547
548 if (!to)
549 to = from;
550
551 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
552 for (b = from; b <= to; b++)
553 set_bit(b, bits);
554}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
deleted file mode 100644
index a313ed76a49..00000000000
--- a/tools/perf/util/pmu.h
+++ /dev/null
@@ -1,57 +0,0 @@
1#ifndef __PMU_H
2#define __PMU_H
3
4#include <linux/bitops.h>
5#include <linux/perf_event.h>
6
7enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG,
9 PERF_PMU_FORMAT_VALUE_CONFIG1,
10 PERF_PMU_FORMAT_VALUE_CONFIG2,
11};
12
13#define PERF_PMU_FORMAT_BITS 64
14
15struct perf_pmu__format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20};
21
22struct perf_pmu__alias {
23 char *name;
24 struct list_head terms;
25 struct list_head list;
26};
27
28struct perf_pmu {
29 char *name;
30 __u32 type;
31 struct cpu_map *cpus;
32 struct list_head format;
33 struct list_head aliases;
34 struct list_head list;
35};
36
37struct perf_pmu *perf_pmu__find(char *name);
38int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
39 struct list_head *head_terms);
40int perf_pmu__config_terms(struct list_head *formats,
41 struct perf_event_attr *attr,
42 struct list_head *head_terms);
43int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
44struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
45 struct list_head *head_terms);
46int perf_pmu_wrap(void);
47void perf_pmu_error(struct list_head *list, char *name, char const *msg);
48
49int perf_pmu__new_format(struct list_head *list, char *name,
50 int config, unsigned long *bits);
51void perf_pmu__set_format(unsigned long *bits, long from, long to);
52int perf_pmu__format_parse(char *dir, struct list_head *head);
53
54struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
55
56int perf_pmu__test(void);
57#endif /* __PMU_H */
diff --git a/tools/perf/util/pmu.l b/tools/perf/util/pmu.l
deleted file mode 100644
index a15d9fbd7c0..00000000000
--- a/tools/perf/util/pmu.l
+++ /dev/null
@@ -1,43 +0,0 @@
1%option prefix="perf_pmu_"
2
3%{
4#include <stdlib.h>
5#include <linux/bitops.h>
6#include "pmu.h"
7#include "pmu-bison.h"
8
9static int value(int base)
10{
11 long num;
12
13 errno = 0;
14 num = strtoul(perf_pmu_text, NULL, base);
15 if (errno)
16 return PP_ERROR;
17
18 perf_pmu_lval.num = num;
19 return PP_VALUE;
20}
21
22%}
23
24num_dec [0-9]+
25
26%%
27
28{num_dec} { return value(10); }
29config { return PP_CONFIG; }
30config1 { return PP_CONFIG1; }
31config2 { return PP_CONFIG2; }
32- { return '-'; }
33: { return ':'; }
34, { return ','; }
35. { ; }
36\n { ; }
37
38%%
39
40int perf_pmu_wrap(void)
41{
42 return 1;
43}
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
deleted file mode 100644
index ec898047ebb..00000000000
--- a/tools/perf/util/pmu.y
+++ /dev/null
@@ -1,93 +0,0 @@
1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format}
4%parse-param {char *name}
5
6%{
7
8#include <linux/compiler.h>
9#include <linux/list.h>
10#include <linux/bitmap.h>
11#include <string.h>
12#include "pmu.h"
13
14extern int perf_pmu_lex (void);
15
16#define ABORT_ON(val) \
17do { \
18 if (val) \
19 YYABORT; \
20} while (0)
21
22%}
23
24%token PP_CONFIG PP_CONFIG1 PP_CONFIG2
25%token PP_VALUE PP_ERROR
26%type <num> PP_VALUE
27%type <bits> bit_term
28%type <bits> bits
29
30%union
31{
32 unsigned long num;
33 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
34}
35
36%%
37
38format:
39format format_term
40|
41format_term
42
43format_term:
44PP_CONFIG ':' bits
45{
46 ABORT_ON(perf_pmu__new_format(format, name,
47 PERF_PMU_FORMAT_VALUE_CONFIG,
48 $3));
49}
50|
51PP_CONFIG1 ':' bits
52{
53 ABORT_ON(perf_pmu__new_format(format, name,
54 PERF_PMU_FORMAT_VALUE_CONFIG1,
55 $3));
56}
57|
58PP_CONFIG2 ':' bits
59{
60 ABORT_ON(perf_pmu__new_format(format, name,
61 PERF_PMU_FORMAT_VALUE_CONFIG2,
62 $3));
63}
64
65bits:
66bits ',' bit_term
67{
68 bitmap_or($$, $1, $3, 64);
69}
70|
71bit_term
72{
73 memcpy($$, $1, sizeof($1));
74}
75
76bit_term:
77PP_VALUE '-' PP_VALUE
78{
79 perf_pmu__set_format($$, $1, $3);
80}
81|
82PP_VALUE
83{
84 perf_pmu__set_format($$, $1, 0);
85}
86
87%%
88
89void perf_pmu_error(struct list_head *list __maybe_unused,
90 char *name __maybe_unused,
91 char const *msg __maybe_unused)
92{
93}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 49a256e6e0a..eb25900e221 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#define _GNU_SOURCE
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>
@@ -32,8 +33,10 @@
32#include <limits.h> 33#include <limits.h>
33#include <elf.h> 34#include <elf.h>
34 35
36#undef _GNU_SOURCE
35#include "util.h" 37#include "util.h"
36#include "event.h" 38#include "event.h"
39#include "string.h"
37#include "strlist.h" 40#include "strlist.h"
38#include "debug.h" 41#include "debug.h"
39#include "cache.h" 42#include "cache.h"
@@ -41,10 +44,9 @@
41#include "symbol.h" 44#include "symbol.h"
42#include "thread.h" 45#include "thread.h"
43#include "debugfs.h" 46#include "debugfs.h"
44#include "trace-event.h" /* For __maybe_unused */ 47#include "trace-event.h" /* For __unused */
45#include "probe-event.h" 48#include "probe-event.h"
46#include "probe-finder.h" 49#include "probe-finder.h"
47#include "session.h"
48 50
49#define MAX_CMDLEN 256 51#define MAX_CMDLEN 256
50#define MAX_PROBE_ARGS 128 52#define MAX_PROBE_ARGS 128
@@ -71,8 +73,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
71} 73}
72 74
73static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 75static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
74static int convert_name_to_addr(struct perf_probe_event *pev,
75 const char *exec);
76static struct machine machine; 76static struct machine machine;
77 77
78/* Initialize symbol maps and path of vmlinux/modules */ 78/* Initialize symbol maps and path of vmlinux/modules */
@@ -173,34 +173,6 @@ const char *kernel_get_module_path(const char *module)
173 return (dso) ? dso->long_name : NULL; 173 return (dso) ? dso->long_name : NULL;
174} 174}
175 175
176static int init_user_exec(void)
177{
178 int ret = 0;
179
180 symbol_conf.try_vmlinux_path = false;
181 symbol_conf.sort_by_name = true;
182 ret = symbol__init();
183
184 if (ret < 0)
185 pr_debug("Failed to init symbol map.\n");
186
187 return ret;
188}
189
190static int convert_to_perf_probe_point(struct probe_trace_point *tp,
191 struct perf_probe_point *pp)
192{
193 pp->function = strdup(tp->symbol);
194
195 if (pp->function == NULL)
196 return -ENOMEM;
197
198 pp->offset = tp->offset;
199 pp->retprobe = tp->retprobe;
200
201 return 0;
202}
203
204#ifdef DWARF_SUPPORT 176#ifdef DWARF_SUPPORT
205/* Open new debuginfo of given module */ 177/* Open new debuginfo of given module */
206static struct debuginfo *open_debuginfo(const char *module) 178static struct debuginfo *open_debuginfo(const char *module)
@@ -255,7 +227,10 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
255 if (ret <= 0) { 227 if (ret <= 0) {
256 pr_debug("Failed to find corresponding probes from " 228 pr_debug("Failed to find corresponding probes from "
257 "debuginfo. Use kprobe event information.\n"); 229 "debuginfo. Use kprobe event information.\n");
258 return convert_to_perf_probe_point(tp, pp); 230 pp->function = strdup(tp->symbol);
231 if (pp->function == NULL)
232 return -ENOMEM;
233 pp->offset = tp->offset;
259 } 234 }
260 pp->retprobe = tp->retprobe; 235 pp->retprobe = tp->retprobe;
261 236
@@ -300,23 +275,12 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
300/* Try to find perf_probe_event with debuginfo */ 275/* Try to find perf_probe_event with debuginfo */
301static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 276static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
302 struct probe_trace_event **tevs, 277 struct probe_trace_event **tevs,
303 int max_tevs, const char *target) 278 int max_tevs, const char *module)
304{ 279{
305 bool need_dwarf = perf_probe_event_need_dwarf(pev); 280 bool need_dwarf = perf_probe_event_need_dwarf(pev);
306 struct debuginfo *dinfo; 281 struct debuginfo *dinfo = open_debuginfo(module);
307 int ntevs, ret = 0; 282 int ntevs, ret = 0;
308 283
309 if (pev->uprobes) {
310 if (need_dwarf) {
311 pr_warning("Debuginfo-analysis is not yet supported"
312 " with -x/--exec option.\n");
313 return -ENOSYS;
314 }
315 return convert_name_to_addr(pev, target);
316 }
317
318 dinfo = open_debuginfo(target);
319
320 if (!dinfo) { 284 if (!dinfo) {
321 if (need_dwarf) { 285 if (need_dwarf) {
322 pr_warning("Failed to open debuginfo file.\n"); 286 pr_warning("Failed to open debuginfo file.\n");
@@ -333,9 +297,9 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
333 297
334 if (ntevs > 0) { /* Succeeded to find trace events */ 298 if (ntevs > 0) { /* Succeeded to find trace events */
335 pr_debug("find %d probe_trace_events.\n", ntevs); 299 pr_debug("find %d probe_trace_events.\n", ntevs);
336 if (target) 300 if (module)
337 ret = add_module_to_probe_trace_events(*tevs, ntevs, 301 ret = add_module_to_probe_trace_events(*tevs, ntevs,
338 target); 302 module);
339 return ret < 0 ? ret : ntevs; 303 return ret < 0 ? ret : ntevs;
340 } 304 }
341 305
@@ -642,37 +606,37 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
642 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); 606 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
643 return -ENOENT; 607 return -ENOENT;
644 } 608 }
609 pp->function = strdup(tp->symbol);
610 if (pp->function == NULL)
611 return -ENOMEM;
612 pp->offset = tp->offset;
613 pp->retprobe = tp->retprobe;
645 614
646 return convert_to_perf_probe_point(tp, pp); 615 return 0;
647} 616}
648 617
649static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 618static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
650 struct probe_trace_event **tevs __maybe_unused, 619 struct probe_trace_event **tevs __unused,
651 int max_tevs __maybe_unused, const char *target) 620 int max_tevs __unused, const char *mod __unused)
652{ 621{
653 if (perf_probe_event_need_dwarf(pev)) { 622 if (perf_probe_event_need_dwarf(pev)) {
654 pr_warning("Debuginfo-analysis is not supported.\n"); 623 pr_warning("Debuginfo-analysis is not supported.\n");
655 return -ENOSYS; 624 return -ENOSYS;
656 } 625 }
657
658 if (pev->uprobes)
659 return convert_name_to_addr(pev, target);
660
661 return 0; 626 return 0;
662} 627}
663 628
664int show_line_range(struct line_range *lr __maybe_unused, 629int show_line_range(struct line_range *lr __unused, const char *module __unused)
665 const char *module __maybe_unused)
666{ 630{
667 pr_warning("Debuginfo-analysis is not supported.\n"); 631 pr_warning("Debuginfo-analysis is not supported.\n");
668 return -ENOSYS; 632 return -ENOSYS;
669} 633}
670 634
671int show_available_vars(struct perf_probe_event *pevs __maybe_unused, 635int show_available_vars(struct perf_probe_event *pevs __unused,
672 int npevs __maybe_unused, int max_vls __maybe_unused, 636 int npevs __unused, int max_vls __unused,
673 const char *module __maybe_unused, 637 const char *module __unused,
674 struct strfilter *filter __maybe_unused, 638 struct strfilter *filter __unused,
675 bool externs __maybe_unused) 639 bool externs __unused)
676{ 640{
677 pr_warning("Debuginfo-analysis is not supported.\n"); 641 pr_warning("Debuginfo-analysis is not supported.\n");
678 return -ENOSYS; 642 return -ENOSYS;
@@ -1100,7 +1064,6 @@ static int parse_probe_trace_command(const char *cmd,
1100 struct probe_trace_point *tp = &tev->point; 1064 struct probe_trace_point *tp = &tev->point;
1101 char pr; 1065 char pr;
1102 char *p; 1066 char *p;
1103 char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str;
1104 int ret, i, argc; 1067 int ret, i, argc;
1105 char **argv; 1068 char **argv;
1106 1069
@@ -1117,27 +1080,14 @@ static int parse_probe_trace_command(const char *cmd,
1117 } 1080 }
1118 1081
1119 /* Scan event and group name. */ 1082 /* Scan event and group name. */
1120 argv0_str = strdup(argv[0]); 1083 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
1121 if (argv0_str == NULL) { 1084 &pr, (float *)(void *)&tev->group,
1122 ret = -ENOMEM; 1085 (float *)(void *)&tev->event);
1123 goto out; 1086 if (ret != 3) {
1124 }
1125 fmt1_str = strtok_r(argv0_str, ":", &fmt);
1126 fmt2_str = strtok_r(NULL, "/", &fmt);
1127 fmt3_str = strtok_r(NULL, " \t", &fmt);
1128 if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL
1129 || fmt3_str == NULL) {
1130 semantic_error("Failed to parse event name: %s\n", argv[0]); 1087 semantic_error("Failed to parse event name: %s\n", argv[0]);
1131 ret = -EINVAL; 1088 ret = -EINVAL;
1132 goto out; 1089 goto out;
1133 } 1090 }
1134 pr = fmt1_str[0];
1135 tev->group = strdup(fmt2_str);
1136 tev->event = strdup(fmt3_str);
1137 if (tev->group == NULL || tev->event == NULL) {
1138 ret = -ENOMEM;
1139 goto out;
1140 }
1141 pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); 1091 pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
1142 1092
1143 tp->retprobe = (pr == 'r'); 1093 tp->retprobe = (pr == 'r');
@@ -1149,17 +1099,10 @@ static int parse_probe_trace_command(const char *cmd,
1149 p++; 1099 p++;
1150 } else 1100 } else
1151 p = argv[1]; 1101 p = argv[1];
1152 fmt1_str = strtok_r(p, "+", &fmt); 1102 ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol,
1153 tp->symbol = strdup(fmt1_str); 1103 &tp->offset);
1154 if (tp->symbol == NULL) { 1104 if (ret == 1)
1155 ret = -ENOMEM;
1156 goto out;
1157 }
1158 fmt2_str = strtok_r(NULL, "", &fmt);
1159 if (fmt2_str == NULL)
1160 tp->offset = 0; 1105 tp->offset = 0;
1161 else
1162 tp->offset = strtoul(fmt2_str, NULL, 10);
1163 1106
1164 tev->nargs = argc - 2; 1107 tev->nargs = argc - 2;
1165 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1108 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1183,7 +1126,6 @@ static int parse_probe_trace_command(const char *cmd,
1183 } 1126 }
1184 ret = 0; 1127 ret = 0;
1185out: 1128out:
1186 free(argv0_str);
1187 argv_free(argv); 1129 argv_free(argv);
1188 return ret; 1130 return ret;
1189} 1131}
@@ -1402,18 +1344,11 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1402 if (buf == NULL) 1344 if (buf == NULL)
1403 return NULL; 1345 return NULL;
1404 1346
1405 if (tev->uprobes) 1347 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
1406 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", 1348 tp->retprobe ? 'r' : 'p',
1407 tp->retprobe ? 'r' : 'p', 1349 tev->group, tev->event,
1408 tev->group, tev->event, 1350 tp->module ?: "", tp->module ? ":" : "",
1409 tp->module, tp->symbol); 1351 tp->symbol, tp->offset);
1410 else
1411 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
1412 tp->retprobe ? 'r' : 'p',
1413 tev->group, tev->event,
1414 tp->module ?: "", tp->module ? ":" : "",
1415 tp->symbol, tp->offset);
1416
1417 if (len <= 0) 1352 if (len <= 0)
1418 goto error; 1353 goto error;
1419 1354
@@ -1432,7 +1367,7 @@ error:
1432} 1367}
1433 1368
1434static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1369static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1435 struct perf_probe_event *pev, bool is_kprobe) 1370 struct perf_probe_event *pev)
1436{ 1371{
1437 char buf[64] = ""; 1372 char buf[64] = "";
1438 int i, ret; 1373 int i, ret;
@@ -1444,11 +1379,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1444 return -ENOMEM; 1379 return -ENOMEM;
1445 1380
1446 /* Convert trace_point to probe_point */ 1381 /* Convert trace_point to probe_point */
1447 if (is_kprobe) 1382 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1448 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1449 else
1450 ret = convert_to_perf_probe_point(&tev->point, &pev->point);
1451
1452 if (ret < 0) 1383 if (ret < 0)
1453 return ret; 1384 return ret;
1454 1385
@@ -1544,26 +1475,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1544 memset(tev, 0, sizeof(*tev)); 1475 memset(tev, 0, sizeof(*tev));
1545} 1476}
1546 1477
1547static void print_warn_msg(const char *file, bool is_kprobe) 1478static int open_kprobe_events(bool readwrite)
1548{
1549
1550 if (errno == ENOENT) {
1551 const char *config;
1552
1553 if (!is_kprobe)
1554 config = "CONFIG_UPROBE_EVENTS";
1555 else
1556 config = "CONFIG_KPROBE_EVENTS";
1557
1558 pr_warning("%s file does not exist - please rebuild kernel"
1559 " with %s.\n", file, config);
1560 } else
1561 pr_warning("Failed to open %s file: %s\n", file,
1562 strerror(errno));
1563}
1564
1565static int open_probe_events(const char *trace_file, bool readwrite,
1566 bool is_kprobe)
1567{ 1479{
1568 char buf[PATH_MAX]; 1480 char buf[PATH_MAX];
1569 const char *__debugfs; 1481 const char *__debugfs;
@@ -1575,31 +1487,27 @@ static int open_probe_events(const char *trace_file, bool readwrite,
1575 return -ENOENT; 1487 return -ENOENT;
1576 } 1488 }
1577 1489
1578 ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); 1490 ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
1579 if (ret >= 0) { 1491 if (ret >= 0) {
1580 pr_debug("Opening %s write=%d\n", buf, readwrite); 1492 pr_debug("Opening %s write=%d\n", buf, readwrite);
1581 if (readwrite && !probe_event_dry_run) 1493 if (readwrite && !probe_event_dry_run)
1582 ret = open(buf, O_RDWR, O_APPEND); 1494 ret = open(buf, O_RDWR, O_APPEND);
1583 else 1495 else
1584 ret = open(buf, O_RDONLY, 0); 1496 ret = open(buf, O_RDONLY, 0);
1497 }
1585 1498
1586 if (ret < 0) 1499 if (ret < 0) {
1587 print_warn_msg(buf, is_kprobe); 1500 if (errno == ENOENT)
1501 pr_warning("kprobe_events file does not exist - please"
1502 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
1503 else
1504 pr_warning("Failed to open kprobe_events file: %s\n",
1505 strerror(errno));
1588 } 1506 }
1589 return ret; 1507 return ret;
1590} 1508}
1591 1509
1592static int open_kprobe_events(bool readwrite) 1510/* Get raw string list of current kprobe_events */
1593{
1594 return open_probe_events("tracing/kprobe_events", readwrite, true);
1595}
1596
1597static int open_uprobe_events(bool readwrite)
1598{
1599 return open_probe_events("tracing/uprobe_events", readwrite, false);
1600}
1601
1602/* Get raw string list of current kprobe_events or uprobe_events */
1603static struct strlist *get_probe_trace_command_rawlist(int fd) 1511static struct strlist *get_probe_trace_command_rawlist(int fd)
1604{ 1512{
1605 int ret, idx; 1513 int ret, idx;
@@ -1664,26 +1572,36 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
1664 return ret; 1572 return ret;
1665} 1573}
1666 1574
1667static int __show_perf_probe_events(int fd, bool is_kprobe) 1575/* List up current perf-probe events */
1576int show_perf_probe_events(void)
1668{ 1577{
1669 int ret = 0; 1578 int fd, ret;
1670 struct probe_trace_event tev; 1579 struct probe_trace_event tev;
1671 struct perf_probe_event pev; 1580 struct perf_probe_event pev;
1672 struct strlist *rawlist; 1581 struct strlist *rawlist;
1673 struct str_node *ent; 1582 struct str_node *ent;
1674 1583
1584 setup_pager();
1585 ret = init_vmlinux();
1586 if (ret < 0)
1587 return ret;
1588
1675 memset(&tev, 0, sizeof(tev)); 1589 memset(&tev, 0, sizeof(tev));
1676 memset(&pev, 0, sizeof(pev)); 1590 memset(&pev, 0, sizeof(pev));
1677 1591
1592 fd = open_kprobe_events(false);
1593 if (fd < 0)
1594 return fd;
1595
1678 rawlist = get_probe_trace_command_rawlist(fd); 1596 rawlist = get_probe_trace_command_rawlist(fd);
1597 close(fd);
1679 if (!rawlist) 1598 if (!rawlist)
1680 return -ENOENT; 1599 return -ENOENT;
1681 1600
1682 strlist__for_each(ent, rawlist) { 1601 strlist__for_each(ent, rawlist) {
1683 ret = parse_probe_trace_command(ent->s, &tev); 1602 ret = parse_probe_trace_command(ent->s, &tev);
1684 if (ret >= 0) { 1603 if (ret >= 0) {
1685 ret = convert_to_perf_probe_event(&tev, &pev, 1604 ret = convert_to_perf_probe_event(&tev, &pev);
1686 is_kprobe);
1687 if (ret >= 0) 1605 if (ret >= 0)
1688 ret = show_perf_probe_event(&pev); 1606 ret = show_perf_probe_event(&pev);
1689 } 1607 }
@@ -1697,33 +1615,6 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
1697 return ret; 1615 return ret;
1698} 1616}
1699 1617
1700/* List up current perf-probe events */
1701int show_perf_probe_events(void)
1702{
1703 int fd, ret;
1704
1705 setup_pager();
1706 fd = open_kprobe_events(false);
1707
1708 if (fd < 0)
1709 return fd;
1710
1711 ret = init_vmlinux();
1712 if (ret < 0)
1713 return ret;
1714
1715 ret = __show_perf_probe_events(fd, true);
1716 close(fd);
1717
1718 fd = open_uprobe_events(false);
1719 if (fd >= 0) {
1720 ret = __show_perf_probe_events(fd, false);
1721 close(fd);
1722 }
1723
1724 return ret;
1725}
1726
1727/* Get current perf-probe event names */ 1618/* Get current perf-probe event names */
1728static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 1619static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1729{ 1620{
@@ -1829,11 +1720,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1829 const char *event, *group; 1720 const char *event, *group;
1830 struct strlist *namelist; 1721 struct strlist *namelist;
1831 1722
1832 if (pev->uprobes) 1723 fd = open_kprobe_events(true);
1833 fd = open_uprobe_events(true);
1834 else
1835 fd = open_kprobe_events(true);
1836
1837 if (fd < 0) 1724 if (fd < 0)
1838 return fd; 1725 return fd;
1839 /* Get current event names */ 1726 /* Get current event names */
@@ -1844,7 +1731,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1844 } 1731 }
1845 1732
1846 ret = 0; 1733 ret = 0;
1847 printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); 1734 printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
1848 for (i = 0; i < ntevs; i++) { 1735 for (i = 0; i < ntevs; i++) {
1849 tev = &tevs[i]; 1736 tev = &tevs[i];
1850 if (pev->event) 1737 if (pev->event)
@@ -1899,7 +1786,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1899 1786
1900 if (ret >= 0) { 1787 if (ret >= 0) {
1901 /* Show how to use the event. */ 1788 /* Show how to use the event. */
1902 printf("\nYou can now use it in all perf tools, such as:\n\n"); 1789 printf("\nYou can now use it on all perf tools, such as:\n\n");
1903 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 1790 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1904 tev->event); 1791 tev->event);
1905 } 1792 }
@@ -1911,14 +1798,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1911 1798
1912static int convert_to_probe_trace_events(struct perf_probe_event *pev, 1799static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1913 struct probe_trace_event **tevs, 1800 struct probe_trace_event **tevs,
1914 int max_tevs, const char *target) 1801 int max_tevs, const char *module)
1915{ 1802{
1916 struct symbol *sym; 1803 struct symbol *sym;
1917 int ret = 0, i; 1804 int ret = 0, i;
1918 struct probe_trace_event *tev; 1805 struct probe_trace_event *tev;
1919 1806
1920 /* Convert perf_probe_event with debuginfo */ 1807 /* Convert perf_probe_event with debuginfo */
1921 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 1808 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1922 if (ret != 0) 1809 if (ret != 0)
1923 return ret; /* Found in debuginfo or got an error */ 1810 return ret; /* Found in debuginfo or got an error */
1924 1811
@@ -1934,8 +1821,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1934 goto error; 1821 goto error;
1935 } 1822 }
1936 1823
1937 if (target) { 1824 if (module) {
1938 tev->point.module = strdup(target); 1825 tev->point.module = strdup(module);
1939 if (tev->point.module == NULL) { 1826 if (tev->point.module == NULL) {
1940 ret = -ENOMEM; 1827 ret = -ENOMEM;
1941 goto error; 1828 goto error;
@@ -1945,8 +1832,6 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1945 tev->point.offset = pev->point.offset; 1832 tev->point.offset = pev->point.offset;
1946 tev->point.retprobe = pev->point.retprobe; 1833 tev->point.retprobe = pev->point.retprobe;
1947 tev->nargs = pev->nargs; 1834 tev->nargs = pev->nargs;
1948 tev->uprobes = pev->uprobes;
1949
1950 if (tev->nargs) { 1835 if (tev->nargs) {
1951 tev->args = zalloc(sizeof(struct probe_trace_arg) 1836 tev->args = zalloc(sizeof(struct probe_trace_arg)
1952 * tev->nargs); 1837 * tev->nargs);
@@ -1977,9 +1862,6 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1977 } 1862 }
1978 } 1863 }
1979 1864
1980 if (pev->uprobes)
1981 return 1;
1982
1983 /* Currently just checking function name from symbol map */ 1865 /* Currently just checking function name from symbol map */
1984 sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 1866 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1985 if (!sym) { 1867 if (!sym) {
@@ -1987,12 +1869,6 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1987 tev->point.symbol); 1869 tev->point.symbol);
1988 ret = -ENOENT; 1870 ret = -ENOENT;
1989 goto error; 1871 goto error;
1990 } else if (tev->point.offset > sym->end - sym->start) {
1991 pr_warning("Offset specified is greater than size of %s\n",
1992 tev->point.symbol);
1993 ret = -ENOENT;
1994 goto error;
1995
1996 } 1872 }
1997 1873
1998 return 1; 1874 return 1;
@@ -2010,23 +1886,17 @@ struct __event_package {
2010}; 1886};
2011 1887
2012int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1888int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
2013 int max_tevs, const char *target, bool force_add) 1889 int max_tevs, const char *module, bool force_add)
2014{ 1890{
2015 int i, j, ret; 1891 int i, j, ret;
2016 struct __event_package *pkgs; 1892 struct __event_package *pkgs;
2017 1893
2018 ret = 0;
2019 pkgs = zalloc(sizeof(struct __event_package) * npevs); 1894 pkgs = zalloc(sizeof(struct __event_package) * npevs);
2020
2021 if (pkgs == NULL) 1895 if (pkgs == NULL)
2022 return -ENOMEM; 1896 return -ENOMEM;
2023 1897
2024 if (!pevs->uprobes) 1898 /* Init vmlinux path */
2025 /* Init vmlinux path */ 1899 ret = init_vmlinux();
2026 ret = init_vmlinux();
2027 else
2028 ret = init_user_exec();
2029
2030 if (ret < 0) { 1900 if (ret < 0) {
2031 free(pkgs); 1901 free(pkgs);
2032 return ret; 1902 return ret;
@@ -2039,7 +1909,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
2039 ret = convert_to_probe_trace_events(pkgs[i].pev, 1909 ret = convert_to_probe_trace_events(pkgs[i].pev,
2040 &pkgs[i].tevs, 1910 &pkgs[i].tevs,
2041 max_tevs, 1911 max_tevs,
2042 target); 1912 module);
2043 if (ret < 0) 1913 if (ret < 0)
2044 goto end; 1914 goto end;
2045 pkgs[i].ntevs = ret; 1915 pkgs[i].ntevs = ret;
@@ -2091,22 +1961,30 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
2091 goto error; 1961 goto error;
2092 } 1962 }
2093 1963
2094 printf("Removed event: %s\n", ent->s); 1964 printf("Remove event: %s\n", ent->s);
2095 return 0; 1965 return 0;
2096error: 1966error:
2097 pr_warning("Failed to delete event: %s\n", strerror(-ret)); 1967 pr_warning("Failed to delete event: %s\n", strerror(-ret));
2098 return ret; 1968 return ret;
2099} 1969}
2100 1970
2101static int del_trace_probe_event(int fd, const char *buf, 1971static int del_trace_probe_event(int fd, const char *group,
2102 struct strlist *namelist) 1972 const char *event, struct strlist *namelist)
2103{ 1973{
1974 char buf[128];
2104 struct str_node *ent, *n; 1975 struct str_node *ent, *n;
2105 int ret = -1; 1976 int found = 0, ret = 0;
1977
1978 ret = e_snprintf(buf, 128, "%s:%s", group, event);
1979 if (ret < 0) {
1980 pr_err("Failed to copy event.\n");
1981 return ret;
1982 }
2106 1983
2107 if (strpbrk(buf, "*?")) { /* Glob-exp */ 1984 if (strpbrk(buf, "*?")) { /* Glob-exp */
2108 strlist__for_each_safe(ent, n, namelist) 1985 strlist__for_each_safe(ent, n, namelist)
2109 if (strglobmatch(ent->s, buf)) { 1986 if (strglobmatch(ent->s, buf)) {
1987 found++;
2110 ret = __del_trace_probe_event(fd, ent); 1988 ret = __del_trace_probe_event(fd, ent);
2111 if (ret < 0) 1989 if (ret < 0)
2112 break; 1990 break;
@@ -2115,43 +1993,40 @@ static int del_trace_probe_event(int fd, const char *buf,
2115 } else { 1993 } else {
2116 ent = strlist__find(namelist, buf); 1994 ent = strlist__find(namelist, buf);
2117 if (ent) { 1995 if (ent) {
1996 found++;
2118 ret = __del_trace_probe_event(fd, ent); 1997 ret = __del_trace_probe_event(fd, ent);
2119 if (ret >= 0) 1998 if (ret >= 0)
2120 strlist__remove(namelist, ent); 1999 strlist__remove(namelist, ent);
2121 } 2000 }
2122 } 2001 }
2002 if (found == 0 && ret >= 0)
2003 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2123 2004
2124 return ret; 2005 return ret;
2125} 2006}
2126 2007
2127int del_perf_probe_events(struct strlist *dellist) 2008int del_perf_probe_events(struct strlist *dellist)
2128{ 2009{
2129 int ret = -1, ufd = -1, kfd = -1; 2010 int fd, ret = 0;
2130 char buf[128];
2131 const char *group, *event; 2011 const char *group, *event;
2132 char *p, *str; 2012 char *p, *str;
2133 struct str_node *ent; 2013 struct str_node *ent;
2134 struct strlist *namelist = NULL, *unamelist = NULL; 2014 struct strlist *namelist;
2135
2136 /* Get current event names */
2137 kfd = open_kprobe_events(true);
2138 if (kfd < 0)
2139 return kfd;
2140
2141 namelist = get_probe_trace_event_names(kfd, true);
2142 ufd = open_uprobe_events(true);
2143 2015
2144 if (ufd >= 0) 2016 fd = open_kprobe_events(true);
2145 unamelist = get_probe_trace_event_names(ufd, true); 2017 if (fd < 0)
2018 return fd;
2146 2019
2147 if (namelist == NULL && unamelist == NULL) 2020 /* Get current event names */
2148 goto error; 2021 namelist = get_probe_trace_event_names(fd, true);
2022 if (namelist == NULL)
2023 return -EINVAL;
2149 2024
2150 strlist__for_each(ent, dellist) { 2025 strlist__for_each(ent, dellist) {
2151 str = strdup(ent->s); 2026 str = strdup(ent->s);
2152 if (str == NULL) { 2027 if (str == NULL) {
2153 ret = -ENOMEM; 2028 ret = -ENOMEM;
2154 goto error; 2029 break;
2155 } 2030 }
2156 pr_debug("Parsing: %s\n", str); 2031 pr_debug("Parsing: %s\n", str);
2157 p = strchr(str, ':'); 2032 p = strchr(str, ':');
@@ -2163,42 +2038,17 @@ int del_perf_probe_events(struct strlist *dellist)
2163 group = "*"; 2038 group = "*";
2164 event = str; 2039 event = str;
2165 } 2040 }
2166
2167 ret = e_snprintf(buf, 128, "%s:%s", group, event);
2168 if (ret < 0) {
2169 pr_err("Failed to copy event.");
2170 free(str);
2171 goto error;
2172 }
2173
2174 pr_debug("Group: %s, Event: %s\n", group, event); 2041 pr_debug("Group: %s, Event: %s\n", group, event);
2175 2042 ret = del_trace_probe_event(fd, group, event, namelist);
2176 if (namelist)
2177 ret = del_trace_probe_event(kfd, buf, namelist);
2178
2179 if (unamelist && ret != 0)
2180 ret = del_trace_probe_event(ufd, buf, unamelist);
2181
2182 if (ret != 0)
2183 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2184
2185 free(str); 2043 free(str);
2044 if (ret < 0)
2045 break;
2186 } 2046 }
2187 2047 strlist__delete(namelist);
2188error: 2048 close(fd);
2189 if (kfd >= 0) {
2190 strlist__delete(namelist);
2191 close(kfd);
2192 }
2193
2194 if (ufd >= 0) {
2195 strlist__delete(unamelist);
2196 close(ufd);
2197 }
2198 2049
2199 return ret; 2050 return ret;
2200} 2051}
2201
2202/* TODO: don't use a global variable for filter ... */ 2052/* TODO: don't use a global variable for filter ... */
2203static struct strfilter *available_func_filter; 2053static struct strfilter *available_func_filter;
2204 2054
@@ -2206,7 +2056,7 @@ static struct strfilter *available_func_filter;
2206 * If a symbol corresponds to a function with global binding and 2056 * If a symbol corresponds to a function with global binding and
2207 * matches filter return 0. For all others return 1. 2057 * matches filter return 0. For all others return 1.
2208 */ 2058 */
2209static int filter_available_functions(struct map *map __maybe_unused, 2059static int filter_available_functions(struct map *map __unused,
2210 struct symbol *sym) 2060 struct symbol *sym)
2211{ 2061{
2212 if (sym->binding == STB_GLOBAL && 2062 if (sym->binding == STB_GLOBAL &&
@@ -2215,24 +2065,13 @@ static int filter_available_functions(struct map *map __maybe_unused,
2215 return 1; 2065 return 1;
2216} 2066}
2217 2067
2218static int __show_available_funcs(struct map *map) 2068int show_available_funcs(const char *module, struct strfilter *_filter)
2219{
2220 if (map__load(map, filter_available_functions)) {
2221 pr_err("Failed to load map.\n");
2222 return -EINVAL;
2223 }
2224 if (!dso__sorted_by_name(map->dso, map->type))
2225 dso__sort_by_name(map->dso, map->type);
2226
2227 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2228 return 0;
2229}
2230
2231static int available_kernel_funcs(const char *module)
2232{ 2069{
2233 struct map *map; 2070 struct map *map;
2234 int ret; 2071 int ret;
2235 2072
2073 setup_pager();
2074
2236 ret = init_vmlinux(); 2075 ret = init_vmlinux();
2237 if (ret < 0) 2076 if (ret < 0)
2238 return ret; 2077 return ret;
@@ -2242,133 +2081,14 @@ static int available_kernel_funcs(const char *module)
2242 pr_err("Failed to find %s map.\n", (module) ? : "kernel"); 2081 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
2243 return -EINVAL; 2082 return -EINVAL;
2244 } 2083 }
2245 return __show_available_funcs(map);
2246}
2247
2248static int available_user_funcs(const char *target)
2249{
2250 struct map *map;
2251 int ret;
2252
2253 ret = init_user_exec();
2254 if (ret < 0)
2255 return ret;
2256
2257 map = dso__new_map(target);
2258 ret = __show_available_funcs(map);
2259 dso__delete(map->dso);
2260 map__delete(map);
2261 return ret;
2262}
2263
2264int show_available_funcs(const char *target, struct strfilter *_filter,
2265 bool user)
2266{
2267 setup_pager();
2268 available_func_filter = _filter; 2084 available_func_filter = _filter;
2269
2270 if (!user)
2271 return available_kernel_funcs(target);
2272
2273 return available_user_funcs(target);
2274}
2275
2276/*
2277 * uprobe_events only accepts address:
2278 * Convert function and any offset to address
2279 */
2280static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2281{
2282 struct perf_probe_point *pp = &pev->point;
2283 struct symbol *sym;
2284 struct map *map = NULL;
2285 char *function = NULL, *name = NULL;
2286 int ret = -EINVAL;
2287 unsigned long long vaddr = 0;
2288
2289 if (!pp->function) {
2290 pr_warning("No function specified for uprobes");
2291 goto out;
2292 }
2293
2294 function = strdup(pp->function);
2295 if (!function) {
2296 pr_warning("Failed to allocate memory by strdup.\n");
2297 ret = -ENOMEM;
2298 goto out;
2299 }
2300
2301 name = realpath(exec, NULL);
2302 if (!name) {
2303 pr_warning("Cannot find realpath for %s.\n", exec);
2304 goto out;
2305 }
2306 map = dso__new_map(name);
2307 if (!map) {
2308 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2309 goto out;
2310 }
2311 available_func_filter = strfilter__new(function, NULL);
2312 if (map__load(map, filter_available_functions)) { 2085 if (map__load(map, filter_available_functions)) {
2313 pr_err("Failed to load map.\n"); 2086 pr_err("Failed to load map.\n");
2314 goto out; 2087 return -EINVAL;
2315 }
2316
2317 sym = map__find_symbol_by_name(map, function, NULL);
2318 if (!sym) {
2319 pr_warning("Cannot find %s in DSO %s\n", function, exec);
2320 goto out;
2321 }
2322
2323 if (map->start > sym->start)
2324 vaddr = map->start;
2325 vaddr += sym->start + pp->offset + map->pgoff;
2326 pp->offset = 0;
2327
2328 if (!pev->event) {
2329 pev->event = function;
2330 function = NULL;
2331 }
2332 if (!pev->group) {
2333 char *ptr1, *ptr2, *exec_copy;
2334
2335 pev->group = zalloc(sizeof(char *) * 64);
2336 exec_copy = strdup(exec);
2337 if (!exec_copy) {
2338 ret = -ENOMEM;
2339 pr_warning("Failed to copy exec string.\n");
2340 goto out;
2341 }
2342
2343 ptr1 = strdup(basename(exec_copy));
2344 if (ptr1) {
2345 ptr2 = strpbrk(ptr1, "-._");
2346 if (ptr2)
2347 *ptr2 = '\0';
2348 e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
2349 ptr1);
2350 free(ptr1);
2351 }
2352 free(exec_copy);
2353 }
2354 free(pp->function);
2355 pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
2356 if (!pp->function) {
2357 ret = -ENOMEM;
2358 pr_warning("Failed to allocate memory by zalloc.\n");
2359 goto out;
2360 } 2088 }
2361 e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); 2089 if (!dso__sorted_by_name(map->dso, map->type))
2362 ret = 0; 2090 dso__sort_by_name(map->dso, map->type);
2363 2091
2364out: 2092 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2365 if (map) { 2093 return 0;
2366 dso__delete(map->dso);
2367 map__delete(map);
2368 }
2369 if (function)
2370 free(function);
2371 if (name)
2372 free(name);
2373 return ret;
2374} 2094}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index f9f3de8b422..a7dee835f49 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
7 7
8extern bool probe_event_dry_run; 8extern bool probe_event_dry_run;
9 9
10/* kprobe-tracer and uprobe-tracer tracing point */ 10/* kprobe-tracer tracing point */
11struct probe_trace_point { 11struct probe_trace_point {
12 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */ 13 char *module; /* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
21 long offset; /* Offset value */ 21 long offset; /* Offset value */
22}; 22};
23 23
24/* kprobe-tracer and uprobe-tracer tracing argument */ 24/* kprobe-tracer tracing argument */
25struct probe_trace_arg { 25struct probe_trace_arg {
26 char *name; /* Argument name */ 26 char *name; /* Argument name */
27 char *value; /* Base value */ 27 char *value; /* Base value */
@@ -29,13 +29,12 @@ struct probe_trace_arg {
29 struct probe_trace_arg_ref *ref; /* Referencing offset */ 29 struct probe_trace_arg_ref *ref; /* Referencing offset */
30}; 30};
31 31
32/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */ 32/* kprobe-tracer tracing event (point + arg) */
33struct probe_trace_event { 33struct probe_trace_event {
34 char *event; /* Event name */ 34 char *event; /* Event name */
35 char *group; /* Group name */ 35 char *group; /* Group name */
36 struct probe_trace_point point; /* Trace point */ 36 struct probe_trace_point point; /* Trace point */
37 int nargs; /* Number of args */ 37 int nargs; /* Number of args */
38 bool uprobes; /* uprobes only */
39 struct probe_trace_arg *args; /* Arguments */ 38 struct probe_trace_arg *args; /* Arguments */
40}; 39};
41 40
@@ -71,7 +70,6 @@ struct perf_probe_event {
71 char *group; /* Group name */ 70 char *group; /* Group name */
72 struct perf_probe_point point; /* Probe point */ 71 struct perf_probe_point point; /* Probe point */
73 int nargs; /* Number of arguments */ 72 int nargs; /* Number of arguments */
74 bool uprobes;
75 struct perf_probe_arg *args; /* Arguments */ 73 struct perf_probe_arg *args; /* Arguments */
76}; 74};
77 75
@@ -131,8 +129,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
131extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 129extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
132 int max_probe_points, const char *module, 130 int max_probe_points, const char *module,
133 struct strfilter *filter, bool externs); 131 struct strfilter *filter, bool externs);
134extern int show_available_funcs(const char *module, struct strfilter *filter, 132extern int show_available_funcs(const char *module, struct strfilter *filter);
135 bool user); 133
136 134
137/* Maximum index number of event-name postfix */ 135/* Maximum index number of event-name postfix */
138#define MAX_EVENT_INDEX 1024 136#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 1daf5c14e75..5d732621a46 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -30,6 +30,7 @@
30#include <stdlib.h> 30#include <stdlib.h>
31#include <string.h> 31#include <string.h>
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h>
33#include <dwarf-regs.h> 34#include <dwarf-regs.h>
34 35
35#include <linux/bitops.h> 36#include <linux/bitops.h>
@@ -207,7 +208,7 @@ static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
207#else 208#else
208/* With older elfutils, this just support kernel module... */ 209/* With older elfutils, this just support kernel module... */
209static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 210static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
210 Dwarf_Addr addr __maybe_unused) 211 Dwarf_Addr addr __used)
211{ 212{
212 const char *path = kernel_get_module_path("kernel"); 213 const char *path = kernel_get_module_path("kernel");
213 214
@@ -525,10 +526,8 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
525 return -ENOENT; 526 return -ENOENT;
526 } 527 }
527 /* Verify it is a data structure */ 528 /* Verify it is a data structure */
528 tag = dwarf_tag(&type); 529 if (dwarf_tag(&type) != DW_TAG_structure_type) {
529 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 530 pr_warning("%s is not a data structure.\n", varname);
530 pr_warning("%s is not a data structure nor an union.\n",
531 varname);
532 return -EINVAL; 531 return -EINVAL;
533 } 532 }
534 533
@@ -541,9 +540,8 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
541 *ref_ptr = ref; 540 *ref_ptr = ref;
542 } else { 541 } else {
543 /* Verify it is a data structure */ 542 /* Verify it is a data structure */
544 if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { 543 if (tag != DW_TAG_structure_type) {
545 pr_warning("%s is not a data structure nor an union.\n", 544 pr_warning("%s is not a data structure.\n", varname);
546 varname);
547 return -EINVAL; 545 return -EINVAL;
548 } 546 }
549 if (field->name[0] == '[') { 547 if (field->name[0] == '[') {
@@ -570,15 +568,10 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
570 } 568 }
571 569
572 /* Get the offset of the field */ 570 /* Get the offset of the field */
573 if (tag == DW_TAG_union_type) { 571 ret = die_get_data_member_location(die_mem, &offs);
574 offs = 0; 572 if (ret < 0) {
575 } else { 573 pr_warning("Failed to get the offset of %s.\n", field->name);
576 ret = die_get_data_member_location(die_mem, &offs); 574 return ret;
577 if (ret < 0) {
578 pr_warning("Failed to get the offset of %s.\n",
579 field->name);
580 return ret;
581 }
582 } 575 }
583 ref->offset += (long)offs; 576 ref->offset += (long)offs;
584 577
@@ -679,7 +672,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
679static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, 672static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
680 bool retprobe, struct probe_trace_point *tp) 673 bool retprobe, struct probe_trace_point *tp)
681{ 674{
682 Dwarf_Addr eaddr, highaddr; 675 Dwarf_Addr eaddr;
683 const char *name; 676 const char *name;
684 677
685 /* Copy the name of probe point */ 678 /* Copy the name of probe point */
@@ -690,16 +683,6 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
690 dwarf_diename(sp_die)); 683 dwarf_diename(sp_die));
691 return -ENOENT; 684 return -ENOENT;
692 } 685 }
693 if (dwarf_highpc(sp_die, &highaddr) != 0) {
694 pr_warning("Failed to get end address of %s\n",
695 dwarf_diename(sp_die));
696 return -ENOENT;
697 }
698 if (paddr > highaddr) {
699 pr_warning("Offset specified is greater than size of %s\n",
700 dwarf_diename(sp_die));
701 return -EINVAL;
702 }
703 tp->symbol = strdup(name); 686 tp->symbol = strdup(name);
704 if (tp->symbol == NULL) 687 if (tp->symbol == NULL)
705 return -ENOMEM; 688 return -ENOMEM;
@@ -980,12 +963,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
980 struct dwarf_callback_param *param = data; 963 struct dwarf_callback_param *param = data;
981 struct probe_finder *pf = param->data; 964 struct probe_finder *pf = param->data;
982 struct perf_probe_point *pp = &pf->pev->point; 965 struct perf_probe_point *pp = &pf->pev->point;
983 Dwarf_Attribute attr;
984 966
985 /* Check tag and diename */ 967 /* Check tag and diename */
986 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 968 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
987 !die_compare_name(sp_die, pp->function) || 969 !die_compare_name(sp_die, pp->function))
988 dwarf_attr(sp_die, DW_AT_declaration, &attr))
989 return DWARF_CB_OK; 970 return DWARF_CB_OK;
990 971
991 /* Check declared file */ 972 /* Check declared file */
@@ -1427,7 +1408,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
1427} 1408}
1428 1409
1429static int line_range_walk_cb(const char *fname, int lineno, 1410static int line_range_walk_cb(const char *fname, int lineno,
1430 Dwarf_Addr addr __maybe_unused, 1411 Dwarf_Addr addr __used,
1431 void *data) 1412 void *data)
1432{ 1413{
1433 struct line_finder *lf = data; 1414 struct line_finder *lf = data;
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 17e94d0c36f..1132c8f0ce8 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -5,6 +5,7 @@
5#include "util.h" 5#include "util.h"
6#include "probe-event.h" 6#include "probe-event.h"
7 7
8#define MAX_PATH_LEN 256
8#define MAX_PROBE_BUFFER 1024 9#define MAX_PROBE_BUFFER 1024
9#define MAX_PROBES 128 10#define MAX_PROBES 128
10 11
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
index daa17aeb6c6..13d36faf64e 100644
--- a/tools/perf/util/pstack.c
+++ b/tools/perf/util/pstack.c
@@ -17,59 +17,59 @@ struct pstack {
17 17
18struct pstack *pstack__new(unsigned short max_nr_entries) 18struct pstack *pstack__new(unsigned short max_nr_entries)
19{ 19{
20 struct pstack *pstack = zalloc((sizeof(*pstack) + 20 struct pstack *self = zalloc((sizeof(*self) +
21 max_nr_entries * sizeof(void *))); 21 max_nr_entries * sizeof(void *)));
22 if (pstack != NULL) 22 if (self != NULL)
23 pstack->max_nr_entries = max_nr_entries; 23 self->max_nr_entries = max_nr_entries;
24 return pstack; 24 return self;
25} 25}
26 26
27void pstack__delete(struct pstack *pstack) 27void pstack__delete(struct pstack *self)
28{ 28{
29 free(pstack); 29 free(self);
30} 30}
31 31
32bool pstack__empty(const struct pstack *pstack) 32bool pstack__empty(const struct pstack *self)
33{ 33{
34 return pstack->top == 0; 34 return self->top == 0;
35} 35}
36 36
37void pstack__remove(struct pstack *pstack, void *key) 37void pstack__remove(struct pstack *self, void *key)
38{ 38{
39 unsigned short i = pstack->top, last_index = pstack->top - 1; 39 unsigned short i = self->top, last_index = self->top - 1;
40 40
41 while (i-- != 0) { 41 while (i-- != 0) {
42 if (pstack->entries[i] == key) { 42 if (self->entries[i] == key) {
43 if (i < last_index) 43 if (i < last_index)
44 memmove(pstack->entries + i, 44 memmove(self->entries + i,
45 pstack->entries + i + 1, 45 self->entries + i + 1,
46 (last_index - i) * sizeof(void *)); 46 (last_index - i) * sizeof(void *));
47 --pstack->top; 47 --self->top;
48 return; 48 return;
49 } 49 }
50 } 50 }
51 pr_err("%s: %p not on the pstack!\n", __func__, key); 51 pr_err("%s: %p not on the pstack!\n", __func__, key);
52} 52}
53 53
54void pstack__push(struct pstack *pstack, void *key) 54void pstack__push(struct pstack *self, void *key)
55{ 55{
56 if (pstack->top == pstack->max_nr_entries) { 56 if (self->top == self->max_nr_entries) {
57 pr_err("%s: top=%d, overflow!\n", __func__, pstack->top); 57 pr_err("%s: top=%d, overflow!\n", __func__, self->top);
58 return; 58 return;
59 } 59 }
60 pstack->entries[pstack->top++] = key; 60 self->entries[self->top++] = key;
61} 61}
62 62
63void *pstack__pop(struct pstack *pstack) 63void *pstack__pop(struct pstack *self)
64{ 64{
65 void *ret; 65 void *ret;
66 66
67 if (pstack->top == 0) { 67 if (self->top == 0) {
68 pr_err("%s: underflow!\n", __func__); 68 pr_err("%s: underflow!\n", __func__);
69 return NULL; 69 return NULL;
70 } 70 }
71 71
72 ret = pstack->entries[--pstack->top]; 72 ret = self->entries[--self->top];
73 pstack->entries[pstack->top] = NULL; 73 self->entries[self->top] = NULL;
74 return ret; 74 return ret;
75} 75}
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
deleted file mode 100644
index c40c2d33199..00000000000
--- a/tools/perf/util/python-ext-sources
+++ /dev/null
@@ -1,21 +0,0 @@
1#
2# List of files needed by perf python extension
3#
4# Each source file must be placed on its own line so that it can be
5# processed by Makefile and util/setup.py accordingly.
6#
7
8util/python.c
9util/ctype.c
10util/evlist.c
11util/evsel.c
12util/cpumap.c
13util/hweight.c
14util/thread_map.c
15util/util.c
16util/xyarray.c
17util/cgroup.c
18util/debugfs.c
19util/rblist.c
20util/strlist.c
21../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index a2657fd9683..7624324efad 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -425,14 +425,14 @@ struct pyrf_thread_map {
425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, 425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
426 PyObject *args, PyObject *kwargs) 426 PyObject *args, PyObject *kwargs)
427{ 427{
428 static char *kwlist[] = { "pid", "tid", "uid", NULL }; 428 static char *kwlist[] = { "pid", "tid", NULL };
429 int pid = -1, tid = -1, uid = UINT_MAX; 429 int pid = -1, tid = -1;
430 430
431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii", 431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
432 kwlist, &pid, &tid, &uid)) 432 kwlist, &pid, &tid))
433 return -1; 433 return -1;
434 434
435 pthreads->threads = thread_map__new(pid, tid, uid); 435 pthreads->threads = thread_map__new(pid, tid);
436 if (pthreads->threads == NULL) 436 if (pthreads->threads == NULL)
437 return -1; 437 return -1;
438 return 0; 438 return 0;
@@ -623,11 +623,7 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
623 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; 623 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
624 624
625 evsel->attr.inherit = inherit; 625 evsel->attr.inherit = inherit;
626 /* 626 if (perf_evsel__open(evsel, cpus, threads, group) < 0) {
627 * This will group just the fds for this single evsel, to group
628 * multiple events, use evlist.open().
629 */
630 if (perf_evsel__open(evsel, cpus, threads) < 0) {
631 PyErr_SetFromErrno(PyExc_OSError); 627 PyErr_SetFromErrno(PyExc_OSError);
632 return NULL; 628 return NULL;
633 } 629 }
@@ -672,7 +668,7 @@ struct pyrf_evlist {
672}; 668};
673 669
674static int pyrf_evlist__init(struct pyrf_evlist *pevlist, 670static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
675 PyObject *args, PyObject *kwargs __maybe_unused) 671 PyObject *args, PyObject *kwargs __used)
676{ 672{
677 PyObject *pcpus = NULL, *pthreads = NULL; 673 PyObject *pcpus = NULL, *pthreads = NULL;
678 struct cpu_map *cpus; 674 struct cpu_map *cpus;
@@ -733,8 +729,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
733} 729}
734 730
735static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, 731static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
736 PyObject *args __maybe_unused, 732 PyObject *args __used, PyObject *kwargs __used)
737 PyObject *kwargs __maybe_unused)
738{ 733{
739 struct perf_evlist *evlist = &pevlist->evlist; 734 struct perf_evlist *evlist = &pevlist->evlist;
740 PyObject *list = PyList_New(0); 735 PyObject *list = PyList_New(0);
@@ -766,8 +761,7 @@ free_list:
766 761
767 762
768static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, 763static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
769 PyObject *args, 764 PyObject *args, PyObject *kwargs __used)
770 PyObject *kwargs __maybe_unused)
771{ 765{
772 struct perf_evlist *evlist = &pevlist->evlist; 766 struct perf_evlist *evlist = &pevlist->evlist;
773 PyObject *pevsel; 767 PyObject *pevsel;
@@ -799,13 +793,17 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
799 793
800 event = perf_evlist__mmap_read(evlist, cpu); 794 event = perf_evlist__mmap_read(evlist, cpu);
801 if (event != NULL) { 795 if (event != NULL) {
796 struct perf_evsel *first;
802 PyObject *pyevent = pyrf_event__new(event); 797 PyObject *pyevent = pyrf_event__new(event);
803 struct pyrf_event *pevent = (struct pyrf_event *)pyevent; 798 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
804 799
805 if (pyevent == NULL) 800 if (pyevent == NULL)
806 return PyErr_NoMemory(); 801 return PyErr_NoMemory();
807 802
808 err = perf_evlist__parse_sample(evlist, event, &pevent->sample); 803 first = list_entry(evlist->entries.next, struct perf_evsel, node);
804 err = perf_event__parse_sample(event, first->attr.sample_type,
805 perf_evsel__sample_size(first),
806 sample_id_all, &pevent->sample, false);
809 if (err) 807 if (err)
810 return PyErr_Format(PyExc_OSError, 808 return PyErr_Format(PyExc_OSError,
811 "perf: can't parse sample, err=%d", err); 809 "perf: can't parse sample, err=%d", err);
@@ -816,28 +814,6 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
816 return Py_None; 814 return Py_None;
817} 815}
818 816
819static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
820 PyObject *args, PyObject *kwargs)
821{
822 struct perf_evlist *evlist = &pevlist->evlist;
823 int group = 0;
824 static char *kwlist[] = { "group", NULL };
825
826 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, &group))
827 return NULL;
828
829 if (group)
830 perf_evlist__set_leader(evlist);
831
832 if (perf_evlist__open(evlist) < 0) {
833 PyErr_SetFromErrno(PyExc_OSError);
834 return NULL;
835 }
836
837 Py_INCREF(Py_None);
838 return Py_None;
839}
840
841static PyMethodDef pyrf_evlist__methods[] = { 817static PyMethodDef pyrf_evlist__methods[] = {
842 { 818 {
843 .ml_name = "mmap", 819 .ml_name = "mmap",
@@ -846,12 +822,6 @@ static PyMethodDef pyrf_evlist__methods[] = {
846 .ml_doc = PyDoc_STR("mmap the file descriptor table.") 822 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
847 }, 823 },
848 { 824 {
849 .ml_name = "open",
850 .ml_meth = (PyCFunction)pyrf_evlist__open,
851 .ml_flags = METH_VARARGS | METH_KEYWORDS,
852 .ml_doc = PyDoc_STR("open the file descriptors.")
853 },
854 {
855 .ml_name = "poll", 825 .ml_name = "poll",
856 .ml_meth = (PyCFunction)pyrf_evlist__poll, 826 .ml_meth = (PyCFunction)pyrf_evlist__poll,
857 .ml_flags = METH_VARARGS | METH_KEYWORDS, 827 .ml_flags = METH_VARARGS | METH_KEYWORDS,
@@ -1015,8 +985,6 @@ PyMODINIT_FUNC initperf(void)
1015 pyrf_cpu_map__setup_types() < 0) 985 pyrf_cpu_map__setup_types() < 0)
1016 return; 986 return;
1017 987
1018 page_size = sysconf(_SC_PAGE_SIZE);
1019
1020 Py_INCREF(&pyrf_evlist__type); 988 Py_INCREF(&pyrf_evlist__type);
1021 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type); 989 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
1022 990
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
deleted file mode 100644
index a16cdd2625a..00000000000
--- a/tools/perf/util/rblist.c
+++ /dev/null
@@ -1,107 +0,0 @@
1/*
2 * Based on strlist.c by:
3 * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
4 *
5 * Licensed under the GPLv2.
6 */
7
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11
12#include "rblist.h"
13
14int rblist__add_node(struct rblist *rblist, const void *new_entry)
15{
16 struct rb_node **p = &rblist->entries.rb_node;
17 struct rb_node *parent = NULL, *new_node;
18
19 while (*p != NULL) {
20 int rc;
21
22 parent = *p;
23
24 rc = rblist->node_cmp(parent, new_entry);
25 if (rc > 0)
26 p = &(*p)->rb_left;
27 else if (rc < 0)
28 p = &(*p)->rb_right;
29 else
30 return -EEXIST;
31 }
32
33 new_node = rblist->node_new(rblist, new_entry);
34 if (new_node == NULL)
35 return -ENOMEM;
36
37 rb_link_node(new_node, parent, p);
38 rb_insert_color(new_node, &rblist->entries);
39 ++rblist->nr_entries;
40
41 return 0;
42}
43
44void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
45{
46 rb_erase(rb_node, &rblist->entries);
47 --rblist->nr_entries;
48 rblist->node_delete(rblist, rb_node);
49}
50
51struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
52{
53 struct rb_node **p = &rblist->entries.rb_node;
54 struct rb_node *parent = NULL;
55
56 while (*p != NULL) {
57 int rc;
58
59 parent = *p;
60
61 rc = rblist->node_cmp(parent, entry);
62 if (rc > 0)
63 p = &(*p)->rb_left;
64 else if (rc < 0)
65 p = &(*p)->rb_right;
66 else
67 return parent;
68 }
69
70 return NULL;
71}
72
73void rblist__init(struct rblist *rblist)
74{
75 if (rblist != NULL) {
76 rblist->entries = RB_ROOT;
77 rblist->nr_entries = 0;
78 }
79
80 return;
81}
82
83void rblist__delete(struct rblist *rblist)
84{
85 if (rblist != NULL) {
86 struct rb_node *pos, *next = rb_first(&rblist->entries);
87
88 while (next) {
89 pos = next;
90 next = rb_next(pos);
91 rblist__remove_node(rblist, pos);
92 }
93 free(rblist);
94 }
95}
96
97struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)
98{
99 struct rb_node *node;
100
101 for (node = rb_first(&rblist->entries); node; node = rb_next(node)) {
102 if (!idx--)
103 return node;
104 }
105
106 return NULL;
107}
diff --git a/tools/perf/util/rblist.h b/tools/perf/util/rblist.h
deleted file mode 100644
index 6d0cae5ae83..00000000000
--- a/tools/perf/util/rblist.h
+++ /dev/null
@@ -1,47 +0,0 @@
1#ifndef __PERF_RBLIST_H
2#define __PERF_RBLIST_H
3
4#include <linux/rbtree.h>
5#include <stdbool.h>
6
7/*
8 * create node structs of the form:
9 * struct my_node {
10 * struct rb_node rb_node;
11 * ... my data ...
12 * };
13 *
14 * create list structs of the form:
15 * struct mylist {
16 * struct rblist rblist;
17 * ... my data ...
18 * };
19 */
20
21struct rblist {
22 struct rb_root entries;
23 unsigned int nr_entries;
24
25 int (*node_cmp)(struct rb_node *rbn, const void *entry);
26 struct rb_node *(*node_new)(struct rblist *rlist, const void *new_entry);
27 void (*node_delete)(struct rblist *rblist, struct rb_node *rb_node);
28};
29
30void rblist__init(struct rblist *rblist);
31void rblist__delete(struct rblist *rblist);
32int rblist__add_node(struct rblist *rblist, const void *new_entry);
33void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node);
34struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
35struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
36
37static inline bool rblist__empty(const struct rblist *rblist)
38{
39 return rblist->nr_entries == 0;
40}
41
42static inline unsigned int rblist__nr_entries(const struct rblist *rblist)
43{
44 return rblist->nr_entries;
45}
46
47#endif /* __PERF_RBLIST_H */
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index f80605eb185..74350ffb57f 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -25,16 +25,13 @@
25#include <ctype.h> 25#include <ctype.h>
26#include <errno.h> 26#include <errno.h>
27 27
28#include "../../perf.h"
28#include "../util.h" 29#include "../util.h"
30#include "../trace-event.h"
31
29#include <EXTERN.h> 32#include <EXTERN.h>
30#include <perl.h> 33#include <perl.h>
31 34
32#include "../../perf.h"
33#include "../thread.h"
34#include "../event.h"
35#include "../trace-event.h"
36#include "../evsel.h"
37
38void boot_Perf__Trace__Context(pTHX_ CV *cv); 35void boot_Perf__Trace__Context(pTHX_ CV *cv);
39void boot_DynaLoader(pTHX_ CV *cv); 36void boot_DynaLoader(pTHX_ CV *cv);
40typedef PerlInterpreter * INTERP; 37typedef PerlInterpreter * INTERP;
@@ -56,7 +53,7 @@ INTERP my_perl;
56#define FTRACE_MAX_EVENT \ 53#define FTRACE_MAX_EVENT \
57 ((1 << (sizeof(unsigned short) * 8)) - 1) 54 ((1 << (sizeof(unsigned short) * 8)) - 1)
58 55
59struct event_format *events[FTRACE_MAX_EVENT]; 56struct event *events[FTRACE_MAX_EVENT];
60 57
61extern struct scripting_context *scripting_context; 58extern struct scripting_context *scripting_context;
62 59
@@ -181,7 +178,7 @@ static void define_flag_field(const char *ev_name,
181 LEAVE; 178 LEAVE;
182} 179}
183 180
184static void define_event_symbols(struct event_format *event, 181static void define_event_symbols(struct event *event,
185 const char *ev_name, 182 const char *ev_name,
186 struct print_arg *args) 183 struct print_arg *args)
187{ 184{
@@ -209,12 +206,6 @@ static void define_event_symbols(struct event_format *event,
209 define_symbolic_values(args->symbol.symbols, ev_name, 206 define_symbolic_values(args->symbol.symbols, ev_name,
210 cur_field_name); 207 cur_field_name);
211 break; 208 break;
212 case PRINT_HEX:
213 define_event_symbols(event, ev_name, args->hex.field);
214 define_event_symbols(event, ev_name, args->hex.size);
215 break;
216 case PRINT_BSTRING:
217 case PRINT_DYNAMIC_ARRAY:
218 case PRINT_STRING: 209 case PRINT_STRING:
219 break; 210 break;
220 case PRINT_TYPE: 211 case PRINT_TYPE:
@@ -226,9 +217,7 @@ static void define_event_symbols(struct event_format *event,
226 define_event_symbols(event, ev_name, args->op.left); 217 define_event_symbols(event, ev_name, args->op.left);
227 define_event_symbols(event, ev_name, args->op.right); 218 define_event_symbols(event, ev_name, args->op.right);
228 break; 219 break;
229 case PRINT_FUNC:
230 default: 220 default:
231 pr_err("Unsupported print arg type\n");
232 /* we should warn... */ 221 /* we should warn... */
233 return; 222 return;
234 } 223 }
@@ -237,16 +226,15 @@ static void define_event_symbols(struct event_format *event,
237 define_event_symbols(event, ev_name, args->next); 226 define_event_symbols(event, ev_name, args->next);
238} 227}
239 228
240static inline struct event_format *find_cache_event(struct perf_evsel *evsel) 229static inline struct event *find_cache_event(int type)
241{ 230{
242 static char ev_name[256]; 231 static char ev_name[256];
243 struct event_format *event; 232 struct event *event;
244 int type = evsel->attr.config;
245 233
246 if (events[type]) 234 if (events[type])
247 return events[type]; 235 return events[type];
248 236
249 events[type] = event = evsel->tp_format; 237 events[type] = event = trace_find_event(type);
250 if (!event) 238 if (!event)
251 return NULL; 239 return NULL;
252 240
@@ -257,34 +245,33 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
257 return event; 245 return event;
258} 246}
259 247
260static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, 248static void perl_process_event(union perf_event *pevent __unused,
261 struct perf_sample *sample, 249 struct perf_sample *sample,
262 struct perf_evsel *evsel, 250 struct perf_evsel *evsel,
263 struct machine *machine __maybe_unused, 251 struct perf_session *session __unused,
264 struct addr_location *al) 252 struct thread *thread)
265{ 253{
266 struct format_field *field; 254 struct format_field *field;
267 static char handler[256]; 255 static char handler[256];
268 unsigned long long val; 256 unsigned long long val;
269 unsigned long s, ns; 257 unsigned long s, ns;
270 struct event_format *event; 258 struct event *event;
259 int type;
271 int pid; 260 int pid;
272 int cpu = sample->cpu; 261 int cpu = sample->cpu;
273 void *data = sample->raw_data; 262 void *data = sample->raw_data;
274 unsigned long long nsecs = sample->time; 263 unsigned long long nsecs = sample->time;
275 struct thread *thread = al->thread;
276 char *comm = thread->comm; 264 char *comm = thread->comm;
277 265
278 dSP; 266 dSP;
279 267
280 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 268 type = trace_parse_common_type(data);
281 return;
282 269
283 event = find_cache_event(evsel); 270 event = find_cache_event(type);
284 if (!event) 271 if (!event)
285 die("ug! no event found for type %" PRIu64, evsel->attr.config); 272 die("ug! no event found for type %d", type);
286 273
287 pid = raw_field_value(event, "common_pid", data); 274 pid = trace_parse_common_pid(data);
288 275
289 sprintf(handler, "%s::%s", event->system, event->name); 276 sprintf(handler, "%s::%s", event->system, event->name);
290 277
@@ -317,8 +304,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
317 offset = field->offset; 304 offset = field->offset;
318 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0))); 305 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
319 } else { /* FIELD_IS_NUMERIC */ 306 } else { /* FIELD_IS_NUMERIC */
320 val = read_size(event, data + field->offset, 307 val = read_size(data + field->offset, field->size);
321 field->size);
322 if (field->flags & FIELD_IS_SIGNED) { 308 if (field->flags & FIELD_IS_SIGNED) {
323 XPUSHs(sv_2mortal(newSViv(val))); 309 XPUSHs(sv_2mortal(newSViv(val)));
324 } else { 310 } else {
@@ -346,42 +332,6 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
346 LEAVE; 332 LEAVE;
347} 333}
348 334
349static void perl_process_event_generic(union perf_event *event,
350 struct perf_sample *sample,
351 struct perf_evsel *evsel,
352 struct machine *machine __maybe_unused,
353 struct addr_location *al __maybe_unused)
354{
355 dSP;
356
357 if (!get_cv("process_event", 0))
358 return;
359
360 ENTER;
361 SAVETMPS;
362 PUSHMARK(SP);
363 XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size)));
364 XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->attr, sizeof(evsel->attr))));
365 XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample))));
366 XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size)));
367 PUTBACK;
368 call_pv("process_event", G_SCALAR);
369 SPAGAIN;
370 PUTBACK;
371 FREETMPS;
372 LEAVE;
373}
374
375static void perl_process_event(union perf_event *event,
376 struct perf_sample *sample,
377 struct perf_evsel *evsel,
378 struct machine *machine,
379 struct addr_location *al)
380{
381 perl_process_tracepoint(event, sample, evsel, machine, al);
382 perl_process_event_generic(event, sample, evsel, machine, al);
383}
384
385static void run_start_sub(void) 335static void run_start_sub(void)
386{ 336{
387 dSP; /* access to Perl stack */ 337 dSP; /* access to Perl stack */
@@ -452,9 +402,9 @@ static int perl_stop_script(void)
452 return 0; 402 return 0;
453} 403}
454 404
455static int perl_generate_script(struct pevent *pevent, const char *outfile) 405static int perl_generate_script(const char *outfile)
456{ 406{
457 struct event_format *event = NULL; 407 struct event *event = NULL;
458 struct format_field *f; 408 struct format_field *f;
459 char fname[PATH_MAX]; 409 char fname[PATH_MAX];
460 int not_first, count; 410 int not_first, count;
@@ -499,7 +449,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)
499 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); 449 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
500 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); 450 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
501 451
502 while ((event = trace_find_next_event(pevent, event))) { 452 while ((event = trace_find_next_event(event))) {
503 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); 453 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
504 fprintf(ofp, "\tmy ("); 454 fprintf(ofp, "\tmy (");
505 455
@@ -603,28 +553,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)
603 fprintf(ofp, "sub print_header\n{\n" 553 fprintf(ofp, "sub print_header\n{\n"
604 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" 554 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
605 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t " 555 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
606 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n"); 556 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
607
608 fprintf(ofp,
609 "\n# Packed byte string args of process_event():\n"
610 "#\n"
611 "# $event:\tunion perf_event\tutil/event.h\n"
612 "# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n"
613 "# $sample:\tstruct perf_sample\tutil/event.h\n"
614 "# $raw_data:\tperf_sample->raw_data\tutil/event.h\n"
615 "\n"
616 "sub process_event\n"
617 "{\n"
618 "\tmy ($event, $attr, $sample, $raw_data) = @_;\n"
619 "\n"
620 "\tmy @event\t= unpack(\"LSS\", $event);\n"
621 "\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n"
622 "\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n"
623 "\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n"
624 "\n"
625 "\tuse Data::Dumper;\n"
626 "\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n"
627 "}\n");
628 557
629 fclose(ofp); 558 fclose(ofp);
630 559
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 14683dfca2e..6ccf70e8d8f 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -24,13 +24,11 @@
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <string.h> 26#include <string.h>
27#include <ctype.h>
27#include <errno.h> 28#include <errno.h>
28 29
29#include "../../perf.h" 30#include "../../perf.h"
30#include "../evsel.h"
31#include "../util.h" 31#include "../util.h"
32#include "../event.h"
33#include "../thread.h"
34#include "../trace-event.h" 32#include "../trace-event.h"
35 33
36PyMODINIT_FUNC initperf_trace_context(void); 34PyMODINIT_FUNC initperf_trace_context(void);
@@ -38,7 +36,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
38#define FTRACE_MAX_EVENT \ 36#define FTRACE_MAX_EVENT \
39 ((1 << (sizeof(unsigned short) * 8)) - 1) 37 ((1 << (sizeof(unsigned short) * 8)) - 1)
40 38
41struct event_format *events[FTRACE_MAX_EVENT]; 39struct event *events[FTRACE_MAX_EVENT];
42 40
43#define MAX_FIELDS 64 41#define MAX_FIELDS 64
44#define N_COMMON_FIELDS 7 42#define N_COMMON_FIELDS 7
@@ -137,7 +135,7 @@ static void define_field(enum print_arg_type field_type,
137 Py_DECREF(t); 135 Py_DECREF(t);
138} 136}
139 137
140static void define_event_symbols(struct event_format *event, 138static void define_event_symbols(struct event *event,
141 const char *ev_name, 139 const char *ev_name,
142 struct print_arg *args) 140 struct print_arg *args)
143{ 141{
@@ -167,10 +165,6 @@ static void define_event_symbols(struct event_format *event,
167 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name, 165 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
168 cur_field_name); 166 cur_field_name);
169 break; 167 break;
170 case PRINT_HEX:
171 define_event_symbols(event, ev_name, args->hex.field);
172 define_event_symbols(event, ev_name, args->hex.size);
173 break;
174 case PRINT_STRING: 168 case PRINT_STRING:
175 break; 169 break;
176 case PRINT_TYPE: 170 case PRINT_TYPE:
@@ -183,10 +177,6 @@ static void define_event_symbols(struct event_format *event,
183 define_event_symbols(event, ev_name, args->op.right); 177 define_event_symbols(event, ev_name, args->op.right);
184 break; 178 break;
185 default: 179 default:
186 /* gcc warns for these? */
187 case PRINT_BSTRING:
188 case PRINT_DYNAMIC_ARRAY:
189 case PRINT_FUNC:
190 /* we should warn... */ 180 /* we should warn... */
191 return; 181 return;
192 } 182 }
@@ -195,21 +185,15 @@ static void define_event_symbols(struct event_format *event,
195 define_event_symbols(event, ev_name, args->next); 185 define_event_symbols(event, ev_name, args->next);
196} 186}
197 187
198static inline struct event_format *find_cache_event(struct perf_evsel *evsel) 188static inline struct event *find_cache_event(int type)
199{ 189{
200 static char ev_name[256]; 190 static char ev_name[256];
201 struct event_format *event; 191 struct event *event;
202 int type = evsel->attr.config; 192
203
204 /*
205 * XXX: Do we really need to cache this since now we have evsel->tp_format
206 * cached already? Need to re-read this "cache" routine that as well calls
207 * define_event_symbols() :-\
208 */
209 if (events[type]) 193 if (events[type])
210 return events[type]; 194 return events[type];
211 195
212 events[type] = event = evsel->tp_format; 196 events[type] = event = trace_find_event(type);
213 if (!event) 197 if (!event)
214 return NULL; 198 return NULL;
215 199
@@ -220,36 +204,37 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
220 return event; 204 return event;
221} 205}
222 206
223static void python_process_tracepoint(union perf_event *perf_event 207static void python_process_event(union perf_event *pevent __unused,
224 __maybe_unused,
225 struct perf_sample *sample, 208 struct perf_sample *sample,
226 struct perf_evsel *evsel, 209 struct perf_evsel *evsel __unused,
227 struct machine *machine __maybe_unused, 210 struct perf_session *session __unused,
228 struct addr_location *al) 211 struct thread *thread)
229{ 212{
230 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 213 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
231 static char handler_name[256]; 214 static char handler_name[256];
232 struct format_field *field; 215 struct format_field *field;
233 unsigned long long val; 216 unsigned long long val;
234 unsigned long s, ns; 217 unsigned long s, ns;
235 struct event_format *event; 218 struct event *event;
236 unsigned n = 0; 219 unsigned n = 0;
220 int type;
237 int pid; 221 int pid;
238 int cpu = sample->cpu; 222 int cpu = sample->cpu;
239 void *data = sample->raw_data; 223 void *data = sample->raw_data;
240 unsigned long long nsecs = sample->time; 224 unsigned long long nsecs = sample->time;
241 struct thread *thread = al->thread;
242 char *comm = thread->comm; 225 char *comm = thread->comm;
243 226
244 t = PyTuple_New(MAX_FIELDS); 227 t = PyTuple_New(MAX_FIELDS);
245 if (!t) 228 if (!t)
246 Py_FatalError("couldn't create Python tuple"); 229 Py_FatalError("couldn't create Python tuple");
247 230
248 event = find_cache_event(evsel); 231 type = trace_parse_common_type(data);
232
233 event = find_cache_event(type);
249 if (!event) 234 if (!event)
250 die("ug! no event found for type %d", (int)evsel->attr.config); 235 die("ug! no event found for type %d", type);
251 236
252 pid = raw_field_value(event, "common_pid", data); 237 pid = trace_parse_common_pid(data);
253 238
254 sprintf(handler_name, "%s__%s", event->system, event->name); 239 sprintf(handler_name, "%s__%s", event->system, event->name);
255 240
@@ -294,8 +279,7 @@ static void python_process_tracepoint(union perf_event *perf_event
294 offset = field->offset; 279 offset = field->offset;
295 obj = PyString_FromString((char *)data + offset); 280 obj = PyString_FromString((char *)data + offset);
296 } else { /* FIELD_IS_NUMERIC */ 281 } else { /* FIELD_IS_NUMERIC */
297 val = read_size(event, data + field->offset, 282 val = read_size(data + field->offset, field->size);
298 field->size);
299 if (field->flags & FIELD_IS_SIGNED) { 283 if (field->flags & FIELD_IS_SIGNED) {
300 if ((long long)val >= LONG_MIN && 284 if ((long long)val >= LONG_MIN &&
301 (long long)val <= LONG_MAX) 285 (long long)val <= LONG_MAX)
@@ -339,84 +323,6 @@ static void python_process_tracepoint(union perf_event *perf_event
339 Py_DECREF(t); 323 Py_DECREF(t);
340} 324}
341 325
342static void python_process_general_event(union perf_event *perf_event
343 __maybe_unused,
344 struct perf_sample *sample,
345 struct perf_evsel *evsel,
346 struct machine *machine __maybe_unused,
347 struct addr_location *al)
348{
349 PyObject *handler, *retval, *t, *dict;
350 static char handler_name[64];
351 unsigned n = 0;
352 struct thread *thread = al->thread;
353
354 /*
355 * Use the MAX_FIELDS to make the function expandable, though
356 * currently there is only one item for the tuple.
357 */
358 t = PyTuple_New(MAX_FIELDS);
359 if (!t)
360 Py_FatalError("couldn't create Python tuple");
361
362 dict = PyDict_New();
363 if (!dict)
364 Py_FatalError("couldn't create Python dictionary");
365
366 snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
367
368 handler = PyDict_GetItemString(main_dict, handler_name);
369 if (!handler || !PyCallable_Check(handler))
370 goto exit;
371
372 PyDict_SetItemString(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
373 PyDict_SetItemString(dict, "attr", PyString_FromStringAndSize(
374 (const char *)&evsel->attr, sizeof(evsel->attr)));
375 PyDict_SetItemString(dict, "sample", PyString_FromStringAndSize(
376 (const char *)sample, sizeof(*sample)));
377 PyDict_SetItemString(dict, "raw_buf", PyString_FromStringAndSize(
378 (const char *)sample->raw_data, sample->raw_size));
379 PyDict_SetItemString(dict, "comm",
380 PyString_FromString(thread->comm));
381 if (al->map) {
382 PyDict_SetItemString(dict, "dso",
383 PyString_FromString(al->map->dso->name));
384 }
385 if (al->sym) {
386 PyDict_SetItemString(dict, "symbol",
387 PyString_FromString(al->sym->name));
388 }
389
390 PyTuple_SetItem(t, n++, dict);
391 if (_PyTuple_Resize(&t, n) == -1)
392 Py_FatalError("error resizing Python tuple");
393
394 retval = PyObject_CallObject(handler, t);
395 if (retval == NULL)
396 handler_call_die(handler_name);
397exit:
398 Py_DECREF(dict);
399 Py_DECREF(t);
400}
401
402static void python_process_event(union perf_event *perf_event,
403 struct perf_sample *sample,
404 struct perf_evsel *evsel,
405 struct machine *machine,
406 struct addr_location *al)
407{
408 switch (evsel->attr.type) {
409 case PERF_TYPE_TRACEPOINT:
410 python_process_tracepoint(perf_event, sample, evsel,
411 machine, al);
412 break;
413 /* Reserve for future process_hw/sw/raw APIs */
414 default:
415 python_process_general_event(perf_event, sample, evsel,
416 machine, al);
417 }
418}
419
420static int run_start_sub(void) 326static int run_start_sub(void)
421{ 327{
422 PyObject *handler, *retval; 328 PyObject *handler, *retval;
@@ -527,9 +433,9 @@ out:
527 return err; 433 return err;
528} 434}
529 435
530static int python_generate_script(struct pevent *pevent, const char *outfile) 436static int python_generate_script(const char *outfile)
531{ 437{
532 struct event_format *event = NULL; 438 struct event *event = NULL;
533 struct format_field *f; 439 struct format_field *f;
534 char fname[PATH_MAX]; 440 char fname[PATH_MAX];
535 int not_first, count; 441 int not_first, count;
@@ -576,7 +482,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
576 fprintf(ofp, "def trace_end():\n"); 482 fprintf(ofp, "def trace_end():\n");
577 fprintf(ofp, "\tprint \"in trace_end\"\n\n"); 483 fprintf(ofp, "\tprint \"in trace_end\"\n\n");
578 484
579 while ((event = trace_find_next_event(pevent, event))) { 485 while ((event = trace_find_next_event(event))) {
580 fprintf(ofp, "def %s__%s(", event->system, event->name); 486 fprintf(ofp, "def %s__%s(", event->system, event->name);
581 fprintf(ofp, "event_name, "); 487 fprintf(ofp, "event_name, ");
582 fprintf(ofp, "context, "); 488 fprintf(ofp, "context, ");
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce6f5116238..72458d9da5b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -10,14 +10,9 @@
10#include "evlist.h" 10#include "evlist.h"
11#include "evsel.h" 11#include "evsel.h"
12#include "session.h" 12#include "session.h"
13#include "tool.h"
14#include "sort.h" 13#include "sort.h"
15#include "util.h" 14#include "util.h"
16#include "cpumap.h" 15#include "cpumap.h"
17#include "event-parse.h"
18#include "perf_regs.h"
19#include "unwind.h"
20#include "vdso.h"
21 16
22static int perf_session__open(struct perf_session *self, bool force) 17static int perf_session__open(struct perf_session *self, bool force)
23{ 18{
@@ -28,7 +23,7 @@ static int perf_session__open(struct perf_session *self, bool force)
28 self->fd = STDIN_FILENO; 23 self->fd = STDIN_FILENO;
29 24
30 if (perf_session__read_header(self, self->fd) < 0) 25 if (perf_session__read_header(self, self->fd) < 0)
31 pr_err("incompatible file format (rerun with -v to learn more)"); 26 pr_err("incompatible file format");
32 27
33 return 0; 28 return 0;
34 } 29 }
@@ -60,7 +55,7 @@ static int perf_session__open(struct perf_session *self, bool force)
60 } 55 }
61 56
62 if (perf_session__read_header(self, self->fd) < 0) { 57 if (perf_session__read_header(self, self->fd) < 0) {
63 pr_err("incompatible file format (rerun with -v to learn more)"); 58 pr_err("incompatible file format");
64 goto out_close; 59 goto out_close;
65 } 60 }
66 61
@@ -83,12 +78,39 @@ out_close:
83 return -1; 78 return -1;
84} 79}
85 80
86void perf_session__set_id_hdr_size(struct perf_session *session) 81static void perf_session__id_header_size(struct perf_session *session)
87{ 82{
88 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); 83 struct perf_sample *data;
84 u64 sample_type = session->sample_type;
85 u16 size = 0;
89 86
90 session->host_machine.id_hdr_size = id_hdr_size; 87 if (!session->sample_id_all)
91 machines__set_id_hdr_size(&session->machines, id_hdr_size); 88 goto out;
89
90 if (sample_type & PERF_SAMPLE_TID)
91 size += sizeof(data->tid) * 2;
92
93 if (sample_type & PERF_SAMPLE_TIME)
94 size += sizeof(data->time);
95
96 if (sample_type & PERF_SAMPLE_ID)
97 size += sizeof(data->id);
98
99 if (sample_type & PERF_SAMPLE_STREAM_ID)
100 size += sizeof(data->stream_id);
101
102 if (sample_type & PERF_SAMPLE_CPU)
103 size += sizeof(data->cpu) * 2;
104out:
105 session->id_hdr_size = size;
106}
107
108void perf_session__update_sample_type(struct perf_session *self)
109{
110 self->sample_type = perf_evlist__sample_type(self->evlist);
111 self->sample_size = __perf_evsel__sample_size(self->sample_type);
112 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
113 perf_session__id_header_size(self);
92} 114}
93 115
94int perf_session__create_kernel_maps(struct perf_session *self) 116int perf_session__create_kernel_maps(struct perf_session *self)
@@ -108,26 +130,18 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
108 130
109struct perf_session *perf_session__new(const char *filename, int mode, 131struct perf_session *perf_session__new(const char *filename, int mode,
110 bool force, bool repipe, 132 bool force, bool repipe,
111 struct perf_tool *tool) 133 struct perf_event_ops *ops)
112{ 134{
113 struct perf_session *self; 135 size_t len = filename ? strlen(filename) + 1 : 0;
114 struct stat st; 136 struct perf_session *self = zalloc(sizeof(*self) + len);
115 size_t len;
116
117 if (!filename || !strlen(filename)) {
118 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
119 filename = "-";
120 else
121 filename = "perf.data";
122 }
123
124 len = strlen(filename);
125 self = zalloc(sizeof(*self) + len);
126 137
127 if (self == NULL) 138 if (self == NULL)
128 goto out; 139 goto out;
129 140
130 memcpy(self->filename, filename, len); 141 memcpy(self->filename, filename, len);
142 self->threads = RB_ROOT;
143 INIT_LIST_HEAD(&self->dead_threads);
144 self->last_match = NULL;
131 /* 145 /*
132 * On 64bit we can mmap the data file in one go. No need for tiny mmap 146 * On 64bit we can mmap the data file in one go. No need for tiny mmap
133 * slices. On 32bit we use 32MB. 147 * slices. On 32bit we use 32MB.
@@ -143,12 +157,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
143 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 157 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
144 INIT_LIST_HEAD(&self->ordered_samples.to_free); 158 INIT_LIST_HEAD(&self->ordered_samples.to_free);
145 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 159 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
146 hists__init(&self->hists);
147 160
148 if (mode == O_RDONLY) { 161 if (mode == O_RDONLY) {
149 if (perf_session__open(self, force) < 0) 162 if (perf_session__open(self, force) < 0)
150 goto out_delete; 163 goto out_delete;
151 perf_session__set_id_hdr_size(self); 164 perf_session__update_sample_type(self);
152 } else if (mode == O_WRONLY) { 165 } else if (mode == O_WRONLY) {
153 /* 166 /*
154 * In O_RDONLY mode this will be performed when reading the 167 * In O_RDONLY mode this will be performed when reading the
@@ -158,10 +171,10 @@ struct perf_session *perf_session__new(const char *filename, int mode,
158 goto out_delete; 171 goto out_delete;
159 } 172 }
160 173
161 if (tool && tool->ordering_requires_timestamps && 174 if (ops && ops->ordering_requires_timestamps &&
162 tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) { 175 ops->ordered_samples && !self->sample_id_all) {
163 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 176 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
164 tool->ordered_samples = false; 177 ops->ordered_samples = false;
165 } 178 }
166 179
167out: 180out:
@@ -171,22 +184,17 @@ out_delete:
171 return NULL; 184 return NULL;
172} 185}
173 186
174static void machine__delete_dead_threads(struct machine *machine) 187static void perf_session__delete_dead_threads(struct perf_session *self)
175{ 188{
176 struct thread *n, *t; 189 struct thread *n, *t;
177 190
178 list_for_each_entry_safe(t, n, &machine->dead_threads, node) { 191 list_for_each_entry_safe(t, n, &self->dead_threads, node) {
179 list_del(&t->node); 192 list_del(&t->node);
180 thread__delete(t); 193 thread__delete(t);
181 } 194 }
182} 195}
183 196
184static void perf_session__delete_dead_threads(struct perf_session *session) 197static void perf_session__delete_threads(struct perf_session *self)
185{
186 machine__delete_dead_threads(&session->host_machine);
187}
188
189static void machine__delete_threads(struct machine *self)
190{ 198{
191 struct rb_node *nd = rb_first(&self->threads); 199 struct rb_node *nd = rb_first(&self->threads);
192 200
@@ -199,11 +207,6 @@ static void machine__delete_threads(struct machine *self)
199 } 207 }
200} 208}
201 209
202static void perf_session__delete_threads(struct perf_session *session)
203{
204 machine__delete_threads(&session->host_machine);
205}
206
207void perf_session__delete(struct perf_session *self) 210void perf_session__delete(struct perf_session *self)
208{ 211{
209 perf_session__destroy_kernel_maps(self); 212 perf_session__destroy_kernel_maps(self);
@@ -212,10 +215,9 @@ void perf_session__delete(struct perf_session *self)
212 machine__exit(&self->host_machine); 215 machine__exit(&self->host_machine);
213 close(self->fd); 216 close(self->fd);
214 free(self); 217 free(self);
215 vdso__exit();
216} 218}
217 219
218void machine__remove_thread(struct machine *self, struct thread *th) 220void perf_session__remove_thread(struct perf_session *self, struct thread *th)
219{ 221{
220 self->last_match = NULL; 222 self->last_match = NULL;
221 rb_erase(&th->rb_node, &self->threads); 223 rb_erase(&th->rb_node, &self->threads);
@@ -234,80 +236,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
234 return 0; 236 return 0;
235} 237}
236 238
237static const u8 cpumodes[] = { 239int perf_session__resolve_callchain(struct perf_session *self,
238 PERF_RECORD_MISC_USER, 240 struct thread *thread,
239 PERF_RECORD_MISC_KERNEL, 241 struct ip_callchain *chain,
240 PERF_RECORD_MISC_GUEST_USER, 242 struct symbol **parent)
241 PERF_RECORD_MISC_GUEST_KERNEL
242};
243#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
244
245static void ip__resolve_ams(struct machine *self, struct thread *thread,
246 struct addr_map_symbol *ams,
247 u64 ip)
248{
249 struct addr_location al;
250 size_t i;
251 u8 m;
252
253 memset(&al, 0, sizeof(al));
254
255 for (i = 0; i < NCPUMODES; i++) {
256 m = cpumodes[i];
257 /*
258 * We cannot use the header.misc hint to determine whether a
259 * branch stack address is user, kernel, guest, hypervisor.
260 * Branches may straddle the kernel/user/hypervisor boundaries.
261 * Thus, we have to try consecutively until we find a match
262 * or else, the symbol is unknown
263 */
264 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
265 ip, &al, NULL);
266 if (al.sym)
267 goto found;
268 }
269found:
270 ams->addr = ip;
271 ams->al_addr = al.addr;
272 ams->sym = al.sym;
273 ams->map = al.map;
274}
275
276struct branch_info *machine__resolve_bstack(struct machine *self,
277 struct thread *thr,
278 struct branch_stack *bs)
279{
280 struct branch_info *bi;
281 unsigned int i;
282
283 bi = calloc(bs->nr, sizeof(struct branch_info));
284 if (!bi)
285 return NULL;
286
287 for (i = 0; i < bs->nr; i++) {
288 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
289 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
290 bi[i].flags = bs->entries[i].flags;
291 }
292 return bi;
293}
294
295static int machine__resolve_callchain_sample(struct machine *machine,
296 struct thread *thread,
297 struct ip_callchain *chain,
298 struct symbol **parent)
299
300{ 243{
301 u8 cpumode = PERF_RECORD_MISC_USER; 244 u8 cpumode = PERF_RECORD_MISC_USER;
302 unsigned int i; 245 unsigned int i;
303 int err; 246 int err;
304 247
305 callchain_cursor_reset(&callchain_cursor); 248 callchain_cursor_reset(&self->callchain_cursor);
306
307 if (chain->nr > PERF_MAX_STACK_DEPTH) {
308 pr_warning("corrupted callchain. skipping...\n");
309 return 0;
310 }
311 249
312 for (i = 0; i < chain->nr; i++) { 250 for (i = 0; i < chain->nr; i++) {
313 u64 ip; 251 u64 ip;
@@ -321,30 +259,20 @@ static int machine__resolve_callchain_sample(struct machine *machine,
321 if (ip >= PERF_CONTEXT_MAX) { 259 if (ip >= PERF_CONTEXT_MAX) {
322 switch (ip) { 260 switch (ip) {
323 case PERF_CONTEXT_HV: 261 case PERF_CONTEXT_HV:
324 cpumode = PERF_RECORD_MISC_HYPERVISOR; 262 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
325 break;
326 case PERF_CONTEXT_KERNEL: 263 case PERF_CONTEXT_KERNEL:
327 cpumode = PERF_RECORD_MISC_KERNEL; 264 cpumode = PERF_RECORD_MISC_KERNEL; break;
328 break;
329 case PERF_CONTEXT_USER: 265 case PERF_CONTEXT_USER:
330 cpumode = PERF_RECORD_MISC_USER; 266 cpumode = PERF_RECORD_MISC_USER; break;
331 break;
332 default: 267 default:
333 pr_debug("invalid callchain context: " 268 break;
334 "%"PRId64"\n", (s64) ip);
335 /*
336 * It seems the callchain is corrupted.
337 * Discard all.
338 */
339 callchain_cursor_reset(&callchain_cursor);
340 return 0;
341 } 269 }
342 continue; 270 continue;
343 } 271 }
344 272
345 al.filtered = false; 273 al.filtered = false;
346 thread__find_addr_location(thread, machine, cpumode, 274 thread__find_addr_location(thread, self, cpumode,
347 MAP__FUNCTION, ip, &al, NULL); 275 MAP__FUNCTION, thread->pid, ip, &al, NULL);
348 if (al.sym != NULL) { 276 if (al.sym != NULL) {
349 if (sort__has_parent && !*parent && 277 if (sort__has_parent && !*parent &&
350 symbol__match_parent_regex(al.sym)) 278 symbol__match_parent_regex(al.sym))
@@ -353,7 +281,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
353 break; 281 break;
354 } 282 }
355 283
356 err = callchain_cursor_append(&callchain_cursor, 284 err = callchain_cursor_append(&self->callchain_cursor,
357 ip, al.map, al.sym); 285 ip, al.map, al.sym);
358 if (err) 286 if (err)
359 return err; 287 return err;
@@ -362,144 +290,75 @@ static int machine__resolve_callchain_sample(struct machine *machine,
362 return 0; 290 return 0;
363} 291}
364 292
365static int unwind_entry(struct unwind_entry *entry, void *arg) 293static int process_event_synth_stub(union perf_event *event __used,
366{ 294 struct perf_session *session __used)
367 struct callchain_cursor *cursor = arg;
368 return callchain_cursor_append(cursor, entry->ip,
369 entry->map, entry->sym);
370}
371
372int machine__resolve_callchain(struct machine *machine,
373 struct perf_evsel *evsel,
374 struct thread *thread,
375 struct perf_sample *sample,
376 struct symbol **parent)
377
378{
379 int ret;
380
381 callchain_cursor_reset(&callchain_cursor);
382
383 ret = machine__resolve_callchain_sample(machine, thread,
384 sample->callchain, parent);
385 if (ret)
386 return ret;
387
388 /* Can we do dwarf post unwind? */
389 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
390 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
391 return 0;
392
393 /* Bail out if nothing was captured. */
394 if ((!sample->user_regs.regs) ||
395 (!sample->user_stack.size))
396 return 0;
397
398 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
399 thread, evsel->attr.sample_regs_user,
400 sample);
401
402}
403
404static int process_event_synth_tracing_data_stub(union perf_event *event
405 __maybe_unused,
406 struct perf_session *session
407 __maybe_unused)
408{
409 dump_printf(": unhandled!\n");
410 return 0;
411}
412
413static int process_event_synth_attr_stub(union perf_event *event __maybe_unused,
414 struct perf_evlist **pevlist
415 __maybe_unused)
416{
417 dump_printf(": unhandled!\n");
418 return 0;
419}
420
421static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,
422 union perf_event *event __maybe_unused,
423 struct perf_sample *sample __maybe_unused,
424 struct perf_evsel *evsel __maybe_unused,
425 struct machine *machine __maybe_unused)
426{ 295{
427 dump_printf(": unhandled!\n"); 296 dump_printf(": unhandled!\n");
428 return 0; 297 return 0;
429} 298}
430 299
431static int process_event_stub(struct perf_tool *tool __maybe_unused, 300static int process_event_sample_stub(union perf_event *event __used,
432 union perf_event *event __maybe_unused, 301 struct perf_sample *sample __used,
433 struct perf_sample *sample __maybe_unused, 302 struct perf_evsel *evsel __used,
434 struct machine *machine __maybe_unused) 303 struct perf_session *session __used)
435{ 304{
436 dump_printf(": unhandled!\n"); 305 dump_printf(": unhandled!\n");
437 return 0; 306 return 0;
438} 307}
439 308
440static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, 309static int process_event_stub(union perf_event *event __used,
441 union perf_event *event __maybe_unused, 310 struct perf_sample *sample __used,
442 struct perf_session *perf_session 311 struct perf_session *session __used)
443 __maybe_unused)
444{ 312{
445 dump_printf(": unhandled!\n"); 313 dump_printf(": unhandled!\n");
446 return 0; 314 return 0;
447} 315}
448 316
449static int process_event_type_stub(struct perf_tool *tool __maybe_unused, 317static int process_finished_round_stub(union perf_event *event __used,
450 union perf_event *event __maybe_unused) 318 struct perf_session *session __used,
319 struct perf_event_ops *ops __used)
451{ 320{
452 dump_printf(": unhandled!\n"); 321 dump_printf(": unhandled!\n");
453 return 0; 322 return 0;
454} 323}
455 324
456static int process_finished_round(struct perf_tool *tool, 325static int process_finished_round(union perf_event *event,
457 union perf_event *event, 326 struct perf_session *session,
458 struct perf_session *session); 327 struct perf_event_ops *ops);
459 328
460static void perf_tool__fill_defaults(struct perf_tool *tool) 329static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
461{ 330{
462 if (tool->sample == NULL) 331 if (handler->sample == NULL)
463 tool->sample = process_event_sample_stub; 332 handler->sample = process_event_sample_stub;
464 if (tool->mmap == NULL) 333 if (handler->mmap == NULL)
465 tool->mmap = process_event_stub; 334 handler->mmap = process_event_stub;
466 if (tool->comm == NULL) 335 if (handler->comm == NULL)
467 tool->comm = process_event_stub; 336 handler->comm = process_event_stub;
468 if (tool->fork == NULL) 337 if (handler->fork == NULL)
469 tool->fork = process_event_stub; 338 handler->fork = process_event_stub;
470 if (tool->exit == NULL) 339 if (handler->exit == NULL)
471 tool->exit = process_event_stub; 340 handler->exit = process_event_stub;
472 if (tool->lost == NULL) 341 if (handler->lost == NULL)
473 tool->lost = perf_event__process_lost; 342 handler->lost = perf_event__process_lost;
474 if (tool->read == NULL) 343 if (handler->read == NULL)
475 tool->read = process_event_sample_stub; 344 handler->read = process_event_stub;
476 if (tool->throttle == NULL) 345 if (handler->throttle == NULL)
477 tool->throttle = process_event_stub; 346 handler->throttle = process_event_stub;
478 if (tool->unthrottle == NULL) 347 if (handler->unthrottle == NULL)
479 tool->unthrottle = process_event_stub; 348 handler->unthrottle = process_event_stub;
480 if (tool->attr == NULL) 349 if (handler->attr == NULL)
481 tool->attr = process_event_synth_attr_stub; 350 handler->attr = process_event_synth_stub;
482 if (tool->event_type == NULL) 351 if (handler->event_type == NULL)
483 tool->event_type = process_event_type_stub; 352 handler->event_type = process_event_synth_stub;
484 if (tool->tracing_data == NULL) 353 if (handler->tracing_data == NULL)
485 tool->tracing_data = process_event_synth_tracing_data_stub; 354 handler->tracing_data = process_event_synth_stub;
486 if (tool->build_id == NULL) 355 if (handler->build_id == NULL)
487 tool->build_id = process_finished_round_stub; 356 handler->build_id = process_event_synth_stub;
488 if (tool->finished_round == NULL) { 357 if (handler->finished_round == NULL) {
489 if (tool->ordered_samples) 358 if (handler->ordered_samples)
490 tool->finished_round = process_finished_round; 359 handler->finished_round = process_finished_round;
491 else 360 else
492 tool->finished_round = process_finished_round_stub; 361 handler->finished_round = process_finished_round_stub;
493 }
494}
495
496void mem_bswap_32(void *src, int byte_size)
497{
498 u32 *m = src;
499 while (byte_size > 0) {
500 *m = bswap_32(*m);
501 byte_size -= sizeof(u32);
502 ++m;
503 } 362 }
504} 363}
505 364
@@ -514,65 +373,37 @@ void mem_bswap_64(void *src, int byte_size)
514 } 373 }
515} 374}
516 375
517static void swap_sample_id_all(union perf_event *event, void *data) 376static void perf_event__all64_swap(union perf_event *event)
518{
519 void *end = (void *) event + event->header.size;
520 int size = end - data;
521
522 BUG_ON(size % sizeof(u64));
523 mem_bswap_64(data, size);
524}
525
526static void perf_event__all64_swap(union perf_event *event,
527 bool sample_id_all __maybe_unused)
528{ 377{
529 struct perf_event_header *hdr = &event->header; 378 struct perf_event_header *hdr = &event->header;
530 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); 379 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
531} 380}
532 381
533static void perf_event__comm_swap(union perf_event *event, bool sample_id_all) 382static void perf_event__comm_swap(union perf_event *event)
534{ 383{
535 event->comm.pid = bswap_32(event->comm.pid); 384 event->comm.pid = bswap_32(event->comm.pid);
536 event->comm.tid = bswap_32(event->comm.tid); 385 event->comm.tid = bswap_32(event->comm.tid);
537
538 if (sample_id_all) {
539 void *data = &event->comm.comm;
540
541 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
542 swap_sample_id_all(event, data);
543 }
544} 386}
545 387
546static void perf_event__mmap_swap(union perf_event *event, 388static void perf_event__mmap_swap(union perf_event *event)
547 bool sample_id_all)
548{ 389{
549 event->mmap.pid = bswap_32(event->mmap.pid); 390 event->mmap.pid = bswap_32(event->mmap.pid);
550 event->mmap.tid = bswap_32(event->mmap.tid); 391 event->mmap.tid = bswap_32(event->mmap.tid);
551 event->mmap.start = bswap_64(event->mmap.start); 392 event->mmap.start = bswap_64(event->mmap.start);
552 event->mmap.len = bswap_64(event->mmap.len); 393 event->mmap.len = bswap_64(event->mmap.len);
553 event->mmap.pgoff = bswap_64(event->mmap.pgoff); 394 event->mmap.pgoff = bswap_64(event->mmap.pgoff);
554
555 if (sample_id_all) {
556 void *data = &event->mmap.filename;
557
558 data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
559 swap_sample_id_all(event, data);
560 }
561} 395}
562 396
563static void perf_event__task_swap(union perf_event *event, bool sample_id_all) 397static void perf_event__task_swap(union perf_event *event)
564{ 398{
565 event->fork.pid = bswap_32(event->fork.pid); 399 event->fork.pid = bswap_32(event->fork.pid);
566 event->fork.tid = bswap_32(event->fork.tid); 400 event->fork.tid = bswap_32(event->fork.tid);
567 event->fork.ppid = bswap_32(event->fork.ppid); 401 event->fork.ppid = bswap_32(event->fork.ppid);
568 event->fork.ptid = bswap_32(event->fork.ptid); 402 event->fork.ptid = bswap_32(event->fork.ptid);
569 event->fork.time = bswap_64(event->fork.time); 403 event->fork.time = bswap_64(event->fork.time);
570
571 if (sample_id_all)
572 swap_sample_id_all(event, &event->fork + 1);
573} 404}
574 405
575static void perf_event__read_swap(union perf_event *event, bool sample_id_all) 406static void perf_event__read_swap(union perf_event *event)
576{ 407{
577 event->read.pid = bswap_32(event->read.pid); 408 event->read.pid = bswap_32(event->read.pid);
578 event->read.tid = bswap_32(event->read.tid); 409 event->read.tid = bswap_32(event->read.tid);
@@ -580,41 +411,6 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
580 event->read.time_enabled = bswap_64(event->read.time_enabled); 411 event->read.time_enabled = bswap_64(event->read.time_enabled);
581 event->read.time_running = bswap_64(event->read.time_running); 412 event->read.time_running = bswap_64(event->read.time_running);
582 event->read.id = bswap_64(event->read.id); 413 event->read.id = bswap_64(event->read.id);
583
584 if (sample_id_all)
585 swap_sample_id_all(event, &event->read + 1);
586}
587
588static u8 revbyte(u8 b)
589{
590 int rev = (b >> 4) | ((b & 0xf) << 4);
591 rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);
592 rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);
593 return (u8) rev;
594}
595
596/*
597 * XXX this is hack in attempt to carry flags bitfield
598 * throught endian village. ABI says:
599 *
600 * Bit-fields are allocated from right to left (least to most significant)
601 * on little-endian implementations and from left to right (most to least
602 * significant) on big-endian implementations.
603 *
604 * The above seems to be byte specific, so we need to reverse each
605 * byte of the bitfield. 'Internet' also says this might be implementation
606 * specific and we probably need proper fix and carry perf_event_attr
607 * bitfield flags in separate data file FEAT_ section. Thought this seems
608 * to work for now.
609 */
610static void swap_bitfield(u8 *p, unsigned len)
611{
612 unsigned i;
613
614 for (i = 0; i < len; i++) {
615 *p = revbyte(*p);
616 p++;
617 }
618} 414}
619 415
620/* exported for swapping attributes in file header */ 416/* exported for swapping attributes in file header */
@@ -630,12 +426,9 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
630 attr->bp_type = bswap_32(attr->bp_type); 426 attr->bp_type = bswap_32(attr->bp_type);
631 attr->bp_addr = bswap_64(attr->bp_addr); 427 attr->bp_addr = bswap_64(attr->bp_addr);
632 attr->bp_len = bswap_64(attr->bp_len); 428 attr->bp_len = bswap_64(attr->bp_len);
633
634 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
635} 429}
636 430
637static void perf_event__hdr_attr_swap(union perf_event *event, 431static void perf_event__hdr_attr_swap(union perf_event *event)
638 bool sample_id_all __maybe_unused)
639{ 432{
640 size_t size; 433 size_t size;
641 434
@@ -646,21 +439,18 @@ static void perf_event__hdr_attr_swap(union perf_event *event,
646 mem_bswap_64(event->attr.id, size); 439 mem_bswap_64(event->attr.id, size);
647} 440}
648 441
649static void perf_event__event_type_swap(union perf_event *event, 442static void perf_event__event_type_swap(union perf_event *event)
650 bool sample_id_all __maybe_unused)
651{ 443{
652 event->event_type.event_type.event_id = 444 event->event_type.event_type.event_id =
653 bswap_64(event->event_type.event_type.event_id); 445 bswap_64(event->event_type.event_type.event_id);
654} 446}
655 447
656static void perf_event__tracing_data_swap(union perf_event *event, 448static void perf_event__tracing_data_swap(union perf_event *event)
657 bool sample_id_all __maybe_unused)
658{ 449{
659 event->tracing_data.size = bswap_32(event->tracing_data.size); 450 event->tracing_data.size = bswap_32(event->tracing_data.size);
660} 451}
661 452
662typedef void (*perf_event__swap_op)(union perf_event *event, 453typedef void (*perf_event__swap_op)(union perf_event *event);
663 bool sample_id_all);
664 454
665static perf_event__swap_op perf_event__swap_ops[] = { 455static perf_event__swap_op perf_event__swap_ops[] = {
666 [PERF_RECORD_MMAP] = perf_event__mmap_swap, 456 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
@@ -700,11 +490,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
700static int perf_session_deliver_event(struct perf_session *session, 490static int perf_session_deliver_event(struct perf_session *session,
701 union perf_event *event, 491 union perf_event *event,
702 struct perf_sample *sample, 492 struct perf_sample *sample,
703 struct perf_tool *tool, 493 struct perf_event_ops *ops,
704 u64 file_offset); 494 u64 file_offset);
705 495
706static int flush_sample_queue(struct perf_session *s, 496static void flush_sample_queue(struct perf_session *s,
707 struct perf_tool *tool) 497 struct perf_event_ops *ops)
708{ 498{
709 struct ordered_samples *os = &s->ordered_samples; 499 struct ordered_samples *os = &s->ordered_samples;
710 struct list_head *head = &os->samples; 500 struct list_head *head = &os->samples;
@@ -712,34 +502,25 @@ static int flush_sample_queue(struct perf_session *s,
712 struct perf_sample sample; 502 struct perf_sample sample;
713 u64 limit = os->next_flush; 503 u64 limit = os->next_flush;
714 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 504 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
715 unsigned idx = 0, progress_next = os->nr_samples / 16;
716 int ret; 505 int ret;
717 506
718 if (!tool->ordered_samples || !limit) 507 if (!ops->ordered_samples || !limit)
719 return 0; 508 return;
720 509
721 list_for_each_entry_safe(iter, tmp, head, list) { 510 list_for_each_entry_safe(iter, tmp, head, list) {
722 if (iter->timestamp > limit) 511 if (iter->timestamp > limit)
723 break; 512 break;
724 513
725 ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); 514 ret = perf_session__parse_sample(s, iter->event, &sample);
726 if (ret) 515 if (ret)
727 pr_err("Can't parse sample, err = %d\n", ret); 516 pr_err("Can't parse sample, err = %d\n", ret);
728 else { 517 else
729 ret = perf_session_deliver_event(s, iter->event, &sample, tool, 518 perf_session_deliver_event(s, iter->event, &sample, ops,
730 iter->file_offset); 519 iter->file_offset);
731 if (ret)
732 return ret;
733 }
734 520
735 os->last_flush = iter->timestamp; 521 os->last_flush = iter->timestamp;
736 list_del(&iter->list); 522 list_del(&iter->list);
737 list_add(&iter->list, &os->sample_cache); 523 list_add(&iter->list, &os->sample_cache);
738 if (++idx >= progress_next) {
739 progress_next += os->nr_samples / 16;
740 ui_progress__update(idx, os->nr_samples,
741 "Processing time ordered events...");
742 }
743 } 524 }
744 525
745 if (list_empty(head)) { 526 if (list_empty(head)) {
@@ -748,10 +529,6 @@ static int flush_sample_queue(struct perf_session *s,
748 os->last_sample = 529 os->last_sample =
749 list_entry(head->prev, struct sample_queue, list); 530 list_entry(head->prev, struct sample_queue, list);
750 } 531 }
751
752 os->nr_samples = 0;
753
754 return 0;
755} 532}
756 533
757/* 534/*
@@ -793,15 +570,14 @@ static int flush_sample_queue(struct perf_session *s,
793 * Flush every events below timestamp 7 570 * Flush every events below timestamp 7
794 * etc... 571 * etc...
795 */ 572 */
796static int process_finished_round(struct perf_tool *tool, 573static int process_finished_round(union perf_event *event __used,
797 union perf_event *event __maybe_unused, 574 struct perf_session *session,
798 struct perf_session *session) 575 struct perf_event_ops *ops)
799{ 576{
800 int ret = flush_sample_queue(session, tool); 577 flush_sample_queue(session, ops);
801 if (!ret) 578 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
802 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
803 579
804 return ret; 580 return 0;
805} 581}
806 582
807/* The queue is ordered by time */ 583/* The queue is ordered by time */
@@ -812,7 +588,6 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s)
812 u64 timestamp = new->timestamp; 588 u64 timestamp = new->timestamp;
813 struct list_head *p; 589 struct list_head *p;
814 590
815 ++os->nr_samples;
816 os->last_sample = new; 591 os->last_sample = new;
817 592
818 if (!sample) { 593 if (!sample) {
@@ -904,62 +679,20 @@ static void callchain__printf(struct perf_sample *sample)
904 i, sample->callchain->ips[i]); 679 i, sample->callchain->ips[i]);
905} 680}
906 681
907static void branch_stack__printf(struct perf_sample *sample)
908{
909 uint64_t i;
910
911 printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr);
912
913 for (i = 0; i < sample->branch_stack->nr; i++)
914 printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 "\n",
915 i, sample->branch_stack->entries[i].from,
916 sample->branch_stack->entries[i].to);
917}
918
919static void regs_dump__printf(u64 mask, u64 *regs)
920{
921 unsigned rid, i = 0;
922
923 for_each_set_bit(rid, (unsigned long *) &mask, sizeof(mask) * 8) {
924 u64 val = regs[i++];
925
926 printf(".... %-5s 0x%" PRIx64 "\n",
927 perf_reg_name(rid), val);
928 }
929}
930
931static void regs_user__printf(struct perf_sample *sample, u64 mask)
932{
933 struct regs_dump *user_regs = &sample->user_regs;
934
935 if (user_regs->regs) {
936 printf("... user regs: mask 0x%" PRIx64 "\n", mask);
937 regs_dump__printf(mask, user_regs->regs);
938 }
939}
940
941static void stack_user__printf(struct stack_dump *dump)
942{
943 printf("... ustack: size %" PRIu64 ", offset 0x%x\n",
944 dump->size, dump->offset);
945}
946
947static void perf_session__print_tstamp(struct perf_session *session, 682static void perf_session__print_tstamp(struct perf_session *session,
948 union perf_event *event, 683 union perf_event *event,
949 struct perf_sample *sample) 684 struct perf_sample *sample)
950{ 685{
951 u64 sample_type = perf_evlist__sample_type(session->evlist);
952
953 if (event->header.type != PERF_RECORD_SAMPLE && 686 if (event->header.type != PERF_RECORD_SAMPLE &&
954 !perf_evlist__sample_id_all(session->evlist)) { 687 !session->sample_id_all) {
955 fputs("-1 -1 ", stdout); 688 fputs("-1 -1 ", stdout);
956 return; 689 return;
957 } 690 }
958 691
959 if ((sample_type & PERF_SAMPLE_CPU)) 692 if ((session->sample_type & PERF_SAMPLE_CPU))
960 printf("%u ", sample->cpu); 693 printf("%u ", sample->cpu);
961 694
962 if (sample_type & PERF_SAMPLE_TIME) 695 if (session->sample_type & PERF_SAMPLE_TIME)
963 printf("%" PRIu64 " ", sample->time); 696 printf("%" PRIu64 " ", sample->time);
964} 697}
965 698
@@ -981,11 +714,9 @@ static void dump_event(struct perf_session *session, union perf_event *event,
981 event->header.size, perf_event__name(event->header.type)); 714 event->header.size, perf_event__name(event->header.type));
982} 715}
983 716
984static void dump_sample(struct perf_evsel *evsel, union perf_event *event, 717static void dump_sample(struct perf_session *session, union perf_event *event,
985 struct perf_sample *sample) 718 struct perf_sample *sample)
986{ 719{
987 u64 sample_type;
988
989 if (!dump_trace) 720 if (!dump_trace)
990 return; 721 return;
991 722
@@ -993,104 +724,45 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
993 event->header.misc, sample->pid, sample->tid, sample->ip, 724 event->header.misc, sample->pid, sample->tid, sample->ip,
994 sample->period, sample->addr); 725 sample->period, sample->addr);
995 726
996 sample_type = evsel->attr.sample_type; 727 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
997
998 if (sample_type & PERF_SAMPLE_CALLCHAIN)
999 callchain__printf(sample); 728 callchain__printf(sample);
1000
1001 if (sample_type & PERF_SAMPLE_BRANCH_STACK)
1002 branch_stack__printf(sample);
1003
1004 if (sample_type & PERF_SAMPLE_REGS_USER)
1005 regs_user__printf(sample, evsel->attr.sample_regs_user);
1006
1007 if (sample_type & PERF_SAMPLE_STACK_USER)
1008 stack_user__printf(&sample->user_stack);
1009}
1010
1011static struct machine *
1012 perf_session__find_machine_for_cpumode(struct perf_session *session,
1013 union perf_event *event)
1014{
1015 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1016
1017 if (perf_guest &&
1018 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
1019 (cpumode == PERF_RECORD_MISC_GUEST_USER))) {
1020 u32 pid;
1021
1022 if (event->header.type == PERF_RECORD_MMAP)
1023 pid = event->mmap.pid;
1024 else
1025 pid = event->ip.pid;
1026
1027 return perf_session__findnew_machine(session, pid);
1028 }
1029
1030 return perf_session__find_host_machine(session);
1031} 729}
1032 730
1033static int perf_session_deliver_event(struct perf_session *session, 731static int perf_session_deliver_event(struct perf_session *session,
1034 union perf_event *event, 732 union perf_event *event,
1035 struct perf_sample *sample, 733 struct perf_sample *sample,
1036 struct perf_tool *tool, 734 struct perf_event_ops *ops,
1037 u64 file_offset) 735 u64 file_offset)
1038{ 736{
1039 struct perf_evsel *evsel; 737 struct perf_evsel *evsel;
1040 struct machine *machine;
1041 738
1042 dump_event(session, event, file_offset, sample); 739 dump_event(session, event, file_offset, sample);
1043 740
1044 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
1045 if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) {
1046 /*
1047 * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here
1048 * because the tools right now may apply filters, discarding
1049 * some of the samples. For consistency, in the future we
1050 * should have something like nr_filtered_samples and remove
1051 * the sample->period from total_sample_period, etc, KISS for
1052 * now tho.
1053 *
1054 * Also testing against NULL allows us to handle files without
1055 * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the
1056 * future probably it'll be a good idea to restrict event
1057 * processing via perf_session to files with both set.
1058 */
1059 hists__inc_nr_events(&evsel->hists, event->header.type);
1060 }
1061
1062 machine = perf_session__find_machine_for_cpumode(session, event);
1063
1064 switch (event->header.type) { 741 switch (event->header.type) {
1065 case PERF_RECORD_SAMPLE: 742 case PERF_RECORD_SAMPLE:
1066 dump_sample(evsel, event, sample); 743 dump_sample(session, event, sample);
744 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
1067 if (evsel == NULL) { 745 if (evsel == NULL) {
1068 ++session->hists.stats.nr_unknown_id; 746 ++session->hists.stats.nr_unknown_id;
1069 return 0; 747 return -1;
1070 }
1071 if (machine == NULL) {
1072 ++session->hists.stats.nr_unprocessable_samples;
1073 return 0;
1074 } 748 }
1075 return tool->sample(tool, event, sample, evsel, machine); 749 return ops->sample(event, sample, evsel, session);
1076 case PERF_RECORD_MMAP: 750 case PERF_RECORD_MMAP:
1077 return tool->mmap(tool, event, sample, machine); 751 return ops->mmap(event, sample, session);
1078 case PERF_RECORD_COMM: 752 case PERF_RECORD_COMM:
1079 return tool->comm(tool, event, sample, machine); 753 return ops->comm(event, sample, session);
1080 case PERF_RECORD_FORK: 754 case PERF_RECORD_FORK:
1081 return tool->fork(tool, event, sample, machine); 755 return ops->fork(event, sample, session);
1082 case PERF_RECORD_EXIT: 756 case PERF_RECORD_EXIT:
1083 return tool->exit(tool, event, sample, machine); 757 return ops->exit(event, sample, session);
1084 case PERF_RECORD_LOST: 758 case PERF_RECORD_LOST:
1085 if (tool->lost == perf_event__process_lost) 759 return ops->lost(event, sample, session);
1086 session->hists.stats.total_lost += event->lost.lost;
1087 return tool->lost(tool, event, sample, machine);
1088 case PERF_RECORD_READ: 760 case PERF_RECORD_READ:
1089 return tool->read(tool, event, sample, evsel, machine); 761 return ops->read(event, sample, session);
1090 case PERF_RECORD_THROTTLE: 762 case PERF_RECORD_THROTTLE:
1091 return tool->throttle(tool, event, sample, machine); 763 return ops->throttle(event, sample, session);
1092 case PERF_RECORD_UNTHROTTLE: 764 case PERF_RECORD_UNTHROTTLE:
1093 return tool->unthrottle(tool, event, sample, machine); 765 return ops->unthrottle(event, sample, session);
1094 default: 766 default:
1095 ++session->hists.stats.nr_unknown_events; 767 ++session->hists.stats.nr_unknown_events;
1096 return -1; 768 return -1;
@@ -1101,7 +773,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
1101 union perf_event *event, struct perf_sample *sample) 773 union perf_event *event, struct perf_sample *sample)
1102{ 774{
1103 if (event->header.type != PERF_RECORD_SAMPLE || 775 if (event->header.type != PERF_RECORD_SAMPLE ||
1104 !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN)) 776 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
1105 return 0; 777 return 0;
1106 778
1107 if (!ip_callchain__valid(sample->callchain, event)) { 779 if (!ip_callchain__valid(sample->callchain, event)) {
@@ -1114,53 +786,40 @@ static int perf_session__preprocess_sample(struct perf_session *session,
1114} 786}
1115 787
1116static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 788static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
1117 struct perf_tool *tool, u64 file_offset) 789 struct perf_event_ops *ops, u64 file_offset)
1118{ 790{
1119 int err;
1120
1121 dump_event(session, event, file_offset, NULL); 791 dump_event(session, event, file_offset, NULL);
1122 792
1123 /* These events are processed right away */ 793 /* These events are processed right away */
1124 switch (event->header.type) { 794 switch (event->header.type) {
1125 case PERF_RECORD_HEADER_ATTR: 795 case PERF_RECORD_HEADER_ATTR:
1126 err = tool->attr(event, &session->evlist); 796 return ops->attr(event, session);
1127 if (err == 0)
1128 perf_session__set_id_hdr_size(session);
1129 return err;
1130 case PERF_RECORD_HEADER_EVENT_TYPE: 797 case PERF_RECORD_HEADER_EVENT_TYPE:
1131 return tool->event_type(tool, event); 798 return ops->event_type(event, session);
1132 case PERF_RECORD_HEADER_TRACING_DATA: 799 case PERF_RECORD_HEADER_TRACING_DATA:
1133 /* setup for reading amidst mmap */ 800 /* setup for reading amidst mmap */
1134 lseek(session->fd, file_offset, SEEK_SET); 801 lseek(session->fd, file_offset, SEEK_SET);
1135 return tool->tracing_data(event, session); 802 return ops->tracing_data(event, session);
1136 case PERF_RECORD_HEADER_BUILD_ID: 803 case PERF_RECORD_HEADER_BUILD_ID:
1137 return tool->build_id(tool, event, session); 804 return ops->build_id(event, session);
1138 case PERF_RECORD_FINISHED_ROUND: 805 case PERF_RECORD_FINISHED_ROUND:
1139 return tool->finished_round(tool, event, session); 806 return ops->finished_round(event, session, ops);
1140 default: 807 default:
1141 return -EINVAL; 808 return -EINVAL;
1142 } 809 }
1143} 810}
1144 811
1145static void event_swap(union perf_event *event, bool sample_id_all)
1146{
1147 perf_event__swap_op swap;
1148
1149 swap = perf_event__swap_ops[event->header.type];
1150 if (swap)
1151 swap(event, sample_id_all);
1152}
1153
1154static int perf_session__process_event(struct perf_session *session, 812static int perf_session__process_event(struct perf_session *session,
1155 union perf_event *event, 813 union perf_event *event,
1156 struct perf_tool *tool, 814 struct perf_event_ops *ops,
1157 u64 file_offset) 815 u64 file_offset)
1158{ 816{
1159 struct perf_sample sample; 817 struct perf_sample sample;
1160 int ret; 818 int ret;
1161 819
1162 if (session->header.needs_swap) 820 if (session->header.needs_swap &&
1163 event_swap(event, perf_evlist__sample_id_all(session->evlist)); 821 perf_event__swap_ops[event->header.type])
822 perf_event__swap_ops[event->header.type](event);
1164 823
1165 if (event->header.type >= PERF_RECORD_HEADER_MAX) 824 if (event->header.type >= PERF_RECORD_HEADER_MAX)
1166 return -EINVAL; 825 return -EINVAL;
@@ -1168,12 +827,12 @@ static int perf_session__process_event(struct perf_session *session,
1168 hists__inc_nr_events(&session->hists, event->header.type); 827 hists__inc_nr_events(&session->hists, event->header.type);
1169 828
1170 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 829 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
1171 return perf_session__process_user_event(session, event, tool, file_offset); 830 return perf_session__process_user_event(session, event, ops, file_offset);
1172 831
1173 /* 832 /*
1174 * For all kernel events we get the sample data 833 * For all kernel events we get the sample data
1175 */ 834 */
1176 ret = perf_evlist__parse_sample(session->evlist, event, &sample); 835 ret = perf_session__parse_sample(session, event, &sample);
1177 if (ret) 836 if (ret)
1178 return ret; 837 return ret;
1179 838
@@ -1181,14 +840,14 @@ static int perf_session__process_event(struct perf_session *session,
1181 if (perf_session__preprocess_sample(session, event, &sample)) 840 if (perf_session__preprocess_sample(session, event, &sample))
1182 return 0; 841 return 0;
1183 842
1184 if (tool->ordered_samples) { 843 if (ops->ordered_samples) {
1185 ret = perf_session_queue_event(session, event, &sample, 844 ret = perf_session_queue_event(session, event, &sample,
1186 file_offset); 845 file_offset);
1187 if (ret != -ETIME) 846 if (ret != -ETIME)
1188 return ret; 847 return ret;
1189 } 848 }
1190 849
1191 return perf_session_deliver_event(session, event, &sample, tool, 850 return perf_session_deliver_event(session, event, &sample, ops,
1192 file_offset); 851 file_offset);
1193} 852}
1194 853
@@ -1199,11 +858,6 @@ void perf_event_header__bswap(struct perf_event_header *self)
1199 self->size = bswap_16(self->size); 858 self->size = bswap_16(self->size);
1200} 859}
1201 860
1202struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1203{
1204 return machine__findnew_thread(&session->host_machine, pid);
1205}
1206
1207static struct thread *perf_session__register_idle_thread(struct perf_session *self) 861static struct thread *perf_session__register_idle_thread(struct perf_session *self)
1208{ 862{
1209 struct thread *thread = perf_session__findnew(self, 0); 863 struct thread *thread = perf_session__findnew(self, 0);
@@ -1217,14 +871,14 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
1217} 871}
1218 872
1219static void perf_session__warn_about_errors(const struct perf_session *session, 873static void perf_session__warn_about_errors(const struct perf_session *session,
1220 const struct perf_tool *tool) 874 const struct perf_event_ops *ops)
1221{ 875{
1222 if (tool->lost == perf_event__process_lost && 876 if (ops->lost == perf_event__process_lost &&
1223 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 877 session->hists.stats.total_lost != 0) {
1224 ui__warning("Processed %d events and lost %d chunks!\n\n" 878 ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
1225 "Check IO/CPU overload!\n\n", 879 "!\n\nCheck IO/CPU overload!\n\n",
1226 session->hists.stats.nr_events[0], 880 session->hists.stats.total_period,
1227 session->hists.stats.nr_events[PERF_RECORD_LOST]); 881 session->hists.stats.total_lost);
1228 } 882 }
1229 883
1230 if (session->hists.stats.nr_unknown_events != 0) { 884 if (session->hists.stats.nr_unknown_events != 0) {
@@ -1248,39 +902,26 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1248 session->hists.stats.nr_invalid_chains, 902 session->hists.stats.nr_invalid_chains,
1249 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 903 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
1250 } 904 }
1251
1252 if (session->hists.stats.nr_unprocessable_samples != 0) {
1253 ui__warning("%u unprocessable samples recorded.\n"
1254 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1255 session->hists.stats.nr_unprocessable_samples);
1256 }
1257} 905}
1258 906
1259#define session_done() (*(volatile int *)(&session_done)) 907#define session_done() (*(volatile int *)(&session_done))
1260volatile int session_done; 908volatile int session_done;
1261 909
1262static int __perf_session__process_pipe_events(struct perf_session *self, 910static int __perf_session__process_pipe_events(struct perf_session *self,
1263 struct perf_tool *tool) 911 struct perf_event_ops *ops)
1264{ 912{
1265 union perf_event *event; 913 union perf_event event;
1266 uint32_t size, cur_size = 0; 914 uint32_t size;
1267 void *buf = NULL;
1268 int skip = 0; 915 int skip = 0;
1269 u64 head; 916 u64 head;
1270 int err; 917 int err;
1271 void *p; 918 void *p;
1272 919
1273 perf_tool__fill_defaults(tool); 920 perf_event_ops__fill_defaults(ops);
1274 921
1275 head = 0; 922 head = 0;
1276 cur_size = sizeof(union perf_event);
1277
1278 buf = malloc(cur_size);
1279 if (!buf)
1280 return -errno;
1281more: 923more:
1282 event = buf; 924 err = readn(self->fd, &event, sizeof(struct perf_event_header));
1283 err = readn(self->fd, event, sizeof(struct perf_event_header));
1284 if (err <= 0) { 925 if (err <= 0) {
1285 if (err == 0) 926 if (err == 0)
1286 goto done; 927 goto done;
@@ -1290,23 +931,13 @@ more:
1290 } 931 }
1291 932
1292 if (self->header.needs_swap) 933 if (self->header.needs_swap)
1293 perf_event_header__bswap(&event->header); 934 perf_event_header__bswap(&event.header);
1294 935
1295 size = event->header.size; 936 size = event.header.size;
1296 if (size == 0) 937 if (size == 0)
1297 size = 8; 938 size = 8;
1298 939
1299 if (size > cur_size) { 940 p = &event;
1300 void *new = realloc(buf, size);
1301 if (!new) {
1302 pr_err("failed to allocate memory to read event\n");
1303 goto out_err;
1304 }
1305 buf = new;
1306 cur_size = size;
1307 event = buf;
1308 }
1309 p = event;
1310 p += sizeof(struct perf_event_header); 941 p += sizeof(struct perf_event_header);
1311 942
1312 if (size - sizeof(struct perf_event_header)) { 943 if (size - sizeof(struct perf_event_header)) {
@@ -1322,11 +953,18 @@ more:
1322 } 953 }
1323 } 954 }
1324 955
1325 if ((skip = perf_session__process_event(self, event, tool, head)) < 0) { 956 if (size == 0 ||
1326 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 957 (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
1327 head, event->header.size, event->header.type); 958 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
1328 err = -EINVAL; 959 head, event.header.size, event.header.type);
1329 goto out_err; 960 /*
961 * assume we lost track of the stream, check alignment, and
962 * increment a single u64 in the hope to catch on again 'soon'.
963 */
964 if (unlikely(head & 7))
965 head &= ~7ULL;
966
967 size = 8;
1330 } 968 }
1331 969
1332 head += size; 970 head += size;
@@ -1339,8 +977,7 @@ more:
1339done: 977done:
1340 err = 0; 978 err = 0;
1341out_err: 979out_err:
1342 free(buf); 980 perf_session__warn_about_errors(self, ops);
1343 perf_session__warn_about_errors(self, tool);
1344 perf_session_free_sample_buffers(self); 981 perf_session_free_sample_buffers(self);
1345 return err; 982 return err;
1346} 983}
@@ -1371,16 +1008,19 @@ fetch_mmaped_event(struct perf_session *session,
1371 1008
1372int __perf_session__process_events(struct perf_session *session, 1009int __perf_session__process_events(struct perf_session *session,
1373 u64 data_offset, u64 data_size, 1010 u64 data_offset, u64 data_size,
1374 u64 file_size, struct perf_tool *tool) 1011 u64 file_size, struct perf_event_ops *ops)
1375{ 1012{
1376 u64 head, page_offset, file_offset, file_pos, progress_next; 1013 u64 head, page_offset, file_offset, file_pos, progress_next;
1377 int err, mmap_prot, mmap_flags, map_idx = 0; 1014 int err, mmap_prot, mmap_flags, map_idx = 0;
1378 size_t mmap_size; 1015 struct ui_progress *progress;
1016 size_t page_size, mmap_size;
1379 char *buf, *mmaps[8]; 1017 char *buf, *mmaps[8];
1380 union perf_event *event; 1018 union perf_event *event;
1381 uint32_t size; 1019 uint32_t size;
1382 1020
1383 perf_tool__fill_defaults(tool); 1021 perf_event_ops__fill_defaults(ops);
1022
1023 page_size = sysconf(_SC_PAGESIZE);
1384 1024
1385 page_offset = page_size * (data_offset / page_size); 1025 page_offset = page_size * (data_offset / page_size);
1386 file_offset = page_offset; 1026 file_offset = page_offset;
@@ -1390,6 +1030,9 @@ int __perf_session__process_events(struct perf_session *session,
1390 file_size = data_offset + data_size; 1030 file_size = data_offset + data_size;
1391 1031
1392 progress_next = file_size / 16; 1032 progress_next = file_size / 16;
1033 progress = ui_progress__new("Processing events...", file_size);
1034 if (progress == NULL)
1035 return -1;
1393 1036
1394 mmap_size = session->mmap_window; 1037 mmap_size = session->mmap_window;
1395 if (mmap_size > file_size) 1038 if (mmap_size > file_size)
@@ -1433,12 +1076,18 @@ more:
1433 size = event->header.size; 1076 size = event->header.size;
1434 1077
1435 if (size == 0 || 1078 if (size == 0 ||
1436 perf_session__process_event(session, event, tool, file_pos) < 0) { 1079 perf_session__process_event(session, event, ops, file_pos) < 0) {
1437 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1080 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
1438 file_offset + head, event->header.size, 1081 file_offset + head, event->header.size,
1439 event->header.type); 1082 event->header.type);
1440 err = -EINVAL; 1083 /*
1441 goto out_err; 1084 * assume we lost track of the stream, check alignment, and
1085 * increment a single u64 in the hope to catch on again 'soon'.
1086 */
1087 if (unlikely(head & 7))
1088 head &= ~7ULL;
1089
1090 size = 8;
1442 } 1091 }
1443 1092
1444 head += size; 1093 head += size;
@@ -1446,8 +1095,7 @@ more:
1446 1095
1447 if (file_pos >= progress_next) { 1096 if (file_pos >= progress_next) {
1448 progress_next += file_size / 16; 1097 progress_next += file_size / 16;
1449 ui_progress__update(file_pos, file_size, 1098 ui_progress__update(progress, file_pos);
1450 "Processing events...");
1451 } 1099 }
1452 1100
1453 if (file_pos < file_size) 1101 if (file_pos < file_size)
@@ -1456,16 +1104,16 @@ more:
1456 err = 0; 1104 err = 0;
1457 /* do the final flush for ordered samples */ 1105 /* do the final flush for ordered samples */
1458 session->ordered_samples.next_flush = ULLONG_MAX; 1106 session->ordered_samples.next_flush = ULLONG_MAX;
1459 err = flush_sample_queue(session, tool); 1107 flush_sample_queue(session, ops);
1460out_err: 1108out_err:
1461 ui_progress__finish(); 1109 ui_progress__delete(progress);
1462 perf_session__warn_about_errors(session, tool); 1110 perf_session__warn_about_errors(session, ops);
1463 perf_session_free_sample_buffers(session); 1111 perf_session_free_sample_buffers(session);
1464 return err; 1112 return err;
1465} 1113}
1466 1114
1467int perf_session__process_events(struct perf_session *self, 1115int perf_session__process_events(struct perf_session *self,
1468 struct perf_tool *tool) 1116 struct perf_event_ops *ops)
1469{ 1117{
1470 int err; 1118 int err;
1471 1119
@@ -1476,16 +1124,16 @@ int perf_session__process_events(struct perf_session *self,
1476 err = __perf_session__process_events(self, 1124 err = __perf_session__process_events(self,
1477 self->header.data_offset, 1125 self->header.data_offset,
1478 self->header.data_size, 1126 self->header.data_size,
1479 self->size, tool); 1127 self->size, ops);
1480 else 1128 else
1481 err = __perf_session__process_pipe_events(self, tool); 1129 err = __perf_session__process_pipe_events(self, ops);
1482 1130
1483 return err; 1131 return err;
1484} 1132}
1485 1133
1486bool perf_session__has_traces(struct perf_session *session, const char *msg) 1134bool perf_session__has_traces(struct perf_session *self, const char *msg)
1487{ 1135{
1488 if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) { 1136 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
1489 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); 1137 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
1490 return false; 1138 return false;
1491 } 1139 }
@@ -1493,8 +1141,9 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg)
1493 return true; 1141 return true;
1494} 1142}
1495 1143
1496int maps__set_kallsyms_ref_reloc_sym(struct map **maps, 1144int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
1497 const char *symbol_name, u64 addr) 1145 const char *symbol_name,
1146 u64 addr)
1498{ 1147{
1499 char *bracket; 1148 char *bracket;
1500 enum map_type i; 1149 enum map_type i;
@@ -1546,34 +1195,13 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1546 ret += hists__fprintf_nr_events(&session->hists, fp); 1195 ret += hists__fprintf_nr_events(&session->hists, fp);
1547 1196
1548 list_for_each_entry(pos, &session->evlist->entries, node) { 1197 list_for_each_entry(pos, &session->evlist->entries, node) {
1549 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1198 ret += fprintf(fp, "%s stats:\n", event_name(pos));
1550 ret += hists__fprintf_nr_events(&pos->hists, fp); 1199 ret += hists__fprintf_nr_events(&pos->hists, fp);
1551 } 1200 }
1552 1201
1553 return ret; 1202 return ret;
1554} 1203}
1555 1204
1556size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1557{
1558 /*
1559 * FIXME: Here we have to actually print all the machines in this
1560 * session, not just the host...
1561 */
1562 return machine__fprintf(&session->host_machine, fp);
1563}
1564
1565void perf_session__remove_thread(struct perf_session *session,
1566 struct thread *th)
1567{
1568 /*
1569 * FIXME: This one makes no sense, we need to remove the thread from
1570 * the machine it belongs to, perf_session can have many machines, so
1571 * doing it always on ->host_machine is wrong. Fix when auditing all
1572 * the 'perf kvm' code.
1573 */
1574 machine__remove_thread(&session->host_machine, th);
1575}
1576
1577struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1205struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1578 unsigned int type) 1206 unsigned int type)
1579{ 1207{
@@ -1586,14 +1214,17 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1586 return NULL; 1214 return NULL;
1587} 1215}
1588 1216
1589void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 1217void perf_session__print_ip(union perf_event *event,
1590 struct perf_sample *sample, struct machine *machine, 1218 struct perf_sample *sample,
1591 int print_sym, int print_dso, int print_symoffset) 1219 struct perf_session *session,
1220 int print_sym, int print_dso)
1592{ 1221{
1593 struct addr_location al; 1222 struct addr_location al;
1223 const char *symname, *dsoname;
1224 struct callchain_cursor *cursor = &session->callchain_cursor;
1594 struct callchain_cursor_node *node; 1225 struct callchain_cursor_node *node;
1595 1226
1596 if (perf_event__preprocess_sample(event, machine, &al, sample, 1227 if (perf_event__preprocess_sample(event, session, &al, sample,
1597 NULL) < 0) { 1228 NULL) < 0) {
1598 error("problem processing %d event, skipping it.\n", 1229 error("problem processing %d event, skipping it.\n",
1599 event->header.type); 1230 event->header.type);
@@ -1602,50 +1233,59 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1602 1233
1603 if (symbol_conf.use_callchain && sample->callchain) { 1234 if (symbol_conf.use_callchain && sample->callchain) {
1604 1235
1605 1236 if (perf_session__resolve_callchain(session, al.thread,
1606 if (machine__resolve_callchain(machine, evsel, al.thread, 1237 sample->callchain, NULL) != 0) {
1607 sample, NULL) != 0) {
1608 if (verbose) 1238 if (verbose)
1609 error("Failed to resolve callchain. Skipping\n"); 1239 error("Failed to resolve callchain. Skipping\n");
1610 return; 1240 return;
1611 } 1241 }
1612 callchain_cursor_commit(&callchain_cursor); 1242 callchain_cursor_commit(cursor);
1613 1243
1614 while (1) { 1244 while (1) {
1615 node = callchain_cursor_current(&callchain_cursor); 1245 node = callchain_cursor_current(cursor);
1616 if (!node) 1246 if (!node)
1617 break; 1247 break;
1618 1248
1619 printf("\t%16" PRIx64, node->ip); 1249 printf("\t%16" PRIx64, node->ip);
1620 if (print_sym) { 1250 if (print_sym) {
1621 printf(" "); 1251 if (node->sym && node->sym->name)
1622 symbol__fprintf_symname(node->sym, stdout); 1252 symname = node->sym->name;
1253 else
1254 symname = "";
1255
1256 printf(" %s", symname);
1623 } 1257 }
1624 if (print_dso) { 1258 if (print_dso) {
1625 printf(" ("); 1259 if (node->map && node->map->dso && node->map->dso->name)
1626 map__fprintf_dsoname(node->map, stdout); 1260 dsoname = node->map->dso->name;
1627 printf(")"); 1261 else
1262 dsoname = "";
1263
1264 printf(" (%s)", dsoname);
1628 } 1265 }
1629 printf("\n"); 1266 printf("\n");
1630 1267
1631 callchain_cursor_advance(&callchain_cursor); 1268 callchain_cursor_advance(cursor);
1632 } 1269 }
1633 1270
1634 } else { 1271 } else {
1635 printf("%16" PRIx64, sample->ip); 1272 printf("%16" PRIx64, sample->ip);
1636 if (print_sym) { 1273 if (print_sym) {
1637 printf(" "); 1274 if (al.sym && al.sym->name)
1638 if (print_symoffset) 1275 symname = al.sym->name;
1639 symbol__fprintf_symname_offs(al.sym, &al,
1640 stdout);
1641 else 1276 else
1642 symbol__fprintf_symname(al.sym, stdout); 1277 symname = "";
1278
1279 printf(" %s", symname);
1643 } 1280 }
1644 1281
1645 if (print_dso) { 1282 if (print_dso) {
1646 printf(" ("); 1283 if (al.map && al.map->dso && al.map->dso->name)
1647 map__fprintf_dsoname(al.map, stdout); 1284 dsoname = al.map->dso->name;
1648 printf(")"); 1285 else
1286 dsoname = "";
1287
1288 printf(" (%s)", dsoname);
1649 } 1289 }
1650 } 1290 }
1651} 1291}
@@ -1671,10 +1311,6 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1671 } 1311 }
1672 1312
1673 map = cpu_map__new(cpu_list); 1313 map = cpu_map__new(cpu_list);
1674 if (map == NULL) {
1675 pr_err("Invalid cpu_list\n");
1676 return -1;
1677 }
1678 1314
1679 for (i = 0; i < map->nr; i++) { 1315 for (i = 0; i < map->nr; i++) {
1680 int cpu = map->map[i]; 1316 int cpu = map->map[i];
@@ -1690,77 +1326,3 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1690 1326
1691 return 0; 1327 return 0;
1692} 1328}
1693
1694void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1695 bool full)
1696{
1697 struct stat st;
1698 int ret;
1699
1700 if (session == NULL || fp == NULL)
1701 return;
1702
1703 ret = fstat(session->fd, &st);
1704 if (ret == -1)
1705 return;
1706
1707 fprintf(fp, "# ========\n");
1708 fprintf(fp, "# captured on: %s", ctime(&st.st_ctime));
1709 perf_header__fprintf_info(session, fp, full);
1710 fprintf(fp, "# ========\n#\n");
1711}
1712
1713
1714int __perf_session__set_tracepoints_handlers(struct perf_session *session,
1715 const struct perf_evsel_str_handler *assocs,
1716 size_t nr_assocs)
1717{
1718 struct perf_evlist *evlist = session->evlist;
1719 struct event_format *format;
1720 struct perf_evsel *evsel;
1721 char *tracepoint, *name;
1722 size_t i;
1723 int err;
1724
1725 for (i = 0; i < nr_assocs; i++) {
1726 err = -ENOMEM;
1727 tracepoint = strdup(assocs[i].name);
1728 if (tracepoint == NULL)
1729 goto out;
1730
1731 err = -ENOENT;
1732 name = strchr(tracepoint, ':');
1733 if (name == NULL)
1734 goto out_free;
1735
1736 *name++ = '\0';
1737 format = pevent_find_event_by_name(session->pevent,
1738 tracepoint, name);
1739 if (format == NULL) {
1740 /*
1741 * Adding a handler for an event not in the session,
1742 * just ignore it.
1743 */
1744 goto next;
1745 }
1746
1747 evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id);
1748 if (evsel == NULL)
1749 goto next;
1750
1751 err = -EEXIST;
1752 if (evsel->handler.func != NULL)
1753 goto out_free;
1754 evsel->handler.func = assocs[i].handler;
1755next:
1756 free(tracepoint);
1757 }
1758
1759 err = 0;
1760out:
1761 return err;
1762
1763out_free:
1764 free(tracepoint);
1765 goto out;
1766}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index cea133a6bdf..974d0cbee5e 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -4,11 +4,10 @@
4#include "hist.h" 4#include "hist.h"
5#include "event.h" 5#include "event.h"
6#include "header.h" 6#include "header.h"
7#include "machine.h"
8#include "symbol.h" 7#include "symbol.h"
9#include "thread.h" 8#include "thread.h"
10#include <linux/rbtree.h> 9#include <linux/rbtree.h>
11#include <linux/perf_event.h> 10#include "../../../include/linux/perf_event.h"
12 11
13struct sample_queue; 12struct sample_queue;
14struct ip_callchain; 13struct ip_callchain;
@@ -24,60 +23,100 @@ struct ordered_samples {
24 struct sample_queue *sample_buffer; 23 struct sample_queue *sample_buffer;
25 struct sample_queue *last_sample; 24 struct sample_queue *last_sample;
26 int sample_buffer_idx; 25 int sample_buffer_idx;
27 unsigned int nr_samples;
28}; 26};
29 27
30struct perf_session { 28struct perf_session {
31 struct perf_header header; 29 struct perf_header header;
32 unsigned long size; 30 unsigned long size;
33 unsigned long mmap_window; 31 unsigned long mmap_window;
32 struct rb_root threads;
33 struct list_head dead_threads;
34 struct thread *last_match;
34 struct machine host_machine; 35 struct machine host_machine;
35 struct rb_root machines; 36 struct rb_root machines;
36 struct perf_evlist *evlist; 37 struct perf_evlist *evlist;
37 struct pevent *pevent;
38 /* 38 /*
39 * FIXME: Need to split this up further, we need global 39 * FIXME: Need to split this up further, we need global
40 * stats + per event stats. 40 * stats + per event stats. 'perf diff' also needs
41 * to properly support multiple events in a single
42 * perf.data file.
41 */ 43 */
42 struct hists hists; 44 struct hists hists;
45 u64 sample_type;
46 int sample_size;
43 int fd; 47 int fd;
44 bool fd_pipe; 48 bool fd_pipe;
45 bool repipe; 49 bool repipe;
50 bool sample_id_all;
51 u16 id_hdr_size;
46 int cwdlen; 52 int cwdlen;
47 char *cwd; 53 char *cwd;
48 struct ordered_samples ordered_samples; 54 struct ordered_samples ordered_samples;
49 char filename[1]; 55 struct callchain_cursor callchain_cursor;
56 char filename[0];
50}; 57};
51 58
52struct perf_tool; 59struct perf_evsel;
60struct perf_event_ops;
61
62typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
63 struct perf_evsel *evsel, struct perf_session *session);
64typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
65 struct perf_session *session);
66typedef int (*event_synth_op)(union perf_event *self,
67 struct perf_session *session);
68typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
69 struct perf_event_ops *ops);
70
71struct perf_event_ops {
72 event_sample sample;
73 event_op mmap,
74 comm,
75 fork,
76 exit,
77 lost,
78 read,
79 throttle,
80 unthrottle;
81 event_synth_op attr,
82 event_type,
83 tracing_data,
84 build_id;
85 event_op2 finished_round;
86 bool ordered_samples;
87 bool ordering_requires_timestamps;
88};
53 89
54struct perf_session *perf_session__new(const char *filename, int mode, 90struct perf_session *perf_session__new(const char *filename, int mode,
55 bool force, bool repipe, 91 bool force, bool repipe,
56 struct perf_tool *tool); 92 struct perf_event_ops *ops);
57void perf_session__delete(struct perf_session *self); 93void perf_session__delete(struct perf_session *self);
58 94
59void perf_event_header__bswap(struct perf_event_header *self); 95void perf_event_header__bswap(struct perf_event_header *self);
60 96
61int __perf_session__process_events(struct perf_session *self, 97int __perf_session__process_events(struct perf_session *self,
62 u64 data_offset, u64 data_size, u64 size, 98 u64 data_offset, u64 data_size, u64 size,
63 struct perf_tool *tool); 99 struct perf_event_ops *ops);
64int perf_session__process_events(struct perf_session *self, 100int perf_session__process_events(struct perf_session *self,
65 struct perf_tool *tool); 101 struct perf_event_ops *event_ops);
66 102
67int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, 103int perf_session__resolve_callchain(struct perf_session *self,
68 struct thread *thread, 104 struct thread *thread,
69 struct ip_callchain *chain, 105 struct ip_callchain *chain,
70 struct symbol **parent); 106 struct symbol **parent);
71 107
72bool perf_session__has_traces(struct perf_session *self, const char *msg); 108bool perf_session__has_traces(struct perf_session *self, const char *msg);
73 109
110int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
111 const char *symbol_name,
112 u64 addr);
113
74void mem_bswap_64(void *src, int byte_size); 114void mem_bswap_64(void *src, int byte_size);
75void mem_bswap_32(void *src, int byte_size);
76void perf_event__attr_swap(struct perf_event_attr *attr); 115void perf_event__attr_swap(struct perf_event_attr *attr);
77 116
78int perf_session__create_kernel_maps(struct perf_session *self); 117int perf_session__create_kernel_maps(struct perf_session *self);
79 118
80void perf_session__set_id_hdr_size(struct perf_session *session); 119void perf_session__update_sample_type(struct perf_session *self);
81void perf_session__remove_thread(struct perf_session *self, struct thread *th); 120void perf_session__remove_thread(struct perf_session *self, struct thread *th);
82 121
83static inline 122static inline
@@ -104,16 +143,12 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p
104 143
105static inline 144static inline
106void perf_session__process_machines(struct perf_session *self, 145void perf_session__process_machines(struct perf_session *self,
107 struct perf_tool *tool,
108 machine__process_t process) 146 machine__process_t process)
109{ 147{
110 process(&self->host_machine, tool); 148 process(&self->host_machine, self);
111 return machines__process(&self->machines, process, tool); 149 return machines__process(&self->machines, process, self);
112} 150}
113 151
114struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
115size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
116
117size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 152size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
118 153
119size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 154size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
@@ -121,24 +156,25 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
121 156
122size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); 157size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
123 158
159static inline int perf_session__parse_sample(struct perf_session *session,
160 const union perf_event *event,
161 struct perf_sample *sample)
162{
163 return perf_event__parse_sample(event, session->sample_type,
164 session->sample_size,
165 session->sample_id_all, sample,
166 session->header.needs_swap);
167}
168
124struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 169struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
125 unsigned int type); 170 unsigned int type);
126 171
127void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 172void perf_session__print_ip(union perf_event *event,
128 struct perf_sample *sample, struct machine *machine, 173 struct perf_sample *sample,
129 int print_sym, int print_dso, int print_symoffset); 174 struct perf_session *session,
175 int print_sym, int print_dso);
130 176
131int perf_session__cpu_bitmap(struct perf_session *session, 177int perf_session__cpu_bitmap(struct perf_session *session,
132 const char *cpu_list, unsigned long *cpu_bitmap); 178 const char *cpu_list, unsigned long *cpu_bitmap);
133 179
134void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
135
136struct perf_evsel_str_handler;
137
138int __perf_session__set_tracepoints_handlers(struct perf_session *session,
139 const struct perf_evsel_str_handler *assocs,
140 size_t nr_assocs);
141
142#define perf_session__set_tracepoints_handlers(session, array) \
143 __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array))
144#endif /* __PERF_SESSION_H */ 180#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 73d51026978..95d37007492 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -23,16 +23,13 @@ cflags += getenv('CFLAGS', '').split()
23 23
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26libtraceevent = getenv('LIBTRACEEVENT')
27
28ext_sources = [f.strip() for f in file('util/python-ext-sources')
29 if len(f.strip()) > 0 and f[0] != '#']
30 26
31perf = Extension('perf', 27perf = Extension('perf',
32 sources = ext_sources, 28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'],
33 include_dirs = ['util/include'], 31 include_dirs = ['util/include'],
34 extra_compile_args = cflags, 32 extra_compile_args = cflags,
35 extra_objects = [libtraceevent],
36 ) 33 )
37 34
38setup(name='perf', 35setup(name='perf',
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cfd1c0feb32..1ee8f1e40f1 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -8,11 +8,11 @@ const char default_sort_order[] = "comm,dso,symbol";
8const char *sort_order = default_sort_order; 8const char *sort_order = default_sort_order;
9int sort__need_collapse = 0; 9int sort__need_collapse = 0;
10int sort__has_parent = 0; 10int sort__has_parent = 0;
11int sort__has_sym = 0;
12int sort__branch_mode = -1; /* -1 = means not set */
13 11
14enum sort_type sort__first_dimension; 12enum sort_type sort__first_dimension;
15 13
14char * field_sep;
15
16LIST_HEAD(hist_entry__sort_list); 16LIST_HEAD(hist_entry__sort_list);
17 17
18static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 18static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
@@ -22,20 +22,17 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
22 22
23 va_start(ap, fmt); 23 va_start(ap, fmt);
24 n = vsnprintf(bf, size, fmt, ap); 24 n = vsnprintf(bf, size, fmt, ap);
25 if (symbol_conf.field_sep && n > 0) { 25 if (field_sep && n > 0) {
26 char *sep = bf; 26 char *sep = bf;
27 27
28 while (1) { 28 while (1) {
29 sep = strchr(sep, *symbol_conf.field_sep); 29 sep = strchr(sep, *field_sep);
30 if (sep == NULL) 30 if (sep == NULL)
31 break; 31 break;
32 *sep = '.'; 32 *sep = '.';
33 } 33 }
34 } 34 }
35 va_end(ap); 35 va_end(ap);
36
37 if (n >= (int)size)
38 return size - 1;
39 return n; 36 return n;
40} 37}
41 38
@@ -97,26 +94,6 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 94 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
98} 95}
99 96
100static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
101{
102 struct dso *dso_l = map_l ? map_l->dso : NULL;
103 struct dso *dso_r = map_r ? map_r->dso : NULL;
104 const char *dso_name_l, *dso_name_r;
105
106 if (!dso_l || !dso_r)
107 return cmp_null(dso_l, dso_r);
108
109 if (verbose) {
110 dso_name_l = dso_l->long_name;
111 dso_name_r = dso_r->long_name;
112 } else {
113 dso_name_l = dso_l->short_name;
114 dso_name_r = dso_r->short_name;
115 }
116
117 return strcmp(dso_name_l, dso_name_r);
118}
119
120struct sort_entry sort_comm = { 97struct sort_entry sort_comm = {
121 .se_header = "Command", 98 .se_header = "Command",
122 .se_cmp = sort__comm_cmp, 99 .se_cmp = sort__comm_cmp,
@@ -130,74 +107,36 @@ struct sort_entry sort_comm = {
130static int64_t 107static int64_t
131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 108sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
132{ 109{
133 return _sort__dso_cmp(left->ms.map, right->ms.map); 110 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
134} 111 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
135 112 const char *dso_name_l, *dso_name_r;
136
137static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
138 u64 ip_l, u64 ip_r)
139{
140 if (!sym_l || !sym_r)
141 return cmp_null(sym_l, sym_r);
142
143 if (sym_l == sym_r)
144 return 0;
145
146 if (sym_l)
147 ip_l = sym_l->start;
148 if (sym_r)
149 ip_r = sym_r->start;
150 113
151 return (int64_t)(ip_r - ip_l); 114 if (!dso_l || !dso_r)
152} 115 return cmp_null(dso_l, dso_r);
153 116
154static int _hist_entry__dso_snprintf(struct map *map, char *bf, 117 if (verbose) {
155 size_t size, unsigned int width) 118 dso_name_l = dso_l->long_name;
156{ 119 dso_name_r = dso_r->long_name;
157 if (map && map->dso) { 120 } else {
158 const char *dso_name = !verbose ? map->dso->short_name : 121 dso_name_l = dso_l->short_name;
159 map->dso->long_name; 122 dso_name_r = dso_r->short_name;
160 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
161 } 123 }
162 124
163 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 125 return strcmp(dso_name_l, dso_name_r);
164} 126}
165 127
166static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, 128static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
167 size_t size, unsigned int width) 129 size_t size, unsigned int width)
168{ 130{
169 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 131 if (self->ms.map && self->ms.map->dso) {
170} 132 const char *dso_name = !verbose ? self->ms.map->dso->short_name :
171 133 self->ms.map->dso->long_name;
172static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 134 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
173 u64 ip, char level, char *bf, size_t size,
174 unsigned int width __maybe_unused)
175{
176 size_t ret = 0;
177
178 if (verbose) {
179 char o = map ? dso__symtab_origin(map->dso) : '!';
180 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
181 BITS_PER_LONG / 4, ip, o);
182 }
183
184 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
185 if (sym)
186 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
187 width - ret,
188 sym->name);
189 else {
190 size_t len = BITS_PER_LONG / 4;
191 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
192 len, ip);
193 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
194 width - ret, "");
195 } 135 }
196 136
197 return ret; 137 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
198} 138}
199 139
200
201struct sort_entry sort_dso = { 140struct sort_entry sort_dso = {
202 .se_header = "Shared Object", 141 .se_header = "Shared Object",
203 .se_cmp = sort__dso_cmp, 142 .se_cmp = sort__dso_cmp,
@@ -205,15 +144,8 @@ struct sort_entry sort_dso = {
205 .se_width_idx = HISTC_DSO, 144 .se_width_idx = HISTC_DSO,
206}; 145};
207 146
208static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
209 size_t size,
210 unsigned int width __maybe_unused)
211{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width);
214}
215
216/* --sort symbol */ 147/* --sort symbol */
148
217static int64_t 149static int64_t
218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 150sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
219{ 151{
@@ -231,69 +163,36 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
231 ip_l = left->ms.sym->start; 163 ip_l = left->ms.sym->start;
232 ip_r = right->ms.sym->start; 164 ip_r = right->ms.sym->start;
233 165
234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); 166 return (int64_t)(ip_r - ip_l);
235} 167}
236 168
237struct sort_entry sort_sym = { 169static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
238 .se_header = "Symbol", 170 size_t size, unsigned int width __used)
239 .se_cmp = sort__sym_cmp, 171{
240 .se_snprintf = hist_entry__sym_snprintf, 172 size_t ret = 0;
241 .se_width_idx = HISTC_SYMBOL,
242};
243 173
244/* --sort srcline */ 174 if (verbose) {
175 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
176 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
177 BITS_PER_LONG / 4, self->ip, o);
178 }
245 179
246static int64_t 180 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
247sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 181 if (self->ms.sym)
248{ 182 ret += repsep_snprintf(bf + ret, size - ret, "%s",
249 return (int64_t)(right->ip - left->ip); 183 self->ms.sym->name);
250} 184 else
185 ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
186 BITS_PER_LONG / 4, self->ip);
251 187
252static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, 188 return ret;
253 size_t size,
254 unsigned int width __maybe_unused)
255{
256 FILE *fp;
257 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
258 size_t line_len;
259
260 if (path != NULL)
261 goto out_path;
262
263 if (!self->ms.map)
264 goto out_ip;
265
266 if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
267 goto out_ip;
268
269 snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
270 self->ms.map->dso->long_name, self->ip);
271 fp = popen(cmd, "r");
272 if (!fp)
273 goto out_ip;
274
275 if (getline(&path, &line_len, fp) < 0 || !line_len)
276 goto out_ip;
277 fclose(fp);
278 self->srcline = strdup(path);
279 if (self->srcline == NULL)
280 goto out_ip;
281
282 nl = strchr(self->srcline, '\n');
283 if (nl != NULL)
284 *nl = '\0';
285 path = self->srcline;
286out_path:
287 return repsep_snprintf(bf, size, "%s", path);
288out_ip:
289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290} 189}
291 190
292struct sort_entry sort_srcline = { 191struct sort_entry sort_sym = {
293 .se_header = "Source:Line", 192 .se_header = "Symbol",
294 .se_cmp = sort__srcline_cmp, 193 .se_cmp = sort__sym_cmp,
295 .se_snprintf = hist_entry__srcline_snprintf, 194 .se_snprintf = hist_entry__sym_snprintf,
296 .se_width_idx = HISTC_SRCLINE, 195 .se_width_idx = HISTC_SYMBOL,
297}; 196};
298 197
299/* --sort parent */ 198/* --sort parent */
@@ -345,158 +244,19 @@ struct sort_entry sort_cpu = {
345 .se_width_idx = HISTC_CPU, 244 .se_width_idx = HISTC_CPU,
346}; 245};
347 246
348static int64_t
349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
350{
351 return _sort__dso_cmp(left->branch_info->from.map,
352 right->branch_info->from.map);
353}
354
355static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
356 size_t size, unsigned int width)
357{
358 return _hist_entry__dso_snprintf(self->branch_info->from.map,
359 bf, size, width);
360}
361
362struct sort_entry sort_dso_from = {
363 .se_header = "Source Shared Object",
364 .se_cmp = sort__dso_from_cmp,
365 .se_snprintf = hist_entry__dso_from_snprintf,
366 .se_width_idx = HISTC_DSO_FROM,
367};
368
369static int64_t
370sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
371{
372 return _sort__dso_cmp(left->branch_info->to.map,
373 right->branch_info->to.map);
374}
375
376static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
377 size_t size, unsigned int width)
378{
379 return _hist_entry__dso_snprintf(self->branch_info->to.map,
380 bf, size, width);
381}
382
383static int64_t
384sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
385{
386 struct addr_map_symbol *from_l = &left->branch_info->from;
387 struct addr_map_symbol *from_r = &right->branch_info->from;
388
389 if (!from_l->sym && !from_r->sym)
390 return right->level - left->level;
391
392 return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr,
393 from_r->addr);
394}
395
396static int64_t
397sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
398{
399 struct addr_map_symbol *to_l = &left->branch_info->to;
400 struct addr_map_symbol *to_r = &right->branch_info->to;
401
402 if (!to_l->sym && !to_r->sym)
403 return right->level - left->level;
404
405 return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr);
406}
407
408static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
409 size_t size,
410 unsigned int width __maybe_unused)
411{
412 struct addr_map_symbol *from = &self->branch_info->from;
413 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
414 self->level, bf, size, width);
415
416}
417
418static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
419 size_t size,
420 unsigned int width __maybe_unused)
421{
422 struct addr_map_symbol *to = &self->branch_info->to;
423 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
424 self->level, bf, size, width);
425
426}
427
428struct sort_entry sort_dso_to = {
429 .se_header = "Target Shared Object",
430 .se_cmp = sort__dso_to_cmp,
431 .se_snprintf = hist_entry__dso_to_snprintf,
432 .se_width_idx = HISTC_DSO_TO,
433};
434
435struct sort_entry sort_sym_from = {
436 .se_header = "Source Symbol",
437 .se_cmp = sort__sym_from_cmp,
438 .se_snprintf = hist_entry__sym_from_snprintf,
439 .se_width_idx = HISTC_SYMBOL_FROM,
440};
441
442struct sort_entry sort_sym_to = {
443 .se_header = "Target Symbol",
444 .se_cmp = sort__sym_to_cmp,
445 .se_snprintf = hist_entry__sym_to_snprintf,
446 .se_width_idx = HISTC_SYMBOL_TO,
447};
448
449static int64_t
450sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
451{
452 const unsigned char mp = left->branch_info->flags.mispred !=
453 right->branch_info->flags.mispred;
454 const unsigned char p = left->branch_info->flags.predicted !=
455 right->branch_info->flags.predicted;
456
457 return mp || p;
458}
459
460static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
461 size_t size, unsigned int width){
462 static const char *out = "N/A";
463
464 if (self->branch_info->flags.predicted)
465 out = "N";
466 else if (self->branch_info->flags.mispred)
467 out = "Y";
468
469 return repsep_snprintf(bf, size, "%-*s", width, out);
470}
471
472struct sort_entry sort_mispredict = {
473 .se_header = "Branch Mispredicted",
474 .se_cmp = sort__mispredict_cmp,
475 .se_snprintf = hist_entry__mispredict_snprintf,
476 .se_width_idx = HISTC_MISPREDICT,
477};
478
479struct sort_dimension { 247struct sort_dimension {
480 const char *name; 248 const char *name;
481 struct sort_entry *entry; 249 struct sort_entry *entry;
482 int taken; 250 int taken;
483}; 251};
484 252
485#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
486
487static struct sort_dimension sort_dimensions[] = { 253static struct sort_dimension sort_dimensions[] = {
488 DIM(SORT_PID, "pid", sort_thread), 254 { .name = "pid", .entry = &sort_thread, },
489 DIM(SORT_COMM, "comm", sort_comm), 255 { .name = "comm", .entry = &sort_comm, },
490 DIM(SORT_DSO, "dso", sort_dso), 256 { .name = "dso", .entry = &sort_dso, },
491 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), 257 { .name = "symbol", .entry = &sort_sym, },
492 DIM(SORT_DSO_TO, "dso_to", sort_dso_to), 258 { .name = "parent", .entry = &sort_parent, },
493 DIM(SORT_SYM, "symbol", sort_sym), 259 { .name = "cpu", .entry = &sort_cpu, },
494 DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
495 DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
496 DIM(SORT_PARENT, "parent", sort_parent),
497 DIM(SORT_CPU, "cpu", sort_cpu),
498 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
499 DIM(SORT_SRCLINE, "srcline", sort_srcline),
500}; 260};
501 261
502int sort_dimension__add(const char *tok) 262int sort_dimension__add(const char *tok)
@@ -508,6 +268,7 @@ int sort_dimension__add(const char *tok)
508 268
509 if (strncasecmp(tok, sd->name, strlen(tok))) 269 if (strncasecmp(tok, sd->name, strlen(tok)))
510 continue; 270 continue;
271
511 if (sd->entry == &sort_parent) { 272 if (sd->entry == &sort_parent) {
512 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 273 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
513 if (ret) { 274 if (ret) {
@@ -518,10 +279,6 @@ int sort_dimension__add(const char *tok)
518 return -EINVAL; 279 return -EINVAL;
519 } 280 }
520 sort__has_parent = 1; 281 sort__has_parent = 1;
521 } else if (sd->entry == &sort_sym ||
522 sd->entry == &sort_sym_from ||
523 sd->entry == &sort_sym_to) {
524 sort__has_sym = 1;
525 } 282 }
526 283
527 if (sd->taken) 284 if (sd->taken)
@@ -543,16 +300,6 @@ int sort_dimension__add(const char *tok)
543 sort__first_dimension = SORT_PARENT; 300 sort__first_dimension = SORT_PARENT;
544 else if (!strcmp(sd->name, "cpu")) 301 else if (!strcmp(sd->name, "cpu"))
545 sort__first_dimension = SORT_CPU; 302 sort__first_dimension = SORT_CPU;
546 else if (!strcmp(sd->name, "symbol_from"))
547 sort__first_dimension = SORT_SYM_FROM;
548 else if (!strcmp(sd->name, "symbol_to"))
549 sort__first_dimension = SORT_SYM_TO;
550 else if (!strcmp(sd->name, "dso_from"))
551 sort__first_dimension = SORT_DSO_FROM;
552 else if (!strcmp(sd->name, "dso_to"))
553 sort__first_dimension = SORT_DSO_TO;
554 else if (!strcmp(sd->name, "mispredict"))
555 sort__first_dimension = SORT_MISPREDICT;
556 } 303 }
557 304
558 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 305 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
@@ -560,6 +307,7 @@ int sort_dimension__add(const char *tok)
560 307
561 return 0; 308 return 0;
562 } 309 }
310
563 return -ESRCH; 311 return -ESRCH;
564} 312}
565 313
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b4e8c3ba559..77d0388ad41 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -31,43 +31,13 @@ extern const char *parent_pattern;
31extern const char default_sort_order[]; 31extern const char default_sort_order[];
32extern int sort__need_collapse; 32extern int sort__need_collapse;
33extern int sort__has_parent; 33extern int sort__has_parent;
34extern int sort__has_sym; 34extern char *field_sep;
35extern int sort__branch_mode;
36extern struct sort_entry sort_comm; 35extern struct sort_entry sort_comm;
37extern struct sort_entry sort_dso; 36extern struct sort_entry sort_dso;
38extern struct sort_entry sort_sym; 37extern struct sort_entry sort_sym;
39extern struct sort_entry sort_parent; 38extern struct sort_entry sort_parent;
40extern struct sort_entry sort_dso_from;
41extern struct sort_entry sort_dso_to;
42extern struct sort_entry sort_sym_from;
43extern struct sort_entry sort_sym_to;
44extern enum sort_type sort__first_dimension; 39extern enum sort_type sort__first_dimension;
45 40
46struct he_stat {
47 u64 period;
48 u64 period_sys;
49 u64 period_us;
50 u64 period_guest_sys;
51 u64 period_guest_us;
52 u32 nr_events;
53};
54
55struct hist_entry_diff {
56 bool computed;
57
58 /* PERF_HPP__DISPL */
59 int displacement;
60
61 /* PERF_HPP__DELTA */
62 double period_ratio_delta;
63
64 /* PERF_HPP__RATIO */
65 double period_ratio;
66
67 /* HISTC_WEIGHTED_DIFF */
68 s64 wdiff;
69};
70
71/** 41/**
72 * struct hist_entry - histogram entry 42 * struct hist_entry - histogram entry
73 * 43 *
@@ -75,19 +45,17 @@ struct hist_entry_diff {
75 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding 45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
76 */ 46 */
77struct hist_entry { 47struct hist_entry {
78 struct rb_node rb_node_in;
79 struct rb_node rb_node; 48 struct rb_node rb_node;
80 union { 49 u64 period;
81 struct list_head node; 50 u64 period_sys;
82 struct list_head head; 51 u64 period_us;
83 } pairs; 52 u64 period_guest_sys;
84 struct he_stat stat; 53 u64 period_guest_us;
85 struct map_symbol ms; 54 struct map_symbol ms;
86 struct thread *thread; 55 struct thread *thread;
87 u64 ip; 56 u64 ip;
88 s32 cpu; 57 s32 cpu;
89 58 u32 nr_events;
90 struct hist_entry_diff diff;
91 59
92 /* XXX These two should move to some tree widget lib */ 60 /* XXX These two should move to some tree widget lib */
93 u16 row_offset; 61 u16 row_offset;
@@ -95,35 +63,16 @@ struct hist_entry {
95 63
96 bool init_have_children; 64 bool init_have_children;
97 char level; 65 char level;
98 bool used;
99 u8 filtered; 66 u8 filtered;
100 char *srcline;
101 struct symbol *parent; 67 struct symbol *parent;
102 unsigned long position; 68 union {
103 struct rb_root sorted_chain; 69 unsigned long position;
104 struct branch_info *branch_info; 70 struct hist_entry *pair;
105 struct hists *hists; 71 struct rb_root sorted_chain;
72 };
106 struct callchain_root callchain[0]; 73 struct callchain_root callchain[0];
107}; 74};
108 75
109static inline bool hist_entry__has_pairs(struct hist_entry *he)
110{
111 return !list_empty(&he->pairs.node);
112}
113
114static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
115{
116 if (hist_entry__has_pairs(he))
117 return list_entry(he->pairs.node.next, struct hist_entry, pairs.node);
118 return NULL;
119}
120
121static inline void hist__entry_add_pair(struct hist_entry *he,
122 struct hist_entry *pair)
123{
124 list_add_tail(&he->pairs.head, &pair->pairs.node);
125}
126
127enum sort_type { 76enum sort_type {
128 SORT_PID, 77 SORT_PID,
129 SORT_COMM, 78 SORT_COMM,
@@ -131,12 +80,6 @@ enum sort_type {
131 SORT_SYM, 80 SORT_SYM,
132 SORT_PARENT, 81 SORT_PARENT,
133 SORT_CPU, 82 SORT_CPU,
134 SORT_DSO_FROM,
135 SORT_DSO_TO,
136 SORT_SYM_FROM,
137 SORT_SYM_TO,
138 SORT_MISPREDICT,
139 SORT_SRCLINE,
140}; 83};
141 84
142/* 85/*
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
deleted file mode 100644
index 23742126f47..00000000000
--- a/tools/perf/util/stat.c
+++ /dev/null
@@ -1,57 +0,0 @@
1#include <math.h>
2
3#include "stat.h"
4
5void update_stats(struct stats *stats, u64 val)
6{
7 double delta;
8
9 stats->n++;
10 delta = val - stats->mean;
11 stats->mean += delta / stats->n;
12 stats->M2 += delta*(val - stats->mean);
13}
14
15double avg_stats(struct stats *stats)
16{
17 return stats->mean;
18}
19
20/*
21 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
22 *
23 * (\Sum n_i^2) - ((\Sum n_i)^2)/n
24 * s^2 = -------------------------------
25 * n - 1
26 *
27 * http://en.wikipedia.org/wiki/Stddev
28 *
29 * The std dev of the mean is related to the std dev by:
30 *
31 * s
32 * s_mean = -------
33 * sqrt(n)
34 *
35 */
36double stddev_stats(struct stats *stats)
37{
38 double variance, variance_mean;
39
40 if (!stats->n)
41 return 0.0;
42
43 variance = stats->M2 / (stats->n - 1);
44 variance_mean = variance / stats->n;
45
46 return sqrt(variance_mean);
47}
48
49double rel_stddev_stats(double stddev, double avg)
50{
51 double pct = 0.0;
52
53 if (avg)
54 pct = 100.0 * stddev/avg;
55
56 return pct;
57}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
deleted file mode 100644
index 588367c3c76..00000000000
--- a/tools/perf/util/stat.h
+++ /dev/null
@@ -1,16 +0,0 @@
1#ifndef __PERF_STATS_H
2#define __PERF_STATS_H
3
4#include "types.h"
5
6struct stats
7{
8 double n, mean, M2;
9};
10
11void update_stats(struct stats *stats, u64 val);
12double avg_stats(struct stats *stats);
13double stddev_stats(struct stats *stats);
14double rel_stddev_stats(double stddev, double avg);
15
16#endif
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index cfa906882e2..92e068517c1 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -1,5 +1,4 @@
1#include "cache.h" 1#include "cache.h"
2#include <linux/kernel.h>
3 2
4int prefixcmp(const char *str, const char *prefix) 3int prefixcmp(const char *str, const char *prefix)
5{ 4{
@@ -100,7 +99,7 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
100 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 99 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
101 va_end(ap); 100 va_end(ap);
102 if (len > strbuf_avail(sb)) { 101 if (len > strbuf_avail(sb)) {
103 die("this should not happen, your vsnprintf is broken"); 102 die("this should not happen, your snprintf is broken");
104 } 103 }
105 } 104 }
106 strbuf_setlen(sb, sb->len + len); 105 strbuf_setlen(sb, sb->len + len);
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 346707df04b..d5836382ff2 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,5 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "linux/string.h" 2#include "string.h"
3 3
4#define K 1024LL 4#define K 1024LL
5/* 5/*
@@ -313,59 +313,3 @@ int strtailcmp(const char *s1, const char *s2)
313 return 0; 313 return 0;
314} 314}
315 315
316/**
317 * strxfrchar - Locate and replace character in @s
318 * @s: The string to be searched/changed.
319 * @from: Source character to be replaced.
320 * @to: Destination character.
321 *
322 * Return pointer to the changed string.
323 */
324char *strxfrchar(char *s, char from, char to)
325{
326 char *p = s;
327
328 while ((p = strchr(p, from)) != NULL)
329 *p++ = to;
330
331 return s;
332}
333
334/**
335 * rtrim - Removes trailing whitespace from @s.
336 * @s: The string to be stripped.
337 *
338 * Note that the first trailing whitespace is replaced with a %NUL-terminator
339 * in the given string @s. Returns @s.
340 */
341char *rtrim(char *s)
342{
343 size_t size = strlen(s);
344 char *end;
345
346 if (!size)
347 return s;
348
349 end = s + size - 1;
350 while (end >= s && isspace(*end))
351 end--;
352 *(end + 1) = '\0';
353
354 return s;
355}
356
357/**
358 * memdup - duplicate region of memory
359 * @src: memory region to duplicate
360 * @len: memory region length
361 */
362void *memdup(const void *src, size_t len)
363{
364 void *p;
365
366 p = malloc(len);
367 if (p)
368 memcpy(p, src, len);
369
370 return p;
371}
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 155d8b7078a..6783a204355 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -10,28 +10,23 @@
10#include <stdlib.h> 10#include <stdlib.h>
11#include <string.h> 11#include <string.h>
12 12
13static 13static struct str_node *str_node__new(const char *s, bool dupstr)
14struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
15{ 14{
16 const char *s = entry; 15 struct str_node *self = malloc(sizeof(*self));
17 struct rb_node *rc = NULL;
18 struct strlist *strlist = container_of(rblist, struct strlist, rblist);
19 struct str_node *snode = malloc(sizeof(*snode));
20 16
21 if (snode != NULL) { 17 if (self != NULL) {
22 if (strlist->dupstr) { 18 if (dupstr) {
23 s = strdup(s); 19 s = strdup(s);
24 if (s == NULL) 20 if (s == NULL)
25 goto out_delete; 21 goto out_delete;
26 } 22 }
27 snode->s = s; 23 self->s = s;
28 rc = &snode->rb_node;
29 } 24 }
30 25
31 return rc; 26 return self;
32 27
33out_delete: 28out_delete:
34 free(snode); 29 free(self);
35 return NULL; 30 return NULL;
36} 31}
37 32
@@ -42,26 +37,36 @@ static void str_node__delete(struct str_node *self, bool dupstr)
42 free(self); 37 free(self);
43} 38}
44 39
45static 40int strlist__add(struct strlist *self, const char *new_entry)
46void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
47{ 41{
48 struct strlist *slist = container_of(rblist, struct strlist, rblist); 42 struct rb_node **p = &self->entries.rb_node;
49 struct str_node *snode = container_of(rb_node, struct str_node, rb_node); 43 struct rb_node *parent = NULL;
50 44 struct str_node *sn;
51 str_node__delete(snode, slist->dupstr); 45
52} 46 while (*p != NULL) {
47 int rc;
48
49 parent = *p;
50 sn = rb_entry(parent, struct str_node, rb_node);
51 rc = strcmp(sn->s, new_entry);
52
53 if (rc > 0)
54 p = &(*p)->rb_left;
55 else if (rc < 0)
56 p = &(*p)->rb_right;
57 else
58 return -EEXIST;
59 }
53 60
54static int strlist__node_cmp(struct rb_node *rb_node, const void *entry) 61 sn = str_node__new(new_entry, self->dupstr);
55{ 62 if (sn == NULL)
56 const char *str = entry; 63 return -ENOMEM;
57 struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
58 64
59 return strcmp(snode->s, str); 65 rb_link_node(&sn->rb_node, parent, p);
60} 66 rb_insert_color(&sn->rb_node, &self->entries);
67 ++self->nr_entries;
61 68
62int strlist__add(struct strlist *self, const char *new_entry) 69 return 0;
63{
64 return rblist__add_node(&self->rblist, new_entry);
65} 70}
66 71
67int strlist__load(struct strlist *self, const char *filename) 72int strlist__load(struct strlist *self, const char *filename)
@@ -91,20 +96,34 @@ out:
91 return err; 96 return err;
92} 97}
93 98
94void strlist__remove(struct strlist *slist, struct str_node *snode) 99void strlist__remove(struct strlist *self, struct str_node *sn)
95{ 100{
96 rblist__remove_node(&slist->rblist, &snode->rb_node); 101 rb_erase(&sn->rb_node, &self->entries);
102 str_node__delete(sn, self->dupstr);
97} 103}
98 104
99struct str_node *strlist__find(struct strlist *slist, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
100{ 106{
101 struct str_node *snode = NULL; 107 struct rb_node **p = &self->entries.rb_node;
102 struct rb_node *rb_node = rblist__find(&slist->rblist, entry); 108 struct rb_node *parent = NULL;
103 109
104 if (rb_node) 110 while (*p != NULL) {
105 snode = container_of(rb_node, struct str_node, rb_node); 111 struct str_node *sn;
112 int rc;
113
114 parent = *p;
115 sn = rb_entry(parent, struct str_node, rb_node);
116 rc = strcmp(sn->s, entry);
117
118 if (rc > 0)
119 p = &(*p)->rb_left;
120 else if (rc < 0)
121 p = &(*p)->rb_right;
122 else
123 return sn;
124 }
106 125
107 return snode; 126 return NULL;
108} 127}
109 128
110static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
@@ -137,12 +156,9 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
137 struct strlist *self = malloc(sizeof(*self)); 156 struct strlist *self = malloc(sizeof(*self));
138 157
139 if (self != NULL) { 158 if (self != NULL) {
140 rblist__init(&self->rblist); 159 self->entries = RB_ROOT;
141 self->rblist.node_cmp = strlist__node_cmp;
142 self->rblist.node_new = strlist__node_new;
143 self->rblist.node_delete = strlist__node_delete;
144
145 self->dupstr = dupstr; 160 self->dupstr = dupstr;
161 self->nr_entries = 0;
146 if (slist && strlist__parse_list(self, slist) != 0) 162 if (slist && strlist__parse_list(self, slist) != 0)
147 goto out_error; 163 goto out_error;
148 } 164 }
@@ -155,18 +171,30 @@ out_error:
155 171
156void strlist__delete(struct strlist *self) 172void strlist__delete(struct strlist *self)
157{ 173{
158 if (self != NULL) 174 if (self != NULL) {
159 rblist__delete(&self->rblist); 175 struct str_node *pos;
176 struct rb_node *next = rb_first(&self->entries);
177
178 while (next) {
179 pos = rb_entry(next, struct str_node, rb_node);
180 next = rb_next(&pos->rb_node);
181 strlist__remove(self, pos);
182 }
183 self->entries = RB_ROOT;
184 free(self);
185 }
160} 186}
161 187
162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) 188struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
163{ 189{
164 struct str_node *snode = NULL; 190 struct rb_node *nd;
165 struct rb_node *rb_node;
166 191
167 rb_node = rblist__entry(&slist->rblist, idx); 192 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
168 if (rb_node) 193 struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
169 snode = container_of(rb_node, struct str_node, rb_node);
170 194
171 return snode; 195 if (!idx--)
196 return pos;
197 }
198
199 return NULL;
172} 200}
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index dd9f922ec67..3ba839007d2 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -4,15 +4,14 @@
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7#include "rblist.h"
8
9struct str_node { 7struct str_node {
10 struct rb_node rb_node; 8 struct rb_node rb_node;
11 const char *s; 9 const char *s;
12}; 10};
13 11
14struct strlist { 12struct strlist {
15 struct rblist rblist; 13 struct rb_root entries;
14 unsigned int nr_entries;
16 bool dupstr; 15 bool dupstr;
17}; 16};
18 17
@@ -33,18 +32,18 @@ static inline bool strlist__has_entry(struct strlist *self, const char *entry)
33 32
34static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
35{ 34{
36 return rblist__empty(&self->rblist); 35 return self->nr_entries == 0;
37} 36}
38 37
39static inline unsigned int strlist__nr_entries(const struct strlist *self) 38static inline unsigned int strlist__nr_entries(const struct strlist *self)
40{ 39{
41 return rblist__nr_entries(&self->rblist); 40 return self->nr_entries;
42} 41}
43 42
44/* For strlist iteration */ 43/* For strlist iteration */
45static inline struct str_node *strlist__first(struct strlist *self) 44static inline struct str_node *strlist__first(struct strlist *self)
46{ 45{
47 struct rb_node *rn = rb_first(&self->rblist.entries); 46 struct rb_node *rn = rb_first(&self->entries);
48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; 47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
49} 48}
50static inline struct str_node *strlist__next(struct str_node *sn) 49static inline struct str_node *strlist__next(struct str_node *sn)
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
deleted file mode 100644
index db0cc92cf2e..00000000000
--- a/tools/perf/util/symbol-elf.c
+++ /dev/null
@@ -1,841 +0,0 @@
1#include <libelf.h>
2#include <gelf.h>
3#include <elf.h>
4#include <fcntl.h>
5#include <stdio.h>
6#include <errno.h>
7#include <string.h>
8#include <unistd.h>
9#include <inttypes.h>
10
11#include "symbol.h"
12#include "debug.h"
13
14#ifndef NT_GNU_BUILD_ID
15#define NT_GNU_BUILD_ID 3
16#endif
17
18/**
19 * elf_symtab__for_each_symbol - iterate thru all the symbols
20 *
21 * @syms: struct elf_symtab instance to iterate
22 * @idx: uint32_t idx
23 * @sym: GElf_Sym iterator
24 */
25#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
26 for (idx = 0, gelf_getsym(syms, idx, &sym);\
27 idx < nr_syms; \
28 idx++, gelf_getsym(syms, idx, &sym))
29
30static inline uint8_t elf_sym__type(const GElf_Sym *sym)
31{
32 return GELF_ST_TYPE(sym->st_info);
33}
34
35static inline int elf_sym__is_function(const GElf_Sym *sym)
36{
37 return elf_sym__type(sym) == STT_FUNC &&
38 sym->st_name != 0 &&
39 sym->st_shndx != SHN_UNDEF;
40}
41
42static inline bool elf_sym__is_object(const GElf_Sym *sym)
43{
44 return elf_sym__type(sym) == STT_OBJECT &&
45 sym->st_name != 0 &&
46 sym->st_shndx != SHN_UNDEF;
47}
48
49static inline int elf_sym__is_label(const GElf_Sym *sym)
50{
51 return elf_sym__type(sym) == STT_NOTYPE &&
52 sym->st_name != 0 &&
53 sym->st_shndx != SHN_UNDEF &&
54 sym->st_shndx != SHN_ABS;
55}
56
57static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
58{
59 switch (type) {
60 case MAP__FUNCTION:
61 return elf_sym__is_function(sym);
62 case MAP__VARIABLE:
63 return elf_sym__is_object(sym);
64 default:
65 return false;
66 }
67}
68
69static inline const char *elf_sym__name(const GElf_Sym *sym,
70 const Elf_Data *symstrs)
71{
72 return symstrs->d_buf + sym->st_name;
73}
74
75static inline const char *elf_sec__name(const GElf_Shdr *shdr,
76 const Elf_Data *secstrs)
77{
78 return secstrs->d_buf + shdr->sh_name;
79}
80
81static inline int elf_sec__is_text(const GElf_Shdr *shdr,
82 const Elf_Data *secstrs)
83{
84 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
85}
86
87static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
88 const Elf_Data *secstrs)
89{
90 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
91}
92
93static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
94 enum map_type type)
95{
96 switch (type) {
97 case MAP__FUNCTION:
98 return elf_sec__is_text(shdr, secstrs);
99 case MAP__VARIABLE:
100 return elf_sec__is_data(shdr, secstrs);
101 default:
102 return false;
103 }
104}
105
106static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
107{
108 Elf_Scn *sec = NULL;
109 GElf_Shdr shdr;
110 size_t cnt = 1;
111
112 while ((sec = elf_nextscn(elf, sec)) != NULL) {
113 gelf_getshdr(sec, &shdr);
114
115 if ((addr >= shdr.sh_addr) &&
116 (addr < (shdr.sh_addr + shdr.sh_size)))
117 return cnt;
118
119 ++cnt;
120 }
121
122 return -1;
123}
124
125static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
126 GElf_Shdr *shp, const char *name,
127 size_t *idx)
128{
129 Elf_Scn *sec = NULL;
130 size_t cnt = 1;
131
132 /* Elf is corrupted/truncated, avoid calling elf_strptr. */
133 if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL))
134 return NULL;
135
136 while ((sec = elf_nextscn(elf, sec)) != NULL) {
137 char *str;
138
139 gelf_getshdr(sec, shp);
140 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
141 if (!strcmp(name, str)) {
142 if (idx)
143 *idx = cnt;
144 break;
145 }
146 ++cnt;
147 }
148
149 return sec;
150}
151
152#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
153 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
154 idx < nr_entries; \
155 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
156
157#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
158 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
159 idx < nr_entries; \
160 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
161
162/*
163 * We need to check if we have a .dynsym, so that we can handle the
164 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
165 * .dynsym or .symtab).
166 * And always look at the original dso, not at debuginfo packages, that
167 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
168 */
169int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map,
170 symbol_filter_t filter)
171{
172 uint32_t nr_rel_entries, idx;
173 GElf_Sym sym;
174 u64 plt_offset;
175 GElf_Shdr shdr_plt;
176 struct symbol *f;
177 GElf_Shdr shdr_rel_plt, shdr_dynsym;
178 Elf_Data *reldata, *syms, *symstrs;
179 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
180 size_t dynsym_idx;
181 GElf_Ehdr ehdr;
182 char sympltname[1024];
183 Elf *elf;
184 int nr = 0, symidx, err = 0;
185
186 if (!ss->dynsym)
187 return 0;
188
189 elf = ss->elf;
190 ehdr = ss->ehdr;
191
192 scn_dynsym = ss->dynsym;
193 shdr_dynsym = ss->dynshdr;
194 dynsym_idx = ss->dynsym_idx;
195
196 if (scn_dynsym == NULL)
197 goto out_elf_end;
198
199 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
200 ".rela.plt", NULL);
201 if (scn_plt_rel == NULL) {
202 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
203 ".rel.plt", NULL);
204 if (scn_plt_rel == NULL)
205 goto out_elf_end;
206 }
207
208 err = -1;
209
210 if (shdr_rel_plt.sh_link != dynsym_idx)
211 goto out_elf_end;
212
213 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
214 goto out_elf_end;
215
216 /*
217 * Fetch the relocation section to find the idxes to the GOT
218 * and the symbols in the .dynsym they refer to.
219 */
220 reldata = elf_getdata(scn_plt_rel, NULL);
221 if (reldata == NULL)
222 goto out_elf_end;
223
224 syms = elf_getdata(scn_dynsym, NULL);
225 if (syms == NULL)
226 goto out_elf_end;
227
228 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
229 if (scn_symstrs == NULL)
230 goto out_elf_end;
231
232 symstrs = elf_getdata(scn_symstrs, NULL);
233 if (symstrs == NULL)
234 goto out_elf_end;
235
236 if (symstrs->d_size == 0)
237 goto out_elf_end;
238
239 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
240 plt_offset = shdr_plt.sh_offset;
241
242 if (shdr_rel_plt.sh_type == SHT_RELA) {
243 GElf_Rela pos_mem, *pos;
244
245 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
246 nr_rel_entries) {
247 symidx = GELF_R_SYM(pos->r_info);
248 plt_offset += shdr_plt.sh_entsize;
249 gelf_getsym(syms, symidx, &sym);
250 snprintf(sympltname, sizeof(sympltname),
251 "%s@plt", elf_sym__name(&sym, symstrs));
252
253 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
254 STB_GLOBAL, sympltname);
255 if (!f)
256 goto out_elf_end;
257
258 if (filter && filter(map, f))
259 symbol__delete(f);
260 else {
261 symbols__insert(&dso->symbols[map->type], f);
262 ++nr;
263 }
264 }
265 } else if (shdr_rel_plt.sh_type == SHT_REL) {
266 GElf_Rel pos_mem, *pos;
267 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
268 nr_rel_entries) {
269 symidx = GELF_R_SYM(pos->r_info);
270 plt_offset += shdr_plt.sh_entsize;
271 gelf_getsym(syms, symidx, &sym);
272 snprintf(sympltname, sizeof(sympltname),
273 "%s@plt", elf_sym__name(&sym, symstrs));
274
275 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
276 STB_GLOBAL, sympltname);
277 if (!f)
278 goto out_elf_end;
279
280 if (filter && filter(map, f))
281 symbol__delete(f);
282 else {
283 symbols__insert(&dso->symbols[map->type], f);
284 ++nr;
285 }
286 }
287 }
288
289 err = 0;
290out_elf_end:
291 if (err == 0)
292 return nr;
293 pr_debug("%s: problems reading %s PLT info.\n",
294 __func__, dso->long_name);
295 return 0;
296}
297
298/*
299 * Align offset to 4 bytes as needed for note name and descriptor data.
300 */
301#define NOTE_ALIGN(n) (((n) + 3) & -4U)
302
303static int elf_read_build_id(Elf *elf, void *bf, size_t size)
304{
305 int err = -1;
306 GElf_Ehdr ehdr;
307 GElf_Shdr shdr;
308 Elf_Data *data;
309 Elf_Scn *sec;
310 Elf_Kind ek;
311 void *ptr;
312
313 if (size < BUILD_ID_SIZE)
314 goto out;
315
316 ek = elf_kind(elf);
317 if (ek != ELF_K_ELF)
318 goto out;
319
320 if (gelf_getehdr(elf, &ehdr) == NULL) {
321 pr_err("%s: cannot get elf header.\n", __func__);
322 goto out;
323 }
324
325 /*
326 * Check following sections for notes:
327 * '.note.gnu.build-id'
328 * '.notes'
329 * '.note' (VDSO specific)
330 */
331 do {
332 sec = elf_section_by_name(elf, &ehdr, &shdr,
333 ".note.gnu.build-id", NULL);
334 if (sec)
335 break;
336
337 sec = elf_section_by_name(elf, &ehdr, &shdr,
338 ".notes", NULL);
339 if (sec)
340 break;
341
342 sec = elf_section_by_name(elf, &ehdr, &shdr,
343 ".note", NULL);
344 if (sec)
345 break;
346
347 return err;
348
349 } while (0);
350
351 data = elf_getdata(sec, NULL);
352 if (data == NULL)
353 goto out;
354
355 ptr = data->d_buf;
356 while (ptr < (data->d_buf + data->d_size)) {
357 GElf_Nhdr *nhdr = ptr;
358 size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
359 descsz = NOTE_ALIGN(nhdr->n_descsz);
360 const char *name;
361
362 ptr += sizeof(*nhdr);
363 name = ptr;
364 ptr += namesz;
365 if (nhdr->n_type == NT_GNU_BUILD_ID &&
366 nhdr->n_namesz == sizeof("GNU")) {
367 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
368 size_t sz = min(size, descsz);
369 memcpy(bf, ptr, sz);
370 memset(bf + sz, 0, size - sz);
371 err = descsz;
372 break;
373 }
374 }
375 ptr += descsz;
376 }
377
378out:
379 return err;
380}
381
382int filename__read_build_id(const char *filename, void *bf, size_t size)
383{
384 int fd, err = -1;
385 Elf *elf;
386
387 if (size < BUILD_ID_SIZE)
388 goto out;
389
390 fd = open(filename, O_RDONLY);
391 if (fd < 0)
392 goto out;
393
394 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
395 if (elf == NULL) {
396 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
397 goto out_close;
398 }
399
400 err = elf_read_build_id(elf, bf, size);
401
402 elf_end(elf);
403out_close:
404 close(fd);
405out:
406 return err;
407}
408
409int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
410{
411 int fd, err = -1;
412
413 if (size < BUILD_ID_SIZE)
414 goto out;
415
416 fd = open(filename, O_RDONLY);
417 if (fd < 0)
418 goto out;
419
420 while (1) {
421 char bf[BUFSIZ];
422 GElf_Nhdr nhdr;
423 size_t namesz, descsz;
424
425 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
426 break;
427
428 namesz = NOTE_ALIGN(nhdr.n_namesz);
429 descsz = NOTE_ALIGN(nhdr.n_descsz);
430 if (nhdr.n_type == NT_GNU_BUILD_ID &&
431 nhdr.n_namesz == sizeof("GNU")) {
432 if (read(fd, bf, namesz) != (ssize_t)namesz)
433 break;
434 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
435 size_t sz = min(descsz, size);
436 if (read(fd, build_id, sz) == (ssize_t)sz) {
437 memset(build_id + sz, 0, size - sz);
438 err = 0;
439 break;
440 }
441 } else if (read(fd, bf, descsz) != (ssize_t)descsz)
442 break;
443 } else {
444 int n = namesz + descsz;
445 if (read(fd, bf, n) != n)
446 break;
447 }
448 }
449 close(fd);
450out:
451 return err;
452}
453
454int filename__read_debuglink(const char *filename, char *debuglink,
455 size_t size)
456{
457 int fd, err = -1;
458 Elf *elf;
459 GElf_Ehdr ehdr;
460 GElf_Shdr shdr;
461 Elf_Data *data;
462 Elf_Scn *sec;
463 Elf_Kind ek;
464
465 fd = open(filename, O_RDONLY);
466 if (fd < 0)
467 goto out;
468
469 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
470 if (elf == NULL) {
471 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
472 goto out_close;
473 }
474
475 ek = elf_kind(elf);
476 if (ek != ELF_K_ELF)
477 goto out_close;
478
479 if (gelf_getehdr(elf, &ehdr) == NULL) {
480 pr_err("%s: cannot get elf header.\n", __func__);
481 goto out_close;
482 }
483
484 sec = elf_section_by_name(elf, &ehdr, &shdr,
485 ".gnu_debuglink", NULL);
486 if (sec == NULL)
487 goto out_close;
488
489 data = elf_getdata(sec, NULL);
490 if (data == NULL)
491 goto out_close;
492
493 /* the start of this section is a zero-terminated string */
494 strncpy(debuglink, data->d_buf, size);
495
496 elf_end(elf);
497
498out_close:
499 close(fd);
500out:
501 return err;
502}
503
504static int dso__swap_init(struct dso *dso, unsigned char eidata)
505{
506 static unsigned int const endian = 1;
507
508 dso->needs_swap = DSO_SWAP__NO;
509
510 switch (eidata) {
511 case ELFDATA2LSB:
512 /* We are big endian, DSO is little endian. */
513 if (*(unsigned char const *)&endian != 1)
514 dso->needs_swap = DSO_SWAP__YES;
515 break;
516
517 case ELFDATA2MSB:
518 /* We are little endian, DSO is big endian. */
519 if (*(unsigned char const *)&endian != 0)
520 dso->needs_swap = DSO_SWAP__YES;
521 break;
522
523 default:
524 pr_err("unrecognized DSO data encoding %d\n", eidata);
525 return -EINVAL;
526 }
527
528 return 0;
529}
530
531bool symsrc__possibly_runtime(struct symsrc *ss)
532{
533 return ss->dynsym || ss->opdsec;
534}
535
536bool symsrc__has_symtab(struct symsrc *ss)
537{
538 return ss->symtab != NULL;
539}
540
541void symsrc__destroy(struct symsrc *ss)
542{
543 free(ss->name);
544 elf_end(ss->elf);
545 close(ss->fd);
546}
547
548int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
549 enum dso_binary_type type)
550{
551 int err = -1;
552 GElf_Ehdr ehdr;
553 Elf *elf;
554 int fd;
555
556 fd = open(name, O_RDONLY);
557 if (fd < 0)
558 return -1;
559
560 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
561 if (elf == NULL) {
562 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
563 goto out_close;
564 }
565
566 if (gelf_getehdr(elf, &ehdr) == NULL) {
567 pr_debug("%s: cannot get elf header.\n", __func__);
568 goto out_elf_end;
569 }
570
571 if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
572 goto out_elf_end;
573
574 /* Always reject images with a mismatched build-id: */
575 if (dso->has_build_id) {
576 u8 build_id[BUILD_ID_SIZE];
577
578 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
579 goto out_elf_end;
580
581 if (!dso__build_id_equal(dso, build_id))
582 goto out_elf_end;
583 }
584
585 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
586 NULL);
587 if (ss->symshdr.sh_type != SHT_SYMTAB)
588 ss->symtab = NULL;
589
590 ss->dynsym_idx = 0;
591 ss->dynsym = elf_section_by_name(elf, &ehdr, &ss->dynshdr, ".dynsym",
592 &ss->dynsym_idx);
593 if (ss->dynshdr.sh_type != SHT_DYNSYM)
594 ss->dynsym = NULL;
595
596 ss->opdidx = 0;
597 ss->opdsec = elf_section_by_name(elf, &ehdr, &ss->opdshdr, ".opd",
598 &ss->opdidx);
599 if (ss->opdshdr.sh_type != SHT_PROGBITS)
600 ss->opdsec = NULL;
601
602 if (dso->kernel == DSO_TYPE_USER) {
603 GElf_Shdr shdr;
604 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
605 elf_section_by_name(elf, &ehdr, &shdr,
606 ".gnu.prelink_undo",
607 NULL) != NULL);
608 } else {
609 ss->adjust_symbols = 0;
610 }
611
612 ss->name = strdup(name);
613 if (!ss->name)
614 goto out_elf_end;
615
616 ss->elf = elf;
617 ss->fd = fd;
618 ss->ehdr = ehdr;
619 ss->type = type;
620
621 return 0;
622
623out_elf_end:
624 elf_end(elf);
625out_close:
626 close(fd);
627 return err;
628}
629
630int dso__load_sym(struct dso *dso, struct map *map,
631 struct symsrc *syms_ss, struct symsrc *runtime_ss,
632 symbol_filter_t filter, int kmodule)
633{
634 struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
635 struct map *curr_map = map;
636 struct dso *curr_dso = dso;
637 Elf_Data *symstrs, *secstrs;
638 uint32_t nr_syms;
639 int err = -1;
640 uint32_t idx;
641 GElf_Ehdr ehdr;
642 GElf_Shdr shdr;
643 Elf_Data *syms, *opddata = NULL;
644 GElf_Sym sym;
645 Elf_Scn *sec, *sec_strndx;
646 Elf *elf;
647 int nr = 0;
648
649 dso->symtab_type = syms_ss->type;
650
651 if (!syms_ss->symtab) {
652 syms_ss->symtab = syms_ss->dynsym;
653 syms_ss->symshdr = syms_ss->dynshdr;
654 }
655
656 elf = syms_ss->elf;
657 ehdr = syms_ss->ehdr;
658 sec = syms_ss->symtab;
659 shdr = syms_ss->symshdr;
660
661 if (runtime_ss->opdsec)
662 opddata = elf_rawdata(runtime_ss->opdsec, NULL);
663
664 syms = elf_getdata(sec, NULL);
665 if (syms == NULL)
666 goto out_elf_end;
667
668 sec = elf_getscn(elf, shdr.sh_link);
669 if (sec == NULL)
670 goto out_elf_end;
671
672 symstrs = elf_getdata(sec, NULL);
673 if (symstrs == NULL)
674 goto out_elf_end;
675
676 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
677 if (sec_strndx == NULL)
678 goto out_elf_end;
679
680 secstrs = elf_getdata(sec_strndx, NULL);
681 if (secstrs == NULL)
682 goto out_elf_end;
683
684 nr_syms = shdr.sh_size / shdr.sh_entsize;
685
686 memset(&sym, 0, sizeof(sym));
687 dso->adjust_symbols = runtime_ss->adjust_symbols;
688 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
689 struct symbol *f;
690 const char *elf_name = elf_sym__name(&sym, symstrs);
691 char *demangled = NULL;
692 int is_label = elf_sym__is_label(&sym);
693 const char *section_name;
694 bool used_opd = false;
695
696 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
697 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
698 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
699
700 if (!is_label && !elf_sym__is_a(&sym, map->type))
701 continue;
702
703 /* Reject ARM ELF "mapping symbols": these aren't unique and
704 * don't identify functions, so will confuse the profile
705 * output: */
706 if (ehdr.e_machine == EM_ARM) {
707 if (!strcmp(elf_name, "$a") ||
708 !strcmp(elf_name, "$d") ||
709 !strcmp(elf_name, "$t"))
710 continue;
711 }
712
713 if (runtime_ss->opdsec && sym.st_shndx == runtime_ss->opdidx) {
714 u32 offset = sym.st_value - syms_ss->opdshdr.sh_addr;
715 u64 *opd = opddata->d_buf + offset;
716 sym.st_value = DSO__SWAP(dso, u64, *opd);
717 sym.st_shndx = elf_addr_to_index(runtime_ss->elf,
718 sym.st_value);
719 used_opd = true;
720 }
721
722 sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
723 if (!sec)
724 goto out_elf_end;
725
726 gelf_getshdr(sec, &shdr);
727
728 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
729 continue;
730
731 section_name = elf_sec__name(&shdr, secstrs);
732
733 /* On ARM, symbols for thumb functions have 1 added to
734 * the symbol address as a flag - remove it */
735 if ((ehdr.e_machine == EM_ARM) &&
736 (map->type == MAP__FUNCTION) &&
737 (sym.st_value & 1))
738 --sym.st_value;
739
740 if (dso->kernel != DSO_TYPE_USER || kmodule) {
741 char dso_name[PATH_MAX];
742
743 if (strcmp(section_name,
744 (curr_dso->short_name +
745 dso->short_name_len)) == 0)
746 goto new_symbol;
747
748 if (strcmp(section_name, ".text") == 0) {
749 curr_map = map;
750 curr_dso = dso;
751 goto new_symbol;
752 }
753
754 snprintf(dso_name, sizeof(dso_name),
755 "%s%s", dso->short_name, section_name);
756
757 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
758 if (curr_map == NULL) {
759 u64 start = sym.st_value;
760
761 if (kmodule)
762 start += map->start + shdr.sh_offset;
763
764 curr_dso = dso__new(dso_name);
765 if (curr_dso == NULL)
766 goto out_elf_end;
767 curr_dso->kernel = dso->kernel;
768 curr_dso->long_name = dso->long_name;
769 curr_dso->long_name_len = dso->long_name_len;
770 curr_map = map__new2(start, curr_dso,
771 map->type);
772 if (curr_map == NULL) {
773 dso__delete(curr_dso);
774 goto out_elf_end;
775 }
776 curr_map->map_ip = identity__map_ip;
777 curr_map->unmap_ip = identity__map_ip;
778 curr_dso->symtab_type = dso->symtab_type;
779 map_groups__insert(kmap->kmaps, curr_map);
780 dsos__add(&dso->node, curr_dso);
781 dso__set_loaded(curr_dso, map->type);
782 } else
783 curr_dso = curr_map->dso;
784
785 goto new_symbol;
786 }
787
788 if ((used_opd && runtime_ss->adjust_symbols)
789 || (!used_opd && syms_ss->adjust_symbols)) {
790 pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
791 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
792 (u64)sym.st_value, (u64)shdr.sh_addr,
793 (u64)shdr.sh_offset);
794 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
795 }
796 /*
797 * We need to figure out if the object was created from C++ sources
798 * DWARF DW_compile_unit has this, but we don't always have access
799 * to it...
800 */
801 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
802 if (demangled != NULL)
803 elf_name = demangled;
804new_symbol:
805 f = symbol__new(sym.st_value, sym.st_size,
806 GELF_ST_BIND(sym.st_info), elf_name);
807 free(demangled);
808 if (!f)
809 goto out_elf_end;
810
811 if (filter && filter(curr_map, f))
812 symbol__delete(f);
813 else {
814 symbols__insert(&curr_dso->symbols[curr_map->type], f);
815 nr++;
816 }
817 }
818
819 /*
820 * For misannotated, zeroed, ASM function sizes.
821 */
822 if (nr > 0) {
823 symbols__fixup_duplicate(&dso->symbols[map->type]);
824 symbols__fixup_end(&dso->symbols[map->type]);
825 if (kmap) {
826 /*
827 * We need to fixup this here too because we create new
828 * maps here, for things like vsyscall sections.
829 */
830 __map_groups__fixup_end(kmap->kmaps, map->type);
831 }
832 }
833 err = nr;
834out_elf_end:
835 return err;
836}
837
838void symbol__elf_init(void)
839{
840 elf_version(EV_CURRENT);
841}
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
deleted file mode 100644
index 259f8f2ea9c..00000000000
--- a/tools/perf/util/symbol-minimal.c
+++ /dev/null
@@ -1,307 +0,0 @@
1#include "symbol.h"
2
3#include <elf.h>
4#include <stdio.h>
5#include <fcntl.h>
6#include <string.h>
7#include <byteswap.h>
8#include <sys/stat.h>
9
10
11static bool check_need_swap(int file_endian)
12{
13 const int data = 1;
14 u8 *check = (u8 *)&data;
15 int host_endian;
16
17 if (check[0] == 1)
18 host_endian = ELFDATA2LSB;
19 else
20 host_endian = ELFDATA2MSB;
21
22 return host_endian != file_endian;
23}
24
25#define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
26
27#define NT_GNU_BUILD_ID 3
28
29static int read_build_id(void *note_data, size_t note_len, void *bf,
30 size_t size, bool need_swap)
31{
32 struct {
33 u32 n_namesz;
34 u32 n_descsz;
35 u32 n_type;
36 } *nhdr;
37 void *ptr;
38
39 ptr = note_data;
40 while (ptr < (note_data + note_len)) {
41 const char *name;
42 size_t namesz, descsz;
43
44 nhdr = ptr;
45 if (need_swap) {
46 nhdr->n_namesz = bswap_32(nhdr->n_namesz);
47 nhdr->n_descsz = bswap_32(nhdr->n_descsz);
48 nhdr->n_type = bswap_32(nhdr->n_type);
49 }
50
51 namesz = NOTE_ALIGN(nhdr->n_namesz);
52 descsz = NOTE_ALIGN(nhdr->n_descsz);
53
54 ptr += sizeof(*nhdr);
55 name = ptr;
56 ptr += namesz;
57 if (nhdr->n_type == NT_GNU_BUILD_ID &&
58 nhdr->n_namesz == sizeof("GNU")) {
59 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
60 size_t sz = min(size, descsz);
61 memcpy(bf, ptr, sz);
62 memset(bf + sz, 0, size - sz);
63 return 0;
64 }
65 }
66 ptr += descsz;
67 }
68
69 return -1;
70}
71
72int filename__read_debuglink(const char *filename __maybe_unused,
73 char *debuglink __maybe_unused,
74 size_t size __maybe_unused)
75{
76 return -1;
77}
78
79/*
80 * Just try PT_NOTE header otherwise fails
81 */
82int filename__read_build_id(const char *filename, void *bf, size_t size)
83{
84 FILE *fp;
85 int ret = -1;
86 bool need_swap = false;
87 u8 e_ident[EI_NIDENT];
88 size_t buf_size;
89 void *buf;
90 int i;
91
92 fp = fopen(filename, "r");
93 if (fp == NULL)
94 return -1;
95
96 if (fread(e_ident, sizeof(e_ident), 1, fp) != 1)
97 goto out;
98
99 if (memcmp(e_ident, ELFMAG, SELFMAG) ||
100 e_ident[EI_VERSION] != EV_CURRENT)
101 goto out;
102
103 need_swap = check_need_swap(e_ident[EI_DATA]);
104
105 /* for simplicity */
106 fseek(fp, 0, SEEK_SET);
107
108 if (e_ident[EI_CLASS] == ELFCLASS32) {
109 Elf32_Ehdr ehdr;
110 Elf32_Phdr *phdr;
111
112 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
113 goto out;
114
115 if (need_swap) {
116 ehdr.e_phoff = bswap_32(ehdr.e_phoff);
117 ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
118 ehdr.e_phnum = bswap_16(ehdr.e_phnum);
119 }
120
121 buf_size = ehdr.e_phentsize * ehdr.e_phnum;
122 buf = malloc(buf_size);
123 if (buf == NULL)
124 goto out;
125
126 fseek(fp, ehdr.e_phoff, SEEK_SET);
127 if (fread(buf, buf_size, 1, fp) != 1)
128 goto out_free;
129
130 for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
131 void *tmp;
132
133 if (need_swap) {
134 phdr->p_type = bswap_32(phdr->p_type);
135 phdr->p_offset = bswap_32(phdr->p_offset);
136 phdr->p_filesz = bswap_32(phdr->p_filesz);
137 }
138
139 if (phdr->p_type != PT_NOTE)
140 continue;
141
142 buf_size = phdr->p_filesz;
143 tmp = realloc(buf, buf_size);
144 if (tmp == NULL)
145 goto out_free;
146
147 buf = tmp;
148 fseek(fp, phdr->p_offset, SEEK_SET);
149 if (fread(buf, buf_size, 1, fp) != 1)
150 goto out_free;
151
152 ret = read_build_id(buf, buf_size, bf, size, need_swap);
153 if (ret == 0)
154 ret = size;
155 break;
156 }
157 } else {
158 Elf64_Ehdr ehdr;
159 Elf64_Phdr *phdr;
160
161 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
162 goto out;
163
164 if (need_swap) {
165 ehdr.e_phoff = bswap_64(ehdr.e_phoff);
166 ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
167 ehdr.e_phnum = bswap_16(ehdr.e_phnum);
168 }
169
170 buf_size = ehdr.e_phentsize * ehdr.e_phnum;
171 buf = malloc(buf_size);
172 if (buf == NULL)
173 goto out;
174
175 fseek(fp, ehdr.e_phoff, SEEK_SET);
176 if (fread(buf, buf_size, 1, fp) != 1)
177 goto out_free;
178
179 for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
180 void *tmp;
181
182 if (need_swap) {
183 phdr->p_type = bswap_32(phdr->p_type);
184 phdr->p_offset = bswap_64(phdr->p_offset);
185 phdr->p_filesz = bswap_64(phdr->p_filesz);
186 }
187
188 if (phdr->p_type != PT_NOTE)
189 continue;
190
191 buf_size = phdr->p_filesz;
192 tmp = realloc(buf, buf_size);
193 if (tmp == NULL)
194 goto out_free;
195
196 buf = tmp;
197 fseek(fp, phdr->p_offset, SEEK_SET);
198 if (fread(buf, buf_size, 1, fp) != 1)
199 goto out_free;
200
201 ret = read_build_id(buf, buf_size, bf, size, need_swap);
202 if (ret == 0)
203 ret = size;
204 break;
205 }
206 }
207out_free:
208 free(buf);
209out:
210 fclose(fp);
211 return ret;
212}
213
214int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
215{
216 int fd;
217 int ret = -1;
218 struct stat stbuf;
219 size_t buf_size;
220 void *buf;
221
222 fd = open(filename, O_RDONLY);
223 if (fd < 0)
224 return -1;
225
226 if (fstat(fd, &stbuf) < 0)
227 goto out;
228
229 buf_size = stbuf.st_size;
230 buf = malloc(buf_size);
231 if (buf == NULL)
232 goto out;
233
234 if (read(fd, buf, buf_size) != (ssize_t) buf_size)
235 goto out_free;
236
237 ret = read_build_id(buf, buf_size, build_id, size, false);
238out_free:
239 free(buf);
240out:
241 close(fd);
242 return ret;
243}
244
245int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
246 const char *name,
247 enum dso_binary_type type)
248{
249 int fd = open(name, O_RDONLY);
250 if (fd < 0)
251 return -1;
252
253 ss->name = strdup(name);
254 if (!ss->name)
255 goto out_close;
256
257 ss->type = type;
258
259 return 0;
260out_close:
261 close(fd);
262 return -1;
263}
264
265bool symsrc__possibly_runtime(struct symsrc *ss __maybe_unused)
266{
267 /* Assume all sym sources could be a runtime image. */
268 return true;
269}
270
271bool symsrc__has_symtab(struct symsrc *ss __maybe_unused)
272{
273 return false;
274}
275
276void symsrc__destroy(struct symsrc *ss)
277{
278 free(ss->name);
279 close(ss->fd);
280}
281
282int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
283 struct symsrc *ss __maybe_unused,
284 struct map *map __maybe_unused,
285 symbol_filter_t filter __maybe_unused)
286{
287 return 0;
288}
289
290int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
291 struct symsrc *ss,
292 struct symsrc *runtime_ss __maybe_unused,
293 symbol_filter_t filter __maybe_unused,
294 int kmodule __maybe_unused)
295{
296 unsigned char *build_id[BUILD_ID_SIZE];
297
298 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
299 dso__set_build_id(dso, build_id);
300 return 1;
301 }
302 return 0;
303}
304
305void symbol__elf_init(void)
306{
307}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 295f8d4feed..40eeaf07725 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,5 +1,8 @@
1#define _GNU_SOURCE
2#include <ctype.h>
1#include <dirent.h> 3#include <dirent.h>
2#include <errno.h> 4#include <errno.h>
5#include <libgen.h>
3#include <stdlib.h> 6#include <stdlib.h>
4#include <stdio.h> 7#include <stdio.h>
5#include <string.h> 8#include <string.h>
@@ -10,20 +13,28 @@
10#include <unistd.h> 13#include <unistd.h>
11#include <inttypes.h> 14#include <inttypes.h>
12#include "build-id.h" 15#include "build-id.h"
13#include "util.h"
14#include "debug.h" 16#include "debug.h"
15#include "machine.h"
16#include "symbol.h" 17#include "symbol.h"
17#include "strlist.h" 18#include "strlist.h"
18 19
20#include <libelf.h>
21#include <gelf.h>
19#include <elf.h> 22#include <elf.h>
20#include <limits.h> 23#include <limits.h>
21#include <sys/utsname.h> 24#include <sys/utsname.h>
22 25
23#ifndef KSYM_NAME_LEN 26#ifndef KSYM_NAME_LEN
24#define KSYM_NAME_LEN 256 27#define KSYM_NAME_LEN 128
25#endif 28#endif
26 29
30#ifndef NT_GNU_BUILD_ID
31#define NT_GNU_BUILD_ID 3
32#endif
33
34static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
35static int elf_read_build_id(Elf *elf, void *bf, size_t size);
36static void dsos__add(struct list_head *head, struct dso *dso);
37static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
27static int dso__load_kernel_sym(struct dso *dso, struct map *map, 38static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 39 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 40static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
@@ -35,26 +46,31 @@ struct symbol_conf symbol_conf = {
35 .exclude_other = true, 46 .exclude_other = true,
36 .use_modules = true, 47 .use_modules = true,
37 .try_vmlinux_path = true, 48 .try_vmlinux_path = true,
38 .annotate_src = true,
39 .symfs = "", 49 .symfs = "",
40}; 50};
41 51
42static enum dso_binary_type binary_type_symtab[] = { 52int dso__name_len(const struct dso *dso)
43 DSO_BINARY_TYPE__KALLSYMS, 53{
44 DSO_BINARY_TYPE__GUEST_KALLSYMS, 54 if (verbose)
45 DSO_BINARY_TYPE__JAVA_JIT, 55 return dso->long_name_len;
46 DSO_BINARY_TYPE__DEBUGLINK,
47 DSO_BINARY_TYPE__BUILD_ID_CACHE,
48 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
49 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
50 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
51 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
52 DSO_BINARY_TYPE__GUEST_KMODULE,
53 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
54 DSO_BINARY_TYPE__NOT_FOUND,
55};
56 56
57#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 57 return dso->short_name_len;
58}
59
60bool dso__loaded(const struct dso *dso, enum map_type type)
61{
62 return dso->loaded & (1 << type);
63}
64
65bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
66{
67 return dso->sorted_by_name & (1 << type);
68}
69
70static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
71{
72 dso->sorted_by_name |= (1 << type);
73}
58 74
59bool symbol_type__is_a(char symbol_type, enum map_type map_type) 75bool symbol_type__is_a(char symbol_type, enum map_type map_type)
60{ 76{
@@ -127,7 +143,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb)
127 return SYMBOL_B; 143 return SYMBOL_B;
128} 144}
129 145
130void symbols__fixup_duplicate(struct rb_root *symbols) 146static void symbols__fixup_duplicate(struct rb_root *symbols)
131{ 147{
132 struct rb_node *nd; 148 struct rb_node *nd;
133 struct symbol *curr, *next; 149 struct symbol *curr, *next;
@@ -156,7 +172,7 @@ again:
156 } 172 }
157} 173}
158 174
159void symbols__fixup_end(struct rb_root *symbols) 175static void symbols__fixup_end(struct rb_root *symbols)
160{ 176{
161 struct rb_node *nd, *prevnd = rb_first(symbols); 177 struct rb_node *nd, *prevnd = rb_first(symbols);
162 struct symbol *curr, *prev; 178 struct symbol *curr, *prev;
@@ -179,7 +195,7 @@ void symbols__fixup_end(struct rb_root *symbols)
179 curr->end = roundup(curr->start, 4096); 195 curr->end = roundup(curr->start, 4096);
180} 196}
181 197
182void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 198static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
183{ 199{
184 struct map *prev, *curr; 200 struct map *prev, *curr;
185 struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); 201 struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]);
@@ -209,7 +225,8 @@ static void map_groups__fixup_end(struct map_groups *mg)
209 __map_groups__fixup_end(mg, i); 225 __map_groups__fixup_end(mg, i);
210} 226}
211 227
212struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 228static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
229 const char *name)
213{ 230{
214 size_t namelen = strlen(name) + 1; 231 size_t namelen = strlen(name) + 1;
215 struct symbol *sym = calloc(1, (symbol_conf.priv_size + 232 struct symbol *sym = calloc(1, (symbol_conf.priv_size +
@@ -237,7 +254,7 @@ void symbol__delete(struct symbol *sym)
237 free(((void *)sym) - symbol_conf.priv_size); 254 free(((void *)sym) - symbol_conf.priv_size);
238} 255}
239 256
240size_t symbol__fprintf(struct symbol *sym, FILE *fp) 257static size_t symbol__fprintf(struct symbol *sym, FILE *fp)
241{ 258{
242 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 259 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
243 sym->start, sym->end, 260 sym->start, sym->end,
@@ -246,29 +263,50 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp)
246 sym->name); 263 sym->name);
247} 264}
248 265
249size_t symbol__fprintf_symname_offs(const struct symbol *sym, 266void dso__set_long_name(struct dso *dso, char *name)
250 const struct addr_location *al, FILE *fp)
251{ 267{
252 unsigned long offset; 268 if (name == NULL)
253 size_t length; 269 return;
270 dso->long_name = name;
271 dso->long_name_len = strlen(name);
272}
254 273
255 if (sym && sym->name) { 274static void dso__set_short_name(struct dso *dso, const char *name)
256 length = fprintf(fp, "%s", sym->name); 275{
257 if (al) { 276 if (name == NULL)
258 offset = al->addr - sym->start; 277 return;
259 length += fprintf(fp, "+0x%lx", offset); 278 dso->short_name = name;
260 } 279 dso->short_name_len = strlen(name);
261 return length;
262 } else
263 return fprintf(fp, "[unknown]");
264} 280}
265 281
266size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 282static void dso__set_basename(struct dso *dso)
267{ 283{
268 return symbol__fprintf_symname_offs(sym, NULL, fp); 284 dso__set_short_name(dso, basename(dso->long_name));
269} 285}
270 286
271void symbols__delete(struct rb_root *symbols) 287struct dso *dso__new(const char *name)
288{
289 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
290
291 if (dso != NULL) {
292 int i;
293 strcpy(dso->name, name);
294 dso__set_long_name(dso, dso->name);
295 dso__set_short_name(dso, dso->name);
296 for (i = 0; i < MAP__NR_TYPES; ++i)
297 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
298 dso->symtab_type = SYMTAB__NOT_FOUND;
299 dso->loaded = 0;
300 dso->sorted_by_name = 0;
301 dso->has_build_id = 0;
302 dso->kernel = DSO_TYPE_USER;
303 INIT_LIST_HEAD(&dso->node);
304 }
305
306 return dso;
307}
308
309static void symbols__delete(struct rb_root *symbols)
272{ 310{
273 struct symbol *pos; 311 struct symbol *pos;
274 struct rb_node *next = rb_first(symbols); 312 struct rb_node *next = rb_first(symbols);
@@ -281,7 +319,25 @@ void symbols__delete(struct rb_root *symbols)
281 } 319 }
282} 320}
283 321
284void symbols__insert(struct rb_root *symbols, struct symbol *sym) 322void dso__delete(struct dso *dso)
323{
324 int i;
325 for (i = 0; i < MAP__NR_TYPES; ++i)
326 symbols__delete(&dso->symbols[i]);
327 if (dso->sname_alloc)
328 free((char *)dso->short_name);
329 if (dso->lname_alloc)
330 free(dso->long_name);
331 free(dso);
332}
333
334void dso__set_build_id(struct dso *dso, void *build_id)
335{
336 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
337 dso->has_build_id = 1;
338}
339
340static void symbols__insert(struct rb_root *symbols, struct symbol *sym)
285{ 341{
286 struct rb_node **p = &symbols->rb_node; 342 struct rb_node **p = &symbols->rb_node;
287 struct rb_node *parent = NULL; 343 struct rb_node *parent = NULL;
@@ -406,6 +462,29 @@ void dso__sort_by_name(struct dso *dso, enum map_type type)
406 &dso->symbols[type]); 462 &dso->symbols[type]);
407} 463}
408 464
465int build_id__sprintf(const u8 *build_id, int len, char *bf)
466{
467 char *bid = bf;
468 const u8 *raw = build_id;
469 int i;
470
471 for (i = 0; i < len; ++i) {
472 sprintf(bid, "%02x", *raw);
473 ++raw;
474 bid += 2;
475 }
476
477 return raw - build_id;
478}
479
480size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
481{
482 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
483
484 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
485 return fprintf(fp, "%s", sbuild_id);
486}
487
409size_t dso__fprintf_symbols_by_name(struct dso *dso, 488size_t dso__fprintf_symbols_by_name(struct dso *dso,
410 enum map_type type, FILE *fp) 489 enum map_type type, FILE *fp)
411{ 490{
@@ -421,9 +500,28 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
421 return ret; 500 return ret;
422} 501}
423 502
503size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
504{
505 struct rb_node *nd;
506 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
507
508 if (dso->short_name != dso->long_name)
509 ret += fprintf(fp, "%s, ", dso->long_name);
510 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
511 dso->loaded ? "" : "NOT ");
512 ret += dso__fprintf_buildid(dso, fp);
513 ret += fprintf(fp, ")\n");
514 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
515 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
516 ret += symbol__fprintf(pos, fp);
517 }
518
519 return ret;
520}
521
424int kallsyms__parse(const char *filename, void *arg, 522int kallsyms__parse(const char *filename, void *arg,
425 int (*process_symbol)(void *arg, const char *name, 523 int (*process_symbol)(void *arg, const char *name,
426 char type, u64 start)) 524 char type, u64 start, u64 end))
427{ 525{
428 char *line = NULL; 526 char *line = NULL;
429 size_t n; 527 size_t n;
@@ -463,8 +561,13 @@ int kallsyms__parse(const char *filename, void *arg,
463 break; 561 break;
464 } 562 }
465 563
564 /*
565 * module symbols are not sorted so we add all
566 * symbols with zero length and rely on
567 * symbols__fixup_end() to fix it up.
568 */
466 err = process_symbol(arg, symbol_name, 569 err = process_symbol(arg, symbol_name,
467 symbol_type, start); 570 symbol_type, start, start);
468 if (err) 571 if (err)
469 break; 572 break;
470 } 573 }
@@ -491,7 +594,7 @@ static u8 kallsyms2elf_type(char type)
491} 594}
492 595
493static int map__process_kallsym_symbol(void *arg, const char *name, 596static int map__process_kallsym_symbol(void *arg, const char *name,
494 char type, u64 start) 597 char type, u64 start, u64 end)
495{ 598{
496 struct symbol *sym; 599 struct symbol *sym;
497 struct process_kallsyms_args *a = arg; 600 struct process_kallsyms_args *a = arg;
@@ -500,12 +603,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
500 if (!symbol_type__is_a(type, a->map->type)) 603 if (!symbol_type__is_a(type, a->map->type))
501 return 0; 604 return 0;
502 605
503 /* 606 sym = symbol__new(start, end - start + 1,
504 * module symbols are not sorted so we add all 607 kallsyms2elf_type(type), name);
505 * symbols, setting length to 0, and rely on
506 * symbols__fixup_end() to fix it up.
507 */
508 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
509 if (sym == NULL) 608 if (sym == NULL)
510 return -ENOMEM; 609 return -ENOMEM;
511 /* 610 /*
@@ -683,9 +782,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
683 symbols__fixup_end(&dso->symbols[map->type]); 782 symbols__fixup_end(&dso->symbols[map->type]);
684 783
685 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 784 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
686 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 785 dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
687 else 786 else
688 dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 787 dso->symtab_type = SYMTAB__KALLSYMS;
689 788
690 return dso__split_kallsyms(dso, map, filter); 789 return dso__split_kallsyms(dso, map, filter);
691} 790}
@@ -752,16 +851,722 @@ out_failure:
752 return -1; 851 return -1;
753} 852}
754 853
854/**
855 * elf_symtab__for_each_symbol - iterate thru all the symbols
856 *
857 * @syms: struct elf_symtab instance to iterate
858 * @idx: uint32_t idx
859 * @sym: GElf_Sym iterator
860 */
861#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
862 for (idx = 0, gelf_getsym(syms, idx, &sym);\
863 idx < nr_syms; \
864 idx++, gelf_getsym(syms, idx, &sym))
865
866static inline uint8_t elf_sym__type(const GElf_Sym *sym)
867{
868 return GELF_ST_TYPE(sym->st_info);
869}
870
871static inline int elf_sym__is_function(const GElf_Sym *sym)
872{
873 return elf_sym__type(sym) == STT_FUNC &&
874 sym->st_name != 0 &&
875 sym->st_shndx != SHN_UNDEF;
876}
877
878static inline bool elf_sym__is_object(const GElf_Sym *sym)
879{
880 return elf_sym__type(sym) == STT_OBJECT &&
881 sym->st_name != 0 &&
882 sym->st_shndx != SHN_UNDEF;
883}
884
885static inline int elf_sym__is_label(const GElf_Sym *sym)
886{
887 return elf_sym__type(sym) == STT_NOTYPE &&
888 sym->st_name != 0 &&
889 sym->st_shndx != SHN_UNDEF &&
890 sym->st_shndx != SHN_ABS;
891}
892
893static inline const char *elf_sec__name(const GElf_Shdr *shdr,
894 const Elf_Data *secstrs)
895{
896 return secstrs->d_buf + shdr->sh_name;
897}
898
899static inline int elf_sec__is_text(const GElf_Shdr *shdr,
900 const Elf_Data *secstrs)
901{
902 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
903}
904
905static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
906 const Elf_Data *secstrs)
907{
908 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
909}
910
911static inline const char *elf_sym__name(const GElf_Sym *sym,
912 const Elf_Data *symstrs)
913{
914 return symstrs->d_buf + sym->st_name;
915}
916
917static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
918 GElf_Shdr *shp, const char *name,
919 size_t *idx)
920{
921 Elf_Scn *sec = NULL;
922 size_t cnt = 1;
923
924 while ((sec = elf_nextscn(elf, sec)) != NULL) {
925 char *str;
926
927 gelf_getshdr(sec, shp);
928 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
929 if (!strcmp(name, str)) {
930 if (idx)
931 *idx = cnt;
932 break;
933 }
934 ++cnt;
935 }
936
937 return sec;
938}
939
940#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
941 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
942 idx < nr_entries; \
943 ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
944
945#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
946 for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
947 idx < nr_entries; \
948 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
949
950/*
951 * We need to check if we have a .dynsym, so that we can handle the
952 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
953 * .dynsym or .symtab).
954 * And always look at the original dso, not at debuginfo packages, that
955 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
956 */
957static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
958 symbol_filter_t filter)
959{
960 uint32_t nr_rel_entries, idx;
961 GElf_Sym sym;
962 u64 plt_offset;
963 GElf_Shdr shdr_plt;
964 struct symbol *f;
965 GElf_Shdr shdr_rel_plt, shdr_dynsym;
966 Elf_Data *reldata, *syms, *symstrs;
967 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
968 size_t dynsym_idx;
969 GElf_Ehdr ehdr;
970 char sympltname[1024];
971 Elf *elf;
972 int nr = 0, symidx, fd, err = 0;
973 char name[PATH_MAX];
974
975 snprintf(name, sizeof(name), "%s%s",
976 symbol_conf.symfs, dso->long_name);
977 fd = open(name, O_RDONLY);
978 if (fd < 0)
979 goto out;
980
981 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
982 if (elf == NULL)
983 goto out_close;
984
985 if (gelf_getehdr(elf, &ehdr) == NULL)
986 goto out_elf_end;
987
988 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
989 ".dynsym", &dynsym_idx);
990 if (scn_dynsym == NULL)
991 goto out_elf_end;
992
993 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
994 ".rela.plt", NULL);
995 if (scn_plt_rel == NULL) {
996 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
997 ".rel.plt", NULL);
998 if (scn_plt_rel == NULL)
999 goto out_elf_end;
1000 }
1001
1002 err = -1;
1003
1004 if (shdr_rel_plt.sh_link != dynsym_idx)
1005 goto out_elf_end;
1006
1007 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
1008 goto out_elf_end;
1009
1010 /*
1011 * Fetch the relocation section to find the idxes to the GOT
1012 * and the symbols in the .dynsym they refer to.
1013 */
1014 reldata = elf_getdata(scn_plt_rel, NULL);
1015 if (reldata == NULL)
1016 goto out_elf_end;
1017
1018 syms = elf_getdata(scn_dynsym, NULL);
1019 if (syms == NULL)
1020 goto out_elf_end;
1021
1022 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
1023 if (scn_symstrs == NULL)
1024 goto out_elf_end;
1025
1026 symstrs = elf_getdata(scn_symstrs, NULL);
1027 if (symstrs == NULL)
1028 goto out_elf_end;
1029
1030 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
1031 plt_offset = shdr_plt.sh_offset;
1032
1033 if (shdr_rel_plt.sh_type == SHT_RELA) {
1034 GElf_Rela pos_mem, *pos;
1035
1036 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
1037 nr_rel_entries) {
1038 symidx = GELF_R_SYM(pos->r_info);
1039 plt_offset += shdr_plt.sh_entsize;
1040 gelf_getsym(syms, symidx, &sym);
1041 snprintf(sympltname, sizeof(sympltname),
1042 "%s@plt", elf_sym__name(&sym, symstrs));
1043
1044 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
1045 STB_GLOBAL, sympltname);
1046 if (!f)
1047 goto out_elf_end;
1048
1049 if (filter && filter(map, f))
1050 symbol__delete(f);
1051 else {
1052 symbols__insert(&dso->symbols[map->type], f);
1053 ++nr;
1054 }
1055 }
1056 } else if (shdr_rel_plt.sh_type == SHT_REL) {
1057 GElf_Rel pos_mem, *pos;
1058 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
1059 nr_rel_entries) {
1060 symidx = GELF_R_SYM(pos->r_info);
1061 plt_offset += shdr_plt.sh_entsize;
1062 gelf_getsym(syms, symidx, &sym);
1063 snprintf(sympltname, sizeof(sympltname),
1064 "%s@plt", elf_sym__name(&sym, symstrs));
1065
1066 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
1067 STB_GLOBAL, sympltname);
1068 if (!f)
1069 goto out_elf_end;
1070
1071 if (filter && filter(map, f))
1072 symbol__delete(f);
1073 else {
1074 symbols__insert(&dso->symbols[map->type], f);
1075 ++nr;
1076 }
1077 }
1078 }
1079
1080 err = 0;
1081out_elf_end:
1082 elf_end(elf);
1083out_close:
1084 close(fd);
1085
1086 if (err == 0)
1087 return nr;
1088out:
1089 pr_debug("%s: problems reading %s PLT info.\n",
1090 __func__, dso->long_name);
1091 return 0;
1092}
1093
1094static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
1095{
1096 switch (type) {
1097 case MAP__FUNCTION:
1098 return elf_sym__is_function(sym);
1099 case MAP__VARIABLE:
1100 return elf_sym__is_object(sym);
1101 default:
1102 return false;
1103 }
1104}
1105
1106static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
1107 enum map_type type)
1108{
1109 switch (type) {
1110 case MAP__FUNCTION:
1111 return elf_sec__is_text(shdr, secstrs);
1112 case MAP__VARIABLE:
1113 return elf_sec__is_data(shdr, secstrs);
1114 default:
1115 return false;
1116 }
1117}
1118
1119static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
1120{
1121 Elf_Scn *sec = NULL;
1122 GElf_Shdr shdr;
1123 size_t cnt = 1;
1124
1125 while ((sec = elf_nextscn(elf, sec)) != NULL) {
1126 gelf_getshdr(sec, &shdr);
1127
1128 if ((addr >= shdr.sh_addr) &&
1129 (addr < (shdr.sh_addr + shdr.sh_size)))
1130 return cnt;
1131
1132 ++cnt;
1133 }
1134
1135 return -1;
1136}
1137
1138static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1139 int fd, symbol_filter_t filter, int kmodule,
1140 int want_symtab)
1141{
1142 struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
1143 struct map *curr_map = map;
1144 struct dso *curr_dso = dso;
1145 Elf_Data *symstrs, *secstrs;
1146 uint32_t nr_syms;
1147 int err = -1;
1148 uint32_t idx;
1149 GElf_Ehdr ehdr;
1150 GElf_Shdr shdr, opdshdr;
1151 Elf_Data *syms, *opddata = NULL;
1152 GElf_Sym sym;
1153 Elf_Scn *sec, *sec_strndx, *opdsec;
1154 Elf *elf;
1155 int nr = 0;
1156 size_t opdidx = 0;
1157
1158 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1159 if (elf == NULL) {
1160 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
1161 goto out_close;
1162 }
1163
1164 if (gelf_getehdr(elf, &ehdr) == NULL) {
1165 pr_debug("%s: cannot get elf header.\n", __func__);
1166 goto out_elf_end;
1167 }
1168
1169 /* Always reject images with a mismatched build-id: */
1170 if (dso->has_build_id) {
1171 u8 build_id[BUILD_ID_SIZE];
1172
1173 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
1174 goto out_elf_end;
1175
1176 if (!dso__build_id_equal(dso, build_id))
1177 goto out_elf_end;
1178 }
1179
1180 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
1181 if (sec == NULL) {
1182 if (want_symtab)
1183 goto out_elf_end;
1184
1185 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1186 if (sec == NULL)
1187 goto out_elf_end;
1188 }
1189
1190 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1191 if (opdshdr.sh_type != SHT_PROGBITS)
1192 opdsec = NULL;
1193 if (opdsec)
1194 opddata = elf_rawdata(opdsec, NULL);
1195
1196 syms = elf_getdata(sec, NULL);
1197 if (syms == NULL)
1198 goto out_elf_end;
1199
1200 sec = elf_getscn(elf, shdr.sh_link);
1201 if (sec == NULL)
1202 goto out_elf_end;
1203
1204 symstrs = elf_getdata(sec, NULL);
1205 if (symstrs == NULL)
1206 goto out_elf_end;
1207
1208 sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
1209 if (sec_strndx == NULL)
1210 goto out_elf_end;
1211
1212 secstrs = elf_getdata(sec_strndx, NULL);
1213 if (secstrs == NULL)
1214 goto out_elf_end;
1215
1216 nr_syms = shdr.sh_size / shdr.sh_entsize;
1217
1218 memset(&sym, 0, sizeof(sym));
1219 if (dso->kernel == DSO_TYPE_USER) {
1220 dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
1221 elf_section_by_name(elf, &ehdr, &shdr,
1222 ".gnu.prelink_undo",
1223 NULL) != NULL);
1224 } else {
1225 dso->adjust_symbols = 0;
1226 }
1227 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
1228 struct symbol *f;
1229 const char *elf_name = elf_sym__name(&sym, symstrs);
1230 char *demangled = NULL;
1231 int is_label = elf_sym__is_label(&sym);
1232 const char *section_name;
1233
1234 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
1235 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
1236 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
1237
1238 if (!is_label && !elf_sym__is_a(&sym, map->type))
1239 continue;
1240
1241 /* Reject ARM ELF "mapping symbols": these aren't unique and
1242 * don't identify functions, so will confuse the profile
1243 * output: */
1244 if (ehdr.e_machine == EM_ARM) {
1245 if (!strcmp(elf_name, "$a") ||
1246 !strcmp(elf_name, "$d") ||
1247 !strcmp(elf_name, "$t"))
1248 continue;
1249 }
1250
1251 if (opdsec && sym.st_shndx == opdidx) {
1252 u32 offset = sym.st_value - opdshdr.sh_addr;
1253 u64 *opd = opddata->d_buf + offset;
1254 sym.st_value = *opd;
1255 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1256 }
1257
1258 sec = elf_getscn(elf, sym.st_shndx);
1259 if (!sec)
1260 goto out_elf_end;
1261
1262 gelf_getshdr(sec, &shdr);
1263
1264 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
1265 continue;
1266
1267 section_name = elf_sec__name(&shdr, secstrs);
1268
1269 /* On ARM, symbols for thumb functions have 1 added to
1270 * the symbol address as a flag - remove it */
1271 if ((ehdr.e_machine == EM_ARM) &&
1272 (map->type == MAP__FUNCTION) &&
1273 (sym.st_value & 1))
1274 --sym.st_value;
1275
1276 if (dso->kernel != DSO_TYPE_USER || kmodule) {
1277 char dso_name[PATH_MAX];
1278
1279 if (strcmp(section_name,
1280 (curr_dso->short_name +
1281 dso->short_name_len)) == 0)
1282 goto new_symbol;
1283
1284 if (strcmp(section_name, ".text") == 0) {
1285 curr_map = map;
1286 curr_dso = dso;
1287 goto new_symbol;
1288 }
1289
1290 snprintf(dso_name, sizeof(dso_name),
1291 "%s%s", dso->short_name, section_name);
1292
1293 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
1294 if (curr_map == NULL) {
1295 u64 start = sym.st_value;
1296
1297 if (kmodule)
1298 start += map->start + shdr.sh_offset;
1299
1300 curr_dso = dso__new(dso_name);
1301 if (curr_dso == NULL)
1302 goto out_elf_end;
1303 curr_dso->kernel = dso->kernel;
1304 curr_dso->long_name = dso->long_name;
1305 curr_dso->long_name_len = dso->long_name_len;
1306 curr_map = map__new2(start, curr_dso,
1307 map->type);
1308 if (curr_map == NULL) {
1309 dso__delete(curr_dso);
1310 goto out_elf_end;
1311 }
1312 curr_map->map_ip = identity__map_ip;
1313 curr_map->unmap_ip = identity__map_ip;
1314 curr_dso->symtab_type = dso->symtab_type;
1315 map_groups__insert(kmap->kmaps, curr_map);
1316 dsos__add(&dso->node, curr_dso);
1317 dso__set_loaded(curr_dso, map->type);
1318 } else
1319 curr_dso = curr_map->dso;
1320
1321 goto new_symbol;
1322 }
1323
1324 if (curr_dso->adjust_symbols) {
1325 pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
1326 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
1327 (u64)sym.st_value, (u64)shdr.sh_addr,
1328 (u64)shdr.sh_offset);
1329 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1330 }
1331 /*
1332 * We need to figure out if the object was created from C++ sources
1333 * DWARF DW_compile_unit has this, but we don't always have access
1334 * to it...
1335 */
1336 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
1337 if (demangled != NULL)
1338 elf_name = demangled;
1339new_symbol:
1340 f = symbol__new(sym.st_value, sym.st_size,
1341 GELF_ST_BIND(sym.st_info), elf_name);
1342 free(demangled);
1343 if (!f)
1344 goto out_elf_end;
1345
1346 if (filter && filter(curr_map, f))
1347 symbol__delete(f);
1348 else {
1349 symbols__insert(&curr_dso->symbols[curr_map->type], f);
1350 nr++;
1351 }
1352 }
1353
1354 /*
1355 * For misannotated, zeroed, ASM function sizes.
1356 */
1357 if (nr > 0) {
1358 symbols__fixup_duplicate(&dso->symbols[map->type]);
1359 symbols__fixup_end(&dso->symbols[map->type]);
1360 if (kmap) {
1361 /*
1362 * We need to fixup this here too because we create new
1363 * maps here, for things like vsyscall sections.
1364 */
1365 __map_groups__fixup_end(kmap->kmaps, map->type);
1366 }
1367 }
1368 err = nr;
1369out_elf_end:
1370 elf_end(elf);
1371out_close:
1372 return err;
1373}
1374
1375static bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
1376{
1377 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
1378}
1379
1380bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1381{
1382 bool have_build_id = false;
1383 struct dso *pos;
1384
1385 list_for_each_entry(pos, head, node) {
1386 if (with_hits && !pos->hit)
1387 continue;
1388 if (pos->has_build_id) {
1389 have_build_id = true;
1390 continue;
1391 }
1392 if (filename__read_build_id(pos->long_name, pos->build_id,
1393 sizeof(pos->build_id)) > 0) {
1394 have_build_id = true;
1395 pos->has_build_id = true;
1396 }
1397 }
1398
1399 return have_build_id;
1400}
1401
1402/*
1403 * Align offset to 4 bytes as needed for note name and descriptor data.
1404 */
1405#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1406
1407static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1408{
1409 int err = -1;
1410 GElf_Ehdr ehdr;
1411 GElf_Shdr shdr;
1412 Elf_Data *data;
1413 Elf_Scn *sec;
1414 Elf_Kind ek;
1415 void *ptr;
1416
1417 if (size < BUILD_ID_SIZE)
1418 goto out;
1419
1420 ek = elf_kind(elf);
1421 if (ek != ELF_K_ELF)
1422 goto out;
1423
1424 if (gelf_getehdr(elf, &ehdr) == NULL) {
1425 pr_err("%s: cannot get elf header.\n", __func__);
1426 goto out;
1427 }
1428
1429 sec = elf_section_by_name(elf, &ehdr, &shdr,
1430 ".note.gnu.build-id", NULL);
1431 if (sec == NULL) {
1432 sec = elf_section_by_name(elf, &ehdr, &shdr,
1433 ".notes", NULL);
1434 if (sec == NULL)
1435 goto out;
1436 }
1437
1438 data = elf_getdata(sec, NULL);
1439 if (data == NULL)
1440 goto out;
1441
1442 ptr = data->d_buf;
1443 while (ptr < (data->d_buf + data->d_size)) {
1444 GElf_Nhdr *nhdr = ptr;
1445 size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
1446 descsz = NOTE_ALIGN(nhdr->n_descsz);
1447 const char *name;
1448
1449 ptr += sizeof(*nhdr);
1450 name = ptr;
1451 ptr += namesz;
1452 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1453 nhdr->n_namesz == sizeof("GNU")) {
1454 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1455 size_t sz = min(size, descsz);
1456 memcpy(bf, ptr, sz);
1457 memset(bf + sz, 0, size - sz);
1458 err = descsz;
1459 break;
1460 }
1461 }
1462 ptr += descsz;
1463 }
1464
1465out:
1466 return err;
1467}
1468
1469int filename__read_build_id(const char *filename, void *bf, size_t size)
1470{
1471 int fd, err = -1;
1472 Elf *elf;
1473
1474 if (size < BUILD_ID_SIZE)
1475 goto out;
1476
1477 fd = open(filename, O_RDONLY);
1478 if (fd < 0)
1479 goto out;
1480
1481 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1482 if (elf == NULL) {
1483 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1484 goto out_close;
1485 }
1486
1487 err = elf_read_build_id(elf, bf, size);
1488
1489 elf_end(elf);
1490out_close:
1491 close(fd);
1492out:
1493 return err;
1494}
1495
1496int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1497{
1498 int fd, err = -1;
1499
1500 if (size < BUILD_ID_SIZE)
1501 goto out;
1502
1503 fd = open(filename, O_RDONLY);
1504 if (fd < 0)
1505 goto out;
1506
1507 while (1) {
1508 char bf[BUFSIZ];
1509 GElf_Nhdr nhdr;
1510 size_t namesz, descsz;
1511
1512 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1513 break;
1514
1515 namesz = NOTE_ALIGN(nhdr.n_namesz);
1516 descsz = NOTE_ALIGN(nhdr.n_descsz);
1517 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1518 nhdr.n_namesz == sizeof("GNU")) {
1519 if (read(fd, bf, namesz) != (ssize_t)namesz)
1520 break;
1521 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1522 size_t sz = min(descsz, size);
1523 if (read(fd, build_id, sz) == (ssize_t)sz) {
1524 memset(build_id + sz, 0, size - sz);
1525 err = 0;
1526 break;
1527 }
1528 } else if (read(fd, bf, descsz) != (ssize_t)descsz)
1529 break;
1530 } else {
1531 int n = namesz + descsz;
1532 if (read(fd, bf, n) != n)
1533 break;
1534 }
1535 }
1536 close(fd);
1537out:
1538 return err;
1539}
1540
1541char dso__symtab_origin(const struct dso *dso)
1542{
1543 static const char origin[] = {
1544 [SYMTAB__KALLSYMS] = 'k',
1545 [SYMTAB__JAVA_JIT] = 'j',
1546 [SYMTAB__BUILD_ID_CACHE] = 'B',
1547 [SYMTAB__FEDORA_DEBUGINFO] = 'f',
1548 [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
1549 [SYMTAB__BUILDID_DEBUGINFO] = 'b',
1550 [SYMTAB__SYSTEM_PATH_DSO] = 'd',
1551 [SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
1552 [SYMTAB__GUEST_KALLSYMS] = 'g',
1553 [SYMTAB__GUEST_KMODULE] = 'G',
1554 };
1555
1556 if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND)
1557 return '!';
1558 return origin[dso->symtab_type];
1559}
1560
755int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 1561int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
756{ 1562{
1563 int size = PATH_MAX;
757 char *name; 1564 char *name;
758 int ret = -1; 1565 int ret = -1;
759 u_int i; 1566 int fd;
760 struct machine *machine; 1567 struct machine *machine;
761 char *root_dir = (char *) ""; 1568 const char *root_dir;
762 int ss_pos = 0; 1569 int want_symtab;
763 struct symsrc ss_[2];
764 struct symsrc *syms_ss = NULL, *runtime_ss = NULL;
765 1570
766 dso__set_loaded(dso, map->type); 1571 dso__set_loaded(dso, map->type);
767 1572
@@ -775,7 +1580,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
775 else 1580 else
776 machine = NULL; 1581 machine = NULL;
777 1582
778 name = malloc(PATH_MAX); 1583 name = malloc(size);
779 if (!name) 1584 if (!name)
780 return -1; 1585 return -1;
781 1586
@@ -794,78 +1599,104 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
794 } 1599 }
795 1600
796 ret = dso__load_perf_map(dso, map, filter); 1601 ret = dso__load_perf_map(dso, map, filter);
797 dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 1602 dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
798 DSO_BINARY_TYPE__NOT_FOUND; 1603 SYMTAB__NOT_FOUND;
799 return ret; 1604 return ret;
800 } 1605 }
801 1606
802 if (machine)
803 root_dir = machine->root_dir;
804
805 /* Iterate over candidate debug images. 1607 /* Iterate over candidate debug images.
806 * Keep track of "interesting" ones (those which have a symtab, dynsym, 1608 * On the first pass, only load images if they have a full symtab.
807 * and/or opd section) for processing. 1609 * Failing that, do a second pass where we accept .dynsym also
808 */ 1610 */
809 for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 1611 want_symtab = 1;
810 struct symsrc *ss = &ss_[ss_pos]; 1612restart:
811 bool next_slot = false; 1613 for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE;
1614 dso->symtab_type != SYMTAB__NOT_FOUND;
1615 dso->symtab_type++) {
1616 switch (dso->symtab_type) {
1617 case SYMTAB__BUILD_ID_CACHE:
1618 /* skip the locally configured cache if a symfs is given */
1619 if (symbol_conf.symfs[0] ||
1620 (dso__build_id_filename(dso, name, size) == NULL)) {
1621 continue;
1622 }
1623 break;
1624 case SYMTAB__FEDORA_DEBUGINFO:
1625 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1626 symbol_conf.symfs, dso->long_name);
1627 break;
1628 case SYMTAB__UBUNTU_DEBUGINFO:
1629 snprintf(name, size, "%s/usr/lib/debug%s",
1630 symbol_conf.symfs, dso->long_name);
1631 break;
1632 case SYMTAB__BUILDID_DEBUGINFO: {
1633 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
812 1634
813 enum dso_binary_type symtab_type = binary_type_symtab[i]; 1635 if (!dso->has_build_id)
1636 continue;
814 1637
815 if (dso__binary_type_file(dso, symtab_type, 1638 build_id__sprintf(dso->build_id,
816 root_dir, name, PATH_MAX)) 1639 sizeof(dso->build_id),
817 continue; 1640 build_id_hex);
1641 snprintf(name, size,
1642 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1643 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1644 }
1645 break;
1646 case SYMTAB__SYSTEM_PATH_DSO:
1647 snprintf(name, size, "%s%s",
1648 symbol_conf.symfs, dso->long_name);
1649 break;
1650 case SYMTAB__GUEST_KMODULE:
1651 if (map->groups && machine)
1652 root_dir = machine->root_dir;
1653 else
1654 root_dir = "";
1655 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1656 root_dir, dso->long_name);
1657 break;
1658
1659 case SYMTAB__SYSTEM_PATH_KMODULE:
1660 snprintf(name, size, "%s%s", symbol_conf.symfs,
1661 dso->long_name);
1662 break;
1663 default:;
1664 }
818 1665
819 /* Name is now the name of the next image to try */ 1666 /* Name is now the name of the next image to try */
820 if (symsrc__init(ss, dso, name, symtab_type) < 0) 1667 fd = open(name, O_RDONLY);
1668 if (fd < 0)
821 continue; 1669 continue;
822 1670
823 if (!syms_ss && symsrc__has_symtab(ss)) { 1671 ret = dso__load_sym(dso, map, name, fd, filter, 0,
824 syms_ss = ss; 1672 want_symtab);
825 next_slot = true; 1673 close(fd);
826 }
827
828 if (!runtime_ss && symsrc__possibly_runtime(ss)) {
829 runtime_ss = ss;
830 next_slot = true;
831 }
832 1674
833 if (next_slot) { 1675 /*
834 ss_pos++; 1676 * Some people seem to have debuginfo files _WITHOUT_ debug
1677 * info!?!?
1678 */
1679 if (!ret)
1680 continue;
835 1681
836 if (syms_ss && runtime_ss) 1682 if (ret > 0) {
837 break; 1683 int nr_plt = dso__synthesize_plt_symbols(dso, map,
1684 filter);
1685 if (nr_plt > 0)
1686 ret += nr_plt;
1687 break;
838 } 1688 }
839
840 }
841
842 if (!runtime_ss && !syms_ss)
843 goto out_free;
844
845 if (runtime_ss && !syms_ss) {
846 syms_ss = runtime_ss;
847 } 1689 }
848 1690
849 /* We'll have to hope for the best */ 1691 /*
850 if (!runtime_ss && syms_ss) 1692 * If we wanted a full symtab but no image had one,
851 runtime_ss = syms_ss; 1693 * relax our requirements and repeat the search.
852 1694 */
853 if (syms_ss) 1695 if (ret <= 0 && want_symtab) {
854 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0); 1696 want_symtab = 0;
855 else 1697 goto restart;
856 ret = -1;
857
858 if (ret > 0) {
859 int nr_plt;
860
861 nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter);
862 if (nr_plt > 0)
863 ret += nr_plt;
864 } 1698 }
865 1699
866 for (; ss_pos > 0; ss_pos--)
867 symsrc__destroy(&ss_[ss_pos - 1]);
868out_free:
869 free(name); 1700 free(name);
870 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 1701 if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
871 return 0; 1702 return 0;
@@ -887,6 +1718,27 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
887 return NULL; 1718 return NULL;
888} 1719}
889 1720
1721static int dso__kernel_module_get_build_id(struct dso *dso,
1722 const char *root_dir)
1723{
1724 char filename[PATH_MAX];
1725 /*
1726 * kernel module short names are of the form "[module]" and
1727 * we need just "module" here.
1728 */
1729 const char *name = dso->short_name + 1;
1730
1731 snprintf(filename, sizeof(filename),
1732 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1733 root_dir, (int)strlen(name) - 1, name);
1734
1735 if (sysfs__read_build_id(filename, dso->build_id,
1736 sizeof(dso->build_id)) == 0)
1737 dso->has_build_id = true;
1738
1739 return 0;
1740}
1741
890static int map_groups__set_modules_path_dir(struct map_groups *mg, 1742static int map_groups__set_modules_path_dir(struct map_groups *mg,
891 const char *dir_name) 1743 const char *dir_name)
892{ 1744{
@@ -904,7 +1756,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
904 struct stat st; 1756 struct stat st;
905 1757
906 /*sshfs might return bad dent->d_type, so we have to stat*/ 1758 /*sshfs might return bad dent->d_type, so we have to stat*/
907 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); 1759 sprintf(path, "%s/%s", dir_name, dent->d_name);
908 if (stat(path, &st)) 1760 if (stat(path, &st))
909 continue; 1761 continue;
910 1762
@@ -913,6 +1765,8 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
913 !strcmp(dent->d_name, "..")) 1765 !strcmp(dent->d_name, ".."))
914 continue; 1766 continue;
915 1767
1768 snprintf(path, sizeof(path), "%s/%s",
1769 dir_name, dent->d_name);
916 ret = map_groups__set_modules_path_dir(mg, path); 1770 ret = map_groups__set_modules_path_dir(mg, path);
917 if (ret < 0) 1771 if (ret < 0)
918 goto out; 1772 goto out;
@@ -933,6 +1787,9 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
933 if (map == NULL) 1787 if (map == NULL)
934 continue; 1788 continue;
935 1789
1790 snprintf(path, sizeof(path), "%s/%s",
1791 dir_name, dent->d_name);
1792
936 long_name = strdup(path); 1793 long_name = strdup(path);
937 if (long_name == NULL) { 1794 if (long_name == NULL) {
938 ret = -1; 1795 ret = -1;
@@ -992,6 +1849,25 @@ static int machine__set_modules_path(struct machine *machine)
992 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); 1849 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
993} 1850}
994 1851
1852/*
1853 * Constructor variant for modules (where we know from /proc/modules where
1854 * they are loaded) and for vmlinux, where only after we load all the
1855 * symbols we'll know where it starts and ends.
1856 */
1857static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1858{
1859 struct map *map = calloc(1, (sizeof(*map) +
1860 (dso->kernel ? sizeof(struct kmap) : 0)));
1861 if (map != NULL) {
1862 /*
1863 * ->end will be filled after we load all the symbols
1864 */
1865 map__init(map, type, start, 0, 0, dso);
1866 }
1867
1868 return map;
1869}
1870
995struct map *machine__new_module(struct machine *machine, u64 start, 1871struct map *machine__new_module(struct machine *machine, u64 start,
996 const char *filename) 1872 const char *filename)
997{ 1873{
@@ -1006,9 +1882,9 @@ struct map *machine__new_module(struct machine *machine, u64 start,
1006 return NULL; 1882 return NULL;
1007 1883
1008 if (machine__is_host(machine)) 1884 if (machine__is_host(machine))
1009 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; 1885 dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
1010 else 1886 else
1011 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; 1887 dso->symtab_type = SYMTAB__GUEST_KMODULE;
1012 map_groups__insert(&machine->kmaps, map); 1888 map_groups__insert(&machine->kmaps, map);
1013 return map; 1889 return map;
1014} 1890}
@@ -1084,30 +1960,22 @@ out_failure:
1084int dso__load_vmlinux(struct dso *dso, struct map *map, 1960int dso__load_vmlinux(struct dso *dso, struct map *map,
1085 const char *vmlinux, symbol_filter_t filter) 1961 const char *vmlinux, symbol_filter_t filter)
1086{ 1962{
1087 int err = -1; 1963 int err = -1, fd;
1088 struct symsrc ss;
1089 char symfs_vmlinux[PATH_MAX]; 1964 char symfs_vmlinux[PATH_MAX];
1090 enum dso_binary_type symtab_type;
1091 1965
1092 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1966 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
1093 symbol_conf.symfs, vmlinux); 1967 symbol_conf.symfs, vmlinux);
1094 1968 fd = open(symfs_vmlinux, O_RDONLY);
1095 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1969 if (fd < 0)
1096 symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
1097 else
1098 symtab_type = DSO_BINARY_TYPE__VMLINUX;
1099
1100 if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type))
1101 return -1; 1970 return -1;
1102 1971
1103 err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1972 dso__set_long_name(dso, (char *)vmlinux);
1104 symsrc__destroy(&ss); 1973 dso__set_loaded(dso, map->type);
1974 err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0);
1975 close(fd);
1105 1976
1106 if (err > 0) { 1977 if (err > 0)
1107 dso__set_long_name(dso, (char *)vmlinux);
1108 dso__set_loaded(dso, map->type);
1109 pr_debug("Using %s for symbols\n", symfs_vmlinux); 1978 pr_debug("Using %s for symbols\n", symfs_vmlinux);
1110 }
1111 1979
1112 return err; 1980 return err;
1113} 1981}
@@ -1124,8 +1992,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1124 filename = dso__build_id_filename(dso, NULL, 0); 1992 filename = dso__build_id_filename(dso, NULL, 0);
1125 if (filename != NULL) { 1993 if (filename != NULL) {
1126 err = dso__load_vmlinux(dso, map, filename, filter); 1994 err = dso__load_vmlinux(dso, map, filename, filter);
1127 if (err > 0) 1995 if (err > 0) {
1996 dso__set_long_name(dso, filename);
1128 goto out; 1997 goto out;
1998 }
1129 free(filename); 1999 free(filename);
1130 } 2000 }
1131 2001
@@ -1240,8 +2110,9 @@ do_kallsyms:
1240 free(kallsyms_allocated_filename); 2110 free(kallsyms_allocated_filename);
1241 2111
1242 if (err > 0) { 2112 if (err > 0) {
1243 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
1244out_fixup: 2113out_fixup:
2114 if (kallsyms_filename != NULL)
2115 dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
1245 map__fixup_start(map); 2116 map__fixup_start(map);
1246 map__fixup_end(map); 2117 map__fixup_end(map);
1247 } 2118 }
@@ -1300,6 +2171,50 @@ out_try_fixup:
1300 return err; 2171 return err;
1301} 2172}
1302 2173
2174static void dsos__add(struct list_head *head, struct dso *dso)
2175{
2176 list_add_tail(&dso->node, head);
2177}
2178
2179static struct dso *dsos__find(struct list_head *head, const char *name)
2180{
2181 struct dso *pos;
2182
2183 list_for_each_entry(pos, head, node)
2184 if (strcmp(pos->long_name, name) == 0)
2185 return pos;
2186 return NULL;
2187}
2188
2189struct dso *__dsos__findnew(struct list_head *head, const char *name)
2190{
2191 struct dso *dso = dsos__find(head, name);
2192
2193 if (!dso) {
2194 dso = dso__new(name);
2195 if (dso != NULL) {
2196 dsos__add(head, dso);
2197 dso__set_basename(dso);
2198 }
2199 }
2200
2201 return dso;
2202}
2203
2204size_t __dsos__fprintf(struct list_head *head, FILE *fp)
2205{
2206 struct dso *pos;
2207 size_t ret = 0;
2208
2209 list_for_each_entry(pos, head, node) {
2210 int i;
2211 for (i = 0; i < MAP__NR_TYPES; ++i)
2212 ret += dso__fprintf(pos, i, fp);
2213 }
2214
2215 return ret;
2216}
2217
1303size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 2218size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1304{ 2219{
1305 struct rb_node *nd; 2220 struct rb_node *nd;
@@ -1314,6 +2229,21 @@ size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1314 return ret; 2229 return ret;
1315} 2230}
1316 2231
2232static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
2233 bool with_hits)
2234{
2235 struct dso *pos;
2236 size_t ret = 0;
2237
2238 list_for_each_entry(pos, head, node) {
2239 if (with_hits && !pos->hit)
2240 continue;
2241 ret += dso__fprintf_buildid(pos, fp);
2242 ret += fprintf(fp, " %s\n", pos->long_name);
2243 }
2244 return ret;
2245}
2246
1317size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 2247size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1318 bool with_hits) 2248 bool with_hits)
1319{ 2249{
@@ -1334,6 +2264,39 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1334 return ret; 2264 return ret;
1335} 2265}
1336 2266
2267static struct dso*
2268dso__kernel_findnew(struct machine *machine, const char *name,
2269 const char *short_name, int dso_type)
2270{
2271 /*
2272 * The kernel dso could be created by build_id processing.
2273 */
2274 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
2275
2276 /*
2277 * We need to run this in all cases, since during the build_id
2278 * processing we had no idea this was the kernel dso.
2279 */
2280 if (dso != NULL) {
2281 dso__set_short_name(dso, short_name);
2282 dso->kernel = dso_type;
2283 }
2284
2285 return dso;
2286}
2287
2288void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
2289{
2290 char path[PATH_MAX];
2291
2292 if (machine__is_default_guest(machine))
2293 return;
2294 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2295 if (sysfs__read_build_id(path, dso->build_id,
2296 sizeof(dso->build_id)) == 0)
2297 dso->has_build_id = true;
2298}
2299
1337static struct dso *machine__get_kernel(struct machine *machine) 2300static struct dso *machine__get_kernel(struct machine *machine)
1338{ 2301{
1339 const char *vmlinux_name = NULL; 2302 const char *vmlinux_name = NULL;
@@ -1372,7 +2335,7 @@ struct process_args {
1372}; 2335};
1373 2336
1374static int symbol__in_kernel(void *arg, const char *name, 2337static int symbol__in_kernel(void *arg, const char *name,
1375 char type __maybe_unused, u64 start) 2338 char type __used, u64 start, u64 end __used)
1376{ 2339{
1377 struct process_args *args = arg; 2340 struct process_args *args = arg;
1378 2341
@@ -1473,15 +2436,8 @@ int machine__create_kernel_maps(struct machine *machine)
1473 __machine__create_kernel_maps(machine, kernel) < 0) 2436 __machine__create_kernel_maps(machine, kernel) < 0)
1474 return -1; 2437 return -1;
1475 2438
1476 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 2439 if (symbol_conf.use_modules && machine__create_modules(machine) < 0)
1477 if (machine__is_host(machine)) 2440 pr_debug("Problems creating module maps, continuing anyway...\n");
1478 pr_debug("Problems creating module maps, "
1479 "continuing anyway...\n");
1480 else
1481 pr_debug("Problems creating module maps for guest %d, "
1482 "continuing anyway...\n", machine->pid);
1483 }
1484
1485 /* 2441 /*
1486 * Now that we have all the maps created, just set the ->end of them: 2442 * Now that we have all the maps created, just set the ->end of them:
1487 */ 2443 */
@@ -1608,10 +2564,9 @@ int symbol__init(void)
1608 if (symbol_conf.initialized) 2564 if (symbol_conf.initialized)
1609 return 0; 2565 return 0;
1610 2566
1611 symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 2567 symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64));
1612
1613 symbol__elf_init();
1614 2568
2569 elf_version(EV_CURRENT);
1615 if (symbol_conf.sort_by_name) 2570 if (symbol_conf.sort_by_name)
1616 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 2571 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1617 sizeof(struct symbol)); 2572 sizeof(struct symbol));
@@ -1653,10 +2608,10 @@ int symbol__init(void)
1653 symbol_conf.initialized = true; 2608 symbol_conf.initialized = true;
1654 return 0; 2609 return 0;
1655 2610
1656out_free_comm_list:
1657 strlist__delete(symbol_conf.comm_list);
1658out_free_dso_list: 2611out_free_dso_list:
1659 strlist__delete(symbol_conf.dso_list); 2612 strlist__delete(symbol_conf.dso_list);
2613out_free_comm_list:
2614 strlist__delete(symbol_conf.comm_list);
1660 return -1; 2615 return -1;
1661} 2616}
1662 2617
@@ -1682,6 +2637,49 @@ int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
1682 return machine__create_kernel_maps(machine); 2637 return machine__create_kernel_maps(machine);
1683} 2638}
1684 2639
2640static int hex(char ch)
2641{
2642 if ((ch >= '0') && (ch <= '9'))
2643 return ch - '0';
2644 if ((ch >= 'a') && (ch <= 'f'))
2645 return ch - 'a' + 10;
2646 if ((ch >= 'A') && (ch <= 'F'))
2647 return ch - 'A' + 10;
2648 return -1;
2649}
2650
2651/*
2652 * While we find nice hex chars, build a long_val.
2653 * Return number of chars processed.
2654 */
2655int hex2u64(const char *ptr, u64 *long_val)
2656{
2657 const char *p = ptr;
2658 *long_val = 0;
2659
2660 while (*p) {
2661 const int hex_val = hex(*p);
2662
2663 if (hex_val < 0)
2664 break;
2665
2666 *long_val = (*long_val << 4) | hex_val;
2667 p++;
2668 }
2669
2670 return p - ptr;
2671}
2672
2673char *strxfrchar(char *s, char from, char to)
2674{
2675 char *p = s;
2676
2677 while ((p = strchr(p, from)) != NULL)
2678 *p++ = to;
2679
2680 return s;
2681}
2682
1685int machines__create_guest_kernel_maps(struct rb_root *machines) 2683int machines__create_guest_kernel_maps(struct rb_root *machines)
1686{ 2684{
1687 int ret = 0; 2685 int ret = 0;
@@ -1689,7 +2687,6 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
1689 int i, items = 0; 2687 int i, items = 0;
1690 char path[PATH_MAX]; 2688 char path[PATH_MAX];
1691 pid_t pid; 2689 pid_t pid;
1692 char *endp;
1693 2690
1694 if (symbol_conf.default_guest_vmlinux_name || 2691 if (symbol_conf.default_guest_vmlinux_name ||
1695 symbol_conf.default_guest_modules || 2692 symbol_conf.default_guest_modules ||
@@ -1706,14 +2703,7 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
1706 /* Filter out . and .. */ 2703 /* Filter out . and .. */
1707 continue; 2704 continue;
1708 } 2705 }
1709 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); 2706 pid = atoi(namelist[i]->d_name);
1710 if ((*endp != '\0') ||
1711 (endp == namelist[i]->d_name) ||
1712 (errno == ERANGE)) {
1713 pr_debug("invalid directory (%s). Skipping.\n",
1714 namelist[i]->d_name);
1715 continue;
1716 }
1717 sprintf(path, "%s/%s/proc/kallsyms", 2707 sprintf(path, "%s/%s/proc/kallsyms",
1718 symbol_conf.guestmount, 2708 symbol_conf.guestmount,
1719 namelist[i]->d_name); 2709 namelist[i]->d_name);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index de68f98b236..4f377d92e75 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -5,51 +5,40 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <stdint.h> 6#include <stdint.h>
7#include "map.h" 7#include "map.h"
8#include "../perf.h"
9#include <linux/list.h> 8#include <linux/list.h>
10#include <linux/rbtree.h> 9#include <linux/rbtree.h>
11#include <stdio.h> 10#include <stdio.h>
12#include <byteswap.h>
13#include <libgen.h>
14#include "build-id.h"
15
16#ifdef LIBELF_SUPPORT
17#include <libelf.h>
18#include <gelf.h>
19#include <elf.h>
20#endif
21
22#include "dso.h"
23 11
24#ifdef HAVE_CPLUS_DEMANGLE 12#ifdef HAVE_CPLUS_DEMANGLE
25extern char *cplus_demangle(const char *, int); 13extern char *cplus_demangle(const char *, int);
26 14
27static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) 15static inline char *bfd_demangle(void __used *v, const char *c, int i)
28{ 16{
29 return cplus_demangle(c, i); 17 return cplus_demangle(c, i);
30} 18}
31#else 19#else
32#ifdef NO_DEMANGLE 20#ifdef NO_DEMANGLE
33static inline char *bfd_demangle(void __maybe_unused *v, 21static inline char *bfd_demangle(void __used *v, const char __used *c,
34 const char __maybe_unused *c, 22 int __used i)
35 int __maybe_unused i)
36{ 23{
37 return NULL; 24 return NULL;
38} 25}
39#else 26#else
40#define PACKAGE 'perf'
41#include <bfd.h> 27#include <bfd.h>
42#endif 28#endif
43#endif 29#endif
44 30
31int hex2u64(const char *ptr, u64 *val);
32char *strxfrchar(char *s, char from, char to);
33
45/* 34/*
46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; 35 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
47 * for newer versions we can use mmap to reduce memory usage: 36 * for newer versions we can use mmap to reduce memory usage:
48 */ 37 */
49#ifdef LIBELF_MMAP 38#ifdef LIBELF_NO_MMAP
50# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
51#else
52# define PERF_ELF_C_READ_MMAP ELF_C_READ 39# define PERF_ELF_C_READ_MMAP ELF_C_READ
40#else
41# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
53#endif 42#endif
54 43
55#ifndef DMGL_PARAMS 44#ifndef DMGL_PARAMS
@@ -57,6 +46,8 @@ static inline char *bfd_demangle(void __maybe_unused *v,
57#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 46#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
58#endif 47#endif
59 48
49#define BUILD_ID_SIZE 20
50
60/** struct symbol - symtab entry 51/** struct symbol - symtab entry
61 * 52 *
62 * @ignore - resolvable but tools ignore it (e.g. idle routines) 53 * @ignore - resolvable but tools ignore it (e.g. idle routines)
@@ -72,31 +63,20 @@ struct symbol {
72}; 63};
73 64
74void symbol__delete(struct symbol *sym); 65void symbol__delete(struct symbol *sym);
75void symbols__delete(struct rb_root *symbols);
76
77static inline size_t symbol__size(const struct symbol *sym)
78{
79 return sym->end - sym->start + 1;
80}
81 66
82struct strlist; 67struct strlist;
83 68
84struct symbol_conf { 69struct symbol_conf {
85 unsigned short priv_size; 70 unsigned short priv_size;
86 unsigned short nr_events;
87 bool try_vmlinux_path, 71 bool try_vmlinux_path,
88 show_kernel_path,
89 use_modules, 72 use_modules,
90 sort_by_name, 73 sort_by_name,
91 show_nr_samples, 74 show_nr_samples,
92 show_total_period,
93 use_callchain, 75 use_callchain,
94 exclude_other, 76 exclude_other,
95 show_cpu_utilization, 77 show_cpu_utilization,
96 initialized, 78 initialized,
97 kptr_restrict, 79 kptr_restrict;
98 annotate_asm_raw,
99 annotate_src;
100 const char *vmlinux_name, 80 const char *vmlinux_name,
101 *kallsyms_name, 81 *kallsyms_name,
102 *source_prefix, 82 *source_prefix,
@@ -111,11 +91,7 @@ struct symbol_conf {
111 *col_width_list_str; 91 *col_width_list_str;
112 struct strlist *dso_list, 92 struct strlist *dso_list,
113 *comm_list, 93 *comm_list,
114 *sym_list, 94 *sym_list;
115 *dso_from_list,
116 *dso_to_list,
117 *sym_from_list,
118 *sym_to_list;
119 const char *symfs; 95 const char *symfs;
120}; 96};
121 97
@@ -139,19 +115,6 @@ struct map_symbol {
139 bool has_children; 115 bool has_children;
140}; 116};
141 117
142struct addr_map_symbol {
143 struct map *map;
144 struct symbol *sym;
145 u64 addr;
146 u64 al_addr;
147};
148
149struct branch_info {
150 struct addr_map_symbol from;
151 struct addr_map_symbol to;
152 struct branch_flags flags;
153};
154
155struct addr_location { 118struct addr_location {
156 struct thread *thread; 119 struct thread *thread;
157 struct map *map; 120 struct map *map;
@@ -163,35 +126,50 @@ struct addr_location {
163 s32 cpu; 126 s32 cpu;
164}; 127};
165 128
166struct symsrc { 129enum dso_kernel_type {
167 char *name; 130 DSO_TYPE_USER = 0,
168 int fd; 131 DSO_TYPE_KERNEL,
169 enum dso_binary_type type; 132 DSO_TYPE_GUEST_KERNEL
133};
170 134
171#ifdef LIBELF_SUPPORT 135struct dso {
172 Elf *elf; 136 struct list_head node;
173 GElf_Ehdr ehdr; 137 struct rb_root symbols[MAP__NR_TYPES];
138 struct rb_root symbol_names[MAP__NR_TYPES];
139 enum dso_kernel_type kernel;
140 u8 adjust_symbols:1;
141 u8 has_build_id:1;
142 u8 hit:1;
143 u8 annotate_warned:1;
144 u8 sname_alloc:1;
145 u8 lname_alloc:1;
146 unsigned char symtab_type;
147 u8 sorted_by_name;
148 u8 loaded;
149 u8 build_id[BUILD_ID_SIZE];
150 const char *short_name;
151 char *long_name;
152 u16 long_name_len;
153 u16 short_name_len;
154 char name[0];
155};
174 156
175 Elf_Scn *opdsec; 157struct dso *dso__new(const char *name);
176 size_t opdidx; 158void dso__delete(struct dso *dso);
177 GElf_Shdr opdshdr;
178 159
179 Elf_Scn *symtab; 160int dso__name_len(const struct dso *dso);
180 GElf_Shdr symshdr;
181 161
182 Elf_Scn *dynsym; 162bool dso__loaded(const struct dso *dso, enum map_type type);
183 size_t dynsym_idx; 163bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
184 GElf_Shdr dynshdr;
185 164
186 bool adjust_symbols; 165static inline void dso__set_loaded(struct dso *dso, enum map_type type)
187#endif 166{
188}; 167 dso->loaded |= (1 << type);
168}
189 169
190void symsrc__destroy(struct symsrc *ss); 170void dso__sort_by_name(struct dso *dso, enum map_type type);
191int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, 171
192 enum dso_binary_type type); 172struct dso *__dsos__findnew(struct list_head *head, const char *name);
193bool symsrc__has_symtab(struct symsrc *ss);
194bool symsrc__possibly_runtime(struct symsrc *ss);
195 173
196int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); 174int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
197int dso__load_vmlinux(struct dso *dso, struct map *map, 175int dso__load_vmlinux(struct dso *dso, struct map *map,
@@ -200,7 +178,42 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
200 symbol_filter_t filter); 178 symbol_filter_t filter);
201int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, 179int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
202 symbol_filter_t filter); 180 symbol_filter_t filter);
181int machine__load_kallsyms(struct machine *machine, const char *filename,
182 enum map_type type, symbol_filter_t filter);
183int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
184 symbol_filter_t filter);
185
186size_t __dsos__fprintf(struct list_head *head, FILE *fp);
187
188size_t machine__fprintf_dsos_buildid(struct machine *machine,
189 FILE *fp, bool with_hits);
190size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
191size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
192 FILE *fp, bool with_hits);
193size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
194size_t dso__fprintf_symbols_by_name(struct dso *dso,
195 enum map_type type, FILE *fp);
196size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
197
198enum symtab_type {
199 SYMTAB__KALLSYMS = 0,
200 SYMTAB__GUEST_KALLSYMS,
201 SYMTAB__JAVA_JIT,
202 SYMTAB__BUILD_ID_CACHE,
203 SYMTAB__FEDORA_DEBUGINFO,
204 SYMTAB__UBUNTU_DEBUGINFO,
205 SYMTAB__BUILDID_DEBUGINFO,
206 SYMTAB__SYSTEM_PATH_DSO,
207 SYMTAB__GUEST_KMODULE,
208 SYMTAB__SYSTEM_PATH_KMODULE,
209 SYMTAB__NOT_FOUND,
210};
203 211
212char dso__symtab_origin(const struct dso *dso);
213void dso__set_long_name(struct dso *dso, char *name);
214void dso__set_build_id(struct dso *dso, void *build_id);
215void dso__read_running_kernel_build_id(struct dso *dso,
216 struct machine *machine);
204struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, 217struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
205 u64 addr); 218 u64 addr);
206struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 219struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
@@ -208,31 +221,24 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
208 221
209int filename__read_build_id(const char *filename, void *bf, size_t size); 222int filename__read_build_id(const char *filename, void *bf, size_t size);
210int sysfs__read_build_id(const char *filename, void *bf, size_t size); 223int sysfs__read_build_id(const char *filename, void *bf, size_t size);
224bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
225int build_id__sprintf(const u8 *build_id, int len, char *bf);
211int kallsyms__parse(const char *filename, void *arg, 226int kallsyms__parse(const char *filename, void *arg,
212 int (*process_symbol)(void *arg, const char *name, 227 int (*process_symbol)(void *arg, const char *name,
213 char type, u64 start)); 228 char type, u64 start, u64 end));
214int filename__read_debuglink(const char *filename, char *debuglink, 229
215 size_t size); 230void machine__destroy_kernel_maps(struct machine *machine);
231int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
232int machine__create_kernel_maps(struct machine *machine);
233
234int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
235int machines__create_guest_kernel_maps(struct rb_root *machines);
236void machines__destroy_guest_kernel_maps(struct rb_root *machines);
216 237
217int symbol__init(void); 238int symbol__init(void);
218void symbol__exit(void); 239void symbol__exit(void);
219void symbol__elf_init(void);
220struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
221size_t symbol__fprintf_symname_offs(const struct symbol *sym,
222 const struct addr_location *al, FILE *fp);
223size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
224size_t symbol__fprintf(struct symbol *sym, FILE *fp);
225bool symbol_type__is_a(char symbol_type, enum map_type map_type); 240bool symbol_type__is_a(char symbol_type, enum map_type map_type);
226 241
227int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 242size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
228 struct symsrc *runtime_ss, symbol_filter_t filter,
229 int kmodule);
230int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
231 struct map *map, symbol_filter_t filter);
232
233void symbols__insert(struct rb_root *symbols, struct symbol *sym);
234void symbols__fixup_duplicate(struct rb_root *symbols);
235void symbols__fixup_end(struct rb_root *symbols);
236void __map_groups__fixup_end(struct map_groups *mg, enum map_type type);
237 243
238#endif /* __PERF_SYMBOL */ 244#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
deleted file mode 100644
index 48c6902e749..00000000000
--- a/tools/perf/util/sysfs.c
+++ /dev/null
@@ -1,60 +0,0 @@
1
2#include "util.h"
3#include "sysfs.h"
4
5static const char * const sysfs_known_mountpoints[] = {
6 "/sys",
7 0,
8};
9
10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX];
12
13static int sysfs_valid_mountpoint(const char *sysfs)
14{
15 struct statfs st_fs;
16
17 if (statfs(sysfs, &st_fs) < 0)
18 return -ENOENT;
19 else if (st_fs.f_type != (long) SYSFS_MAGIC)
20 return -ENOENT;
21
22 return 0;
23}
24
25const char *sysfs_find_mountpoint(void)
26{
27 const char * const *ptr;
28 char type[100];
29 FILE *fp;
30
31 if (sysfs_found)
32 return (const char *) sysfs_mountpoint;
33
34 ptr = sysfs_known_mountpoints;
35 while (*ptr) {
36 if (sysfs_valid_mountpoint(*ptr) == 0) {
37 sysfs_found = 1;
38 strcpy(sysfs_mountpoint, *ptr);
39 return sysfs_mountpoint;
40 }
41 ptr++;
42 }
43
44 /* give up and parse /proc/mounts */
45 fp = fopen("/proc/mounts", "r");
46 if (fp == NULL)
47 return NULL;
48
49 while (!sysfs_found &&
50 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
51 sysfs_mountpoint, type) == 2) {
52
53 if (strcmp(type, "sysfs") == 0)
54 sysfs_found = 1;
55 }
56
57 fclose(fp);
58
59 return sysfs_found ? sysfs_mountpoint : NULL;
60}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
deleted file mode 100644
index a813b720393..00000000000
--- a/tools/perf/util/sysfs.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef __SYSFS_H__
2#define __SYSFS_H__
3
4const char *sysfs_find_mountpoint(void);
5
6#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
deleted file mode 100644
index 065528b7563..00000000000
--- a/tools/perf/util/target.c
+++ /dev/null
@@ -1,151 +0,0 @@
1/*
2 * Helper functions for handling target threads/cpus
3 *
4 * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com>
5 *
6 * Released under the GPL v2.
7 */
8
9#include "target.h"
10#include "debug.h"
11
12#include <pwd.h>
13#include <string.h>
14
15
16enum perf_target_errno perf_target__validate(struct perf_target *target)
17{
18 enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS;
19
20 if (target->pid)
21 target->tid = target->pid;
22
23 /* CPU and PID are mutually exclusive */
24 if (target->tid && target->cpu_list) {
25 target->cpu_list = NULL;
26 if (ret == PERF_ERRNO_TARGET__SUCCESS)
27 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU;
28 }
29
30 /* UID and PID are mutually exclusive */
31 if (target->tid && target->uid_str) {
32 target->uid_str = NULL;
33 if (ret == PERF_ERRNO_TARGET__SUCCESS)
34 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID;
35 }
36
37 /* UID and CPU are mutually exclusive */
38 if (target->uid_str && target->cpu_list) {
39 target->cpu_list = NULL;
40 if (ret == PERF_ERRNO_TARGET__SUCCESS)
41 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU;
42 }
43
44 /* PID and SYSTEM are mutually exclusive */
45 if (target->tid && target->system_wide) {
46 target->system_wide = false;
47 if (ret == PERF_ERRNO_TARGET__SUCCESS)
48 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM;
49 }
50
51 /* UID and SYSTEM are mutually exclusive */
52 if (target->uid_str && target->system_wide) {
53 target->system_wide = false;
54 if (ret == PERF_ERRNO_TARGET__SUCCESS)
55 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
56 }
57
58 return ret;
59}
60
61enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
62{
63 struct passwd pwd, *result;
64 char buf[1024];
65 const char *str = target->uid_str;
66
67 target->uid = UINT_MAX;
68 if (str == NULL)
69 return PERF_ERRNO_TARGET__SUCCESS;
70
71 /* Try user name first */
72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
73
74 if (result == NULL) {
75 /*
76 * The user name not found. Maybe it's a UID number.
77 */
78 char *endptr;
79 int uid = strtol(str, &endptr, 10);
80
81 if (*endptr != '\0')
82 return PERF_ERRNO_TARGET__INVALID_UID;
83
84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
85
86 if (result == NULL)
87 return PERF_ERRNO_TARGET__USER_NOT_FOUND;
88 }
89
90 target->uid = result->pw_uid;
91 return PERF_ERRNO_TARGET__SUCCESS;
92}
93
94/*
95 * This must have a same ordering as the enum perf_target_errno.
96 */
97static const char *perf_target__error_str[] = {
98 "PID/TID switch overriding CPU",
99 "PID/TID switch overriding UID",
100 "UID switch overriding CPU",
101 "PID/TID switch overriding SYSTEM",
102 "UID switch overriding SYSTEM",
103 "Invalid User: %s",
104 "Problems obtaining information for user %s",
105};
106
107int perf_target__strerror(struct perf_target *target, int errnum,
108 char *buf, size_t buflen)
109{
110 int idx;
111 const char *msg;
112
113 BUG_ON(buflen == 0);
114
115 if (errnum >= 0) {
116 const char *err = strerror_r(errnum, buf, buflen);
117
118 if (err != buf) {
119 size_t len = strlen(err);
120 memcpy(buf, err, min(buflen - 1, len));
121 *(buf + min(buflen - 1, len)) = '\0';
122 }
123
124 return 0;
125 }
126
127 if (errnum < __PERF_ERRNO_TARGET__START ||
128 errnum >= __PERF_ERRNO_TARGET__END)
129 return -1;
130
131 idx = errnum - __PERF_ERRNO_TARGET__START;
132 msg = perf_target__error_str[idx];
133
134 switch (errnum) {
135 case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
136 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
137 snprintf(buf, buflen, "%s", msg);
138 break;
139
140 case PERF_ERRNO_TARGET__INVALID_UID:
141 case PERF_ERRNO_TARGET__USER_NOT_FOUND:
142 snprintf(buf, buflen, msg, target->uid_str);
143 break;
144
145 default:
146 /* cannot reach here */
147 break;
148 }
149
150 return 0;
151}
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
deleted file mode 100644
index a4be8575fda..00000000000
--- a/tools/perf/util/target.h
+++ /dev/null
@@ -1,65 +0,0 @@
1#ifndef _PERF_TARGET_H
2#define _PERF_TARGET_H
3
4#include <stdbool.h>
5#include <sys/types.h>
6
7struct perf_target {
8 const char *pid;
9 const char *tid;
10 const char *cpu_list;
11 const char *uid_str;
12 uid_t uid;
13 bool system_wide;
14 bool uses_mmap;
15};
16
17enum perf_target_errno {
18 PERF_ERRNO_TARGET__SUCCESS = 0,
19
20 /*
21 * Choose an arbitrary negative big number not to clash with standard
22 * errno since SUS requires the errno has distinct positive values.
23 * See 'Issue 6' in the link below.
24 *
25 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
26 */
27 __PERF_ERRNO_TARGET__START = -10000,
28
29
30 /* for perf_target__validate() */
31 PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START,
32 PERF_ERRNO_TARGET__PID_OVERRIDE_UID,
33 PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
34 PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
35 PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
36
37 /* for perf_target__parse_uid() */
38 PERF_ERRNO_TARGET__INVALID_UID,
39 PERF_ERRNO_TARGET__USER_NOT_FOUND,
40
41 __PERF_ERRNO_TARGET__END,
42};
43
44enum perf_target_errno perf_target__validate(struct perf_target *target);
45enum perf_target_errno perf_target__parse_uid(struct perf_target *target);
46
47int perf_target__strerror(struct perf_target *target, int errnum, char *buf,
48 size_t buflen);
49
50static inline bool perf_target__has_task(struct perf_target *target)
51{
52 return target->tid || target->pid || target->uid_str;
53}
54
55static inline bool perf_target__has_cpu(struct perf_target *target)
56{
57 return target->system_wide || target->cpu_list;
58}
59
60static inline bool perf_target__none(struct perf_target *target)
61{
62 return !perf_target__has_task(target) && !perf_target__has_cpu(target);
63}
64
65#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index df59623ac76..d5d3b22250f 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,7 +7,7 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10struct thread *thread__new(pid_t pid) 10static struct thread *thread__new(pid_t pid)
11{ 11{
12 struct thread *self = zalloc(sizeof(*self)); 12 struct thread *self = zalloc(sizeof(*self));
13 13
@@ -39,6 +39,7 @@ int thread__set_comm(struct thread *self, const char *comm)
39 err = self->comm == NULL ? -ENOMEM : 0; 39 err = self->comm == NULL ? -ENOMEM : 0;
40 if (!err) { 40 if (!err) {
41 self->comm_set = true; 41 self->comm_set = true;
42 map_groups__flush(&self->mg);
42 } 43 }
43 return err; 44 return err;
44} 45}
@@ -60,6 +61,45 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
60 map_groups__fprintf(&self->mg, verbose, fp); 61 map_groups__fprintf(&self->mg, verbose, fp);
61} 62}
62 63
64struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
65{
66 struct rb_node **p = &self->threads.rb_node;
67 struct rb_node *parent = NULL;
68 struct thread *th;
69
70 /*
71 * Font-end cache - PID lookups come in blocks,
72 * so most of the time we dont have to look up
73 * the full rbtree:
74 */
75 if (self->last_match && self->last_match->pid == pid)
76 return self->last_match;
77
78 while (*p != NULL) {
79 parent = *p;
80 th = rb_entry(parent, struct thread, rb_node);
81
82 if (th->pid == pid) {
83 self->last_match = th;
84 return th;
85 }
86
87 if (pid < th->pid)
88 p = &(*p)->rb_left;
89 else
90 p = &(*p)->rb_right;
91 }
92
93 th = thread__new(pid);
94 if (th != NULL) {
95 rb_link_node(&th->rb_node, parent, p);
96 rb_insert_color(&th->rb_node, &self->threads);
97 self->last_match = th;
98 }
99
100 return th;
101}
102
63void thread__insert_map(struct thread *self, struct map *map) 103void thread__insert_map(struct thread *self, struct map *map)
64{ 104{
65 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); 105 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr);
@@ -85,12 +125,12 @@ int thread__fork(struct thread *self, struct thread *parent)
85 return 0; 125 return 0;
86} 126}
87 127
88size_t machine__fprintf(struct machine *machine, FILE *fp) 128size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
89{ 129{
90 size_t ret = 0; 130 size_t ret = 0;
91 struct rb_node *nd; 131 struct rb_node *nd;
92 132
93 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { 133 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
94 struct thread *pos = rb_entry(nd, struct thread, rb_node); 134 struct thread *pos = rb_entry(nd, struct thread, rb_node);
95 135
96 ret += thread__fprintf(pos, fp); 136 ret += thread__fprintf(pos, fp);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index f2fa17caa7d..e5f2401c1b5 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -3,7 +3,6 @@
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <unistd.h> 5#include <unistd.h>
6#include <sys/types.h>
7#include "symbol.h" 6#include "symbol.h"
8 7
9struct thread { 8struct thread {
@@ -17,19 +16,18 @@ struct thread {
17 bool comm_set; 16 bool comm_set;
18 char *comm; 17 char *comm;
19 int comm_len; 18 int comm_len;
20
21 void *priv;
22}; 19};
23 20
24struct machine; 21struct perf_session;
25 22
26struct thread *thread__new(pid_t pid);
27void thread__delete(struct thread *self); 23void thread__delete(struct thread *self);
28 24
29int thread__set_comm(struct thread *self, const char *comm); 25int thread__set_comm(struct thread *self, const char *comm);
30int thread__comm_len(struct thread *self); 26int thread__comm_len(struct thread *self);
27struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
31void thread__insert_map(struct thread *self, struct map *map); 28void thread__insert_map(struct thread *self, struct map *map);
32int thread__fork(struct thread *self, struct thread *parent); 29int thread__fork(struct thread *self, struct thread *parent);
30size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
33 31
34static inline struct map *thread__find_map(struct thread *self, 32static inline struct map *thread__find_map(struct thread *self,
35 enum map_type type, u64 addr) 33 enum map_type type, u64 addr)
@@ -37,12 +35,14 @@ static inline struct map *thread__find_map(struct thread *self,
37 return self ? map_groups__find(&self->mg, type, addr) : NULL; 35 return self ? map_groups__find(&self->mg, type, addr) : NULL;
38} 36}
39 37
40void thread__find_addr_map(struct thread *thread, struct machine *machine, 38void thread__find_addr_map(struct thread *self,
41 u8 cpumode, enum map_type type, u64 addr, 39 struct perf_session *session, u8 cpumode,
40 enum map_type type, pid_t pid, u64 addr,
42 struct addr_location *al); 41 struct addr_location *al);
43 42
44void thread__find_addr_location(struct thread *thread, struct machine *machine, 43void thread__find_addr_location(struct thread *self,
45 u8 cpumode, enum map_type type, u64 addr, 44 struct perf_session *session, u8 cpumode,
45 enum map_type type, pid_t pid, u64 addr,
46 struct addr_location *al, 46 struct addr_location *al,
47 symbol_filter_t filter); 47 symbol_filter_t filter);
48#endif /* __PERF_THREAD_H */ 48#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 9b5f856cc28..a5df131b77c 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -1,13 +1,6 @@
1#include <dirent.h> 1#include <dirent.h>
2#include <limits.h>
3#include <stdbool.h>
4#include <stdlib.h> 2#include <stdlib.h>
5#include <stdio.h> 3#include <stdio.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include "strlist.h"
10#include <string.h>
11#include "thread_map.h" 4#include "thread_map.h"
12 5
13/* Skip "." and ".." directories */ 6/* Skip "." and ".." directories */
@@ -30,7 +23,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
30 sprintf(name, "/proc/%d/task", pid); 23 sprintf(name, "/proc/%d/task", pid);
31 items = scandir(name, &namelist, filter, NULL); 24 items = scandir(name, &namelist, filter, NULL);
32 if (items <= 0) 25 if (items <= 0)
33 return NULL; 26 return NULL;
34 27
35 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); 28 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
36 if (threads != NULL) { 29 if (threads != NULL) {
@@ -58,239 +51,14 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
58 return threads; 51 return threads;
59} 52}
60 53
61struct thread_map *thread_map__new_by_uid(uid_t uid) 54struct thread_map *thread_map__new(pid_t pid, pid_t tid)
62{
63 DIR *proc;
64 int max_threads = 32, items, i;
65 char path[256];
66 struct dirent dirent, *next, **namelist = NULL;
67 struct thread_map *threads = malloc(sizeof(*threads) +
68 max_threads * sizeof(pid_t));
69 if (threads == NULL)
70 goto out;
71
72 proc = opendir("/proc");
73 if (proc == NULL)
74 goto out_free_threads;
75
76 threads->nr = 0;
77
78 while (!readdir_r(proc, &dirent, &next) && next) {
79 char *end;
80 bool grow = false;
81 struct stat st;
82 pid_t pid = strtol(dirent.d_name, &end, 10);
83
84 if (*end) /* only interested in proper numerical dirents */
85 continue;
86
87 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
88
89 if (stat(path, &st) != 0)
90 continue;
91
92 if (st.st_uid != uid)
93 continue;
94
95 snprintf(path, sizeof(path), "/proc/%d/task", pid);
96 items = scandir(path, &namelist, filter, NULL);
97 if (items <= 0)
98 goto out_free_closedir;
99
100 while (threads->nr + items >= max_threads) {
101 max_threads *= 2;
102 grow = true;
103 }
104
105 if (grow) {
106 struct thread_map *tmp;
107
108 tmp = realloc(threads, (sizeof(*threads) +
109 max_threads * sizeof(pid_t)));
110 if (tmp == NULL)
111 goto out_free_namelist;
112
113 threads = tmp;
114 }
115
116 for (i = 0; i < items; i++)
117 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
118
119 for (i = 0; i < items; i++)
120 free(namelist[i]);
121 free(namelist);
122
123 threads->nr += items;
124 }
125
126out_closedir:
127 closedir(proc);
128out:
129 return threads;
130
131out_free_threads:
132 free(threads);
133 return NULL;
134
135out_free_namelist:
136 for (i = 0; i < items; i++)
137 free(namelist[i]);
138 free(namelist);
139
140out_free_closedir:
141 free(threads);
142 threads = NULL;
143 goto out_closedir;
144}
145
146struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
147{ 55{
148 if (pid != -1) 56 if (pid != -1)
149 return thread_map__new_by_pid(pid); 57 return thread_map__new_by_pid(pid);
150
151 if (tid == -1 && uid != UINT_MAX)
152 return thread_map__new_by_uid(uid);
153
154 return thread_map__new_by_tid(tid); 58 return thread_map__new_by_tid(tid);
155} 59}
156 60
157static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
158{
159 struct thread_map *threads = NULL, *nt;
160 char name[256];
161 int items, total_tasks = 0;
162 struct dirent **namelist = NULL;
163 int i, j = 0;
164 pid_t pid, prev_pid = INT_MAX;
165 char *end_ptr;
166 struct str_node *pos;
167 struct strlist *slist = strlist__new(false, pid_str);
168
169 if (!slist)
170 return NULL;
171
172 strlist__for_each(pos, slist) {
173 pid = strtol(pos->s, &end_ptr, 10);
174
175 if (pid == INT_MIN || pid == INT_MAX ||
176 (*end_ptr != '\0' && *end_ptr != ','))
177 goto out_free_threads;
178
179 if (pid == prev_pid)
180 continue;
181
182 sprintf(name, "/proc/%d/task", pid);
183 items = scandir(name, &namelist, filter, NULL);
184 if (items <= 0)
185 goto out_free_threads;
186
187 total_tasks += items;
188 nt = realloc(threads, (sizeof(*threads) +
189 sizeof(pid_t) * total_tasks));
190 if (nt == NULL)
191 goto out_free_namelist;
192
193 threads = nt;
194
195 for (i = 0; i < items; i++) {
196 threads->map[j++] = atoi(namelist[i]->d_name);
197 free(namelist[i]);
198 }
199 threads->nr = total_tasks;
200 free(namelist);
201 }
202
203out:
204 strlist__delete(slist);
205 return threads;
206
207out_free_namelist:
208 for (i = 0; i < items; i++)
209 free(namelist[i]);
210 free(namelist);
211
212out_free_threads:
213 free(threads);
214 threads = NULL;
215 goto out;
216}
217
218static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
219{
220 struct thread_map *threads = NULL, *nt;
221 int ntasks = 0;
222 pid_t tid, prev_tid = INT_MAX;
223 char *end_ptr;
224 struct str_node *pos;
225 struct strlist *slist;
226
227 /* perf-stat expects threads to be generated even if tid not given */
228 if (!tid_str) {
229 threads = malloc(sizeof(*threads) + sizeof(pid_t));
230 if (threads != NULL) {
231 threads->map[0] = -1;
232 threads->nr = 1;
233 }
234 return threads;
235 }
236
237 slist = strlist__new(false, tid_str);
238 if (!slist)
239 return NULL;
240
241 strlist__for_each(pos, slist) {
242 tid = strtol(pos->s, &end_ptr, 10);
243
244 if (tid == INT_MIN || tid == INT_MAX ||
245 (*end_ptr != '\0' && *end_ptr != ','))
246 goto out_free_threads;
247
248 if (tid == prev_tid)
249 continue;
250
251 ntasks++;
252 nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks);
253
254 if (nt == NULL)
255 goto out_free_threads;
256
257 threads = nt;
258 threads->map[ntasks - 1] = tid;
259 threads->nr = ntasks;
260 }
261out:
262 return threads;
263
264out_free_threads:
265 free(threads);
266 threads = NULL;
267 goto out;
268}
269
270struct thread_map *thread_map__new_str(const char *pid, const char *tid,
271 uid_t uid)
272{
273 if (pid)
274 return thread_map__new_by_pid_str(pid);
275
276 if (!tid && uid != UINT_MAX)
277 return thread_map__new_by_uid(uid);
278
279 return thread_map__new_by_tid_str(tid);
280}
281
282void thread_map__delete(struct thread_map *threads) 61void thread_map__delete(struct thread_map *threads)
283{ 62{
284 free(threads); 63 free(threads);
285} 64}
286
287size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
288{
289 int i;
290 size_t printed = fprintf(fp, "%d thread%s: ",
291 threads->nr, threads->nr > 1 ? "s" : "");
292 for (i = 0; i < threads->nr; ++i)
293 printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
294
295 return printed + fprintf(fp, "\n");
296}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index f718df8a3c5..3cb90731140 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -2,23 +2,14 @@
2#define __PERF_THREAD_MAP_H 2#define __PERF_THREAD_MAP_H
3 3
4#include <sys/types.h> 4#include <sys/types.h>
5#include <stdio.h>
6 5
7struct thread_map { 6struct thread_map {
8 int nr; 7 int nr;
9 pid_t map[]; 8 int map[];
10}; 9};
11 10
12struct thread_map *thread_map__new_by_pid(pid_t pid); 11struct thread_map *thread_map__new_by_pid(pid_t pid);
13struct thread_map *thread_map__new_by_tid(pid_t tid); 12struct thread_map *thread_map__new_by_tid(pid_t tid);
14struct thread_map *thread_map__new_by_uid(uid_t uid); 13struct thread_map *thread_map__new(pid_t pid, pid_t tid);
15struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
16
17struct thread_map *thread_map__new_str(const char *pid,
18 const char *tid, uid_t uid);
19
20void thread_map__delete(struct thread_map *threads); 14void thread_map__delete(struct thread_map *threads);
21
22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
23
24#endif /* __PERF_THREAD_MAP_H */ 15#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
deleted file mode 100644
index b0e1aadba8d..00000000000
--- a/tools/perf/util/tool.h
+++ /dev/null
@@ -1,50 +0,0 @@
1#ifndef __PERF_TOOL_H
2#define __PERF_TOOL_H
3
4#include <stdbool.h>
5
6struct perf_session;
7union perf_event;
8struct perf_evlist;
9struct perf_evsel;
10struct perf_sample;
11struct perf_tool;
12struct machine;
13
14typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
15 struct perf_sample *sample,
16 struct perf_evsel *evsel, struct machine *machine);
17
18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
19 struct perf_sample *sample, struct machine *machine);
20
21typedef int (*event_attr_op)(union perf_event *event,
22 struct perf_evlist **pevlist);
23typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
24
25typedef int (*event_synth_op)(union perf_event *event,
26 struct perf_session *session);
27
28typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
29 struct perf_session *session);
30
31struct perf_tool {
32 event_sample sample,
33 read;
34 event_op mmap,
35 comm,
36 fork,
37 exit,
38 lost,
39 throttle,
40 unthrottle;
41 event_attr_op attr;
42 event_synth_op tracing_data;
43 event_simple_op event_type;
44 event_op2 finished_round,
45 build_id;
46 bool ordered_samples;
47 bool ordering_requires_timestamps;
48};
49
50#endif /* __PERF_TOOL_H */
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 884dde9b9bc..a11f60735a1 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -15,6 +15,52 @@
15#include "top.h" 15#include "top.h"
16#include <inttypes.h> 16#include <inttypes.h>
17 17
18/*
19 * Ordering weight: count-1 * count-2 * ... / count-n
20 */
21static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
22{
23 double weight = sym->snap_count;
24 int counter;
25
26 if (!top->display_weighted)
27 return weight;
28
29 for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
30 weight *= sym->count[counter];
31
32 weight /= (sym->count[counter] + 1);
33
34 return weight;
35}
36
37static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
38{
39 pthread_mutex_lock(&top->active_symbols_lock);
40 list_del_init(&syme->node);
41 pthread_mutex_unlock(&top->active_symbols_lock);
42}
43
44static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
45{
46 struct rb_node **p = &tree->rb_node;
47 struct rb_node *parent = NULL;
48 struct sym_entry *iter;
49
50 while (*p != NULL) {
51 parent = *p;
52 iter = rb_entry(parent, struct sym_entry, rb_node);
53
54 if (se->weight > iter->weight)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 rb_link_node(&se->rb_node, parent, p);
61 rb_insert_color(&se->rb_node, tree);
62}
63
18#define SNPRINTF(buf, size, fmt, args...) \ 64#define SNPRINTF(buf, size, fmt, args...) \
19({ \ 65({ \
20 size_t r = snprintf(buf, size, fmt, ## args); \ 66 size_t r = snprintf(buf, size, fmt, ## args); \
@@ -23,6 +69,7 @@
23 69
24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) 70size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
25{ 71{
72 struct perf_evsel *counter;
26 float samples_per_sec = top->samples / top->delay_secs; 73 float samples_per_sec = top->samples / top->delay_secs;
27 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 74 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
28 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 75 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
@@ -57,35 +104,52 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
57 esamples_percent); 104 esamples_percent);
58 } 105 }
59 106
60 if (top->evlist->nr_entries == 1) { 107 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
61 struct perf_evsel *first = perf_evlist__first(top->evlist); 108 struct perf_evsel *first;
109 first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
62 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 110 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
63 (uint64_t)first->attr.sample_period, 111 (uint64_t)first->attr.sample_period,
64 top->freq ? "Hz" : ""); 112 top->freq ? "Hz" : "");
65 } 113 }
66 114
67 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); 115 if (!top->display_weighted) {
116 ret += SNPRINTF(bf + ret, size - ret, "%s",
117 event_name(top->sym_evsel));
118 } else {
119 /*
120 * Don't let events eat all the space. Leaving 30 bytes
121 * for the rest should be enough.
122 */
123 size_t last_pos = size - 30;
124
125 list_for_each_entry(counter, &top->evlist->entries, node) {
126 ret += SNPRINTF(bf + ret, size - ret, "%s%s",
127 counter->idx ? "/" : "",
128 event_name(counter));
129 if (ret > last_pos) {
130 sprintf(bf + last_pos - 3, "..");
131 ret = last_pos - 1;
132 break;
133 }
134 }
135 }
68 136
69 ret += SNPRINTF(bf + ret, size - ret, "], "); 137 ret += SNPRINTF(bf + ret, size - ret, "], ");
70 138
71 if (top->target.pid) 139 if (top->target_pid != -1)
72 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 140 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d",
73 top->target.pid); 141 top->target_pid);
74 else if (top->target.tid) 142 else if (top->target_tid != -1)
75 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 143 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d",
76 top->target.tid); 144 top->target_tid);
77 else if (top->target.uid_str != NULL)
78 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
79 top->target.uid_str);
80 else 145 else
81 ret += SNPRINTF(bf + ret, size - ret, " (all"); 146 ret += SNPRINTF(bf + ret, size - ret, " (all");
82 147
83 if (top->target.cpu_list) 148 if (top->cpu_list)
84 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 149 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
85 top->evlist->cpus->nr > 1 ? "s" : "", 150 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
86 top->target.cpu_list);
87 else { 151 else {
88 if (top->target.tid) 152 if (top->target_tid != -1)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 153 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 154 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 155 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
@@ -102,3 +166,73 @@ void perf_top__reset_sample_counters(struct perf_top *top)
102 top->exact_samples = top->guest_kernel_samples = 166 top->exact_samples = top->guest_kernel_samples =
103 top->guest_us_samples = 0; 167 top->guest_us_samples = 0;
104} 168}
169
170float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
171{
172 struct sym_entry *syme, *n;
173 float sum_ksamples = 0.0;
174 int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
175
176 /* Sort the active symbols */
177 pthread_mutex_lock(&top->active_symbols_lock);
178 syme = list_entry(top->active_symbols.next, struct sym_entry, node);
179 pthread_mutex_unlock(&top->active_symbols_lock);
180
181 top->rb_entries = 0;
182 list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
183 syme->snap_count = syme->count[snap];
184 if (syme->snap_count != 0) {
185
186 if ((top->hide_user_symbols &&
187 syme->map->dso->kernel == DSO_TYPE_USER) ||
188 (top->hide_kernel_symbols &&
189 syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
190 perf_top__remove_active_sym(top, syme);
191 continue;
192 }
193 syme->weight = sym_weight(syme, top);
194
195 if ((int)syme->snap_count >= top->count_filter) {
196 rb_insert_active_sym(root, syme);
197 ++top->rb_entries;
198 }
199 sum_ksamples += syme->snap_count;
200
201 for (j = 0; j < top->evlist->nr_entries; j++)
202 syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
203 } else
204 perf_top__remove_active_sym(top, syme);
205 }
206
207 return sum_ksamples;
208}
209
210/*
211 * Find the longest symbol name that will be displayed
212 */
213void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
214 int *dso_width, int *dso_short_width, int *sym_width)
215{
216 struct rb_node *nd;
217 int printed = 0;
218
219 *sym_width = *dso_width = *dso_short_width = 0;
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
223 struct symbol *sym = sym_entry__symbol(syme);
224
225 if (++printed > top->print_entries ||
226 (int)syme->snap_count < top->count_filter)
227 continue;
228
229 if (syme->map->dso->long_name_len > *dso_width)
230 *dso_width = syme->map->dso->long_name_len;
231
232 if (syme->map->dso->short_name_len > *dso_short_width)
233 *dso_short_width = syme->map->dso->short_name_len;
234
235 if (sym->namelen > *sym_width)
236 *sym_width = sym->namelen;
237 }
238}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 86ff1b15059..bfbf95bcc60 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -1,52 +1,64 @@
1#ifndef __PERF_TOP_H 1#ifndef __PERF_TOP_H
2#define __PERF_TOP_H 1 2#define __PERF_TOP_H 1
3 3
4#include "tool.h"
5#include "types.h" 4#include "types.h"
5#include "../perf.h"
6#include <stddef.h> 6#include <stddef.h>
7#include <stdbool.h> 7#include <pthread.h>
8#include <termios.h> 8#include <linux/list.h>
9#include <linux/rbtree.h>
9 10
10struct perf_evlist; 11struct perf_evlist;
11struct perf_evsel; 12struct perf_evsel;
12struct perf_session; 13
14struct sym_entry {
15 struct rb_node rb_node;
16 struct list_head node;
17 unsigned long snap_count;
18 double weight;
19 struct map *map;
20 unsigned long count[0];
21};
22
23static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
24{
25 return ((void *)self) + symbol_conf.priv_size;
26}
13 27
14struct perf_top { 28struct perf_top {
15 struct perf_tool tool;
16 struct perf_evlist *evlist; 29 struct perf_evlist *evlist;
17 struct perf_target target;
18 /* 30 /*
19 * Symbols will be added here in perf_event__process_sample and will 31 * Symbols will be added here in perf_event__process_sample and will
20 * get out after decayed. 32 * get out after decayed.
21 */ 33 */
34 struct list_head active_symbols;
35 pthread_mutex_t active_symbols_lock;
36 pthread_cond_t active_symbols_cond;
22 u64 samples; 37 u64 samples;
23 u64 kernel_samples, us_samples; 38 u64 kernel_samples, us_samples;
24 u64 exact_samples; 39 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 40 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 41 int print_entries, count_filter, delay_secs;
27 int freq; 42 int display_weighted, freq, rb_entries;
43 pid_t target_pid, target_tid;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 44 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool use_tui, use_stdio; 45 const char *cpu_list;
30 bool sort_has_symbols; 46 struct sym_entry *sym_filter_entry;
31 bool dont_use_callchains;
32 bool kptr_restrict_warned;
33 bool vmlinux_warned;
34 bool inherit;
35 bool group;
36 bool sample_id_all_missing;
37 bool exclude_guest_missing;
38 bool dump_symtab;
39 struct hist_entry *sym_filter_entry;
40 struct perf_evsel *sym_evsel; 47 struct perf_evsel *sym_evsel;
41 struct perf_session *session;
42 struct winsize winsize;
43 unsigned int mmap_pages;
44 int default_interval;
45 int realtime_prio;
46 int sym_pcnt_filter;
47 const char *sym_filter;
48}; 48};
49 49
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
51void perf_top__reset_sample_counters(struct perf_top *top); 51void perf_top__reset_sample_counters(struct perf_top *top);
52float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
53void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
54 int *dso_width, int *dso_short_width, int *sym_width);
55
56#ifdef NO_NEWT_SUPPORT
57static inline int perf_top__tui_browser(struct perf_top *top __used)
58{
59 return 0;
60}
61#else
62int perf_top__tui_browser(struct perf_top *top);
63#endif
52#endif /* __PERF_TOP_H */ 64#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index a8d81c35ef6..3403f814ad7 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#include "util.h" 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h> 23#include <mntent.h>
24#include <stdio.h> 24#include <stdio.h>
@@ -31,6 +31,7 @@
31#include <pthread.h> 31#include <pthread.h>
32#include <fcntl.h> 32#include <fcntl.h>
33#include <unistd.h> 33#include <unistd.h>
34#include <ctype.h>
34#include <errno.h> 35#include <errno.h>
35#include <stdbool.h> 36#include <stdbool.h>
36#include <linux/list.h> 37#include <linux/list.h>
@@ -43,6 +44,10 @@
43 44
44#define VERSION "0.5" 45#define VERSION "0.5"
45 46
47#define _STR(x) #x
48#define STR(x) _STR(x)
49#define MAX_PATH 256
50
46#define TRACE_CTRL "tracing_on" 51#define TRACE_CTRL "tracing_on"
47#define TRACE "trace" 52#define TRACE "trace"
48#define AVAILABLE "available_tracers" 53#define AVAILABLE "available_tracers"
@@ -68,7 +73,27 @@ struct events {
68}; 73};
69 74
70 75
71static void *malloc_or_die(unsigned int size) 76
77static void die(const char *fmt, ...)
78{
79 va_list ap;
80 int ret = errno;
81
82 if (errno)
83 perror("trace-cmd");
84 else
85 ret = -1;
86
87 va_start(ap, fmt);
88 fprintf(stderr, " ");
89 vfprintf(stderr, fmt, ap);
90 va_end(ap);
91
92 fprintf(stderr, "\n");
93 exit(ret);
94}
95
96void *malloc_or_die(unsigned int size)
72{ 97{
73 void *data; 98 void *data;
74 99
@@ -171,8 +196,7 @@ static void record_file(const char *file, size_t hdr_sz)
171 die("Can't read '%s'", file); 196 die("Can't read '%s'", file);
172 197
173 /* put in zeros for file size, then fill true size later */ 198 /* put in zeros for file size, then fill true size later */
174 if (hdr_sz) 199 write_or_die(&size, hdr_sz);
175 write_or_die(&size, hdr_sz);
176 200
177 do { 201 do {
178 r = read(fd, buf, BUFSIZ); 202 r = read(fd, buf, BUFSIZ);
@@ -188,7 +212,7 @@ static void record_file(const char *file, size_t hdr_sz)
188 if (bigendian()) 212 if (bigendian())
189 sizep += sizeof(u64) - hdr_sz; 213 sizep += sizeof(u64) - hdr_sz;
190 214
191 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) 215 if (pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0)
192 die("writing to %s", output_file); 216 die("writing to %s", output_file);
193} 217}
194 218
@@ -404,19 +428,6 @@ get_tracepoints_path(struct list_head *pattrs)
404 return nr_tracepoints > 0 ? path.next : NULL; 428 return nr_tracepoints > 0 ? path.next : NULL;
405} 429}
406 430
407static void
408put_tracepoints_path(struct tracepoint_path *tps)
409{
410 while (tps) {
411 struct tracepoint_path *t = tps;
412
413 tps = tps->next;
414 free(t->name);
415 free(t->system);
416 free(t);
417 }
418}
419
420bool have_tracepoints(struct list_head *pattrs) 431bool have_tracepoints(struct list_head *pattrs)
421{ 432{
422 struct perf_evsel *pos; 433 struct perf_evsel *pos;
@@ -428,11 +439,19 @@ bool have_tracepoints(struct list_head *pattrs)
428 return false; 439 return false;
429} 440}
430 441
431static void tracing_data_header(void) 442int read_tracing_data(int fd, struct list_head *pattrs)
432{ 443{
433 char buf[20]; 444 char buf[BUFSIZ];
445 struct tracepoint_path *tps = get_tracepoints_path(pattrs);
446
447 /*
448 * What? No tracepoints? No sense writing anything here, bail out.
449 */
450 if (tps == NULL)
451 return -1;
452
453 output_fd = fd;
434 454
435 /* just guessing this is someone's birthday.. ;) */
436 buf[0] = 23; 455 buf[0] = 23;
437 buf[1] = 8; 456 buf[1] = 8;
438 buf[2] = 68; 457 buf[2] = 68;
@@ -448,8 +467,6 @@ static void tracing_data_header(void)
448 else 467 else
449 buf[0] = 0; 468 buf[0] = 0;
450 469
451 read_trace_init(buf[0], buf[0]);
452
453 write_or_die(buf, 1); 470 write_or_die(buf, 1);
454 471
455 /* save size of long */ 472 /* save size of long */
@@ -459,86 +476,28 @@ static void tracing_data_header(void)
459 /* save page_size */ 476 /* save page_size */
460 page_size = sysconf(_SC_PAGESIZE); 477 page_size = sysconf(_SC_PAGESIZE);
461 write_or_die(&page_size, 4); 478 write_or_die(&page_size, 4);
462}
463 479
464struct tracing_data *tracing_data_get(struct list_head *pattrs,
465 int fd, bool temp)
466{
467 struct tracepoint_path *tps;
468 struct tracing_data *tdata;
469
470 output_fd = fd;
471
472 tps = get_tracepoints_path(pattrs);
473 if (!tps)
474 return NULL;
475
476 tdata = malloc_or_die(sizeof(*tdata));
477 tdata->temp = temp;
478 tdata->size = 0;
479
480 if (temp) {
481 int temp_fd;
482
483 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
484 "/tmp/perf-XXXXXX");
485 if (!mkstemp(tdata->temp_file))
486 die("Can't make temp file");
487
488 temp_fd = open(tdata->temp_file, O_RDWR);
489 if (temp_fd < 0)
490 die("Can't read '%s'", tdata->temp_file);
491
492 /*
493 * Set the temp file the default output, so all the
494 * tracing data are stored into it.
495 */
496 output_fd = temp_fd;
497 }
498
499 tracing_data_header();
500 read_header_files(); 480 read_header_files();
501 read_ftrace_files(tps); 481 read_ftrace_files(tps);
502 read_event_files(tps); 482 read_event_files(tps);
503 read_proc_kallsyms(); 483 read_proc_kallsyms();
504 read_ftrace_printk(); 484 read_ftrace_printk();
505 485
506 /* 486 return 0;
507 * All tracing data are stored by now, we can restore
508 * the default output file in case we used temp file.
509 */
510 if (temp) {
511 tdata->size = lseek(output_fd, 0, SEEK_CUR);
512 close(output_fd);
513 output_fd = fd;
514 }
515
516 put_tracepoints_path(tps);
517 return tdata;
518} 487}
519 488
520void tracing_data_put(struct tracing_data *tdata) 489ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
521{ 490{
522 if (tdata->temp) { 491 ssize_t size;
523 record_file(tdata->temp_file, 0); 492 int err = 0;
524 unlink(tdata->temp_file);
525 }
526
527 free(tdata);
528}
529 493
530int read_tracing_data(int fd, struct list_head *pattrs) 494 calc_data_size = 1;
531{ 495 err = read_tracing_data(fd, pattrs);
532 struct tracing_data *tdata; 496 size = calc_data_size - 1;
497 calc_data_size = 0;
533 498
534 /* 499 if (err < 0)
535 * We work over the real file, so we can write data 500 return err;
536 * directly, no temp file is needed.
537 */
538 tdata = tracing_data_get(pattrs, fd, false);
539 if (!tdata)
540 return -ENOMEM;
541 501
542 tracing_data_put(tdata); 502 return size;
543 return 0;
544} 503}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 3aabcd687cd..bf54c48871d 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -17,300 +17,2163 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by Frederic Weisbecker.
20 */ 23 */
24#define _GNU_SOURCE
21#include <stdio.h> 25#include <stdio.h>
22#include <stdlib.h> 26#include <stdlib.h>
23#include <string.h> 27#include <string.h>
24#include <ctype.h> 28#include <ctype.h>
25#include <errno.h> 29#include <errno.h>
26 30
31#undef _GNU_SOURCE
27#include "../perf.h" 32#include "../perf.h"
28#include "util.h" 33#include "util.h"
29#include "trace-event.h" 34#include "trace-event.h"
30 35
31int header_page_size_size; 36int header_page_ts_offset;
32int header_page_ts_size; 37int header_page_ts_size;
38int header_page_size_offset;
39int header_page_size_size;
40int header_page_overwrite_offset;
41int header_page_overwrite_size;
33int header_page_data_offset; 42int header_page_data_offset;
43int header_page_data_size;
34 44
35bool latency_format; 45bool latency_format;
36 46
37struct pevent *read_trace_init(int file_bigendian, int host_bigendian) 47static char *input_buf;
48static unsigned long long input_buf_ptr;
49static unsigned long long input_buf_siz;
50
51static int cpus;
52static int long_size;
53static int is_flag_field;
54static int is_symbolic_field;
55
56static struct format_field *
57find_any_field(struct event *event, const char *name);
58
59static void init_input_buf(char *buf, unsigned long long size)
60{
61 input_buf = buf;
62 input_buf_siz = size;
63 input_buf_ptr = 0;
64}
65
66struct cmdline {
67 char *comm;
68 int pid;
69};
70
71static struct cmdline *cmdlines;
72static int cmdline_count;
73
74static int cmdline_cmp(const void *a, const void *b)
38{ 75{
39 struct pevent *pevent = pevent_alloc(); 76 const struct cmdline *ca = a;
77 const struct cmdline *cb = b;
78
79 if (ca->pid < cb->pid)
80 return -1;
81 if (ca->pid > cb->pid)
82 return 1;
83
84 return 0;
85}
86
87void parse_cmdlines(char *file, int size __unused)
88{
89 struct cmdline_list {
90 struct cmdline_list *next;
91 char *comm;
92 int pid;
93 } *list = NULL, *item;
94 char *line;
95 char *next = NULL;
96 int i;
97
98 line = strtok_r(file, "\n", &next);
99 while (line) {
100 item = malloc_or_die(sizeof(*item));
101 sscanf(line, "%d %as", &item->pid,
102 (float *)(void *)&item->comm); /* workaround gcc warning */
103 item->next = list;
104 list = item;
105 line = strtok_r(NULL, "\n", &next);
106 cmdline_count++;
107 }
40 108
41 if (pevent != NULL) { 109 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
42 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); 110
43 pevent_set_file_bigendian(pevent, file_bigendian); 111 i = 0;
44 pevent_set_host_bigendian(pevent, host_bigendian); 112 while (list) {
113 cmdlines[i].pid = list->pid;
114 cmdlines[i].comm = list->comm;
115 i++;
116 item = list;
117 list = list->next;
118 free(item);
45 } 119 }
46 120
47 return pevent; 121 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
48} 122}
49 123
50static int get_common_field(struct scripting_context *context, 124static struct func_map {
51 int *offset, int *size, const char *type) 125 unsigned long long addr;
126 char *func;
127 char *mod;
128} *func_list;
129static unsigned int func_count;
130
131static int func_cmp(const void *a, const void *b)
52{ 132{
53 struct pevent *pevent = context->pevent; 133 const struct func_map *fa = a;
54 struct event_format *event; 134 const struct func_map *fb = b;
55 struct format_field *field;
56 135
57 if (!*size) { 136 if (fa->addr < fb->addr)
58 if (!pevent->events) 137 return -1;
59 return 0; 138 if (fa->addr > fb->addr)
139 return 1;
60 140
61 event = pevent->events[0]; 141 return 0;
62 field = pevent_find_common_field(event, type); 142}
63 if (!field) 143
64 return 0; 144void parse_proc_kallsyms(char *file, unsigned int size __unused)
65 *offset = field->offset; 145{
66 *size = field->size; 146 struct func_list {
147 struct func_list *next;
148 unsigned long long addr;
149 char *func;
150 char *mod;
151 } *list = NULL, *item;
152 char *line;
153 char *next = NULL;
154 char *addr_str;
155 char ch;
156 int ret __used;
157 int i;
158
159 line = strtok_r(file, "\n", &next);
160 while (line) {
161 item = malloc_or_die(sizeof(*item));
162 item->mod = NULL;
163 ret = sscanf(line, "%as %c %as\t[%as",
164 (float *)(void *)&addr_str, /* workaround gcc warning */
165 &ch,
166 (float *)(void *)&item->func,
167 (float *)(void *)&item->mod);
168 item->addr = strtoull(addr_str, NULL, 16);
169 free(addr_str);
170
171 /* truncate the extra ']' */
172 if (item->mod)
173 item->mod[strlen(item->mod) - 1] = 0;
174
175
176 item->next = list;
177 list = item;
178 line = strtok_r(NULL, "\n", &next);
179 func_count++;
67 } 180 }
68 181
69 return pevent_read_number(pevent, context->event_data + *offset, *size); 182 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
183
184 i = 0;
185 while (list) {
186 func_list[i].func = list->func;
187 func_list[i].addr = list->addr;
188 func_list[i].mod = list->mod;
189 i++;
190 item = list;
191 list = list->next;
192 free(item);
193 }
194
195 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
196
197 /*
198 * Add a special record at the end.
199 */
200 func_list[func_count].func = NULL;
201 func_list[func_count].addr = 0;
202 func_list[func_count].mod = NULL;
70} 203}
71 204
72int common_lock_depth(struct scripting_context *context) 205/*
206 * We are searching for a record in between, not an exact
207 * match.
208 */
209static int func_bcmp(const void *a, const void *b)
73{ 210{
74 static int offset; 211 const struct func_map *fa = a;
75 static int size; 212 const struct func_map *fb = b;
76 int ret;
77 213
78 ret = get_common_field(context, &size, &offset, 214 if ((fa->addr == fb->addr) ||
79 "common_lock_depth"); 215
80 if (ret < 0) 216 (fa->addr > fb->addr &&
217 fa->addr < (fb+1)->addr))
218 return 0;
219
220 if (fa->addr < fb->addr)
81 return -1; 221 return -1;
82 222
83 return ret; 223 return 1;
84} 224}
85 225
86int common_flags(struct scripting_context *context) 226static struct func_map *find_func(unsigned long long addr)
87{ 227{
88 static int offset; 228 struct func_map *func;
89 static int size; 229 struct func_map key;
90 int ret;
91 230
92 ret = get_common_field(context, &size, &offset, 231 key.addr = addr;
93 "common_flags"); 232
94 if (ret < 0) 233 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
234 func_bcmp);
235
236 return func;
237}
238
239void print_funcs(void)
240{
241 int i;
242
243 for (i = 0; i < (int)func_count; i++) {
244 printf("%016llx %s",
245 func_list[i].addr,
246 func_list[i].func);
247 if (func_list[i].mod)
248 printf(" [%s]\n", func_list[i].mod);
249 else
250 printf("\n");
251 }
252}
253
254static struct printk_map {
255 unsigned long long addr;
256 char *printk;
257} *printk_list;
258static unsigned int printk_count;
259
260static int printk_cmp(const void *a, const void *b)
261{
262 const struct func_map *fa = a;
263 const struct func_map *fb = b;
264
265 if (fa->addr < fb->addr)
95 return -1; 266 return -1;
267 if (fa->addr > fb->addr)
268 return 1;
269
270 return 0;
271}
272
273static struct printk_map *find_printk(unsigned long long addr)
274{
275 struct printk_map *printk;
276 struct printk_map key;
277
278 key.addr = addr;
279
280 printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
281 printk_cmp);
282
283 return printk;
284}
285
286void parse_ftrace_printk(char *file, unsigned int size __unused)
287{
288 struct printk_list {
289 struct printk_list *next;
290 unsigned long long addr;
291 char *printk;
292 } *list = NULL, *item;
293 char *line;
294 char *next = NULL;
295 char *addr_str;
296 int i;
297
298 line = strtok_r(file, "\n", &next);
299 while (line) {
300 addr_str = strsep(&line, ":");
301 if (!line) {
302 warning("error parsing print strings");
303 break;
304 }
305 item = malloc_or_die(sizeof(*item));
306 item->addr = strtoull(addr_str, NULL, 16);
307 /* fmt still has a space, skip it */
308 item->printk = strdup(line+1);
309 item->next = list;
310 list = item;
311 line = strtok_r(NULL, "\n", &next);
312 printk_count++;
313 }
314
315 printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
316
317 i = 0;
318 while (list) {
319 printk_list[i].printk = list->printk;
320 printk_list[i].addr = list->addr;
321 i++;
322 item = list;
323 list = list->next;
324 free(item);
325 }
326
327 qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
328}
329
330void print_printk(void)
331{
332 int i;
333
334 for (i = 0; i < (int)printk_count; i++) {
335 printf("%016llx %s\n",
336 printk_list[i].addr,
337 printk_list[i].printk);
338 }
339}
340
341static struct event *alloc_event(void)
342{
343 struct event *event;
344
345 event = malloc_or_die(sizeof(*event));
346 memset(event, 0, sizeof(*event));
347
348 return event;
349}
350
351enum event_type {
352 EVENT_ERROR,
353 EVENT_NONE,
354 EVENT_SPACE,
355 EVENT_NEWLINE,
356 EVENT_OP,
357 EVENT_DELIM,
358 EVENT_ITEM,
359 EVENT_DQUOTE,
360 EVENT_SQUOTE,
361};
362
363static struct event *event_list;
364
365static void add_event(struct event *event)
366{
367 event->next = event_list;
368 event_list = event;
369}
370
371static int event_item_type(enum event_type type)
372{
373 switch (type) {
374 case EVENT_ITEM ... EVENT_SQUOTE:
375 return 1;
376 case EVENT_ERROR ... EVENT_DELIM:
377 default:
378 return 0;
379 }
380}
381
382static void free_arg(struct print_arg *arg)
383{
384 if (!arg)
385 return;
386
387 switch (arg->type) {
388 case PRINT_ATOM:
389 if (arg->atom.atom)
390 free(arg->atom.atom);
391 break;
392 case PRINT_NULL:
393 case PRINT_FIELD ... PRINT_OP:
394 default:
395 /* todo */
396 break;
397 }
398
399 free(arg);
400}
401
402static enum event_type get_type(int ch)
403{
404 if (ch == '\n')
405 return EVENT_NEWLINE;
406 if (isspace(ch))
407 return EVENT_SPACE;
408 if (isalnum(ch) || ch == '_')
409 return EVENT_ITEM;
410 if (ch == '\'')
411 return EVENT_SQUOTE;
412 if (ch == '"')
413 return EVENT_DQUOTE;
414 if (!isprint(ch))
415 return EVENT_NONE;
416 if (ch == '(' || ch == ')' || ch == ',')
417 return EVENT_DELIM;
418
419 return EVENT_OP;
420}
421
422static int __read_char(void)
423{
424 if (input_buf_ptr >= input_buf_siz)
425 return -1;
426
427 return input_buf[input_buf_ptr++];
428}
429
430static int __peek_char(void)
431{
432 if (input_buf_ptr >= input_buf_siz)
433 return -1;
434
435 return input_buf[input_buf_ptr];
436}
437
438static enum event_type __read_token(char **tok)
439{
440 char buf[BUFSIZ];
441 int ch, last_ch, quote_ch, next_ch;
442 int i = 0;
443 int tok_size = 0;
444 enum event_type type;
445
446 *tok = NULL;
447
448
449 ch = __read_char();
450 if (ch < 0)
451 return EVENT_NONE;
452
453 type = get_type(ch);
454 if (type == EVENT_NONE)
455 return type;
456
457 buf[i++] = ch;
458
459 switch (type) {
460 case EVENT_NEWLINE:
461 case EVENT_DELIM:
462 *tok = malloc_or_die(2);
463 (*tok)[0] = ch;
464 (*tok)[1] = 0;
465 return type;
466
467 case EVENT_OP:
468 switch (ch) {
469 case '-':
470 next_ch = __peek_char();
471 if (next_ch == '>') {
472 buf[i++] = __read_char();
473 break;
474 }
475 /* fall through */
476 case '+':
477 case '|':
478 case '&':
479 case '>':
480 case '<':
481 last_ch = ch;
482 ch = __peek_char();
483 if (ch != last_ch)
484 goto test_equal;
485 buf[i++] = __read_char();
486 switch (last_ch) {
487 case '>':
488 case '<':
489 goto test_equal;
490 default:
491 break;
492 }
493 break;
494 case '!':
495 case '=':
496 goto test_equal;
497 default: /* what should we do instead? */
498 break;
499 }
500 buf[i] = 0;
501 *tok = strdup(buf);
502 return type;
503
504 test_equal:
505 ch = __peek_char();
506 if (ch == '=')
507 buf[i++] = __read_char();
508 break;
509
510 case EVENT_DQUOTE:
511 case EVENT_SQUOTE:
512 /* don't keep quotes */
513 i--;
514 quote_ch = ch;
515 last_ch = 0;
516 do {
517 if (i == (BUFSIZ - 1)) {
518 buf[i] = 0;
519 if (*tok) {
520 *tok = realloc(*tok, tok_size + BUFSIZ);
521 if (!*tok)
522 return EVENT_NONE;
523 strcat(*tok, buf);
524 } else
525 *tok = strdup(buf);
526
527 if (!*tok)
528 return EVENT_NONE;
529 tok_size += BUFSIZ;
530 i = 0;
531 }
532 last_ch = ch;
533 ch = __read_char();
534 buf[i++] = ch;
535 /* the '\' '\' will cancel itself */
536 if (ch == '\\' && last_ch == '\\')
537 last_ch = 0;
538 } while (ch != quote_ch || last_ch == '\\');
539 /* remove the last quote */
540 i--;
541 goto out;
542
543 case EVENT_ERROR ... EVENT_SPACE:
544 case EVENT_ITEM:
545 default:
546 break;
547 }
548
549 while (get_type(__peek_char()) == type) {
550 if (i == (BUFSIZ - 1)) {
551 buf[i] = 0;
552 if (*tok) {
553 *tok = realloc(*tok, tok_size + BUFSIZ);
554 if (!*tok)
555 return EVENT_NONE;
556 strcat(*tok, buf);
557 } else
558 *tok = strdup(buf);
559
560 if (!*tok)
561 return EVENT_NONE;
562 tok_size += BUFSIZ;
563 i = 0;
564 }
565 ch = __read_char();
566 buf[i++] = ch;
567 }
568
569 out:
570 buf[i] = 0;
571 if (*tok) {
572 *tok = realloc(*tok, tok_size + i);
573 if (!*tok)
574 return EVENT_NONE;
575 strcat(*tok, buf);
576 } else
577 *tok = strdup(buf);
578 if (!*tok)
579 return EVENT_NONE;
580
581 return type;
582}
583
584static void free_token(char *tok)
585{
586 if (tok)
587 free(tok);
588}
589
590static enum event_type read_token(char **tok)
591{
592 enum event_type type;
593
594 for (;;) {
595 type = __read_token(tok);
596 if (type != EVENT_SPACE)
597 return type;
598
599 free_token(*tok);
600 }
601
602 /* not reached */
603 return EVENT_NONE;
604}
605
606/* no newline */
607static enum event_type read_token_item(char **tok)
608{
609 enum event_type type;
610
611 for (;;) {
612 type = __read_token(tok);
613 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
614 return type;
615
616 free_token(*tok);
617 }
618
619 /* not reached */
620 return EVENT_NONE;
621}
622
623static int test_type(enum event_type type, enum event_type expect)
624{
625 if (type != expect) {
626 warning("Error: expected type %d but read %d",
627 expect, type);
628 return -1;
629 }
630 return 0;
631}
632
633static int __test_type_token(enum event_type type, char *token,
634 enum event_type expect, const char *expect_tok,
635 bool warn)
636{
637 if (type != expect) {
638 if (warn)
639 warning("Error: expected type %d but read %d",
640 expect, type);
641 return -1;
642 }
643
644 if (strcmp(token, expect_tok) != 0) {
645 if (warn)
646 warning("Error: expected '%s' but read '%s'",
647 expect_tok, token);
648 return -1;
649 }
650 return 0;
651}
652
653static int test_type_token(enum event_type type, char *token,
654 enum event_type expect, const char *expect_tok)
655{
656 return __test_type_token(type, token, expect, expect_tok, true);
657}
658
659static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
660{
661 enum event_type type;
662
663 if (newline_ok)
664 type = read_token(tok);
665 else
666 type = read_token_item(tok);
667 return test_type(type, expect);
668}
669
670static int read_expect_type(enum event_type expect, char **tok)
671{
672 return __read_expect_type(expect, tok, 1);
673}
674
675static int __read_expected(enum event_type expect, const char *str,
676 int newline_ok, bool warn)
677{
678 enum event_type type;
679 char *token;
680 int ret;
681
682 if (newline_ok)
683 type = read_token(&token);
684 else
685 type = read_token_item(&token);
686
687 ret = __test_type_token(type, token, expect, str, warn);
688
689 free_token(token);
96 690
97 return ret; 691 return ret;
98} 692}
99 693
100int common_pc(struct scripting_context *context) 694static int read_expected(enum event_type expect, const char *str)
695{
696 return __read_expected(expect, str, 1, true);
697}
698
699static int read_expected_item(enum event_type expect, const char *str)
101{ 700{
102 static int offset; 701 return __read_expected(expect, str, 0, true);
103 static int size; 702}
703
704static char *event_read_name(void)
705{
706 char *token;
707
708 if (read_expected(EVENT_ITEM, "name") < 0)
709 return NULL;
710
711 if (read_expected(EVENT_OP, ":") < 0)
712 return NULL;
713
714 if (read_expect_type(EVENT_ITEM, &token) < 0)
715 goto fail;
716
717 return token;
718
719 fail:
720 free_token(token);
721 return NULL;
722}
723
724static int event_read_id(void)
725{
726 char *token;
727 int id;
728
729 if (read_expected_item(EVENT_ITEM, "ID") < 0)
730 return -1;
731
732 if (read_expected(EVENT_OP, ":") < 0)
733 return -1;
734
735 if (read_expect_type(EVENT_ITEM, &token) < 0)
736 goto fail;
737
738 id = strtoul(token, NULL, 0);
739 free_token(token);
740 return id;
741
742 fail:
743 free_token(token);
744 return -1;
745}
746
747static int field_is_string(struct format_field *field)
748{
749 if ((field->flags & FIELD_IS_ARRAY) &&
750 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
751 !strstr(field->type, "s8")))
752 return 1;
753
754 return 0;
755}
756
757static int field_is_dynamic(struct format_field *field)
758{
759 if (!strncmp(field->type, "__data_loc", 10))
760 return 1;
761
762 return 0;
763}
764
765static int event_read_fields(struct event *event, struct format_field **fields)
766{
767 struct format_field *field = NULL;
768 enum event_type type;
769 char *token;
770 char *last_token;
771 int count = 0;
772
773 do {
774 type = read_token(&token);
775 if (type == EVENT_NEWLINE) {
776 free_token(token);
777 return count;
778 }
779
780 count++;
781
782 if (test_type_token(type, token, EVENT_ITEM, "field"))
783 goto fail;
784 free_token(token);
785
786 type = read_token(&token);
787 /*
788 * The ftrace fields may still use the "special" name.
789 * Just ignore it.
790 */
791 if (event->flags & EVENT_FL_ISFTRACE &&
792 type == EVENT_ITEM && strcmp(token, "special") == 0) {
793 free_token(token);
794 type = read_token(&token);
795 }
796
797 if (test_type_token(type, token, EVENT_OP, ":") < 0)
798 return -1;
799
800 if (read_expect_type(EVENT_ITEM, &token) < 0)
801 goto fail;
802
803 last_token = token;
804
805 field = malloc_or_die(sizeof(*field));
806 memset(field, 0, sizeof(*field));
807
808 /* read the rest of the type */
809 for (;;) {
810 type = read_token(&token);
811 if (type == EVENT_ITEM ||
812 (type == EVENT_OP && strcmp(token, "*") == 0) ||
813 /*
814 * Some of the ftrace fields are broken and have
815 * an illegal "." in them.
816 */
817 (event->flags & EVENT_FL_ISFTRACE &&
818 type == EVENT_OP && strcmp(token, ".") == 0)) {
819
820 if (strcmp(token, "*") == 0)
821 field->flags |= FIELD_IS_POINTER;
822
823 if (field->type) {
824 field->type = realloc(field->type,
825 strlen(field->type) +
826 strlen(last_token) + 2);
827 strcat(field->type, " ");
828 strcat(field->type, last_token);
829 } else
830 field->type = last_token;
831 last_token = token;
832 continue;
833 }
834
835 break;
836 }
837
838 if (!field->type) {
839 die("no type found");
840 goto fail;
841 }
842 field->name = last_token;
843
844 if (test_type(type, EVENT_OP))
845 goto fail;
846
847 if (strcmp(token, "[") == 0) {
848 enum event_type last_type = type;
849 char *brackets = token;
850 int len;
851
852 field->flags |= FIELD_IS_ARRAY;
853
854 type = read_token(&token);
855 while (strcmp(token, "]") != 0) {
856 if (last_type == EVENT_ITEM &&
857 type == EVENT_ITEM)
858 len = 2;
859 else
860 len = 1;
861 last_type = type;
862
863 brackets = realloc(brackets,
864 strlen(brackets) +
865 strlen(token) + len);
866 if (len == 2)
867 strcat(brackets, " ");
868 strcat(brackets, token);
869 free_token(token);
870 type = read_token(&token);
871 if (type == EVENT_NONE) {
872 die("failed to find token");
873 goto fail;
874 }
875 }
876
877 free_token(token);
878
879 brackets = realloc(brackets, strlen(brackets) + 2);
880 strcat(brackets, "]");
881
882 /* add brackets to type */
883
884 type = read_token(&token);
885 /*
886 * If the next token is not an OP, then it is of
887 * the format: type [] item;
888 */
889 if (type == EVENT_ITEM) {
890 field->type = realloc(field->type,
891 strlen(field->type) +
892 strlen(field->name) +
893 strlen(brackets) + 2);
894 strcat(field->type, " ");
895 strcat(field->type, field->name);
896 free_token(field->name);
897 strcat(field->type, brackets);
898 field->name = token;
899 type = read_token(&token);
900 } else {
901 field->type = realloc(field->type,
902 strlen(field->type) +
903 strlen(brackets) + 1);
904 strcat(field->type, brackets);
905 }
906 free(brackets);
907 }
908
909 if (field_is_string(field)) {
910 field->flags |= FIELD_IS_STRING;
911 if (field_is_dynamic(field))
912 field->flags |= FIELD_IS_DYNAMIC;
913 }
914
915 if (test_type_token(type, token, EVENT_OP, ";"))
916 goto fail;
917 free_token(token);
918
919 if (read_expected(EVENT_ITEM, "offset") < 0)
920 goto fail_expect;
921
922 if (read_expected(EVENT_OP, ":") < 0)
923 goto fail_expect;
924
925 if (read_expect_type(EVENT_ITEM, &token))
926 goto fail;
927 field->offset = strtoul(token, NULL, 0);
928 free_token(token);
929
930 if (read_expected(EVENT_OP, ";") < 0)
931 goto fail_expect;
932
933 if (read_expected(EVENT_ITEM, "size") < 0)
934 goto fail_expect;
935
936 if (read_expected(EVENT_OP, ":") < 0)
937 goto fail_expect;
938
939 if (read_expect_type(EVENT_ITEM, &token))
940 goto fail;
941 field->size = strtoul(token, NULL, 0);
942 free_token(token);
943
944 if (read_expected(EVENT_OP, ";") < 0)
945 goto fail_expect;
946
947 type = read_token(&token);
948 if (type != EVENT_NEWLINE) {
949 /* newer versions of the kernel have a "signed" type */
950 if (test_type_token(type, token, EVENT_ITEM, "signed"))
951 goto fail;
952
953 free_token(token);
954
955 if (read_expected(EVENT_OP, ":") < 0)
956 goto fail_expect;
957
958 if (read_expect_type(EVENT_ITEM, &token))
959 goto fail;
960
961 if (strtoul(token, NULL, 0))
962 field->flags |= FIELD_IS_SIGNED;
963
964 free_token(token);
965 if (read_expected(EVENT_OP, ";") < 0)
966 goto fail_expect;
967
968 if (read_expect_type(EVENT_NEWLINE, &token))
969 goto fail;
970 }
971
972 free_token(token);
973
974 *fields = field;
975 fields = &field->next;
976
977 } while (1);
978
979 return 0;
980
981fail:
982 free_token(token);
983fail_expect:
984 if (field)
985 free(field);
986 return -1;
987}
988
989static int event_read_format(struct event *event)
990{
991 char *token;
104 int ret; 992 int ret;
105 993
106 ret = get_common_field(context, &size, &offset, 994 if (read_expected_item(EVENT_ITEM, "format") < 0)
107 "common_preempt_count");
108 if (ret < 0)
109 return -1; 995 return -1;
110 996
111 return ret; 997 if (read_expected(EVENT_OP, ":") < 0)
998 return -1;
999
1000 if (read_expect_type(EVENT_NEWLINE, &token))
1001 goto fail;
1002 free_token(token);
1003
1004 ret = event_read_fields(event, &event->format.common_fields);
1005 if (ret < 0)
1006 return ret;
1007 event->format.nr_common = ret;
1008
1009 ret = event_read_fields(event, &event->format.fields);
1010 if (ret < 0)
1011 return ret;
1012 event->format.nr_fields = ret;
1013
1014 return 0;
1015
1016 fail:
1017 free_token(token);
1018 return -1;
112} 1019}
113 1020
114unsigned long long 1021enum event_type
115raw_field_value(struct event_format *event, const char *name, void *data) 1022process_arg_token(struct event *event, struct print_arg *arg,
1023 char **tok, enum event_type type);
1024
1025static enum event_type
1026process_arg(struct event *event, struct print_arg *arg, char **tok)
116{ 1027{
117 struct format_field *field; 1028 enum event_type type;
118 unsigned long long val; 1029 char *token;
119 1030
120 field = pevent_find_any_field(event, name); 1031 type = read_token(&token);
121 if (!field) 1032 *tok = token;
122 return 0ULL;
123 1033
124 pevent_read_number_field(field, data, &val); 1034 return process_arg_token(event, arg, tok, type);
1035}
125 1036
126 return val; 1037static enum event_type
1038process_cond(struct event *event, struct print_arg *top, char **tok)
1039{
1040 struct print_arg *arg, *left, *right;
1041 enum event_type type;
1042 char *token = NULL;
1043
1044 arg = malloc_or_die(sizeof(*arg));
1045 memset(arg, 0, sizeof(*arg));
1046
1047 left = malloc_or_die(sizeof(*left));
1048
1049 right = malloc_or_die(sizeof(*right));
1050
1051 arg->type = PRINT_OP;
1052 arg->op.left = left;
1053 arg->op.right = right;
1054
1055 *tok = NULL;
1056 type = process_arg(event, left, &token);
1057 if (test_type_token(type, token, EVENT_OP, ":"))
1058 goto out_free;
1059
1060 arg->op.op = token;
1061
1062 type = process_arg(event, right, &token);
1063
1064 top->op.right = arg;
1065
1066 *tok = token;
1067 return type;
1068
1069out_free:
1070 free_token(*tok);
1071 free(right);
1072 free(left);
1073 free_arg(arg);
1074 return EVENT_ERROR;
127} 1075}
128 1076
129void *raw_field_ptr(struct event_format *event, const char *name, void *data) 1077static enum event_type
1078process_array(struct event *event, struct print_arg *top, char **tok)
130{ 1079{
131 struct format_field *field; 1080 struct print_arg *arg;
1081 enum event_type type;
1082 char *token = NULL;
132 1083
133 field = pevent_find_any_field(event, name); 1084 arg = malloc_or_die(sizeof(*arg));
134 if (!field) 1085 memset(arg, 0, sizeof(*arg));
135 return NULL;
136 1086
137 if (field->flags & FIELD_IS_DYNAMIC) { 1087 *tok = NULL;
138 int offset; 1088 type = process_arg(event, arg, &token);
1089 if (test_type_token(type, token, EVENT_OP, "]"))
1090 goto out_free;
139 1091
140 offset = *(int *)(data + field->offset); 1092 top->op.right = arg;
141 offset &= 0xffff;
142 1093
143 return data + offset; 1094 free_token(token);
1095 type = read_token_item(&token);
1096 *tok = token;
1097
1098 return type;
1099
1100out_free:
1101 free_token(*tok);
1102 free_arg(arg);
1103 return EVENT_ERROR;
1104}
1105
1106static int get_op_prio(char *op)
1107{
1108 if (!op[1]) {
1109 switch (op[0]) {
1110 case '*':
1111 case '/':
1112 case '%':
1113 return 6;
1114 case '+':
1115 case '-':
1116 return 7;
1117 /* '>>' and '<<' are 8 */
1118 case '<':
1119 case '>':
1120 return 9;
1121 /* '==' and '!=' are 10 */
1122 case '&':
1123 return 11;
1124 case '^':
1125 return 12;
1126 case '|':
1127 return 13;
1128 case '?':
1129 return 16;
1130 default:
1131 die("unknown op '%c'", op[0]);
1132 return -1;
1133 }
1134 } else {
1135 if (strcmp(op, "++") == 0 ||
1136 strcmp(op, "--") == 0) {
1137 return 3;
1138 } else if (strcmp(op, ">>") == 0 ||
1139 strcmp(op, "<<") == 0) {
1140 return 8;
1141 } else if (strcmp(op, ">=") == 0 ||
1142 strcmp(op, "<=") == 0) {
1143 return 9;
1144 } else if (strcmp(op, "==") == 0 ||
1145 strcmp(op, "!=") == 0) {
1146 return 10;
1147 } else if (strcmp(op, "&&") == 0) {
1148 return 14;
1149 } else if (strcmp(op, "||") == 0) {
1150 return 15;
1151 } else {
1152 die("unknown op '%s'", op);
1153 return -1;
1154 }
144 } 1155 }
1156}
145 1157
146 return data + field->offset; 1158static void set_op_prio(struct print_arg *arg)
1159{
1160
1161 /* single ops are the greatest */
1162 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
1163 arg->op.prio = 0;
1164 return;
1165 }
1166
1167 arg->op.prio = get_op_prio(arg->op.op);
147} 1168}
148 1169
149int trace_parse_common_type(struct pevent *pevent, void *data) 1170static enum event_type
1171process_op(struct event *event, struct print_arg *arg, char **tok)
150{ 1172{
151 struct pevent_record record; 1173 struct print_arg *left, *right = NULL;
1174 enum event_type type;
1175 char *token;
1176
1177 /* the op is passed in via tok */
1178 token = *tok;
1179
1180 if (arg->type == PRINT_OP && !arg->op.left) {
1181 /* handle single op */
1182 if (token[1]) {
1183 die("bad op token %s", token);
1184 return EVENT_ERROR;
1185 }
1186 switch (token[0]) {
1187 case '!':
1188 case '+':
1189 case '-':
1190 break;
1191 default:
1192 die("bad op token %s", token);
1193 return EVENT_ERROR;
1194 }
1195
1196 /* make an empty left */
1197 left = malloc_or_die(sizeof(*left));
1198 left->type = PRINT_NULL;
1199 arg->op.left = left;
1200
1201 right = malloc_or_die(sizeof(*right));
1202 arg->op.right = right;
1203
1204 type = process_arg(event, right, tok);
1205
1206 } else if (strcmp(token, "?") == 0) {
1207
1208 left = malloc_or_die(sizeof(*left));
1209 /* copy the top arg to the left */
1210 *left = *arg;
1211
1212 arg->type = PRINT_OP;
1213 arg->op.op = token;
1214 arg->op.left = left;
1215 arg->op.prio = 0;
1216
1217 type = process_cond(event, arg, tok);
1218
1219 } else if (strcmp(token, ">>") == 0 ||
1220 strcmp(token, "<<") == 0 ||
1221 strcmp(token, "&") == 0 ||
1222 strcmp(token, "|") == 0 ||
1223 strcmp(token, "&&") == 0 ||
1224 strcmp(token, "||") == 0 ||
1225 strcmp(token, "-") == 0 ||
1226 strcmp(token, "+") == 0 ||
1227 strcmp(token, "*") == 0 ||
1228 strcmp(token, "^") == 0 ||
1229 strcmp(token, "/") == 0 ||
1230 strcmp(token, "<") == 0 ||
1231 strcmp(token, ">") == 0 ||
1232 strcmp(token, "==") == 0 ||
1233 strcmp(token, "!=") == 0) {
1234
1235 left = malloc_or_die(sizeof(*left));
1236
1237 /* copy the top arg to the left */
1238 *left = *arg;
1239
1240 arg->type = PRINT_OP;
1241 arg->op.op = token;
1242 arg->op.left = left;
1243
1244 set_op_prio(arg);
1245
1246 right = malloc_or_die(sizeof(*right));
1247
1248 type = read_token_item(&token);
1249 *tok = token;
1250
1251 /* could just be a type pointer */
1252 if ((strcmp(arg->op.op, "*") == 0) &&
1253 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1254 if (left->type != PRINT_ATOM)
1255 die("bad pointer type");
1256 left->atom.atom = realloc(left->atom.atom,
1257 sizeof(left->atom.atom) + 3);
1258 strcat(left->atom.atom, " *");
1259 *arg = *left;
1260 free(arg);
1261
1262 return type;
1263 }
152 1264
153 record.data = data; 1265 type = process_arg_token(event, right, tok, type);
154 return pevent_data_type(pevent, &record); 1266
1267 arg->op.right = right;
1268
1269 } else if (strcmp(token, "[") == 0) {
1270
1271 left = malloc_or_die(sizeof(*left));
1272 *left = *arg;
1273
1274 arg->type = PRINT_OP;
1275 arg->op.op = token;
1276 arg->op.left = left;
1277
1278 arg->op.prio = 0;
1279 type = process_array(event, arg, tok);
1280
1281 } else {
1282 warning("unknown op '%s'", token);
1283 event->flags |= EVENT_FL_FAILED;
1284 /* the arg is now the left side */
1285 return EVENT_NONE;
1286 }
1287
1288 if (type == EVENT_OP) {
1289 int prio;
1290
1291 /* higher prios need to be closer to the root */
1292 prio = get_op_prio(*tok);
1293
1294 if (prio > arg->op.prio)
1295 return process_op(event, arg, tok);
1296
1297 return process_op(event, right, tok);
1298 }
1299
1300 return type;
155} 1301}
156 1302
157int trace_parse_common_pid(struct pevent *pevent, void *data) 1303static enum event_type
1304process_entry(struct event *event __unused, struct print_arg *arg,
1305 char **tok)
158{ 1306{
159 struct pevent_record record; 1307 enum event_type type;
1308 char *field;
1309 char *token;
1310
1311 if (read_expected(EVENT_OP, "->") < 0)
1312 return EVENT_ERROR;
1313
1314 if (read_expect_type(EVENT_ITEM, &token) < 0)
1315 goto fail;
1316 field = token;
1317
1318 arg->type = PRINT_FIELD;
1319 arg->field.name = field;
1320
1321 if (is_flag_field) {
1322 arg->field.field = find_any_field(event, arg->field.name);
1323 arg->field.field->flags |= FIELD_IS_FLAG;
1324 is_flag_field = 0;
1325 } else if (is_symbolic_field) {
1326 arg->field.field = find_any_field(event, arg->field.name);
1327 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1328 is_symbolic_field = 0;
1329 }
1330
1331 type = read_token(&token);
1332 *tok = token;
160 1333
161 record.data = data; 1334 return type;
162 return pevent_data_pid(pevent, &record); 1335
1336fail:
1337 free_token(token);
1338 return EVENT_ERROR;
163} 1339}
164 1340
165unsigned long long read_size(struct event_format *event, void *ptr, int size) 1341static char *arg_eval (struct print_arg *arg);
1342
1343static long long arg_num_eval(struct print_arg *arg)
166{ 1344{
167 return pevent_read_number(event->pevent, ptr, size); 1345 long long left, right;
1346 long long val = 0;
1347
1348 switch (arg->type) {
1349 case PRINT_ATOM:
1350 val = strtoll(arg->atom.atom, NULL, 0);
1351 break;
1352 case PRINT_TYPE:
1353 val = arg_num_eval(arg->typecast.item);
1354 break;
1355 case PRINT_OP:
1356 switch (arg->op.op[0]) {
1357 case '|':
1358 left = arg_num_eval(arg->op.left);
1359 right = arg_num_eval(arg->op.right);
1360 if (arg->op.op[1])
1361 val = left || right;
1362 else
1363 val = left | right;
1364 break;
1365 case '&':
1366 left = arg_num_eval(arg->op.left);
1367 right = arg_num_eval(arg->op.right);
1368 if (arg->op.op[1])
1369 val = left && right;
1370 else
1371 val = left & right;
1372 break;
1373 case '<':
1374 left = arg_num_eval(arg->op.left);
1375 right = arg_num_eval(arg->op.right);
1376 switch (arg->op.op[1]) {
1377 case 0:
1378 val = left < right;
1379 break;
1380 case '<':
1381 val = left << right;
1382 break;
1383 case '=':
1384 val = left <= right;
1385 break;
1386 default:
1387 die("unknown op '%s'", arg->op.op);
1388 }
1389 break;
1390 case '>':
1391 left = arg_num_eval(arg->op.left);
1392 right = arg_num_eval(arg->op.right);
1393 switch (arg->op.op[1]) {
1394 case 0:
1395 val = left > right;
1396 break;
1397 case '>':
1398 val = left >> right;
1399 break;
1400 case '=':
1401 val = left >= right;
1402 break;
1403 default:
1404 die("unknown op '%s'", arg->op.op);
1405 }
1406 break;
1407 case '=':
1408 left = arg_num_eval(arg->op.left);
1409 right = arg_num_eval(arg->op.right);
1410
1411 if (arg->op.op[1] != '=')
1412 die("unknown op '%s'", arg->op.op);
1413
1414 val = left == right;
1415 break;
1416 case '!':
1417 left = arg_num_eval(arg->op.left);
1418 right = arg_num_eval(arg->op.right);
1419
1420 switch (arg->op.op[1]) {
1421 case '=':
1422 val = left != right;
1423 break;
1424 default:
1425 die("unknown op '%s'", arg->op.op);
1426 }
1427 break;
1428 default:
1429 die("unknown op '%s'", arg->op.op);
1430 }
1431 break;
1432
1433 case PRINT_NULL:
1434 case PRINT_FIELD ... PRINT_SYMBOL:
1435 case PRINT_STRING:
1436 default:
1437 die("invalid eval type %d", arg->type);
1438
1439 }
1440 return val;
168} 1441}
169 1442
170void event_format__print(struct event_format *event, 1443static char *arg_eval (struct print_arg *arg)
171 int cpu, void *data, int size)
172{ 1444{
173 struct pevent_record record; 1445 long long val;
174 struct trace_seq s; 1446 static char buf[20];
1447
1448 switch (arg->type) {
1449 case PRINT_ATOM:
1450 return arg->atom.atom;
1451 case PRINT_TYPE:
1452 return arg_eval(arg->typecast.item);
1453 case PRINT_OP:
1454 val = arg_num_eval(arg);
1455 sprintf(buf, "%lld", val);
1456 return buf;
1457
1458 case PRINT_NULL:
1459 case PRINT_FIELD ... PRINT_SYMBOL:
1460 case PRINT_STRING:
1461 default:
1462 die("invalid eval type %d", arg->type);
1463 break;
1464 }
1465
1466 return NULL;
1467}
1468
1469static enum event_type
1470process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1471{
1472 enum event_type type;
1473 struct print_arg *arg = NULL;
1474 struct print_flag_sym *field;
1475 char *token = NULL;
1476 char *value;
1477
1478 do {
1479 free_token(token);
1480 type = read_token_item(&token);
1481 if (test_type_token(type, token, EVENT_OP, "{"))
1482 break;
1483
1484 arg = malloc_or_die(sizeof(*arg));
1485
1486 free_token(token);
1487 type = process_arg(event, arg, &token);
1488 if (test_type_token(type, token, EVENT_DELIM, ","))
1489 goto out_free;
175 1490
176 memset(&record, 0, sizeof(record)); 1491 field = malloc_or_die(sizeof(*field));
177 record.cpu = cpu; 1492 memset(field, 0, sizeof(*field));
178 record.size = size;
179 record.data = data;
180 1493
181 trace_seq_init(&s); 1494 value = arg_eval(arg);
182 pevent_event_info(&s, event, &record); 1495 field->value = strdup(value);
183 trace_seq_do_printf(&s); 1496
1497 free_token(token);
1498 type = process_arg(event, arg, &token);
1499 if (test_type_token(type, token, EVENT_OP, "}"))
1500 goto out_free;
1501
1502 value = arg_eval(arg);
1503 field->str = strdup(value);
1504 free_arg(arg);
1505 arg = NULL;
1506
1507 *list = field;
1508 list = &field->next;
1509
1510 free_token(token);
1511 type = read_token_item(&token);
1512 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1513
1514 *tok = token;
1515 return type;
1516
1517out_free:
1518 free_arg(arg);
1519 free_token(token);
1520
1521 return EVENT_ERROR;
184} 1522}
185 1523
186void print_trace_event(struct pevent *pevent, int cpu, void *data, int size) 1524static enum event_type
1525process_flags(struct event *event, struct print_arg *arg, char **tok)
187{ 1526{
188 int type = trace_parse_common_type(pevent, data); 1527 struct print_arg *field;
189 struct event_format *event = pevent_find_event(pevent, type); 1528 enum event_type type;
1529 char *token;
190 1530
191 if (!event) { 1531 memset(arg, 0, sizeof(*arg));
192 warning("ug! no event found for type %d", type); 1532 arg->type = PRINT_FLAGS;
193 return; 1533
1534 if (read_expected_item(EVENT_DELIM, "(") < 0)
1535 return EVENT_ERROR;
1536
1537 field = malloc_or_die(sizeof(*field));
1538
1539 type = process_arg(event, field, &token);
1540 while (type == EVENT_OP)
1541 type = process_op(event, field, &token);
1542 if (test_type_token(type, token, EVENT_DELIM, ","))
1543 goto out_free;
1544
1545 arg->flags.field = field;
1546
1547 type = read_token_item(&token);
1548 if (event_item_type(type)) {
1549 arg->flags.delim = token;
1550 type = read_token_item(&token);
194 } 1551 }
195 1552
196 event_format__print(event, cpu, data, size); 1553 if (test_type_token(type, token, EVENT_DELIM, ","))
1554 goto out_free;
1555
1556 type = process_fields(event, &arg->flags.flags, &token);
1557 if (test_type_token(type, token, EVENT_DELIM, ")"))
1558 goto out_free;
1559
1560 free_token(token);
1561 type = read_token_item(tok);
1562 return type;
1563
1564out_free:
1565 free_token(token);
1566 return EVENT_ERROR;
197} 1567}
198 1568
199void print_event(struct pevent *pevent, int cpu, void *data, int size, 1569static enum event_type
200 unsigned long long nsecs, char *comm) 1570process_symbols(struct event *event, struct print_arg *arg, char **tok)
201{ 1571{
202 struct pevent_record record; 1572 struct print_arg *field;
203 struct trace_seq s; 1573 enum event_type type;
204 int pid; 1574 char *token;
205 1575
206 pevent->latency_format = latency_format; 1576 memset(arg, 0, sizeof(*arg));
1577 arg->type = PRINT_SYMBOL;
207 1578
208 record.ts = nsecs; 1579 if (read_expected_item(EVENT_DELIM, "(") < 0)
209 record.cpu = cpu; 1580 return EVENT_ERROR;
210 record.size = size;
211 record.data = data;
212 pid = pevent_data_pid(pevent, &record);
213 1581
214 if (!pevent_pid_is_registered(pevent, pid)) 1582 field = malloc_or_die(sizeof(*field));
215 pevent_register_comm(pevent, comm, pid);
216 1583
217 trace_seq_init(&s); 1584 type = process_arg(event, field, &token);
218 pevent_print_event(pevent, &s, &record); 1585 while (type == EVENT_OP)
219 trace_seq_do_printf(&s); 1586 type = process_op(event, field, &token);
220 printf("\n"); 1587 if (test_type_token(type, token, EVENT_DELIM, ","))
1588 goto out_free;
1589
1590 arg->symbol.field = field;
1591
1592 type = process_fields(event, &arg->symbol.symbols, &token);
1593 if (test_type_token(type, token, EVENT_DELIM, ")"))
1594 goto out_free;
1595
1596 free_token(token);
1597 type = read_token_item(tok);
1598 return type;
1599
1600out_free:
1601 free_token(token);
1602 return EVENT_ERROR;
221} 1603}
222 1604
223void parse_proc_kallsyms(struct pevent *pevent, 1605static enum event_type
224 char *file, unsigned int size __maybe_unused) 1606process_paren(struct event *event, struct print_arg *arg, char **tok)
225{ 1607{
226 unsigned long long addr; 1608 struct print_arg *item_arg;
227 char *func; 1609 enum event_type type;
228 char *line; 1610 char *token;
229 char *next = NULL;
230 char *addr_str;
231 char *mod;
232 char *fmt;
233 1611
234 line = strtok_r(file, "\n", &next); 1612 type = process_arg(event, arg, &token);
235 while (line) {
236 mod = NULL;
237 addr_str = strtok_r(line, " ", &fmt);
238 addr = strtoull(addr_str, NULL, 16);
239 /* skip character */
240 strtok_r(NULL, " ", &fmt);
241 func = strtok_r(NULL, "\t", &fmt);
242 mod = strtok_r(NULL, "]", &fmt);
243 /* truncate the extra '[' */
244 if (mod)
245 mod = mod + 1;
246
247 pevent_register_function(pevent, func, addr, mod);
248 1613
249 line = strtok_r(NULL, "\n", &next); 1614 if (type == EVENT_ERROR)
1615 return EVENT_ERROR;
1616
1617 if (type == EVENT_OP)
1618 type = process_op(event, arg, &token);
1619
1620 if (type == EVENT_ERROR)
1621 return EVENT_ERROR;
1622
1623 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1624 free_token(token);
1625 return EVENT_ERROR;
250 } 1626 }
1627
1628 free_token(token);
1629 type = read_token_item(&token);
1630
1631 /*
1632 * If the next token is an item or another open paren, then
1633 * this was a typecast.
1634 */
1635 if (event_item_type(type) ||
1636 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1637
1638 /* make this a typecast and contine */
1639
1640 /* prevous must be an atom */
1641 if (arg->type != PRINT_ATOM)
1642 die("previous needed to be PRINT_ATOM");
1643
1644 item_arg = malloc_or_die(sizeof(*item_arg));
1645
1646 arg->type = PRINT_TYPE;
1647 arg->typecast.type = arg->atom.atom;
1648 arg->typecast.item = item_arg;
1649 type = process_arg_token(event, item_arg, &token, type);
1650
1651 }
1652
1653 *tok = token;
1654 return type;
251} 1655}
252 1656
253void parse_ftrace_printk(struct pevent *pevent, 1657
254 char *file, unsigned int size __maybe_unused) 1658static enum event_type
1659process_str(struct event *event __unused, struct print_arg *arg, char **tok)
255{ 1660{
256 unsigned long long addr; 1661 enum event_type type;
257 char *printk; 1662 char *token;
258 char *line;
259 char *next = NULL;
260 char *addr_str;
261 char *fmt;
262 1663
263 line = strtok_r(file, "\n", &next); 1664 if (read_expected(EVENT_DELIM, "(") < 0)
264 while (line) { 1665 return EVENT_ERROR;
265 addr_str = strtok_r(line, ":", &fmt); 1666
266 if (!addr_str) { 1667 if (read_expect_type(EVENT_ITEM, &token) < 0)
267 warning("printk format with empty entry"); 1668 goto fail;
1669
1670 arg->type = PRINT_STRING;
1671 arg->string.string = token;
1672 arg->string.offset = -1;
1673
1674 if (read_expected(EVENT_DELIM, ")") < 0)
1675 return EVENT_ERROR;
1676
1677 type = read_token(&token);
1678 *tok = token;
1679
1680 return type;
1681fail:
1682 free_token(token);
1683 return EVENT_ERROR;
1684}
1685
1686enum event_type
1687process_arg_token(struct event *event, struct print_arg *arg,
1688 char **tok, enum event_type type)
1689{
1690 char *token;
1691 char *atom;
1692
1693 token = *tok;
1694
1695 switch (type) {
1696 case EVENT_ITEM:
1697 if (strcmp(token, "REC") == 0) {
1698 free_token(token);
1699 type = process_entry(event, arg, &token);
1700 } else if (strcmp(token, "__print_flags") == 0) {
1701 free_token(token);
1702 is_flag_field = 1;
1703 type = process_flags(event, arg, &token);
1704 } else if (strcmp(token, "__print_symbolic") == 0) {
1705 free_token(token);
1706 is_symbolic_field = 1;
1707 type = process_symbols(event, arg, &token);
1708 } else if (strcmp(token, "__get_str") == 0) {
1709 free_token(token);
1710 type = process_str(event, arg, &token);
1711 } else {
1712 atom = token;
1713 /* test the next token */
1714 type = read_token_item(&token);
1715
1716 /* atoms can be more than one token long */
1717 while (type == EVENT_ITEM) {
1718 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1719 strcat(atom, " ");
1720 strcat(atom, token);
1721 free_token(token);
1722 type = read_token_item(&token);
1723 }
1724
1725 /* todo, test for function */
1726
1727 arg->type = PRINT_ATOM;
1728 arg->atom.atom = atom;
1729 }
1730 break;
1731 case EVENT_DQUOTE:
1732 case EVENT_SQUOTE:
1733 arg->type = PRINT_ATOM;
1734 arg->atom.atom = token;
1735 type = read_token_item(&token);
1736 break;
1737 case EVENT_DELIM:
1738 if (strcmp(token, "(") == 0) {
1739 free_token(token);
1740 type = process_paren(event, arg, &token);
268 break; 1741 break;
269 } 1742 }
270 addr = strtoull(addr_str, NULL, 16); 1743 case EVENT_OP:
271 /* fmt still has a space, skip it */ 1744 /* handle single ops */
272 printk = strdup(fmt+1); 1745 arg->type = PRINT_OP;
273 line = strtok_r(NULL, "\n", &next); 1746 arg->op.op = token;
274 pevent_register_print_string(pevent, printk, addr); 1747 arg->op.left = NULL;
1748 type = process_op(event, arg, &token);
1749
1750 break;
1751
1752 case EVENT_ERROR ... EVENT_NEWLINE:
1753 default:
1754 die("unexpected type %d", type);
275 } 1755 }
1756 *tok = token;
1757
1758 return type;
276} 1759}
277 1760
278int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) 1761static int event_read_print_args(struct event *event, struct print_arg **list)
279{ 1762{
280 return pevent_parse_event(pevent, buf, size, "ftrace"); 1763 enum event_type type = EVENT_ERROR;
1764 struct print_arg *arg;
1765 char *token;
1766 int args = 0;
1767
1768 do {
1769 if (type == EVENT_NEWLINE) {
1770 free_token(token);
1771 type = read_token_item(&token);
1772 continue;
1773 }
1774
1775 arg = malloc_or_die(sizeof(*arg));
1776 memset(arg, 0, sizeof(*arg));
1777
1778 type = process_arg(event, arg, &token);
1779
1780 if (type == EVENT_ERROR) {
1781 free_arg(arg);
1782 return -1;
1783 }
1784
1785 *list = arg;
1786 args++;
1787
1788 if (type == EVENT_OP) {
1789 type = process_op(event, arg, &token);
1790 list = &arg->next;
1791 continue;
1792 }
1793
1794 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1795 free_token(token);
1796 *list = arg;
1797 list = &arg->next;
1798 continue;
1799 }
1800 break;
1801 } while (type != EVENT_NONE);
1802
1803 if (type != EVENT_NONE)
1804 free_token(token);
1805
1806 return args;
281} 1807}
282 1808
283int parse_event_file(struct pevent *pevent, 1809static int event_read_print(struct event *event)
284 char *buf, unsigned long size, char *sys)
285{ 1810{
286 return pevent_parse_event(pevent, buf, size, sys); 1811 enum event_type type;
1812 char *token;
1813 int ret;
1814
1815 if (read_expected_item(EVENT_ITEM, "print") < 0)
1816 return -1;
1817
1818 if (read_expected(EVENT_ITEM, "fmt") < 0)
1819 return -1;
1820
1821 if (read_expected(EVENT_OP, ":") < 0)
1822 return -1;
1823
1824 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1825 goto fail;
1826
1827 concat:
1828 event->print_fmt.format = token;
1829 event->print_fmt.args = NULL;
1830
1831 /* ok to have no arg */
1832 type = read_token_item(&token);
1833
1834 if (type == EVENT_NONE)
1835 return 0;
1836
1837 /* Handle concatination of print lines */
1838 if (type == EVENT_DQUOTE) {
1839 char *cat;
1840
1841 cat = malloc_or_die(strlen(event->print_fmt.format) +
1842 strlen(token) + 1);
1843 strcpy(cat, event->print_fmt.format);
1844 strcat(cat, token);
1845 free_token(token);
1846 free_token(event->print_fmt.format);
1847 event->print_fmt.format = NULL;
1848 token = cat;
1849 goto concat;
1850 }
1851
1852 if (test_type_token(type, token, EVENT_DELIM, ","))
1853 goto fail;
1854
1855 free_token(token);
1856
1857 ret = event_read_print_args(event, &event->print_fmt.args);
1858 if (ret < 0)
1859 return -1;
1860
1861 return ret;
1862
1863 fail:
1864 free_token(token);
1865 return -1;
1866}
1867
1868static struct format_field *
1869find_common_field(struct event *event, const char *name)
1870{
1871 struct format_field *format;
1872
1873 for (format = event->format.common_fields;
1874 format; format = format->next) {
1875 if (strcmp(format->name, name) == 0)
1876 break;
1877 }
1878
1879 return format;
287} 1880}
288 1881
289struct event_format *trace_find_next_event(struct pevent *pevent, 1882static struct format_field *
290 struct event_format *event) 1883find_field(struct event *event, const char *name)
291{ 1884{
292 static int idx; 1885 struct format_field *format;
1886
1887 for (format = event->format.fields;
1888 format; format = format->next) {
1889 if (strcmp(format->name, name) == 0)
1890 break;
1891 }
1892
1893 return format;
1894}
293 1895
294 if (!pevent || !pevent->events) 1896static struct format_field *
1897find_any_field(struct event *event, const char *name)
1898{
1899 struct format_field *format;
1900
1901 format = find_common_field(event, name);
1902 if (format)
1903 return format;
1904 return find_field(event, name);
1905}
1906
1907unsigned long long read_size(void *ptr, int size)
1908{
1909 switch (size) {
1910 case 1:
1911 return *(unsigned char *)ptr;
1912 case 2:
1913 return data2host2(ptr);
1914 case 4:
1915 return data2host4(ptr);
1916 case 8:
1917 return data2host8(ptr);
1918 default:
1919 /* BUG! */
1920 return 0;
1921 }
1922}
1923
1924unsigned long long
1925raw_field_value(struct event *event, const char *name, void *data)
1926{
1927 struct format_field *field;
1928
1929 field = find_any_field(event, name);
1930 if (!field)
1931 return 0ULL;
1932
1933 return read_size(data + field->offset, field->size);
1934}
1935
1936void *raw_field_ptr(struct event *event, const char *name, void *data)
1937{
1938 struct format_field *field;
1939
1940 field = find_any_field(event, name);
1941 if (!field)
295 return NULL; 1942 return NULL;
296 1943
297 if (!event) { 1944 if (field->flags & FIELD_IS_DYNAMIC) {
298 idx = 0; 1945 int offset;
299 return pevent->events[0]; 1946
1947 offset = *(int *)(data + field->offset);
1948 offset &= 0xffff;
1949
1950 return data + offset;
1951 }
1952
1953 return data + field->offset;
1954}
1955
1956static int get_common_info(const char *type, int *offset, int *size)
1957{
1958 struct event *event;
1959 struct format_field *field;
1960
1961 /*
1962 * All events should have the same common elements.
1963 * Pick any event to find where the type is;
1964 */
1965 if (!event_list)
1966 die("no event_list!");
1967
1968 event = event_list;
1969 field = find_common_field(event, type);
1970 if (!field)
1971 die("field '%s' not found", type);
1972
1973 *offset = field->offset;
1974 *size = field->size;
1975
1976 return 0;
1977}
1978
1979static int __parse_common(void *data, int *size, int *offset,
1980 const char *name)
1981{
1982 int ret;
1983
1984 if (!*size) {
1985 ret = get_common_info(name, offset, size);
1986 if (ret < 0)
1987 return ret;
300 } 1988 }
1989 return read_size(data + *offset, *size);
1990}
1991
1992int trace_parse_common_type(void *data)
1993{
1994 static int type_offset;
1995 static int type_size;
1996
1997 return __parse_common(data, &type_size, &type_offset,
1998 "common_type");
1999}
2000
2001int trace_parse_common_pid(void *data)
2002{
2003 static int pid_offset;
2004 static int pid_size;
301 2005
302 if (idx < pevent->nr_events && event == pevent->events[idx]) { 2006 return __parse_common(data, &pid_size, &pid_offset,
303 idx++; 2007 "common_pid");
304 if (idx == pevent->nr_events) 2008}
305 return NULL; 2009
306 return pevent->events[idx]; 2010int parse_common_pc(void *data)
2011{
2012 static int pc_offset;
2013 static int pc_size;
2014
2015 return __parse_common(data, &pc_size, &pc_offset,
2016 "common_preempt_count");
2017}
2018
2019int parse_common_flags(void *data)
2020{
2021 static int flags_offset;
2022 static int flags_size;
2023
2024 return __parse_common(data, &flags_size, &flags_offset,
2025 "common_flags");
2026}
2027
2028int parse_common_lock_depth(void *data)
2029{
2030 static int ld_offset;
2031 static int ld_size;
2032 int ret;
2033
2034 ret = __parse_common(data, &ld_size, &ld_offset,
2035 "common_lock_depth");
2036 if (ret < 0)
2037 return -1;
2038
2039 return ret;
2040}
2041
2042struct event *trace_find_event(int id)
2043{
2044 struct event *event;
2045
2046 for (event = event_list; event; event = event->next) {
2047 if (event->id == id)
2048 break;
307 } 2049 }
2050 return event;
2051}
308 2052
309 for (idx = 1; idx < pevent->nr_events; idx++) { 2053struct event *trace_find_next_event(struct event *event)
310 if (event == pevent->events[idx - 1]) 2054{
311 return pevent->events[idx]; 2055 if (!event)
2056 return event_list;
2057
2058 return event->next;
2059}
2060
2061static unsigned long long eval_num_arg(void *data, int size,
2062 struct event *event, struct print_arg *arg)
2063{
2064 unsigned long long val = 0;
2065 unsigned long long left, right;
2066 struct print_arg *larg;
2067
2068 switch (arg->type) {
2069 case PRINT_NULL:
2070 /* ?? */
2071 return 0;
2072 case PRINT_ATOM:
2073 return strtoull(arg->atom.atom, NULL, 0);
2074 case PRINT_FIELD:
2075 if (!arg->field.field) {
2076 arg->field.field = find_any_field(event, arg->field.name);
2077 if (!arg->field.field)
2078 die("field %s not found", arg->field.name);
2079 }
2080 /* must be a number */
2081 val = read_size(data + arg->field.field->offset,
2082 arg->field.field->size);
2083 break;
2084 case PRINT_FLAGS:
2085 case PRINT_SYMBOL:
2086 break;
2087 case PRINT_TYPE:
2088 return eval_num_arg(data, size, event, arg->typecast.item);
2089 case PRINT_STRING:
2090 return 0;
2091 break;
2092 case PRINT_OP:
2093 if (strcmp(arg->op.op, "[") == 0) {
2094 /*
2095 * Arrays are special, since we don't want
2096 * to read the arg as is.
2097 */
2098 if (arg->op.left->type != PRINT_FIELD)
2099 goto default_op; /* oops, all bets off */
2100 larg = arg->op.left;
2101 if (!larg->field.field) {
2102 larg->field.field =
2103 find_any_field(event, larg->field.name);
2104 if (!larg->field.field)
2105 die("field %s not found", larg->field.name);
2106 }
2107 right = eval_num_arg(data, size, event, arg->op.right);
2108 val = read_size(data + larg->field.field->offset +
2109 right * long_size, long_size);
2110 break;
2111 }
2112 default_op:
2113 left = eval_num_arg(data, size, event, arg->op.left);
2114 right = eval_num_arg(data, size, event, arg->op.right);
2115 switch (arg->op.op[0]) {
2116 case '|':
2117 if (arg->op.op[1])
2118 val = left || right;
2119 else
2120 val = left | right;
2121 break;
2122 case '&':
2123 if (arg->op.op[1])
2124 val = left && right;
2125 else
2126 val = left & right;
2127 break;
2128 case '<':
2129 switch (arg->op.op[1]) {
2130 case 0:
2131 val = left < right;
2132 break;
2133 case '<':
2134 val = left << right;
2135 break;
2136 case '=':
2137 val = left <= right;
2138 break;
2139 default:
2140 die("unknown op '%s'", arg->op.op);
2141 }
2142 break;
2143 case '>':
2144 switch (arg->op.op[1]) {
2145 case 0:
2146 val = left > right;
2147 break;
2148 case '>':
2149 val = left >> right;
2150 break;
2151 case '=':
2152 val = left >= right;
2153 break;
2154 default:
2155 die("unknown op '%s'", arg->op.op);
2156 }
2157 break;
2158 case '=':
2159 if (arg->op.op[1] != '=')
2160 die("unknown op '%s'", arg->op.op);
2161 val = left == right;
2162 break;
2163 case '-':
2164 val = left - right;
2165 break;
2166 case '+':
2167 val = left + right;
2168 break;
2169 default:
2170 die("unknown op '%s'", arg->op.op);
2171 }
2172 break;
2173 default: /* not sure what to do there */
2174 return 0;
312 } 2175 }
313 return NULL; 2176 return val;
314} 2177}
315 2178
316struct flag { 2179struct flag {
@@ -352,3 +2215,933 @@ unsigned long long eval_flag(const char *flag)
352 2215
353 return 0; 2216 return 0;
354} 2217}
2218
2219static void print_str_arg(void *data, int size,
2220 struct event *event, struct print_arg *arg)
2221{
2222 struct print_flag_sym *flag;
2223 unsigned long long val, fval;
2224 char *str;
2225 int print;
2226
2227 switch (arg->type) {
2228 case PRINT_NULL:
2229 /* ?? */
2230 return;
2231 case PRINT_ATOM:
2232 printf("%s", arg->atom.atom);
2233 return;
2234 case PRINT_FIELD:
2235 if (!arg->field.field) {
2236 arg->field.field = find_any_field(event, arg->field.name);
2237 if (!arg->field.field)
2238 die("field %s not found", arg->field.name);
2239 }
2240 str = malloc_or_die(arg->field.field->size + 1);
2241 memcpy(str, data + arg->field.field->offset,
2242 arg->field.field->size);
2243 str[arg->field.field->size] = 0;
2244 printf("%s", str);
2245 free(str);
2246 break;
2247 case PRINT_FLAGS:
2248 val = eval_num_arg(data, size, event, arg->flags.field);
2249 print = 0;
2250 for (flag = arg->flags.flags; flag; flag = flag->next) {
2251 fval = eval_flag(flag->value);
2252 if (!val && !fval) {
2253 printf("%s", flag->str);
2254 break;
2255 }
2256 if (fval && (val & fval) == fval) {
2257 if (print && arg->flags.delim)
2258 printf("%s", arg->flags.delim);
2259 printf("%s", flag->str);
2260 print = 1;
2261 val &= ~fval;
2262 }
2263 }
2264 break;
2265 case PRINT_SYMBOL:
2266 val = eval_num_arg(data, size, event, arg->symbol.field);
2267 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2268 fval = eval_flag(flag->value);
2269 if (val == fval) {
2270 printf("%s", flag->str);
2271 break;
2272 }
2273 }
2274 break;
2275
2276 case PRINT_TYPE:
2277 break;
2278 case PRINT_STRING: {
2279 int str_offset;
2280
2281 if (arg->string.offset == -1) {
2282 struct format_field *f;
2283
2284 f = find_any_field(event, arg->string.string);
2285 arg->string.offset = f->offset;
2286 }
2287 str_offset = *(int *)(data + arg->string.offset);
2288 str_offset &= 0xffff;
2289 printf("%s", ((char *)data) + str_offset);
2290 break;
2291 }
2292 case PRINT_OP:
2293 /*
2294 * The only op for string should be ? :
2295 */
2296 if (arg->op.op[0] != '?')
2297 return;
2298 val = eval_num_arg(data, size, event, arg->op.left);
2299 if (val)
2300 print_str_arg(data, size, event, arg->op.right->op.left);
2301 else
2302 print_str_arg(data, size, event, arg->op.right->op.right);
2303 break;
2304 default:
2305 /* well... */
2306 break;
2307 }
2308}
2309
2310static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2311{
2312 static struct format_field *field, *ip_field;
2313 struct print_arg *args, *arg, **next;
2314 unsigned long long ip, val;
2315 char *ptr;
2316 void *bptr;
2317
2318 if (!field) {
2319 field = find_field(event, "buf");
2320 if (!field)
2321 die("can't find buffer field for binary printk");
2322 ip_field = find_field(event, "ip");
2323 if (!ip_field)
2324 die("can't find ip field for binary printk");
2325 }
2326
2327 ip = read_size(data + ip_field->offset, ip_field->size);
2328
2329 /*
2330 * The first arg is the IP pointer.
2331 */
2332 args = malloc_or_die(sizeof(*args));
2333 arg = args;
2334 arg->next = NULL;
2335 next = &arg->next;
2336
2337 arg->type = PRINT_ATOM;
2338 arg->atom.atom = malloc_or_die(32);
2339 sprintf(arg->atom.atom, "%lld", ip);
2340
2341 /* skip the first "%pf : " */
2342 for (ptr = fmt + 6, bptr = data + field->offset;
2343 bptr < data + size && *ptr; ptr++) {
2344 int ls = 0;
2345
2346 if (*ptr == '%') {
2347 process_again:
2348 ptr++;
2349 switch (*ptr) {
2350 case '%':
2351 break;
2352 case 'l':
2353 ls++;
2354 goto process_again;
2355 case 'L':
2356 ls = 2;
2357 goto process_again;
2358 case '0' ... '9':
2359 goto process_again;
2360 case 'p':
2361 ls = 1;
2362 /* fall through */
2363 case 'd':
2364 case 'u':
2365 case 'x':
2366 case 'i':
2367 /* the pointers are always 4 bytes aligned */
2368 bptr = (void *)(((unsigned long)bptr + 3) &
2369 ~3);
2370 switch (ls) {
2371 case 0:
2372 case 1:
2373 ls = long_size;
2374 break;
2375 case 2:
2376 ls = 8;
2377 default:
2378 break;
2379 }
2380 val = read_size(bptr, ls);
2381 bptr += ls;
2382 arg = malloc_or_die(sizeof(*arg));
2383 arg->next = NULL;
2384 arg->type = PRINT_ATOM;
2385 arg->atom.atom = malloc_or_die(32);
2386 sprintf(arg->atom.atom, "%lld", val);
2387 *next = arg;
2388 next = &arg->next;
2389 break;
2390 case 's':
2391 arg = malloc_or_die(sizeof(*arg));
2392 arg->next = NULL;
2393 arg->type = PRINT_STRING;
2394 arg->string.string = strdup(bptr);
2395 bptr += strlen(bptr) + 1;
2396 *next = arg;
2397 next = &arg->next;
2398 default:
2399 break;
2400 }
2401 }
2402 }
2403
2404 return args;
2405}
2406
2407static void free_args(struct print_arg *args)
2408{
2409 struct print_arg *next;
2410
2411 while (args) {
2412 next = args->next;
2413
2414 if (args->type == PRINT_ATOM)
2415 free(args->atom.atom);
2416 else
2417 free(args->string.string);
2418 free(args);
2419 args = next;
2420 }
2421}
2422
2423static char *get_bprint_format(void *data, int size __unused, struct event *event)
2424{
2425 unsigned long long addr;
2426 static struct format_field *field;
2427 struct printk_map *printk;
2428 char *format;
2429 char *p;
2430
2431 if (!field) {
2432 field = find_field(event, "fmt");
2433 if (!field)
2434 die("can't find format field for binary printk");
2435 printf("field->offset = %d size=%d\n", field->offset, field->size);
2436 }
2437
2438 addr = read_size(data + field->offset, field->size);
2439
2440 printk = find_printk(addr);
2441 if (!printk) {
2442 format = malloc_or_die(45);
2443 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2444 addr);
2445 return format;
2446 }
2447
2448 p = printk->printk;
2449 /* Remove any quotes. */
2450 if (*p == '"')
2451 p++;
2452 format = malloc_or_die(strlen(p) + 10);
2453 sprintf(format, "%s : %s", "%pf", p);
2454 /* remove ending quotes and new line since we will add one too */
2455 p = format + strlen(format) - 1;
2456 if (*p == '"')
2457 *p = 0;
2458
2459 p -= 2;
2460 if (strcmp(p, "\\n") == 0)
2461 *p = 0;
2462
2463 return format;
2464}
2465
2466static void pretty_print(void *data, int size, struct event *event)
2467{
2468 struct print_fmt *print_fmt = &event->print_fmt;
2469 struct print_arg *arg = print_fmt->args;
2470 struct print_arg *args = NULL;
2471 const char *ptr = print_fmt->format;
2472 unsigned long long val;
2473 struct func_map *func;
2474 const char *saveptr;
2475 char *bprint_fmt = NULL;
2476 char format[32];
2477 int show_func;
2478 int len;
2479 int ls;
2480
2481 if (event->flags & EVENT_FL_ISFUNC)
2482 ptr = " %pF <-- %pF";
2483
2484 if (event->flags & EVENT_FL_ISBPRINT) {
2485 bprint_fmt = get_bprint_format(data, size, event);
2486 args = make_bprint_args(bprint_fmt, data, size, event);
2487 arg = args;
2488 ptr = bprint_fmt;
2489 }
2490
2491 for (; *ptr; ptr++) {
2492 ls = 0;
2493 if (*ptr == '\\') {
2494 ptr++;
2495 switch (*ptr) {
2496 case 'n':
2497 printf("\n");
2498 break;
2499 case 't':
2500 printf("\t");
2501 break;
2502 case 'r':
2503 printf("\r");
2504 break;
2505 case '\\':
2506 printf("\\");
2507 break;
2508 default:
2509 printf("%c", *ptr);
2510 break;
2511 }
2512
2513 } else if (*ptr == '%') {
2514 saveptr = ptr;
2515 show_func = 0;
2516 cont_process:
2517 ptr++;
2518 switch (*ptr) {
2519 case '%':
2520 printf("%%");
2521 break;
2522 case 'l':
2523 ls++;
2524 goto cont_process;
2525 case 'L':
2526 ls = 2;
2527 goto cont_process;
2528 case 'z':
2529 case 'Z':
2530 case '0' ... '9':
2531 goto cont_process;
2532 case 'p':
2533 if (long_size == 4)
2534 ls = 1;
2535 else
2536 ls = 2;
2537
2538 if (*(ptr+1) == 'F' ||
2539 *(ptr+1) == 'f') {
2540 ptr++;
2541 show_func = *ptr;
2542 }
2543
2544 /* fall through */
2545 case 'd':
2546 case 'i':
2547 case 'x':
2548 case 'X':
2549 case 'u':
2550 if (!arg)
2551 die("no argument match");
2552
2553 len = ((unsigned long)ptr + 1) -
2554 (unsigned long)saveptr;
2555
2556 /* should never happen */
2557 if (len > 32)
2558 die("bad format!");
2559
2560 memcpy(format, saveptr, len);
2561 format[len] = 0;
2562
2563 val = eval_num_arg(data, size, event, arg);
2564 arg = arg->next;
2565
2566 if (show_func) {
2567 func = find_func(val);
2568 if (func) {
2569 printf("%s", func->func);
2570 if (show_func == 'F')
2571 printf("+0x%llx",
2572 val - func->addr);
2573 break;
2574 }
2575 }
2576 switch (ls) {
2577 case 0:
2578 printf(format, (int)val);
2579 break;
2580 case 1:
2581 printf(format, (long)val);
2582 break;
2583 case 2:
2584 printf(format, (long long)val);
2585 break;
2586 default:
2587 die("bad count (%d)", ls);
2588 }
2589 break;
2590 case 's':
2591 if (!arg)
2592 die("no matching argument");
2593
2594 print_str_arg(data, size, event, arg);
2595 arg = arg->next;
2596 break;
2597 default:
2598 printf(">%c<", *ptr);
2599
2600 }
2601 } else
2602 printf("%c", *ptr);
2603 }
2604
2605 if (args) {
2606 free_args(args);
2607 free(bprint_fmt);
2608 }
2609}
2610
2611static inline int log10_cpu(int nb)
2612{
2613 if (nb / 100)
2614 return 3;
2615 if (nb / 10)
2616 return 2;
2617 return 1;
2618}
2619
2620static void print_lat_fmt(void *data, int size __unused)
2621{
2622 unsigned int lat_flags;
2623 unsigned int pc;
2624 int lock_depth;
2625 int hardirq;
2626 int softirq;
2627
2628 lat_flags = parse_common_flags(data);
2629 pc = parse_common_pc(data);
2630 lock_depth = parse_common_lock_depth(data);
2631
2632 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2633 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2634
2635 printf("%c%c%c",
2636 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2637 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2638 'X' : '.',
2639 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2640 'N' : '.',
2641 (hardirq && softirq) ? 'H' :
2642 hardirq ? 'h' : softirq ? 's' : '.');
2643
2644 if (pc)
2645 printf("%x", pc);
2646 else
2647 printf(".");
2648
2649 if (lock_depth < 0)
2650 printf(". ");
2651 else
2652 printf("%d ", lock_depth);
2653}
2654
2655#define TRACE_GRAPH_INDENT 2
2656
2657static struct record *
2658get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2659 struct record *next)
2660{
2661 struct format_field *field;
2662 struct event *event;
2663 unsigned long val;
2664 int type;
2665 int pid;
2666
2667 type = trace_parse_common_type(next->data);
2668 event = trace_find_event(type);
2669 if (!event)
2670 return NULL;
2671
2672 if (!(event->flags & EVENT_FL_ISFUNCRET))
2673 return NULL;
2674
2675 pid = trace_parse_common_pid(next->data);
2676 field = find_field(event, "func");
2677 if (!field)
2678 die("function return does not have field func");
2679
2680 val = read_size(next->data + field->offset, field->size);
2681
2682 if (cur_pid != pid || cur_func != val)
2683 return NULL;
2684
2685 /* this is a leaf, now advance the iterator */
2686 return trace_read_data(cpu);
2687}
2688
2689/* Signal a overhead of time execution to the output */
2690static void print_graph_overhead(unsigned long long duration)
2691{
2692 /* Non nested entry or return */
2693 if (duration == ~0ULL)
2694 return (void)printf(" ");
2695
2696 /* Duration exceeded 100 msecs */
2697 if (duration > 100000ULL)
2698 return (void)printf("! ");
2699
2700 /* Duration exceeded 10 msecs */
2701 if (duration > 10000ULL)
2702 return (void)printf("+ ");
2703
2704 printf(" ");
2705}
2706
2707static void print_graph_duration(unsigned long long duration)
2708{
2709 unsigned long usecs = duration / 1000;
2710 unsigned long nsecs_rem = duration % 1000;
2711 /* log10(ULONG_MAX) + '\0' */
2712 char msecs_str[21];
2713 char nsecs_str[5];
2714 int len;
2715 int i;
2716
2717 sprintf(msecs_str, "%lu", usecs);
2718
2719 /* Print msecs */
2720 len = printf("%lu", usecs);
2721
2722 /* Print nsecs (we don't want to exceed 7 numbers) */
2723 if (len < 7) {
2724 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2725 len += printf(".%s", nsecs_str);
2726 }
2727
2728 printf(" us ");
2729
2730 /* Print remaining spaces to fit the row's width */
2731 for (i = len; i < 7; i++)
2732 printf(" ");
2733
2734 printf("| ");
2735}
2736
2737static void
2738print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2739{
2740 unsigned long long rettime, calltime;
2741 unsigned long long duration, depth;
2742 unsigned long long val;
2743 struct format_field *field;
2744 struct func_map *func;
2745 struct event *ret_event;
2746 int type;
2747 int i;
2748
2749 type = trace_parse_common_type(ret_rec->data);
2750 ret_event = trace_find_event(type);
2751
2752 field = find_field(ret_event, "rettime");
2753 if (!field)
2754 die("can't find rettime in return graph");
2755 rettime = read_size(ret_rec->data + field->offset, field->size);
2756
2757 field = find_field(ret_event, "calltime");
2758 if (!field)
2759 die("can't find rettime in return graph");
2760 calltime = read_size(ret_rec->data + field->offset, field->size);
2761
2762 duration = rettime - calltime;
2763
2764 /* Overhead */
2765 print_graph_overhead(duration);
2766
2767 /* Duration */
2768 print_graph_duration(duration);
2769
2770 field = find_field(event, "depth");
2771 if (!field)
2772 die("can't find depth in entry graph");
2773 depth = read_size(data + field->offset, field->size);
2774
2775 /* Function */
2776 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2777 printf(" ");
2778
2779 field = find_field(event, "func");
2780 if (!field)
2781 die("can't find func in entry graph");
2782 val = read_size(data + field->offset, field->size);
2783 func = find_func(val);
2784
2785 if (func)
2786 printf("%s();", func->func);
2787 else
2788 printf("%llx();", val);
2789}
2790
2791static void print_graph_nested(struct event *event, void *data)
2792{
2793 struct format_field *field;
2794 unsigned long long depth;
2795 unsigned long long val;
2796 struct func_map *func;
2797 int i;
2798
2799 /* No overhead */
2800 print_graph_overhead(-1);
2801
2802 /* No time */
2803 printf(" | ");
2804
2805 field = find_field(event, "depth");
2806 if (!field)
2807 die("can't find depth in entry graph");
2808 depth = read_size(data + field->offset, field->size);
2809
2810 /* Function */
2811 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2812 printf(" ");
2813
2814 field = find_field(event, "func");
2815 if (!field)
2816 die("can't find func in entry graph");
2817 val = read_size(data + field->offset, field->size);
2818 func = find_func(val);
2819
2820 if (func)
2821 printf("%s() {", func->func);
2822 else
2823 printf("%llx() {", val);
2824}
2825
2826static void
2827pretty_print_func_ent(void *data, int size, struct event *event,
2828 int cpu, int pid)
2829{
2830 struct format_field *field;
2831 struct record *rec;
2832 void *copy_data;
2833 unsigned long val;
2834
2835 if (latency_format) {
2836 print_lat_fmt(data, size);
2837 printf(" | ");
2838 }
2839
2840 field = find_field(event, "func");
2841 if (!field)
2842 die("function entry does not have func field");
2843
2844 val = read_size(data + field->offset, field->size);
2845
2846 /*
2847 * peek_data may unmap the data pointer. Copy it first.
2848 */
2849 copy_data = malloc_or_die(size);
2850 memcpy(copy_data, data, size);
2851 data = copy_data;
2852
2853 rec = trace_peek_data(cpu);
2854 if (rec) {
2855 rec = get_return_for_leaf(cpu, pid, val, rec);
2856 if (rec) {
2857 print_graph_entry_leaf(event, data, rec);
2858 goto out_free;
2859 }
2860 }
2861 print_graph_nested(event, data);
2862out_free:
2863 free(data);
2864}
2865
2866static void
2867pretty_print_func_ret(void *data, int size __unused, struct event *event)
2868{
2869 unsigned long long rettime, calltime;
2870 unsigned long long duration, depth;
2871 struct format_field *field;
2872 int i;
2873
2874 if (latency_format) {
2875 print_lat_fmt(data, size);
2876 printf(" | ");
2877 }
2878
2879 field = find_field(event, "rettime");
2880 if (!field)
2881 die("can't find rettime in return graph");
2882 rettime = read_size(data + field->offset, field->size);
2883
2884 field = find_field(event, "calltime");
2885 if (!field)
2886 die("can't find calltime in return graph");
2887 calltime = read_size(data + field->offset, field->size);
2888
2889 duration = rettime - calltime;
2890
2891 /* Overhead */
2892 print_graph_overhead(duration);
2893
2894 /* Duration */
2895 print_graph_duration(duration);
2896
2897 field = find_field(event, "depth");
2898 if (!field)
2899 die("can't find depth in entry graph");
2900 depth = read_size(data + field->offset, field->size);
2901
2902 /* Function */
2903 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2904 printf(" ");
2905
2906 printf("}");
2907}
2908
2909static void
2910pretty_print_func_graph(void *data, int size, struct event *event,
2911 int cpu, int pid)
2912{
2913 if (event->flags & EVENT_FL_ISFUNCENT)
2914 pretty_print_func_ent(data, size, event, cpu, pid);
2915 else if (event->flags & EVENT_FL_ISFUNCRET)
2916 pretty_print_func_ret(data, size, event);
2917 printf("\n");
2918}
2919
2920void print_trace_event(int cpu, void *data, int size)
2921{
2922 struct event *event;
2923 int type;
2924 int pid;
2925
2926 type = trace_parse_common_type(data);
2927
2928 event = trace_find_event(type);
2929 if (!event) {
2930 warning("ug! no event found for type %d", type);
2931 return;
2932 }
2933
2934 pid = trace_parse_common_pid(data);
2935
2936 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2937 return pretty_print_func_graph(data, size, event, cpu, pid);
2938
2939 if (latency_format)
2940 print_lat_fmt(data, size);
2941
2942 if (event->flags & EVENT_FL_FAILED) {
2943 printf("EVENT '%s' FAILED TO PARSE\n",
2944 event->name);
2945 return;
2946 }
2947
2948 pretty_print(data, size, event);
2949}
2950
2951static void print_fields(struct print_flag_sym *field)
2952{
2953 printf("{ %s, %s }", field->value, field->str);
2954 if (field->next) {
2955 printf(", ");
2956 print_fields(field->next);
2957 }
2958}
2959
2960static void print_args(struct print_arg *args)
2961{
2962 int print_paren = 1;
2963
2964 switch (args->type) {
2965 case PRINT_NULL:
2966 printf("null");
2967 break;
2968 case PRINT_ATOM:
2969 printf("%s", args->atom.atom);
2970 break;
2971 case PRINT_FIELD:
2972 printf("REC->%s", args->field.name);
2973 break;
2974 case PRINT_FLAGS:
2975 printf("__print_flags(");
2976 print_args(args->flags.field);
2977 printf(", %s, ", args->flags.delim);
2978 print_fields(args->flags.flags);
2979 printf(")");
2980 break;
2981 case PRINT_SYMBOL:
2982 printf("__print_symbolic(");
2983 print_args(args->symbol.field);
2984 printf(", ");
2985 print_fields(args->symbol.symbols);
2986 printf(")");
2987 break;
2988 case PRINT_STRING:
2989 printf("__get_str(%s)", args->string.string);
2990 break;
2991 case PRINT_TYPE:
2992 printf("(%s)", args->typecast.type);
2993 print_args(args->typecast.item);
2994 break;
2995 case PRINT_OP:
2996 if (strcmp(args->op.op, ":") == 0)
2997 print_paren = 0;
2998 if (print_paren)
2999 printf("(");
3000 print_args(args->op.left);
3001 printf(" %s ", args->op.op);
3002 print_args(args->op.right);
3003 if (print_paren)
3004 printf(")");
3005 break;
3006 default:
3007 /* we should warn... */
3008 return;
3009 }
3010 if (args->next) {
3011 printf("\n");
3012 print_args(args->next);
3013 }
3014}
3015
3016int parse_ftrace_file(char *buf, unsigned long size)
3017{
3018 struct format_field *field;
3019 struct print_arg *arg, **list;
3020 struct event *event;
3021 int ret;
3022
3023 init_input_buf(buf, size);
3024
3025 event = alloc_event();
3026 if (!event)
3027 return -ENOMEM;
3028
3029 event->flags |= EVENT_FL_ISFTRACE;
3030
3031 event->name = event_read_name();
3032 if (!event->name)
3033 die("failed to read ftrace event name");
3034
3035 if (strcmp(event->name, "function") == 0)
3036 event->flags |= EVENT_FL_ISFUNC;
3037
3038 else if (strcmp(event->name, "funcgraph_entry") == 0)
3039 event->flags |= EVENT_FL_ISFUNCENT;
3040
3041 else if (strcmp(event->name, "funcgraph_exit") == 0)
3042 event->flags |= EVENT_FL_ISFUNCRET;
3043
3044 else if (strcmp(event->name, "bprint") == 0)
3045 event->flags |= EVENT_FL_ISBPRINT;
3046
3047 event->id = event_read_id();
3048 if (event->id < 0)
3049 die("failed to read ftrace event id");
3050
3051 add_event(event);
3052
3053 ret = event_read_format(event);
3054 if (ret < 0)
3055 die("failed to read ftrace event format");
3056
3057 ret = event_read_print(event);
3058 if (ret < 0)
3059 die("failed to read ftrace event print fmt");
3060
3061 /* New ftrace handles args */
3062 if (ret > 0)
3063 return 0;
3064 /*
3065 * The arguments for ftrace files are parsed by the fields.
3066 * Set up the fields as their arguments.
3067 */
3068 list = &event->print_fmt.args;
3069 for (field = event->format.fields; field; field = field->next) {
3070 arg = malloc_or_die(sizeof(*arg));
3071 memset(arg, 0, sizeof(*arg));
3072 *list = arg;
3073 list = &arg->next;
3074 arg->type = PRINT_FIELD;
3075 arg->field.name = field->name;
3076 arg->field.field = field;
3077 }
3078 return 0;
3079}
3080
3081int parse_event_file(char *buf, unsigned long size, char *sys)
3082{
3083 struct event *event;
3084 int ret;
3085
3086 init_input_buf(buf, size);
3087
3088 event = alloc_event();
3089 if (!event)
3090 return -ENOMEM;
3091
3092 event->name = event_read_name();
3093 if (!event->name)
3094 die("failed to read event name");
3095
3096 event->id = event_read_id();
3097 if (event->id < 0)
3098 die("failed to read event id");
3099
3100 ret = event_read_format(event);
3101 if (ret < 0) {
3102 warning("failed to read event format for %s", event->name);
3103 goto event_failed;
3104 }
3105
3106 ret = event_read_print(event);
3107 if (ret < 0) {
3108 warning("failed to read event print fmt for %s", event->name);
3109 goto event_failed;
3110 }
3111
3112 event->system = strdup(sys);
3113
3114#define PRINT_ARGS 0
3115 if (PRINT_ARGS && event->print_fmt.args)
3116 print_args(event->print_fmt.args);
3117
3118 add_event(event);
3119 return 0;
3120
3121 event_failed:
3122 event->flags |= EVENT_FL_FAILED;
3123 /* still add it even if it failed */
3124 add_event(event);
3125 return -1;
3126}
3127
3128void parse_set_info(int nr_cpus, int long_sz)
3129{
3130 cpus = nr_cpus;
3131 long_size = long_sz;
3132}
3133
3134int common_pc(struct scripting_context *context)
3135{
3136 return parse_common_pc(context->event_data);
3137}
3138
3139int common_flags(struct scripting_context *context)
3140{
3141 return parse_common_flags(context->event_data);
3142}
3143
3144int common_lock_depth(struct scripting_context *context)
3145{
3146 return parse_common_lock_depth(context->event_data);
3147}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 3741572696a..f55cc3a765a 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -33,6 +33,7 @@
33#include <pthread.h> 33#include <pthread.h>
34#include <fcntl.h> 34#include <fcntl.h>
35#include <unistd.h> 35#include <unistd.h>
36#include <ctype.h>
36#include <errno.h> 37#include <errno.h>
37 38
38#include "../perf.h" 39#include "../perf.h"
@@ -47,19 +48,11 @@ int file_bigendian;
47int host_bigendian; 48int host_bigendian;
48static int long_size; 49static int long_size;
49 50
51static unsigned long page_size;
52
50static ssize_t calc_data_size; 53static ssize_t calc_data_size;
51static bool repipe; 54static bool repipe;
52 55
53static void *malloc_or_die(int size)
54{
55 void *ret;
56
57 ret = malloc(size);
58 if (!ret)
59 die("malloc");
60 return ret;
61}
62
63static int do_read(int fd, void *buf, int size) 56static int do_read(int fd, void *buf, int size)
64{ 57{
65 int rsize = size; 58 int rsize = size;
@@ -112,20 +105,20 @@ static void skip(int size)
112 }; 105 };
113} 106}
114 107
115static unsigned int read4(struct pevent *pevent) 108static unsigned int read4(void)
116{ 109{
117 unsigned int data; 110 unsigned int data;
118 111
119 read_or_die(&data, 4); 112 read_or_die(&data, 4);
120 return __data2host4(pevent, data); 113 return __data2host4(data);
121} 114}
122 115
123static unsigned long long read8(struct pevent *pevent) 116static unsigned long long read8(void)
124{ 117{
125 unsigned long long data; 118 unsigned long long data;
126 119
127 read_or_die(&data, 8); 120 read_or_die(&data, 8);
128 return __data2host8(pevent, data); 121 return __data2host8(data);
129} 122}
130 123
131static char *read_string(void) 124static char *read_string(void)
@@ -166,12 +159,12 @@ static char *read_string(void)
166 return str; 159 return str;
167} 160}
168 161
169static void read_proc_kallsyms(struct pevent *pevent) 162static void read_proc_kallsyms(void)
170{ 163{
171 unsigned int size; 164 unsigned int size;
172 char *buf; 165 char *buf;
173 166
174 size = read4(pevent); 167 size = read4();
175 if (!size) 168 if (!size)
176 return; 169 return;
177 170
@@ -179,29 +172,29 @@ static void read_proc_kallsyms(struct pevent *pevent)
179 read_or_die(buf, size); 172 read_or_die(buf, size);
180 buf[size] = '\0'; 173 buf[size] = '\0';
181 174
182 parse_proc_kallsyms(pevent, buf, size); 175 parse_proc_kallsyms(buf, size);
183 176
184 free(buf); 177 free(buf);
185} 178}
186 179
187static void read_ftrace_printk(struct pevent *pevent) 180static void read_ftrace_printk(void)
188{ 181{
189 unsigned int size; 182 unsigned int size;
190 char *buf; 183 char *buf;
191 184
192 size = read4(pevent); 185 size = read4();
193 if (!size) 186 if (!size)
194 return; 187 return;
195 188
196 buf = malloc_or_die(size); 189 buf = malloc_or_die(size);
197 read_or_die(buf, size); 190 read_or_die(buf, size);
198 191
199 parse_ftrace_printk(pevent, buf, size); 192 parse_ftrace_printk(buf, size);
200 193
201 free(buf); 194 free(buf);
202} 195}
203 196
204static void read_header_files(struct pevent *pevent) 197static void read_header_files(void)
205{ 198{
206 unsigned long long size; 199 unsigned long long size;
207 char *header_event; 200 char *header_event;
@@ -212,7 +205,7 @@ static void read_header_files(struct pevent *pevent)
212 if (memcmp(buf, "header_page", 12) != 0) 205 if (memcmp(buf, "header_page", 12) != 0)
213 die("did not read header page"); 206 die("did not read header page");
214 207
215 size = read8(pevent); 208 size = read8();
216 skip(size); 209 skip(size);
217 210
218 /* 211 /*
@@ -225,48 +218,47 @@ static void read_header_files(struct pevent *pevent)
225 if (memcmp(buf, "header_event", 13) != 0) 218 if (memcmp(buf, "header_event", 13) != 0)
226 die("did not read header event"); 219 die("did not read header event");
227 220
228 size = read8(pevent); 221 size = read8();
229 header_event = malloc_or_die(size); 222 header_event = malloc_or_die(size);
230 read_or_die(header_event, size); 223 read_or_die(header_event, size);
231 free(header_event); 224 free(header_event);
232} 225}
233 226
234static void read_ftrace_file(struct pevent *pevent, unsigned long long size) 227static void read_ftrace_file(unsigned long long size)
235{ 228{
236 char *buf; 229 char *buf;
237 230
238 buf = malloc_or_die(size); 231 buf = malloc_or_die(size);
239 read_or_die(buf, size); 232 read_or_die(buf, size);
240 parse_ftrace_file(pevent, buf, size); 233 parse_ftrace_file(buf, size);
241 free(buf); 234 free(buf);
242} 235}
243 236
244static void read_event_file(struct pevent *pevent, char *sys, 237static void read_event_file(char *sys, unsigned long long size)
245 unsigned long long size)
246{ 238{
247 char *buf; 239 char *buf;
248 240
249 buf = malloc_or_die(size); 241 buf = malloc_or_die(size);
250 read_or_die(buf, size); 242 read_or_die(buf, size);
251 parse_event_file(pevent, buf, size, sys); 243 parse_event_file(buf, size, sys);
252 free(buf); 244 free(buf);
253} 245}
254 246
255static void read_ftrace_files(struct pevent *pevent) 247static void read_ftrace_files(void)
256{ 248{
257 unsigned long long size; 249 unsigned long long size;
258 int count; 250 int count;
259 int i; 251 int i;
260 252
261 count = read4(pevent); 253 count = read4();
262 254
263 for (i = 0; i < count; i++) { 255 for (i = 0; i < count; i++) {
264 size = read8(pevent); 256 size = read8();
265 read_ftrace_file(pevent, size); 257 read_ftrace_file(size);
266 } 258 }
267} 259}
268 260
269static void read_event_files(struct pevent *pevent) 261static void read_event_files(void)
270{ 262{
271 unsigned long long size; 263 unsigned long long size;
272 char *sys; 264 char *sys;
@@ -274,15 +266,15 @@ static void read_event_files(struct pevent *pevent)
274 int count; 266 int count;
275 int i,x; 267 int i,x;
276 268
277 systems = read4(pevent); 269 systems = read4();
278 270
279 for (i = 0; i < systems; i++) { 271 for (i = 0; i < systems; i++) {
280 sys = read_string(); 272 sys = read_string();
281 273
282 count = read4(pevent); 274 count = read4();
283 for (x=0; x < count; x++) { 275 for (x=0; x < count; x++) {
284 size = read8(pevent); 276 size = read8();
285 read_event_file(pevent, sys, size); 277 read_event_file(sys, size);
286 } 278 }
287 } 279 }
288} 280}
@@ -291,7 +283,7 @@ struct cpu_data {
291 unsigned long long offset; 283 unsigned long long offset;
292 unsigned long long size; 284 unsigned long long size;
293 unsigned long long timestamp; 285 unsigned long long timestamp;
294 struct pevent_record *next; 286 struct record *next;
295 char *page; 287 char *page;
296 int cpu; 288 int cpu;
297 int index; 289 int index;
@@ -376,9 +368,9 @@ static int calc_index(void *ptr, int cpu)
376 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 368 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
377} 369}
378 370
379struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu) 371struct record *trace_peek_data(int cpu)
380{ 372{
381 struct pevent_record *data; 373 struct record *data;
382 void *page = cpu_data[cpu].page; 374 void *page = cpu_data[cpu].page;
383 int idx = cpu_data[cpu].index; 375 int idx = cpu_data[cpu].index;
384 void *ptr = page + idx; 376 void *ptr = page + idx;
@@ -398,15 +390,15 @@ struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu)
398 /* FIXME: handle header page */ 390 /* FIXME: handle header page */
399 if (header_page_ts_size != 8) 391 if (header_page_ts_size != 8)
400 die("expected a long long type for timestamp"); 392 die("expected a long long type for timestamp");
401 cpu_data[cpu].timestamp = data2host8(pevent, ptr); 393 cpu_data[cpu].timestamp = data2host8(ptr);
402 ptr += 8; 394 ptr += 8;
403 switch (header_page_size_size) { 395 switch (header_page_size_size) {
404 case 4: 396 case 4:
405 cpu_data[cpu].page_size = data2host4(pevent, ptr); 397 cpu_data[cpu].page_size = data2host4(ptr);
406 ptr += 4; 398 ptr += 4;
407 break; 399 break;
408 case 8: 400 case 8:
409 cpu_data[cpu].page_size = data2host8(pevent, ptr); 401 cpu_data[cpu].page_size = data2host8(ptr);
410 ptr += 8; 402 ptr += 8;
411 break; 403 break;
412 default: 404 default:
@@ -420,10 +412,10 @@ read_again:
420 412
421 if (idx >= cpu_data[cpu].page_size) { 413 if (idx >= cpu_data[cpu].page_size) {
422 get_next_page(cpu); 414 get_next_page(cpu);
423 return trace_peek_data(pevent, cpu); 415 return trace_peek_data(cpu);
424 } 416 }
425 417
426 type_len_ts = data2host4(pevent, ptr); 418 type_len_ts = data2host4(ptr);
427 ptr += 4; 419 ptr += 4;
428 420
429 type_len = type_len4host(type_len_ts); 421 type_len = type_len4host(type_len_ts);
@@ -433,14 +425,14 @@ read_again:
433 case RINGBUF_TYPE_PADDING: 425 case RINGBUF_TYPE_PADDING:
434 if (!delta) 426 if (!delta)
435 die("error, hit unexpected end of page"); 427 die("error, hit unexpected end of page");
436 length = data2host4(pevent, ptr); 428 length = data2host4(ptr);
437 ptr += 4; 429 ptr += 4;
438 length *= 4; 430 length *= 4;
439 ptr += length; 431 ptr += length;
440 goto read_again; 432 goto read_again;
441 433
442 case RINGBUF_TYPE_TIME_EXTEND: 434 case RINGBUF_TYPE_TIME_EXTEND:
443 extend = data2host4(pevent, ptr); 435 extend = data2host4(ptr);
444 ptr += 4; 436 ptr += 4;
445 extend <<= TS_SHIFT; 437 extend <<= TS_SHIFT;
446 extend += delta; 438 extend += delta;
@@ -451,7 +443,7 @@ read_again:
451 ptr += 12; 443 ptr += 12;
452 break; 444 break;
453 case 0: 445 case 0:
454 length = data2host4(pevent, ptr); 446 length = data2host4(ptr);
455 ptr += 4; 447 ptr += 4;
456 die("here! length=%d", length); 448 die("here! length=%d", length);
457 break; 449 break;
@@ -476,17 +468,17 @@ read_again:
476 return data; 468 return data;
477} 469}
478 470
479struct pevent_record *trace_read_data(struct pevent *pevent, int cpu) 471struct record *trace_read_data(int cpu)
480{ 472{
481 struct pevent_record *data; 473 struct record *data;
482 474
483 data = trace_peek_data(pevent, cpu); 475 data = trace_peek_data(cpu);
484 cpu_data[cpu].next = NULL; 476 cpu_data[cpu].next = NULL;
485 477
486 return data; 478 return data;
487} 479}
488 480
489ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 481ssize_t trace_report(int fd, bool __repipe)
490{ 482{
491 char buf[BUFSIZ]; 483 char buf[BUFSIZ];
492 char test[] = { 23, 8, 68 }; 484 char test[] = { 23, 8, 68 };
@@ -518,32 +510,28 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
518 file_bigendian = buf[0]; 510 file_bigendian = buf[0];
519 host_bigendian = bigendian(); 511 host_bigendian = bigendian();
520 512
521 *ppevent = read_trace_init(file_bigendian, host_bigendian);
522 if (*ppevent == NULL)
523 die("read_trace_init failed");
524
525 read_or_die(buf, 1); 513 read_or_die(buf, 1);
526 long_size = buf[0]; 514 long_size = buf[0];
527 515
528 page_size = read4(*ppevent); 516 page_size = read4();
529 517
530 read_header_files(*ppevent); 518 read_header_files();
531 519
532 read_ftrace_files(*ppevent); 520 read_ftrace_files();
533 read_event_files(*ppevent); 521 read_event_files();
534 read_proc_kallsyms(*ppevent); 522 read_proc_kallsyms();
535 read_ftrace_printk(*ppevent); 523 read_ftrace_printk();
536 524
537 size = calc_data_size - 1; 525 size = calc_data_size - 1;
538 calc_data_size = 0; 526 calc_data_size = 0;
539 repipe = false; 527 repipe = false;
540 528
541 if (show_funcs) { 529 if (show_funcs) {
542 pevent_print_funcs(*ppevent); 530 print_funcs();
543 return size; 531 return size;
544 } 532 }
545 if (show_printk) { 533 if (show_printk) {
546 pevent_print_printk(*ppevent); 534 print_printk();
547 return size; 535 return size;
548 } 536 }
549 537
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 8715a1006d0..c9dcbec7d80 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -22,6 +22,7 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <ctype.h>
25#include <errno.h> 26#include <errno.h>
26 27
27#include "../perf.h" 28#include "../perf.h"
@@ -35,11 +36,11 @@ static int stop_script_unsupported(void)
35 return 0; 36 return 0;
36} 37}
37 38
38static void process_event_unsupported(union perf_event *event __maybe_unused, 39static void process_event_unsupported(union perf_event *event __unused,
39 struct perf_sample *sample __maybe_unused, 40 struct perf_sample *sample __unused,
40 struct perf_evsel *evsel __maybe_unused, 41 struct perf_evsel *evsel __unused,
41 struct machine *machine __maybe_unused, 42 struct perf_session *session __unused,
42 struct addr_location *al __maybe_unused) 43 struct thread *thread __unused)
43{ 44{
44} 45}
45 46
@@ -52,19 +53,16 @@ static void print_python_unsupported_msg(void)
52 "\n etc.\n"); 53 "\n etc.\n");
53} 54}
54 55
55static int python_start_script_unsupported(const char *script __maybe_unused, 56static int python_start_script_unsupported(const char *script __unused,
56 int argc __maybe_unused, 57 int argc __unused,
57 const char **argv __maybe_unused) 58 const char **argv __unused)
58{ 59{
59 print_python_unsupported_msg(); 60 print_python_unsupported_msg();
60 61
61 return -1; 62 return -1;
62} 63}
63 64
64static int python_generate_script_unsupported(struct pevent *pevent 65static int python_generate_script_unsupported(const char *outfile __unused)
65 __maybe_unused,
66 const char *outfile
67 __maybe_unused)
68{ 66{
69 print_python_unsupported_msg(); 67 print_python_unsupported_msg();
70 68
@@ -116,18 +114,16 @@ static void print_perl_unsupported_msg(void)
116 "\n etc.\n"); 114 "\n etc.\n");
117} 115}
118 116
119static int perl_start_script_unsupported(const char *script __maybe_unused, 117static int perl_start_script_unsupported(const char *script __unused,
120 int argc __maybe_unused, 118 int argc __unused,
121 const char **argv __maybe_unused) 119 const char **argv __unused)
122{ 120{
123 print_perl_unsupported_msg(); 121 print_perl_unsupported_msg();
124 122
125 return -1; 123 return -1;
126} 124}
127 125
128static int perl_generate_script_unsupported(struct pevent *pevent 126static int perl_generate_script_unsupported(const char *outfile __unused)
129 __maybe_unused,
130 const char *outfile __maybe_unused)
131{ 127{
132 print_perl_unsupported_msg(); 128 print_perl_unsupported_msg();
133 129
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index a55fd37ffea..f674dda3363 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,21 +1,16 @@
1#ifndef _PERF_UTIL_TRACE_EVENT_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define _PERF_UTIL_TRACE_EVENT_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include <stdbool.h>
4#include "parse-events.h" 5#include "parse-events.h"
5#include "event-parse.h"
6#include "session.h" 6#include "session.h"
7 7
8struct machine; 8#define __unused __attribute__((unused))
9struct perf_sample;
10union perf_event;
11struct perf_tool;
12 9
13extern int header_page_size_size;
14extern int header_page_ts_size;
15extern int header_page_data_offset;
16 10
17extern bool latency_format; 11#ifndef PAGE_MASK
18extern struct pevent *perf_pevent; 12#define PAGE_MASK (page_size - 1)
13#endif
19 14
20enum { 15enum {
21 RINGBUF_TYPE_PADDING = 29, 16 RINGBUF_TYPE_PADDING = 29,
@@ -27,57 +22,257 @@ enum {
27#define TS_SHIFT 27 22#define TS_SHIFT 27
28#endif 23#endif
29 24
30int bigendian(void); 25#define NSECS_PER_SEC 1000000000ULL
26#define NSECS_PER_USEC 1000ULL
31 27
32struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 28enum format_flags {
33void print_trace_event(struct pevent *pevent, int cpu, void *data, int size); 29 FIELD_IS_ARRAY = 1,
34void event_format__print(struct event_format *event, 30 FIELD_IS_POINTER = 2,
35 int cpu, void *data, int size); 31 FIELD_IS_SIGNED = 4,
32 FIELD_IS_STRING = 8,
33 FIELD_IS_DYNAMIC = 16,
34 FIELD_IS_FLAG = 32,
35 FIELD_IS_SYMBOLIC = 64,
36};
36 37
37void print_event(struct pevent *pevent, int cpu, void *data, int size, 38struct format_field {
38 unsigned long long nsecs, char *comm); 39 struct format_field *next;
40 char *type;
41 char *name;
42 int offset;
43 int size;
44 unsigned long flags;
45};
39 46
40int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); 47struct format {
41int parse_event_file(struct pevent *pevent, 48 int nr_common;
42 char *buf, unsigned long size, char *sys); 49 int nr_fields;
50 struct format_field *common_fields;
51 struct format_field *fields;
52};
43 53
44struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu); 54struct print_arg_atom {
55 char *atom;
56};
45 57
46unsigned long long 58struct print_arg_string {
47raw_field_value(struct event_format *event, const char *name, void *data); 59 char *string;
48void *raw_field_ptr(struct event_format *event, const char *name, void *data); 60 int offset;
61};
49 62
50void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 63struct print_arg_field {
51void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); 64 char *name;
65 struct format_field *field;
66};
52 67
53ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); 68struct print_flag_sym {
69 struct print_flag_sym *next;
70 char *value;
71 char *str;
72};
54 73
55int trace_parse_common_type(struct pevent *pevent, void *data); 74struct print_arg_typecast {
56int trace_parse_common_pid(struct pevent *pevent, void *data); 75 char *type;
76 struct print_arg *item;
77};
57 78
58struct event_format *trace_find_next_event(struct pevent *pevent, 79struct print_arg_flags {
59 struct event_format *event); 80 struct print_arg *field;
60unsigned long long read_size(struct event_format *event, void *ptr, int size); 81 char *delim;
61unsigned long long eval_flag(const char *flag); 82 struct print_flag_sym *flags;
83};
62 84
63struct pevent_record *trace_read_data(struct pevent *pevent, int cpu); 85struct print_arg_symbol {
64int read_tracing_data(int fd, struct list_head *pattrs); 86 struct print_arg *field;
87 struct print_flag_sym *symbols;
88};
89
90struct print_arg;
91
92struct print_arg_op {
93 char *op;
94 int prio;
95 struct print_arg *left;
96 struct print_arg *right;
97};
98
99struct print_arg_func {
100 char *name;
101 struct print_arg *args;
102};
103
104enum print_arg_type {
105 PRINT_NULL,
106 PRINT_ATOM,
107 PRINT_FIELD,
108 PRINT_FLAGS,
109 PRINT_SYMBOL,
110 PRINT_TYPE,
111 PRINT_STRING,
112 PRINT_OP,
113};
114
115struct print_arg {
116 struct print_arg *next;
117 enum print_arg_type type;
118 union {
119 struct print_arg_atom atom;
120 struct print_arg_field field;
121 struct print_arg_typecast typecast;
122 struct print_arg_flags flags;
123 struct print_arg_symbol symbol;
124 struct print_arg_func func;
125 struct print_arg_string string;
126 struct print_arg_op op;
127 };
128};
129
130struct print_fmt {
131 char *format;
132 struct print_arg *args;
133};
134
135struct event {
136 struct event *next;
137 char *name;
138 int id;
139 int flags;
140 struct format format;
141 struct print_fmt print_fmt;
142 char *system;
143};
144
145enum {
146 EVENT_FL_ISFTRACE = 0x01,
147 EVENT_FL_ISPRINT = 0x02,
148 EVENT_FL_ISBPRINT = 0x04,
149 EVENT_FL_ISFUNC = 0x08,
150 EVENT_FL_ISFUNCENT = 0x10,
151 EVENT_FL_ISFUNCRET = 0x20,
65 152
66struct tracing_data { 153 EVENT_FL_FAILED = 0x80000000
67 /* size is only valid if temp is 'true' */
68 ssize_t size;
69 bool temp;
70 char temp_file[50];
71}; 154};
72 155
73struct tracing_data *tracing_data_get(struct list_head *pattrs, 156struct record {
74 int fd, bool temp); 157 unsigned long long ts;
75void tracing_data_put(struct tracing_data *tdata); 158 int size;
159 void *data;
160};
161
162struct record *trace_peek_data(int cpu);
163struct record *trace_read_data(int cpu);
164
165void parse_set_info(int nr_cpus, int long_sz);
166
167ssize_t trace_report(int fd, bool repipe);
168
169void *malloc_or_die(unsigned int size);
170
171void parse_cmdlines(char *file, int size);
172void parse_proc_kallsyms(char *file, unsigned int size);
173void parse_ftrace_printk(char *file, unsigned int size);
174
175void print_funcs(void);
176void print_printk(void);
177
178int parse_ftrace_file(char *buf, unsigned long size);
179int parse_event_file(char *buf, unsigned long size, char *sys);
180void print_trace_event(int cpu, void *data, int size);
181
182extern int file_bigendian;
183extern int host_bigendian;
184
185int bigendian(void);
186
187static inline unsigned short __data2host2(unsigned short data)
188{
189 unsigned short swap;
190
191 if (host_bigendian == file_bigendian)
192 return data;
193
194 swap = ((data & 0xffULL) << 8) |
195 ((data & (0xffULL << 8)) >> 8);
196
197 return swap;
198}
199
200static inline unsigned int __data2host4(unsigned int data)
201{
202 unsigned int swap;
203
204 if (host_bigendian == file_bigendian)
205 return data;
76 206
207 swap = ((data & 0xffULL) << 24) |
208 ((data & (0xffULL << 8)) << 8) |
209 ((data & (0xffULL << 16)) >> 8) |
210 ((data & (0xffULL << 24)) >> 24);
77 211
78struct addr_location; 212 return swap;
213}
79 214
80struct perf_session; 215static inline unsigned long long __data2host8(unsigned long long data)
216{
217 unsigned long long swap;
218
219 if (host_bigendian == file_bigendian)
220 return data;
221
222 swap = ((data & 0xffULL) << 56) |
223 ((data & (0xffULL << 8)) << 40) |
224 ((data & (0xffULL << 16)) << 24) |
225 ((data & (0xffULL << 24)) << 8) |
226 ((data & (0xffULL << 32)) >> 8) |
227 ((data & (0xffULL << 40)) >> 24) |
228 ((data & (0xffULL << 48)) >> 40) |
229 ((data & (0xffULL << 56)) >> 56);
230
231 return swap;
232}
233
234#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
235#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
236#define data2host8(ptr) ({ \
237 unsigned long long __val; \
238 \
239 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
240 __data2host8(__val); \
241})
242
243extern int header_page_ts_offset;
244extern int header_page_ts_size;
245extern int header_page_size_offset;
246extern int header_page_size_size;
247extern int header_page_data_offset;
248extern int header_page_data_size;
249
250extern bool latency_format;
251
252int trace_parse_common_type(void *data);
253int trace_parse_common_pid(void *data);
254int parse_common_pc(void *data);
255int parse_common_flags(void *data);
256int parse_common_lock_depth(void *data);
257struct event *trace_find_event(int id);
258struct event *trace_find_next_event(struct event *event);
259unsigned long long read_size(void *ptr, int size);
260unsigned long long
261raw_field_value(struct event *event, const char *name, void *data);
262void *raw_field_ptr(struct event *event, const char *name, void *data);
263unsigned long long eval_flag(const char *flag);
264
265int read_tracing_data(int fd, struct list_head *pattrs);
266ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
267
268/* taken from kernel/trace/trace.h */
269enum trace_flag_type {
270 TRACE_FLAG_IRQS_OFF = 0x01,
271 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
272 TRACE_FLAG_NEED_RESCHED = 0x04,
273 TRACE_FLAG_HARDIRQ = 0x08,
274 TRACE_FLAG_SOFTIRQ = 0x10,
275};
81 276
82struct scripting_ops { 277struct scripting_ops {
83 const char *name; 278 const char *name;
@@ -86,9 +281,9 @@ struct scripting_ops {
86 void (*process_event) (union perf_event *event, 281 void (*process_event) (union perf_event *event,
87 struct perf_sample *sample, 282 struct perf_sample *sample,
88 struct perf_evsel *evsel, 283 struct perf_evsel *evsel,
89 struct machine *machine, 284 struct perf_session *session,
90 struct addr_location *al); 285 struct thread *thread);
91 int (*generate_script) (struct pevent *pevent, const char *outfile); 286 int (*generate_script) (const char *outfile);
92}; 287};
93 288
94int script_spec_register(const char *spec, struct scripting_ops *ops); 289int script_spec_register(const char *spec, struct scripting_ops *ops);
@@ -97,7 +292,6 @@ void setup_perl_scripting(void);
97void setup_python_scripting(void); 292void setup_python_scripting(void);
98 293
99struct scripting_context { 294struct scripting_context {
100 struct pevent *pevent;
101 void *event_data; 295 void *event_data;
102}; 296};
103 297
@@ -105,4 +299,4 @@ int common_pc(struct scripting_context *context);
105int common_flags(struct scripting_context *context); 299int common_flags(struct scripting_context *context);
106int common_lock_depth(struct scripting_context *context); 300int common_lock_depth(struct scripting_context *context);
107 301
108#endif /* _PERF_UTIL_TRACE_EVENT_H */ 302#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index c51fa6b70a2..5f3689a3d08 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -16,9 +16,4 @@ typedef signed short s16;
16typedef unsigned char u8; 16typedef unsigned char u8;
17typedef signed char s8; 17typedef signed char s8;
18 18
19union u64_swap {
20 u64 val64;
21 u32 val32[2];
22};
23
24#endif /* __PERF_TYPES_H */ 19#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
deleted file mode 100644
index 958723ba3d2..00000000000
--- a/tools/perf/util/unwind.c
+++ /dev/null
@@ -1,571 +0,0 @@
1/*
2 * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps.
3 *
4 * Lots of this code have been borrowed or heavily inspired from parts of
5 * the libunwind 0.99 code which are (amongst other contributors I may have
6 * forgotten):
7 *
8 * Copyright (C) 2002-2007 Hewlett-Packard Co
9 * Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
10 *
11 * And the bugs have been added by:
12 *
13 * Copyright (C) 2010, Frederic Weisbecker <fweisbec@gmail.com>
14 * Copyright (C) 2012, Jiri Olsa <jolsa@redhat.com>
15 *
16 */
17
18#include <elf.h>
19#include <gelf.h>
20#include <fcntl.h>
21#include <string.h>
22#include <unistd.h>
23#include <sys/mman.h>
24#include <linux/list.h>
25#include <libunwind.h>
26#include <libunwind-ptrace.h>
27#include "thread.h"
28#include "session.h"
29#include "perf_regs.h"
30#include "unwind.h"
31#include "util.h"
32
33extern int
34UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
35 unw_word_t ip,
36 unw_dyn_info_t *di,
37 unw_proc_info_t *pi,
38 int need_unwind_info, void *arg);
39
40#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
41
42#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
43#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
44
45/* Pointer-encoding formats: */
46#define DW_EH_PE_omit 0xff
47#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */
48#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */
49#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */
50#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */
51#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */
52
53/* Pointer-encoding application: */
54#define DW_EH_PE_absptr 0x00 /* absolute value */
55#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */
56
57/*
58 * The following are not documented by LSB v1.3, yet they are used by
59 * GCC, presumably they aren't documented by LSB since they aren't
60 * used on Linux:
61 */
62#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */
63#define DW_EH_PE_aligned 0x50 /* aligned pointer */
64
65/* Flags intentionaly not handled, since they're not needed:
66 * #define DW_EH_PE_indirect 0x80
67 * #define DW_EH_PE_uleb128 0x01
68 * #define DW_EH_PE_udata2 0x02
69 * #define DW_EH_PE_sleb128 0x09
70 * #define DW_EH_PE_sdata2 0x0a
71 * #define DW_EH_PE_textrel 0x20
72 * #define DW_EH_PE_datarel 0x30
73 */
74
75struct unwind_info {
76 struct perf_sample *sample;
77 struct machine *machine;
78 struct thread *thread;
79 u64 sample_uregs;
80};
81
82#define dw_read(ptr, type, end) ({ \
83 type *__p = (type *) ptr; \
84 type __v; \
85 if ((__p + 1) > (type *) end) \
86 return -EINVAL; \
87 __v = *__p++; \
88 ptr = (typeof(ptr)) __p; \
89 __v; \
90 })
91
92static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
93 u8 encoding)
94{
95 u8 *cur = *p;
96 *val = 0;
97
98 switch (encoding) {
99 case DW_EH_PE_omit:
100 *val = 0;
101 goto out;
102 case DW_EH_PE_ptr:
103 *val = dw_read(cur, unsigned long, end);
104 goto out;
105 default:
106 break;
107 }
108
109 switch (encoding & DW_EH_PE_APPL_MASK) {
110 case DW_EH_PE_absptr:
111 break;
112 case DW_EH_PE_pcrel:
113 *val = (unsigned long) cur;
114 break;
115 default:
116 return -EINVAL;
117 }
118
119 if ((encoding & 0x07) == 0x00)
120 encoding |= DW_EH_PE_udata4;
121
122 switch (encoding & DW_EH_PE_FORMAT_MASK) {
123 case DW_EH_PE_sdata4:
124 *val += dw_read(cur, s32, end);
125 break;
126 case DW_EH_PE_udata4:
127 *val += dw_read(cur, u32, end);
128 break;
129 case DW_EH_PE_sdata8:
130 *val += dw_read(cur, s64, end);
131 break;
132 case DW_EH_PE_udata8:
133 *val += dw_read(cur, u64, end);
134 break;
135 default:
136 return -EINVAL;
137 }
138
139 out:
140 *p = cur;
141 return 0;
142}
143
144#define dw_read_encoded_value(ptr, end, enc) ({ \
145 u64 __v; \
146 if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \
147 return -EINVAL; \
148 } \
149 __v; \
150 })
151
152static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
153 GElf_Shdr *shp, const char *name)
154{
155 Elf_Scn *sec = NULL;
156
157 while ((sec = elf_nextscn(elf, sec)) != NULL) {
158 char *str;
159
160 gelf_getshdr(sec, shp);
161 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
162 if (!strcmp(name, str))
163 break;
164 }
165
166 return sec;
167}
168
169static u64 elf_section_offset(int fd, const char *name)
170{
171 Elf *elf;
172 GElf_Ehdr ehdr;
173 GElf_Shdr shdr;
174 u64 offset = 0;
175
176 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
177 if (elf == NULL)
178 return 0;
179
180 do {
181 if (gelf_getehdr(elf, &ehdr) == NULL)
182 break;
183
184 if (!elf_section_by_name(elf, &ehdr, &shdr, name))
185 break;
186
187 offset = shdr.sh_offset;
188 } while (0);
189
190 elf_end(elf);
191 return offset;
192}
193
194struct table_entry {
195 u32 start_ip_offset;
196 u32 fde_offset;
197};
198
199struct eh_frame_hdr {
200 unsigned char version;
201 unsigned char eh_frame_ptr_enc;
202 unsigned char fde_count_enc;
203 unsigned char table_enc;
204
205 /*
206 * The rest of the header is variable-length and consists of the
207 * following members:
208 *
209 * encoded_t eh_frame_ptr;
210 * encoded_t fde_count;
211 */
212
213 /* A single encoded pointer should not be more than 8 bytes. */
214 u64 enc[2];
215
216 /*
217 * struct {
218 * encoded_t start_ip;
219 * encoded_t fde_addr;
220 * } binary_search_table[fde_count];
221 */
222 char data[0];
223} __packed;
224
225static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
226 u64 offset, u64 *table_data, u64 *segbase,
227 u64 *fde_count)
228{
229 struct eh_frame_hdr hdr;
230 u8 *enc = (u8 *) &hdr.enc;
231 u8 *end = (u8 *) &hdr.data;
232 ssize_t r;
233
234 r = dso__data_read_offset(dso, machine, offset,
235 (u8 *) &hdr, sizeof(hdr));
236 if (r != sizeof(hdr))
237 return -EINVAL;
238
239 /* We dont need eh_frame_ptr, just skip it. */
240 dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc);
241
242 *fde_count = dw_read_encoded_value(enc, end, hdr.fde_count_enc);
243 *segbase = offset;
244 *table_data = (enc - (u8 *) &hdr) + offset;
245 return 0;
246}
247
248static int read_unwind_spec(struct dso *dso, struct machine *machine,
249 u64 *table_data, u64 *segbase, u64 *fde_count)
250{
251 int ret = -EINVAL, fd;
252 u64 offset;
253
254 fd = dso__data_fd(dso, machine);
255 if (fd < 0)
256 return -EINVAL;
257
258 offset = elf_section_offset(fd, ".eh_frame_hdr");
259 close(fd);
260
261 if (offset)
262 ret = unwind_spec_ehframe(dso, machine, offset,
263 table_data, segbase,
264 fde_count);
265
266 /* TODO .debug_frame check if eh_frame_hdr fails */
267 return ret;
268}
269
270static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
271{
272 struct addr_location al;
273
274 thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
275 MAP__FUNCTION, ip, &al);
276 return al.map;
277}
278
279static int
280find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
281 int need_unwind_info, void *arg)
282{
283 struct unwind_info *ui = arg;
284 struct map *map;
285 unw_dyn_info_t di;
286 u64 table_data, segbase, fde_count;
287
288 map = find_map(ip, ui);
289 if (!map || !map->dso)
290 return -EINVAL;
291
292 pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
293
294 if (read_unwind_spec(map->dso, ui->machine,
295 &table_data, &segbase, &fde_count))
296 return -EINVAL;
297
298 memset(&di, 0, sizeof(di));
299 di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
300 di.start_ip = map->start;
301 di.end_ip = map->end;
302 di.u.rti.segbase = map->start + segbase;
303 di.u.rti.table_data = map->start + table_data;
304 di.u.rti.table_len = fde_count * sizeof(struct table_entry)
305 / sizeof(unw_word_t);
306 return dwarf_search_unwind_table(as, ip, &di, pi,
307 need_unwind_info, arg);
308}
309
310static int access_fpreg(unw_addr_space_t __maybe_unused as,
311 unw_regnum_t __maybe_unused num,
312 unw_fpreg_t __maybe_unused *val,
313 int __maybe_unused __write,
314 void __maybe_unused *arg)
315{
316 pr_err("unwind: access_fpreg unsupported\n");
317 return -UNW_EINVAL;
318}
319
320static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as,
321 unw_word_t __maybe_unused *dil_addr,
322 void __maybe_unused *arg)
323{
324 return -UNW_ENOINFO;
325}
326
327static int resume(unw_addr_space_t __maybe_unused as,
328 unw_cursor_t __maybe_unused *cu,
329 void __maybe_unused *arg)
330{
331 pr_err("unwind: resume unsupported\n");
332 return -UNW_EINVAL;
333}
334
335static int
336get_proc_name(unw_addr_space_t __maybe_unused as,
337 unw_word_t __maybe_unused addr,
338 char __maybe_unused *bufp, size_t __maybe_unused buf_len,
339 unw_word_t __maybe_unused *offp, void __maybe_unused *arg)
340{
341 pr_err("unwind: get_proc_name unsupported\n");
342 return -UNW_EINVAL;
343}
344
345static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
346 unw_word_t *data)
347{
348 struct addr_location al;
349 ssize_t size;
350
351 thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
352 MAP__FUNCTION, addr, &al);
353 if (!al.map) {
354 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
355 return -1;
356 }
357
358 if (!al.map->dso)
359 return -1;
360
361 size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
362 addr, (u8 *) data, sizeof(*data));
363
364 return !(size == sizeof(*data));
365}
366
367static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
368 u64 sample_regs)
369{
370 int i, idx = 0;
371
372 if (!(sample_regs & (1 << id)))
373 return -EINVAL;
374
375 for (i = 0; i < id; i++) {
376 if (sample_regs & (1 << i))
377 idx++;
378 }
379
380 *valp = regs->regs[idx];
381 return 0;
382}
383
384static int access_mem(unw_addr_space_t __maybe_unused as,
385 unw_word_t addr, unw_word_t *valp,
386 int __write, void *arg)
387{
388 struct unwind_info *ui = arg;
389 struct stack_dump *stack = &ui->sample->user_stack;
390 unw_word_t start, end;
391 int offset;
392 int ret;
393
394 /* Don't support write, probably not needed. */
395 if (__write || !stack || !ui->sample->user_regs.regs) {
396 *valp = 0;
397 return 0;
398 }
399
400 ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
401 ui->sample_uregs);
402 if (ret)
403 return ret;
404
405 end = start + stack->size;
406
407 /* Check overflow. */
408 if (addr + sizeof(unw_word_t) < addr)
409 return -EINVAL;
410
411 if (addr < start || addr + sizeof(unw_word_t) >= end) {
412 ret = access_dso_mem(ui, addr, valp);
413 if (ret) {
414 pr_debug("unwind: access_mem %p not inside range %p-%p\n",
415 (void *)addr, (void *)start, (void *)end);
416 *valp = 0;
417 return ret;
418 }
419 return 0;
420 }
421
422 offset = addr - start;
423 *valp = *(unw_word_t *)&stack->data[offset];
424 pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
425 (void *)addr, (unsigned long)*valp, offset);
426 return 0;
427}
428
429static int access_reg(unw_addr_space_t __maybe_unused as,
430 unw_regnum_t regnum, unw_word_t *valp,
431 int __write, void *arg)
432{
433 struct unwind_info *ui = arg;
434 int id, ret;
435
436 /* Don't support write, I suspect we don't need it. */
437 if (__write) {
438 pr_err("unwind: access_reg w %d\n", regnum);
439 return 0;
440 }
441
442 if (!ui->sample->user_regs.regs) {
443 *valp = 0;
444 return 0;
445 }
446
447 id = unwind__arch_reg_id(regnum);
448 if (id < 0)
449 return -EINVAL;
450
451 ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
452 if (ret) {
453 pr_err("unwind: can't read reg %d\n", regnum);
454 return ret;
455 }
456
457 pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
458 return 0;
459}
460
461static void put_unwind_info(unw_addr_space_t __maybe_unused as,
462 unw_proc_info_t *pi __maybe_unused,
463 void *arg __maybe_unused)
464{
465 pr_debug("unwind: put_unwind_info called\n");
466}
467
468static int entry(u64 ip, struct thread *thread, struct machine *machine,
469 unwind_entry_cb_t cb, void *arg)
470{
471 struct unwind_entry e;
472 struct addr_location al;
473
474 thread__find_addr_location(thread, machine,
475 PERF_RECORD_MISC_USER,
476 MAP__FUNCTION, ip, &al, NULL);
477
478 e.ip = ip;
479 e.map = al.map;
480 e.sym = al.sym;
481
482 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
483 al.sym ? al.sym->name : "''",
484 ip,
485 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
486
487 return cb(&e, arg);
488}
489
490static void display_error(int err)
491{
492 switch (err) {
493 case UNW_EINVAL:
494 pr_err("unwind: Only supports local.\n");
495 break;
496 case UNW_EUNSPEC:
497 pr_err("unwind: Unspecified error.\n");
498 break;
499 case UNW_EBADREG:
500 pr_err("unwind: Register unavailable.\n");
501 break;
502 default:
503 break;
504 }
505}
506
507static unw_accessors_t accessors = {
508 .find_proc_info = find_proc_info,
509 .put_unwind_info = put_unwind_info,
510 .get_dyn_info_list_addr = get_dyn_info_list_addr,
511 .access_mem = access_mem,
512 .access_reg = access_reg,
513 .access_fpreg = access_fpreg,
514 .resume = resume,
515 .get_proc_name = get_proc_name,
516};
517
518static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
519 void *arg)
520{
521 unw_addr_space_t addr_space;
522 unw_cursor_t c;
523 int ret;
524
525 addr_space = unw_create_addr_space(&accessors, 0);
526 if (!addr_space) {
527 pr_err("unwind: Can't create unwind address space.\n");
528 return -ENOMEM;
529 }
530
531 ret = unw_init_remote(&c, addr_space, ui);
532 if (ret)
533 display_error(ret);
534
535 while (!ret && (unw_step(&c) > 0)) {
536 unw_word_t ip;
537
538 unw_get_reg(&c, UNW_REG_IP, &ip);
539 ret = entry(ip, ui->thread, ui->machine, cb, arg);
540 }
541
542 unw_destroy_addr_space(addr_space);
543 return ret;
544}
545
546int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
547 struct machine *machine, struct thread *thread,
548 u64 sample_uregs, struct perf_sample *data)
549{
550 unw_word_t ip;
551 struct unwind_info ui = {
552 .sample = data,
553 .sample_uregs = sample_uregs,
554 .thread = thread,
555 .machine = machine,
556 };
557 int ret;
558
559 if (!data->user_regs.regs)
560 return -EINVAL;
561
562 ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
563 if (ret)
564 return ret;
565
566 ret = entry(ip, thread, machine, cb, arg);
567 if (ret)
568 return -ENOMEM;
569
570 return get_entries(&ui, cb, arg);
571}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
deleted file mode 100644
index cb6bc503a79..00000000000
--- a/tools/perf/util/unwind.h
+++ /dev/null
@@ -1,35 +0,0 @@
1#ifndef __UNWIND_H
2#define __UNWIND_H
3
4#include "types.h"
5#include "event.h"
6#include "symbol.h"
7
8struct unwind_entry {
9 struct map *map;
10 struct symbol *sym;
11 u64 ip;
12};
13
14typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
15
16#ifdef LIBUNWIND_SUPPORT
17int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
18 struct machine *machine,
19 struct thread *thread,
20 u64 sample_uregs,
21 struct perf_sample *data);
22int unwind__arch_reg_id(int regnum);
23#else
24static inline int
25unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
26 void *arg __maybe_unused,
27 struct machine *machine __maybe_unused,
28 struct thread *thread __maybe_unused,
29 u64 sample_uregs __maybe_unused,
30 struct perf_sample *data __maybe_unused)
31{
32 return 0;
33}
34#endif /* LIBUNWIND_SUPPORT */
35#endif /* __UNWIND_H */
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index 4007aca8e0c..e16bf9a707e 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -1,13 +1,9 @@
1/* 1/*
2 * usage.c 2 * GIT - The information manager from hell
3 *
4 * Various reporting routines.
5 * Originally copied from GIT source.
6 * 3 *
7 * Copyright (C) Linus Torvalds, 2005 4 * Copyright (C) Linus Torvalds, 2005
8 */ 5 */
9#include "util.h" 6#include "util.h"
10#include "debug.h"
11 7
12static void report(const char *prefix, const char *err, va_list params) 8static void report(const char *prefix, const char *err, va_list params)
13{ 9{
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 5906e8426cc..5b3ea49aa63 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,29 +1,5 @@
1#include "../perf.h"
2#include "util.h" 1#include "util.h"
3#include <sys/mman.h> 2#include <sys/mman.h>
4#ifdef BACKTRACE_SUPPORT
5#include <execinfo.h>
6#endif
7#include <stdio.h>
8#include <stdlib.h>
9
10/*
11 * XXX We need to find a better place for these things...
12 */
13unsigned int page_size;
14
15bool perf_host = true;
16bool perf_guest = false;
17
18void event_attr_init(struct perf_event_attr *attr)
19{
20 if (!perf_host)
21 attr->exclude_host = 1;
22 if (!perf_guest)
23 attr->exclude_guest = 1;
24 /* to capture ABI version */
25 attr->size = sizeof(*attr);
26}
27 3
28int mkdir_p(char *path, mode_t mode) 4int mkdir_p(char *path, mode_t mode)
29{ 5{
@@ -155,66 +131,3 @@ int readn(int fd, void *buf, size_t n)
155 131
156 return buf - buf_start; 132 return buf - buf_start;
157} 133}
158
159size_t hex_width(u64 v)
160{
161 size_t n = 1;
162
163 while ((v >>= 4))
164 ++n;
165
166 return n;
167}
168
169static int hex(char ch)
170{
171 if ((ch >= '0') && (ch <= '9'))
172 return ch - '0';
173 if ((ch >= 'a') && (ch <= 'f'))
174 return ch - 'a' + 10;
175 if ((ch >= 'A') && (ch <= 'F'))
176 return ch - 'A' + 10;
177 return -1;
178}
179
180/*
181 * While we find nice hex chars, build a long_val.
182 * Return number of chars processed.
183 */
184int hex2u64(const char *ptr, u64 *long_val)
185{
186 const char *p = ptr;
187 *long_val = 0;
188
189 while (*p) {
190 const int hex_val = hex(*p);
191
192 if (hex_val < 0)
193 break;
194
195 *long_val = (*long_val << 4) | hex_val;
196 p++;
197 }
198
199 return p - ptr;
200}
201
202/* Obtain a backtrace and print it to stdout. */
203#ifdef BACKTRACE_SUPPORT
204void dump_stack(void)
205{
206 void *array[16];
207 size_t size = backtrace(array, ARRAY_SIZE(array));
208 char **strings = backtrace_symbols(array, size);
209 size_t i;
210
211 printf("Obtained %zd stack frames.\n", size);
212
213 for (i = 0; i < size; i++)
214 printf("%s\n", strings[i]);
215
216 free(strings);
217}
218#else
219void dump_stack(void) {}
220#endif
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c2330918110..0128906bac8 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -40,6 +40,7 @@
40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) 40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
41 41
42#define _ALL_SOURCE 1 42#define _ALL_SOURCE 1
43#define _GNU_SOURCE 1
43#define _BSD_SOURCE 1 44#define _BSD_SOURCE 1
44#define HAS_BOOL 45#define HAS_BOOL
45 46
@@ -69,8 +70,14 @@
69#include <sys/poll.h> 70#include <sys/poll.h>
70#include <sys/socket.h> 71#include <sys/socket.h>
71#include <sys/ioctl.h> 72#include <sys/ioctl.h>
73#include <sys/select.h>
74#include <netinet/in.h>
75#include <netinet/tcp.h>
76#include <arpa/inet.h>
77#include <netdb.h>
78#include <pwd.h>
72#include <inttypes.h> 79#include <inttypes.h>
73#include <linux/magic.h> 80#include "../../../include/linux/magic.h"
74#include "types.h" 81#include "types.h"
75#include <sys/ttydefaults.h> 82#include <sys/ttydefaults.h>
76 83
@@ -193,15 +200,9 @@ static inline int has_extension(const char *filename, const char *ext)
193#undef isalpha 200#undef isalpha
194#undef isprint 201#undef isprint
195#undef isalnum 202#undef isalnum
196#undef islower
197#undef isupper
198#undef tolower 203#undef tolower
199#undef toupper 204#undef toupper
200 205
201#ifndef NSEC_PER_MSEC
202#define NSEC_PER_MSEC 1000000L
203#endif
204
205extern unsigned char sane_ctype[256]; 206extern unsigned char sane_ctype[256];
206#define GIT_SPACE 0x01 207#define GIT_SPACE 0x01
207#define GIT_DIGIT 0x02 208#define GIT_DIGIT 0x02
@@ -219,8 +220,6 @@ extern unsigned char sane_ctype[256];
219#define isalpha(x) sane_istest(x,GIT_ALPHA) 220#define isalpha(x) sane_istest(x,GIT_ALPHA)
220#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 221#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
221#define isprint(x) sane_istest(x,GIT_PRINT) 222#define isprint(x) sane_istest(x,GIT_PRINT)
222#define islower(x) (sane_istest(x,GIT_ALPHA) && sane_istest(x,0x20))
223#define isupper(x) (sane_istest(x,GIT_ALPHA) && !sane_istest(x,0x20))
224#define tolower(x) sane_case((unsigned char)(x), 0x20) 223#define tolower(x) sane_case((unsigned char)(x), 0x20)
225#define toupper(x) sane_case((unsigned char)(x), 0) 224#define toupper(x) sane_case((unsigned char)(x), 0)
226 225
@@ -240,35 +239,10 @@ void argv_free(char **argv);
240bool strglobmatch(const char *str, const char *pat); 239bool strglobmatch(const char *str, const char *pat);
241bool strlazymatch(const char *str, const char *pat); 240bool strlazymatch(const char *str, const char *pat);
242int strtailcmp(const char *s1, const char *s2); 241int strtailcmp(const char *s1, const char *s2);
243char *strxfrchar(char *s, char from, char to);
244unsigned long convert_unit(unsigned long value, char *unit); 242unsigned long convert_unit(unsigned long value, char *unit);
245int readn(int fd, void *buf, size_t size); 243int readn(int fd, void *buf, size_t size);
246 244
247struct perf_event_attr;
248
249void event_attr_init(struct perf_event_attr *attr);
250
251#define _STR(x) #x 245#define _STR(x) #x
252#define STR(x) _STR(x) 246#define STR(x) _STR(x)
253 247
254/*
255 * Determine whether some value is a power of two, where zero is
256 * *not* considered a power of two.
257 */
258
259static inline __attribute__((const))
260bool is_power_of_2(unsigned long n)
261{
262 return (n != 0 && ((n & (n - 1)) == 0));
263}
264
265size_t hex_width(u64 v);
266int hex2u64(const char *ptr, u64 *val);
267
268char *rtrim(char *s);
269
270void dump_stack(void);
271
272extern unsigned int page_size;
273
274#endif 248#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 697c8b4e59c..bdd33470b23 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -32,7 +32,6 @@ void perf_read_values_destroy(struct perf_read_values *values)
32 32
33 for (i = 0; i < values->threads; i++) 33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]); 34 free(values->value[i]);
35 free(values->value);
36 free(values->pid); 35 free(values->pid);
37 free(values->tid); 36 free(values->tid);
38 free(values->counterrawid); 37 free(values->counterrawid);
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
deleted file mode 100644
index e60951fcdb1..00000000000
--- a/tools/perf/util/vdso.c
+++ /dev/null
@@ -1,111 +0,0 @@
1
2#include <unistd.h>
3#include <stdio.h>
4#include <string.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <stdlib.h>
9#include <linux/kernel.h>
10
11#include "vdso.h"
12#include "util.h"
13#include "symbol.h"
14#include "linux/string.h"
15
16static bool vdso_found;
17static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
18
19static int find_vdso_map(void **start, void **end)
20{
21 FILE *maps;
22 char line[128];
23 int found = 0;
24
25 maps = fopen("/proc/self/maps", "r");
26 if (!maps) {
27 pr_err("vdso: cannot open maps\n");
28 return -1;
29 }
30
31 while (!found && fgets(line, sizeof(line), maps)) {
32 int m = -1;
33
34 /* We care only about private r-x mappings. */
35 if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
36 start, end, &m))
37 continue;
38 if (m < 0)
39 continue;
40
41 if (!strncmp(&line[m], VDSO__MAP_NAME,
42 sizeof(VDSO__MAP_NAME) - 1))
43 found = 1;
44 }
45
46 fclose(maps);
47 return !found;
48}
49
50static char *get_file(void)
51{
52 char *vdso = NULL;
53 char *buf = NULL;
54 void *start, *end;
55 size_t size;
56 int fd;
57
58 if (vdso_found)
59 return vdso_file;
60
61 if (find_vdso_map(&start, &end))
62 return NULL;
63
64 size = end - start;
65
66 buf = memdup(start, size);
67 if (!buf)
68 return NULL;
69
70 fd = mkstemp(vdso_file);
71 if (fd < 0)
72 goto out;
73
74 if (size == (size_t) write(fd, buf, size))
75 vdso = vdso_file;
76
77 close(fd);
78
79 out:
80 free(buf);
81
82 vdso_found = (vdso != NULL);
83 return vdso;
84}
85
86void vdso__exit(void)
87{
88 if (vdso_found)
89 unlink(vdso_file);
90}
91
92struct dso *vdso__dso_findnew(struct list_head *head)
93{
94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME);
95
96 if (!dso) {
97 char *file;
98
99 file = get_file();
100 if (!file)
101 return NULL;
102
103 dso = dso__new(VDSO__MAP_NAME);
104 if (dso != NULL) {
105 dsos__add(head, dso);
106 dso__set_long_name(dso, file);
107 }
108 }
109
110 return dso;
111}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
deleted file mode 100644
index 0f76e7caf6f..00000000000
--- a/tools/perf/util/vdso.h
+++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef __PERF_VDSO__
2#define __PERF_VDSO__
3
4#include <linux/types.h>
5#include <string.h>
6#include <stdbool.h>
7
8#define VDSO__MAP_NAME "[vdso]"
9
10static inline bool is_vdso_map(const char *filename)
11{
12 return !strcmp(filename, VDSO__MAP_NAME);
13}
14
15struct dso *vdso__dso_findnew(struct list_head *head);
16void vdso__exit(void);
17
18#endif /* __PERF_VDSO__ */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 19f15b65070..73e900edb5a 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -7,8 +7,7 @@
7 * There's no pack memory to release - but stay close to the Git 7 * There's no pack memory to release - but stay close to the Git
8 * version so wrap this away: 8 * version so wrap this away:
9 */ 9 */
10static inline void release_pack_memory(size_t size __maybe_unused, 10static inline void release_pack_memory(size_t size __used, int flag __used)
11 int flag __maybe_unused)
12{ 11{
13} 12}
14 13
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
deleted file mode 100644
index 6b9cf7a987c..00000000000
--- a/tools/power/acpi/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
1PROG= acpidump
2SRCS= acpidump.c
3KERNEL_INCLUDE := ../../../include
4CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE)
5
6all: acpidump
7$(PROG) : $(SRCS)
8 $(CC) $(CFLAGS) $(SRCS) -o $(PROG)
9
10CLEANFILES= $(PROG)
11
12clean :
13 rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~
14
15install :
16 install acpidump /usr/bin/acpidump
17 install acpidump.8 /usr/share/man/man8
18
diff --git a/tools/power/acpi/acpidump.8 b/tools/power/acpi/acpidump.8
deleted file mode 100644
index adfa99166e5..00000000000
--- a/tools/power/acpi/acpidump.8
+++ /dev/null
@@ -1,59 +0,0 @@
1.TH ACPIDUMP 8
2.SH NAME
3acpidump \- Dump system's ACPI tables to an ASCII file.
4.SH SYNOPSIS
5.ft B
6.B acpidump > acpidump.out
7.SH DESCRIPTION
8\fBacpidump \fP dumps the systems ACPI tables to an ASCII file
9appropriate for attaching to a bug report.
10
11Subsequently, they can be processed by utilities in the ACPICA package.
12.SS Options
13no options worth worrying about.
14.PP
15.SH EXAMPLE
16
17.nf
18# acpidump > acpidump.out
19
20$ acpixtract -a acpidump.out
21 Acpi table [DSDT] - 15974 bytes written to DSDT.dat
22 Acpi table [FACS] - 64 bytes written to FACS.dat
23 Acpi table [FACP] - 116 bytes written to FACP.dat
24 Acpi table [APIC] - 120 bytes written to APIC.dat
25 Acpi table [MCFG] - 60 bytes written to MCFG.dat
26 Acpi table [SSDT] - 444 bytes written to SSDT1.dat
27 Acpi table [SSDT] - 439 bytes written to SSDT2.dat
28 Acpi table [SSDT] - 439 bytes written to SSDT3.dat
29 Acpi table [SSDT] - 439 bytes written to SSDT4.dat
30 Acpi table [SSDT] - 439 bytes written to SSDT5.dat
31 Acpi table [RSDT] - 76 bytes written to RSDT.dat
32 Acpi table [RSDP] - 20 bytes written to RSDP.dat
33
34$ iasl -d *.dat
35...
36.fi
37creates *.dsl, a human readable form which can be edited
38and compiled using iasl.
39
40
41.SH NOTES
42
43.B "acpidump "
44must be run as root.
45
46.SH REFERENCES
47ACPICA: https://acpica.org/
48
49.SH FILES
50.ta
51.nf
52/dev/mem
53/sys/firmware/acpi/tables/dynamic/*
54.fi
55
56.PP
57.SH AUTHOR
58.nf
59Written by Len Brown <len.brown@intel.com>
diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/acpidump.c
deleted file mode 100644
index a84553a0e0d..00000000000
--- a/tools/power/acpi/acpidump.c
+++ /dev/null
@@ -1,559 +0,0 @@
1/*
2 * (c) Alexey Starikovskiy, Intel, 2005-2006.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer,
10 * without modification.
11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12 * substantially similar to the "NO WARRANTY" disclaimer below
13 * ("Disclaimer") and any redistribution must be conditioned upon
14 * including a substantially similar Disclaimer requirement for further
15 * binary redistribution.
16 * 3. Neither the names of the above-listed copyright holders nor the names
17 * of any contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * NO WARRANTY
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGES.
36 */
37
38#ifdef DEFINE_ALTERNATE_TYPES
39/* hack to enable building old application with new headers -lenb */
40#define acpi_fadt_descriptor acpi_table_fadt
41#define acpi_rsdp_descriptor acpi_table_rsdp
42#define DSDT_SIG ACPI_SIG_DSDT
43#define FACS_SIG ACPI_SIG_FACS
44#define FADT_SIG ACPI_SIG_FADT
45#define xfirmware_ctrl Xfacs
46#define firmware_ctrl facs
47
48typedef int s32;
49typedef unsigned char u8;
50typedef unsigned short u16;
51typedef unsigned int u32;
52typedef unsigned long long u64;
53typedef long long s64;
54#endif
55
56#include <sys/mman.h>
57#include <sys/types.h>
58#include <sys/stat.h>
59#include <fcntl.h>
60#include <stdio.h>
61#include <string.h>
62#include <unistd.h>
63#include <getopt.h>
64
65#include <dirent.h>
66
67#include <acpi/acconfig.h>
68#include <acpi/platform/acenv.h>
69#include <acpi/actypes.h>
70#include <acpi/actbl.h>
71
72static inline u8 checksum(u8 * buffer, u32 length)
73{
74 u8 sum = 0, *i = buffer;
75 buffer += length;
76 for (; i < buffer; sum += *(i++));
77 return sum;
78}
79
80static unsigned long psz, addr, length;
81static int print, connect, skip;
82static u8 select_sig[4];
83
84static unsigned long read_efi_systab( void )
85{
86 char buffer[80];
87 unsigned long addr;
88 FILE *f = fopen("/sys/firmware/efi/systab", "r");
89 if (f) {
90 while (fgets(buffer, 80, f)) {
91 if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1)
92 return addr;
93 }
94 fclose(f);
95 }
96 return 0;
97}
98
99static u8 *acpi_map_memory(unsigned long where, unsigned length)
100{
101 unsigned long offset;
102 u8 *there;
103 int fd = open("/dev/mem", O_RDONLY);
104 if (fd < 0) {
105 fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n");
106 exit(1);
107 }
108 offset = where % psz;
109 there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE,
110 fd, where - offset);
111 close(fd);
112 if (there == MAP_FAILED) return 0;
113 return (there + offset);
114}
115
116static void acpi_unmap_memory(u8 * there, unsigned length)
117{
118 unsigned long offset = (unsigned long)there % psz;
119 munmap(there - offset, length + offset);
120}
121
122static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig)
123{
124 unsigned size;
125 struct acpi_table_header *tbl = (struct acpi_table_header *)
126 acpi_map_memory(where, sizeof(struct acpi_table_header));
127 if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0;
128 size = tbl->length;
129 acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header));
130 return (struct acpi_table_header *)acpi_map_memory(where, size);
131}
132
133static void acpi_unmap_table(struct acpi_table_header *tbl)
134{
135 acpi_unmap_memory((u8 *)tbl, tbl->length);
136}
137
138static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length)
139{
140 struct acpi_rsdp_descriptor *rsdp;
141 u8 *i, *end = begin + length;
142 /* Search from given start address for the requested length */
143 for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) {
144 /* The signature and checksum must both be correct */
145 if (memcmp((char *)i, "RSD PTR ", 8)) continue;
146 rsdp = (struct acpi_rsdp_descriptor *)i;
147 /* Signature matches, check the appropriate checksum */
148 if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ?
149 ACPI_RSDP_CHECKSUM_LENGTH :
150 ACPI_RSDP_XCHECKSUM_LENGTH))
151 /* Checksum valid, we have found a valid RSDP */
152 return rsdp;
153 }
154 /* Searched entire block, no RSDP was found */
155 return 0;
156}
157
158/*
159 * Output data
160 */
161static void acpi_show_data(int fd, u8 * data, int size)
162{
163 char buffer[256];
164 int len;
165 int i, remain = size;
166 while (remain > 0) {
167 len = snprintf(buffer, 256, " %04x:", size - remain);
168 for (i = 0; i < 16 && i < remain; i++) {
169 len +=
170 snprintf(&buffer[len], 256 - len, " %02x", data[i]);
171 }
172 for (; i < 16; i++) {
173 len += snprintf(&buffer[len], 256 - len, " ");
174 }
175 len += snprintf(&buffer[len], 256 - len, " ");
176 for (i = 0; i < 16 && i < remain; i++) {
177 buffer[len++] = (isprint(data[i])) ? data[i] : '.';
178 }
179 buffer[len++] = '\n';
180 write(fd, buffer, len);
181 data += 16;
182 remain -= 16;
183 }
184}
185
186/*
187 * Output ACPI table
188 */
189static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr)
190{
191 char buff[80];
192 int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr);
193 write(fd, buff, len);
194 acpi_show_data(fd, (u8 *) table, table->length);
195 buff[0] = '\n';
196 write(fd, buff, 1);
197}
198
199static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr)
200{
201 static int select_done = 0;
202 if (!select_sig[0]) {
203 if (print) {
204 acpi_show_table(fd, tbl, addr);
205 } else {
206 write(fd, tbl, tbl->length);
207 }
208 } else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) {
209 if (skip > 0) {
210 --skip;
211 return;
212 }
213 if (print) {
214 acpi_show_table(fd, tbl, addr);
215 } else {
216 write(fd, tbl, tbl->length);
217 }
218 select_done = 1;
219 }
220}
221
222static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) {
223 struct acpi_fadt_descriptor x;
224 unsigned long addr;
225 size_t len = sizeof(struct acpi_fadt_descriptor);
226 if (len > tbl->length) len = tbl->length;
227 memcpy(&x, tbl, len);
228 x.header.length = len;
229 if (checksum((u8 *)tbl, len)) {
230 fprintf(stderr, "Wrong checksum for FADT!\n");
231 }
232 if (x.header.length >= 148 && x.Xdsdt) {
233 addr = (unsigned long)x.Xdsdt;
234 if (connect) {
235 x.Xdsdt = lseek(fd, 0, SEEK_CUR);
236 }
237 } else if (x.header.length >= 44 && x.dsdt) {
238 addr = (unsigned long)x.dsdt;
239 if (connect) {
240 x.dsdt = lseek(fd, 0, SEEK_CUR);
241 }
242 } else {
243 fprintf(stderr, "No DSDT in FADT!\n");
244 goto no_dsdt;
245 }
246 tbl = acpi_map_table(addr, DSDT_SIG);
247 if (!tbl) goto no_dsdt;
248 if (checksum((u8 *)tbl, tbl->length))
249 fprintf(stderr, "Wrong checksum for DSDT!\n");
250 write_table(fd, tbl, addr);
251 acpi_unmap_table(tbl);
252no_dsdt:
253 if (x.header.length >= 140 && x.xfirmware_ctrl) {
254 addr = (unsigned long)x.xfirmware_ctrl;
255 if (connect) {
256 x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR);
257 }
258 } else if (x.header.length >= 40 && x.firmware_ctrl) {
259 addr = (unsigned long)x.firmware_ctrl;
260 if (connect) {
261 x.firmware_ctrl = lseek(fd, 0, SEEK_CUR);
262 }
263 } else {
264 fprintf(stderr, "No FACS in FADT!\n");
265 goto no_facs;
266 }
267 tbl = acpi_map_table(addr, FACS_SIG);
268 if (!tbl) goto no_facs;
269 /* do not checksum FACS */
270 write_table(fd, tbl, addr);
271 acpi_unmap_table(tbl);
272no_facs:
273 write_table(fd, (struct acpi_table_header *)&x, xaddr);
274}
275
276static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp)
277{
278 struct acpi_table_header *sdt, *tbl = 0;
279 int xsdt = 1, i, num;
280 char *offset;
281 unsigned long addr;
282 if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
283 tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT");
284 }
285 if (!tbl && rsdp->rsdt_physical_address) {
286 xsdt = 0;
287 tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT");
288 }
289 if (!tbl) return 0;
290 sdt = malloc(tbl->length);
291 memcpy(sdt, tbl, tbl->length);
292 acpi_unmap_table(tbl);
293 if (checksum((u8 *)sdt, sdt->length))
294 fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT");
295 num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32));
296 offset = (char *)sdt + sizeof(struct acpi_table_header);
297 for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) {
298 addr = (xsdt) ? (unsigned long)(*(u64 *)offset):
299 (unsigned long)(*(u32 *)offset);
300 if (!addr) continue;
301 tbl = acpi_map_table(addr, 0);
302 if (!tbl) continue;
303 if (!memcmp(tbl->signature, FADT_SIG, 4)) {
304 acpi_dump_FADT(fd, tbl, addr);
305 } else {
306 if (checksum((u8 *)tbl, tbl->length))
307 fprintf(stderr, "Wrong checksum for generic table!\n");
308 write_table(fd, tbl, addr);
309 }
310 acpi_unmap_table(tbl);
311 if (connect) {
312 if (xsdt)
313 (*(u64*)offset) = lseek(fd, 0, SEEK_CUR);
314 else
315 (*(u32*)offset) = lseek(fd, 0, SEEK_CUR);
316 }
317 }
318 if (xsdt) {
319 addr = (unsigned long)rsdp->xsdt_physical_address;
320 if (connect) {
321 rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR);
322 }
323 } else {
324 addr = (unsigned long)rsdp->rsdt_physical_address;
325 if (connect) {
326 rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR);
327 }
328 }
329 write_table(fd, sdt, addr);
330 free (sdt);
331 return 1;
332}
333
334#define DYNAMIC_SSDT "/sys/firmware/acpi/tables/dynamic"
335
336static void acpi_dump_dynamic_SSDT(int fd)
337{
338 struct stat file_stat;
339 char filename[256], *ptr;
340 DIR *tabledir;
341 struct dirent *entry;
342 FILE *fp;
343 int count, readcount, length;
344 struct acpi_table_header table_header, *ptable;
345
346 if (stat(DYNAMIC_SSDT, &file_stat) == -1) {
347 /* The directory doesn't exist */
348 return;
349 }
350 tabledir = opendir(DYNAMIC_SSDT);
351 if(!tabledir){
352 /*can't open the directory */
353 return;
354 }
355
356 while ((entry = readdir(tabledir)) != 0){
357 /* skip the file of . /.. */
358 if (entry->d_name[0] == '.')
359 continue;
360
361 sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name);
362 fp = fopen(filename, "r");
363 if (fp == NULL) {
364 fprintf(stderr, "Can't open the file of %s\n",
365 filename);
366 continue;
367 }
368 /* Read the Table header to parse the table length */
369 count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp);
370 if (count < sizeof(table_header)) {
371 /* the length is lessn than ACPI table header. skip it */
372 fclose(fp);
373 continue;
374 }
375 length = table_header.length;
376 ptr = malloc(table_header.length);
377 fseek(fp, 0, SEEK_SET);
378 readcount = 0;
379 while(!feof(fp) && readcount < length) {
380 count = fread(ptr + readcount, 1, 256, fp);
381 readcount += count;
382 }
383 fclose(fp);
384 ptable = (struct acpi_table_header *) ptr;
385 if (checksum((u8 *) ptable, ptable->length))
386 fprintf(stderr, "Wrong checksum "
387 "for dynamic SSDT table!\n");
388 write_table(fd, ptable, 0);
389 free(ptr);
390 }
391 closedir(tabledir);
392 return;
393}
394
395static void usage(const char *progname)
396{
397 puts("Usage:");
398 printf("%s [--addr 0x1234][--table DSDT][--output filename]"
399 "[--binary][--length 0x456][--help]\n", progname);
400 puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address");
401 puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature");
402 puts("\t--output filename or -o filename -- redirect output from stdin to filename");
403 puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format");
404 puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory"
405 "\n\t\tregion without trying to understand it's contents");
406 puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one");
407 puts("\t--help or -h -- this help message");
408 exit(0);
409}
410
411static struct option long_options[] = {
412 {"addr", 1, 0, 0},
413 {"table", 1, 0, 0},
414 {"output", 1, 0, 0},
415 {"binary", 0, 0, 0},
416 {"length", 1, 0, 0},
417 {"skip", 1, 0, 0},
418 {"help", 0, 0, 0},
419 {0, 0, 0, 0}
420};
421int main(int argc, char **argv)
422{
423 int option_index, c, fd;
424 u8 *raw;
425 struct acpi_rsdp_descriptor rsdpx, *x = 0;
426 char *filename = 0;
427 char buff[80];
428 memset(select_sig, 0, 4);
429 print = 1;
430 connect = 0;
431 addr = length = 0;
432 skip = 0;
433 while (1) {
434 option_index = 0;
435 c = getopt_long(argc, argv, "a:t:o:bl:s:h",
436 long_options, &option_index);
437 if (c == -1)
438 break;
439
440 switch (c) {
441 case 0:
442 switch (option_index) {
443 case 0:
444 addr = strtoul(optarg, (char **)NULL, 16);
445 break;
446 case 1:
447 memcpy(select_sig, optarg, 4);
448 break;
449 case 2:
450 filename = optarg;
451 break;
452 case 3:
453 print = 0;
454 break;
455 case 4:
456 length = strtoul(optarg, (char **)NULL, 16);
457 break;
458 case 5:
459 skip = strtoul(optarg, (char **)NULL, 10);
460 break;
461 case 6:
462 usage(argv[0]);
463 exit(0);
464 }
465 break;
466 case 'a':
467 addr = strtoul(optarg, (char **)NULL, 16);
468 break;
469 case 't':
470 memcpy(select_sig, optarg, 4);
471 break;
472 case 'o':
473 filename = optarg;
474 break;
475 case 'b':
476 print = 0;
477 break;
478 case 'l':
479 length = strtoul(optarg, (char **)NULL, 16);
480 break;
481 case 's':
482 skip = strtoul(optarg, (char **)NULL, 10);
483 break;
484 case 'h':
485 usage(argv[0]);
486 exit(0);
487 default:
488 printf("Unknown option!\n");
489 usage(argv[0]);
490 exit(0);
491 }
492 }
493
494 fd = STDOUT_FILENO;
495 if (filename) {
496 fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
497 if (fd < 0)
498 return fd;
499 }
500
501 if (!select_sig[0] && !print) {
502 connect = 1;
503 }
504
505 psz = sysconf(_SC_PAGESIZE);
506 if (length && addr) {
507 /* We know length and address, it means we just want a memory dump */
508 if (!(raw = acpi_map_memory(addr, length)))
509 goto not_found;
510 write(fd, raw, length);
511 acpi_unmap_memory(raw, length);
512 close(fd);
513 return 0;
514 }
515
516 length = sizeof(struct acpi_rsdp_descriptor);
517 if (!addr) {
518 addr = read_efi_systab();
519 if (!addr) {
520 addr = ACPI_HI_RSDP_WINDOW_BASE;
521 length = ACPI_HI_RSDP_WINDOW_SIZE;
522 }
523 }
524
525 if (!(raw = acpi_map_memory(addr, length)) ||
526 !(x = acpi_scan_for_rsdp(raw, length)))
527 goto not_found;
528
529 /* Find RSDP and print all found tables */
530 memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor));
531 acpi_unmap_memory(raw, length);
532 if (connect) {
533 lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET);
534 }
535 if (!acpi_dump_SDT(fd, &rsdpx))
536 goto not_found;
537 if (connect) {
538 lseek(fd, 0, SEEK_SET);
539 write(fd, x, (rsdpx.revision < 2) ?
540 ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
541 } else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) {
542 addr += (long)x - (long)raw;
543 length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr);
544 write(fd, buff, length);
545 acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ?
546 ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH);
547 buff[0] = '\n';
548 write(fd, buff, 1);
549 }
550 acpi_dump_dynamic_SSDT(fd);
551 close(fd);
552 return 0;
553not_found:
554 close(fd);
555 fprintf(stderr, "ACPI tables were not found. If you know location "
556 "of RSD PTR table (from dmesg, etc), "
557 "supply it with either --addr or -a option\n");
558 return 1;
559}
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index d875a74a3bd..e8a03aceceb 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -19,16 +19,6 @@
19# along with this program; if not, write to the Free Software 19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21# 21#
22OUTPUT=./
23ifeq ("$(origin O)", "command line")
24 OUTPUT := $(O)/
25endif
26
27ifneq ($(OUTPUT),)
28# check that the output directory actually exists
29OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
30$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
31endif
32 22
33# --- CONFIGURATION BEGIN --- 23# --- CONFIGURATION BEGIN ---
34 24
@@ -97,7 +87,6 @@ AR = $(CROSS)ar
97STRIP = $(CROSS)strip 87STRIP = $(CROSS)strip
98RANLIB = $(CROSS)ranlib 88RANLIB = $(CROSS)ranlib
99HOSTCC = gcc 89HOSTCC = gcc
100MKDIR = mkdir
101 90
102 91
103# Now we set up the build system 92# Now we set up the build system
@@ -106,12 +95,12 @@ MKDIR = mkdir
106# set up PWD so that older versions of make will work with our build. 95# set up PWD so that older versions of make will work with our build.
107PWD = $(shell pwd) 96PWD = $(shell pwd)
108 97
109GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; done;} 98GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;}
110 99
111export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS 100export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS
112 101
113# check if compiler option is supported 102# check if compiler option is supported
114cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} 103cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;}
115 104
116# use '-Os' optimization if available, else use -O2 105# use '-Os' optimization if available, else use -O2
117OPTIMIZATION := $(call cc-supports,-Os,-O2) 106OPTIMIZATION := $(call cc-supports,-Os,-O2)
@@ -133,18 +122,15 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \
133 utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ 122 utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
134 utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o 123 utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o
135 124
136UTIL_SRC := $(UTIL_OBJS:.o=.c)
137
138UTIL_OBJS := $(addprefix $(OUTPUT),$(UTIL_OBJS))
139
140UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ 125UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
141 utils/helpers/bitmask.h \ 126 utils/helpers/bitmask.h \
142 utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def 127 utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
143 128
129UTIL_SRC := $(UTIL_OBJS:.o=.c)
130
144LIB_HEADERS = lib/cpufreq.h lib/sysfs.h 131LIB_HEADERS = lib/cpufreq.h lib/sysfs.h
145LIB_SRC = lib/cpufreq.c lib/sysfs.c 132LIB_SRC = lib/cpufreq.c lib/sysfs.c
146LIB_OBJS = lib/cpufreq.o lib/sysfs.o 133LIB_OBJS = lib/cpufreq.o lib/sysfs.o
147LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS))
148 134
149CFLAGS += -pipe 135CFLAGS += -pipe
150 136
@@ -182,91 +168,83 @@ endif
182 168
183# the actual make rules 169# the actual make rules
184 170
185all: libcpupower $(OUTPUT)cpupower $(COMPILE_NLS) $(COMPILE_BENCH) 171all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH)
186 172
187$(OUTPUT)lib/%.o: $(LIB_SRC) $(LIB_HEADERS) 173lib/%.o: $(LIB_SRC) $(LIB_HEADERS)
188 $(ECHO) " CC " $@ 174 $(ECHO) " CC " $@
189 $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c 175 $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c
190 176
191$(OUTPUT)libcpupower.so.$(LIB_MAJ): $(LIB_OBJS) 177libcpupower.so.$(LIB_MAJ): $(LIB_OBJS)
192 $(ECHO) " LD " $@ 178 $(ECHO) " LD " $@
193 $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \ 179 $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \
194 -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS) 180 -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS)
195 @ln -sf $(@F) $(OUTPUT)libcpupower.so 181 @ln -sf $@ libcpupower.so
196 @ln -sf $(@F) $(OUTPUT)libcpupower.so.$(LIB_MIN) 182 @ln -sf $@ libcpupower.so.$(LIB_MIN)
197 183
198libcpupower: $(OUTPUT)libcpupower.so.$(LIB_MAJ) 184libcpupower: libcpupower.so.$(LIB_MAJ)
199 185
200# Let all .o files depend on its .c file and all headers 186# Let all .o files depend on its .c file and all headers
201# Might be worth to put this into utils/Makefile at some point of time 187# Might be worth to put this into utils/Makefile at some point of time
202$(UTIL_OBJS): $(UTIL_HEADERS) 188$(UTIL_OBJS): $(UTIL_HEADERS)
203 189
204$(OUTPUT)%.o: %.c 190.c.o:
205 $(ECHO) " CC " $@ 191 $(ECHO) " CC " $@
206 $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c 192 $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c
207 193
208$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ) 194cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ)
209 $(ECHO) " CC " $@ 195 $(ECHO) " CC " $@
210 $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@ 196 $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS)
211 $(QUIET) $(STRIPCMD) $@ 197 $(QUIET) $(STRIPCMD) $@
212 198
213$(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC) 199po/$(PACKAGE).pot: $(UTIL_SRC)
214 $(ECHO) " GETTEXT " $@ 200 $(ECHO) " GETTEXT " $@
215 $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \ 201 $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \
216 --keyword=_ --keyword=N_ $(UTIL_SRC) -p $(@D) -o $(@F) 202 --keyword=_ --keyword=N_ $(UTIL_SRC) && \
203 test -f $(PACKAGE).po && \
204 mv -f $(PACKAGE).po po/$(PACKAGE).pot
217 205
218$(OUTPUT)po/%.gmo: po/%.po 206po/%.gmo: po/%.po
219 $(ECHO) " MSGFMT " $@ 207 $(ECHO) " MSGFMT " $@
220 $(QUIET) msgfmt -o $@ po/$*.po 208 $(QUIET) msgfmt -o $@ po/$*.po
221 209
222create-gmo: ${GMO_FILES} 210create-gmo: ${GMO_FILES}
223 211
224update-po: $(OUTPUT)po/$(PACKAGE).pot 212update-po: po/$(PACKAGE).pot
225 $(ECHO) " MSGMRG " $@ 213 $(ECHO) " MSGMRG " $@
226 $(QUIET) @for HLANG in $(LANGUAGES); do \ 214 $(QUIET) @for HLANG in $(LANGUAGES); do \
227 echo -n "Updating $$HLANG "; \ 215 echo -n "Updating $$HLANG "; \
228 if msgmerge po/$$HLANG.po $< -o \ 216 if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \
229 $(OUTPUT)po/$$HLANG.new.po; then \ 217 po/$$HLANG.new.po; then \
230 mv -f $(OUTPUT)po/$$HLANG.new.po $(OUTPUT)po/$$HLANG.po; \ 218 mv -f po/$$HLANG.new.po po/$$HLANG.po; \
231 else \ 219 else \
232 echo "msgmerge for $$HLANG failed!"; \ 220 echo "msgmerge for $$HLANG failed!"; \
233 rm -f $(OUTPUT)po/$$HLANG.new.po; \ 221 rm -f po/$$HLANG.new.po; \
234 fi; \ 222 fi; \
235 done; 223 done;
236 224
237compile-bench: $(OUTPUT)libcpupower.so.$(LIB_MAJ) 225compile-bench: libcpupower.so.$(LIB_MAJ)
238 @V=$(V) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) 226 @V=$(V) confdir=$(confdir) $(MAKE) -C bench
239
240# we compile into subdirectories. if the target directory is not the
241# source directory, they might not exists. So we depend the various
242# files onto their directories.
243DIRECTORY_DEPS = $(LIB_OBJS) $(UTIL_OBJS) $(GMO_FILES)
244$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
245
246# In the second step, we make a rule to actually create these directories
247$(sort $(dir $(DIRECTORY_DEPS))):
248 $(ECHO) " MKDIR " $@
249 $(QUIET) $(MKDIR) -p $@ 2>/dev/null
250 227
251clean: 228clean:
252 -find $(OUTPUT) \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ 229 -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
253 | xargs rm -f 230 | xargs rm -f
254 -rm -f $(OUTPUT)cpupower 231 -rm -f $(UTIL_BINS)
255 -rm -f $(OUTPUT)libcpupower.so* 232 -rm -f $(IDLE_OBJS)
256 -rm -rf $(OUTPUT)po/*.gmo 233 -rm -f cpupower
257 -rm -rf $(OUTPUT)po/*.pot 234 -rm -f libcpupower.so*
258 $(MAKE) -C bench O=$(OUTPUT) clean 235 -rm -rf po/*.gmo po/*.pot
236 $(MAKE) -C bench clean
259 237
260 238
261install-lib: 239install-lib:
262 $(INSTALL) -d $(DESTDIR)${libdir} 240 $(INSTALL) -d $(DESTDIR)${libdir}
263 $(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ 241 $(CP) libcpupower.so* $(DESTDIR)${libdir}/
264 $(INSTALL) -d $(DESTDIR)${includedir} 242 $(INSTALL) -d $(DESTDIR)${includedir}
265 $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h 243 $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h
266 244
267install-tools: 245install-tools:
268 $(INSTALL) -d $(DESTDIR)${bindir} 246 $(INSTALL) -d $(DESTDIR)${bindir}
269 $(INSTALL_PROGRAM) $(OUTPUT)cpupower $(DESTDIR)${bindir} 247 $(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir}
270 248
271install-man: 249install-man:
272 $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 250 $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1
@@ -279,13 +257,13 @@ install-man:
279install-gmo: 257install-gmo:
280 $(INSTALL) -d $(DESTDIR)${localedir} 258 $(INSTALL) -d $(DESTDIR)${localedir}
281 for HLANG in $(LANGUAGES); do \ 259 for HLANG in $(LANGUAGES); do \
282 echo '$(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \ 260 echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \
283 $(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ 261 $(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
284 done; 262 done;
285 263
286install-bench: 264install-bench:
287 @#DESTDIR must be set from outside to survive 265 @#DESTDIR must be set from outside to survive
288 @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) install 266 @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install
289 267
290install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) 268install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH)
291 269
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile
index 7ec7021a29c..2b67606fc3e 100644
--- a/tools/power/cpupower/bench/Makefile
+++ b/tools/power/cpupower/bench/Makefile
@@ -1,36 +1,29 @@
1OUTPUT := ./ 1LIBS = -L../ -lm -lcpupower
2ifeq ("$(origin O)", "command line")
3ifneq ($(O),)
4 OUTPUT := $(O)/
5endif
6endif
7 2
8LIBS = -L../ -L$(OUTPUT) -lm -lcpupower 3OBJS = main.o parse.o system.o benchmark.o
9
10OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o
11CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" 4CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\"
12 5
13$(OUTPUT)%.o : %.c 6%.o : %.c
14 $(ECHO) " CC " $@ 7 $(ECHO) " CC " $@
15 $(QUIET) $(CC) -c $(CFLAGS) $< -o $@ 8 $(QUIET) $(CC) -c $(CFLAGS) $< -o $@
16 9
17$(OUTPUT)cpufreq-bench: $(OBJS) 10cpufreq-bench: $(OBJS)
18 $(ECHO) " CC " $@ 11 $(ECHO) " CC " $@
19 $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) 12 $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS)
20 13
21all: $(OUTPUT)cpufreq-bench 14all: cpufreq-bench
22 15
23install: 16install:
24 mkdir -p $(DESTDIR)/$(sbindir) 17 mkdir -p $(DESTDIR)/$(sbindir)
25 mkdir -p $(DESTDIR)/$(bindir) 18 mkdir -p $(DESTDIR)/$(bindir)
26 mkdir -p $(DESTDIR)/$(docdir) 19 mkdir -p $(DESTDIR)/$(docdir)
27 mkdir -p $(DESTDIR)/$(confdir) 20 mkdir -p $(DESTDIR)/$(confdir)
28 install -m 755 $(OUTPUT)cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench 21 install -m 755 cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench
29 install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh 22 install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh
30 install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH 23 install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH
31 install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh 24 install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh
32 install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf 25 install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf
33 26
34clean: 27clean:
35 rm -f $(OUTPUT)*.o 28 rm -f *.o
36 rm -f $(OUTPUT)cpufreq-bench 29 rm -f cpufreq-bench
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile
index c05cc0ac80c..d08cc1ead9b 100644
--- a/tools/power/cpupower/debug/i386/Makefile
+++ b/tools/power/cpupower/debug/i386/Makefile
@@ -1,41 +1,20 @@
1OUTPUT=./
2ifeq ("$(origin O)", "command line")
3 OUTPUT := $(O)/
4endif
5
6DESTDIR =
7bindir = /usr/bin
8
9INSTALL = /usr/bin/install
10
11
12default: all 1default: all
13 2
14$(OUTPUT)centrino-decode: centrino-decode.c 3centrino-decode: centrino-decode.c
15 $(CC) $(CFLAGS) -o $@ centrino-decode.c 4 $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
16 5
17$(OUTPUT)dump_psb: dump_psb.c 6dump_psb: dump_psb.c
18 $(CC) $(CFLAGS) -o $@ dump_psb.c 7 $(CC) $(CFLAGS) -o dump_psb dump_psb.c
19 8
20$(OUTPUT)intel_gsic: intel_gsic.c 9intel_gsic: intel_gsic.c
21 $(CC) $(CFLAGS) -o $@ -llrmi intel_gsic.c 10 $(CC) $(CFLAGS) -o intel_gsic -llrmi intel_gsic.c
22 11
23$(OUTPUT)powernow-k8-decode: powernow-k8-decode.c 12powernow-k8-decode: powernow-k8-decode.c
24 $(CC) $(CFLAGS) -o $@ powernow-k8-decode.c 13 $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
25 14
26all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode 15all: centrino-decode dump_psb intel_gsic powernow-k8-decode
27 16
28clean: 17clean:
29 rm -rf $(OUTPUT)centrino-decode 18 rm -rf centrino-decode dump_psb intel_gsic powernow-k8-decode
30 rm -rf $(OUTPUT)dump_psb
31 rm -rf $(OUTPUT)intel_gsic
32 rm -rf $(OUTPUT)powernow-k8-decode
33
34install:
35 $(INSTALL) -d $(DESTDIR)${bindir}
36 $(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir}
37 $(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir}
38 $(INSTALL) $(OUTPUT)dump_psb $(DESTDIR)${bindir}
39 $(INSTALL) $(OUTPUT)intel_gsic $(DESTDIR)${bindir}
40 19
41.PHONY: all default clean install 20.PHONY: all default clean
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
index 1c521452671..3326217dd31 100644
--- a/tools/power/cpupower/debug/x86_64/Makefile
+++ b/tools/power/cpupower/debug/x86_64/Makefile
@@ -1,30 +1,14 @@
1OUTPUT=./
2ifeq ("$(origin O)", "command line")
3 OUTPUT := $(O)/
4endif
5
6DESTDIR =
7bindir = /usr/bin
8
9INSTALL = /usr/bin/install
10
11
12default: all 1default: all
13 2
14$(OUTPUT)centrino-decode: ../i386/centrino-decode.c 3centrino-decode: ../i386/centrino-decode.c
15 $(CC) $(CFLAGS) -o $@ $< 4 $(CC) $(CFLAGS) -o $@ $<
16 5
17$(OUTPUT)powernow-k8-decode: ../i386/powernow-k8-decode.c 6powernow-k8-decode: ../i386/powernow-k8-decode.c
18 $(CC) $(CFLAGS) -o $@ $< 7 $(CC) $(CFLAGS) -o $@ $<
19 8
20all: $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode 9all: centrino-decode powernow-k8-decode
21 10
22clean: 11clean:
23 rm -rf $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode 12 rm -rf centrino-decode powernow-k8-decode
24
25install:
26 $(INSTALL) -d $(DESTDIR)${bindir}
27 $(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir}
28 $(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir}
29 13
30.PHONY: all default clean install 14.PHONY: all default clean
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
index 4a1918ea8f9..bb60a8d1e45 100644
--- a/tools/power/cpupower/man/cpupower-frequency-info.1
+++ b/tools/power/cpupower/man/cpupower-frequency-info.1
@@ -1,4 +1,4 @@
1.TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual" 1.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" ""
2.SH "NAME" 2.SH "NAME"
3.LP 3.LP
4cpupower frequency\-info \- Utility to retrieve cpufreq kernel information 4cpupower frequency\-info \- Utility to retrieve cpufreq kernel information
@@ -50,6 +50,8 @@ Prints out information like provided by the /proc/cpufreq interface in 2.4. and
50\fB\-m\fR \fB\-\-human\fR 50\fB\-m\fR \fB\-\-human\fR
51human\-readable output for the \-f, \-w, \-s and \-y parameters. 51human\-readable output for the \-f, \-w, \-s and \-y parameters.
52.TP 52.TP
53\fB\-h\fR \fB\-\-help\fR
54Prints out the help screen.
53.SH "REMARKS" 55.SH "REMARKS"
54.LP 56.LP
55By default only values of core zero are displayed. How to display settings of 57By default only values of core zero are displayed. How to display settings of
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1
index 3eacc8d03d1..685f469093a 100644
--- a/tools/power/cpupower/man/cpupower-frequency-set.1
+++ b/tools/power/cpupower/man/cpupower-frequency-set.1
@@ -1,4 +1,4 @@
1.TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual" 1.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" ""
2.SH "NAME" 2.SH "NAME"
3.LP 3.LP
4cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. 4cpupower frequency\-set \- A small tool which allows to modify cpufreq settings.
@@ -26,6 +26,8 @@ specific frequency to be set. Requires userspace governor to be available and lo
26\fB\-r\fR \fB\-\-related\fR 26\fB\-r\fR \fB\-\-related\fR
27modify all hardware-related CPUs at the same time 27modify all hardware-related CPUs at the same time
28.TP 28.TP
29\fB\-h\fR \fB\-\-help\fR
30Prints out the help screen.
29.SH "REMARKS" 31.SH "REMARKS"
30.LP 32.LP
31By default values are applied on all cores. How to modify single core 33By default values are applied on all cores. How to modify single core
diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1
deleted file mode 100644
index 4178effd9e9..00000000000
--- a/tools/power/cpupower/man/cpupower-idle-info.1
+++ /dev/null
@@ -1,90 +0,0 @@
1.TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual"
2.SH "NAME"
3.LP
4cpupower idle\-info \- Utility to retrieve cpu idle kernel information
5.SH "SYNTAX"
6.LP
7cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP]
8.SH "DESCRIPTION"
9.LP
10A tool which prints out per cpu idle information helpful to developers and interested users.
11.SH "OPTIONS"
12.LP
13.TP
14\fB\-f\fR \fB\-\-silent\fR
15Only print a summary of all available C-states in the system.
16.TP
17\fB\-e\fR \fB\-\-proc\fR
18deprecated.
19Prints out idle information in old /proc/acpi/processor/*/power format. This
20interface has been removed from the kernel for quite some time, do not let
21further code depend on this option, best do not use it.
22
23.SH IDLE\-INFO DESCRIPTIONS
24CPU sleep state statistics and descriptions are retrieved from sysfs files,
25exported by the cpuidle kernel subsystem. The kernel only updates these
26statistics when it enters or leaves an idle state, therefore on a very idle or
27a very busy system, these statistics may not be accurate. They still provide a
28good overview about the usage and availability of processor sleep states on
29the platform.
30
31Be aware that the sleep states as exported by the hardware or BIOS and used by
32the Linux kernel may not exactly reflect the capabilities of the
33processor. This often is the case on the X86 architecture when the acpi_idle
34driver is used. It is also possible that the hardware overrules the kernel
35requests, due to internal activity monitors or other reasons.
36On recent X86 platforms it is often possible to read out hardware registers
37which monitor the duration of sleep states the processor resided in. The
38cpupower monitor tool (cpupower\-monitor(1)) can be used to show real sleep
39state residencies. Please refer to the architecture specific description
40section below.
41
42.SH IDLE\-INFO ARCHITECTURE SPECIFIC DESCRIPTIONS
43.SS "X86"
44POLL idle state
45
46If cpuidle is active, X86 platforms have one special idle state.
47The POLL idle state is not a real idle state, it does not save any
48power. Instead, a busy\-loop is executed doing nothing for a short period of
49time. This state is used if the kernel knows that work has to be processed
50very soon and entering any real hardware idle state may result in a slight
51performance penalty.
52
53There exist two different cpuidle drivers on the X86 architecture platform:
54
55"acpi_idle" cpuidle driver
56
57The acpi_idle cpuidle driver retrieves available sleep states (C\-states) from
58the ACPI BIOS tables (from the _CST ACPI function on recent platforms or from
59the FADT BIOS table on older ones).
60The C1 state is not retrieved from ACPI tables. If the C1 state is entered,
61the kernel will call the hlt instruction (or mwait on Intel).
62
63"intel_idle" cpuidle driver
64
65In kernel 2.6.36 the intel_idle driver was introduced.
66It only serves recent Intel CPUs (Nehalem, Westmere, Sandybridge, Atoms or
67newer). On older Intel CPUs the acpi_idle driver is still used (if the BIOS
68provides C\-state ACPI tables).
69The intel_idle driver knows the sleep state capabilities of the processor and
70ignores ACPI BIOS exported processor sleep states tables.
71
72.SH "REMARKS"
73.LP
74By default only values of core zero are displayed. How to display settings of
75other cores is described in the cpupower(1) manpage in the \-\-cpu option
76section.
77.SH REFERENCES
78http://www.acpi.info/spec.htm
79.SH "FILES"
80.nf
81\fI/sys/devices/system/cpu/cpu*/cpuidle/state*\fP
82\fI/sys/devices/system/cpu/cpuidle/*\fP
83.fi
84.SH "AUTHORS"
85.nf
86Thomas Renninger <trenn@suse.de>
87.fi
88.SH "SEE ALSO"
89.LP
90cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1)
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
index e01c35d13b6..d5cfa265c3d 100644
--- a/tools/power/cpupower/man/cpupower-monitor.1
+++ b/tools/power/cpupower/man/cpupower-monitor.1
@@ -7,11 +7,11 @@ cpupower\-monitor \- Report processor frequency and idle statistics
7.RB "\-l" 7.RB "\-l"
8 8
9.B cpupower monitor 9.B cpupower monitor
10.RB [ -c ] [ "\-m <mon1>," [ "<mon2>,..." ] ] 10.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
11.RB [ "\-i seconds" ] 11.RB [ "\-i seconds" ]
12.br 12.br
13.B cpupower monitor 13.B cpupower monitor
14.RB [ -c ][ "\-m <mon1>," [ "<mon2>,..." ] ] 14.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
15.RB command 15.RB command
16.br 16.br
17.SH DESCRIPTION 17.SH DESCRIPTION
@@ -64,17 +64,6 @@ Only display specific monitors. Use the monitor string(s) provided by \-l option
64Measure intervall. 64Measure intervall.
65.RE 65.RE
66.PP 66.PP
67\-c
68.RS 4
69Schedule the process on every core before starting and ending measuring.
70This could be needed for the Idle_Stats monitor when no other MSR based
71monitor (has to be run on the core that is measured) is run in parallel.
72This is to wake up the processors from deeper sleep states and let the
73kernel re
74-account its cpuidle (C-state) information before reading the
75cpuidle timings from sysfs.
76.RE
77.PP
78command 67command
79.RS 4 68.RS 4
80Measure idle and frequency characteristics of an arbitrary command/workload. 69Measure idle and frequency characteristics of an arbitrary command/workload.
@@ -118,7 +107,7 @@ Deepest package sleep states may in reality show up as machine/platform wide
118sleep states and can only be entered if all cores are idle. Look up Intel 107sleep states and can only be entered if all cores are idle. Look up Intel
119manuals (some are provided in the References section) for further details. 108manuals (some are provided in the References section) for further details.
120 109
121.SS "Fam_12h" "Fam_14h" 110.SS "Ontario" "Liano"
122AMD laptop and desktop processor (family 12h and 14h) sleep state counters. 111AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
123The registers are accessed via PCI and therefore can still be read out while 112The registers are accessed via PCI and therefore can still be read out while
124cores have been offlined. 113cores have been offlined.
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1
index 9dbd536518a..c4954a9fe4e 100644
--- a/tools/power/cpupower/man/cpupower-set.1
+++ b/tools/power/cpupower/man/cpupower-set.1
@@ -85,6 +85,15 @@ Possible values are:
85savings 85savings
86.RE 86.RE
87 87
88sched_mc_power_savings is dependent upon SCHED_MC, which is
89itself architecture dependent.
90
91sched_smt_power_savings is dependent upon SCHED_SMT, which
92is itself architecture dependent.
93
94The two files are independent of each other. It is possible
95that one file may be present without the other.
96
88.SH "SEE ALSO" 97.SH "SEE ALSO"
89cpupower-info(1), cpupower-monitor(1), powertop(1) 98cpupower-info(1), cpupower-monitor(1), powertop(1)
90.PP 99.PP
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 8145af5f93a..b028267c137 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -35,9 +35,17 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
35 printf(_("CPU %u: Can't read idle state info\n"), cpu); 35 printf(_("CPU %u: Can't read idle state info\n"), cpu);
36 return; 36 return;
37 } 37 }
38 tmp = sysfs_get_idlestate_name(cpu, idlestates - 1);
39 if (!tmp) {
40 printf(_("Could not determine max idle state %u\n"),
41 idlestates - 1);
42 return;
43 }
44
38 printf(_("Number of idle states: %d\n"), idlestates); 45 printf(_("Number of idle states: %d\n"), idlestates);
46
39 printf(_("Available idle states:")); 47 printf(_("Available idle states:"));
40 for (idlestate = 0; idlestate < idlestates; idlestate++) { 48 for (idlestate = 1; idlestate < idlestates; idlestate++) {
41 tmp = sysfs_get_idlestate_name(cpu, idlestate); 49 tmp = sysfs_get_idlestate_name(cpu, idlestate);
42 if (!tmp) 50 if (!tmp)
43 continue; 51 continue;
@@ -49,7 +57,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
49 if (!verbose) 57 if (!verbose)
50 return; 58 return;
51 59
52 for (idlestate = 0; idlestate < idlestates; idlestate++) { 60 for (idlestate = 1; idlestate < idlestates; idlestate++) {
53 tmp = sysfs_get_idlestate_name(cpu, idlestate); 61 tmp = sysfs_get_idlestate_name(cpu, idlestate);
54 if (!tmp) 62 if (!tmp)
55 continue; 63 continue;
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
index 6437ef39aee..87d5605bdda 100644
--- a/tools/power/cpupower/utils/helpers/amd.c
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -112,12 +112,14 @@ int decode_pstates(unsigned int cpu, unsigned int cpu_family,
112int amd_pci_get_num_boost_states(int *active, int *states) 112int amd_pci_get_num_boost_states(int *active, int *states)
113{ 113{
114 struct pci_access *pci_acc; 114 struct pci_access *pci_acc;
115 int vendor_id = 0x1022;
116 int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0};
115 struct pci_dev *device; 117 struct pci_dev *device;
116 uint8_t val = 0; 118 uint8_t val = 0;
117 119
118 *active = *states = 0; 120 *active = *states = 0;
119 121
120 device = pci_slot_func_init(&pci_acc, 0x18, 4); 122 device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids);
121 123
122 if (device == NULL) 124 if (device == NULL)
123 return -ENODEV; 125 return -ENODEV;
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
index 93b0aa74ca0..906895d21cc 100644
--- a/tools/power/cpupower/utils/helpers/cpuid.c
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -158,8 +158,6 @@ out:
158 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; 158 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
159 case 0x2A: /* SNB */ 159 case 0x2A: /* SNB */
160 case 0x2D: /* SNB Xeon */ 160 case 0x2D: /* SNB Xeon */
161 case 0x3A: /* IVB */
162 case 0x3E: /* IVB Xeon */
163 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; 161 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
164 cpu_info->caps |= CPUPOWER_CAP_IS_SNB; 162 cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
165 break; 163 break;
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index aa9e95486a2..2747e738efb 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -66,8 +66,8 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
66#define CPUPOWER_CAP_AMD_CBP 0x00000004 66#define CPUPOWER_CAP_AMD_CBP 0x00000004
67#define CPUPOWER_CAP_PERF_BIAS 0x00000008 67#define CPUPOWER_CAP_PERF_BIAS 0x00000008
68#define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010 68#define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010
69#define CPUPOWER_CAP_IS_SNB 0x00000020 69#define CPUPOWER_CAP_IS_SNB 0x00000011
70#define CPUPOWER_CAP_INTEL_IDA 0x00000040 70#define CPUPOWER_CAP_INTEL_IDA 0x00000012
71 71
72#define MAX_HW_PSTATES 10 72#define MAX_HW_PSTATES 10
73 73
@@ -92,14 +92,6 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
92extern struct cpupower_cpu_info cpupower_cpu_info; 92extern struct cpupower_cpu_info cpupower_cpu_info;
93/* cpuid and cpuinfo helpers **************************/ 93/* cpuid and cpuinfo helpers **************************/
94 94
95struct cpuid_core_info {
96 int pkg;
97 int core;
98 int cpu;
99
100 /* flags */
101 unsigned int is_online:1;
102};
103 95
104/* CPU topology/hierarchy parsing ******************/ 96/* CPU topology/hierarchy parsing ******************/
105struct cpupower_topology { 97struct cpupower_topology {
@@ -109,12 +101,18 @@ struct cpupower_topology {
109 unsigned int threads; /* per core */ 101 unsigned int threads; /* per core */
110 102
111 /* Array gets mallocated with cores entries, holding per core info */ 103 /* Array gets mallocated with cores entries, holding per core info */
112 struct cpuid_core_info *core_info; 104 struct {
105 int pkg;
106 int core;
107 int cpu;
108
109 /* flags */
110 unsigned int is_online:1;
111 } *core_info;
113}; 112};
114 113
115extern int get_cpu_topology(struct cpupower_topology *cpu_top); 114extern int get_cpu_topology(struct cpupower_topology *cpu_top);
116extern void cpu_topology_release(struct cpupower_topology cpu_top); 115extern void cpu_topology_release(struct cpupower_topology cpu_top);
117
118/* CPU topology/hierarchy parsing ******************/ 116/* CPU topology/hierarchy parsing ******************/
119 117
120/* X86 ONLY ****************************************/ 118/* X86 ONLY ****************************************/
@@ -134,11 +132,8 @@ extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu);
134 132
135/* PCI stuff ****************************/ 133/* PCI stuff ****************************/
136extern int amd_pci_get_num_boost_states(int *active, int *states); 134extern int amd_pci_get_num_boost_states(int *active, int *states);
137extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, 135extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
138 int bus, int slot, int func, int vendor, 136 int *dev_ids);
139 int dev);
140extern struct pci_dev *pci_slot_func_init(struct pci_access **pacc,
141 int slot, int func);
142 137
143/* PCI stuff ****************************/ 138/* PCI stuff ****************************/
144 139
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c
index 9690798e644..cd2eb6fe41c 100644
--- a/tools/power/cpupower/utils/helpers/pci.c
+++ b/tools/power/cpupower/utils/helpers/pci.c
@@ -10,24 +10,19 @@
10 * **pacc : if a valid pci_dev is returned 10 * **pacc : if a valid pci_dev is returned
11 * *pacc must be passed to pci_acc_cleanup to free it 11 * *pacc must be passed to pci_acc_cleanup to free it
12 * 12 *
13 * domain: domain 13 * vendor_id : the pci vendor id matching the pci device to access
14 * bus: bus 14 * dev_ids : device ids matching the pci device to access
15 * slot: slot
16 * func: func
17 * vendor: vendor
18 * device: device
19 * Pass -1 for one of the six above to match any
20 * 15 *
21 * Returns : 16 * Returns :
22 * struct pci_dev which can be used with pci_{read,write}_* functions 17 * struct pci_dev which can be used with pci_{read,write}_* functions
23 * to access the PCI config space of matching pci devices 18 * to access the PCI config space of matching pci devices
24 */ 19 */
25struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, int bus, 20struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
26 int slot, int func, int vendor, int dev) 21 int *dev_ids)
27{ 22{
28 struct pci_filter filter_nb_link = { domain, bus, slot, func, 23 struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0};
29 vendor, dev };
30 struct pci_dev *device; 24 struct pci_dev *device;
25 unsigned int i;
31 26
32 *pacc = pci_alloc(); 27 *pacc = pci_alloc();
33 if (*pacc == NULL) 28 if (*pacc == NULL)
@@ -36,20 +31,14 @@ struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, int bus,
36 pci_init(*pacc); 31 pci_init(*pacc);
37 pci_scan_bus(*pacc); 32 pci_scan_bus(*pacc);
38 33
39 for (device = (*pacc)->devices; device; device = device->next) { 34 for (i = 0; dev_ids[i] != 0; i++) {
40 if (pci_filter_match(&filter_nb_link, device)) 35 filter_nb_link.device = dev_ids[i];
41 return device; 36 for (device = (*pacc)->devices; device; device = device->next) {
37 if (pci_filter_match(&filter_nb_link, device))
38 return device;
39 }
42 } 40 }
43 pci_cleanup(*pacc); 41 pci_cleanup(*pacc);
44 return NULL; 42 return NULL;
45} 43}
46
47/* Typically one wants to get a specific slot(device)/func of the root domain
48 and bus */
49struct pci_dev *pci_slot_func_init(struct pci_access **pacc, int slot,
50 int func)
51{
52 return pci_acc_init(pacc, 0, 0, slot, func, -1, -1);
53}
54
55#endif /* defined(__i386__) || defined(__x86_64__) */ 44#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 38ab9162946..c6343024a61 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -37,6 +37,25 @@ unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
37 return (unsigned int) numread; 37 return (unsigned int) numread;
38} 38}
39 39
40static unsigned int sysfs_write_file(const char *path,
41 const char *value, size_t len)
42{
43 int fd;
44 ssize_t numwrite;
45
46 fd = open(path, O_WRONLY);
47 if (fd == -1)
48 return 0;
49
50 numwrite = write(fd, value, len);
51 if (numwrite < 1) {
52 close(fd);
53 return 0;
54 }
55 close(fd);
56 return (unsigned int) numwrite;
57}
58
40/* 59/*
41 * Detect whether a CPU is online 60 * Detect whether a CPU is online
42 * 61 *
@@ -343,7 +362,22 @@ char *sysfs_get_cpuidle_driver(void)
343 */ 362 */
344int sysfs_get_sched(const char *smt_mc) 363int sysfs_get_sched(const char *smt_mc)
345{ 364{
346 return -ENODEV; 365 unsigned long value;
366 char linebuf[MAX_LINE_LEN];
367 char *endp;
368 char path[SYSFS_PATH_MAX];
369
370 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
371 return -EINVAL;
372
373 snprintf(path, sizeof(path),
374 PATH_TO_CPU "sched_%s_power_savings", smt_mc);
375 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
376 return -1;
377 value = strtoul(linebuf, &endp, 0);
378 if (endp == linebuf || errno == ERANGE)
379 return -1;
380 return value;
347} 381}
348 382
349/* 383/*
@@ -354,5 +388,21 @@ int sysfs_get_sched(const char *smt_mc)
354 */ 388 */
355int sysfs_set_sched(const char *smt_mc, int val) 389int sysfs_set_sched(const char *smt_mc, int val)
356{ 390{
357 return -ENODEV; 391 char linebuf[MAX_LINE_LEN];
392 char path[SYSFS_PATH_MAX];
393 struct stat statbuf;
394
395 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
396 return -EINVAL;
397
398 snprintf(path, sizeof(path),
399 PATH_TO_CPU "sched_%s_power_savings", smt_mc);
400 sprintf(linebuf, "%d", val);
401
402 if (stat(path, &statbuf) != 0)
403 return -ENODEV;
404
405 if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)
406 return -1;
407 return 0;
358} 408}
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index c13120af519..4eae2c47ba4 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -20,8 +20,9 @@
20#include <helpers/sysfs.h> 20#include <helpers/sysfs.h>
21 21
22/* returns -1 on failure, 0 on success */ 22/* returns -1 on failure, 0 on success */
23static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) 23int sysfs_topology_read_file(unsigned int cpu, const char *fname)
24{ 24{
25 unsigned long value;
25 char linebuf[MAX_LINE_LEN]; 26 char linebuf[MAX_LINE_LEN];
26 char *endp; 27 char *endp;
27 char path[SYSFS_PATH_MAX]; 28 char path[SYSFS_PATH_MAX];
@@ -30,12 +31,20 @@ static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *re
30 cpu, fname); 31 cpu, fname);
31 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) 32 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
32 return -1; 33 return -1;
33 *result = strtol(linebuf, &endp, 0); 34 value = strtoul(linebuf, &endp, 0);
34 if (endp == linebuf || errno == ERANGE) 35 if (endp == linebuf || errno == ERANGE)
35 return -1; 36 return -1;
36 return 0; 37 return value;
37} 38}
38 39
40struct cpuid_core_info {
41 unsigned int pkg;
42 unsigned int thread;
43 unsigned int cpu;
44 /* flags */
45 unsigned int is_online:1;
46};
47
39static int __compare(const void *t1, const void *t2) 48static int __compare(const void *t1, const void *t2)
40{ 49{
41 struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; 50 struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
@@ -44,9 +53,9 @@ static int __compare(const void *t1, const void *t2)
44 return -1; 53 return -1;
45 else if (top1->pkg > top2->pkg) 54 else if (top1->pkg > top2->pkg)
46 return 1; 55 return 1;
47 else if (top1->core < top2->core) 56 else if (top1->thread < top2->thread)
48 return -1; 57 return -1;
49 else if (top1->core > top2->core) 58 else if (top1->thread > top2->thread)
50 return 1; 59 return 1;
51 else if (top1->cpu < top2->cpu) 60 else if (top1->cpu < top2->cpu)
52 return -1; 61 return -1;
@@ -64,42 +73,28 @@ static int __compare(const void *t1, const void *t2)
64 */ 73 */
65int get_cpu_topology(struct cpupower_topology *cpu_top) 74int get_cpu_topology(struct cpupower_topology *cpu_top)
66{ 75{
67 int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); 76 int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF);
68 77
69 cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); 78 cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus);
70 if (cpu_top->core_info == NULL) 79 if (cpu_top->core_info == NULL)
71 return -ENOMEM; 80 return -ENOMEM;
72 cpu_top->pkgs = cpu_top->cores = 0; 81 cpu_top->pkgs = cpu_top->cores = 0;
73 for (cpu = 0; cpu < cpus; cpu++) { 82 for (cpu = 0; cpu < cpus; cpu++) {
74 cpu_top->core_info[cpu].cpu = cpu; 83 cpu_top->core_info[cpu].cpu = cpu;
75 cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); 84 cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
76 if(sysfs_topology_read_file( 85 cpu_top->core_info[cpu].pkg =
77 cpu, 86 sysfs_topology_read_file(cpu, "physical_package_id");
78 "physical_package_id", 87 if ((int)cpu_top->core_info[cpu].pkg != -1 &&
79 &(cpu_top->core_info[cpu].pkg)) < 0) 88 cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
80 return -1; 89 cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
81 if(sysfs_topology_read_file( 90 cpu_top->core_info[cpu].core =
82 cpu, 91 sysfs_topology_read_file(cpu, "core_id");
83 "core_id",
84 &(cpu_top->core_info[cpu].core)) < 0)
85 return -1;
86 } 92 }
93 cpu_top->pkgs++;
87 94
88 qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), 95 qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
89 __compare); 96 __compare);
90 97
91 /* Count the number of distinct pkgs values. This works
92 because the primary sort of the core_info struct was just
93 done by pkg value. */
94 last_pkg = cpu_top->core_info[0].pkg;
95 for(cpu = 1; cpu < cpus; cpu++) {
96 if(cpu_top->core_info[cpu].pkg != last_pkg) {
97 last_pkg = cpu_top->core_info[cpu].pkg;
98 cpu_top->pkgs++;
99 }
100 }
101 cpu_top->pkgs++;
102
103 /* Intel's cores count is not consecutively numbered, there may 98 /* Intel's cores count is not consecutively numbered, there may
104 * be a core_id of 3, but none of 2. Assume there always is 0 99 * be a core_id of 3, but none of 2. Assume there always is 0
105 * Get amount of cores by counting duplicates in a package 100 * Get amount of cores by counting duplicates in a package
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
index 2116df9ad83..202e555988b 100644
--- a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
@@ -20,6 +20,8 @@
20#include "idle_monitor/cpupower-monitor.h" 20#include "idle_monitor/cpupower-monitor.h"
21#include "helpers/helpers.h" 21#include "helpers/helpers.h"
22 22
23/******** PCI parts could go into own file and get shared ***************/
24
23#define PCI_NON_PC0_OFFSET 0xb0 25#define PCI_NON_PC0_OFFSET 0xb0
24#define PCI_PC1_OFFSET 0xb4 26#define PCI_PC1_OFFSET 0xb4
25#define PCI_PC6_OFFSET 0xb8 27#define PCI_PC6_OFFSET 0xb8
@@ -80,7 +82,10 @@ static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = {
80}; 82};
81 83
82static struct pci_access *pci_acc; 84static struct pci_access *pci_acc;
85static int pci_vendor_id = 0x1022;
86static int pci_dev_ids[2] = {0x1716, 0};
83static struct pci_dev *amd_fam14h_pci_dev; 87static struct pci_dev *amd_fam14h_pci_dev;
88
84static int nbp1_entered; 89static int nbp1_entered;
85 90
86struct timespec start_time; 91struct timespec start_time;
@@ -281,13 +286,13 @@ struct cpuidle_monitor *amd_fam14h_register(void)
281 if (cpupower_cpu_info.vendor != X86_VENDOR_AMD) 286 if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
282 return NULL; 287 return NULL;
283 288
284 if (cpupower_cpu_info.family == 0x14) 289 if (cpupower_cpu_info.family == 0x14) {
285 strncpy(amd_fam14h_monitor.name, "Fam_14h", 290 if (cpu_count <= 0 || cpu_count > 2) {
286 MONITOR_NAME_LEN - 1); 291 fprintf(stderr, "AMD fam14h: Invalid cpu count: %d\n",
287 else if (cpupower_cpu_info.family == 0x12) 292 cpu_count);
288 strncpy(amd_fam14h_monitor.name, "Fam_12h", 293 return NULL;
289 MONITOR_NAME_LEN - 1); 294 }
290 else 295 } else
291 return NULL; 296 return NULL;
292 297
293 /* We do not alloc for nbp1 machine wide counter */ 298 /* We do not alloc for nbp1 machine wide counter */
@@ -298,9 +303,7 @@ struct cpuidle_monitor *amd_fam14h_register(void)
298 sizeof(unsigned long long)); 303 sizeof(unsigned long long));
299 } 304 }
300 305
301 /* We need PCI device: Slot 18, Func 6, compare with BKDG 306 amd_fam14h_pci_dev = pci_acc_init(&pci_acc, pci_vendor_id, pci_dev_ids);
302 for fam 12h/14h */
303 amd_fam14h_pci_dev = pci_slot_func_init(&pci_acc, 0x18, 6);
304 if (amd_fam14h_pci_dev == NULL || pci_acc == NULL) 307 if (amd_fam14h_pci_dev == NULL || pci_acc == NULL)
305 return NULL; 308 return NULL;
306 309
@@ -322,7 +325,7 @@ static void amd_fam14h_unregister(void)
322} 325}
323 326
324struct cpuidle_monitor amd_fam14h_monitor = { 327struct cpuidle_monitor amd_fam14h_monitor = {
325 .name = "", 328 .name = "Ontario",
326 .hw_states = amd_fam14h_cstates, 329 .hw_states = amd_fam14h_cstates,
327 .hw_states_num = AMD_FAM14H_STATE_NUM, 330 .hw_states_num = AMD_FAM14H_STATE_NUM,
328 .start = amd_fam14h_start, 331 .start = amd_fam14h_start,
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index c4bae9203a6..0d6571e418d 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -39,7 +39,6 @@ static int mode;
39static int interval = 1; 39static int interval = 1;
40static char *show_monitors_param; 40static char *show_monitors_param;
41static struct cpupower_topology cpu_top; 41static struct cpupower_topology cpu_top;
42static unsigned int wake_cpus;
43 42
44/* ToDo: Document this in the manpage */ 43/* ToDo: Document this in the manpage */
45static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; 44static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
@@ -85,7 +84,7 @@ int fill_string_with_spaces(char *s, int n)
85void print_header(int topology_depth) 84void print_header(int topology_depth)
86{ 85{
87 int unsigned mon; 86 int unsigned mon;
88 int state, need_len; 87 int state, need_len, pr_mon_len;
89 cstate_t s; 88 cstate_t s;
90 char buf[128] = ""; 89 char buf[128] = "";
91 int percent_width = 4; 90 int percent_width = 4;
@@ -94,6 +93,7 @@ void print_header(int topology_depth)
94 printf("%s|", buf); 93 printf("%s|", buf);
95 94
96 for (mon = 0; mon < avail_monitors; mon++) { 95 for (mon = 0; mon < avail_monitors; mon++) {
96 pr_mon_len = 0;
97 need_len = monitors[mon]->hw_states_num * (percent_width + 3) 97 need_len = monitors[mon]->hw_states_num * (percent_width + 3)
98 - 1; 98 - 1;
99 if (mon != 0) { 99 if (mon != 0) {
@@ -315,28 +315,16 @@ int fork_it(char **argv)
315int do_interval_measure(int i) 315int do_interval_measure(int i)
316{ 316{
317 unsigned int num; 317 unsigned int num;
318 int cpu;
319
320 if (wake_cpus)
321 for (cpu = 0; cpu < cpu_count; cpu++)
322 bind_cpu(cpu);
323 318
324 for (num = 0; num < avail_monitors; num++) { 319 for (num = 0; num < avail_monitors; num++) {
325 dprint("HW C-state residency monitor: %s - States: %d\n", 320 dprint("HW C-state residency monitor: %s - States: %d\n",
326 monitors[num]->name, monitors[num]->hw_states_num); 321 monitors[num]->name, monitors[num]->hw_states_num);
327 monitors[num]->start(); 322 monitors[num]->start();
328 } 323 }
329
330 sleep(i); 324 sleep(i);
331
332 if (wake_cpus)
333 for (cpu = 0; cpu < cpu_count; cpu++)
334 bind_cpu(cpu);
335
336 for (num = 0; num < avail_monitors; num++) 325 for (num = 0; num < avail_monitors; num++)
337 monitors[num]->stop(); 326 monitors[num]->stop();
338 327
339
340 return 0; 328 return 0;
341} 329}
342 330
@@ -345,7 +333,7 @@ static void cmdline(int argc, char *argv[])
345 int opt; 333 int opt;
346 progname = basename(argv[0]); 334 progname = basename(argv[0]);
347 335
348 while ((opt = getopt(argc, argv, "+lci:m:")) != -1) { 336 while ((opt = getopt(argc, argv, "+li:m:")) != -1) {
349 switch (opt) { 337 switch (opt) {
350 case 'l': 338 case 'l':
351 if (mode) 339 if (mode)
@@ -364,9 +352,6 @@ static void cmdline(int argc, char *argv[])
364 mode = show; 352 mode = show;
365 show_monitors_param = optarg; 353 show_monitors_param = optarg;
366 break; 354 break;
367 case 'c':
368 wake_cpus = 1;
369 break;
370 default: 355 default:
371 print_wrong_arg_exit(); 356 print_wrong_arg_exit();
372 } 357 }
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
index 9e43f3371fb..9312ee1f2db 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
@@ -65,21 +65,4 @@ extern long long timespec_diff_us(struct timespec start, struct timespec end);
65 "could be inaccurate\n"), mes, ov); \ 65 "could be inaccurate\n"), mes, ov); \
66} 66}
67 67
68
69/* Taken over from x86info project sources -> return 0 on success */
70#include <sched.h>
71#include <sys/types.h>
72#include <unistd.h>
73static inline int bind_cpu(int cpu)
74{
75 cpu_set_t set;
76
77 if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
78 CPU_ZERO(&set);
79 CPU_SET(cpu, &set);
80 return sched_setaffinity(getpid(), sizeof(set), &set);
81 }
82 return 1;
83}
84
85#endif /* __CPUIDLE_INFO_HW__ */ 68#endif /* __CPUIDLE_INFO_HW__ */
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
index a99b43b97d6..a1bc07cd53e 100644
--- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
@@ -150,15 +150,9 @@ static struct cpuidle_monitor *snb_register(void)
150 || cpupower_cpu_info.family != 6) 150 || cpupower_cpu_info.family != 6)
151 return NULL; 151 return NULL;
152 152
153 switch (cpupower_cpu_info.model) { 153 if (cpupower_cpu_info.model != 0x2A
154 case 0x2A: /* SNB */ 154 && cpupower_cpu_info.model != 0x2D)
155 case 0x2D: /* SNB Xeon */
156 case 0x3A: /* IVB */
157 case 0x3E: /* IVB Xeon */
158 break;
159 default:
160 return NULL; 155 return NULL;
161 }
162 156
163 is_valid = calloc(cpu_count, sizeof(int)); 157 is_valid = calloc(cpu_count, sizeof(int));
164 for (num = 0; num < SNB_CSTATE_COUNT; num++) { 158 for (num = 0; num < SNB_CSTATE_COUNT; num++) {
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
index f09641da40d..fd8e1f1297a 100644
--- a/tools/power/x86/turbostat/Makefile
+++ b/tools/power/x86/turbostat/Makefile
@@ -1,22 +1,8 @@
1CC = $(CROSS_COMPILE)gcc
2BUILD_OUTPUT := $(PWD)
3PREFIX := /usr
4DESTDIR :=
5
6turbostat : turbostat.c 1turbostat : turbostat.c
7CFLAGS += -Wall
8CFLAGS += -I../../../../arch/x86/include/uapi/
9
10%: %.c
11 @mkdir -p $(BUILD_OUTPUT)
12 $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
13 2
14.PHONY : clean
15clean : 3clean :
16 @rm -f $(BUILD_OUTPUT)/turbostat 4 rm -f turbostat
17 5
18install : turbostat 6install :
19 install -d $(DESTDIR)$(PREFIX)/bin 7 install turbostat /usr/bin/turbostat
20 install $(BUILD_OUTPUT)/turbostat $(DESTDIR)$(PREFIX)/bin/turbostat 8 install turbostat.8 /usr/share/man/man8
21 install -d $(DESTDIR)$(PREFIX)/share/man/man8
22 install turbostat.8 $(DESTDIR)$(PREFIX)/share/man/man8
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index 0d7dc2cfefb..ff75125deed 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -4,42 +4,31 @@ turbostat \- Report processor frequency and idle statistics
4.SH SYNOPSIS 4.SH SYNOPSIS
5.ft B 5.ft B
6.B turbostat 6.B turbostat
7.RB [ Options ] 7.RB [ "\-v" ]
8.RB [ "\-M MSR#" ]
8.RB command 9.RB command
9.br 10.br
10.B turbostat 11.B turbostat
11.RB [ Options ] 12.RB [ "\-v" ]
13.RB [ "\-M MSR#" ]
12.RB [ "\-i interval_sec" ] 14.RB [ "\-i interval_sec" ]
13.SH DESCRIPTION 15.SH DESCRIPTION
14\fBturbostat \fP reports processor topology, frequency, 16\fBturbostat \fP reports processor topology, frequency
15idle power-state statistics, temperature and power on modern X86 processors. 17and idle power state statistics on modern X86 processors.
16Either \fBcommand\fP is forked and statistics are printed 18Either \fBcommand\fP is forked and statistics are printed
17upon its completion, or statistics are printed periodically. 19upon its completion, or statistics are printed periodically.
18 20
19\fBturbostat \fP 21\fBturbostat \fP
20must be run on root, and 22requires that the processor
21minimally requires that the processor
22supports an "invariant" TSC, plus the APERF and MPERF MSRs. 23supports an "invariant" TSC, plus the APERF and MPERF MSRs.
23Additional information is reported depending on hardware counter support. 24\fBturbostat \fP will report idle cpu power state residency
25on processors that additionally support C-state residency counters.
24 26
25.SS Options 27.SS Options
26The \fB-p\fP option limits output to the 1st thread in 1st core of each package.
27.PP
28The \fB-P\fP option limits output to the 1st thread in each Package.
29.PP
30The \fB-S\fP option limits output to a 1-line System Summary for each interval.
31.PP
32The \fB-v\fP option increases verbosity. 28The \fB-v\fP option increases verbosity.
33.PP 29.PP
34The \fB-s\fP option prints the SMI counter, equivalent to "-c 0x34" 30The \fB-M MSR#\fP option dumps the specified MSR,
35.PP 31in addition to the usual frequency and idle statistics.
36The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter.
37.PP
38The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter.
39.PP
40The \fB-m MSR#\fP option includes the the specified 32-bit MSR value.
41.PP
42The \fB-M MSR#\fP option includes the the specified 64-bit MSR value.
43.PP 32.PP
44The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. 33The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
45The default is 5 seconds. 34The default is 5 seconds.
@@ -49,23 +38,14 @@ displays the statistics gathered since it was forked.
49.PP 38.PP
50.SH FIELD DESCRIPTIONS 39.SH FIELD DESCRIPTIONS
51.nf 40.nf
52\fBpk\fP processor package number. 41\fBpkg\fP processor package number.
53\fBcor\fP processor core number. 42\fBcore\fP processor core number.
54\fBCPU\fP Linux CPU (logical processor) number. 43\fBCPU\fP Linux CPU (logical processor) number.
55Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading Technology.
56\fB%c0\fP percent of the interval that the CPU retired instructions. 44\fB%c0\fP percent of the interval that the CPU retired instructions.
57\fBGHz\fP average clock rate while the CPU was in c0 state. 45\fBGHz\fP average clock rate while the CPU was in c0 state.
58\fBTSC\fP average GHz that the TSC ran during the entire interval. 46\fBTSC\fP average GHz that the TSC ran during the entire interval.
59\fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states. 47\fB%c1, %c3, %c6\fP show the percentage residency in hardware core idle states.
60\fBCTMP\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. 48\fB%pc3, %pc6\fP percentage residency in hardware package idle states.
61\fBPTMP\fP Degrees Celsius reported by the per-package Package Thermal Monitor.
62\fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states.
63\fBPkg_W\fP Watts consumed by the whole package.
64\fBCor_W\fP Watts consumed by the core part of the package.
65\fBGFX_W\fP Watts consumed by the Graphics part of the package -- available only on client processors.
66\fBRAM_W\fP Watts consumed by the DRAM DIMMS -- available only on server processors.
67\fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package.
68\fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM.
69.fi 49.fi
70.PP 50.PP
71.SH EXAMPLE 51.SH EXAMPLE
@@ -73,74 +53,38 @@ Without any parameters, turbostat prints out counters ever 5 seconds.
73(override interval with "-i sec" option, or specify a command 53(override interval with "-i sec" option, or specify a command
74for turbostat to fork). 54for turbostat to fork).
75 55
76The first row of statistics is a summary for the entire system. 56The first row of statistics reflect the average for the entire system.
77For residency % columns, the summary is a weighted average.
78For Temperature columns, the summary is the column maximum.
79For Watts columns, the summary is a system total.
80Subsequent rows show per-CPU statistics. 57Subsequent rows show per-CPU statistics.
81 58
82.nf 59.nf
83[root@sandy]# ./turbostat 60[root@x980]# ./turbostat
84cor CPU %c0 GHz TSC %c1 %c3 %c6 %c7 CTMP PTMP %pc2 %pc3 %pc6 %pc7 Pkg_W Cor_W GFX_W 61core CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
85 0.06 0.80 2.29 0.11 0.00 0.00 99.83 47 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14 62 0.04 1.62 3.38 0.11 0.00 99.85 0.00 95.07
86 0 0 0.07 0.80 2.29 0.07 0.00 0.00 99.86 40 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14 63 0 0 0.04 1.62 3.38 0.06 0.00 99.90 0.00 95.07
87 0 4 0.03 0.80 2.29 0.12 64 0 6 0.02 1.62 3.38 0.08 0.00 99.90 0.00 95.07
88 1 1 0.04 0.80 2.29 0.25 0.01 0.00 99.71 40 65 1 2 0.10 1.62 3.38 0.29 0.00 99.61 0.00 95.07
89 1 5 0.16 0.80 2.29 0.13 66 1 8 0.11 1.62 3.38 0.28 0.00 99.61 0.00 95.07
90 2 2 0.05 0.80 2.29 0.06 0.01 0.00 99.88 40 67 2 4 0.01 1.62 3.38 0.01 0.00 99.98 0.00 95.07
91 2 6 0.03 0.80 2.29 0.08 68 2 10 0.01 1.61 3.38 0.02 0.00 99.98 0.00 95.07
92 3 3 0.05 0.80 2.29 0.08 0.00 0.00 99.87 47 69 8 1 0.07 1.62 3.38 0.15 0.00 99.78 0.00 95.07
93 3 7 0.04 0.84 2.29 0.09 70 8 7 0.03 1.62 3.38 0.19 0.00 99.78 0.00 95.07
94.fi 71 9 3 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07
95.SH SUMMARY EXAMPLE 72 9 9 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07
96The "-s" option prints the column headers just once, 73 10 5 0.01 1.62 3.38 0.13 0.00 99.86 0.00 95.07
97and then the one line system summary for each sample interval. 74 10 11 0.08 1.62 3.38 0.05 0.00 99.86 0.00 95.07
98
99.nf
100[root@wsm]# turbostat -S
101 %c0 GHz TSC %c1 %c3 %c6 CTMP %pc3 %pc6
102 1.40 2.81 3.38 10.78 43.47 44.35 42 13.67 2.09
103 1.34 2.90 3.38 11.48 58.96 28.23 41 19.89 0.15
104 1.55 2.72 3.38 26.73 37.66 34.07 42 2.53 2.80
105 1.37 2.83 3.38 16.95 60.05 21.63 42 5.76 0.20
106.fi 75.fi
107.SH VERBOSE EXAMPLE 76.SH VERBOSE EXAMPLE
108The "-v" option adds verbosity to the output: 77The "-v" option adds verbosity to the output:
109 78
110.nf 79.nf
111[root@ivy]# turbostat -v 80GenuineIntel 11 CPUID levels; family:model:stepping 0x6:2c:2 (6:44:2)
112turbostat v3.0 November 23, 2012 - Len Brown <lenb@kernel.org> 8112 * 133 = 1600 MHz max efficiency
113CPUID(0): GenuineIntel 13 CPUID levels; family:model:stepping 0x6:3a:9 (6:58:9) 8225 * 133 = 3333 MHz TSC frequency
114CPUID(6): APERF, DTS, PTM, EPB 8326 * 133 = 3467 MHz max turbo 4 active cores
115RAPL: 851 sec. Joule Counter Range 8426 * 133 = 3467 MHz max turbo 3 active cores
116cpu0: MSR_NHM_PLATFORM_INFO: 0x81010f0012300 8527 * 133 = 3600 MHz max turbo 2 active cores
11716 * 100 = 1600 MHz max efficiency 8627 * 133 = 3600 MHz max turbo 1 active cores
11835 * 100 = 3500 MHz TSC frequency 87
119cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x1e008402 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, locked: pkg-cstate-limit=2: pc6-noret)
120cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x25262727
12137 * 100 = 3700 MHz max turbo 4 active cores
12238 * 100 = 3800 MHz max turbo 3 active cores
12339 * 100 = 3900 MHz max turbo 2 active cores
12439 * 100 = 3900 MHz max turbo 1 active cores
125cpu0: MSR_IA32_ENERGY_PERF_BIAS: 0x00000006 (balanced)
126cpu0: MSR_RAPL_POWER_UNIT: 0x000a1003 (0.125000 Watts, 0.000015 Joules, 0.000977 sec.)
127cpu0: MSR_PKG_POWER_INFO: 0x01e00268 (77 W TDP, RAPL 60 - 0 W, 0.000000 sec.)
128cpu0: MSR_PKG_POWER_LIMIT: 0x830000148268 (UNlocked)
129cpu0: PKG Limit #1: ENabled (77.000000 Watts, 1.000000 sec, clamp DISabled)
130cpu0: PKG Limit #2: ENabled (96.000000 Watts, 0.000977* sec, clamp DISabled)
131cpu0: MSR_PP0_POLICY: 0
132cpu0: MSR_PP0_POWER_LIMIT: 0x00000000 (UNlocked)
133cpu0: Cores Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
134cpu0: MSR_PP1_POLICY: 0
135cpu0: MSR_PP1_POWER_LIMIT: 0x00000000 (UNlocked)
136cpu0: GFX Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
137cpu0: MSR_IA32_TEMPERATURE_TARGET: 0x00691400 (105 C)
138cpu0: MSR_IA32_PACKAGE_THERM_STATUS: 0x884e0000 (27 C)
139cpu0: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1)
140cpu1: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1)
141cpu2: MSR_IA32_THERM_STATUS: 0x88540000 (21 C +/- 1)
142cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1)
143 ...
144.fi 88.fi
145The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency 89The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency
146available at the minimum package voltage. The \fBTSC frequency\fP is the nominal 90available at the minimum package voltage. The \fBTSC frequency\fP is the nominal
@@ -157,56 +101,35 @@ until ^C while the other CPUs are mostly idle:
157 101
158.nf 102.nf
159[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null 103[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null
160^C 104
161cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 105^Ccore CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
162 8.86 3.61 3.38 15.06 31.19 44.89 0.00 0.00 106 8.49 3.63 3.38 16.23 0.66 74.63 0.00 0.00
163 0 0 1.46 3.22 3.38 16.84 29.48 52.22 0.00 0.00 107 0 0 1.22 3.62 3.38 32.18 0.00 66.60 0.00 0.00
164 0 6 0.21 3.06 3.38 18.09 108 0 6 0.40 3.61 3.38 33.00 0.00 66.60 0.00 0.00
165 1 2 0.53 3.33 3.38 2.80 46.40 50.27 109 1 2 0.11 3.14 3.38 0.19 3.95 95.75 0.00 0.00
166 1 8 0.89 3.47 3.38 2.44 110 1 8 0.05 2.88 3.38 0.25 3.95 95.75 0.00 0.00
167 2 4 1.36 3.43 3.38 9.04 23.71 65.89 111 2 4 0.00 3.13 3.38 0.02 0.00 99.98 0.00 0.00
168 2 10 0.18 2.86 3.38 10.22 112 2 10 0.00 3.09 3.38 0.02 0.00 99.98 0.00 0.00
169 8 1 0.04 2.87 3.38 99.96 0.01 0.00 113 8 1 0.04 3.50 3.38 14.43 0.00 85.54 0.00 0.00
170 8 7 99.72 3.63 3.38 0.27 114 8 7 0.03 2.98 3.38 14.43 0.00 85.54 0.00 0.00
171 9 3 0.31 3.21 3.38 7.64 56.55 35.50 115 9 3 0.00 3.16 3.38 100.00 0.00 0.00 0.00 0.00
172 9 9 0.08 2.95 3.38 7.88 116 9 9 99.93 3.63 3.38 0.06 0.00 0.00 0.00 0.00
173 10 5 1.42 3.43 3.38 2.14 30.99 65.44 117 10 5 0.01 2.82 3.38 0.08 0.00 99.91 0.00 0.00
174 10 11 0.16 2.88 3.38 3.40 118 10 11 0.02 3.36 3.38 0.06 0.00 99.91 0.00 0.00
1196.950866 sec
120
175.fi 121.fi
176Above the cycle soaker drives cpu7 up its 3.6 GHz turbo limit 122Above the cycle soaker drives cpu9 up 3.6 Ghz turbo limit
177while the other processors are generally in various states of idle. 123while the other processors are generally in various states of idle.
178 124
179Note that cpu1 and cpu7 are HT siblings within core8. 125Note that cpu3 is an HT sibling sharing core9
180As cpu7 is very busy, it prevents its sibling, cpu1, 126with cpu9, and thus it is unable to get to an idle state
181from entering a c-state deeper than c1. 127deeper than c1 while cpu9 is busy.
182 128
183Note that turbostat reports average GHz of 3.63, while 129Note that turbostat reports average GHz of 3.61, while
184the arithmetic average of the GHz column above is lower. 130the arithmetic average of the GHz column above is 3.24.
185This is a weighted average, where the weight is %c0. ie. it is the total number of 131This is a weighted average, where the weight is %c0. ie. it is the total number of
186un-halted cycles elapsed per time divided by the number of CPUs. 132un-halted cycles elapsed per time divided by the number of CPUs.
187.SH SMI COUNTING EXAMPLE
188On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter.
189Using the -m option, you can display how many SMIs have fired since reset, or if there
190are SMIs during the measurement interval, you can display the delta using the -d option.
191.nf
192[root@x980 ~]# turbostat -m 0x34
193cor CPU %c0 GHz TSC MSR 0x034 %c1 %c3 %c6 %pc3 %pc6
194 1.41 1.82 3.38 0x00000000 8.92 37.82 51.85 17.37 0.55
195 0 0 3.73 2.03 3.38 0x00000055 1.72 48.25 46.31 17.38 0.55
196 0 6 0.14 1.63 3.38 0x00000056 5.30
197 1 2 2.51 1.80 3.38 0x00000056 15.65 29.33 52.52
198 1 8 0.10 1.65 3.38 0x00000056 18.05
199 2 4 1.16 1.68 3.38 0x00000056 5.87 24.47 68.50
200 2 10 0.10 1.63 3.38 0x00000056 6.93
201 8 1 3.84 1.91 3.38 0x00000056 1.36 50.65 44.16
202 8 7 0.08 1.64 3.38 0x00000056 5.12
203 9 3 1.82 1.73 3.38 0x00000056 7.59 24.21 66.38
204 9 9 0.09 1.68 3.38 0x00000056 9.32
205 10 5 1.66 1.65 3.38 0x00000056 15.10 50.00 33.23
206 10 11 1.72 1.65 3.38 0x00000056 15.05
207^C
208[root@x980 ~]#
209.fi
210.SH NOTES 133.SH NOTES
211 134
212.B "turbostat " 135.B "turbostat "
@@ -222,13 +145,6 @@ may work poorly on Linux-2.6.20 through 2.6.29,
222as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF 145as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
223in those kernels. 146in those kernels.
224 147
225If the TSC column does not make sense, then
226the other numbers will also make no sense.
227Turbostat is lightweight, and its data collection is not atomic.
228These issues are usually caused by an extremely short measurement
229interval (much less than 1 second), or system activity that prevents
230turbostat from being able to run on all CPUS to quickly collect data.
231
232The APERF, MPERF MSRs are defined to count non-halted cycles. 148The APERF, MPERF MSRs are defined to count non-halted cycles.
233Although it is not guaranteed by the architecture, turbostat assumes 149Although it is not guaranteed by the architecture, turbostat assumes
234that they count at TSC rate, which is true on all processors tested to date. 150that they count at TSC rate, which is true on all processors tested to date.
@@ -251,6 +167,6 @@ http://www.intel.com/products/processor/manuals/
251.SH "SEE ALSO" 167.SH "SEE ALSO"
252msr(4), vmstat(8) 168msr(4), vmstat(8)
253.PP 169.PP
254.SH AUTHOR 170.SH AUTHORS
255.nf 171.nf
256Written by Len Brown <len.brown@intel.com> 172Written by Len Brown <len.brown@intel.com>
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index ce6d46038f7..8b2d37b59c9 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -2,7 +2,7 @@
2 * turbostat -- show CPU frequency and C-state residency 2 * turbostat -- show CPU frequency and C-state residency
3 * on modern Intel turbo-capable processors. 3 * on modern Intel turbo-capable processors.
4 * 4 *
5 * Copyright (c) 2012 Intel Corporation. 5 * Copyright (c) 2010, Intel Corporation.
6 * Len Brown <len.brown@intel.com> 6 * Len Brown <len.brown@intel.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify it 8 * This program is free software; you can redistribute it and/or modify it
@@ -19,8 +19,6 @@
19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20 */ 20 */
21 21
22#define _GNU_SOURCE
23#include <asm/msr.h>
24#include <stdio.h> 22#include <stdio.h>
25#include <unistd.h> 23#include <unistd.h>
26#include <sys/types.h> 24#include <sys/types.h>
@@ -34,871 +32,440 @@
34#include <dirent.h> 32#include <dirent.h>
35#include <string.h> 33#include <string.h>
36#include <ctype.h> 34#include <ctype.h>
37#include <sched.h> 35
36#define MSR_TSC 0x10
37#define MSR_NEHALEM_PLATFORM_INFO 0xCE
38#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
39#define MSR_APERF 0xE8
40#define MSR_MPERF 0xE7
41#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */
42#define MSR_PKG_C3_RESIDENCY 0x3F8
43#define MSR_PKG_C6_RESIDENCY 0x3F9
44#define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */
45#define MSR_CORE_C3_RESIDENCY 0x3FC
46#define MSR_CORE_C6_RESIDENCY 0x3FD
47#define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */
38 48
39char *proc_stat = "/proc/stat"; 49char *proc_stat = "/proc/stat";
40unsigned int interval_sec = 5; /* set with -i interval_sec */ 50unsigned int interval_sec = 5; /* set with -i interval_sec */
41unsigned int verbose; /* set with -v */ 51unsigned int verbose; /* set with -v */
42unsigned int rapl_verbose; /* set with -R */
43unsigned int thermal_verbose; /* set with -T */
44unsigned int summary_only; /* set with -s */
45unsigned int skip_c0; 52unsigned int skip_c0;
46unsigned int skip_c1; 53unsigned int skip_c1;
47unsigned int do_nhm_cstates; 54unsigned int do_nhm_cstates;
48unsigned int do_snb_cstates; 55unsigned int do_snb_cstates;
49unsigned int has_aperf; 56unsigned int has_aperf;
50unsigned int has_epb;
51unsigned int units = 1000000000; /* Ghz etc */ 57unsigned int units = 1000000000; /* Ghz etc */
52unsigned int genuine_intel; 58unsigned int genuine_intel;
53unsigned int has_invariant_tsc; 59unsigned int has_invariant_tsc;
54unsigned int do_nehalem_platform_info; 60unsigned int do_nehalem_platform_info;
55unsigned int do_nehalem_turbo_ratio_limit; 61unsigned int do_nehalem_turbo_ratio_limit;
56unsigned int do_ivt_turbo_ratio_limit; 62unsigned int extra_msr_offset;
57unsigned int extra_msr_offset32;
58unsigned int extra_msr_offset64;
59unsigned int extra_delta_offset32;
60unsigned int extra_delta_offset64;
61double bclk; 63double bclk;
62unsigned int show_pkg; 64unsigned int show_pkg;
63unsigned int show_core; 65unsigned int show_core;
64unsigned int show_cpu; 66unsigned int show_cpu;
65unsigned int show_pkg_only;
66unsigned int show_core_only;
67char *output_buffer, *outp;
68unsigned int do_rapl;
69unsigned int do_dts;
70unsigned int do_ptm;
71unsigned int tcc_activation_temp;
72unsigned int tcc_activation_temp_override;
73double rapl_power_units, rapl_energy_units, rapl_time_units;
74double rapl_joule_counter_range;
75
76#define RAPL_PKG (1 << 0)
77#define RAPL_CORES (1 << 1)
78#define RAPL_GFX (1 << 2)
79#define RAPL_DRAM (1 << 3)
80#define RAPL_PKG_PERF_STATUS (1 << 4)
81#define RAPL_DRAM_PERF_STATUS (1 << 5)
82#define TJMAX_DEFAULT 100
83
84#define MAX(a, b) ((a) > (b) ? (a) : (b))
85 67
86int aperf_mperf_unstable; 68int aperf_mperf_unstable;
87int backwards_count; 69int backwards_count;
88char *progname; 70char *progname;
89 71int need_reinitialize;
90cpu_set_t *cpu_present_set, *cpu_affinity_set; 72
91size_t cpu_present_setsize, cpu_affinity_setsize; 73int num_cpus;
92 74
93struct thread_data { 75struct counters {
94 unsigned long long tsc; 76 unsigned long long tsc; /* per thread */
95 unsigned long long aperf; 77 unsigned long long aperf; /* per thread */
96 unsigned long long mperf; 78 unsigned long long mperf; /* per thread */
97 unsigned long long c1; /* derived */ 79 unsigned long long c1; /* per thread (calculated) */
98 unsigned long long extra_msr64; 80 unsigned long long c3; /* per core */
99 unsigned long long extra_delta64; 81 unsigned long long c6; /* per core */
100 unsigned long long extra_msr32; 82 unsigned long long c7; /* per core */
101 unsigned long long extra_delta32; 83 unsigned long long pc2; /* per package */
102 unsigned int cpu_id; 84 unsigned long long pc3; /* per package */
103 unsigned int flags; 85 unsigned long long pc6; /* per package */
104#define CPU_IS_FIRST_THREAD_IN_CORE 0x2 86 unsigned long long pc7; /* per package */
105#define CPU_IS_FIRST_CORE_IN_PACKAGE 0x4 87 unsigned long long extra_msr; /* per thread */
106} *thread_even, *thread_odd; 88 int pkg;
107 89 int core;
108struct core_data { 90 int cpu;
109 unsigned long long c3; 91 struct counters *next;
110 unsigned long long c6; 92};
111 unsigned long long c7; 93
112 unsigned int core_temp_c; 94struct counters *cnt_even;
113 unsigned int core_id; 95struct counters *cnt_odd;
114} *core_even, *core_odd; 96struct counters *cnt_delta;
115 97struct counters *cnt_average;
116struct pkg_data { 98struct timeval tv_even;
117 unsigned long long pc2; 99struct timeval tv_odd;
118 unsigned long long pc3; 100struct timeval tv_delta;
119 unsigned long long pc6; 101
120 unsigned long long pc7; 102unsigned long long get_msr(int cpu, off_t offset)
121 unsigned int package_id;
122 unsigned int energy_pkg; /* MSR_PKG_ENERGY_STATUS */
123 unsigned int energy_dram; /* MSR_DRAM_ENERGY_STATUS */
124 unsigned int energy_cores; /* MSR_PP0_ENERGY_STATUS */
125 unsigned int energy_gfx; /* MSR_PP1_ENERGY_STATUS */
126 unsigned int rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */
127 unsigned int rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */
128 unsigned int pkg_temp_c;
129
130} *package_even, *package_odd;
131
132#define ODD_COUNTERS thread_odd, core_odd, package_odd
133#define EVEN_COUNTERS thread_even, core_even, package_even
134
135#define GET_THREAD(thread_base, thread_no, core_no, pkg_no) \
136 (thread_base + (pkg_no) * topo.num_cores_per_pkg * \
137 topo.num_threads_per_core + \
138 (core_no) * topo.num_threads_per_core + (thread_no))
139#define GET_CORE(core_base, core_no, pkg_no) \
140 (core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no))
141#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no)
142
143struct system_summary {
144 struct thread_data threads;
145 struct core_data cores;
146 struct pkg_data packages;
147} sum, average;
148
149
150struct topo_params {
151 int num_packages;
152 int num_cpus;
153 int num_cores;
154 int max_cpu_num;
155 int num_cores_per_pkg;
156 int num_threads_per_core;
157} topo;
158
159struct timeval tv_even, tv_odd, tv_delta;
160
161void setup_all_buffers(void);
162
163int cpu_is_not_present(int cpu)
164{
165 return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
166}
167/*
168 * run func(thread, core, package) in topology order
169 * skip non-present cpus
170 */
171
172int for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg_data *),
173 struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base)
174{
175 int retval, pkg_no, core_no, thread_no;
176
177 for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
178 for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
179 for (thread_no = 0; thread_no <
180 topo.num_threads_per_core; ++thread_no) {
181 struct thread_data *t;
182 struct core_data *c;
183 struct pkg_data *p;
184
185 t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
186
187 if (cpu_is_not_present(t->cpu_id))
188 continue;
189
190 c = GET_CORE(core_base, core_no, pkg_no);
191 p = GET_PKG(pkg_base, pkg_no);
192
193 retval = func(t, c, p);
194 if (retval)
195 return retval;
196 }
197 }
198 }
199 return 0;
200}
201
202int cpu_migrate(int cpu)
203{
204 CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
205 CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set);
206 if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1)
207 return -1;
208 else
209 return 0;
210}
211
212int get_msr(int cpu, off_t offset, unsigned long long *msr)
213{ 103{
214 ssize_t retval; 104 ssize_t retval;
105 unsigned long long msr;
215 char pathname[32]; 106 char pathname[32];
216 int fd; 107 int fd;
217 108
218 sprintf(pathname, "/dev/cpu/%d/msr", cpu); 109 sprintf(pathname, "/dev/cpu/%d/msr", cpu);
219 fd = open(pathname, O_RDONLY); 110 fd = open(pathname, O_RDONLY);
220 if (fd < 0) 111 if (fd < 0) {
221 return -1; 112 perror(pathname);
222 113 need_reinitialize = 1;
223 retval = pread(fd, msr, sizeof *msr, offset); 114 return 0;
224 close(fd); 115 }
225 116
226 if (retval != sizeof *msr) { 117 retval = pread(fd, &msr, sizeof msr, offset);
227 fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset); 118 if (retval != sizeof msr) {
228 return -1; 119 fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",
120 cpu, offset, retval);
121 exit(-2);
229 } 122 }
230 123
231 return 0; 124 close(fd);
125 return msr;
232} 126}
233 127
234void print_header(void) 128void print_header(void)
235{ 129{
236 if (show_pkg) 130 if (show_pkg)
237 outp += sprintf(outp, "pk"); 131 fprintf(stderr, "pk");
238 if (show_pkg)
239 outp += sprintf(outp, " ");
240 if (show_core) 132 if (show_core)
241 outp += sprintf(outp, "cor"); 133 fprintf(stderr, " cr");
242 if (show_cpu) 134 if (show_cpu)
243 outp += sprintf(outp, " CPU"); 135 fprintf(stderr, " CPU");
244 if (show_pkg || show_core || show_cpu)
245 outp += sprintf(outp, " ");
246 if (do_nhm_cstates) 136 if (do_nhm_cstates)
247 outp += sprintf(outp, " %%c0"); 137 fprintf(stderr, " %%c0 ");
248 if (has_aperf) 138 if (has_aperf)
249 outp += sprintf(outp, " GHz"); 139 fprintf(stderr, " GHz");
250 outp += sprintf(outp, " TSC"); 140 fprintf(stderr, " TSC");
251 if (extra_delta_offset32)
252 outp += sprintf(outp, " count 0x%03X", extra_delta_offset32);
253 if (extra_delta_offset64)
254 outp += sprintf(outp, " COUNT 0x%03X", extra_delta_offset64);
255 if (extra_msr_offset32)
256 outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset32);
257 if (extra_msr_offset64)
258 outp += sprintf(outp, " MSR 0x%03X", extra_msr_offset64);
259 if (do_nhm_cstates) 141 if (do_nhm_cstates)
260 outp += sprintf(outp, " %%c1"); 142 fprintf(stderr, " %%c1");
261 if (do_nhm_cstates) 143 if (do_nhm_cstates)
262 outp += sprintf(outp, " %%c3"); 144 fprintf(stderr, " %%c3");
263 if (do_nhm_cstates) 145 if (do_nhm_cstates)
264 outp += sprintf(outp, " %%c6"); 146 fprintf(stderr, " %%c6");
265 if (do_snb_cstates) 147 if (do_snb_cstates)
266 outp += sprintf(outp, " %%c7"); 148 fprintf(stderr, " %%c7");
267
268 if (do_dts)
269 outp += sprintf(outp, " CTMP");
270 if (do_ptm)
271 outp += sprintf(outp, " PTMP");
272
273 if (do_snb_cstates) 149 if (do_snb_cstates)
274 outp += sprintf(outp, " %%pc2"); 150 fprintf(stderr, " %%pc2");
275 if (do_nhm_cstates) 151 if (do_nhm_cstates)
276 outp += sprintf(outp, " %%pc3"); 152 fprintf(stderr, " %%pc3");
277 if (do_nhm_cstates) 153 if (do_nhm_cstates)
278 outp += sprintf(outp, " %%pc6"); 154 fprintf(stderr, " %%pc6");
279 if (do_snb_cstates) 155 if (do_snb_cstates)
280 outp += sprintf(outp, " %%pc7"); 156 fprintf(stderr, " %%pc7");
281 157 if (extra_msr_offset)
282 if (do_rapl & RAPL_PKG) 158 fprintf(stderr, " MSR 0x%x ", extra_msr_offset);
283 outp += sprintf(outp, " Pkg_W"); 159
284 if (do_rapl & RAPL_CORES) 160 putc('\n', stderr);
285 outp += sprintf(outp, " Cor_W");
286 if (do_rapl & RAPL_GFX)
287 outp += sprintf(outp, " GFX_W");
288 if (do_rapl & RAPL_DRAM)
289 outp += sprintf(outp, " RAM_W");
290 if (do_rapl & RAPL_PKG_PERF_STATUS)
291 outp += sprintf(outp, " PKG_%%");
292 if (do_rapl & RAPL_DRAM_PERF_STATUS)
293 outp += sprintf(outp, " RAM_%%");
294
295 outp += sprintf(outp, "\n");
296} 161}
297 162
298int dump_counters(struct thread_data *t, struct core_data *c, 163void dump_cnt(struct counters *cnt)
299 struct pkg_data *p)
300{ 164{
301 fprintf(stderr, "t %p, c %p, p %p\n", t, c, p); 165 fprintf(stderr, "package: %d ", cnt->pkg);
302 166 fprintf(stderr, "core:: %d ", cnt->core);
303 if (t) { 167 fprintf(stderr, "CPU: %d ", cnt->cpu);
304 fprintf(stderr, "CPU: %d flags 0x%x\n", t->cpu_id, t->flags); 168 fprintf(stderr, "TSC: %016llX\n", cnt->tsc);
305 fprintf(stderr, "TSC: %016llX\n", t->tsc); 169 fprintf(stderr, "c3: %016llX\n", cnt->c3);
306 fprintf(stderr, "aperf: %016llX\n", t->aperf); 170 fprintf(stderr, "c6: %016llX\n", cnt->c6);
307 fprintf(stderr, "mperf: %016llX\n", t->mperf); 171 fprintf(stderr, "c7: %016llX\n", cnt->c7);
308 fprintf(stderr, "c1: %016llX\n", t->c1); 172 fprintf(stderr, "aperf: %016llX\n", cnt->aperf);
309 fprintf(stderr, "msr0x%x: %08llX\n", 173 fprintf(stderr, "pc2: %016llX\n", cnt->pc2);
310 extra_delta_offset32, t->extra_delta32); 174 fprintf(stderr, "pc3: %016llX\n", cnt->pc3);
311 fprintf(stderr, "msr0x%x: %016llX\n", 175 fprintf(stderr, "pc6: %016llX\n", cnt->pc6);
312 extra_delta_offset64, t->extra_delta64); 176 fprintf(stderr, "pc7: %016llX\n", cnt->pc7);
313 fprintf(stderr, "msr0x%x: %08llX\n", 177 fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr);
314 extra_msr_offset32, t->extra_msr32); 178}
315 fprintf(stderr, "msr0x%x: %016llX\n",
316 extra_msr_offset64, t->extra_msr64);
317 }
318 179
319 if (c) { 180void dump_list(struct counters *cnt)
320 fprintf(stderr, "core: %d\n", c->core_id); 181{
321 fprintf(stderr, "c3: %016llX\n", c->c3); 182 printf("dump_list 0x%p\n", cnt);
322 fprintf(stderr, "c6: %016llX\n", c->c6);
323 fprintf(stderr, "c7: %016llX\n", c->c7);
324 fprintf(stderr, "DTS: %dC\n", c->core_temp_c);
325 }
326 183
327 if (p) { 184 for (; cnt; cnt = cnt->next)
328 fprintf(stderr, "package: %d\n", p->package_id); 185 dump_cnt(cnt);
329 fprintf(stderr, "pc2: %016llX\n", p->pc2);
330 fprintf(stderr, "pc3: %016llX\n", p->pc3);
331 fprintf(stderr, "pc6: %016llX\n", p->pc6);
332 fprintf(stderr, "pc7: %016llX\n", p->pc7);
333 fprintf(stderr, "Joules PKG: %0X\n", p->energy_pkg);
334 fprintf(stderr, "Joules COR: %0X\n", p->energy_cores);
335 fprintf(stderr, "Joules GFX: %0X\n", p->energy_gfx);
336 fprintf(stderr, "Joules RAM: %0X\n", p->energy_dram);
337 fprintf(stderr, "Throttle PKG: %0X\n", p->rapl_pkg_perf_status);
338 fprintf(stderr, "Throttle RAM: %0X\n", p->rapl_dram_perf_status);
339 fprintf(stderr, "PTM: %dC\n", p->pkg_temp_c);
340 }
341 return 0;
342} 186}
343 187
344/* 188void print_cnt(struct counters *p)
345 * column formatting convention & formats
346 * package: "pk" 2 columns %2d
347 * core: "cor" 3 columns %3d
348 * CPU: "CPU" 3 columns %3d
349 * Pkg_W: %6.2
350 * Cor_W: %6.2
351 * GFX_W: %5.2
352 * RAM_W: %5.2
353 * GHz: "GHz" 3 columns %3.2
354 * TSC: "TSC" 3 columns %3.2
355 * percentage " %pc3" %6.2
356 * Perf Status percentage: %5.2
357 * "CTMP" 4 columns %4d
358 */
359int format_counters(struct thread_data *t, struct core_data *c,
360 struct pkg_data *p)
361{ 189{
362 double interval_float; 190 double interval_float;
363 char *fmt5, *fmt6;
364
365 /* if showing only 1st thread in core and this isn't one, bail out */
366 if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
367 return 0;
368
369 /* if showing only 1st thread in pkg and this isn't one, bail out */
370 if (show_pkg_only && !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
371 return 0;
372 191
373 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0; 192 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
374 193
375 /* topo columns, print blanks on 1st (average) line */ 194 /* topology columns, print blanks on 1st (average) line */
376 if (t == &average.threads) { 195 if (p == cnt_average) {
377 if (show_pkg) 196 if (show_pkg)
378 outp += sprintf(outp, " "); 197 fprintf(stderr, " ");
379 if (show_pkg && show_core)
380 outp += sprintf(outp, " ");
381 if (show_core) 198 if (show_core)
382 outp += sprintf(outp, " "); 199 fprintf(stderr, " ");
383 if (show_cpu) 200 if (show_cpu)
384 outp += sprintf(outp, " " " "); 201 fprintf(stderr, " ");
385 } else { 202 } else {
386 if (show_pkg) { 203 if (show_pkg)
387 if (p) 204 fprintf(stderr, "%d", p->pkg);
388 outp += sprintf(outp, "%2d", p->package_id); 205 if (show_core)
389 else 206 fprintf(stderr, "%4d", p->core);
390 outp += sprintf(outp, " ");
391 }
392 if (show_pkg && show_core)
393 outp += sprintf(outp, " ");
394 if (show_core) {
395 if (c)
396 outp += sprintf(outp, "%3d", c->core_id);
397 else
398 outp += sprintf(outp, " ");
399 }
400 if (show_cpu) 207 if (show_cpu)
401 outp += sprintf(outp, " %3d", t->cpu_id); 208 fprintf(stderr, "%4d", p->cpu);
402 } 209 }
210
403 /* %c0 */ 211 /* %c0 */
404 if (do_nhm_cstates) { 212 if (do_nhm_cstates) {
405 if (show_pkg || show_core || show_cpu)
406 outp += sprintf(outp, " ");
407 if (!skip_c0) 213 if (!skip_c0)
408 outp += sprintf(outp, "%6.2f", 100.0 * t->mperf/t->tsc); 214 fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc);
409 else 215 else
410 outp += sprintf(outp, " ****"); 216 fprintf(stderr, " ****");
411 } 217 }
412 218
413 /* GHz */ 219 /* GHz */
414 if (has_aperf) { 220 if (has_aperf) {
415 if (!aperf_mperf_unstable) { 221 if (!aperf_mperf_unstable) {
416 outp += sprintf(outp, " %3.2f", 222 fprintf(stderr, "%5.2f",
417 1.0 * t->tsc / units * t->aperf / 223 1.0 * p->tsc / units * p->aperf /
418 t->mperf / interval_float); 224 p->mperf / interval_float);
419 } else { 225 } else {
420 if (t->aperf > t->tsc || t->mperf > t->tsc) { 226 if (p->aperf > p->tsc || p->mperf > p->tsc) {
421 outp += sprintf(outp, " ***"); 227 fprintf(stderr, " ****");
422 } else { 228 } else {
423 outp += sprintf(outp, "%3.1f*", 229 fprintf(stderr, "%4.1f*",
424 1.0 * t->tsc / 230 1.0 * p->tsc /
425 units * t->aperf / 231 units * p->aperf /
426 t->mperf / interval_float); 232 p->mperf / interval_float);
427 } 233 }
428 } 234 }
429 } 235 }
430 236
431 /* TSC */ 237 /* TSC */
432 outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); 238 fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float);
433
434 /* delta */
435 if (extra_delta_offset32)
436 outp += sprintf(outp, " %11llu", t->extra_delta32);
437
438 /* DELTA */
439 if (extra_delta_offset64)
440 outp += sprintf(outp, " %11llu", t->extra_delta64);
441 /* msr */
442 if (extra_msr_offset32)
443 outp += sprintf(outp, " 0x%08llx", t->extra_msr32);
444
445 /* MSR */
446 if (extra_msr_offset64)
447 outp += sprintf(outp, " 0x%016llx", t->extra_msr64);
448 239
449 if (do_nhm_cstates) { 240 if (do_nhm_cstates) {
450 if (!skip_c1) 241 if (!skip_c1)
451 outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc); 242 fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);
452 else 243 else
453 outp += sprintf(outp, " ****"); 244 fprintf(stderr, " ****");
454 } 245 }
455
456 /* print per-core data only for 1st thread in core */
457 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
458 goto done;
459
460 if (do_nhm_cstates) 246 if (do_nhm_cstates)
461 outp += sprintf(outp, " %6.2f", 100.0 * c->c3/t->tsc); 247 fprintf(stderr, " %6.2f", 100.0 * p->c3/p->tsc);
462 if (do_nhm_cstates) 248 if (do_nhm_cstates)
463 outp += sprintf(outp, " %6.2f", 100.0 * c->c6/t->tsc); 249 fprintf(stderr, " %6.2f", 100.0 * p->c6/p->tsc);
464 if (do_snb_cstates) 250 if (do_snb_cstates)
465 outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc); 251 fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc);
466
467 if (do_dts)
468 outp += sprintf(outp, " %4d", c->core_temp_c);
469
470 /* print per-package data only for 1st core in package */
471 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
472 goto done;
473
474 if (do_ptm)
475 outp += sprintf(outp, " %4d", p->pkg_temp_c);
476
477 if (do_snb_cstates) 252 if (do_snb_cstates)
478 outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc); 253 fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc);
479 if (do_nhm_cstates) 254 if (do_nhm_cstates)
480 outp += sprintf(outp, " %6.2f", 100.0 * p->pc3/t->tsc); 255 fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc);
481 if (do_nhm_cstates) 256 if (do_nhm_cstates)
482 outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc); 257 fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc);
483 if (do_snb_cstates) 258 if (do_snb_cstates)
484 outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); 259 fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc);
485 260 if (extra_msr_offset)
486 /* 261 fprintf(stderr, " 0x%016llx", p->extra_msr);
487 * If measurement interval exceeds minimum RAPL Joule Counter range, 262 putc('\n', stderr);
488 * indicate that results are suspect by printing "**" in fraction place.
489 */
490 if (interval_float < rapl_joule_counter_range) {
491 fmt5 = " %5.2f";
492 fmt6 = " %6.2f";
493 } else {
494 fmt5 = " %3.0f**";
495 fmt6 = " %4.0f**";
496 }
497
498 if (do_rapl & RAPL_PKG)
499 outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float);
500 if (do_rapl & RAPL_CORES)
501 outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float);
502 if (do_rapl & RAPL_GFX)
503 outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float);
504 if (do_rapl & RAPL_DRAM)
505 outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float);
506 if (do_rapl & RAPL_PKG_PERF_STATUS )
507 outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
508 if (do_rapl & RAPL_DRAM_PERF_STATUS )
509 outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
510
511done:
512 outp += sprintf(outp, "\n");
513
514 return 0;
515} 263}
516 264
517void flush_stdout() 265void print_counters(struct counters *counters)
518{ 266{
519 fputs(output_buffer, stdout); 267 struct counters *cnt;
520 fflush(stdout);
521 outp = output_buffer;
522}
523void flush_stderr()
524{
525 fputs(output_buffer, stderr);
526 outp = output_buffer;
527}
528void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
529{
530 static int printed;
531 268
532 if (!printed || !summary_only) 269 print_header();
533 print_header();
534 270
535 if (topo.num_cpus > 1) 271 if (num_cpus > 1)
536 format_counters(&average.threads, &average.cores, 272 print_cnt(cnt_average);
537 &average.packages);
538 273
539 printed = 1; 274 for (cnt = counters; cnt != NULL; cnt = cnt->next)
275 print_cnt(cnt);
540 276
541 if (summary_only)
542 return;
543
544 for_all_cpus(format_counters, t, c, p);
545} 277}
546 278
547#define DELTA_WRAP32(new, old) \ 279#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
548 if (new > old) { \
549 old = new - old; \
550 } else { \
551 old = 0x100000000 + new - old; \
552 }
553
554void
555delta_package(struct pkg_data *new, struct pkg_data *old)
556{
557 old->pc2 = new->pc2 - old->pc2;
558 old->pc3 = new->pc3 - old->pc3;
559 old->pc6 = new->pc6 - old->pc6;
560 old->pc7 = new->pc7 - old->pc7;
561 old->pkg_temp_c = new->pkg_temp_c;
562
563 DELTA_WRAP32(new->energy_pkg, old->energy_pkg);
564 DELTA_WRAP32(new->energy_cores, old->energy_cores);
565 DELTA_WRAP32(new->energy_gfx, old->energy_gfx);
566 DELTA_WRAP32(new->energy_dram, old->energy_dram);
567 DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status);
568 DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status);
569}
570 280
571void 281int compute_delta(struct counters *after,
572delta_core(struct core_data *new, struct core_data *old) 282 struct counters *before, struct counters *delta)
573{ 283{
574 old->c3 = new->c3 - old->c3; 284 int errors = 0;
575 old->c6 = new->c6 - old->c6; 285 int perf_err = 0;
576 old->c7 = new->c7 - old->c7;
577 old->core_temp_c = new->core_temp_c;
578}
579 286
580/* 287 skip_c0 = skip_c1 = 0;
581 * old = new - old
582 */
583void
584delta_thread(struct thread_data *new, struct thread_data *old,
585 struct core_data *core_delta)
586{
587 old->tsc = new->tsc - old->tsc;
588
589 /* check for TSC < 1 Mcycles over interval */
590 if (old->tsc < (1000 * 1000)) {
591 fprintf(stderr, "Insanely slow TSC rate, TSC stops in idle?\n");
592 fprintf(stderr, "You can disable all c-states by booting with \"idle=poll\"\n");
593 fprintf(stderr, "or just the deep ones with \"processor.max_cstate=1\"\n");
594 exit(-3);
595 }
596 288
597 old->c1 = new->c1 - old->c1; 289 for ( ; after && before && delta;
290 after = after->next, before = before->next, delta = delta->next) {
291 if (before->cpu != after->cpu) {
292 printf("cpu configuration changed: %d != %d\n",
293 before->cpu, after->cpu);
294 return -1;
295 }
598 296
599 if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) { 297 if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) {
600 old->aperf = new->aperf - old->aperf; 298 fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n",
601 old->mperf = new->mperf - old->mperf; 299 before->cpu, before->tsc, after->tsc);
602 } else { 300 errors++;
301 }
302 /* check for TSC < 1 Mcycles over interval */
303 if (delta->tsc < (1000 * 1000)) {
304 fprintf(stderr, "Insanely slow TSC rate,"
305 " TSC stops in idle?\n");
306 fprintf(stderr, "You can disable all c-states"
307 " by booting with \"idle=poll\"\n");
308 fprintf(stderr, "or just the deep ones with"
309 " \"processor.max_cstate=1\"\n");
310 exit(-3);
311 }
312 if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) {
313 fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n",
314 before->cpu, before->c3, after->c3);
315 errors++;
316 }
317 if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) {
318 fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n",
319 before->cpu, before->c6, after->c6);
320 errors++;
321 }
322 if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) {
323 fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n",
324 before->cpu, before->c7, after->c7);
325 errors++;
326 }
327 if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) {
328 fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n",
329 before->cpu, before->pc2, after->pc2);
330 errors++;
331 }
332 if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) {
333 fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n",
334 before->cpu, before->pc3, after->pc3);
335 errors++;
336 }
337 if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) {
338 fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n",
339 before->cpu, before->pc6, after->pc6);
340 errors++;
341 }
342 if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) {
343 fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n",
344 before->cpu, before->pc7, after->pc7);
345 errors++;
346 }
603 347
604 if (!aperf_mperf_unstable) { 348 perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf);
605 fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname); 349 if (perf_err) {
606 fprintf(stderr, "* Frequency results do not cover entire interval *\n"); 350 fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n",
607 fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n"); 351 before->cpu, before->aperf, after->aperf);
352 }
353 perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf);
354 if (perf_err) {
355 fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n",
356 before->cpu, before->mperf, after->mperf);
357 }
358 if (perf_err) {
359 if (!aperf_mperf_unstable) {
360 fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
361 fprintf(stderr, "* Frequency results do not cover entire interval *\n");
362 fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
608 363
609 aperf_mperf_unstable = 1; 364 aperf_mperf_unstable = 1;
365 }
366 /*
367 * mperf delta is likely a huge "positive" number
368 * can not use it for calculating c0 time
369 */
370 skip_c0 = 1;
371 skip_c1 = 1;
610 } 372 }
373
611 /* 374 /*
612 * mperf delta is likely a huge "positive" number 375 * As mperf and tsc collection are not atomic,
613 * can not use it for calculating c0 time 376 * it is possible for mperf's non-halted cycles
377 * to exceed TSC's all cycles: show c1 = 0% in that case.
614 */ 378 */
615 skip_c0 = 1; 379 if (delta->mperf > delta->tsc)
616 skip_c1 = 1; 380 delta->c1 = 0;
617 } 381 else /* normal case, derive c1 */
382 delta->c1 = delta->tsc - delta->mperf
383 - delta->c3 - delta->c6 - delta->c7;
618 384
385 if (delta->mperf == 0)
386 delta->mperf = 1; /* divide by 0 protection */
619 387
620 /* 388 /*
621 * As counter collection is not atomic, 389 * for "extra msr", just copy the latest w/o subtracting
622 * it is possible for mperf's non-halted cycles + idle states 390 */
623 * to exceed TSC's all cycles: show c1 = 0% in that case. 391 delta->extra_msr = after->extra_msr;
624 */ 392 if (errors) {
625 if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc) 393 fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
626 old->c1 = 0; 394 dump_cnt(before);
627 else { 395 fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
628 /* normal case, derive c1 */ 396 dump_cnt(after);
629 old->c1 = old->tsc - old->mperf - core_delta->c3 397 errors = 0;
630 - core_delta->c6 - core_delta->c7; 398 }
631 }
632
633 if (old->mperf == 0) {
634 if (verbose > 1) fprintf(stderr, "cpu%d MPERF 0!\n", old->cpu_id);
635 old->mperf = 1; /* divide by 0 protection */
636 } 399 }
637
638 old->extra_delta32 = new->extra_delta32 - old->extra_delta32;
639 old->extra_delta32 &= 0xFFFFFFFF;
640
641 old->extra_delta64 = new->extra_delta64 - old->extra_delta64;
642
643 /*
644 * Extra MSR is just a snapshot, simply copy latest w/o subtracting
645 */
646 old->extra_msr32 = new->extra_msr32;
647 old->extra_msr64 = new->extra_msr64;
648}
649
650int delta_cpu(struct thread_data *t, struct core_data *c,
651 struct pkg_data *p, struct thread_data *t2,
652 struct core_data *c2, struct pkg_data *p2)
653{
654 /* calculate core delta only for 1st thread in core */
655 if (t->flags & CPU_IS_FIRST_THREAD_IN_CORE)
656 delta_core(c, c2);
657
658 /* always calculate thread delta */
659 delta_thread(t, t2, c2); /* c2 is core delta */
660
661 /* calculate package delta only for 1st core in package */
662 if (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)
663 delta_package(p, p2);
664
665 return 0; 400 return 0;
666} 401}
667 402
668void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) 403void compute_average(struct counters *delta, struct counters *avg)
669{ 404{
670 t->tsc = 0; 405 struct counters *sum;
671 t->aperf = 0;
672 t->mperf = 0;
673 t->c1 = 0;
674
675 t->extra_delta32 = 0;
676 t->extra_delta64 = 0;
677
678 /* tells format_counters to dump all fields from this set */
679 t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
680
681 c->c3 = 0;
682 c->c6 = 0;
683 c->c7 = 0;
684 c->core_temp_c = 0;
685
686 p->pc2 = 0;
687 p->pc3 = 0;
688 p->pc6 = 0;
689 p->pc7 = 0;
690
691 p->energy_pkg = 0;
692 p->energy_dram = 0;
693 p->energy_cores = 0;
694 p->energy_gfx = 0;
695 p->rapl_pkg_perf_status = 0;
696 p->rapl_dram_perf_status = 0;
697 p->pkg_temp_c = 0;
698}
699int sum_counters(struct thread_data *t, struct core_data *c,
700 struct pkg_data *p)
701{
702 average.threads.tsc += t->tsc;
703 average.threads.aperf += t->aperf;
704 average.threads.mperf += t->mperf;
705 average.threads.c1 += t->c1;
706
707 average.threads.extra_delta32 += t->extra_delta32;
708 average.threads.extra_delta64 += t->extra_delta64;
709
710 /* sum per-core values only for 1st thread in core */
711 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
712 return 0;
713
714 average.cores.c3 += c->c3;
715 average.cores.c6 += c->c6;
716 average.cores.c7 += c->c7;
717
718 average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c);
719
720 /* sum per-pkg values only for 1st core in pkg */
721 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
722 return 0;
723
724 average.packages.pc2 += p->pc2;
725 average.packages.pc3 += p->pc3;
726 average.packages.pc6 += p->pc6;
727 average.packages.pc7 += p->pc7;
728
729 average.packages.energy_pkg += p->energy_pkg;
730 average.packages.energy_dram += p->energy_dram;
731 average.packages.energy_cores += p->energy_cores;
732 average.packages.energy_gfx += p->energy_gfx;
733
734 average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c);
735 406
736 average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status; 407 sum = calloc(1, sizeof(struct counters));
737 average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status; 408 if (sum == NULL) {
738 return 0; 409 perror("calloc sum");
739} 410 exit(1);
740/* 411 }
741 * sum the counters for all cpus in the system
742 * compute the weighted average
743 */
744void compute_average(struct thread_data *t, struct core_data *c,
745 struct pkg_data *p)
746{
747 clear_counters(&average.threads, &average.cores, &average.packages);
748
749 for_all_cpus(sum_counters, t, c, p);
750
751 average.threads.tsc /= topo.num_cpus;
752 average.threads.aperf /= topo.num_cpus;
753 average.threads.mperf /= topo.num_cpus;
754 average.threads.c1 /= topo.num_cpus;
755
756 average.threads.extra_delta32 /= topo.num_cpus;
757 average.threads.extra_delta32 &= 0xFFFFFFFF;
758
759 average.threads.extra_delta64 /= topo.num_cpus;
760
761 average.cores.c3 /= topo.num_cores;
762 average.cores.c6 /= topo.num_cores;
763 average.cores.c7 /= topo.num_cores;
764
765 average.packages.pc2 /= topo.num_packages;
766 average.packages.pc3 /= topo.num_packages;
767 average.packages.pc6 /= topo.num_packages;
768 average.packages.pc7 /= topo.num_packages;
769}
770
771static unsigned long long rdtsc(void)
772{
773 unsigned int low, high;
774
775 asm volatile("rdtsc" : "=a" (low), "=d" (high));
776 412
777 return low | ((unsigned long long)high) << 32; 413 for (; delta; delta = delta->next) {
414 sum->tsc += delta->tsc;
415 sum->c1 += delta->c1;
416 sum->c3 += delta->c3;
417 sum->c6 += delta->c6;
418 sum->c7 += delta->c7;
419 sum->aperf += delta->aperf;
420 sum->mperf += delta->mperf;
421 sum->pc2 += delta->pc2;
422 sum->pc3 += delta->pc3;
423 sum->pc6 += delta->pc6;
424 sum->pc7 += delta->pc7;
425 }
426 avg->tsc = sum->tsc/num_cpus;
427 avg->c1 = sum->c1/num_cpus;
428 avg->c3 = sum->c3/num_cpus;
429 avg->c6 = sum->c6/num_cpus;
430 avg->c7 = sum->c7/num_cpus;
431 avg->aperf = sum->aperf/num_cpus;
432 avg->mperf = sum->mperf/num_cpus;
433 avg->pc2 = sum->pc2/num_cpus;
434 avg->pc3 = sum->pc3/num_cpus;
435 avg->pc6 = sum->pc6/num_cpus;
436 avg->pc7 = sum->pc7/num_cpus;
437
438 free(sum);
778} 439}
779 440
780 441void get_counters(struct counters *cnt)
781/*
782 * get_counters(...)
783 * migrate to cpu
784 * acquire and record local counters for that cpu
785 */
786int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
787{ 442{
788 int cpu = t->cpu_id; 443 for ( ; cnt; cnt = cnt->next) {
789 unsigned long long msr; 444 cnt->tsc = get_msr(cnt->cpu, MSR_TSC);
790 445 if (do_nhm_cstates)
791 if (cpu_migrate(cpu)) { 446 cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY);
792 fprintf(stderr, "Could not migrate to CPU %d\n", cpu); 447 if (do_nhm_cstates)
793 return -1; 448 cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY);
794 } 449 if (do_snb_cstates)
795 450 cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY);
796 t->tsc = rdtsc(); /* we are running on local CPU of interest */ 451 if (has_aperf)
797 452 cnt->aperf = get_msr(cnt->cpu, MSR_APERF);
798 if (has_aperf) { 453 if (has_aperf)
799 if (get_msr(cpu, MSR_IA32_APERF, &t->aperf)) 454 cnt->mperf = get_msr(cnt->cpu, MSR_MPERF);
800 return -3; 455 if (do_snb_cstates)
801 if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf)) 456 cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY);
802 return -4; 457 if (do_nhm_cstates)
803 } 458 cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY);
804 459 if (do_nhm_cstates)
805 if (extra_delta_offset32) { 460 cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY);
806 if (get_msr(cpu, extra_delta_offset32, &msr)) 461 if (do_snb_cstates)
807 return -5; 462 cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY);
808 t->extra_delta32 = msr & 0xFFFFFFFF; 463 if (extra_msr_offset)
809 } 464 cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset);
810
811 if (extra_delta_offset64)
812 if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64))
813 return -5;
814
815 if (extra_msr_offset32) {
816 if (get_msr(cpu, extra_msr_offset32, &msr))
817 return -5;
818 t->extra_msr32 = msr & 0xFFFFFFFF;
819 }
820
821 if (extra_msr_offset64)
822 if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
823 return -5;
824
825 /* collect core counters only for 1st thread in core */
826 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
827 return 0;
828
829 if (do_nhm_cstates) {
830 if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
831 return -6;
832 if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
833 return -7;
834 } 465 }
835
836 if (do_snb_cstates)
837 if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
838 return -8;
839
840 if (do_dts) {
841 if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
842 return -9;
843 c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
844 }
845
846
847 /* collect package counters only for 1st core in package */
848 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
849 return 0;
850
851 if (do_nhm_cstates) {
852 if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3))
853 return -9;
854 if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6))
855 return -10;
856 }
857 if (do_snb_cstates) {
858 if (get_msr(cpu, MSR_PKG_C2_RESIDENCY, &p->pc2))
859 return -11;
860 if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7))
861 return -12;
862 }
863 if (do_rapl & RAPL_PKG) {
864 if (get_msr(cpu, MSR_PKG_ENERGY_STATUS, &msr))
865 return -13;
866 p->energy_pkg = msr & 0xFFFFFFFF;
867 }
868 if (do_rapl & RAPL_CORES) {
869 if (get_msr(cpu, MSR_PP0_ENERGY_STATUS, &msr))
870 return -14;
871 p->energy_cores = msr & 0xFFFFFFFF;
872 }
873 if (do_rapl & RAPL_DRAM) {
874 if (get_msr(cpu, MSR_DRAM_ENERGY_STATUS, &msr))
875 return -15;
876 p->energy_dram = msr & 0xFFFFFFFF;
877 }
878 if (do_rapl & RAPL_GFX) {
879 if (get_msr(cpu, MSR_PP1_ENERGY_STATUS, &msr))
880 return -16;
881 p->energy_gfx = msr & 0xFFFFFFFF;
882 }
883 if (do_rapl & RAPL_PKG_PERF_STATUS) {
884 if (get_msr(cpu, MSR_PKG_PERF_STATUS, &msr))
885 return -16;
886 p->rapl_pkg_perf_status = msr & 0xFFFFFFFF;
887 }
888 if (do_rapl & RAPL_DRAM_PERF_STATUS) {
889 if (get_msr(cpu, MSR_DRAM_PERF_STATUS, &msr))
890 return -16;
891 p->rapl_dram_perf_status = msr & 0xFFFFFFFF;
892 }
893 if (do_ptm) {
894 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
895 return -17;
896 p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
897 }
898 return 0;
899} 466}
900 467
901void print_verbose_header(void) 468void print_nehalem_info(void)
902{ 469{
903 unsigned long long msr; 470 unsigned long long msr;
904 unsigned int ratio; 471 unsigned int ratio;
@@ -906,10 +473,7 @@ void print_verbose_header(void)
906 if (!do_nehalem_platform_info) 473 if (!do_nehalem_platform_info)
907 return; 474 return;
908 475
909 get_msr(0, MSR_NHM_PLATFORM_INFO, &msr); 476 msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO);
910
911 if (verbose)
912 fprintf(stderr, "cpu0: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", msr);
913 477
914 ratio = (msr >> 40) & 0xFF; 478 ratio = (msr >> 40) & 0xFF;
915 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", 479 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
@@ -919,223 +483,170 @@ void print_verbose_header(void)
919 fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", 483 fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",
920 ratio, bclk, ratio * bclk); 484 ratio, bclk, ratio * bclk);
921 485
922 if (!do_ivt_turbo_ratio_limit) 486 if (verbose > 1)
923 goto print_nhm_turbo_ratio_limits; 487 fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
924
925 get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr);
926
927 if (verbose)
928 fprintf(stderr, "cpu0: MSR_IVT_TURBO_RATIO_LIMIT: 0x%08llx\n", msr);
929
930 ratio = (msr >> 56) & 0xFF;
931 if (ratio)
932 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 16 active cores\n",
933 ratio, bclk, ratio * bclk);
934
935 ratio = (msr >> 48) & 0xFF;
936 if (ratio)
937 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 15 active cores\n",
938 ratio, bclk, ratio * bclk);
939 488
940 ratio = (msr >> 40) & 0xFF; 489 if (!do_nehalem_turbo_ratio_limit)
941 if (ratio) 490 return;
942 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 14 active cores\n",
943 ratio, bclk, ratio * bclk);
944 491
945 ratio = (msr >> 32) & 0xFF; 492 msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT);
946 if (ratio)
947 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 13 active cores\n",
948 ratio, bclk, ratio * bclk);
949 493
950 ratio = (msr >> 24) & 0xFF; 494 ratio = (msr >> 24) & 0xFF;
951 if (ratio) 495 if (ratio)
952 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 12 active cores\n", 496 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
953 ratio, bclk, ratio * bclk); 497 ratio, bclk, ratio * bclk);
954 498
955 ratio = (msr >> 16) & 0xFF; 499 ratio = (msr >> 16) & 0xFF;
956 if (ratio) 500 if (ratio)
957 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 11 active cores\n", 501 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
958 ratio, bclk, ratio * bclk); 502 ratio, bclk, ratio * bclk);
959 503
960 ratio = (msr >> 8) & 0xFF; 504 ratio = (msr >> 8) & 0xFF;
961 if (ratio) 505 if (ratio)
962 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 10 active cores\n", 506 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
963 ratio, bclk, ratio * bclk); 507 ratio, bclk, ratio * bclk);
964 508
965 ratio = (msr >> 0) & 0xFF; 509 ratio = (msr >> 0) & 0xFF;
966 if (ratio) 510 if (ratio)
967 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 9 active cores\n", 511 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
968 ratio, bclk, ratio * bclk); 512 ratio, bclk, ratio * bclk);
969 513
970print_nhm_turbo_ratio_limits: 514}
971 get_msr(0, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
972
973#define SNB_C1_AUTO_UNDEMOTE (1UL << 27)
974#define SNB_C3_AUTO_UNDEMOTE (1UL << 28)
975
976 fprintf(stderr, "cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", msr);
977
978 fprintf(stderr, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: ",
979 (msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "",
980 (msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "",
981 (msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "",
982 (msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "",
983 (msr & (1 << 15)) ? "" : "UN",
984 (unsigned int)msr & 7);
985
986
987 switch(msr & 0x7) {
988 case 0:
989 fprintf(stderr, "pc0");
990 break;
991 case 1:
992 fprintf(stderr, do_snb_cstates ? "pc2" : "pc0");
993 break;
994 case 2:
995 fprintf(stderr, do_snb_cstates ? "pc6-noret" : "pc3");
996 break;
997 case 3:
998 fprintf(stderr, "pc6");
999 break;
1000 case 4:
1001 fprintf(stderr, "pc7");
1002 break;
1003 case 5:
1004 fprintf(stderr, do_snb_cstates ? "pc7s" : "invalid");
1005 break;
1006 case 7:
1007 fprintf(stderr, "unlimited");
1008 break;
1009 default:
1010 fprintf(stderr, "invalid");
1011 }
1012 fprintf(stderr, ")\n");
1013
1014 if (!do_nehalem_turbo_ratio_limit)
1015 return;
1016
1017 get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
1018
1019 if (verbose)
1020 fprintf(stderr, "cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n", msr);
1021 515
1022 ratio = (msr >> 56) & 0xFF; 516void free_counter_list(struct counters *list)
1023 if (ratio) 517{
1024 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 8 active cores\n", 518 struct counters *p;
1025 ratio, bclk, ratio * bclk);
1026 519
1027 ratio = (msr >> 48) & 0xFF; 520 for (p = list; p; ) {
1028 if (ratio) 521 struct counters *free_me;
1029 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 7 active cores\n",
1030 ratio, bclk, ratio * bclk);
1031 522
1032 ratio = (msr >> 40) & 0xFF; 523 free_me = p;
1033 if (ratio) 524 p = p->next;
1034 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 6 active cores\n", 525 free(free_me);
1035 ratio, bclk, ratio * bclk); 526 }
1036 527}
1037 ratio = (msr >> 32) & 0xFF;
1038 if (ratio)
1039 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 5 active cores\n",
1040 ratio, bclk, ratio * bclk);
1041 528
1042 ratio = (msr >> 24) & 0xFF; 529void free_all_counters(void)
1043 if (ratio) 530{
1044 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n", 531 free_counter_list(cnt_even);
1045 ratio, bclk, ratio * bclk); 532 cnt_even = NULL;
1046 533
1047 ratio = (msr >> 16) & 0xFF; 534 free_counter_list(cnt_odd);
1048 if (ratio) 535 cnt_odd = NULL;
1049 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
1050 ratio, bclk, ratio * bclk);
1051 536
1052 ratio = (msr >> 8) & 0xFF; 537 free_counter_list(cnt_delta);
1053 if (ratio) 538 cnt_delta = NULL;
1054 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
1055 ratio, bclk, ratio * bclk);
1056 539
1057 ratio = (msr >> 0) & 0xFF; 540 free_counter_list(cnt_average);
1058 if (ratio) 541 cnt_average = NULL;
1059 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
1060 ratio, bclk, ratio * bclk);
1061} 542}
1062 543
1063void free_all_buffers(void) 544void insert_counters(struct counters **list,
545 struct counters *new)
1064{ 546{
1065 CPU_FREE(cpu_present_set); 547 struct counters *prev;
1066 cpu_present_set = NULL;
1067 cpu_present_set = 0;
1068 548
1069 CPU_FREE(cpu_affinity_set); 549 /*
1070 cpu_affinity_set = NULL; 550 * list was empty
1071 cpu_affinity_setsize = 0; 551 */
552 if (*list == NULL) {
553 new->next = *list;
554 *list = new;
555 return;
556 }
1072 557
1073 free(thread_even); 558 show_cpu = 1; /* there is more than one CPU */
1074 free(core_even);
1075 free(package_even);
1076 559
1077 thread_even = NULL; 560 /*
1078 core_even = NULL; 561 * insert on front of list.
1079 package_even = NULL; 562 * It is sorted by ascending package#, core#, cpu#
563 */
564 if (((*list)->pkg > new->pkg) ||
565 (((*list)->pkg == new->pkg) && ((*list)->core > new->core)) ||
566 (((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) {
567 new->next = *list;
568 *list = new;
569 return;
570 }
1080 571
1081 free(thread_odd); 572 prev = *list;
1082 free(core_odd);
1083 free(package_odd);
1084 573
1085 thread_odd = NULL; 574 while (prev->next && (prev->next->pkg < new->pkg)) {
1086 core_odd = NULL; 575 prev = prev->next;
1087 package_odd = NULL; 576 show_pkg = 1; /* there is more than 1 package */
577 }
1088 578
1089 free(output_buffer); 579 while (prev->next && (prev->next->pkg == new->pkg)
1090 output_buffer = NULL; 580 && (prev->next->core < new->core)) {
1091 outp = NULL; 581 prev = prev->next;
582 show_core = 1; /* there is more than 1 core */
583 }
584
585 while (prev->next && (prev->next->pkg == new->pkg)
586 && (prev->next->core == new->core)
587 && (prev->next->cpu < new->cpu)) {
588 prev = prev->next;
589 }
590
591 /*
592 * insert after "prev"
593 */
594 new->next = prev->next;
595 prev->next = new;
1092} 596}
1093 597
1094/* 598void alloc_new_counters(int pkg, int core, int cpu)
1095 * cpu_is_first_sibling_in_core(cpu)
1096 * return 1 if given CPU is 1st HT sibling in the core
1097 */
1098int cpu_is_first_sibling_in_core(int cpu)
1099{ 599{
1100 char path[64]; 600 struct counters *new;
1101 FILE *filep;
1102 int first_cpu;
1103 601
1104 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); 602 if (verbose > 1)
1105 filep = fopen(path, "r"); 603 printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
1106 if (filep == NULL) { 604
1107 perror(path); 605 new = (struct counters *)calloc(1, sizeof(struct counters));
606 if (new == NULL) {
607 perror("calloc");
1108 exit(1); 608 exit(1);
1109 } 609 }
1110 fscanf(filep, "%d", &first_cpu); 610 new->pkg = pkg;
1111 fclose(filep); 611 new->core = core;
1112 return (cpu == first_cpu); 612 new->cpu = cpu;
1113} 613 insert_counters(&cnt_odd, new);
1114 614
1115/* 615 new = (struct counters *)calloc(1,
1116 * cpu_is_first_core_in_package(cpu) 616 sizeof(struct counters));
1117 * return 1 if given CPU is 1st core in package 617 if (new == NULL) {
1118 */ 618 perror("calloc");
1119int cpu_is_first_core_in_package(int cpu) 619 exit(1);
1120{ 620 }
1121 char path[64]; 621 new->pkg = pkg;
1122 FILE *filep; 622 new->core = core;
1123 int first_cpu; 623 new->cpu = cpu;
624 insert_counters(&cnt_even, new);
1124 625
1125 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); 626 new = (struct counters *)calloc(1, sizeof(struct counters));
1126 filep = fopen(path, "r"); 627 if (new == NULL) {
1127 if (filep == NULL) { 628 perror("calloc");
1128 perror(path);
1129 exit(1); 629 exit(1);
1130 } 630 }
1131 fscanf(filep, "%d", &first_cpu); 631 new->pkg = pkg;
1132 fclose(filep); 632 new->core = core;
1133 return (cpu == first_cpu); 633 new->cpu = cpu;
634 insert_counters(&cnt_delta, new);
635
636 new = (struct counters *)calloc(1, sizeof(struct counters));
637 if (new == NULL) {
638 perror("calloc");
639 exit(1);
640 }
641 new->pkg = pkg;
642 new->core = core;
643 new->cpu = cpu;
644 cnt_average = new;
1134} 645}
1135 646
1136int get_physical_package_id(int cpu) 647int get_physical_package_id(int cpu)
1137{ 648{
1138 char path[80]; 649 char path[64];
1139 FILE *filep; 650 FILE *filep;
1140 int pkg; 651 int pkg;
1141 652
@@ -1152,7 +663,7 @@ int get_physical_package_id(int cpu)
1152 663
1153int get_core_id(int cpu) 664int get_core_id(int cpu)
1154{ 665{
1155 char path[80]; 666 char path[64];
1156 FILE *filep; 667 FILE *filep;
1157 int core; 668 int core;
1158 669
@@ -1167,87 +678,14 @@ int get_core_id(int cpu)
1167 return core; 678 return core;
1168} 679}
1169 680
1170int get_num_ht_siblings(int cpu)
1171{
1172 char path[80];
1173 FILE *filep;
1174 int sib1, sib2;
1175 int matches;
1176 char character;
1177
1178 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);
1179 filep = fopen(path, "r");
1180 if (filep == NULL) {
1181 perror(path);
1182 exit(1);
1183 }
1184 /*
1185 * file format:
1186 * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4)
1187 * otherwinse 1 sibling (self).
1188 */
1189 matches = fscanf(filep, "%d%c%d\n", &sib1, &character, &sib2);
1190
1191 fclose(filep);
1192
1193 if (matches == 3)
1194 return 2;
1195 else
1196 return 1;
1197}
1198
1199/* 681/*
1200 * run func(thread, core, package) in topology order 682 * run func(index, cpu) on every cpu in /proc/stat
1201 * skip non-present cpus
1202 */ 683 */
1203 684
1204int for_all_cpus_2(int (func)(struct thread_data *, struct core_data *, 685int for_all_cpus(void (func)(int, int, int))
1205 struct pkg_data *, struct thread_data *, struct core_data *,
1206 struct pkg_data *), struct thread_data *thread_base,
1207 struct core_data *core_base, struct pkg_data *pkg_base,
1208 struct thread_data *thread_base2, struct core_data *core_base2,
1209 struct pkg_data *pkg_base2)
1210{
1211 int retval, pkg_no, core_no, thread_no;
1212
1213 for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
1214 for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) {
1215 for (thread_no = 0; thread_no <
1216 topo.num_threads_per_core; ++thread_no) {
1217 struct thread_data *t, *t2;
1218 struct core_data *c, *c2;
1219 struct pkg_data *p, *p2;
1220
1221 t = GET_THREAD(thread_base, thread_no, core_no, pkg_no);
1222
1223 if (cpu_is_not_present(t->cpu_id))
1224 continue;
1225
1226 t2 = GET_THREAD(thread_base2, thread_no, core_no, pkg_no);
1227
1228 c = GET_CORE(core_base, core_no, pkg_no);
1229 c2 = GET_CORE(core_base2, core_no, pkg_no);
1230
1231 p = GET_PKG(pkg_base, pkg_no);
1232 p2 = GET_PKG(pkg_base2, pkg_no);
1233
1234 retval = func(t, c, p, t2, c2, p2);
1235 if (retval)
1236 return retval;
1237 }
1238 }
1239 }
1240 return 0;
1241}
1242
1243/*
1244 * run func(cpu) on every cpu in /proc/stat
1245 * return max_cpu number
1246 */
1247int for_all_proc_cpus(int (func)(int))
1248{ 686{
1249 FILE *fp; 687 FILE *fp;
1250 int cpu_num; 688 int cpu_count;
1251 int retval; 689 int retval;
1252 690
1253 fp = fopen(proc_stat, "r"); 691 fp = fopen(proc_stat, "r");
@@ -1262,101 +700,77 @@ int for_all_proc_cpus(int (func)(int))
1262 exit(1); 700 exit(1);
1263 } 701 }
1264 702
1265 while (1) { 703 for (cpu_count = 0; ; cpu_count++) {
1266 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); 704 int cpu;
705
706 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu);
1267 if (retval != 1) 707 if (retval != 1)
1268 break; 708 break;
1269 709
1270 retval = func(cpu_num); 710 func(get_physical_package_id(cpu), get_core_id(cpu), cpu);
1271 if (retval) {
1272 fclose(fp);
1273 return(retval);
1274 }
1275 } 711 }
1276 fclose(fp); 712 fclose(fp);
1277 return 0; 713 return cpu_count;
1278} 714}
1279 715
1280void re_initialize(void) 716void re_initialize(void)
1281{ 717{
1282 free_all_buffers(); 718 printf("turbostat: topology changed, re-initializing.\n");
1283 setup_all_buffers(); 719 free_all_counters();
1284 printf("turbostat: re-initialized with num_cpus %d\n", topo.num_cpus); 720 num_cpus = for_all_cpus(alloc_new_counters);
721 need_reinitialize = 0;
722 printf("num_cpus is now %d\n", num_cpus);
1285} 723}
1286 724
1287 725void dummy(int pkg, int core, int cpu) { return; }
1288/* 726/*
1289 * count_cpus() 727 * check to see if a cpu came on-line
1290 * remember the last one seen, it will be the max
1291 */ 728 */
1292int count_cpus(int cpu) 729void verify_num_cpus(void)
1293{ 730{
1294 if (topo.max_cpu_num < cpu) 731 int new_num_cpus;
1295 topo.max_cpu_num = cpu;
1296 732
1297 topo.num_cpus += 1; 733 new_num_cpus = for_all_cpus(dummy);
1298 return 0; 734
1299} 735 if (new_num_cpus != num_cpus) {
1300int mark_cpu_present(int cpu) 736 if (verbose)
1301{ 737 printf("num_cpus was %d, is now %d\n",
1302 CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set); 738 num_cpus, new_num_cpus);
1303 return 0; 739 need_reinitialize = 1;
740 }
1304} 741}
1305 742
1306void turbostat_loop() 743void turbostat_loop()
1307{ 744{
1308 int retval;
1309 int restarted = 0;
1310
1311restart: 745restart:
1312 restarted++; 746 get_counters(cnt_even);
1313
1314 retval = for_all_cpus(get_counters, EVEN_COUNTERS);
1315 if (retval < -1) {
1316 exit(retval);
1317 } else if (retval == -1) {
1318 if (restarted > 1) {
1319 exit(retval);
1320 }
1321 re_initialize();
1322 goto restart;
1323 }
1324 restarted = 0;
1325 gettimeofday(&tv_even, (struct timezone *)NULL); 747 gettimeofday(&tv_even, (struct timezone *)NULL);
1326 748
1327 while (1) { 749 while (1) {
1328 if (for_all_proc_cpus(cpu_is_not_present)) { 750 verify_num_cpus();
751 if (need_reinitialize) {
1329 re_initialize(); 752 re_initialize();
1330 goto restart; 753 goto restart;
1331 } 754 }
1332 sleep(interval_sec); 755 sleep(interval_sec);
1333 retval = for_all_cpus(get_counters, ODD_COUNTERS); 756 get_counters(cnt_odd);
1334 if (retval < -1) {
1335 exit(retval);
1336 } else if (retval == -1) {
1337 re_initialize();
1338 goto restart;
1339 }
1340 gettimeofday(&tv_odd, (struct timezone *)NULL); 757 gettimeofday(&tv_odd, (struct timezone *)NULL);
758
759 compute_delta(cnt_odd, cnt_even, cnt_delta);
1341 timersub(&tv_odd, &tv_even, &tv_delta); 760 timersub(&tv_odd, &tv_even, &tv_delta);
1342 for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS); 761 compute_average(cnt_delta, cnt_average);
1343 compute_average(EVEN_COUNTERS); 762 print_counters(cnt_delta);
1344 format_all_counters(EVEN_COUNTERS); 763 if (need_reinitialize) {
1345 flush_stdout();
1346 sleep(interval_sec);
1347 retval = for_all_cpus(get_counters, EVEN_COUNTERS);
1348 if (retval < -1) {
1349 exit(retval);
1350 } else if (retval == -1) {
1351 re_initialize(); 764 re_initialize();
1352 goto restart; 765 goto restart;
1353 } 766 }
767 sleep(interval_sec);
768 get_counters(cnt_even);
1354 gettimeofday(&tv_even, (struct timezone *)NULL); 769 gettimeofday(&tv_even, (struct timezone *)NULL);
770 compute_delta(cnt_even, cnt_odd, cnt_delta);
1355 timersub(&tv_even, &tv_odd, &tv_delta); 771 timersub(&tv_even, &tv_odd, &tv_delta);
1356 for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS); 772 compute_average(cnt_delta, cnt_average);
1357 compute_average(ODD_COUNTERS); 773 print_counters(cnt_delta);
1358 format_all_counters(ODD_COUNTERS);
1359 flush_stdout();
1360 } 774 }
1361} 775}
1362 776
@@ -1395,8 +809,6 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
1395 case 0x2C: /* Westmere EP - Gulftown */ 809 case 0x2C: /* Westmere EP - Gulftown */
1396 case 0x2A: /* SNB */ 810 case 0x2A: /* SNB */
1397 case 0x2D: /* SNB Xeon */ 811 case 0x2D: /* SNB Xeon */
1398 case 0x3A: /* IVB */
1399 case 0x3E: /* IVB Xeon */
1400 return 1; 812 return 1;
1401 case 0x2E: /* Nehalem-EX Xeon - Beckton */ 813 case 0x2E: /* Nehalem-EX Xeon - Beckton */
1402 case 0x2F: /* Westmere-EX Xeon - Eagleton */ 814 case 0x2F: /* Westmere-EX Xeon - Eagleton */
@@ -1404,315 +816,6 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
1404 return 0; 816 return 0;
1405 } 817 }
1406} 818}
1407int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
1408{
1409 if (!genuine_intel)
1410 return 0;
1411
1412 if (family != 6)
1413 return 0;
1414
1415 switch (model) {
1416 case 0x3E: /* IVB Xeon */
1417 return 1;
1418 default:
1419 return 0;
1420 }
1421}
1422
1423/*
1424 * print_epb()
1425 * Decode the ENERGY_PERF_BIAS MSR
1426 */
1427int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1428{
1429 unsigned long long msr;
1430 char *epb_string;
1431 int cpu;
1432
1433 if (!has_epb)
1434 return 0;
1435
1436 cpu = t->cpu_id;
1437
1438 /* EPB is per-package */
1439 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1440 return 0;
1441
1442 if (cpu_migrate(cpu)) {
1443 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1444 return -1;
1445 }
1446
1447 if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr))
1448 return 0;
1449
1450 switch (msr & 0x7) {
1451 case ENERGY_PERF_BIAS_PERFORMANCE:
1452 epb_string = "performance";
1453 break;
1454 case ENERGY_PERF_BIAS_NORMAL:
1455 epb_string = "balanced";
1456 break;
1457 case ENERGY_PERF_BIAS_POWERSAVE:
1458 epb_string = "powersave";
1459 break;
1460 default:
1461 epb_string = "custom";
1462 break;
1463 }
1464 fprintf(stderr, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string);
1465
1466 return 0;
1467}
1468
1469#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */
1470#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */
1471
1472/*
1473 * rapl_probe()
1474 *
1475 * sets do_rapl
1476 */
1477void rapl_probe(unsigned int family, unsigned int model)
1478{
1479 unsigned long long msr;
1480 double tdp;
1481
1482 if (!genuine_intel)
1483 return;
1484
1485 if (family != 6)
1486 return;
1487
1488 switch (model) {
1489 case 0x2A:
1490 case 0x3A:
1491 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX;
1492 break;
1493 case 0x2D:
1494 case 0x3E:
1495 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS;
1496 break;
1497 default:
1498 return;
1499 }
1500
1501 /* units on package 0, verify later other packages match */
1502 if (get_msr(0, MSR_RAPL_POWER_UNIT, &msr))
1503 return;
1504
1505 rapl_power_units = 1.0 / (1 << (msr & 0xF));
1506 rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
1507 rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF));
1508
1509 /* get TDP to determine energy counter range */
1510 if (get_msr(0, MSR_PKG_POWER_INFO, &msr))
1511 return;
1512
1513 tdp = ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
1514
1515 rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
1516
1517 if (verbose)
1518 fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range\n", rapl_joule_counter_range);
1519
1520 return;
1521}
1522
1523int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1524{
1525 unsigned long long msr;
1526 unsigned int dts;
1527 int cpu;
1528
1529 if (!(do_dts || do_ptm))
1530 return 0;
1531
1532 cpu = t->cpu_id;
1533
1534 /* DTS is per-core, no need to print for each thread */
1535 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
1536 return 0;
1537
1538 if (cpu_migrate(cpu)) {
1539 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1540 return -1;
1541 }
1542
1543 if (do_ptm && (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) {
1544 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
1545 return 0;
1546
1547 dts = (msr >> 16) & 0x7F;
1548 fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
1549 cpu, msr, tcc_activation_temp - dts);
1550
1551#ifdef THERM_DEBUG
1552 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr))
1553 return 0;
1554
1555 dts = (msr >> 16) & 0x7F;
1556 dts2 = (msr >> 8) & 0x7F;
1557 fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
1558 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
1559#endif
1560 }
1561
1562
1563 if (do_dts) {
1564 unsigned int resolution;
1565
1566 if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
1567 return 0;
1568
1569 dts = (msr >> 16) & 0x7F;
1570 resolution = (msr >> 27) & 0xF;
1571 fprintf(stderr, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
1572 cpu, msr, tcc_activation_temp - dts, resolution);
1573
1574#ifdef THERM_DEBUG
1575 if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr))
1576 return 0;
1577
1578 dts = (msr >> 16) & 0x7F;
1579 dts2 = (msr >> 8) & 0x7F;
1580 fprintf(stderr, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
1581 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
1582#endif
1583 }
1584
1585 return 0;
1586}
1587
1588void print_power_limit_msr(int cpu, unsigned long long msr, char *label)
1589{
1590 fprintf(stderr, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n",
1591 cpu, label,
1592 ((msr >> 15) & 1) ? "EN" : "DIS",
1593 ((msr >> 0) & 0x7FFF) * rapl_power_units,
1594 (1.0 + (((msr >> 22) & 0x3)/4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units,
1595 (((msr >> 16) & 1) ? "EN" : "DIS"));
1596
1597 return;
1598}
1599
1600int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1601{
1602 unsigned long long msr;
1603 int cpu;
1604 double local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units;
1605
1606 if (!do_rapl)
1607 return 0;
1608
1609 /* RAPL counters are per package, so print only for 1st thread/package */
1610 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1611 return 0;
1612
1613 cpu = t->cpu_id;
1614 if (cpu_migrate(cpu)) {
1615 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1616 return -1;
1617 }
1618
1619 if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
1620 return -1;
1621
1622 local_rapl_power_units = 1.0 / (1 << (msr & 0xF));
1623 local_rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
1624 local_rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF));
1625
1626 if (local_rapl_power_units != rapl_power_units)
1627 fprintf(stderr, "cpu%d, ERROR: Power units mis-match\n", cpu);
1628 if (local_rapl_energy_units != rapl_energy_units)
1629 fprintf(stderr, "cpu%d, ERROR: Energy units mis-match\n", cpu);
1630 if (local_rapl_time_units != rapl_time_units)
1631 fprintf(stderr, "cpu%d, ERROR: Time units mis-match\n", cpu);
1632
1633 if (verbose) {
1634 fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "
1635 "(%f Watts, %f Joules, %f sec.)\n", cpu, msr,
1636 local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units);
1637 }
1638 if (do_rapl & RAPL_PKG) {
1639 if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr))
1640 return -5;
1641
1642
1643 fprintf(stderr, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
1644 cpu, msr,
1645 ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1646 ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1647 ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1648 ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
1649
1650 if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr))
1651 return -9;
1652
1653 fprintf(stderr, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n",
1654 cpu, msr, (msr >> 63) & 1 ? "": "UN");
1655
1656 print_power_limit_msr(cpu, msr, "PKG Limit #1");
1657 fprintf(stderr, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n",
1658 cpu,
1659 ((msr >> 47) & 1) ? "EN" : "DIS",
1660 ((msr >> 32) & 0x7FFF) * rapl_power_units,
1661 (1.0 + (((msr >> 54) & 0x3)/4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units,
1662 ((msr >> 48) & 1) ? "EN" : "DIS");
1663 }
1664
1665 if (do_rapl & RAPL_DRAM) {
1666 if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr))
1667 return -6;
1668
1669
1670 fprintf(stderr, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
1671 cpu, msr,
1672 ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1673 ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1674 ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1675 ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
1676
1677
1678 if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr))
1679 return -9;
1680 fprintf(stderr, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n",
1681 cpu, msr, (msr >> 31) & 1 ? "": "UN");
1682
1683 print_power_limit_msr(cpu, msr, "DRAM Limit");
1684 }
1685 if (do_rapl & RAPL_CORES) {
1686 if (verbose) {
1687 if (get_msr(cpu, MSR_PP0_POLICY, &msr))
1688 return -7;
1689
1690 fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
1691
1692 if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr))
1693 return -9;
1694 fprintf(stderr, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n",
1695 cpu, msr, (msr >> 31) & 1 ? "": "UN");
1696 print_power_limit_msr(cpu, msr, "Cores Limit");
1697 }
1698 }
1699 if (do_rapl & RAPL_GFX) {
1700 if (verbose) {
1701 if (get_msr(cpu, MSR_PP1_POLICY, &msr))
1702 return -8;
1703
1704 fprintf(stderr, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF);
1705
1706 if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr))
1707 return -9;
1708 fprintf(stderr, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n",
1709 cpu, msr, (msr >> 31) & 1 ? "": "UN");
1710 print_power_limit_msr(cpu, msr, "GFX Limit");
1711 }
1712 }
1713 return 0;
1714}
1715
1716 819
1717int is_snb(unsigned int family, unsigned int model) 820int is_snb(unsigned int family, unsigned int model)
1718{ 821{
@@ -1722,8 +825,6 @@ int is_snb(unsigned int family, unsigned int model)
1722 switch (model) { 825 switch (model) {
1723 case 0x2A: 826 case 0x2A:
1724 case 0x2D: 827 case 0x2D:
1725 case 0x3A: /* IVB */
1726 case 0x3E: /* IVB Xeon */
1727 return 1; 828 return 1;
1728 } 829 }
1729 return 0; 830 return 0;
@@ -1737,72 +838,6 @@ double discover_bclk(unsigned int family, unsigned int model)
1737 return 133.33; 838 return 133.33;
1738} 839}
1739 840
1740/*
1741 * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where
1742 * the Thermal Control Circuit (TCC) activates.
1743 * This is usually equal to tjMax.
1744 *
1745 * Older processors do not have this MSR, so there we guess,
1746 * but also allow cmdline over-ride with -T.
1747 *
1748 * Several MSR temperature values are in units of degrees-C
1749 * below this value, including the Digital Thermal Sensor (DTS),
1750 * Package Thermal Management Sensor (PTM), and thermal event thresholds.
1751 */
1752int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1753{
1754 unsigned long long msr;
1755 unsigned int target_c_local;
1756 int cpu;
1757
1758 /* tcc_activation_temp is used only for dts or ptm */
1759 if (!(do_dts || do_ptm))
1760 return 0;
1761
1762 /* this is a per-package concept */
1763 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1764 return 0;
1765
1766 cpu = t->cpu_id;
1767 if (cpu_migrate(cpu)) {
1768 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1769 return -1;
1770 }
1771
1772 if (tcc_activation_temp_override != 0) {
1773 tcc_activation_temp = tcc_activation_temp_override;
1774 fprintf(stderr, "cpu%d: Using cmdline TCC Target (%d C)\n",
1775 cpu, tcc_activation_temp);
1776 return 0;
1777 }
1778
1779 /* Temperature Target MSR is Nehalem and newer only */
1780 if (!do_nehalem_platform_info)
1781 goto guess;
1782
1783 if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))
1784 goto guess;
1785
1786 target_c_local = (msr >> 16) & 0x7F;
1787
1788 if (verbose)
1789 fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
1790 cpu, msr, target_c_local);
1791
1792 if (target_c_local < 85 || target_c_local > 120)
1793 goto guess;
1794
1795 tcc_activation_temp = target_c_local;
1796
1797 return 0;
1798
1799guess:
1800 tcc_activation_temp = TJMAX_DEFAULT;
1801 fprintf(stderr, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n",
1802 cpu, tcc_activation_temp);
1803
1804 return 0;
1805}
1806void check_cpuid() 841void check_cpuid()
1807{ 842{
1808 unsigned int eax, ebx, ecx, edx, max_level; 843 unsigned int eax, ebx, ecx, edx, max_level;
@@ -1816,7 +851,7 @@ void check_cpuid()
1816 genuine_intel = 1; 851 genuine_intel = 1;
1817 852
1818 if (verbose) 853 if (verbose)
1819 fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", 854 fprintf(stderr, "%.4s%.4s%.4s ",
1820 (char *)&ebx, (char *)&edx, (char *)&ecx); 855 (char *)&ebx, (char *)&edx, (char *)&ecx);
1821 856
1822 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); 857 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
@@ -1867,19 +902,10 @@ void check_cpuid()
1867 902
1868 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); 903 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
1869 has_aperf = ecx & (1 << 0); 904 has_aperf = ecx & (1 << 0);
1870 do_dts = eax & (1 << 0); 905 if (!has_aperf) {
1871 do_ptm = eax & (1 << 6); 906 fprintf(stderr, "No APERF MSR\n");
1872 has_epb = ecx & (1 << 3); 907 exit(1);
1873 908 }
1874 if (verbose)
1875 fprintf(stderr, "CPUID(6): %s%s%s%s\n",
1876 has_aperf ? "APERF" : "No APERF!",
1877 do_dts ? ", DTS" : "",
1878 do_ptm ? ", PTM": "",
1879 has_epb ? ", EPB": "");
1880
1881 if (!has_aperf)
1882 exit(-1);
1883 909
1884 do_nehalem_platform_info = genuine_intel && has_invariant_tsc; 910 do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
1885 do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ 911 do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
@@ -1887,16 +913,12 @@ void check_cpuid()
1887 bclk = discover_bclk(family, model); 913 bclk = discover_bclk(family, model);
1888 914
1889 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); 915 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
1890 do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model);
1891 rapl_probe(family, model);
1892
1893 return;
1894} 916}
1895 917
1896 918
1897void usage() 919void usage()
1898{ 920{
1899 fprintf(stderr, "%s: [-v][-R][-T][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", 921 fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
1900 progname); 922 progname);
1901 exit(1); 923 exit(1);
1902} 924}
@@ -1919,208 +941,6 @@ int open_dev_cpu_msr(int dummy1)
1919 return 0; 941 return 0;
1920} 942}
1921 943
1922void topology_probe()
1923{
1924 int i;
1925 int max_core_id = 0;
1926 int max_package_id = 0;
1927 int max_siblings = 0;
1928 struct cpu_topology {
1929 int core_id;
1930 int physical_package_id;
1931 } *cpus;
1932
1933 /* Initialize num_cpus, max_cpu_num */
1934 topo.num_cpus = 0;
1935 topo.max_cpu_num = 0;
1936 for_all_proc_cpus(count_cpus);
1937 if (!summary_only && topo.num_cpus > 1)
1938 show_cpu = 1;
1939
1940 if (verbose > 1)
1941 fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num);
1942
1943 cpus = calloc(1, (topo.max_cpu_num + 1) * sizeof(struct cpu_topology));
1944 if (cpus == NULL) {
1945 perror("calloc cpus");
1946 exit(1);
1947 }
1948
1949 /*
1950 * Allocate and initialize cpu_present_set
1951 */
1952 cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1));
1953 if (cpu_present_set == NULL) {
1954 perror("CPU_ALLOC");
1955 exit(3);
1956 }
1957 cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
1958 CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
1959 for_all_proc_cpus(mark_cpu_present);
1960
1961 /*
1962 * Allocate and initialize cpu_affinity_set
1963 */
1964 cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1));
1965 if (cpu_affinity_set == NULL) {
1966 perror("CPU_ALLOC");
1967 exit(3);
1968 }
1969 cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
1970 CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set);
1971
1972
1973 /*
1974 * For online cpus
1975 * find max_core_id, max_package_id
1976 */
1977 for (i = 0; i <= topo.max_cpu_num; ++i) {
1978 int siblings;
1979
1980 if (cpu_is_not_present(i)) {
1981 if (verbose > 1)
1982 fprintf(stderr, "cpu%d NOT PRESENT\n", i);
1983 continue;
1984 }
1985 cpus[i].core_id = get_core_id(i);
1986 if (cpus[i].core_id > max_core_id)
1987 max_core_id = cpus[i].core_id;
1988
1989 cpus[i].physical_package_id = get_physical_package_id(i);
1990 if (cpus[i].physical_package_id > max_package_id)
1991 max_package_id = cpus[i].physical_package_id;
1992
1993 siblings = get_num_ht_siblings(i);
1994 if (siblings > max_siblings)
1995 max_siblings = siblings;
1996 if (verbose > 1)
1997 fprintf(stderr, "cpu %d pkg %d core %d\n",
1998 i, cpus[i].physical_package_id, cpus[i].core_id);
1999 }
2000 topo.num_cores_per_pkg = max_core_id + 1;
2001 if (verbose > 1)
2002 fprintf(stderr, "max_core_id %d, sizing for %d cores per package\n",
2003 max_core_id, topo.num_cores_per_pkg);
2004 if (!summary_only && topo.num_cores_per_pkg > 1)
2005 show_core = 1;
2006
2007 topo.num_packages = max_package_id + 1;
2008 if (verbose > 1)
2009 fprintf(stderr, "max_package_id %d, sizing for %d packages\n",
2010 max_package_id, topo.num_packages);
2011 if (!summary_only && topo.num_packages > 1)
2012 show_pkg = 1;
2013
2014 topo.num_threads_per_core = max_siblings;
2015 if (verbose > 1)
2016 fprintf(stderr, "max_siblings %d\n", max_siblings);
2017
2018 free(cpus);
2019}
2020
2021void
2022allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data **p)
2023{
2024 int i;
2025
2026 *t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg *
2027 topo.num_packages, sizeof(struct thread_data));
2028 if (*t == NULL)
2029 goto error;
2030
2031 for (i = 0; i < topo.num_threads_per_core *
2032 topo.num_cores_per_pkg * topo.num_packages; i++)
2033 (*t)[i].cpu_id = -1;
2034
2035 *c = calloc(topo.num_cores_per_pkg * topo.num_packages,
2036 sizeof(struct core_data));
2037 if (*c == NULL)
2038 goto error;
2039
2040 for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++)
2041 (*c)[i].core_id = -1;
2042
2043 *p = calloc(topo.num_packages, sizeof(struct pkg_data));
2044 if (*p == NULL)
2045 goto error;
2046
2047 for (i = 0; i < topo.num_packages; i++)
2048 (*p)[i].package_id = i;
2049
2050 return;
2051error:
2052 perror("calloc counters");
2053 exit(1);
2054}
2055/*
2056 * init_counter()
2057 *
2058 * set cpu_id, core_num, pkg_num
2059 * set FIRST_THREAD_IN_CORE and FIRST_CORE_IN_PACKAGE
2060 *
2061 * increment topo.num_cores when 1st core in pkg seen
2062 */
2063void init_counter(struct thread_data *thread_base, struct core_data *core_base,
2064 struct pkg_data *pkg_base, int thread_num, int core_num,
2065 int pkg_num, int cpu_id)
2066{
2067 struct thread_data *t;
2068 struct core_data *c;
2069 struct pkg_data *p;
2070
2071 t = GET_THREAD(thread_base, thread_num, core_num, pkg_num);
2072 c = GET_CORE(core_base, core_num, pkg_num);
2073 p = GET_PKG(pkg_base, pkg_num);
2074
2075 t->cpu_id = cpu_id;
2076 if (thread_num == 0) {
2077 t->flags |= CPU_IS_FIRST_THREAD_IN_CORE;
2078 if (cpu_is_first_core_in_package(cpu_id))
2079 t->flags |= CPU_IS_FIRST_CORE_IN_PACKAGE;
2080 }
2081
2082 c->core_id = core_num;
2083 p->package_id = pkg_num;
2084}
2085
2086
2087int initialize_counters(int cpu_id)
2088{
2089 int my_thread_id, my_core_id, my_package_id;
2090
2091 my_package_id = get_physical_package_id(cpu_id);
2092 my_core_id = get_core_id(cpu_id);
2093
2094 if (cpu_is_first_sibling_in_core(cpu_id)) {
2095 my_thread_id = 0;
2096 topo.num_cores++;
2097 } else {
2098 my_thread_id = 1;
2099 }
2100
2101 init_counter(EVEN_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
2102 init_counter(ODD_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id);
2103 return 0;
2104}
2105
2106void allocate_output_buffer()
2107{
2108 output_buffer = calloc(1, (1 + topo.num_cpus) * 128);
2109 outp = output_buffer;
2110 if (outp == NULL) {
2111 perror("calloc");
2112 exit(-1);
2113 }
2114}
2115
2116void setup_all_buffers(void)
2117{
2118 topology_probe();
2119 allocate_counters(&thread_even, &core_even, &package_even);
2120 allocate_counters(&thread_odd, &core_odd, &package_odd);
2121 allocate_output_buffer();
2122 for_all_proc_cpus(initialize_counters);
2123}
2124void turbostat_init() 944void turbostat_init()
2125{ 945{
2126 check_cpuid(); 946 check_cpuid();
@@ -2128,33 +948,17 @@ void turbostat_init()
2128 check_dev_msr(); 948 check_dev_msr();
2129 check_super_user(); 949 check_super_user();
2130 950
2131 setup_all_buffers(); 951 num_cpus = for_all_cpus(alloc_new_counters);
2132 952
2133 if (verbose) 953 if (verbose)
2134 print_verbose_header(); 954 print_nehalem_info();
2135
2136 if (verbose)
2137 for_all_cpus(print_epb, ODD_COUNTERS);
2138
2139 if (verbose)
2140 for_all_cpus(print_rapl, ODD_COUNTERS);
2141
2142 for_all_cpus(set_temperature_target, ODD_COUNTERS);
2143
2144 if (verbose)
2145 for_all_cpus(print_thermal, ODD_COUNTERS);
2146} 955}
2147 956
2148int fork_it(char **argv) 957int fork_it(char **argv)
2149{ 958{
959 int retval;
2150 pid_t child_pid; 960 pid_t child_pid;
2151 int status; 961 get_counters(cnt_even);
2152
2153 status = for_all_cpus(get_counters, EVEN_COUNTERS);
2154 if (status)
2155 exit(status);
2156 /* clear affinity side-effect of get_counters() */
2157 sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
2158 gettimeofday(&tv_even, (struct timezone *)NULL); 962 gettimeofday(&tv_even, (struct timezone *)NULL);
2159 963
2160 child_pid = fork(); 964 child_pid = fork();
@@ -2162,6 +966,7 @@ int fork_it(char **argv)
2162 /* child */ 966 /* child */
2163 execvp(argv[0], argv); 967 execvp(argv[0], argv);
2164 } else { 968 } else {
969 int status;
2165 970
2166 /* parent */ 971 /* parent */
2167 if (child_pid == -1) { 972 if (child_pid == -1) {
@@ -2173,24 +978,21 @@ int fork_it(char **argv)
2173 signal(SIGQUIT, SIG_IGN); 978 signal(SIGQUIT, SIG_IGN);
2174 if (waitpid(child_pid, &status, 0) == -1) { 979 if (waitpid(child_pid, &status, 0) == -1) {
2175 perror("wait"); 980 perror("wait");
2176 exit(status); 981 exit(1);
2177 } 982 }
2178 } 983 }
2179 /* 984 get_counters(cnt_odd);
2180 * n.b. fork_it() does not check for errors from for_all_cpus()
2181 * because re-starting is problematic when forking
2182 */
2183 for_all_cpus(get_counters, ODD_COUNTERS);
2184 gettimeofday(&tv_odd, (struct timezone *)NULL); 985 gettimeofday(&tv_odd, (struct timezone *)NULL);
986 retval = compute_delta(cnt_odd, cnt_even, cnt_delta);
987
2185 timersub(&tv_odd, &tv_even, &tv_delta); 988 timersub(&tv_odd, &tv_even, &tv_delta);
2186 for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS); 989 compute_average(cnt_delta, cnt_average);
2187 compute_average(EVEN_COUNTERS); 990 if (!retval)
2188 format_all_counters(EVEN_COUNTERS); 991 print_counters(cnt_delta);
2189 flush_stderr();
2190 992
2191 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0); 993 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
2192 994
2193 return status; 995 return 0;
2194} 996}
2195 997
2196void cmdline(int argc, char **argv) 998void cmdline(int argc, char **argv)
@@ -2199,43 +1001,18 @@ void cmdline(int argc, char **argv)
2199 1001
2200 progname = argv[0]; 1002 progname = argv[0];
2201 1003
2202 while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:RT:")) != -1) { 1004 while ((opt = getopt(argc, argv, "+vi:M:")) != -1) {
2203 switch (opt) { 1005 switch (opt) {
2204 case 'p':
2205 show_core_only++;
2206 break;
2207 case 'P':
2208 show_pkg_only++;
2209 break;
2210 case 'S':
2211 summary_only++;
2212 break;
2213 case 'v': 1006 case 'v':
2214 verbose++; 1007 verbose++;
2215 break; 1008 break;
2216 case 'i': 1009 case 'i':
2217 interval_sec = atoi(optarg); 1010 interval_sec = atoi(optarg);
2218 break; 1011 break;
2219 case 'c':
2220 sscanf(optarg, "%x", &extra_delta_offset32);
2221 break;
2222 case 's':
2223 extra_delta_offset32 = 0x34; /* SMI counter */
2224 break;
2225 case 'C':
2226 sscanf(optarg, "%x", &extra_delta_offset64);
2227 break;
2228 case 'm':
2229 sscanf(optarg, "%x", &extra_msr_offset32);
2230 break;
2231 case 'M': 1012 case 'M':
2232 sscanf(optarg, "%x", &extra_msr_offset64); 1013 sscanf(optarg, "%x", &extra_msr_offset);
2233 break; 1014 if (verbose > 1)
2234 case 'R': 1015 fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
2235 rapl_verbose++;
2236 break;
2237 case 'T':
2238 tcc_activation_temp_override = atoi(optarg);
2239 break; 1016 break;
2240 default: 1017 default:
2241 usage(); 1018 usage();
@@ -2247,9 +1024,11 @@ int main(int argc, char **argv)
2247{ 1024{
2248 cmdline(argc, argv); 1025 cmdline(argc, argv);
2249 1026
2250 if (verbose) 1027 if (verbose > 1)
2251 fprintf(stderr, "turbostat v3.0 November 23, 2012" 1028 fprintf(stderr, "turbostat Dec 6, 2010"
2252 " - Len Brown <lenb@kernel.org>\n"); 1029 " - Len Brown <lenb@kernel.org>\n");
1030 if (verbose > 1)
1031 fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");
2253 1032
2254 turbostat_init(); 1033 turbostat_init();
2255 1034
diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile
index 971c9ffdcb5..f458237fdd7 100644
--- a/tools/power/x86/x86_energy_perf_policy/Makefile
+++ b/tools/power/x86/x86_energy_perf_policy/Makefile
@@ -1,10 +1,8 @@
1DESTDIR ?=
2
3x86_energy_perf_policy : x86_energy_perf_policy.c 1x86_energy_perf_policy : x86_energy_perf_policy.c
4 2
5clean : 3clean :
6 rm -f x86_energy_perf_policy 4 rm -f x86_energy_perf_policy
7 5
8install : 6install :
9 install x86_energy_perf_policy ${DESTDIR}/usr/bin/ 7 install x86_energy_perf_policy /usr/bin/
10 install x86_energy_perf_policy.8 ${DESTDIR}/usr/share/man/man8/ 8 install x86_energy_perf_policy.8 /usr/share/man/man8/
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
index 40b3e5482f8..33c5c7ee148 100644
--- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
@@ -289,7 +289,7 @@ void for_every_cpu(void (func)(int))
289 "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", 289 "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n",
290 &cpu); 290 &cpu);
291 if (retval != 1) 291 if (retval != 1)
292 break; 292 return;
293 293
294 func(cpu); 294 func(cpu);
295 } 295 }
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
deleted file mode 100644
index 2964b96aa55..00000000000
--- a/tools/scripts/Makefile.include
+++ /dev/null
@@ -1,77 +0,0 @@
1ifeq ($(origin O), command line)
2 dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),)
3 ABSOLUTE_O := $(shell cd $(O) ; pwd)
4 OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/)
5 COMMAND_O := O=$(ABSOLUTE_O)
6ifeq ($(objtree),)
7 objtree := $(O)
8endif
9endif
10
11ifneq ($(OUTPUT),)
12# check that the output directory actually exists
13OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
14$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
15endif
16
17#
18# Include saner warnings here, which can catch bugs:
19#
20EXTRA_WARNINGS := -Wbad-function-cast
21EXTRA_WARNINGS += -Wdeclaration-after-statement
22EXTRA_WARNINGS += -Wformat-security
23EXTRA_WARNINGS += -Wformat-y2k
24EXTRA_WARNINGS += -Winit-self
25EXTRA_WARNINGS += -Wmissing-declarations
26EXTRA_WARNINGS += -Wmissing-prototypes
27EXTRA_WARNINGS += -Wnested-externs
28EXTRA_WARNINGS += -Wno-system-headers
29EXTRA_WARNINGS += -Wold-style-definition
30EXTRA_WARNINGS += -Wpacked
31EXTRA_WARNINGS += -Wredundant-decls
32EXTRA_WARNINGS += -Wshadow
33EXTRA_WARNINGS += -Wstrict-aliasing=3
34EXTRA_WARNINGS += -Wstrict-prototypes
35EXTRA_WARNINGS += -Wswitch-default
36EXTRA_WARNINGS += -Wswitch-enum
37EXTRA_WARNINGS += -Wundef
38EXTRA_WARNINGS += -Wwrite-strings
39EXTRA_WARNINGS += -Wformat
40
41ifneq ($(findstring $(MAKEFLAGS), w),w)
42PRINT_DIR = --no-print-directory
43else
44NO_SUBDIR = :
45endif
46
47#
48# Define a callable command for descending to a new directory
49#
50# Call by doing: $(call descend,directory[,target])
51#
52descend = \
53 +mkdir -p $(OUTPUT)$(1) && \
54 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
55
56QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
57QUIET_SUBDIR1 =
58
59ifneq ($(findstring $(MAKEFLAGS),s),s)
60ifndef V
61 QUIET_CC = @echo ' ' CC $@;
62 QUIET_AR = @echo ' ' AR $@;
63 QUIET_LINK = @echo ' ' LINK $@;
64 QUIET_MKDIR = @echo ' ' MKDIR $@;
65 QUIET_GEN = @echo ' ' GEN $@;
66 QUIET_SUBDIR0 = +@subdir=
67 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
68 $(MAKE) $(PRINT_DIR) -C $$subdir
69 QUIET_FLEX = @echo ' ' FLEX $@;
70 QUIET_BISON = @echo ' ' BISON $@;
71
72 descend = \
73 @echo ' ' DESCEND $(1); \
74 mkdir -p $(OUTPUT)$(1) && \
75 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
76endif
77endif
diff --git a/tools/testing/fault-injection/failcmd.sh b/tools/testing/fault-injection/failcmd.sh
deleted file mode 100644
index 78a9ed7fecd..00000000000
--- a/tools/testing/fault-injection/failcmd.sh
+++ /dev/null
@@ -1,219 +0,0 @@
1#!/bin/bash
2#
3# NAME
4# failcmd.sh - run a command with injecting slab/page allocation failures
5#
6# SYNOPSIS
7# failcmd.sh --help
8# failcmd.sh [<options>] command [arguments]
9#
10# DESCRIPTION
11# Run command with injecting slab/page allocation failures by fault
12# injection.
13#
14# NOTE: you need to run this script as root.
15#
16
17usage()
18{
19 cat >&2 <<EOF
20Usage: $0 [options] command [arguments]
21
22OPTIONS
23 -p percent
24 --probability=percent
25 likelihood of failure injection, in percent.
26 Default value is 1
27
28 -t value
29 --times=value
30 specifies how many times failures may happen at most.
31 Default value is 1
32
33 --oom-kill-allocating-task=value
34 set /proc/sys/vm/oom_kill_allocating_task to specified value
35 before running the command.
36 Default value is 1
37
38 -h, --help
39 Display a usage message and exit
40
41 --interval=value, --space=value, --verbose=value, --task-filter=value,
42 --stacktrace-depth=value, --require-start=value, --require-end=value,
43 --reject-start=value, --reject-end=value, --ignore-gfp-wait=value
44 See Documentation/fault-injection/fault-injection.txt for more
45 information
46
47 failslab options:
48 --cache-filter=value
49
50 fail_page_alloc options:
51 --ignore-gfp-highmem=value, --min-order=value
52
53ENVIRONMENT
54 FAILCMD_TYPE
55 The following values for FAILCMD_TYPE are recognized:
56
57 failslab
58 inject slab allocation failures
59 fail_page_alloc
60 inject page allocation failures
61
62 If FAILCMD_TYPE is not defined, then failslab is used.
63EOF
64}
65
66if [ $UID != 0 ]; then
67 echo must be run as root >&2
68 exit 1
69fi
70
71DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3}'`
72
73if [ ! -d "$DEBUGFS" ]; then
74 echo debugfs is not mounted >&2
75 exit 1
76fi
77
78FAILCMD_TYPE=${FAILCMD_TYPE:-failslab}
79FAULTATTR=$DEBUGFS/$FAILCMD_TYPE
80
81if [ ! -d $FAULTATTR ]; then
82 echo $FAILCMD_TYPE is not available >&2
83 exit 1
84fi
85
86LONGOPTS=probability:,interval:,times:,space:,verbose:,task-filter:
87LONGOPTS=$LONGOPTS,stacktrace-depth:,require-start:,require-end:
88LONGOPTS=$LONGOPTS,reject-start:,reject-end:,oom-kill-allocating-task:,help
89
90if [ $FAILCMD_TYPE = failslab ]; then
91 LONGOPTS=$LONGOPTS,ignore-gfp-wait:,cache-filter:
92elif [ $FAILCMD_TYPE = fail_page_alloc ]; then
93 LONGOPTS=$LONGOPTS,ignore-gfp-wait:,ignore-gfp-highmem:,min-order:
94fi
95
96TEMP=`getopt -o p:i:t:s:v:h --long $LONGOPTS -n 'failcmd.sh' -- "$@"`
97
98if [ $? != 0 ]; then
99 usage
100 exit 1
101fi
102
103eval set -- "$TEMP"
104
105fault_attr_default()
106{
107 echo N > $FAULTATTR/task-filter
108 echo 0 > $FAULTATTR/probability
109 echo 1 > $FAULTATTR/times
110}
111
112fault_attr_default
113
114oom_kill_allocating_task_saved=`cat /proc/sys/vm/oom_kill_allocating_task`
115
116restore_values()
117{
118 fault_attr_default
119 echo $oom_kill_allocating_task_saved \
120 > /proc/sys/vm/oom_kill_allocating_task
121}
122
123#
124# Default options
125#
126declare -i oom_kill_allocating_task=1
127declare task_filter=Y
128declare -i probability=1
129declare -i times=1
130
131while true; do
132 case "$1" in
133 -p|--probability)
134 probability=$2
135 shift 2
136 ;;
137 -i|--interval)
138 echo $2 > $FAULTATTR/interval
139 shift 2
140 ;;
141 -t|--times)
142 times=$2
143 shift 2
144 ;;
145 -s|--space)
146 echo $2 > $FAULTATTR/space
147 shift 2
148 ;;
149 -v|--verbose)
150 echo $2 > $FAULTATTR/verbose
151 shift 2
152 ;;
153 --task-filter)
154 task_filter=$2
155 shift 2
156 ;;
157 --stacktrace-depth)
158 echo $2 > $FAULTATTR/stacktrace-depth
159 shift 2
160 ;;
161 --require-start)
162 echo $2 > $FAULTATTR/require-start
163 shift 2
164 ;;
165 --require-end)
166 echo $2 > $FAULTATTR/require-end
167 shift 2
168 ;;
169 --reject-start)
170 echo $2 > $FAULTATTR/reject-start
171 shift 2
172 ;;
173 --reject-end)
174 echo $2 > $FAULTATTR/reject-end
175 shift 2
176 ;;
177 --oom-kill-allocating-task)
178 oom_kill_allocating_task=$2
179 shift 2
180 ;;
181 --ignore-gfp-wait)
182 echo $2 > $FAULTATTR/ignore-gfp-wait
183 shift 2
184 ;;
185 --cache-filter)
186 echo $2 > $FAULTATTR/cache_filter
187 shift 2
188 ;;
189 --ignore-gfp-highmem)
190 echo $2 > $FAULTATTR/ignore-gfp-highmem
191 shift 2
192 ;;
193 --min-order)
194 echo $2 > $FAULTATTR/min-order
195 shift 2
196 ;;
197 -h|--help)
198 usage
199 exit 0
200 shift
201 ;;
202 --)
203 shift
204 break
205 ;;
206 esac
207done
208
209[ -z "$1" ] && exit 0
210
211echo $oom_kill_allocating_task > /proc/sys/vm/oom_kill_allocating_task
212echo $task_filter > $FAULTATTR/task-filter
213echo $probability > $FAULTATTR/probability
214echo $times > $FAULTATTR/times
215
216trap "restore_values" SIGINT SIGTERM EXIT
217
218cmd="echo 1 > /proc/self/make-it-fail && exec $@"
219bash -c "$cmd"
diff --git a/tools/testing/ktest/compare-ktest-sample.pl b/tools/testing/ktest/compare-ktest-sample.pl
index a373a5bfff6..9a571e71683 100755
--- a/tools/testing/ktest/compare-ktest-sample.pl
+++ b/tools/testing/ktest/compare-ktest-sample.pl
@@ -2,9 +2,7 @@
2 2
3open (IN,"ktest.pl"); 3open (IN,"ktest.pl");
4while (<IN>) { 4while (<IN>) {
5 # hashes are now used
6 if (/\$opt\{"?([A-Z].*?)(\[.*\])?"?\}/ || 5 if (/\$opt\{"?([A-Z].*?)(\[.*\])?"?\}/ ||
7 /^\s*"?([A-Z].*?)"?\s*=>\s*/ ||
8 /set_test_option\("(.*?)"/) { 6 /set_test_option\("(.*?)"/) {
9 $opt{$1} = 1; 7 $opt{$1} = 1;
10 } 8 }
@@ -13,7 +11,7 @@ close IN;
13 11
14open (IN, "sample.conf"); 12open (IN, "sample.conf");
15while (<IN>) { 13while (<IN>) {
16 if (/^\s*#?\s*([A-Z]\S*)\s*=/) { 14 if (/^\s*#?\s*(\S+)\s*=/) {
17 $samp{$1} = 1; 15 $samp{$1} = 1;
18 } 16 }
19} 17}
diff --git a/tools/testing/ktest/examples/README b/tools/testing/ktest/examples/README
deleted file mode 100644
index a12d295a09d..00000000000
--- a/tools/testing/ktest/examples/README
+++ /dev/null
@@ -1,32 +0,0 @@
1This directory contains example configs to use ktest for various tasks.
2The configs still need to be customized for your environment, but it
3is broken up by task which makes it easier to understand how to set up
4ktest.
5
6The configs are based off of real working configs but have been modified
7and commented to show more generic use cases that are more helpful for
8developers.
9
10crosstests.conf - this config shows an example of testing a git repo against
11 lots of different architectures. It only does build tests, but makes
12 it easy to compile test different archs. You can download the arch
13 cross compilers from:
14 http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
15
16test.conf - A generic example of a config. This is based on an actual config
17 used to perform real testing.
18
19kvm.conf - A example of a config that is used to test a virtual guest running
20 on a host.
21
22snowball.conf - An example config that was used to demo ktest.pl against
23 a snowball ARM board.
24
25include/ - The include directory holds default configs that can be
26 included into other configs. This is a real use example that shows how
27 to reuse configs for various machines or set ups. The files here
28 are included by other config files, where the other config files define
29 options and variables that will make the included config work for the
30 given environment.
31
32
diff --git a/tools/testing/ktest/examples/crosstests.conf b/tools/testing/ktest/examples/crosstests.conf
deleted file mode 100644
index 46736604c26..00000000000
--- a/tools/testing/ktest/examples/crosstests.conf
+++ /dev/null
@@ -1,260 +0,0 @@
1#
2# Example config for cross compiling
3#
4# In this config, it is expected that the tool chains from:
5#
6# http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
7#
8# running on a x86_64 system have been downloaded and installed into:
9#
10# /usr/local/
11#
12# such that the compiler binaries are something like:
13#
14# /usr/local/gcc-4.5.2-nolibc/mips-linux/bin/mips-linux-gcc
15#
16# Some of the archs will use gcc-4.5.1 instead of gcc-4.5.2
17# this config uses variables to differentiate them.
18#
19# Comments describe some of the options, but full descriptions of
20# options are described in the samples.conf file.
21
22# ${PWD} is defined by ktest.pl to be the directory that the user
23# was in when they executed ktest.pl. It may be better to hardcode the
24# path name here. THIS_DIR is the variable used through out the config file
25# in case you want to change it.
26
27THIS_DIR := ${PWD}
28
29# Update the BUILD_DIR option to the location of your git repo you want to test.
30BUILD_DIR = ${THIS_DIR}/linux.git
31
32# The build will go into this directory. It will be created when you run the test.
33OUTPUT_DIR = ${THIS_DIR}/cross-compile
34
35# The build will be compiled with -j8
36BUILD_OPTIONS = -j8
37
38# The test will not stop when it hits a failure.
39DIE_ON_FAILURE = 0
40
41# If you want to have ktest.pl store the failure somewhere, uncomment this option
42# and change the directory where ktest should store the failures.
43#STORE_FAILURES = ${THIS_DIR}/failures
44
45# The log file is stored in the OUTPUT_DIR called cross.log
46# If you enable this, you need to create the OUTPUT_DIR. It wont be created for you.
47LOG_FILE = ${OUTPUT_DIR}/cross.log
48
49# The log file will be cleared each time you run ktest.
50CLEAR_LOG = 1
51
52# As some archs do not build with the defconfig, they have been marked
53# to be ignored. If you want to test them anyway, change DO_FAILED to 1.
54# If a test that has been marked as DO_FAILED passes, then you should change
55# that test to be DO_DEFAULT
56
57DO_FAILED := 0
58DO_DEFAULT := 1
59
60# By setting both DO_FAILED and DO_DEFAULT to zero, you can pick a single
61# arch that you want to test. (uncomment RUN and chose your arch)
62#RUN := m32r
63
64# At the bottom of the config file exists a bisect test. You can update that
65# test and set DO_FAILED and DO_DEFAULT to zero, and uncomment this variable
66# to run the bisect on the arch.
67#RUN := bisect
68
69# By default all tests will be running gcc 4.5.2. Some tests are using 4.5.1
70# and they select that in the test.
71# Note: GCC_VER is declared as on option and not a variable ('=' instead of ':=')
72# This is important. A variable is used only in the config file and if it is set
73# it stays that way for the rest of the config file until it is change again.
74# Here we want GCC_VER to remain persistent and change for each test, as it is used in
75# the MAKE_CMD. By using '=' instead of ':=' we achieve our goal.
76
77GCC_VER = 4.5.2
78MAKE_CMD = PATH=/usr/local/gcc-${GCC_VER}-nolibc/${CROSS}/bin:$PATH CROSS_COMPILE=${CROSS}- make ARCH=${ARCH}
79
80# all tests are only doing builds.
81TEST_TYPE = build
82
83# If you want to add configs on top of the defconfig, you can add those configs into
84# the add-config file and uncomment this option. This is useful if you want to test
85# all cross compiles with PREEMPT set, or TRACING on, etc.
86#ADD_CONFIG = ${THIS_DIR}/add-config
87
88# All tests are using defconfig
89BUILD_TYPE = defconfig
90
91# The test names will have the arch and cross compiler used. This will be shown in
92# the results.
93TEST_NAME = ${ARCH} ${CROSS}
94
95# alpha
96TEST_START IF ${RUN} == alpha || ${DO_DEFAULT}
97# Notice that CROSS and ARCH are also options and not variables (again '=' instead
98# of ':='). This is because TEST_NAME and MAKE_CMD wil use them for each test.
99# Only options are available during runs. Variables are only present in parsing the
100# config file.
101CROSS = alpha-linux
102ARCH = alpha
103
104# arm
105TEST_START IF ${RUN} == arm || ${DO_DEFAULT}
106CROSS = arm-unknown-linux-gnueabi
107ARCH = arm
108
109# black fin
110TEST_START IF ${RUN} == bfin || ${DO_DEFAULT}
111CROSS = bfin-uclinux
112ARCH = blackfin
113BUILD_OPTIONS = -j8 vmlinux
114
115# cris - FAILS?
116TEST_START IF ${RUN} == cris || ${RUN} == cris64 || ${DO_FAILED}
117CROSS = cris-linux
118ARCH = cris
119
120# cris32 - not right arch?
121TEST_START IF ${RUN} == cris || ${RUN} == cris32 || ${DO_FAILED}
122CROSS = crisv32-linux
123ARCH = cris
124
125# ia64
126TEST_START IF ${RUN} == ia64 || ${DO_DEFAULT}
127CROSS = ia64-linux
128ARCH = ia64
129
130# frv
131TEST_START IF ${RUN} == frv || ${DO_FAILED}
132CROSS = frv-linux
133ARCH = frv
134GCC_VER = 4.5.1
135
136# h8300 - failed make defconfig??
137TEST_START IF ${RUN} == h8300 || ${DO_FAILED}
138CROSS = h8300-elf
139ARCH = h8300
140GCC_VER = 4.5.1
141
142# m68k fails with error?
143TEST_START IF ${RUN} == m68k || ${DO_DEFAULT}
144CROSS = m68k-linux
145ARCH = m68k
146
147# mips64
148TEST_START IF ${RUN} == mips || ${RUN} == mips64 || ${DO_DEFAULT}
149CROSS = mips64-linux
150ARCH = mips
151
152# mips32
153TEST_START IF ${RUN} == mips || ${RUN} == mips32 || ${DO_DEFAULT}
154CROSS = mips-linux
155ARCH = mips
156
157# m32r
158TEST_START IF ${RUN} == m32r || ${DO_FAILED}
159CROSS = m32r-linux
160ARCH = m32r
161GCC_VER = 4.5.1
162BUILD_OPTIONS = -j8 vmlinux
163
164# parisc64 failed?
165TEST_START IF ${RUN} == hppa || ${RUN} == hppa64 || ${DO_FAILED}
166CROSS = hppa64-linux
167ARCH = parisc
168
169# parisc
170TEST_START IF ${RUN} == hppa || ${RUN} == hppa32 || ${DO_FAILED}
171CROSS = hppa-linux
172ARCH = parisc
173
174# ppc
175TEST_START IF ${RUN} == ppc || ${RUN} == ppc32 || ${DO_DEFAULT}
176CROSS = powerpc-linux
177ARCH = powerpc
178
179# ppc64
180TEST_START IF ${RUN} == ppc || ${RUN} == ppc64 || ${DO_DEFAULT}
181CROSS = powerpc64-linux
182ARCH = powerpc
183
184# s390
185TEST_START IF ${RUN} == s390 || ${DO_DEFAULT}
186CROSS = s390x-linux
187ARCH = s390
188
189# sh
190TEST_START IF ${RUN} == sh || ${DO_DEFAULT}
191CROSS = sh4-linux
192ARCH = sh
193
194# sparc64
195TEST_START IF ${RUN} == sparc || ${RUN} == sparc64 || ${DO_DEFAULT}
196CROSS = sparc64-linux
197ARCH = sparc64
198
199# sparc
200TEST_START IF ${RUN} == sparc || ${RUN} == sparc32 || ${DO_DEFAULT}
201CROSS = sparc-linux
202ARCH = sparc
203
204# xtensa failed
205TEST_START IF ${RUN} == xtensa || ${DO_FAILED}
206CROSS = xtensa-linux
207ARCH = xtensa
208
209# UML
210TEST_START IF ${RUN} == uml || ${DO_DEFAULT}
211MAKE_CMD = make ARCH=um SUBARCH=x86_64
212ARCH = uml
213CROSS =
214
215TEST_START IF ${RUN} == x86 || ${RUN} == i386 || ${DO_DEFAULT}
216MAKE_CMD = make ARCH=i386
217ARCH = i386
218CROSS =
219
220TEST_START IF ${RUN} == x86 || ${RUN} == x86_64 || ${DO_DEFAULT}
221MAKE_CMD = make ARCH=x86_64
222ARCH = x86_64
223CROSS =
224
225#################################
226
227# This is a bisect if needed. You need to give it a MIN_CONFIG that
228# will be the config file it uses. Basically, just copy the created defconfig
229# for the arch someplace and point MIN_CONFIG to it.
230TEST_START IF ${RUN} == bisect
231MIN_CONFIG = ${THIS_DIR}/min-config
232CROSS = s390x-linux
233ARCH = s390
234TEST_TYPE = bisect
235BISECT_TYPE = build
236BISECT_GOOD = v3.1
237BISECT_BAD = v3.2
238CHECKOUT = v3.2
239
240#################################
241
242# These defaults are needed to keep ktest.pl from complaining. They are
243# ignored because the test does not go pass the build. No install or
244# booting of the target images.
245
246DEFAULTS
247MACHINE = crosstest
248SSH_USER = root
249BUILD_TARGET = cross
250TARGET_IMAGE = image
251POWER_CYCLE = cycle
252CONSOLE = console
253LOCALVERSION = version
254GRUB_MENU = grub
255
256REBOOT_ON_ERROR = 0
257POWEROFF_ON_ERROR = 0
258POWEROFF_ON_SUCCESS = 0
259REBOOT_ON_SUCCESS = 0
260
diff --git a/tools/testing/ktest/examples/include/bisect.conf b/tools/testing/ktest/examples/include/bisect.conf
deleted file mode 100644
index 009bea65bfb..00000000000
--- a/tools/testing/ktest/examples/include/bisect.conf
+++ /dev/null
@@ -1,90 +0,0 @@
1#
2# This example shows the bisect tests (git bisect and config bisect)
3#
4
5
6# The config that includes this file may define a RUN_TEST
7# variable that will tell this config what test to run.
8# (what to set the TEST option to).
9#
10DEFAULTS IF NOT DEFINED RUN_TEST
11# Requires that hackbench is in the PATH
12RUN_TEST := ${SSH} hackbench 50
13
14
15# Set TEST to 'bisect' to do a normal git bisect. You need
16# to modify the options below to make it bisect the exact
17# commits you are interested in.
18#
19TEST_START IF ${TEST} == bisect
20TEST_TYPE = bisect
21# You must set the commit that was considered good (git bisect good)
22BISECT_GOOD = v3.3
23# You must set the commit that was considered bad (git bisect bad)
24BISECT_BAD = HEAD
25# It's best to specify the branch to checkout before starting the bisect.
26CHECKOUT = origin/master
27# This can be build, boot, or test. Here we are doing a bisect
28# that requires to run a test to know if the bisect was good or bad.
29# The test should exit with 0 on good, non-zero for bad. But see
30# the BISECT_RET_* options in samples.conf to override this.
31BISECT_TYPE = test
32TEST = ${RUN_TEST}
33# It is usually a good idea to confirm that the GOOD and the BAD
34# commits are truly good and bad respectively. Having BISECT_CHECK
35# set to 1 will check both that the good commit works and the bad
36# commit fails. If you only want to check one or the other,
37# set BISECT_CHECK to 'good' or to 'bad'.
38BISECT_CHECK = 1
39#BISECT_CHECK = good
40#BISECT_CHECK = bad
41
42# Usually it's a good idea to specify the exact config you
43# want to use throughout the entire bisect. Here we placed
44# it in the directory we called ktest.pl from and named it
45# 'config-bisect'.
46MIN_CONFIG = ${THIS_DIR}/config-bisect
47# By default, if we are doing a BISECT_TYPE = test run but the
48# build or boot fails, ktest.pl will do a 'git bisect skip'.
49# Uncomment the below option to make ktest stop testing on such
50# an error.
51#BISECT_SKIP = 0
52# Now if you had BISECT_SKIP = 0 and the test fails, you can
53# examine what happened and then do 'git bisect log > /tmp/replay'
54# Set BISECT_REPLAY to /tmp/replay and ktest.pl will run the
55# 'git bisect replay /tmp/replay' before continuing the bisect test.
56#BISECT_REPLAY = /tmp/replay
57# If you used BISECT_REPLAY after the bisect test failed, you may
58# not want to continue the bisect on that commit that failed.
59# By setting BISECT_START to a new commit. ktest.pl will checkout
60# that commit after it has performed the 'git bisect replay' but
61# before it continues running the bisect test.
62#BISECT_START = 2545eb6198e7e1ec50daa0cfc64a4cdfecf24ec9
63
64# Now if you don't trust ktest.pl to make the decisions for you, then
65# set BISECT_MANUAL to 1. This will cause ktest.pl not to decide
66# if the commit was good or bad. Instead, it will ask you to tell
67# it if the current commit was good. In the mean time, you could
68# take the result, load it on any machine you want. Run several tests,
69# or whatever you feel like. Then, when you are happy, you can tell
70# ktest if you think it was good or not and ktest.pl will continue
71# the git bisect. You can even change what commit it is currently at.
72#BISECT_MANUAL = 1
73
74
75# One of the unique tests that ktest does is the config bisect.
76# Currently (which hopefully will be fixed soon), the bad config
77# must be a superset of the good config. This is because it only
78# searches for a config that causes the target to fail. If the
79# good config is not a subset of the bad config, or if the target
80# fails because of a lack of a config, then it will not find
81# the config for you.
82TEST_START IF ${TEST} == config-bisect
83TEST_TYPE = config_bisect
84# set to build, boot, test
85CONFIG_BISECT_TYPE = boot
86# Set the config that is considered bad.
87CONFIG_BISECT = ${THIS_DIR}/config-bad
88# This config is optional. By default it uses the
89# MIN_CONFIG as the good config.
90CONFIG_BISECT_GOOD = ${THIS_DIR}/config-good
diff --git a/tools/testing/ktest/examples/include/defaults.conf b/tools/testing/ktest/examples/include/defaults.conf
deleted file mode 100644
index 63a1a83f4f0..00000000000
--- a/tools/testing/ktest/examples/include/defaults.conf
+++ /dev/null
@@ -1,157 +0,0 @@
1# This file holds defaults for most the tests. It defines the options that
2# are most common to tests that are likely to be shared.
3#
4# Note, after including this file, a config file may override any option
5# with a DEFAULTS OVERRIDE section.
6#
7
8# For those cases that use the same machine to boot a 64 bit
9# and a 32 bit version. The MACHINE is the DNS name to get to the
10# box (usually different if it was 64 bit or 32 bit) but the
11# BOX here is defined as a variable that will be the name of the box
12# itself. It is useful for calling scripts that will power cycle
13# the box, as only one script needs to be created to power cycle
14# even though the box itself has multiple operating systems on it.
15# By default, BOX and MACHINE are the same.
16
17DEFAULTS IF NOT DEFINED BOX
18BOX := ${MACHINE}
19
20
21# Consider each box as 64 bit box, unless the config including this file
22# has defined BITS = 32
23
24DEFAULTS IF NOT DEFINED BITS
25BITS := 64
26
27
28DEFAULTS
29
30# THIS_DIR is used through out the configs and defaults to ${PWD} which
31# is the directory that ktest.pl was called from.
32
33THIS_DIR := ${PWD}
34
35
36# to organize your configs, having each machine save their configs
37# into a separate directly is useful.
38CONFIG_DIR := ${THIS_DIR}/configs/${MACHINE}
39
40# Reset the log before running each test.
41CLEAR_LOG = 1
42
43# As installing kernels usually requires root privilege, default the
44# user on the target as root. It is also required that the target
45# allows ssh to root from the host without asking for a password.
46
47SSH_USER = root
48
49# For accesing the machine, we will ssh to root@machine.
50SSH := ssh ${SSH_USER}@${MACHINE}
51
52# Update this. The default here is ktest will ssh to the target box
53# and run a script called 'run-test' located on that box.
54TEST = ${SSH} run-test
55
56# Point build dir to the git repo you use
57BUILD_DIR = ${THIS_DIR}/linux.git
58
59# Each machine will have its own output build directory.
60OUTPUT_DIR = ${THIS_DIR}/build/${MACHINE}
61
62# Yes this config is focused on x86 (but ktest works for other archs too)
63BUILD_TARGET = arch/x86/boot/bzImage
64TARGET_IMAGE = /boot/vmlinuz-test
65
66# have directory for the scripts to reboot and power cycle the boxes
67SCRIPTS_DIR := ${THIS_DIR}/scripts
68
69# You can have each box/machine have a script to power cycle it.
70# Name your script <box>-cycle.
71POWER_CYCLE = ${SCRIPTS_DIR}/${BOX}-cycle
72
73# This script is used to power off the box.
74POWER_OFF = ${SCRIPTS_DIR}/${BOX}-poweroff
75
76# Keep your test kernels separate from your other kernels.
77LOCALVERSION = -test
78
79# The /boot/grub/menu.lst is searched for the line:
80# title Test Kernel
81# and ktest will use that kernel to reboot into.
82# For grub2 or other boot loaders, you need to set BOOT_TYPE
83# to 'script' and define other ways to load the kernel.
84# See snowball.conf example.
85#
86GRUB_MENU = Test Kernel
87
88# The kernel build will use this option.
89BUILD_OPTIONS = -j8
90
91# Keeping the log file with the output dir is convenient.
92LOG_FILE = ${OUTPUT_DIR}/${MACHINE}.log
93
94# Each box should have their own minum configuration
95# See min-config.conf
96MIN_CONFIG = ${CONFIG_DIR}/config-min
97
98# For things like randconfigs, there may be configs you find that
99# are already broken, or there may be some configs that you always
100# want set. Uncomment ADD_CONFIG and point it to the make config files
101# that set the configs you want to keep on (or off) in your build.
102# ADD_CONFIG is usually something to add configs to all machines,
103# where as, MIN_CONFIG is specific per machine.
104#ADD_CONFIG = ${THIS_DIR}/config-broken ${THIS_DIR}/config-general
105
106# To speed up reboots for bisects and patchcheck, instead of
107# waiting 60 seconds for the console to be idle, if this line is
108# seen in the console output, ktest will know the good kernel has
109# finished rebooting and it will be able to continue the tests.
110REBOOT_SUCCESS_LINE = ${MACHINE} login:
111
112# The following is different ways to end the test.
113# by setting the variable REBOOT to: none, error, fail or
114# something else, ktest will power cycle or reboot the target box
115# at the end of the tests.
116#
117# REBOOT := none
118# Don't do anything at the end of the test.
119#
120# REBOOT := error
121# Reboot the box if ktest detects an error
122#
123# REBOOT := fail
124# Do not stop on failure, and after all tests are complete
125# power off the box (for both success and error)
126# This is good to run over a weekend and you don't want to waste
127# electricity.
128#
129
130DEFAULTS IF ${REBOOT} == none
131REBOOT_ON_SUCCESS = 0
132REBOOT_ON_ERROR = 0
133POWEROFF_ON_ERROR = 0
134POWEROFF_ON_SUCCESS = 0
135
136DEFAULTS ELSE IF ${REBOOT} == error
137REBOOT_ON_SUCCESS = 0
138REBOOT_ON_ERROR = 1
139POWEROFF_ON_ERROR = 0
140POWEROFF_ON_SUCCESS = 0
141
142DEFAULTS ELSE IF ${REBOOT} == fail
143REBOOT_ON_SUCCESS = 0
144POWEROFF_ON_ERROR = 1
145POWEROFF_ON_SUCCESS = 1
146POWEROFF_AFTER_HALT = 120
147DIE_ON_FAILURE = 0
148
149# Store the failure information into this directory
150# such as the .config, dmesg, and build log.
151STORE_FAILURES = ${THIS_DIR}/failures
152
153DEFAULTS ELSE
154REBOOT_ON_SUCCESS = 1
155REBOOT_ON_ERROR = 1
156POWEROFF_ON_ERROR = 0
157POWEROFF_ON_SUCCESS = 0
diff --git a/tools/testing/ktest/examples/include/min-config.conf b/tools/testing/ktest/examples/include/min-config.conf
deleted file mode 100644
index c703cc46d15..00000000000
--- a/tools/testing/ktest/examples/include/min-config.conf
+++ /dev/null
@@ -1,60 +0,0 @@
1#
2# This file has some examples for creating a MIN_CONFIG.
3# (A .config file that is the minimum for a machine to boot, or
4# to boot and make a network connection.)
5#
6# A MIN_CONFIG is very useful as it is the minimum configuration
7# needed to boot a given machine. You can debug someone else's
8# .config by only setting the configs in your MIN_CONFIG. The closer
9# your MIN_CONFIG is to the true minimum set of configs needed to
10# boot your machine, the closer the config you test with will be
11# to the users config that had the failure.
12#
13# The make_min_config test allows you to create a MIN_CONFIG that
14# is truly the minimum set of configs needed to boot a box.
15#
16# In this example, the final config will reside in
17# ${CONFIG_DIR}/config-new-min and ${CONFIG_DIR}/config-new-min-net.
18# Just move one to the location you have set for MIN_CONFIG.
19#
20# The first test creates a MIN_CONFIG that will be the minimum
21# configuration to boot ${MACHINE} and be able to ssh to it.
22#
23# The second test creates a MIN_CONFIG that will only boot
24# the target and most likely will not let you ssh to it. (Notice
25# how the second test uses the first test's result to continue with.
26# This is because the second test config is a subset of the first).
27#
28# The ${CONFIG_DIR}/config-skip (and -net) will hold the configs
29# that ktest.pl found would not boot the target without them set.
30# The config-new-min holds configs that ktest.pl could not test
31# directly because another config that was needed to boot the box
32# selected them. Sometimes it is possible that this file will hold
33# the true minimum configuration. You can test to see if this is
34# the case by running the boot test with BOOT_TYPE = allnoconfig and
35# setting setting the MIN_CONFIG to ${CONFIG_DIR}/config-skip. If the
36# machine still boots, then you can use the config-skip as your MIN_CONFIG.
37#
38# These tests can run for several hours (and perhaps days).
39# It's OK to kill the test with a Ctrl^C. By restarting without
40# modifying this config, ktest.pl will notice that the config-new-min(-net)
41# exists, and will use that instead as the starting point.
42# The USE_OUTPUT_MIN_CONFIG is set to 1 to keep ktest.pl from asking
43# you if you want to use the OUTPUT_MIN_CONFIG as the starting point.
44# By using the OUTPUT_MIN_CONFIG as the starting point will allow ktest.pl to
45# start almost where it left off.
46#
47TEST_START IF ${TEST} == min-config
48TEST_TYPE = make_min_config
49OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
50IGNORE_CONFIG = ${CONFIG_DIR}/config-skip-net
51MIN_CONFIG_TYPE = test
52TEST = ${SSH} echo hi
53USE_OUTPUT_MIN_CONFIG = 1
54
55TEST_START IF ${TEST} == min-config && ${MULTI}
56TEST_TYPE = make_min_config
57OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min
58IGNORE_CONFIG = ${CONFIG_DIR}/config-skip
59MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
60USE_OUTPUT_MIN_CONFIG = 1
diff --git a/tools/testing/ktest/examples/include/patchcheck.conf b/tools/testing/ktest/examples/include/patchcheck.conf
deleted file mode 100644
index 339d3e1700f..00000000000
--- a/tools/testing/ktest/examples/include/patchcheck.conf
+++ /dev/null
@@ -1,74 +0,0 @@
1# patchcheck.conf
2#
3# This contains a test that takes two git commits and will test each
4# commit between the two. The build test will look at what files the
5# commit has touched, and if any of those files produce a warning, then
6# the build will fail.
7
8
9# PATCH_START is the commit to begin with and PATCH_END is the commit
10# to end with (inclusive). This is similar to doing a git rebase -i PATCH_START~1
11# and then testing each commit and doing a git rebase --continue.
12# You can use a SHA1, a git tag, or anything that git will accept for a checkout
13
14PATCH_START := HEAD~3
15PATCH_END := HEAD
16
17# Change PATCH_CHECKOUT to be the branch you want to test. The test will
18# do a git checkout of this branch before starting. Obviously both
19# PATCH_START and PATCH_END must be in this branch (and PATCH_START must
20# be contained by PATCH_END).
21
22PATCH_CHECKOUT := test/branch
23
24# Usually it's a good idea to have a set config to use for testing individual
25# patches.
26PATCH_CONFIG := ${CONFIG_DIR}/config-patchcheck
27
28# Change PATCH_TEST to run some test for each patch. Each commit that is
29# tested, after it is built and installed on the test machine, this command
30# will be executed. Usually what is done is to ssh to the target box and
31# run some test scripts. If you just want to boot test your patches
32# comment PATCH_TEST out.
33PATCH_TEST := ${SSH} "/usr/local/bin/ktest-test-script"
34
35DEFAULTS IF DEFINED PATCH_TEST
36PATCH_TEST_TYPE := test
37
38DEFAULTS ELSE
39PATCH_TEST_TYPE := boot
40
41# If for some reason a file has a warning that one of your patches touch
42# but you do not care about it, set IGNORE_WARNINGS to that commit(s)
43# (space delimited)
44#IGNORE_WARNINGS = 39eaf7ef884dcc44f7ff1bac803ca2a1dcf43544 6edb2a8a385f0cdef51dae37ff23e74d76d8a6ce
45
46# If you are running a multi test, and the test failed on the first
47# test but on, say the 5th patch. If you want to restart on the
48# fifth patch, set PATCH_START1. This will make the first test start
49# from this commit instead of the PATCH_START commit.
50# Note, do not change this option. Just define PATCH_START1 in the
51# top config (the one you pass to ktest.pl), and this will use it,
52# otherwise it will just use PATCH_START if PATCH_START1 is not defined.
53DEFAULTS IF NOT DEFINED PATCH_START1
54PATCH_START1 := ${PATCH_START}
55
56TEST_START IF ${TEST} == patchcheck
57TEST_TYPE = patchcheck
58MIN_CONFIG = ${PATCH_CONFIG}
59TEST = ${PATCH_TEST}
60PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
61PATCHCHECK_START = ${PATCH_START1}
62PATCHCHECK_END = ${PATCH_END}
63CHECKOUT = ${PATCH_CHECKOUT}
64
65TEST_START IF ${TEST} == patchcheck && ${MULTI}
66TEST_TYPE = patchcheck
67MIN_CONFIG = ${PATCH_CONFIG}
68TEST = ${PATCH_TEST}
69PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
70PATCHCHECK_START = ${PATCH_START}
71PATCHCHECK_END = ${PATCH_END}
72CHECKOUT = ${PATCH_CHECKOUT}
73# Use multi to test different compilers?
74MAKE_CMD = CC=gcc-4.5.1 make
diff --git a/tools/testing/ktest/examples/include/tests.conf b/tools/testing/ktest/examples/include/tests.conf
deleted file mode 100644
index 60cedb1a115..00000000000
--- a/tools/testing/ktest/examples/include/tests.conf
+++ /dev/null
@@ -1,74 +0,0 @@
1#
2# This is an example of various tests that you can run
3#
4# The variable TEST can be of boot, build, randconfig, or test.
5#
6# Note that TEST is a variable created with ':=' and only exists
7# throughout the config processing (not during the tests itself).
8#
9# The TEST option (defined with '=') is used to tell ktest.pl
10# what test to run after a successful boot. The TEST option is
11# persistent into the test runs.
12#
13
14# The config that includes this file may define a BOOT_TYPE
15# variable that tells this config what type of boot test to run.
16# If it's not defined, the below DEFAULTS will set the default
17# to 'oldconfig'.
18#
19DEFAULTS IF NOT DEFINED BOOT_TYPE
20BOOT_TYPE := oldconfig
21
22# The config that includes this file may define a RUN_TEST
23# variable that will tell this config what test to run.
24# (what to set the TEST option to).
25#
26DEFAULTS IF NOT DEFINED RUN_TEST
27# Requires that hackbench is in the PATH
28RUN_TEST := ${SSH} hackbench 50
29
30
31# If TEST is set to 'boot' then just build a kernel and boot
32# the target.
33TEST_START IF ${TEST} == boot
34TEST_TYPE = boot
35# Notice how we set the BUILD_TYPE option to the BOOT_TYPE variable.
36BUILD_TYPE = ${BOOT_TYPE}
37# Do not do a make mrproper.
38BUILD_NOCLEAN = 1
39
40# If you only want to build the kernel, and perhaps install
41# and test it yourself, then just set TEST to build.
42TEST_START IF ${TEST} == build
43TEST_TYPE = build
44BUILD_TYPE = ${BOOT_TYPE}
45BUILD_NOCLEAN = 1
46
47# Build, install, boot and test with a randconfg 10 times.
48# It is important that you have set MIN_CONFIG in the config
49# that includes this file otherwise it is likely that the
50# randconfig will not have the necessary configs needed to
51# boot your box. This version of the test requires a min
52# config that has enough to make sure the target has network
53# working.
54TEST_START ITERATE 10 IF ${TEST} == randconfig
55MIN_CONFIG = ${CONFIG_DIR}/config-min-net
56TEST_TYPE = test
57BUILD_TYPE = randconfig
58TEST = ${RUN_TEST}
59
60# This is the same as above, but only tests to a boot prompt.
61# The MIN_CONFIG used here does not need to have networking
62# working.
63TEST_START ITERATE 10 IF ${TEST} == randconfig && ${MULTI}
64TEST_TYPE = boot
65BUILD_TYPE = randconfig
66MIN_CONFIG = ${CONFIG_DIR}/config-min
67MAKE_CMD = make
68
69# This builds, installs, boots and tests the target.
70TEST_START IF ${TEST} == test
71TEST_TYPE = test
72BUILD_TYPE = ${BOOT_TYPE}
73TEST = ${RUN_TEST}
74BUILD_NOCLEAN = 1
diff --git a/tools/testing/ktest/examples/kvm.conf b/tools/testing/ktest/examples/kvm.conf
deleted file mode 100644
index 831c7c5395f..00000000000
--- a/tools/testing/ktest/examples/kvm.conf
+++ /dev/null
@@ -1,88 +0,0 @@
1#
2# This config is an example usage of ktest.pl with a kvm guest
3#
4# The guest is called 'Guest' and this would be something that
5# could be run on the host to test a virtual machine target.
6
7MACHINE = Guest
8
9
10# Use virsh to read the serial console of the guest
11CONSOLE = virsh console ${MACHINE}
12
13#*************************************#
14# This part is the same as test.conf #
15#*************************************#
16
17# The include files will set up the type of test to run. Just set TEST to
18# which test you want to run.
19#
20# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
21#
22# See the include/*.conf files that define these tests
23#
24TEST := patchcheck
25
26# Some tests may have more than one test to run. Define MULTI := 1 to run
27# the extra tests.
28MULTI := 0
29
30# In case you want to differentiate which type of system you are testing
31BITS := 64
32
33# REBOOT = none, error, fail, empty
34# See include/defaults.conf
35REBOOT := empty
36
37
38# The defaults file will set up various settings that can be used by all
39# machine configs.
40INCLUDE include/defaults.conf
41
42
43#*************************************#
44# Now we are different from test.conf #
45#*************************************#
46
47
48# The example here assumes that Guest is running a Fedora release
49# that uses dracut for its initfs. The POST_INSTALL will be executed
50# after the install of the kernel and modules are complete.
51#
52POST_INSTALL = ${SSH} /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
53
54# Guests sometimes get stuck on reboot. We wait 3 seconds after running
55# the reboot command and then do a full power-cycle of the guest.
56# This forces the guest to restart.
57#
58POWERCYCLE_AFTER_REBOOT = 3
59
60# We do the same after the halt command, but this time we wait 20 seconds.
61POWEROFF_AFTER_HALT = 20
62
63
64# As the defaults.conf file has a POWER_CYCLE option already defined,
65# and options can not be defined in the same section more than once
66# (all DEFAULTS sections are considered the same). We use the
67# DEFAULTS OVERRIDE to tell ktest.pl to ignore the previous defined
68# options, for the options set in the OVERRIDE section.
69#
70DEFAULTS OVERRIDE
71
72# Instead of using the default POWER_CYCLE option defined in
73# defaults.conf, we use virsh to cycle it. To do so, we destroy
74# the guest, wait 5 seconds, and then start it up again.
75# Crude, but effective.
76#
77POWER_CYCLE = virsh destroy ${MACHINE}; sleep 5; virsh start ${MACHINE}
78
79
80DEFAULTS
81
82# The following files each handle a different test case.
83# Having them included allows you to set up more than one machine and share
84# the same tests.
85INCLUDE include/patchcheck.conf
86INCLUDE include/tests.conf
87INCLUDE include/bisect.conf
88INCLUDE include/min-config.conf
diff --git a/tools/testing/ktest/examples/snowball.conf b/tools/testing/ktest/examples/snowball.conf
deleted file mode 100644
index a82a3c5bc2b..00000000000
--- a/tools/testing/ktest/examples/snowball.conf
+++ /dev/null
@@ -1,53 +0,0 @@
1# This example was used to boot the snowball ARM board.
2# See http://people.redhat.com/srostedt/ktest-embedded-2012/
3
4# PWD is a ktest.pl variable that will result in the process working
5# directory that ktest.pl is executed in.
6
7# THIS_DIR is automatically assigned the PWD of the path that generated
8# the config file. It is best to use this variable when assigning other
9# directory paths within this directory. This allows you to easily
10# move the test cases to other locations or to other machines.
11#
12THIS_DIR := /home/rostedt/work/demo/ktest-embed
13LOG_FILE = ${OUTPUT_DIR}/snowball.log
14CLEAR_LOG = 1
15MAKE_CMD = PATH=/usr/local/gcc-4.5.2-nolibc/arm-unknown-linux-gnueabi/bin:$PATH CROSS_COMPILE=arm-unknown-linux-gnueabi- make ARCH=arm
16ADD_CONFIG = ${THIS_DIR}/addconfig
17
18SCP_TO_TARGET = echo "don't do scp"
19
20TFTPBOOT := /var/lib/tftpboot
21TFTPDEF := ${TFTPBOOT}/snowball-default
22TFTPTEST := ${OUTPUT_DIR}/${BUILD_TARGET}
23
24SWITCH_TO_GOOD = cp ${TFTPDEF} ${TARGET_IMAGE}
25SWITCH_TO_TEST = cp ${TFTPTEST} ${TARGET_IMAGE}
26
27# Define each test with TEST_START
28# The config options below it will override the defaults
29TEST_START SKIP
30TEST_TYPE = boot
31BUILD_TYPE = u8500_defconfig
32BUILD_NOCLEAN = 1
33
34TEST_START
35TEST_TYPE = make_min_config
36OUTPUT_MIN_CONFIG = ${THIS_DIR}/config.newmin
37START_MIN_CONFIG = ${THIS_DIR}/config.orig
38IGNORE_CONFIG = ${THIS_DIR}/config.ignore
39BUILD_NOCLEAN = 1
40
41
42DEFAULTS
43LOCALVERSION = -test
44POWER_CYCLE = echo use the thumb luke; read a
45CONSOLE = cat ${THIS_DIR}/snowball-cat
46REBOOT_TYPE = script
47SSH_USER = root
48BUILD_OPTIONS = -j8 uImage
49BUILD_DIR = ${THIS_DIR}/linux.git
50OUTPUT_DIR = ${THIS_DIR}/snowball-build
51MACHINE = snowball
52TARGET_IMAGE = /var/lib/tftpboot/snowball-image
53BUILD_TARGET = arch/arm/boot/uImage
diff --git a/tools/testing/ktest/examples/test.conf b/tools/testing/ktest/examples/test.conf
deleted file mode 100644
index b725210efb7..00000000000
--- a/tools/testing/ktest/examples/test.conf
+++ /dev/null
@@ -1,62 +0,0 @@
1#
2# Generic config for a machine
3#
4
5# Name your machine (the DNS name, what you ssh to)
6MACHINE = foo
7
8# BOX can be different than foo, if the machine BOX has
9# multiple partitions with different systems installed. For example,
10# you may have a i386 and x86_64 installation on a test box.
11# If this is the case, MACHINE defines the way to connect to the
12# machine, which may be different between which system the machine
13# is booting into. BOX is used for the scripts to reboot and power cycle
14# the machine, where it does not matter which system the machine boots into.
15#
16#BOX := bar
17
18# Define a way to read the console
19CONSOLE = stty -F /dev/ttyS0 115200 parodd; cat /dev/ttyS0
20
21# The include files will set up the type of test to run. Just set TEST to
22# which test you want to run.
23#
24# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
25#
26# See the include/*.conf files that define these tests
27#
28TEST := patchcheck
29
30# Some tests may have more than one test to run. Define MULTI := 1 to run
31# the extra tests.
32MULTI := 0
33
34# In case you want to differentiate which type of system you are testing
35BITS := 64
36
37# REBOOT = none, error, fail, empty
38# See include/defaults.conf
39REBOOT := empty
40
41# The defaults file will set up various settings that can be used by all
42# machine configs.
43INCLUDE include/defaults.conf
44
45# In case you need to add a patch for a bisect or something
46#PRE_BUILD = patch -p1 < ${THIS_DIR}/fix.patch
47
48# Reset the repo after the build and remove all 'test' modules from the target
49# Notice that DO_POST_BUILD is a variable (defined by ':=') and POST_BUILD
50# is the option (defined by '=')
51
52DO_POST_BUILD := git reset --hard
53POST_BUILD = ${SSH} 'rm -rf /lib/modules/*-test*'; ${DO_POST_BUILD}
54
55# The following files each handle a different test case.
56# Having them included allows you to set up more than one machine and share
57# the same tests.
58INCLUDE include/patchcheck.conf
59INCLUDE include/tests.conf
60INCLUDE include/bisect.conf
61INCLUDE include/min-config.conf
62
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 35fc584a4ff..8d02ccb10c5 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -18,60 +18,42 @@ $| = 1;
18my %opt; 18my %opt;
19my %repeat_tests; 19my %repeat_tests;
20my %repeats; 20my %repeats;
21my %default;
21 22
22#default opts 23#default opts
23my %default = ( 24$default{"NUM_TESTS"} = 1;
24 "NUM_TESTS" => 1, 25$default{"REBOOT_TYPE"} = "grub";
25 "TEST_TYPE" => "build", 26$default{"TEST_TYPE"} = "test";
26 "BUILD_TYPE" => "randconfig", 27$default{"BUILD_TYPE"} = "randconfig";
27 "MAKE_CMD" => "make", 28$default{"MAKE_CMD"} = "make";
28 "TIMEOUT" => 120, 29$default{"TIMEOUT"} = 120;
29 "TMP_DIR" => "/tmp/ktest/\${MACHINE}", 30$default{"TMP_DIR"} = "/tmp/ktest/\${MACHINE}";
30 "SLEEP_TIME" => 60, # sleep time between tests 31$default{"SLEEP_TIME"} = 60; # sleep time between tests
31 "BUILD_NOCLEAN" => 0, 32$default{"BUILD_NOCLEAN"} = 0;
32 "REBOOT_ON_ERROR" => 0, 33$default{"REBOOT_ON_ERROR"} = 0;
33 "POWEROFF_ON_ERROR" => 0, 34$default{"POWEROFF_ON_ERROR"} = 0;
34 "REBOOT_ON_SUCCESS" => 1, 35$default{"REBOOT_ON_SUCCESS"} = 1;
35 "POWEROFF_ON_SUCCESS" => 0, 36$default{"POWEROFF_ON_SUCCESS"} = 0;
36 "BUILD_OPTIONS" => "", 37$default{"BUILD_OPTIONS"} = "";
37 "BISECT_SLEEP_TIME" => 60, # sleep time between bisects 38$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects
38 "PATCHCHECK_SLEEP_TIME" => 60, # sleep time between patch checks 39$default{"PATCHCHECK_SLEEP_TIME"} = 60; # sleep time between patch checks
39 "CLEAR_LOG" => 0, 40$default{"CLEAR_LOG"} = 0;
40 "BISECT_MANUAL" => 0, 41$default{"BISECT_MANUAL"} = 0;
41 "BISECT_SKIP" => 1, 42$default{"BISECT_SKIP"} = 1;
42 "MIN_CONFIG_TYPE" => "boot", 43$default{"SUCCESS_LINE"} = "login:";
43 "SUCCESS_LINE" => "login:", 44$default{"DETECT_TRIPLE_FAULT"} = 1;
44 "DETECT_TRIPLE_FAULT" => 1, 45$default{"BOOTED_TIMEOUT"} = 1;
45 "NO_INSTALL" => 0, 46$default{"DIE_ON_FAILURE"} = 1;
46 "BOOTED_TIMEOUT" => 1, 47$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
47 "DIE_ON_FAILURE" => 1, 48$default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
48 "SSH_EXEC" => "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND", 49$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot";
49 "SCP_TO_TARGET" => "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE", 50$default{"STOP_AFTER_SUCCESS"} = 10;
50 "SCP_TO_TARGET_INSTALL" => "\${SCP_TO_TARGET}", 51$default{"STOP_AFTER_FAILURE"} = 60;
51 "REBOOT" => "ssh \$SSH_USER\@\$MACHINE reboot", 52$default{"STOP_TEST_AFTER"} = 600;
52 "STOP_AFTER_SUCCESS" => 10, 53$default{"LOCALVERSION"} = "-test";
53 "STOP_AFTER_FAILURE" => 60,
54 "STOP_TEST_AFTER" => 600,
55 "MAX_MONITOR_WAIT" => 1800,
56 "GRUB_REBOOT" => "grub2-reboot",
57 "SYSLINUX" => "extlinux",
58 "SYSLINUX_PATH" => "/boot/extlinux",
59
60# required, and we will ask users if they don't have them but we keep the default
61# value something that is common.
62 "REBOOT_TYPE" => "grub",
63 "LOCALVERSION" => "-test",
64 "SSH_USER" => "root",
65 "BUILD_TARGET" => "arch/x86/boot/bzImage",
66 "TARGET_IMAGE" => "/boot/vmlinuz-test",
67
68 "LOG_FILE" => undef,
69 "IGNORE_UNUSED" => 0,
70);
71 54
72my $ktest_config; 55my $ktest_config;
73my $version; 56my $version;
74my $have_version = 0;
75my $machine; 57my $machine;
76my $ssh_user; 58my $ssh_user;
77my $tmpdir; 59my $tmpdir;
@@ -81,11 +63,6 @@ my $output_config;
81my $test_type; 63my $test_type;
82my $build_type; 64my $build_type;
83my $build_options; 65my $build_options;
84my $final_post_ktest;
85my $pre_ktest;
86my $post_ktest;
87my $pre_test;
88my $post_test;
89my $pre_build; 66my $pre_build;
90my $post_build; 67my $post_build;
91my $pre_build_die; 68my $pre_build_die;
@@ -95,56 +72,35 @@ my $reboot_script;
95my $power_cycle; 72my $power_cycle;
96my $reboot; 73my $reboot;
97my $reboot_on_error; 74my $reboot_on_error;
98my $switch_to_good;
99my $switch_to_test;
100my $poweroff_on_error; 75my $poweroff_on_error;
101my $reboot_on_success;
102my $die_on_failure; 76my $die_on_failure;
103my $powercycle_after_reboot; 77my $powercycle_after_reboot;
104my $poweroff_after_halt; 78my $poweroff_after_halt;
105my $max_monitor_wait;
106my $ssh_exec; 79my $ssh_exec;
107my $scp_to_target; 80my $scp_to_target;
108my $scp_to_target_install;
109my $power_off; 81my $power_off;
110my $grub_menu; 82my $grub_menu;
111my $grub_file;
112my $grub_number; 83my $grub_number;
113my $grub_reboot;
114my $syslinux;
115my $syslinux_path;
116my $syslinux_label;
117my $target; 84my $target;
118my $make; 85my $make;
119my $pre_install;
120my $post_install; 86my $post_install;
121my $no_install;
122my $noclean; 87my $noclean;
123my $minconfig; 88my $minconfig;
124my $start_minconfig; 89my $start_minconfig;
125my $start_minconfig_defined; 90my $start_minconfig_defined;
126my $output_minconfig; 91my $output_minconfig;
127my $minconfig_type;
128my $use_output_minconfig;
129my $ignore_config; 92my $ignore_config;
130my $ignore_errors;
131my $addconfig; 93my $addconfig;
132my $in_bisect = 0; 94my $in_bisect = 0;
133my $bisect_bad_commit = ""; 95my $bisect_bad = "";
134my $reverse_bisect; 96my $reverse_bisect;
135my $bisect_manual; 97my $bisect_manual;
136my $bisect_skip; 98my $bisect_skip;
137my $config_bisect_good; 99my $config_bisect_good;
138my $bisect_ret_good;
139my $bisect_ret_bad;
140my $bisect_ret_skip;
141my $bisect_ret_abort;
142my $bisect_ret_default;
143my $in_patchcheck = 0; 100my $in_patchcheck = 0;
144my $run_test; 101my $run_test;
145my $redirect; 102my $redirect;
146my $buildlog; 103my $buildlog;
147my $testlog;
148my $dmesg; 104my $dmesg;
149my $monitor_fp; 105my $monitor_fp;
150my $monitor_pid; 106my $monitor_pid;
@@ -154,171 +110,28 @@ my $bisect_sleep_time;
154my $patchcheck_sleep_time; 110my $patchcheck_sleep_time;
155my $ignore_warnings; 111my $ignore_warnings;
156my $store_failures; 112my $store_failures;
157my $store_successes;
158my $test_name; 113my $test_name;
159my $timeout; 114my $timeout;
160my $booted_timeout; 115my $booted_timeout;
161my $detect_triplefault; 116my $detect_triplefault;
162my $console; 117my $console;
163my $reboot_success_line;
164my $success_line; 118my $success_line;
165my $stop_after_success; 119my $stop_after_success;
166my $stop_after_failure; 120my $stop_after_failure;
167my $stop_test_after; 121my $stop_test_after;
168my $build_target; 122my $build_target;
169my $target_image; 123my $target_image;
170my $checkout;
171my $localversion; 124my $localversion;
172my $iteration = 0; 125my $iteration = 0;
173my $successes = 0; 126my $successes = 0;
174 127
175my $bisect_good;
176my $bisect_bad;
177my $bisect_type;
178my $bisect_start;
179my $bisect_replay;
180my $bisect_files;
181my $bisect_reverse;
182my $bisect_check;
183
184my $config_bisect;
185my $config_bisect_type;
186my $config_bisect_check;
187
188my $patchcheck_type;
189my $patchcheck_start;
190my $patchcheck_end;
191
192# set when a test is something other that just building or install
193# which would require more options.
194my $buildonly = 1;
195
196# set when creating a new config
197my $newconfig = 0;
198
199my %entered_configs; 128my %entered_configs;
200my %config_help; 129my %config_help;
201my %variable; 130my %variable;
202
203# force_config is the list of configs that we force enabled (or disabled)
204# in a .config file. The MIN_CONFIG and ADD_CONFIG configs.
205my %force_config; 131my %force_config;
206 132
207# do not force reboots on config problems
208my $no_reboot = 1;
209
210# reboot on success
211my $reboot_success = 0;
212
213my %option_map = (
214 "MACHINE" => \$machine,
215 "SSH_USER" => \$ssh_user,
216 "TMP_DIR" => \$tmpdir,
217 "OUTPUT_DIR" => \$outputdir,
218 "BUILD_DIR" => \$builddir,
219 "TEST_TYPE" => \$test_type,
220 "PRE_KTEST" => \$pre_ktest,
221 "POST_KTEST" => \$post_ktest,
222 "PRE_TEST" => \$pre_test,
223 "POST_TEST" => \$post_test,
224 "BUILD_TYPE" => \$build_type,
225 "BUILD_OPTIONS" => \$build_options,
226 "PRE_BUILD" => \$pre_build,
227 "POST_BUILD" => \$post_build,
228 "PRE_BUILD_DIE" => \$pre_build_die,
229 "POST_BUILD_DIE" => \$post_build_die,
230 "POWER_CYCLE" => \$power_cycle,
231 "REBOOT" => \$reboot,
232 "BUILD_NOCLEAN" => \$noclean,
233 "MIN_CONFIG" => \$minconfig,
234 "OUTPUT_MIN_CONFIG" => \$output_minconfig,
235 "START_MIN_CONFIG" => \$start_minconfig,
236 "MIN_CONFIG_TYPE" => \$minconfig_type,
237 "USE_OUTPUT_MIN_CONFIG" => \$use_output_minconfig,
238 "IGNORE_CONFIG" => \$ignore_config,
239 "TEST" => \$run_test,
240 "ADD_CONFIG" => \$addconfig,
241 "REBOOT_TYPE" => \$reboot_type,
242 "GRUB_MENU" => \$grub_menu,
243 "GRUB_FILE" => \$grub_file,
244 "GRUB_REBOOT" => \$grub_reboot,
245 "SYSLINUX" => \$syslinux,
246 "SYSLINUX_PATH" => \$syslinux_path,
247 "SYSLINUX_LABEL" => \$syslinux_label,
248 "PRE_INSTALL" => \$pre_install,
249 "POST_INSTALL" => \$post_install,
250 "NO_INSTALL" => \$no_install,
251 "REBOOT_SCRIPT" => \$reboot_script,
252 "REBOOT_ON_ERROR" => \$reboot_on_error,
253 "SWITCH_TO_GOOD" => \$switch_to_good,
254 "SWITCH_TO_TEST" => \$switch_to_test,
255 "POWEROFF_ON_ERROR" => \$poweroff_on_error,
256 "REBOOT_ON_SUCCESS" => \$reboot_on_success,
257 "DIE_ON_FAILURE" => \$die_on_failure,
258 "POWER_OFF" => \$power_off,
259 "POWERCYCLE_AFTER_REBOOT" => \$powercycle_after_reboot,
260 "POWEROFF_AFTER_HALT" => \$poweroff_after_halt,
261 "MAX_MONITOR_WAIT" => \$max_monitor_wait,
262 "SLEEP_TIME" => \$sleep_time,
263 "BISECT_SLEEP_TIME" => \$bisect_sleep_time,
264 "PATCHCHECK_SLEEP_TIME" => \$patchcheck_sleep_time,
265 "IGNORE_WARNINGS" => \$ignore_warnings,
266 "IGNORE_ERRORS" => \$ignore_errors,
267 "BISECT_MANUAL" => \$bisect_manual,
268 "BISECT_SKIP" => \$bisect_skip,
269 "CONFIG_BISECT_GOOD" => \$config_bisect_good,
270 "BISECT_RET_GOOD" => \$bisect_ret_good,
271 "BISECT_RET_BAD" => \$bisect_ret_bad,
272 "BISECT_RET_SKIP" => \$bisect_ret_skip,
273 "BISECT_RET_ABORT" => \$bisect_ret_abort,
274 "BISECT_RET_DEFAULT" => \$bisect_ret_default,
275 "STORE_FAILURES" => \$store_failures,
276 "STORE_SUCCESSES" => \$store_successes,
277 "TEST_NAME" => \$test_name,
278 "TIMEOUT" => \$timeout,
279 "BOOTED_TIMEOUT" => \$booted_timeout,
280 "CONSOLE" => \$console,
281 "DETECT_TRIPLE_FAULT" => \$detect_triplefault,
282 "SUCCESS_LINE" => \$success_line,
283 "REBOOT_SUCCESS_LINE" => \$reboot_success_line,
284 "STOP_AFTER_SUCCESS" => \$stop_after_success,
285 "STOP_AFTER_FAILURE" => \$stop_after_failure,
286 "STOP_TEST_AFTER" => \$stop_test_after,
287 "BUILD_TARGET" => \$build_target,
288 "SSH_EXEC" => \$ssh_exec,
289 "SCP_TO_TARGET" => \$scp_to_target,
290 "SCP_TO_TARGET_INSTALL" => \$scp_to_target_install,
291 "CHECKOUT" => \$checkout,
292 "TARGET_IMAGE" => \$target_image,
293 "LOCALVERSION" => \$localversion,
294
295 "BISECT_GOOD" => \$bisect_good,
296 "BISECT_BAD" => \$bisect_bad,
297 "BISECT_TYPE" => \$bisect_type,
298 "BISECT_START" => \$bisect_start,
299 "BISECT_REPLAY" => \$bisect_replay,
300 "BISECT_FILES" => \$bisect_files,
301 "BISECT_REVERSE" => \$bisect_reverse,
302 "BISECT_CHECK" => \$bisect_check,
303
304 "CONFIG_BISECT" => \$config_bisect,
305 "CONFIG_BISECT_TYPE" => \$config_bisect_type,
306 "CONFIG_BISECT_CHECK" => \$config_bisect_check,
307
308 "PATCHCHECK_TYPE" => \$patchcheck_type,
309 "PATCHCHECK_START" => \$patchcheck_start,
310 "PATCHCHECK_END" => \$patchcheck_end,
311);
312
313# Options may be used by other options, record them.
314my %used_options;
315
316# default variables that can be used
317chomp ($variable{"PWD"} = `pwd`);
318
319$config_help{"MACHINE"} = << "EOF" 133$config_help{"MACHINE"} = << "EOF"
320 The machine hostname that you will test. 134 The machine hostname that you will test.
321 For build only tests, it is still needed to differentiate log files.
322EOF 135EOF
323 ; 136 ;
324$config_help{"SSH_USER"} = << "EOF" 137$config_help{"SSH_USER"} = << "EOF"
@@ -328,15 +141,11 @@ EOF
328 ; 141 ;
329$config_help{"BUILD_DIR"} = << "EOF" 142$config_help{"BUILD_DIR"} = << "EOF"
330 The directory that contains the Linux source code (full path). 143 The directory that contains the Linux source code (full path).
331 You can use \${PWD} that will be the path where ktest.pl is run, or use
332 \${THIS_DIR} which is assigned \${PWD} but may be changed later.
333EOF 144EOF
334 ; 145 ;
335$config_help{"OUTPUT_DIR"} = << "EOF" 146$config_help{"OUTPUT_DIR"} = << "EOF"
336 The directory that the objects will be built (full path). 147 The directory that the objects will be built (full path).
337 (can not be same as BUILD_DIR) 148 (can not be same as BUILD_DIR)
338 You can use \${PWD} that will be the path where ktest.pl is run, or use
339 \${THIS_DIR} which is assigned \${PWD} but may be changed later.
340EOF 149EOF
341 ; 150 ;
342$config_help{"BUILD_TARGET"} = << "EOF" 151$config_help{"BUILD_TARGET"} = << "EOF"
@@ -344,11 +153,6 @@ $config_help{"BUILD_TARGET"} = << "EOF"
344 (relative to OUTPUT_DIR) 153 (relative to OUTPUT_DIR)
345EOF 154EOF
346 ; 155 ;
347$config_help{"BUILD_OPTIONS"} = << "EOF"
348 Options to add to \"make\" when building.
349 i.e. -j20
350EOF
351 ;
352$config_help{"TARGET_IMAGE"} = << "EOF" 156$config_help{"TARGET_IMAGE"} = << "EOF"
353 The place to put your image on the test machine. 157 The place to put your image on the test machine.
354EOF 158EOF
@@ -381,7 +185,7 @@ EOF
381 ; 185 ;
382$config_help{"REBOOT_TYPE"} = << "EOF" 186$config_help{"REBOOT_TYPE"} = << "EOF"
383 Way to reboot the box to the test kernel. 187 Way to reboot the box to the test kernel.
384 Only valid options so far are "grub", "grub2", "syslinux", and "script". 188 Only valid options so far are "grub" and "script".
385 189
386 If you specify grub, it will assume grub version 1 190 If you specify grub, it will assume grub version 1
387 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU 191 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU
@@ -391,19 +195,11 @@ $config_help{"REBOOT_TYPE"} = << "EOF"
391 195
392 The entry in /boot/grub/menu.lst must be entered in manually. 196 The entry in /boot/grub/menu.lst must be entered in manually.
393 The test will not modify that file. 197 The test will not modify that file.
394
395 If you specify grub2, then you also need to specify both \$GRUB_MENU
396 and \$GRUB_FILE.
397
398 If you specify syslinux, then you may use SYSLINUX to define the syslinux
399 command (defaults to extlinux), and SYSLINUX_PATH to specify the path to
400 the syslinux install (defaults to /boot/extlinux). But you have to specify
401 SYSLINUX_LABEL to define the label to boot to for the test kernel.
402EOF 198EOF
403 ; 199 ;
404$config_help{"GRUB_MENU"} = << "EOF" 200$config_help{"GRUB_MENU"} = << "EOF"
405 The grub title name for the test kernel to boot 201 The grub title name for the test kernel to boot
406 (Only mandatory if REBOOT_TYPE = grub or grub2) 202 (Only mandatory if REBOOT_TYPE = grub)
407 203
408 Note, ktest.pl will not update the grub menu.lst, you need to 204 Note, ktest.pl will not update the grub menu.lst, you need to
409 manually add an option for the test. ktest.pl will search 205 manually add an option for the test. ktest.pl will search
@@ -414,22 +210,6 @@ $config_help{"GRUB_MENU"} = << "EOF"
414 title Test Kernel 210 title Test Kernel
415 kernel vmlinuz-test 211 kernel vmlinuz-test
416 GRUB_MENU = Test Kernel 212 GRUB_MENU = Test Kernel
417
418 For grub2, a search of \$GRUB_FILE is performed for the lines
419 that begin with "menuentry". It will not detect submenus. The
420 menu must be a non-nested menu. Add the quotes used in the menu
421 to guarantee your selection, as the first menuentry with the content
422 of \$GRUB_MENU that is found will be used.
423EOF
424 ;
425$config_help{"GRUB_FILE"} = << "EOF"
426 If grub2 is used, the full path for the grub.cfg file is placed
427 here. Use something like /boot/grub2/grub.cfg to search.
428EOF
429 ;
430$config_help{"SYSLINUX_LABEL"} = << "EOF"
431 If syslinux is used, the label that boots the target kernel must
432 be specified with SYSLINUX_LABEL.
433EOF 213EOF
434 ; 214 ;
435$config_help{"REBOOT_SCRIPT"} = << "EOF" 215$config_help{"REBOOT_SCRIPT"} = << "EOF"
@@ -438,36 +218,20 @@ $config_help{"REBOOT_SCRIPT"} = << "EOF"
438EOF 218EOF
439 ; 219 ;
440 220
441sub read_prompt { 221sub read_yn {
442 my ($cancel, $prompt) = @_; 222 my ($prompt) = @_;
443 223
444 my $ans; 224 my $ans;
445 225
446 for (;;) { 226 for (;;) {
447 if ($cancel) { 227 print "$prompt [Y/n] ";
448 print "$prompt [y/n/C] ";
449 } else {
450 print "$prompt [Y/n] ";
451 }
452 $ans = <STDIN>; 228 $ans = <STDIN>;
453 chomp $ans; 229 chomp $ans;
454 if ($ans =~ /^\s*$/) { 230 if ($ans =~ /^\s*$/) {
455 if ($cancel) { 231 $ans = "y";
456 $ans = "c";
457 } else {
458 $ans = "y";
459 }
460 } 232 }
461 last if ($ans =~ /^y$/i || $ans =~ /^n$/i); 233 last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
462 if ($cancel) { 234 print "Please answer either 'y' or 'n'.\n";
463 last if ($ans =~ /^c$/i);
464 print "Please answer either 'y', 'n' or 'c'.\n";
465 } else {
466 print "Please answer either 'y' or 'n'.\n";
467 }
468 }
469 if ($ans =~ /^c/i) {
470 exit;
471 } 235 }
472 if ($ans !~ /^y$/i) { 236 if ($ans !~ /^y$/i) {
473 return 0; 237 return 0;
@@ -475,21 +239,8 @@ sub read_prompt {
475 return 1; 239 return 1;
476} 240}
477 241
478sub read_yn {
479 my ($prompt) = @_;
480
481 return read_prompt 0, $prompt;
482}
483
484sub read_ync {
485 my ($prompt) = @_;
486
487 return read_prompt 1, $prompt;
488}
489
490sub get_ktest_config { 242sub get_ktest_config {
491 my ($config) = @_; 243 my ($config) = @_;
492 my $ans;
493 244
494 return if (defined($opt{$config})); 245 return if (defined($opt{$config}));
495 246
@@ -500,50 +251,34 @@ sub get_ktest_config {
500 251
501 for (;;) { 252 for (;;) {
502 print "$config = "; 253 print "$config = ";
503 if (defined($default{$config}) && length($default{$config})) { 254 if (defined($default{$config})) {
504 print "\[$default{$config}\] "; 255 print "\[$default{$config}\] ";
505 } 256 }
506 $ans = <STDIN>; 257 $entered_configs{$config} = <STDIN>;
507 $ans =~ s/^\s*(.*\S)\s*$/$1/; 258 $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/;
508 if ($ans =~ /^\s*$/) { 259 if ($entered_configs{$config} =~ /^\s*$/) {
509 if ($default{$config}) { 260 if ($default{$config}) {
510 $ans = $default{$config}; 261 $entered_configs{$config} = $default{$config};
511 } else { 262 } else {
512 print "Your answer can not be blank\n"; 263 print "Your answer can not be blank\n";
513 next; 264 next;
514 } 265 }
515 } 266 }
516 $entered_configs{$config} = ${ans};
517 last; 267 last;
518 } 268 }
519} 269}
520 270
521sub get_ktest_configs { 271sub get_ktest_configs {
522 get_ktest_config("MACHINE"); 272 get_ktest_config("MACHINE");
273 get_ktest_config("SSH_USER");
523 get_ktest_config("BUILD_DIR"); 274 get_ktest_config("BUILD_DIR");
524 get_ktest_config("OUTPUT_DIR"); 275 get_ktest_config("OUTPUT_DIR");
525 276 get_ktest_config("BUILD_TARGET");
526 if ($newconfig) { 277 get_ktest_config("TARGET_IMAGE");
527 get_ktest_config("BUILD_OPTIONS"); 278 get_ktest_config("POWER_CYCLE");
528 } 279 get_ktest_config("CONSOLE");
529
530 # options required for other than just building a kernel
531 if (!$buildonly) {
532 get_ktest_config("POWER_CYCLE");
533 get_ktest_config("CONSOLE");
534 }
535
536 # options required for install and more
537 if ($buildonly != 1) {
538 get_ktest_config("SSH_USER");
539 get_ktest_config("BUILD_TARGET");
540 get_ktest_config("TARGET_IMAGE");
541 }
542
543 get_ktest_config("LOCALVERSION"); 280 get_ktest_config("LOCALVERSION");
544 281
545 return if ($buildonly);
546
547 my $rtype = $opt{"REBOOT_TYPE"}; 282 my $rtype = $opt{"REBOOT_TYPE"};
548 283
549 if (!defined($rtype)) { 284 if (!defined($rtype)) {
@@ -557,20 +292,13 @@ sub get_ktest_configs {
557 292
558 if ($rtype eq "grub") { 293 if ($rtype eq "grub") {
559 get_ktest_config("GRUB_MENU"); 294 get_ktest_config("GRUB_MENU");
560 } 295 } else {
561 296 get_ktest_config("REBOOT_SCRIPT");
562 if ($rtype eq "grub2") {
563 get_ktest_config("GRUB_MENU");
564 get_ktest_config("GRUB_FILE");
565 }
566
567 if ($rtype eq "syslinux") {
568 get_ktest_config("SYSLINUX_LABEL");
569 } 297 }
570} 298}
571 299
572sub process_variables { 300sub process_variables {
573 my ($value, $remove_undef) = @_; 301 my ($value) = @_;
574 my $retval = ""; 302 my $retval = "";
575 303
576 # We want to check for '\', and it is just easier 304 # We want to check for '\', and it is just easier
@@ -588,17 +316,9 @@ sub process_variables {
588 $retval = "$retval$begin"; 316 $retval = "$retval$begin";
589 if (defined($variable{$var})) { 317 if (defined($variable{$var})) {
590 $retval = "$retval$variable{$var}"; 318 $retval = "$retval$variable{$var}";
591 } elsif (defined($remove_undef) && $remove_undef) {
592 # for if statements, any variable that is not defined,
593 # we simple convert to 0
594 $retval = "${retval}0";
595 } else { 319 } else {
596 # put back the origin piece. 320 # put back the origin piece.
597 $retval = "$retval\$\{$var\}"; 321 $retval = "$retval\$\{$var\}";
598 # This could be an option that is used later, save
599 # it so we don't warn if this option is not one of
600 # ktests options.
601 $used_options{$var} = 1;
602 } 322 }
603 $value = $end; 323 $value = $end;
604 } 324 }
@@ -611,35 +331,16 @@ sub process_variables {
611} 331}
612 332
613sub set_value { 333sub set_value {
614 my ($lvalue, $rvalue, $override, $overrides, $name) = @_; 334 my ($lvalue, $rvalue) = @_;
615
616 my $prvalue = process_variables($rvalue);
617
618 if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") {
619 # Note if a test is something other than build, then we
620 # will need other manditory options.
621 if ($prvalue ne "install") {
622 $buildonly = 0;
623 } else {
624 # install still limits some manditory options.
625 $buildonly = 2;
626 }
627 }
628 335
629 if (defined($opt{$lvalue})) { 336 if (defined($opt{$lvalue})) {
630 if (!$override || defined(${$overrides}{$lvalue})) { 337 die "Error: Option $lvalue defined more than once!\n";
631 my $extra = "";
632 if ($override) {
633 $extra = "In the same override section!\n";
634 }
635 die "$name: $.: Option $lvalue defined more than once!\n$extra";
636 }
637 ${$overrides}{$lvalue} = $prvalue;
638 } 338 }
639 if ($rvalue =~ /^\s*$/) { 339 if ($rvalue =~ /^\s*$/) {
640 delete $opt{$lvalue}; 340 delete $opt{$lvalue};
641 } else { 341 } else {
642 $opt{$lvalue} = $prvalue; 342 $rvalue = process_variables($rvalue);
343 $opt{$lvalue} = $rvalue;
643 } 344 }
644} 345}
645 346
@@ -654,280 +355,86 @@ sub set_variable {
654 } 355 }
655} 356}
656 357
657sub process_compare { 358sub read_config {
658 my ($lval, $cmp, $rval) = @_; 359 my ($config) = @_;
659
660 # remove whitespace
661
662 $lval =~ s/^\s*//;
663 $lval =~ s/\s*$//;
664
665 $rval =~ s/^\s*//;
666 $rval =~ s/\s*$//;
667
668 if ($cmp eq "==") {
669 return $lval eq $rval;
670 } elsif ($cmp eq "!=") {
671 return $lval ne $rval;
672 } elsif ($cmp eq "=~") {
673 return $lval =~ m/$rval/;
674 } elsif ($cmp eq "!~") {
675 return $lval !~ m/$rval/;
676 }
677
678 my $statement = "$lval $cmp $rval";
679 my $ret = eval $statement;
680
681 # $@ stores error of eval
682 if ($@) {
683 return -1;
684 }
685
686 return $ret;
687}
688
689sub value_defined {
690 my ($val) = @_;
691
692 return defined($variable{$2}) ||
693 defined($opt{$2});
694}
695
696my $d = 0;
697sub process_expression {
698 my ($name, $val) = @_;
699
700 my $c = $d++;
701
702 while ($val =~ s/\(([^\(]*?)\)/\&\&\&\&VAL\&\&\&\&/) {
703 my $express = $1;
704
705 if (process_expression($name, $express)) {
706 $val =~ s/\&\&\&\&VAL\&\&\&\&/ 1 /;
707 } else {
708 $val =~ s/\&\&\&\&VAL\&\&\&\&/ 0 /;
709 }
710 }
711
712 $d--;
713 my $OR = "\\|\\|";
714 my $AND = "\\&\\&";
715
716 while ($val =~ s/^(.*?)($OR|$AND)//) {
717 my $express = $1;
718 my $op = $2;
719
720 if (process_expression($name, $express)) {
721 if ($op eq "||") {
722 return 1;
723 }
724 } else {
725 if ($op eq "&&") {
726 return 0;
727 }
728 }
729 }
730
731 if ($val =~ /(.*)(==|\!=|>=|<=|>|<|=~|\!~)(.*)/) {
732 my $ret = process_compare($1, $2, $3);
733 if ($ret < 0) {
734 die "$name: $.: Unable to process comparison\n";
735 }
736 return $ret;
737 }
738
739 if ($val =~ /^\s*(NOT\s*)?DEFINED\s+(\S+)\s*$/) {
740 if (defined $1) {
741 return !value_defined($2);
742 } else {
743 return value_defined($2);
744 }
745 }
746
747 if ($val =~ /^\s*0\s*$/) {
748 return 0;
749 } elsif ($val =~ /^\s*\d+\s*$/) {
750 return 1;
751 }
752
753 die ("$name: $.: Undefined content $val in if statement\n");
754}
755
756sub process_if {
757 my ($name, $value) = @_;
758
759 # Convert variables and replace undefined ones with 0
760 my $val = process_variables($value, 1);
761 my $ret = process_expression $name, $val;
762
763 return $ret;
764}
765
766sub __read_config {
767 my ($config, $current_test_num) = @_;
768 360
769 my $in; 361 open(IN, $config) || die "can't read file $config";
770 open($in, $config) || die "can't read file $config";
771 362
772 my $name = $config; 363 my $name = $config;
773 $name =~ s,.*/(.*),$1,; 364 $name =~ s,.*/(.*),$1,;
774 365
775 my $test_num = $$current_test_num; 366 my $test_num = 0;
776 my $default = 1; 367 my $default = 1;
777 my $repeat = 1; 368 my $repeat = 1;
778 my $num_tests_set = 0; 369 my $num_tests_set = 0;
779 my $skip = 0; 370 my $skip = 0;
780 my $rest; 371 my $rest;
781 my $line;
782 my $test_case = 0; 372 my $test_case = 0;
783 my $if = 0;
784 my $if_set = 0;
785 my $override = 0;
786
787 my %overrides;
788 373
789 while (<$in>) { 374 while (<IN>) {
790 375
791 # ignore blank lines and comments 376 # ignore blank lines and comments
792 next if (/^\s*$/ || /\s*\#/); 377 next if (/^\s*$/ || /\s*\#/);
793 378
794 if (/^\s*(TEST_START|DEFAULTS)\b(.*)/) { 379 if (/^\s*TEST_START(.*)/) {
795
796 my $type = $1;
797 $rest = $2;
798 $line = $2;
799 380
800 my $old_test_num; 381 $rest = $1;
801 my $old_repeat;
802 $override = 0;
803
804 if ($type eq "TEST_START") {
805 382
806 if ($num_tests_set) { 383 if ($num_tests_set) {
807 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n"; 384 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
808 } 385 }
809 386
810 $old_test_num = $test_num; 387 my $old_test_num = $test_num;
811 $old_repeat = $repeat; 388 my $old_repeat = $repeat;
812 389
813 $test_num += $repeat; 390 $test_num += $repeat;
814 $default = 0; 391 $default = 0;
815 $repeat = 1; 392 $repeat = 1;
816 } else {
817 $default = 1;
818 }
819 393
820 # If SKIP is anywhere in the line, the command will be skipped 394 if ($rest =~ /\s+SKIP(.*)/) {
821 if ($rest =~ s/\s+SKIP\b//) { 395 $rest = $1;
822 $skip = 1; 396 $skip = 1;
823 } else { 397 } else {
824 $test_case = 1; 398 $test_case = 1;
825 $skip = 0; 399 $skip = 0;
826 } 400 }
827 401
828 if ($rest =~ s/\sELSE\b//) { 402 if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) {
829 if (!$if) { 403 $repeat = $1;
830 die "$name: $.: ELSE found with out matching IF section\n$_"; 404 $rest = $2;
831 } 405 $repeat_tests{"$test_num"} = $repeat;
832 $if = 0;
833
834 if ($if_set) {
835 $skip = 1;
836 } else {
837 $skip = 0;
838 }
839 }
840
841 if ($rest =~ s/\sIF\s+(.*)//) {
842 if (process_if($name, $1)) {
843 $if_set = 1;
844 } else {
845 $skip = 1;
846 }
847 $if = 1;
848 } else {
849 $if = 0;
850 $if_set = 0;
851 } 406 }
852 407
853 if (!$skip) { 408 if ($rest =~ /\s+SKIP(.*)/) {
854 if ($type eq "TEST_START") { 409 $rest = $1;
855 if ($rest =~ s/\s+ITERATE\s+(\d+)//) { 410 $skip = 1;
856 $repeat = $1;
857 $repeat_tests{"$test_num"} = $repeat;
858 }
859 } elsif ($rest =~ s/\sOVERRIDE\b//) {
860 # DEFAULT only
861 $override = 1;
862 # Clear previous overrides
863 %overrides = ();
864 }
865 } 411 }
866 412
867 if (!$skip && $rest !~ /^\s*$/) { 413 if ($rest !~ /^\s*$/) {
868 die "$name: $.: Gargbage found after $type\n$_"; 414 die "$name: $.: Gargbage found after TEST_START\n$_";
869 } 415 }
870 416
871 if ($skip && $type eq "TEST_START") { 417 if ($skip) {
872 $test_num = $old_test_num; 418 $test_num = $old_test_num;
873 $repeat = $old_repeat; 419 $repeat = $old_repeat;
874 } 420 }
875 421
876 } elsif (/^\s*ELSE\b(.*)$/) { 422 } elsif (/^\s*DEFAULTS(.*)$/) {
877 if (!$if) { 423 $default = 1;
878 die "$name: $.: ELSE found with out matching IF section\n$_"; 424
879 }
880 $rest = $1; 425 $rest = $1;
881 if ($if_set) { 426
427 if ($rest =~ /\s+SKIP(.*)/) {
428 $rest = $1;
882 $skip = 1; 429 $skip = 1;
883 $rest = "";
884 } else { 430 } else {
885 $skip = 0; 431 $skip = 0;
886
887 if ($rest =~ /\sIF\s+(.*)/) {
888 # May be a ELSE IF section.
889 if (process_if($name, $1)) {
890 $if_set = 1;
891 } else {
892 $skip = 1;
893 }
894 $rest = "";
895 } else {
896 $if = 0;
897 }
898 } 432 }
899 433
900 if ($rest !~ /^\s*$/) { 434 if ($rest !~ /^\s*$/) {
901 die "$name: $.: Gargbage found after DEFAULTS\n$_"; 435 die "$name: $.: Gargbage found after DEFAULTS\n$_";
902 } 436 }
903 437
904 } elsif (/^\s*INCLUDE\s+(\S+)/) {
905
906 next if ($skip);
907
908 if (!$default) {
909 die "$name: $.: INCLUDE can only be done in default sections\n$_";
910 }
911
912 my $file = process_variables($1);
913
914 if ($file !~ m,^/,) {
915 # check the path of the config file first
916 if ($config =~ m,(.*)/,) {
917 if (-f "$1/$file") {
918 $file = "$1/$file";
919 }
920 }
921 }
922
923 if ( ! -r $file ) {
924 die "$name: $.: Can't read file $file\n$_";
925 }
926
927 if (__read_config($file, \$test_num)) {
928 $test_case = 1;
929 }
930
931 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { 438 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
932 439
933 next if ($skip); 440 next if ($skip);
@@ -953,10 +460,10 @@ sub __read_config {
953 } 460 }
954 461
955 if ($default || $lvalue =~ /\[\d+\]$/) { 462 if ($default || $lvalue =~ /\[\d+\]$/) {
956 set_value($lvalue, $rvalue, $override, \%overrides, $name); 463 set_value($lvalue, $rvalue);
957 } else { 464 } else {
958 my $val = "$lvalue\[$test_num\]"; 465 my $val = "$lvalue\[$test_num\]";
959 set_value($val, $rvalue, $override, \%overrides, $name); 466 set_value($val, $rvalue);
960 467
961 if ($repeat > 1) { 468 if ($repeat > 1) {
962 $repeats{$val} = $repeat; 469 $repeats{$val} = $repeat;
@@ -983,42 +490,23 @@ sub __read_config {
983 } 490 }
984 } 491 }
985 492
493 close(IN);
494
986 if ($test_num) { 495 if ($test_num) {
987 $test_num += $repeat - 1; 496 $test_num += $repeat - 1;
988 $opt{"NUM_TESTS"} = $test_num; 497 $opt{"NUM_TESTS"} = $test_num;
989 } 498 }
990 499
991 close($in);
992
993 $$current_test_num = $test_num;
994
995 return $test_case;
996}
997
998sub get_test_case {
999 print "What test case would you like to run?\n";
1000 print " (build, install or boot)\n";
1001 print " Other tests are available but require editing the config file\n";
1002 my $ans = <STDIN>;
1003 chomp $ans;
1004 $default{"TEST_TYPE"} = $ans;
1005}
1006
1007sub read_config {
1008 my ($config) = @_;
1009
1010 my $test_case;
1011 my $test_num = 0;
1012
1013 $test_case = __read_config $config, \$test_num;
1014
1015 # make sure we have all mandatory configs 500 # make sure we have all mandatory configs
1016 get_ktest_configs; 501 get_ktest_configs;
1017 502
1018 # was a test specified? 503 # was a test specified?
1019 if (!$test_case) { 504 if (!$test_case) {
1020 print "No test case specified.\n"; 505 print "No test case specified.\n";
1021 get_test_case; 506 print "What test case would you like to run?\n";
507 my $ans = <STDIN>;
508 chomp $ans;
509 $default{"TEST_TYPE"} = $ans;
1022 } 510 }
1023 511
1024 # set any defaults 512 # set any defaults
@@ -1028,37 +516,6 @@ sub read_config {
1028 $opt{$default} = $default{$default}; 516 $opt{$default} = $default{$default};
1029 } 517 }
1030 } 518 }
1031
1032 if ($opt{"IGNORE_UNUSED"} == 1) {
1033 return;
1034 }
1035
1036 my %not_used;
1037
1038 # check if there are any stragglers (typos?)
1039 foreach my $option (keys %opt) {
1040 my $op = $option;
1041 # remove per test labels.
1042 $op =~ s/\[.*\]//;
1043 if (!exists($option_map{$op}) &&
1044 !exists($default{$op}) &&
1045 !exists($used_options{$op})) {
1046 $not_used{$op} = 1;
1047 }
1048 }
1049
1050 if (%not_used) {
1051 my $s = "s are";
1052 $s = " is" if (keys %not_used == 1);
1053 print "The following option$s not used; could be a typo:\n";
1054 foreach my $option (keys %not_used) {
1055 print "$option\n";
1056 }
1057 print "Set IGRNORE_UNUSED = 1 to have ktest ignore unused variables\n";
1058 if (!read_yn "Do you want to continue?") {
1059 exit -1;
1060 }
1061 }
1062} 519}
1063 520
1064sub __eval_option { 521sub __eval_option {
@@ -1067,18 +524,6 @@ sub __eval_option {
1067 # Add space to evaluate the character before $ 524 # Add space to evaluate the character before $
1068 $option = " $option"; 525 $option = " $option";
1069 my $retval = ""; 526 my $retval = "";
1070 my $repeated = 0;
1071 my $parent = 0;
1072
1073 foreach my $test (keys %repeat_tests) {
1074 if ($i >= $test &&
1075 $i < $test + $repeat_tests{$test}) {
1076
1077 $repeated = 1;
1078 $parent = $test;
1079 last;
1080 }
1081 }
1082 527
1083 while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) { 528 while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) {
1084 my $start = $1; 529 my $start = $1;
@@ -1092,14 +537,10 @@ sub __eval_option {
1092 # otherwise see if the default OPT (without [$i]) exists. 537 # otherwise see if the default OPT (without [$i]) exists.
1093 538
1094 my $o = "$var\[$i\]"; 539 my $o = "$var\[$i\]";
1095 my $parento = "$var\[$parent\]";
1096 540
1097 if (defined($opt{$o})) { 541 if (defined($opt{$o})) {
1098 $o = $opt{$o}; 542 $o = $opt{$o};
1099 $retval = "$retval$o"; 543 $retval = "$retval$o";
1100 } elsif ($repeated && defined($opt{$parento})) {
1101 $o = $opt{$parento};
1102 $retval = "$retval$o";
1103 } elsif (defined($opt{$var})) { 544 } elsif (defined($opt{$var})) {
1104 $o = $opt{$var}; 545 $o = $opt{$var};
1105 $retval = "$retval$o"; 546 $retval = "$retval$o";
@@ -1162,23 +603,8 @@ sub doprint {
1162} 603}
1163 604
1164sub run_command; 605sub run_command;
1165sub start_monitor;
1166sub end_monitor;
1167sub wait_for_monitor;
1168 606
1169sub reboot { 607sub reboot {
1170 my ($time) = @_;
1171
1172 # Make sure everything has been written to disk
1173 run_ssh("sync");
1174
1175 if (defined($time)) {
1176 start_monitor;
1177 # flush out current monitor
1178 # May contain the reboot success line
1179 wait_for_monitor 1;
1180 }
1181
1182 # try to reboot normally 608 # try to reboot normally
1183 if (run_command $reboot) { 609 if (run_command $reboot) {
1184 if (defined($powercycle_after_reboot)) { 610 if (defined($powercycle_after_reboot)) {
@@ -1189,31 +615,12 @@ sub reboot {
1189 # nope? power cycle it. 615 # nope? power cycle it.
1190 run_command "$power_cycle"; 616 run_command "$power_cycle";
1191 } 617 }
1192
1193 if (defined($time)) {
1194 if (wait_for_monitor($time, $reboot_success_line)) {
1195 # reboot got stuck?
1196 doprint "Reboot did not finish. Forcing power cycle\n";
1197 run_command "$power_cycle";
1198 }
1199 end_monitor;
1200 }
1201}
1202
1203sub reboot_to_good {
1204 my ($time) = @_;
1205
1206 if (defined($switch_to_good)) {
1207 run_command $switch_to_good;
1208 }
1209
1210 reboot $time;
1211} 618}
1212 619
1213sub do_not_reboot { 620sub do_not_reboot {
1214 my $i = $iteration; 621 my $i = $iteration;
1215 622
1216 return $test_type eq "build" || $no_reboot || 623 return $test_type eq "build" ||
1217 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || 624 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
1218 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); 625 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
1219} 626}
@@ -1226,7 +633,7 @@ sub dodie {
1226 if ($reboot_on_error && !do_not_reboot) { 633 if ($reboot_on_error && !do_not_reboot) {
1227 634
1228 doprint "REBOOTING\n"; 635 doprint "REBOOTING\n";
1229 reboot_to_good; 636 reboot;
1230 637
1231 } elsif ($poweroff_on_error && defined($power_off)) { 638 } elsif ($poweroff_on_error && defined($power_off)) {
1232 doprint "POWERING OFF\n"; 639 doprint "POWERING OFF\n";
@@ -1286,108 +693,21 @@ sub end_monitor {
1286} 693}
1287 694
1288sub wait_for_monitor { 695sub wait_for_monitor {
1289 my ($time, $stop) = @_; 696 my ($time) = @_;
1290 my $full_line = "";
1291 my $line; 697 my $line;
1292 my $booted = 0;
1293 my $start_time = time;
1294 my $skip_call_trace = 0;
1295 my $bug = 0;
1296 my $bug_ignored = 0;
1297 my $now;
1298 698
1299 doprint "** Wait for monitor to settle down **\n"; 699 doprint "** Wait for monitor to settle down **\n";
1300 700
1301 # read the monitor and wait for the system to calm down 701 # read the monitor and wait for the system to calm down
1302 while (!$booted) { 702 do {
1303 $line = wait_for_input($monitor_fp, $time); 703 $line = wait_for_input($monitor_fp, $time);
1304 last if (!defined($line)); 704 print "$line" if (defined($line));
1305 print "$line"; 705 } while (defined($line));
1306 $full_line .= $line;
1307
1308 if (defined($stop) && $full_line =~ /$stop/) {
1309 doprint "wait for monitor detected $stop\n";
1310 $booted = 1;
1311 }
1312
1313 if ($full_line =~ /\[ backtrace testing \]/) {
1314 $skip_call_trace = 1;
1315 }
1316
1317 if ($full_line =~ /call trace:/i) {
1318 if (!$bug && !$skip_call_trace) {
1319 if ($ignore_errors) {
1320 $bug_ignored = 1;
1321 } else {
1322 $bug = 1;
1323 }
1324 }
1325 }
1326
1327 if ($full_line =~ /\[ end of backtrace testing \]/) {
1328 $skip_call_trace = 0;
1329 }
1330
1331 if ($full_line =~ /Kernel panic -/) {
1332 $bug = 1;
1333 }
1334
1335 if ($line =~ /\n/) {
1336 $full_line = "";
1337 }
1338 $now = time;
1339 if ($now - $start_time >= $max_monitor_wait) {
1340 doprint "Exiting monitor flush due to hitting MAX_MONITOR_WAIT\n";
1341 return 1;
1342 }
1343 }
1344 print "** Monitor flushed **\n"; 706 print "** Monitor flushed **\n";
1345 return $bug;
1346}
1347
1348sub save_logs {
1349 my ($result, $basedir) = @_;
1350 my @t = localtime;
1351 my $date = sprintf "%04d%02d%02d%02d%02d%02d",
1352 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
1353
1354 my $type = $build_type;
1355 if ($type =~ /useconfig/) {
1356 $type = "useconfig";
1357 }
1358
1359 my $dir = "$machine-$test_type-$type-$result-$date";
1360
1361 $dir = "$basedir/$dir";
1362
1363 if (!-d $dir) {
1364 mkpath($dir) or
1365 die "can't create $dir";
1366 }
1367
1368 my %files = (
1369 "config" => $output_config,
1370 "buildlog" => $buildlog,
1371 "dmesg" => $dmesg,
1372 "testlog" => $testlog,
1373 );
1374
1375 while (my ($name, $source) = each(%files)) {
1376 if (-f "$source") {
1377 cp "$source", "$dir/$name" or
1378 die "failed to copy $source";
1379 }
1380 }
1381
1382 doprint "*** Saved info to $dir ***\n";
1383} 707}
1384 708
1385sub fail { 709sub fail {
1386 710
1387 if (defined($post_test)) {
1388 run_command $post_test;
1389 }
1390
1391 if ($die_on_failure) { 711 if ($die_on_failure) {
1392 dodie @_; 712 dodie @_;
1393 } 713 }
@@ -1399,7 +719,10 @@ sub fail {
1399 # no need to reboot for just building. 719 # no need to reboot for just building.
1400 if (!do_not_reboot) { 720 if (!do_not_reboot) {
1401 doprint "REBOOTING\n"; 721 doprint "REBOOTING\n";
1402 reboot_to_good $sleep_time; 722 reboot;
723 start_monitor;
724 wait_for_monitor $sleep_time;
725 end_monitor;
1403 } 726 }
1404 727
1405 my $name = ""; 728 my $name = "";
@@ -1414,9 +737,38 @@ sub fail {
1414 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 737 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
1415 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"; 738 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
1416 739
1417 if (defined($store_failures)) { 740 return 1 if (!defined($store_failures));
1418 save_logs "fail", $store_failures; 741
1419 } 742 my @t = localtime;
743 my $date = sprintf "%04d%02d%02d%02d%02d%02d",
744 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
745
746 my $type = $build_type;
747 if ($type =~ /useconfig/) {
748 $type = "useconfig";
749 }
750
751 my $dir = "$machine-$test_type-$type-fail-$date";
752 my $faildir = "$store_failures/$dir";
753
754 if (!-d $faildir) {
755 mkpath($faildir) or
756 die "can't create $faildir";
757 }
758 if (-f "$output_config") {
759 cp "$output_config", "$faildir/config" or
760 die "failed to copy .config";
761 }
762 if (-f $buildlog) {
763 cp $buildlog, "$faildir/buildlog" or
764 die "failed to move $buildlog";
765 }
766 if (-f $dmesg) {
767 cp $dmesg, "$faildir/dmesg" or
768 die "failed to move $dmesg";
769 }
770
771 doprint "*** Saved info to $faildir ***\n";
1420 772
1421 return 1; 773 return 1;
1422} 774}
@@ -1477,7 +829,8 @@ sub run_ssh {
1477} 829}
1478 830
1479sub run_scp { 831sub run_scp {
1480 my ($src, $dst, $cp_scp) = @_; 832 my ($src, $dst) = @_;
833 my $cp_scp = $scp_to_target;
1481 834
1482 $cp_scp =~ s/\$SRC_FILE/$src/g; 835 $cp_scp =~ s/\$SRC_FILE/$src/g;
1483 $cp_scp =~ s/\$DST_FILE/$dst/g; 836 $cp_scp =~ s/\$DST_FILE/$dst/g;
@@ -1485,60 +838,8 @@ sub run_scp {
1485 return run_command "$cp_scp"; 838 return run_command "$cp_scp";
1486} 839}
1487 840
1488sub run_scp_install {
1489 my ($src, $dst) = @_;
1490
1491 my $cp_scp = $scp_to_target_install;
1492
1493 return run_scp($src, $dst, $cp_scp);
1494}
1495
1496sub run_scp_mod {
1497 my ($src, $dst) = @_;
1498
1499 my $cp_scp = $scp_to_target;
1500
1501 return run_scp($src, $dst, $cp_scp);
1502}
1503
1504sub get_grub2_index {
1505
1506 return if (defined($grub_number));
1507
1508 doprint "Find grub2 menu ... ";
1509 $grub_number = -1;
1510
1511 my $ssh_grub = $ssh_exec;
1512 $ssh_grub =~ s,\$SSH_COMMAND,cat $grub_file,g;
1513
1514 open(IN, "$ssh_grub |")
1515 or die "unable to get $grub_file";
1516
1517 my $found = 0;
1518
1519 while (<IN>) {
1520 if (/^menuentry.*$grub_menu/) {
1521 $grub_number++;
1522 $found = 1;
1523 last;
1524 } elsif (/^menuentry\s/) {
1525 $grub_number++;
1526 }
1527 }
1528 close(IN);
1529
1530 die "Could not find '$grub_menu' in $grub_file on $machine"
1531 if (!$found);
1532 doprint "$grub_number\n";
1533}
1534
1535sub get_grub_index { 841sub get_grub_index {
1536 842
1537 if ($reboot_type eq "grub2") {
1538 get_grub2_index;
1539 return;
1540 }
1541
1542 if ($reboot_type ne "grub") { 843 if ($reboot_type ne "grub") {
1543 return; 844 return;
1544 } 845 }
@@ -1553,12 +854,9 @@ sub get_grub_index {
1553 open(IN, "$ssh_grub |") 854 open(IN, "$ssh_grub |")
1554 or die "unable to get menu.lst"; 855 or die "unable to get menu.lst";
1555 856
1556 my $found = 0;
1557
1558 while (<IN>) { 857 while (<IN>) {
1559 if (/^\s*title\s+$grub_menu\s*$/) { 858 if (/^\s*title\s+$grub_menu\s*$/) {
1560 $grub_number++; 859 $grub_number++;
1561 $found = 1;
1562 last; 860 last;
1563 } elsif (/^\s*title\s/) { 861 } elsif (/^\s*title\s/) {
1564 $grub_number++; 862 $grub_number++;
@@ -1567,7 +865,7 @@ sub get_grub_index {
1567 close(IN); 865 close(IN);
1568 866
1569 die "Could not find '$grub_menu' in /boot/grub/menu on $machine" 867 die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
1570 if (!$found); 868 if ($grub_number < 0);
1571 doprint "$grub_number\n"; 869 doprint "$grub_number\n";
1572} 870}
1573 871
@@ -1603,20 +901,12 @@ sub wait_for_input
1603} 901}
1604 902
1605sub reboot_to { 903sub reboot_to {
1606 if (defined($switch_to_test)) {
1607 run_command $switch_to_test;
1608 }
1609
1610 if ($reboot_type eq "grub") { 904 if ($reboot_type eq "grub") {
1611 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; 905 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'";
1612 } elsif ($reboot_type eq "grub2") { 906 return;
1613 run_ssh "$grub_reboot $grub_number";
1614 } elsif ($reboot_type eq "syslinux") {
1615 run_ssh "$syslinux --once \\\"$syslinux_label\\\" $syslinux_path";
1616 } elsif (defined $reboot_script) {
1617 run_command "$reboot_script";
1618 } 907 }
1619 reboot; 908
909 run_command "$reboot_script";
1620} 910}
1621 911
1622sub get_sha1 { 912sub get_sha1 {
@@ -1643,7 +933,6 @@ sub get_sha1 {
1643sub monitor { 933sub monitor {
1644 my $booted = 0; 934 my $booted = 0;
1645 my $bug = 0; 935 my $bug = 0;
1646 my $bug_ignored = 0;
1647 my $skip_call_trace = 0; 936 my $skip_call_trace = 0;
1648 my $loops; 937 my $loops;
1649 938
@@ -1716,12 +1005,8 @@ sub monitor {
1716 1005
1717 if ($full_line =~ /call trace:/i) { 1006 if ($full_line =~ /call trace:/i) {
1718 if (!$bug && !$skip_call_trace) { 1007 if (!$bug && !$skip_call_trace) {
1719 if ($ignore_errors) { 1008 $bug = 1;
1720 $bug_ignored = 1; 1009 $failure_start = time;
1721 } else {
1722 $bug = 1;
1723 $failure_start = time;
1724 }
1725 } 1010 }
1726 } 1011 }
1727 1012
@@ -1783,53 +1068,22 @@ sub monitor {
1783 fail "failed - never got a boot prompt." and return 0; 1068 fail "failed - never got a boot prompt." and return 0;
1784 } 1069 }
1785 1070
1786 if ($bug_ignored) {
1787 doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n";
1788 }
1789
1790 return 1; 1071 return 1;
1791} 1072}
1792 1073
1793sub eval_kernel_version {
1794 my ($option) = @_;
1795
1796 $option =~ s/\$KERNEL_VERSION/$version/g;
1797
1798 return $option;
1799}
1800
1801sub do_post_install { 1074sub do_post_install {
1802 1075
1803 return if (!defined($post_install)); 1076 return if (!defined($post_install));
1804 1077
1805 my $cp_post_install = eval_kernel_version $post_install; 1078 my $cp_post_install = $post_install;
1079 $cp_post_install =~ s/\$KERNEL_VERSION/$version/g;
1806 run_command "$cp_post_install" or 1080 run_command "$cp_post_install" or
1807 dodie "Failed to run post install"; 1081 dodie "Failed to run post install";
1808} 1082}
1809 1083
1810# Sometimes the reboot fails, and will hang. We try to ssh to the box
1811# and if we fail, we force another reboot, that should powercycle it.
1812sub test_booted {
1813 if (!run_ssh "echo testing connection") {
1814 reboot $sleep_time;
1815 }
1816}
1817
1818sub install { 1084sub install {
1819 1085
1820 return if ($no_install); 1086 run_scp "$outputdir/$build_target", "$target_image" or
1821
1822 if (defined($pre_install)) {
1823 my $cp_pre_install = eval_kernel_version $pre_install;
1824 run_command "$cp_pre_install" or
1825 dodie "Failed to run pre install";
1826 }
1827
1828 my $cp_target = eval_kernel_version $target_image;
1829
1830 test_booted;
1831
1832 run_scp_install "$outputdir/$build_target", "$cp_target" or
1833 dodie "failed to copy image"; 1087 dodie "failed to copy image";
1834 1088
1835 my $install_mods = 0; 1089 my $install_mods = 0;
@@ -1839,10 +1093,8 @@ sub install {
1839 open(IN, "$output_config") or dodie("Can't read config file"); 1093 open(IN, "$output_config") or dodie("Can't read config file");
1840 while (<IN>) { 1094 while (<IN>) {
1841 if (/CONFIG_MODULES(=y)?/) { 1095 if (/CONFIG_MODULES(=y)?/) {
1842 if (defined($1)) { 1096 $install_mods = 1 if (defined($1));
1843 $install_mods = 1; 1097 last;
1844 last;
1845 }
1846 } 1098 }
1847 } 1099 }
1848 close(IN); 1100 close(IN);
@@ -1853,7 +1105,7 @@ sub install {
1853 return; 1105 return;
1854 } 1106 }
1855 1107
1856 run_command "$make INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=$tmpdir modules_install" or 1108 run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
1857 dodie "Failed to install modules"; 1109 dodie "Failed to install modules";
1858 1110
1859 my $modlib = "/lib/modules/$version"; 1111 my $modlib = "/lib/modules/$version";
@@ -1866,7 +1118,7 @@ sub install {
1866 run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or 1118 run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
1867 dodie "making tarball"; 1119 dodie "making tarball";
1868 1120
1869 run_scp_mod "$tmpdir/$modtar", "/tmp" or 1121 run_scp "$tmpdir/$modtar", "/tmp" or
1870 dodie "failed to copy modules"; 1122 dodie "failed to copy modules";
1871 1123
1872 unlink "$tmpdir/$modtar"; 1124 unlink "$tmpdir/$modtar";
@@ -1881,20 +1133,13 @@ sub install {
1881 1133
1882sub get_version { 1134sub get_version {
1883 # get the release name 1135 # get the release name
1884 return if ($have_version);
1885 doprint "$make kernelrelease ... "; 1136 doprint "$make kernelrelease ... ";
1886 $version = `$make kernelrelease | tail -1`; 1137 $version = `$make kernelrelease | tail -1`;
1887 chomp($version); 1138 chomp($version);
1888 doprint "$version\n"; 1139 doprint "$version\n";
1889 $have_version = 1;
1890} 1140}
1891 1141
1892sub start_monitor_and_boot { 1142sub start_monitor_and_boot {
1893 # Make sure the stable kernel has finished booting
1894 start_monitor;
1895 wait_for_monitor 5;
1896 end_monitor;
1897
1898 get_grub_index; 1143 get_grub_index;
1899 get_version; 1144 get_version;
1900 install; 1145 install;
@@ -1974,16 +1219,12 @@ sub make_oldconfig {
1974 apply_min_config; 1219 apply_min_config;
1975 } 1220 }
1976 1221
1977 if (!run_command "$make olddefconfig") { 1222 if (!run_command "$make oldnoconfig") {
1978 # Perhaps olddefconfig doesn't exist in this version of the kernel 1223 # Perhaps oldnoconfig doesn't exist in this version of the kernel
1979 # try oldnoconfig 1224 # try a yes '' | oldconfig
1980 doprint "olddefconfig failed, trying make oldnoconfig\n"; 1225 doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
1981 if (!run_command "$make oldnoconfig") { 1226 run_command "yes '' | $make oldconfig" or
1982 doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; 1227 dodie "failed make config oldconfig";
1983 # try a yes '' | oldconfig
1984 run_command "yes '' | $make oldconfig" or
1985 dodie "failed make config oldconfig";
1986 }
1987 } 1228 }
1988} 1229}
1989 1230
@@ -1991,7 +1232,6 @@ sub make_oldconfig {
1991sub load_force_config { 1232sub load_force_config {
1992 my ($config) = @_; 1233 my ($config) = @_;
1993 1234
1994 doprint "Loading force configs from $config\n";
1995 open(IN, $config) or 1235 open(IN, $config) or
1996 dodie "failed to read $config"; 1236 dodie "failed to read $config";
1997 while (<IN>) { 1237 while (<IN>) {
@@ -2010,13 +1250,6 @@ sub build {
2010 1250
2011 unlink $buildlog; 1251 unlink $buildlog;
2012 1252
2013 # Failed builds should not reboot the target
2014 my $save_no_reboot = $no_reboot;
2015 $no_reboot = 1;
2016
2017 # Calculate a new version from here.
2018 $have_version = 0;
2019
2020 if (defined($pre_build)) { 1253 if (defined($pre_build)) {
2021 my $ret = run_command $pre_build; 1254 my $ret = run_command $pre_build;
2022 if (!$ret && defined($pre_build_die) && 1255 if (!$ret && defined($pre_build_die) &&
@@ -2034,21 +1267,21 @@ sub build {
2034 1267
2035 # old config can ask questions 1268 # old config can ask questions
2036 if ($type eq "oldconfig") { 1269 if ($type eq "oldconfig") {
2037 $type = "olddefconfig"; 1270 $type = "oldnoconfig";
2038 1271
2039 # allow for empty configs 1272 # allow for empty configs
2040 run_command "touch $output_config"; 1273 run_command "touch $output_config";
2041 1274
2042 if (!$noclean) { 1275 run_command "mv $output_config $outputdir/config_temp" or
2043 run_command "mv $output_config $outputdir/config_temp" or 1276 dodie "moving .config";
2044 dodie "moving .config";
2045
2046 run_command "$make mrproper" or dodie "make mrproper";
2047 1277
2048 run_command "mv $outputdir/config_temp $output_config" or 1278 if (!$noclean && !run_command "$make mrproper") {
2049 dodie "moving config_temp"; 1279 dodie "make mrproper";
2050 } 1280 }
2051 1281
1282 run_command "mv $outputdir/config_temp $output_config" or
1283 dodie "moving config_temp";
1284
2052 } elsif (!$noclean) { 1285 } elsif (!$noclean) {
2053 unlink "$output_config"; 1286 unlink "$output_config";
2054 run_command "$make mrproper" or 1287 run_command "$make mrproper" or
@@ -2064,7 +1297,7 @@ sub build {
2064 load_force_config($minconfig); 1297 load_force_config($minconfig);
2065 } 1298 }
2066 1299
2067 if ($type ne "olddefconfig") { 1300 if ($type ne "oldnoconfig") {
2068 run_command "$make $type" or 1301 run_command "$make $type" or
2069 dodie "failed make config"; 1302 dodie "failed make config";
2070 } 1303 }
@@ -2076,9 +1309,6 @@ sub build {
2076 undef $redirect; 1309 undef $redirect;
2077 1310
2078 if (defined($post_build)) { 1311 if (defined($post_build)) {
2079 # Because a post build may change the kernel version
2080 # do it now.
2081 get_version;
2082 my $ret = run_command $post_build; 1312 my $ret = run_command $post_build;
2083 if (!$ret && defined($post_build_die) && 1313 if (!$ret && defined($post_build_die) &&
2084 $post_build_die) { 1314 $post_build_die) {
@@ -2088,15 +1318,10 @@ sub build {
2088 1318
2089 if (!$build_ret) { 1319 if (!$build_ret) {
2090 # bisect may need this to pass 1320 # bisect may need this to pass
2091 if ($in_bisect) { 1321 return 0 if ($in_bisect);
2092 $no_reboot = $save_no_reboot;
2093 return 0;
2094 }
2095 fail "failed build" and return 0; 1322 fail "failed build" and return 0;
2096 } 1323 }
2097 1324
2098 $no_reboot = $save_no_reboot;
2099
2100 return 1; 1325 return 1;
2101} 1326}
2102 1327
@@ -2115,10 +1340,6 @@ sub halt {
2115sub success { 1340sub success {
2116 my ($i) = @_; 1341 my ($i) = @_;
2117 1342
2118 if (defined($post_test)) {
2119 run_command $post_test;
2120 }
2121
2122 $successes++; 1343 $successes++;
2123 1344
2124 my $name = ""; 1345 my $name = "";
@@ -2133,13 +1354,12 @@ sub success {
2133 doprint "*******************************************\n"; 1354 doprint "*******************************************\n";
2134 doprint "*******************************************\n"; 1355 doprint "*******************************************\n";
2135 1356
2136 if (defined($store_successes)) {
2137 save_logs "success", $store_successes;
2138 }
2139
2140 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) { 1357 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
2141 doprint "Reboot and wait $sleep_time seconds\n"; 1358 doprint "Reboot and wait $sleep_time seconds\n";
2142 reboot_to_good $sleep_time; 1359 reboot;
1360 start_monitor;
1361 wait_for_monitor $sleep_time;
1362 end_monitor;
2143 } 1363 }
2144} 1364}
2145 1365
@@ -2166,10 +1386,7 @@ sub child_run_test {
2166 $poweroff_on_error = 0; 1386 $poweroff_on_error = 0;
2167 $die_on_failure = 1; 1387 $die_on_failure = 1;
2168 1388
2169 $redirect = "$testlog";
2170 run_command $run_test or $failed = 1; 1389 run_command $run_test or $failed = 1;
2171 undef $redirect;
2172
2173 exit $failed; 1390 exit $failed;
2174} 1391}
2175 1392
@@ -2185,7 +1402,6 @@ sub do_run_test {
2185 my $line; 1402 my $line;
2186 my $full_line; 1403 my $full_line;
2187 my $bug = 0; 1404 my $bug = 0;
2188 my $bug_ignored = 0;
2189 1405
2190 wait_for_monitor 1; 1406 wait_for_monitor 1;
2191 1407
@@ -2210,11 +1426,7 @@ sub do_run_test {
2210 doprint $line; 1426 doprint $line;
2211 1427
2212 if ($full_line =~ /call trace:/i) { 1428 if ($full_line =~ /call trace:/i) {
2213 if ($ignore_errors) { 1429 $bug = 1;
2214 $bug_ignored = 1;
2215 } else {
2216 $bug = 1;
2217 }
2218 } 1430 }
2219 1431
2220 if ($full_line =~ /Kernel panic -/) { 1432 if ($full_line =~ /Kernel panic -/) {
@@ -2227,10 +1439,6 @@ sub do_run_test {
2227 } 1439 }
2228 } while (!$child_done && !$bug); 1440 } while (!$child_done && !$bug);
2229 1441
2230 if (!$bug && $bug_ignored) {
2231 doprint "WARNING: Call Trace detected but ignored due to IGNORE_ERRORS=1\n";
2232 }
2233
2234 if ($bug) { 1442 if ($bug) {
2235 my $failure_start = time; 1443 my $failure_start = time;
2236 my $now; 1444 my $now;
@@ -2253,43 +1461,6 @@ sub do_run_test {
2253 waitpid $child_pid, 0; 1461 waitpid $child_pid, 0;
2254 $child_exit = $?; 1462 $child_exit = $?;
2255 1463
2256 if (!$bug && $in_bisect) {
2257 if (defined($bisect_ret_good)) {
2258 if ($child_exit == $bisect_ret_good) {
2259 return 1;
2260 }
2261 }
2262 if (defined($bisect_ret_skip)) {
2263 if ($child_exit == $bisect_ret_skip) {
2264 return -1;
2265 }
2266 }
2267 if (defined($bisect_ret_abort)) {
2268 if ($child_exit == $bisect_ret_abort) {
2269 fail "test abort" and return -2;
2270 }
2271 }
2272 if (defined($bisect_ret_bad)) {
2273 if ($child_exit == $bisect_ret_skip) {
2274 return 0;
2275 }
2276 }
2277 if (defined($bisect_ret_default)) {
2278 if ($bisect_ret_default eq "good") {
2279 return 1;
2280 } elsif ($bisect_ret_default eq "bad") {
2281 return 0;
2282 } elsif ($bisect_ret_default eq "skip") {
2283 return -1;
2284 } elsif ($bisect_ret_default eq "abort") {
2285 return -2;
2286 } else {
2287 fail "unknown default action: $bisect_ret_default"
2288 and return -2;
2289 }
2290 }
2291 }
2292
2293 if ($bug || $child_exit) { 1464 if ($bug || $child_exit) {
2294 return 0 if $in_bisect; 1465 return 0 if $in_bisect;
2295 fail "test failed" and return 0; 1466 fail "test failed" and return 0;
@@ -2316,7 +1487,7 @@ sub run_git_bisect {
2316 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) { 1487 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
2317 doprint "$1 [$2]\n"; 1488 doprint "$1 [$2]\n";
2318 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) { 1489 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
2319 $bisect_bad_commit = $1; 1490 $bisect_bad = $1;
2320 doprint "Found bad commit... $1\n"; 1491 doprint "Found bad commit... $1\n";
2321 return 0; 1492 return 0;
2322 } else { 1493 } else {
@@ -2329,7 +1500,10 @@ sub run_git_bisect {
2329 1500
2330sub bisect_reboot { 1501sub bisect_reboot {
2331 doprint "Reboot and sleep $bisect_sleep_time seconds\n"; 1502 doprint "Reboot and sleep $bisect_sleep_time seconds\n";
2332 reboot_to_good $bisect_sleep_time; 1503 reboot;
1504 start_monitor;
1505 wait_for_monitor $bisect_sleep_time;
1506 end_monitor;
2333} 1507}
2334 1508
2335# returns 1 on success, 0 on failure, -1 on skip 1509# returns 1 on success, 0 on failure, -1 on skip
@@ -2400,7 +1574,7 @@ sub run_bisect {
2400 } 1574 }
2401 1575
2402 # Are we looking for where it worked, not failed? 1576 # Are we looking for where it worked, not failed?
2403 if ($reverse_bisect && $ret >= 0) { 1577 if ($reverse_bisect) {
2404 $ret = !$ret; 1578 $ret = !$ret;
2405 } 1579 }
2406 1580
@@ -2414,28 +1588,21 @@ sub run_bisect {
2414 } 1588 }
2415} 1589}
2416 1590
2417sub update_bisect_replay {
2418 my $tmp_log = "$tmpdir/ktest_bisect_log";
2419 run_command "git bisect log > $tmp_log" or
2420 die "can't create bisect log";
2421 return $tmp_log;
2422}
2423
2424sub bisect { 1591sub bisect {
2425 my ($i) = @_; 1592 my ($i) = @_;
2426 1593
2427 my $result; 1594 my $result;
2428 1595
2429 die "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); 1596 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
2430 die "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); 1597 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
2431 die "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); 1598 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
2432 1599
2433 my $good = $bisect_good; 1600 my $good = $opt{"BISECT_GOOD[$i]"};
2434 my $bad = $bisect_bad; 1601 my $bad = $opt{"BISECT_BAD[$i]"};
2435 my $type = $bisect_type; 1602 my $type = $opt{"BISECT_TYPE[$i]"};
2436 my $start = $bisect_start; 1603 my $start = $opt{"BISECT_START[$i]"};
2437 my $replay = $bisect_replay; 1604 my $replay = $opt{"BISECT_REPLAY[$i]"};
2438 my $start_files = $bisect_files; 1605 my $start_files = $opt{"BISECT_FILES[$i]"};
2439 1606
2440 if (defined($start_files)) { 1607 if (defined($start_files)) {
2441 $start_files = " -- " . $start_files; 1608 $start_files = " -- " . $start_files;
@@ -2447,7 +1614,8 @@ sub bisect {
2447 $good = get_sha1($good); 1614 $good = get_sha1($good);
2448 $bad = get_sha1($bad); 1615 $bad = get_sha1($bad);
2449 1616
2450 if (defined($bisect_reverse) && $bisect_reverse == 1) { 1617 if (defined($opt{"BISECT_REVERSE[$i]"}) &&
1618 $opt{"BISECT_REVERSE[$i]"} == 1) {
2451 doprint "Performing a reverse bisect (bad is good, good is bad!)\n"; 1619 doprint "Performing a reverse bisect (bad is good, good is bad!)\n";
2452 $reverse_bisect = 1; 1620 $reverse_bisect = 1;
2453 } else { 1621 } else {
@@ -2459,31 +1627,8 @@ sub bisect {
2459 $type = "boot"; 1627 $type = "boot";
2460 } 1628 }
2461 1629
2462 # Check if a bisect was running 1630 my $check = $opt{"BISECT_CHECK[$i]"};
2463 my $bisect_start_file = "$builddir/.git/BISECT_START"; 1631 if (defined($check) && $check ne "0") {
2464
2465 my $check = $bisect_check;
2466 my $do_check = defined($check) && $check ne "0";
2467
2468 if ( -f $bisect_start_file ) {
2469 print "Bisect in progress found\n";
2470 if ($do_check) {
2471 print " If you say yes, then no checks of good or bad will be done\n";
2472 }
2473 if (defined($replay)) {
2474 print "** BISECT_REPLAY is defined in config file **";
2475 print " Ignore config option and perform new git bisect log?\n";
2476 if (read_ync " (yes, no, or cancel) ") {
2477 $replay = update_bisect_replay;
2478 $do_check = 0;
2479 }
2480 } elsif (read_yn "read git log and continue?") {
2481 $replay = update_bisect_replay;
2482 $do_check = 0;
2483 }
2484 }
2485
2486 if ($do_check) {
2487 1632
2488 # get current HEAD 1633 # get current HEAD
2489 my $head = get_sha1("HEAD"); 1634 my $head = get_sha1("HEAD");
@@ -2548,28 +1693,14 @@ sub bisect {
2548 run_command "git bisect reset" or 1693 run_command "git bisect reset" or
2549 dodie "could not reset git bisect"; 1694 dodie "could not reset git bisect";
2550 1695
2551 doprint "Bad commit was [$bisect_bad_commit]\n"; 1696 doprint "Bad commit was [$bisect_bad]\n";
2552 1697
2553 success $i; 1698 success $i;
2554} 1699}
2555 1700
2556# config_ignore holds the configs that were set (or unset) for
2557# a good config and we will ignore these configs for the rest
2558# of a config bisect. These configs stay as they were.
2559my %config_ignore; 1701my %config_ignore;
2560
2561# config_set holds what all configs were set as.
2562my %config_set; 1702my %config_set;
2563 1703
2564# config_off holds the set of configs that the bad config had disabled.
2565# We need to record them and set them in the .config when running
2566# olddefconfig, because olddefconfig keeps the defaults.
2567my %config_off;
2568
2569# config_off_tmp holds a set of configs to turn off for now
2570my @config_off_tmp;
2571
2572# config_list is the set of configs that are being tested
2573my %config_list; 1704my %config_list;
2574my %null_config; 1705my %null_config;
2575 1706
@@ -2648,21 +1779,12 @@ sub create_config {
2648 } 1779 }
2649 } 1780 }
2650 1781
2651 # turn off configs to keep off
2652 foreach my $config (keys %config_off) {
2653 print OUT "# $config is not set\n";
2654 }
2655
2656 # turn off configs that should be off for now
2657 foreach my $config (@config_off_tmp) {
2658 print OUT "# $config is not set\n";
2659 }
2660
2661 foreach my $config (keys %config_ignore) { 1782 foreach my $config (keys %config_ignore) {
2662 print OUT "$config_ignore{$config}\n"; 1783 print OUT "$config_ignore{$config}\n";
2663 } 1784 }
2664 close(OUT); 1785 close(OUT);
2665 1786
1787# exit;
2666 make_oldconfig; 1788 make_oldconfig;
2667} 1789}
2668 1790
@@ -2727,7 +1849,7 @@ sub run_config_bisect {
2727 } 1849 }
2728 1850
2729 doprint "***** RUN TEST ***\n"; 1851 doprint "***** RUN TEST ***\n";
2730 my $type = $config_bisect_type; 1852 my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"};
2731 my $ret; 1853 my $ret;
2732 my %current_config; 1854 my %current_config;
2733 1855
@@ -2739,13 +1861,6 @@ sub run_config_bisect {
2739 do { 1861 do {
2740 my @tophalf = @start_list[0 .. $half]; 1862 my @tophalf = @start_list[0 .. $half];
2741 1863
2742 # keep the bottom half off
2743 if ($half < $#start_list) {
2744 @config_off_tmp = @start_list[$half + 1 .. $#start_list];
2745 } else {
2746 @config_off_tmp = ();
2747 }
2748
2749 create_config @tophalf; 1864 create_config @tophalf;
2750 read_current_config \%current_config; 1865 read_current_config \%current_config;
2751 1866
@@ -2762,11 +1877,7 @@ sub run_config_bisect {
2762 if (!$found) { 1877 if (!$found) {
2763 # try the other half 1878 # try the other half
2764 doprint "Top half produced no set configs, trying bottom half\n"; 1879 doprint "Top half produced no set configs, trying bottom half\n";
2765
2766 # keep the top half off
2767 @config_off_tmp = @tophalf;
2768 @tophalf = @start_list[$half + 1 .. $#start_list]; 1880 @tophalf = @start_list[$half + 1 .. $#start_list];
2769
2770 create_config @tophalf; 1881 create_config @tophalf;
2771 read_current_config \%current_config; 1882 read_current_config \%current_config;
2772 foreach my $config (@tophalf) { 1883 foreach my $config (@tophalf) {
@@ -2842,7 +1953,7 @@ sub run_config_bisect {
2842sub config_bisect { 1953sub config_bisect {
2843 my ($i) = @_; 1954 my ($i) = @_;
2844 1955
2845 my $start_config = $config_bisect; 1956 my $start_config = $opt{"CONFIG_BISECT[$i]"};
2846 1957
2847 my $tmpconfig = "$tmpdir/use_config"; 1958 my $tmpconfig = "$tmpdir/use_config";
2848 1959
@@ -2871,7 +1982,7 @@ sub config_bisect {
2871 # read directly what we want to check 1982 # read directly what we want to check
2872 my %config_check; 1983 my %config_check;
2873 open (IN, $output_config) 1984 open (IN, $output_config)
2874 or dodie "failed to open $output_config"; 1985 or dodie "faied to open $output_config";
2875 1986
2876 while (<IN>) { 1987 while (<IN>) {
2877 if (/^((CONFIG\S*)=.*)/) { 1988 if (/^((CONFIG\S*)=.*)/) {
@@ -2904,10 +2015,6 @@ sub config_bisect {
2904 $added_configs{$2} = $1; 2015 $added_configs{$2} = $1;
2905 $config_list{$2} = $1; 2016 $config_list{$2} = $1;
2906 } 2017 }
2907 } elsif (/^# ((CONFIG\S*).*)/) {
2908 # Keep these configs disabled
2909 $config_set{$2} = $1;
2910 $config_off{$2} = $1;
2911 } 2018 }
2912 } 2019 }
2913 close(IN); 2020 close(IN);
@@ -2930,8 +2037,6 @@ sub config_bisect {
2930 my %config_test; 2037 my %config_test;
2931 my $once = 0; 2038 my $once = 0;
2932 2039
2933 @config_off_tmp = ();
2934
2935 # Sometimes kconfig does weird things. We must make sure 2040 # Sometimes kconfig does weird things. We must make sure
2936 # that the config we autocreate has everything we need 2041 # that the config we autocreate has everything we need
2937 # to test, otherwise we may miss testing configs, or 2042 # to test, otherwise we may miss testing configs, or
@@ -2950,18 +2055,6 @@ sub config_bisect {
2950 } 2055 }
2951 } 2056 }
2952 my $ret; 2057 my $ret;
2953
2954 if (defined($config_bisect_check) && $config_bisect_check) {
2955 doprint " Checking to make sure bad config with min config fails\n";
2956 create_config keys %config_list;
2957 $ret = run_config_bisect_test $config_bisect_type;
2958 if ($ret) {
2959 doprint " FAILED! Bad config with min config boots fine\n";
2960 return -1;
2961 }
2962 doprint " Bad config with min config fails as expected\n";
2963 }
2964
2965 do { 2058 do {
2966 $ret = run_config_bisect; 2059 $ret = run_config_bisect;
2967 } while (!$ret); 2060 } while (!$ret);
@@ -2973,29 +2066,32 @@ sub config_bisect {
2973 2066
2974sub patchcheck_reboot { 2067sub patchcheck_reboot {
2975 doprint "Reboot and sleep $patchcheck_sleep_time seconds\n"; 2068 doprint "Reboot and sleep $patchcheck_sleep_time seconds\n";
2976 reboot_to_good $patchcheck_sleep_time; 2069 reboot;
2070 start_monitor;
2071 wait_for_monitor $patchcheck_sleep_time;
2072 end_monitor;
2977} 2073}
2978 2074
2979sub patchcheck { 2075sub patchcheck {
2980 my ($i) = @_; 2076 my ($i) = @_;
2981 2077
2982 die "PATCHCHECK_START[$i] not defined\n" 2078 die "PATCHCHECK_START[$i] not defined\n"
2983 if (!defined($patchcheck_start)); 2079 if (!defined($opt{"PATCHCHECK_START[$i]"}));
2984 die "PATCHCHECK_TYPE[$i] not defined\n" 2080 die "PATCHCHECK_TYPE[$i] not defined\n"
2985 if (!defined($patchcheck_type)); 2081 if (!defined($opt{"PATCHCHECK_TYPE[$i]"}));
2986 2082
2987 my $start = $patchcheck_start; 2083 my $start = $opt{"PATCHCHECK_START[$i]"};
2988 2084
2989 my $end = "HEAD"; 2085 my $end = "HEAD";
2990 if (defined($patchcheck_end)) { 2086 if (defined($opt{"PATCHCHECK_END[$i]"})) {
2991 $end = $patchcheck_end; 2087 $end = $opt{"PATCHCHECK_END[$i]"};
2992 } 2088 }
2993 2089
2994 # Get the true sha1's since we can use things like HEAD~3 2090 # Get the true sha1's since we can use things like HEAD~3
2995 $start = get_sha1($start); 2091 $start = get_sha1($start);
2996 $end = get_sha1($end); 2092 $end = get_sha1($end);
2997 2093
2998 my $type = $patchcheck_type; 2094 my $type = $opt{"PATCHCHECK_TYPE[$i]"};
2999 2095
3000 # Can't have a test without having a test to run 2096 # Can't have a test without having a test to run
3001 if ($type eq "test" && !defined($run_test)) { 2097 if ($type eq "test" && !defined($run_test)) {
@@ -3082,31 +2178,12 @@ sub patchcheck {
3082} 2178}
3083 2179
3084my %depends; 2180my %depends;
3085my %depcount;
3086my $iflevel = 0; 2181my $iflevel = 0;
3087my @ifdeps; 2182my @ifdeps;
3088 2183
3089# prevent recursion 2184# prevent recursion
3090my %read_kconfigs; 2185my %read_kconfigs;
3091 2186
3092sub add_dep {
3093 # $config depends on $dep
3094 my ($config, $dep) = @_;
3095
3096 if (defined($depends{$config})) {
3097 $depends{$config} .= " " . $dep;
3098 } else {
3099 $depends{$config} = $dep;
3100 }
3101
3102 # record the number of configs depending on $dep
3103 if (defined $depcount{$dep}) {
3104 $depcount{$dep}++;
3105 } else {
3106 $depcount{$dep} = 1;
3107 }
3108}
3109
3110# taken from streamline_config.pl 2187# taken from streamline_config.pl
3111sub read_kconfig { 2188sub read_kconfig {
3112 my ($kconfig) = @_; 2189 my ($kconfig) = @_;
@@ -3153,19 +2230,30 @@ sub read_kconfig {
3153 $config = $2; 2230 $config = $2;
3154 2231
3155 for (my $i = 0; $i < $iflevel; $i++) { 2232 for (my $i = 0; $i < $iflevel; $i++) {
3156 add_dep $config, $ifdeps[$i]; 2233 if ($i) {
2234 $depends{$config} .= " " . $ifdeps[$i];
2235 } else {
2236 $depends{$config} = $ifdeps[$i];
2237 }
2238 $state = "DEP";
3157 } 2239 }
3158 2240
3159 # collect the depends for the config 2241 # collect the depends for the config
3160 } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) { 2242 } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
3161 2243
3162 add_dep $config, $1; 2244 if (defined($depends{$1})) {
2245 $depends{$config} .= " " . $1;
2246 } else {
2247 $depends{$config} = $1;
2248 }
3163 2249
3164 # Get the configs that select this config 2250 # Get the configs that select this config
3165 } elsif ($state eq "NEW" && /^\s*select\s+(\S+)/) { 2251 } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
3166 2252 if (defined($depends{$1})) {
3167 # selected by depends on config 2253 $depends{$1} .= " " . $config;
3168 add_dep $1, $config; 2254 } else {
2255 $depends{$1} = $config;
2256 }
3169 2257
3170 # Check for if statements 2258 # Check for if statements
3171 } elsif (/^if\s+(.*\S)\s*$/) { 2259 } elsif (/^if\s+(.*\S)\s*$/) {
@@ -3277,18 +2365,11 @@ sub make_new_config {
3277 close OUT; 2365 close OUT;
3278} 2366}
3279 2367
3280sub chomp_config {
3281 my ($config) = @_;
3282
3283 $config =~ s/CONFIG_//;
3284
3285 return $config;
3286}
3287
3288sub get_depends { 2368sub get_depends {
3289 my ($dep) = @_; 2369 my ($dep) = @_;
3290 2370
3291 my $kconfig = chomp_config $dep; 2371 my $kconfig = $dep;
2372 $kconfig =~ s/CONFIG_//;
3292 2373
3293 $dep = $depends{"$kconfig"}; 2374 $dep = $depends{"$kconfig"};
3294 2375
@@ -3338,7 +2419,8 @@ sub test_this_config {
3338 return undef; 2419 return undef;
3339 } 2420 }
3340 2421
3341 my $kconfig = chomp_config $config; 2422 my $kconfig = $config;
2423 $kconfig =~ s/CONFIG_//;
3342 2424
3343 # Test dependencies first 2425 # Test dependencies first
3344 if (defined($depends{"$kconfig"})) { 2426 if (defined($depends{"$kconfig"})) {
@@ -3354,7 +2436,7 @@ sub test_this_config {
3354 } 2436 }
3355 2437
3356 # Remove this config from the list of configs 2438 # Remove this config from the list of configs
3357 # do a make olddefconfig and then read the resulting 2439 # do a make oldnoconfig and then read the resulting
3358 # .config to make sure it is missing the config that 2440 # .config to make sure it is missing the config that
3359 # we had before 2441 # we had before
3360 my %configs = %min_configs; 2442 my %configs = %min_configs;
@@ -3376,12 +2458,6 @@ sub test_this_config {
3376sub make_min_config { 2458sub make_min_config {
3377 my ($i) = @_; 2459 my ($i) = @_;
3378 2460
3379 my $type = $minconfig_type;
3380 if ($type ne "boot" && $type ne "test") {
3381 fail "Invalid MIN_CONFIG_TYPE '$minconfig_type'\n" .
3382 " make_min_config works only with 'boot' and 'test'\n" and return;
3383 }
3384
3385 if (!defined($output_minconfig)) { 2461 if (!defined($output_minconfig)) {
3386 fail "OUTPUT_MIN_CONFIG not defined" and return; 2462 fail "OUTPUT_MIN_CONFIG not defined" and return;
3387 } 2463 }
@@ -3391,15 +2467,8 @@ sub make_min_config {
3391 # that instead. 2467 # that instead.
3392 if (-f $output_minconfig && !$start_minconfig_defined) { 2468 if (-f $output_minconfig && !$start_minconfig_defined) {
3393 print "$output_minconfig exists\n"; 2469 print "$output_minconfig exists\n";
3394 if (!defined($use_output_minconfig)) { 2470 if (read_yn " Use it as minconfig?") {
3395 if (read_yn " Use it as minconfig?") {
3396 $start_minconfig = $output_minconfig;
3397 }
3398 } elsif ($use_output_minconfig > 0) {
3399 doprint "Using $output_minconfig as MIN_CONFIG\n";
3400 $start_minconfig = $output_minconfig; 2471 $start_minconfig = $output_minconfig;
3401 } else {
3402 doprint "Set to still use MIN_CONFIG as starting point\n";
3403 } 2472 }
3404 } 2473 }
3405 2474
@@ -3441,14 +2510,6 @@ sub make_min_config {
3441 2510
3442 my @config_keys = keys %min_configs; 2511 my @config_keys = keys %min_configs;
3443 2512
3444 # All configs need a depcount
3445 foreach my $config (@config_keys) {
3446 my $kconfig = chomp_config $config;
3447 if (!defined $depcount{$kconfig}) {
3448 $depcount{$kconfig} = 0;
3449 }
3450 }
3451
3452 # Remove anything that was set by the make allnoconfig 2513 # Remove anything that was set by the make allnoconfig
3453 # we shouldn't need them as they get set for us anyway. 2514 # we shouldn't need them as they get set for us anyway.
3454 foreach my $config (@config_keys) { 2515 foreach my $config (@config_keys) {
@@ -3487,13 +2548,8 @@ sub make_min_config {
3487 # Now disable each config one by one and do a make oldconfig 2548 # Now disable each config one by one and do a make oldconfig
3488 # till we find a config that changes our list. 2549 # till we find a config that changes our list.
3489 2550
3490 my @test_configs = keys %min_configs;
3491
3492 # Sort keys by who is most dependent on
3493 @test_configs = sort { $depcount{chomp_config($b)} <=> $depcount{chomp_config($a)} }
3494 @test_configs ;
3495
3496 # Put configs that did not modify the config at the end. 2551 # Put configs that did not modify the config at the end.
2552 my @test_configs = keys %min_configs;
3497 my $reset = 1; 2553 my $reset = 1;
3498 for (my $i = 0; $i < $#test_configs; $i++) { 2554 for (my $i = 0; $i < $#test_configs; $i++) {
3499 if (!defined($nochange_config{$test_configs[0]})) { 2555 if (!defined($nochange_config{$test_configs[0]})) {
@@ -3545,16 +2601,9 @@ sub make_min_config {
3545 $in_bisect = 1; 2601 $in_bisect = 1;
3546 2602
3547 my $failed = 0; 2603 my $failed = 0;
3548 build "oldconfig" or $failed = 1; 2604 build "oldconfig";
3549 if (!$failed) { 2605 start_monitor_and_boot or $failed = 1;
3550 start_monitor_and_boot or $failed = 1; 2606 end_monitor;
3551
3552 if ($type eq "test" && !$failed) {
3553 do_run_test or $failed = 1;
3554 }
3555
3556 end_monitor;
3557 }
3558 2607
3559 $in_bisect = 0; 2608 $in_bisect = 0;
3560 2609
@@ -3610,7 +2659,10 @@ sub make_min_config {
3610 } 2659 }
3611 2660
3612 doprint "Reboot and wait $sleep_time seconds\n"; 2661 doprint "Reboot and wait $sleep_time seconds\n";
3613 reboot_to_good $sleep_time; 2662 reboot;
2663 start_monitor;
2664 wait_for_monitor $sleep_time;
2665 end_monitor;
3614 } 2666 }
3615 2667
3616 success $i; 2668 success $i;
@@ -3632,27 +2684,13 @@ if ($#ARGV == 0) {
3632} 2684}
3633 2685
3634if (! -f $ktest_config) { 2686if (! -f $ktest_config) {
3635 $newconfig = 1;
3636 get_test_case;
3637 open(OUT, ">$ktest_config") or die "Can not create $ktest_config"; 2687 open(OUT, ">$ktest_config") or die "Can not create $ktest_config";
3638 print OUT << "EOF" 2688 print OUT << "EOF"
3639# Generated by ktest.pl 2689# Generated by ktest.pl
3640# 2690#
3641
3642# PWD is a ktest.pl variable that will result in the process working
3643# directory that ktest.pl is executed in.
3644
3645# THIS_DIR is automatically assigned the PWD of the path that generated
3646# the config file. It is best to use this variable when assigning other
3647# directory paths within this directory. This allows you to easily
3648# move the test cases to other locations or to other machines.
3649#
3650THIS_DIR := $variable{"PWD"}
3651
3652# Define each test with TEST_START 2691# Define each test with TEST_START
3653# The config options below it will override the defaults 2692# The config options below it will override the defaults
3654TEST_START 2693TEST_START
3655TEST_TYPE = $default{"TEST_TYPE"}
3656 2694
3657DEFAULTS 2695DEFAULTS
3658EOF 2696EOF
@@ -3672,7 +2710,7 @@ if ($#new_configs >= 0) {
3672 open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config"; 2710 open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config";
3673 foreach my $config (@new_configs) { 2711 foreach my $config (@new_configs) {
3674 print OUT "$config = $entered_configs{$config}\n"; 2712 print OUT "$config = $entered_configs{$config}\n";
3675 $opt{$config} = process_variables($entered_configs{$config}); 2713 $opt{$config} = $entered_configs{$config};
3676 } 2714 }
3677} 2715}
3678 2716
@@ -3745,37 +2783,66 @@ sub set_test_option {
3745# First we need to do is the builds 2783# First we need to do is the builds
3746for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { 2784for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3747 2785
3748 # Do not reboot on failing test options
3749 $no_reboot = 1;
3750 $reboot_success = 0;
3751
3752 $have_version = 0;
3753
3754 $iteration = $i; 2786 $iteration = $i;
3755 2787
3756 undef %force_config;
3757
3758 my $makecmd = set_test_option("MAKE_CMD", $i); 2788 my $makecmd = set_test_option("MAKE_CMD", $i);
3759 2789
3760 # Load all the options into their mapped variable names 2790 $machine = set_test_option("MACHINE", $i);
3761 foreach my $opt (keys %option_map) { 2791 $ssh_user = set_test_option("SSH_USER", $i);
3762 ${$option_map{$opt}} = set_test_option($opt, $i); 2792 $tmpdir = set_test_option("TMP_DIR", $i);
3763 } 2793 $outputdir = set_test_option("OUTPUT_DIR", $i);
2794 $builddir = set_test_option("BUILD_DIR", $i);
2795 $test_type = set_test_option("TEST_TYPE", $i);
2796 $build_type = set_test_option("BUILD_TYPE", $i);
2797 $build_options = set_test_option("BUILD_OPTIONS", $i);
2798 $pre_build = set_test_option("PRE_BUILD", $i);
2799 $post_build = set_test_option("POST_BUILD", $i);
2800 $pre_build_die = set_test_option("PRE_BUILD_DIE", $i);
2801 $post_build_die = set_test_option("POST_BUILD_DIE", $i);
2802 $power_cycle = set_test_option("POWER_CYCLE", $i);
2803 $reboot = set_test_option("REBOOT", $i);
2804 $noclean = set_test_option("BUILD_NOCLEAN", $i);
2805 $minconfig = set_test_option("MIN_CONFIG", $i);
2806 $output_minconfig = set_test_option("OUTPUT_MIN_CONFIG", $i);
2807 $start_minconfig = set_test_option("START_MIN_CONFIG", $i);
2808 $ignore_config = set_test_option("IGNORE_CONFIG", $i);
2809 $run_test = set_test_option("TEST", $i);
2810 $addconfig = set_test_option("ADD_CONFIG", $i);
2811 $reboot_type = set_test_option("REBOOT_TYPE", $i);
2812 $grub_menu = set_test_option("GRUB_MENU", $i);
2813 $post_install = set_test_option("POST_INSTALL", $i);
2814 $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
2815 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
2816 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
2817 $die_on_failure = set_test_option("DIE_ON_FAILURE", $i);
2818 $power_off = set_test_option("POWER_OFF", $i);
2819 $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
2820 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
2821 $sleep_time = set_test_option("SLEEP_TIME", $i);
2822 $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
2823 $patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i);
2824 $ignore_warnings = set_test_option("IGNORE_WARNINGS", $i);
2825 $bisect_manual = set_test_option("BISECT_MANUAL", $i);
2826 $bisect_skip = set_test_option("BISECT_SKIP", $i);
2827 $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i);
2828 $store_failures = set_test_option("STORE_FAILURES", $i);
2829 $test_name = set_test_option("TEST_NAME", $i);
2830 $timeout = set_test_option("TIMEOUT", $i);
2831 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
2832 $console = set_test_option("CONSOLE", $i);
2833 $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i);
2834 $success_line = set_test_option("SUCCESS_LINE", $i);
2835 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
2836 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
2837 $stop_test_after = set_test_option("STOP_TEST_AFTER", $i);
2838 $build_target = set_test_option("BUILD_TARGET", $i);
2839 $ssh_exec = set_test_option("SSH_EXEC", $i);
2840 $scp_to_target = set_test_option("SCP_TO_TARGET", $i);
2841 $target_image = set_test_option("TARGET_IMAGE", $i);
2842 $localversion = set_test_option("LOCALVERSION", $i);
3764 2843
3765 $start_minconfig_defined = 1; 2844 $start_minconfig_defined = 1;
3766 2845
3767 # The first test may override the PRE_KTEST option
3768 if (defined($pre_ktest) && $i == 1) {
3769 doprint "\n";
3770 run_command $pre_ktest;
3771 }
3772
3773 # Any test can override the POST_KTEST option
3774 # The last test takes precedence.
3775 if (defined($post_ktest)) {
3776 $final_post_ktest = $post_ktest;
3777 }
3778
3779 if (!defined($start_minconfig)) { 2846 if (!defined($start_minconfig)) {
3780 $start_minconfig_defined = 0; 2847 $start_minconfig_defined = 0;
3781 $start_minconfig = $minconfig; 2848 $start_minconfig = $minconfig;
@@ -3783,41 +2850,34 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3783 2850
3784 chdir $builddir || die "can't change directory to $builddir"; 2851 chdir $builddir || die "can't change directory to $builddir";
3785 2852
3786 foreach my $dir ($tmpdir, $outputdir) { 2853 if (!-d $tmpdir) {
3787 if (!-d $dir) { 2854 mkpath($tmpdir) or
3788 mkpath($dir) or 2855 die "can't create $tmpdir";
3789 die "can't create $dir";
3790 }
3791 } 2856 }
3792 2857
3793 $ENV{"SSH_USER"} = $ssh_user; 2858 $ENV{"SSH_USER"} = $ssh_user;
3794 $ENV{"MACHINE"} = $machine; 2859 $ENV{"MACHINE"} = $machine;
3795 2860
2861 $target = "$ssh_user\@$machine";
2862
3796 $buildlog = "$tmpdir/buildlog-$machine"; 2863 $buildlog = "$tmpdir/buildlog-$machine";
3797 $testlog = "$tmpdir/testlog-$machine";
3798 $dmesg = "$tmpdir/dmesg-$machine"; 2864 $dmesg = "$tmpdir/dmesg-$machine";
3799 $make = "$makecmd O=$outputdir"; 2865 $make = "$makecmd O=$outputdir";
3800 $output_config = "$outputdir/.config"; 2866 $output_config = "$outputdir/.config";
3801 2867
3802 if (!$buildonly) { 2868 if ($reboot_type eq "grub") {
3803 $target = "$ssh_user\@$machine"; 2869 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
3804 if ($reboot_type eq "grub") { 2870 } elsif (!defined($reboot_script)) {
3805 dodie "GRUB_MENU not defined" if (!defined($grub_menu)); 2871 dodie "REBOOT_SCRIPT not defined"
3806 } elsif ($reboot_type eq "grub2") {
3807 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
3808 dodie "GRUB_FILE not defined" if (!defined($grub_file));
3809 } elsif ($reboot_type eq "syslinux") {
3810 dodie "SYSLINUX_LABEL not defined" if (!defined($syslinux_label));
3811 }
3812 } 2872 }
3813 2873
3814 my $run_type = $build_type; 2874 my $run_type = $build_type;
3815 if ($test_type eq "patchcheck") { 2875 if ($test_type eq "patchcheck") {
3816 $run_type = $patchcheck_type; 2876 $run_type = $opt{"PATCHCHECK_TYPE[$i]"};
3817 } elsif ($test_type eq "bisect") { 2877 } elsif ($test_type eq "bisect") {
3818 $run_type = $bisect_type; 2878 $run_type = $opt{"BISECT_TYPE[$i]"};
3819 } elsif ($test_type eq "config_bisect") { 2879 } elsif ($test_type eq "config_bisect") {
3820 $run_type = $config_bisect_type; 2880 $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"};
3821 } 2881 }
3822 2882
3823 if ($test_type eq "make_min_config") { 2883 if ($test_type eq "make_min_config") {
@@ -3829,19 +2889,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3829 $run_type = "ERROR"; 2889 $run_type = "ERROR";
3830 } 2890 }
3831 2891
3832 my $installme = "";
3833 $installme = " no_install" if ($no_install);
3834
3835 doprint "\n\n"; 2892 doprint "\n\n";
3836 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n"; 2893 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
3837
3838 if (defined($pre_test)) {
3839 run_command $pre_test;
3840 }
3841 2894
3842 unlink $dmesg; 2895 unlink $dmesg;
3843 unlink $buildlog; 2896 unlink $buildlog;
3844 unlink $testlog;
3845 2897
3846 if (defined($addconfig)) { 2898 if (defined($addconfig)) {
3847 my $min = $minconfig; 2899 my $min = $minconfig;
@@ -3853,18 +2905,12 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3853 $minconfig = "$tmpdir/add_config"; 2905 $minconfig = "$tmpdir/add_config";
3854 } 2906 }
3855 2907
2908 my $checkout = $opt{"CHECKOUT[$i]"};
3856 if (defined($checkout)) { 2909 if (defined($checkout)) {
3857 run_command "git checkout $checkout" or 2910 run_command "git checkout $checkout" or
3858 die "failed to checkout $checkout"; 2911 die "failed to checkout $checkout";
3859 } 2912 }
3860 2913
3861 $no_reboot = 0;
3862
3863 # A test may opt to not reboot the box
3864 if ($reboot_on_success) {
3865 $reboot_success = 1;
3866 }
3867
3868 if ($test_type eq "bisect") { 2914 if ($test_type eq "bisect") {
3869 bisect $i; 2915 bisect $i;
3870 next; 2916 next;
@@ -3883,13 +2929,6 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3883 build $build_type or next; 2929 build $build_type or next;
3884 } 2930 }
3885 2931
3886 if ($test_type eq "install") {
3887 get_version;
3888 install;
3889 success $i;
3890 next;
3891 }
3892
3893 if ($test_type ne "build") { 2932 if ($test_type ne "build") {
3894 my $failed = 0; 2933 my $failed = 0;
3895 start_monitor_and_boot or $failed = 1; 2934 start_monitor_and_boot or $failed = 1;
@@ -3904,20 +2943,12 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3904 success $i; 2943 success $i;
3905} 2944}
3906 2945
3907if (defined($final_post_ktest)) {
3908 run_command $final_post_ktest;
3909}
3910
3911if ($opt{"POWEROFF_ON_SUCCESS"}) { 2946if ($opt{"POWEROFF_ON_SUCCESS"}) {
3912 halt; 2947 halt;
3913} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot && $reboot_success) { 2948} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
3914 reboot_to_good; 2949 reboot;
3915} elsif (defined($switch_to_good)) {
3916 # still need to get to the good kernel
3917 run_command $switch_to_good;
3918} 2950}
3919 2951
3920
3921doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; 2952doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n";
3922 2953
3923exit 0; 2954exit 0;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 4012e933034..b8bcd14b5a4 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -72,128 +72,6 @@
72# the same option name under the same test or as default 72# the same option name under the same test or as default
73# ktest will fail to execute, and no tests will run. 73# ktest will fail to execute, and no tests will run.
74# 74#
75# DEFAULTS OVERRIDE
76#
77# Options defined in the DEFAULTS section can not be duplicated
78# even if they are defined in two different DEFAULT sections.
79# This is done to catch mistakes where an option is added but
80# the previous option was forgotten about and not commented.
81#
82# The OVERRIDE keyword can be added to a section to allow this
83# section to override other DEFAULT sections values that have
84# been defined previously. It will only override options that
85# have been defined before its use. Options defined later
86# in a non override section will still error. The same option
87# can not be defined in the same section even if that section
88# is marked OVERRIDE.
89#
90#
91#
92# Both TEST_START and DEFAULTS sections can also have the IF keyword
93# The value after the IF must evaluate into a 0 or non 0 positive
94# integer, and can use the config variables (explained below).
95#
96# DEFAULTS IF ${IS_X86_32}
97#
98# The above will process the DEFAULTS section if the config
99# variable IS_X86_32 evaluates to a non zero positive integer
100# otherwise if it evaluates to zero, it will act the same
101# as if the SKIP keyword was used.
102#
103# The ELSE keyword can be used directly after a section with
104# a IF statement.
105#
106# TEST_START IF ${RUN_NET_TESTS}
107# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
108#
109# ELSE
110#
111# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-normal
112#
113#
114# The ELSE keyword can also contain an IF statement to allow multiple
115# if then else sections. But all the sections must be either
116# DEFAULT or TEST_START, they can not be a mixture.
117#
118# TEST_START IF ${RUN_NET_TESTS}
119# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
120#
121# ELSE IF ${RUN_DISK_TESTS}
122# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-tests
123#
124# ELSE IF ${RUN_CPU_TESTS}
125# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-cpu
126#
127# ELSE
128# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-network
129#
130# The if statement may also have comparisons that will and for
131# == and !=, strings may be used for both sides.
132#
133# BOX_TYPE := x86_32
134#
135# DEFAULTS IF ${BOX_TYPE} == x86_32
136# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-32
137# ELSE
138# BUILD_TYPE = useconfig:${CONFIG_DIR}/config-64
139#
140# The DEFINED keyword can be used by the IF statements too.
141# It returns true if the given config variable or option has been defined
142# or false otherwise.
143#
144#
145# DEFAULTS IF DEFINED USE_CC
146# CC := ${USE_CC}
147# ELSE
148# CC := gcc
149#
150#
151# As well as NOT DEFINED.
152#
153# DEFAULTS IF NOT DEFINED MAKE_CMD
154# MAKE_CMD := make ARCH=x86
155#
156#
157# And/or ops (&&,||) may also be used to make complex conditionals.
158#
159# TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf
160#
161# Notice the use of parentheses. Without any parentheses the above would be
162# processed the same as:
163#
164# TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf)
165#
166#
167#
168# INCLUDE file
169#
170# The INCLUDE keyword may be used in DEFAULT sections. This will
171# read another config file and process that file as well. The included
172# file can include other files, add new test cases or default
173# statements. Config variables will be passed to these files and changes
174# to config variables will be seen by top level config files. Including
175# a file is processed just like the contents of the file was cut and pasted
176# into the top level file, except, that include files that end with
177# TEST_START sections will have that section ended at the end of
178# the include file. That is, an included file is included followed
179# by another DEFAULT keyword.
180#
181# Unlike other files referenced in this config, the file path does not need
182# to be absolute. If the file does not start with '/', then the directory
183# that the current config file was located in is used. If no config by the
184# given name is found there, then the current directory is searched.
185#
186# INCLUDE myfile
187# DEFAULT
188#
189# is the same as:
190#
191# INCLUDE myfile
192#
193# Note, if the include file does not contain a full path, the file is
194# searched first by the location of the original include file, and then
195# by the location that ktest.pl was executed in.
196#
197 75
198#### Config variables #### 76#### Config variables ####
199# 77#
@@ -332,18 +210,8 @@
332# from other linux builds on the system. 210# from other linux builds on the system.
333#LOCALVERSION = -test 211#LOCALVERSION = -test
334 212
335# For REBOOT_TYPE = grub2, you must specify where the grub.cfg
336# file is. This is the file that is searched to find the menu
337# option to boot to with GRUB_REBOOT
338#GRUB_FILE = /boot/grub2/grub.cfg
339
340# The tool for REBOOT_TYPE = grub2 to set the next reboot kernel
341# to boot into (one shot mode).
342# (default grub2_reboot)
343#GRUB_REBOOT = grub2_reboot
344
345# The grub title name for the test kernel to boot 213# The grub title name for the test kernel to boot
346# (Only mandatory if REBOOT_TYPE = grub or grub2) 214# (Only mandatory if REBOOT_TYPE = grub)
347# 215#
348# Note, ktest.pl will not update the grub menu.lst, you need to 216# Note, ktest.pl will not update the grub menu.lst, you need to
349# manually add an option for the test. ktest.pl will search 217# manually add an option for the test. ktest.pl will search
@@ -353,38 +221,10 @@
353# For example, if in the /boot/grub/menu.lst the test kernel title has: 221# For example, if in the /boot/grub/menu.lst the test kernel title has:
354# title Test Kernel 222# title Test Kernel
355# kernel vmlinuz-test 223# kernel vmlinuz-test
356#
357# For grub2, a search of top level "menuentry"s are done. No
358# submenu is searched. The menu is found by searching for the
359# contents of GRUB_MENU in the line that starts with "menuentry".
360# You may want to include the quotes around the option. For example:
361# for: menuentry 'Test Kernel'
362# do a: GRUB_MENU = 'Test Kernel'
363# For customizing, add your entry in /etc/grub.d/40_custom.
364#
365#GRUB_MENU = Test Kernel 224#GRUB_MENU = Test Kernel
366 225
367# For REBOOT_TYPE = syslinux, the name of the syslinux executable
368# (on the target) to use to set up the next reboot to boot the
369# test kernel.
370# (default extlinux)
371#SYSLINUX = syslinux
372
373# For REBOOT_TYPE = syslinux, the path that is passed to to the
374# syslinux command where syslinux is installed.
375# (default /boot/extlinux)
376#SYSLINUX_PATH = /boot/syslinux
377
378# For REBOOT_TYPE = syslinux, the syslinux label that references the
379# test kernel in the syslinux config file.
380# (default undefined)
381#SYSLINUX_LABEL = "test-kernel"
382
383# A script to reboot the target into the test kernel 226# A script to reboot the target into the test kernel
384# This and SWITCH_TO_TEST are about the same, except 227# (Only mandatory if REBOOT_TYPE = script)
385# SWITCH_TO_TEST is run even for REBOOT_TYPE = grub.
386# This may be left undefined.
387# (default undefined)
388#REBOOT_SCRIPT = 228#REBOOT_SCRIPT =
389 229
390#### Optional Config Options (all have defaults) #### 230#### Optional Config Options (all have defaults) ####
@@ -411,30 +251,11 @@
411# DEFAULTS 251# DEFAULTS
412# DEFAULTS SKIP 252# DEFAULTS SKIP
413 253
414# If you want to execute some command before the first test runs
415# you can set this option. Note, it can be set as a default option
416# or an option in the first test case. All other test cases will
417# ignore it. If both the default and first test have this option
418# set, then the first test will take precedence.
419#
420# default (undefined)
421#PRE_KTEST = ${SSH} ~/set_up_test
422
423# If you want to execute some command after all the tests have
424# completed, you can set this option. Note, it can be set as a
425# default or any test case can override it. If multiple test cases
426# set this option, then the last test case that set it will take
427# precedence
428#
429# default (undefined)
430#POST_KTEST = ${SSH} ~/dismantle_test
431
432# The default test type (default test) 254# The default test type (default test)
433# The test types may be: 255# The test types may be:
434# build - only build the kernel, do nothing else 256# build - only build the kernel, do nothing else
435# install - build and install, but do nothing else (does not reboot) 257# boot - build and boot the kernel
436# boot - build, install, and boot the kernel 258# test - build, boot and if TEST is set, run the test script
437# test - build, boot and if TEST is set, run the test script
438# (If TEST is not set, it defaults back to boot) 259# (If TEST is not set, it defaults back to boot)
439# bisect - Perform a bisect on the kernel (see BISECT_TYPE below) 260# bisect - Perform a bisect on the kernel (see BISECT_TYPE below)
440# patchcheck - Do a test on a series of commits in git (see PATCHCHECK below) 261# patchcheck - Do a test on a series of commits in git (see PATCHCHECK below)
@@ -461,14 +282,6 @@
461# (default "") 282# (default "")
462#BUILD_OPTIONS = -j20 283#BUILD_OPTIONS = -j20
463 284
464# If you need to do some special handling before installing
465# you can add a script with this option.
466# The environment variable KERNEL_VERSION will be set to the
467# kernel version that is used.
468#
469# default (undefined)
470#PRE_INSTALL = ssh user@target rm -rf '/lib/modules/*-test*'
471
472# If you need an initrd, you can add a script or code here to install 285# If you need an initrd, you can add a script or code here to install
473# it. The environment variable KERNEL_VERSION will be set to the 286# it. The environment variable KERNEL_VERSION will be set to the
474# kernel version that is used. Remember to add the initrd line 287# kernel version that is used. Remember to add the initrd line
@@ -480,25 +293,6 @@
480# or on some systems: 293# or on some systems:
481#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION 294#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
482 295
483# If for some reason you just want to boot the kernel and you do not
484# want the test to install anything new. For example, you may just want
485# to boot test the same kernel over and over and do not want to go through
486# the hassle of installing anything, you can set this option to 1
487# (default 0)
488#NO_INSTALL = 1
489
490# If there is a command that you want to run before the individual test
491# case executes, then you can set this option
492#
493# default (undefined)
494#PRE_TEST = ${SSH} reboot_to_special_kernel
495
496# If there is a command you want to run after the individual test case
497# completes, then you can set this option.
498#
499# default (undefined)
500#POST_TEST = cd ${BUILD_DIR}; git reset --hard
501
502# If there is a script that you require to run before the build is done 296# If there is a script that you require to run before the build is done
503# you can specify it with PRE_BUILD. 297# you can specify it with PRE_BUILD.
504# 298#
@@ -532,7 +326,7 @@
532#POST_BUILD_DIE = 1 326#POST_BUILD_DIE = 1
533 327
534# Way to reboot the box to the test kernel. 328# Way to reboot the box to the test kernel.
535# Only valid options so far are "grub", "grub2", "syslinux" and "script" 329# Only valid options so far are "grub" and "script"
536# (default grub) 330# (default grub)
537# If you specify grub, it will assume grub version 1 331# If you specify grub, it will assume grub version 1
538# and will search in /boot/grub/menu.lst for the title $GRUB_MENU 332# and will search in /boot/grub/menu.lst for the title $GRUB_MENU
@@ -540,38 +334,10 @@
540# your setup, then specify "script" and have a command or script 334# your setup, then specify "script" and have a command or script
541# specified in REBOOT_SCRIPT to boot to the target. 335# specified in REBOOT_SCRIPT to boot to the target.
542# 336#
543# For REBOOT_TYPE = grub2, you must define both GRUB_MENU and
544# GRUB_FILE.
545#
546# For REBOOT_TYPE = syslinux, you must define SYSLINUX_LABEL, and
547# perhaps modify SYSLINUX (default extlinux) and SYSLINUX_PATH
548# (default /boot/extlinux)
549#
550# The entry in /boot/grub/menu.lst must be entered in manually. 337# The entry in /boot/grub/menu.lst must be entered in manually.
551# The test will not modify that file. 338# The test will not modify that file.
552#REBOOT_TYPE = grub 339#REBOOT_TYPE = grub
553 340
554# If you are using a machine that doesn't boot with grub, and
555# perhaps gets its kernel from a remote server (tftp), then
556# you can use this option to update the target image with the
557# test image.
558#
559# You could also do the same with POST_INSTALL, but the difference
560# between that option and this option is that POST_INSTALL runs
561# after the install, where this one runs just before a reboot.
562# (default undefined)
563#SWITCH_TO_TEST = cp ${OUTPUT_DIR}/${BUILD_TARGET} ${TARGET_IMAGE}
564
565# If you are using a machine that doesn't boot with grub, and
566# perhaps gets its kernel from a remote server (tftp), then
567# you can use this option to update the target image with the
568# the known good image to reboot safely back into.
569#
570# This option holds a command that will execute before needing
571# to reboot to a good known image.
572# (default undefined)
573#SWITCH_TO_GOOD = ssh ${SSH_USER}/${MACHINE} cp good_image ${TARGET_IMAGE}
574
575# The min config that is needed to build for the machine 341# The min config that is needed to build for the machine
576# A nice way to create this is with the following: 342# A nice way to create this is with the following:
577# 343#
@@ -649,14 +415,6 @@
649# (default "login:") 415# (default "login:")
650#SUCCESS_LINE = login: 416#SUCCESS_LINE = login:
651 417
652# To speed up between reboots, defining a line that the
653# default kernel produces that represents that the default
654# kernel has successfully booted and can be used to pass
655# a new test kernel to it. Otherwise ktest.pl will wait till
656# SLEEP_TIME to continue.
657# (default undefined)
658#REBOOT_SUCCESS_LINE = login:
659
660# In case the console constantly fills the screen, having 418# In case the console constantly fills the screen, having
661# a specified time to stop the test after success is recommended. 419# a specified time to stop the test after success is recommended.
662# (in seconds) 420# (in seconds)
@@ -693,12 +451,6 @@
693# (default undefined) 451# (default undefined)
694#STORE_FAILURES = /home/test/failures 452#STORE_FAILURES = /home/test/failures
695 453
696# Directory to store success directories on success. If this is not
697# set, the .config, dmesg and bootlog will not be saved if a
698# test succeeds.
699# (default undefined)
700#STORE_SUCCESSES = /home/test/successes
701
702# Build without doing a make mrproper, or removing .config 454# Build without doing a make mrproper, or removing .config
703# (default 0) 455# (default 0)
704#BUILD_NOCLEAN = 0 456#BUILD_NOCLEAN = 0
@@ -728,8 +480,6 @@
728# another test. If a reboot to the reliable kernel happens, 480# another test. If a reboot to the reliable kernel happens,
729# we wait SLEEP_TIME for the console to stop producing output 481# we wait SLEEP_TIME for the console to stop producing output
730# before starting the next test. 482# before starting the next test.
731#
732# You can speed up reboot times even more by setting REBOOT_SUCCESS_LINE.
733# (default 60) 483# (default 60)
734#SLEEP_TIME = 60 484#SLEEP_TIME = 60
735 485
@@ -737,14 +487,6 @@
737# (default 60) 487# (default 60)
738#BISECT_SLEEP_TIME = 60 488#BISECT_SLEEP_TIME = 60
739 489
740# The max wait time (in seconds) for waiting for the console to finish.
741# If for some reason, the console is outputting content without
742# ever finishing, this will cause ktest to get stuck. This
743# option is the max time ktest will wait for the monitor (console)
744# to settle down before continuing.
745# (default 1800)
746#MAX_MONITOR_WAIT
747
748# The time in between patch checks to sleep (in seconds) 490# The time in between patch checks to sleep (in seconds)
749# (default 60) 491# (default 60)
750#PATCHCHECK_SLEEP_TIME = 60 492#PATCHCHECK_SLEEP_TIME = 60
@@ -798,18 +540,10 @@
798# The variables SSH_USER, MACHINE and SSH_COMMAND are defined 540# The variables SSH_USER, MACHINE and SSH_COMMAND are defined
799#SSH_EXEC = ssh $SSH_USER@$MACHINE $SSH_COMMAND"; 541#SSH_EXEC = ssh $SSH_USER@$MACHINE $SSH_COMMAND";
800 542
801# The way to copy a file to the target (install and modules) 543# The way to copy a file to the target
802# (default scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE) 544# (default scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE)
803# The variables SSH_USER, MACHINE are defined by the config 545# The variables SSH_USER, MACHINE, SRC_FILE and DST_FILE are defined.
804# SRC_FILE and DST_FILE are ktest internal variables and 546#SCP_TO_TARGET = scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE
805# should only have '$' and not the '${}' notation.
806# (default scp $SRC_FILE ${SSH_USER}@${MACHINE}:$DST_FILE)
807#SCP_TO_TARGET = echo skip scp for $SRC_FILE $DST_FILE
808
809# If install needs to be different than modules, then this
810# option will override the SCP_TO_TARGET for installation.
811# (default ${SCP_TO_TARGET} )
812#SCP_TO_TARGET_INSTALL = scp $SRC_FILE tftp@tftpserver:$DST_FILE
813 547
814# The nice way to reboot the target 548# The nice way to reboot the target
815# (default ssh $SSH_USER@$MACHINE reboot) 549# (default ssh $SSH_USER@$MACHINE reboot)
@@ -826,25 +560,6 @@
826# (default 1) 560# (default 1)
827#DETECT_TRIPLE_FAULT = 0 561#DETECT_TRIPLE_FAULT = 0
828 562
829# All options in the config file should be either used by ktest
830# or could be used within a value of another option. If an option
831# in the config file is not used, ktest will warn about it and ask
832# if you want to continue.
833#
834# If you don't care if there are non-used options, enable this
835# option. Be careful though, a non-used option is usually a sign
836# of an option name being typed incorrectly.
837# (default 0)
838#IGNORE_UNUSED = 1
839
840# When testing a kernel that happens to have WARNINGs, and call
841# traces, ktest.pl will detect these and fail a boot or test run
842# due to warnings. By setting this option, ktest will ignore
843# call traces, and will not fail a test if the kernel produces
844# an oops. Use this option with care.
845# (default 0)
846#IGNORE_ERRORS = 1
847
848#### Per test run options #### 563#### Per test run options ####
849# The following options are only allowed in TEST_START sections. 564# The following options are only allowed in TEST_START sections.
850# They are ignored in the DEFAULTS sections. 565# They are ignored in the DEFAULTS sections.
@@ -1007,42 +722,6 @@
1007# BISECT_BAD with BISECT_CHECK = good or 722# BISECT_BAD with BISECT_CHECK = good or
1008# BISECT_CHECK = bad, respectively. 723# BISECT_CHECK = bad, respectively.
1009# 724#
1010# BISECT_RET_GOOD = 0 (optional, default undefined)
1011#
1012# In case the specificed test returns something other than just
1013# 0 for good, and non-zero for bad, you can override 0 being
1014# good by defining BISECT_RET_GOOD.
1015#
1016# BISECT_RET_BAD = 1 (optional, default undefined)
1017#
1018# In case the specificed test returns something other than just
1019# 0 for good, and non-zero for bad, you can override non-zero being
1020# bad by defining BISECT_RET_BAD.
1021#
1022# BISECT_RET_ABORT = 255 (optional, default undefined)
1023#
1024# If you need to abort the bisect if the test discovers something
1025# that was wrong, you can define BISECT_RET_ABORT to be the error
1026# code returned by the test in order to abort the bisect.
1027#
1028# BISECT_RET_SKIP = 2 (optional, default undefined)
1029#
1030# If the test detects that the current commit is neither good
1031# nor bad, but something else happened (another bug detected)
1032# you can specify BISECT_RET_SKIP to an error code that the
1033# test returns when it should skip the current commit.
1034#
1035# BISECT_RET_DEFAULT = good (optional, default undefined)
1036#
1037# You can override the default of what to do when the above
1038# options are not hit. This may be one of, "good", "bad",
1039# "abort" or "skip" (without the quotes).
1040#
1041# Note, if you do not define any of the previous BISECT_RET_*
1042# and define BISECT_RET_DEFAULT, all bisects results will do
1043# what the BISECT_RET_DEFAULT has.
1044#
1045#
1046# Example: 725# Example:
1047# TEST_START 726# TEST_START
1048# TEST_TYPE = bisect 727# TEST_TYPE = bisect
@@ -1127,17 +806,11 @@
1127# can specify it with CONFIG_BISECT_GOOD. Otherwise 806# can specify it with CONFIG_BISECT_GOOD. Otherwise
1128# the MIN_CONFIG is the base. 807# the MIN_CONFIG is the base.
1129# 808#
1130# CONFIG_BISECT_CHECK (optional)
1131# Set this to 1 if you want to confirm that the config ktest
1132# generates (the bad config with the min config) is still bad.
1133# It may be that the min config fixes what broke the bad config
1134# and the test will not return a result.
1135#
1136# Example: 809# Example:
1137# TEST_START 810# TEST_START
1138# TEST_TYPE = config_bisect 811# TEST_TYPE = config_bisect
1139# CONFIG_BISECT_TYPE = build 812# CONFIG_BISECT_TYPE = build
1140# CONFIG_BISECT = /home/test/config-bad 813# CONFIG_BISECT = /home/test/¢onfig-bad
1141# MIN_CONFIG = /home/test/config-min 814# MIN_CONFIG = /home/test/config-min
1142# BISECT_MANUAL = 1 815# BISECT_MANUAL = 1
1143# 816#
@@ -1199,26 +872,10 @@
1199# and will not be tested again in later runs. 872# and will not be tested again in later runs.
1200# (optional) 873# (optional)
1201# 874#
1202# MIN_CONFIG_TYPE can be either 'boot' or 'test'. With 'boot' it will
1203# test if the created config can just boot the machine. If this is
1204# set to 'test', then the TEST option must be defined and the created
1205# config will not only boot the target, but also make sure that the
1206# config lets the test succeed. This is useful to make sure the final
1207# config that is generated allows network activity (ssh).
1208# (optional)
1209#
1210# USE_OUTPUT_MIN_CONFIG set this to 1 if you do not want to be prompted
1211# about using the OUTPUT_MIN_CONFIG as the MIN_CONFIG as the starting
1212# point. Set it to 0 if you want to always just use the given MIN_CONFIG.
1213# If it is not defined, it will prompt you to pick which config
1214# to start with (MIN_CONFIG or OUTPUT_MIN_CONFIG).
1215#
1216# Example: 875# Example:
1217# 876#
1218# TEST_TYPE = make_min_config 877# TEST_TYPE = make_min_config
1219# OUTPUT_MIN_CONFIG = /path/to/config-new-min 878# OUTPUT_MIN_CONFIG = /path/to/config-new-min
1220# START_MIN_CONFIG = /path/to/config-min 879# START_MIN_CONFIG = /path/to/config-min
1221# IGNORE_CONFIG = /path/to/config-tested 880# IGNORE_CONFIG = /path/to/config-tested
1222# MIN_CONFIG_TYPE = test
1223# TEST = ssh ${USER}@${MACHINE} echo hi
1224# 881#
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
deleted file mode 100644
index 85baf11e2ac..00000000000
--- a/tools/testing/selftests/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
1TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug
2
3all:
4 for TARGET in $(TARGETS); do \
5 make -C $$TARGET; \
6 done;
7
8run_tests: all
9 for TARGET in $(TARGETS); do \
10 make -C $$TARGET run_tests; \
11 done;
12
13clean:
14 for TARGET in $(TARGETS); do \
15 make -C $$TARGET clean; \
16 done;
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
deleted file mode 100644
index e18b42b254a..00000000000
--- a/tools/testing/selftests/breakpoints/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
1# Taken from perf makefile
2uname_M := $(shell uname -m 2>/dev/null || echo not)
3ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
4ifeq ($(ARCH),i386)
5 ARCH := x86
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := x86
9endif
10
11
12all:
13ifeq ($(ARCH),x86)
14 gcc breakpoint_test.c -o breakpoint_test
15else
16 echo "Not an x86 target, can't build breakpoints selftests"
17endif
18
19run_tests:
20 @./breakpoint_test || echo "breakpoints selftests: [FAIL]"
21
22clean:
23 rm -fr breakpoint_test
diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c
deleted file mode 100644
index a0743f3b2b5..00000000000
--- a/tools/testing/selftests/breakpoints/breakpoint_test.c
+++ /dev/null
@@ -1,394 +0,0 @@
1/*
2 * Copyright (C) 2011 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
3 *
4 * Licensed under the terms of the GNU GPL License version 2
5 *
6 * Selftests for breakpoints (and more generally the do_debug() path) in x86.
7 */
8
9
10#include <sys/ptrace.h>
11#include <unistd.h>
12#include <stddef.h>
13#include <sys/user.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <signal.h>
17#include <sys/types.h>
18#include <sys/wait.h>
19
20
21/* Breakpoint access modes */
22enum {
23 BP_X = 1,
24 BP_RW = 2,
25 BP_W = 4,
26};
27
28static pid_t child_pid;
29
30/*
31 * Ensures the child and parent are always "talking" about
32 * the same test sequence. (ie: that we haven't forgotten
33 * to call check_trapped() somewhere).
34 */
35static int nr_tests;
36
37static void set_breakpoint_addr(void *addr, int n)
38{
39 int ret;
40
41 ret = ptrace(PTRACE_POKEUSER, child_pid,
42 offsetof(struct user, u_debugreg[n]), addr);
43 if (ret) {
44 perror("Can't set breakpoint addr\n");
45 exit(-1);
46 }
47}
48
49static void toggle_breakpoint(int n, int type, int len,
50 int local, int global, int set)
51{
52 int ret;
53
54 int xtype, xlen;
55 unsigned long vdr7, dr7;
56
57 switch (type) {
58 case BP_X:
59 xtype = 0;
60 break;
61 case BP_W:
62 xtype = 1;
63 break;
64 case BP_RW:
65 xtype = 3;
66 break;
67 }
68
69 switch (len) {
70 case 1:
71 xlen = 0;
72 break;
73 case 2:
74 xlen = 4;
75 break;
76 case 4:
77 xlen = 0xc;
78 break;
79 case 8:
80 xlen = 8;
81 break;
82 }
83
84 dr7 = ptrace(PTRACE_PEEKUSER, child_pid,
85 offsetof(struct user, u_debugreg[7]), 0);
86
87 vdr7 = (xlen | xtype) << 16;
88 vdr7 <<= 4 * n;
89
90 if (local) {
91 vdr7 |= 1 << (2 * n);
92 vdr7 |= 1 << 8;
93 }
94 if (global) {
95 vdr7 |= 2 << (2 * n);
96 vdr7 |= 1 << 9;
97 }
98
99 if (set)
100 dr7 |= vdr7;
101 else
102 dr7 &= ~vdr7;
103
104 ret = ptrace(PTRACE_POKEUSER, child_pid,
105 offsetof(struct user, u_debugreg[7]), dr7);
106 if (ret) {
107 perror("Can't set dr7");
108 exit(-1);
109 }
110}
111
112/* Dummy variables to test read/write accesses */
113static unsigned long long dummy_var[4];
114
115/* Dummy functions to test execution accesses */
116static void dummy_func(void) { }
117static void dummy_func1(void) { }
118static void dummy_func2(void) { }
119static void dummy_func3(void) { }
120
121static void (*dummy_funcs[])(void) = {
122 dummy_func,
123 dummy_func1,
124 dummy_func2,
125 dummy_func3,
126};
127
128static int trapped;
129
130static void check_trapped(void)
131{
132 /*
133 * If we haven't trapped, wake up the parent
134 * so that it notices the failure.
135 */
136 if (!trapped)
137 kill(getpid(), SIGUSR1);
138 trapped = 0;
139
140 nr_tests++;
141}
142
143static void write_var(int len)
144{
145 char *pcval; short *psval; int *pival; long long *plval;
146 int i;
147
148 for (i = 0; i < 4; i++) {
149 switch (len) {
150 case 1:
151 pcval = (char *)&dummy_var[i];
152 *pcval = 0xff;
153 break;
154 case 2:
155 psval = (short *)&dummy_var[i];
156 *psval = 0xffff;
157 break;
158 case 4:
159 pival = (int *)&dummy_var[i];
160 *pival = 0xffffffff;
161 break;
162 case 8:
163 plval = (long long *)&dummy_var[i];
164 *plval = 0xffffffffffffffffLL;
165 break;
166 }
167 check_trapped();
168 }
169}
170
171static void read_var(int len)
172{
173 char cval; short sval; int ival; long long lval;
174 int i;
175
176 for (i = 0; i < 4; i++) {
177 switch (len) {
178 case 1:
179 cval = *(char *)&dummy_var[i];
180 break;
181 case 2:
182 sval = *(short *)&dummy_var[i];
183 break;
184 case 4:
185 ival = *(int *)&dummy_var[i];
186 break;
187 case 8:
188 lval = *(long long *)&dummy_var[i];
189 break;
190 }
191 check_trapped();
192 }
193}
194
195/*
196 * Do the r/w/x accesses to trigger the breakpoints. And run
197 * the usual traps.
198 */
199static void trigger_tests(void)
200{
201 int len, local, global, i;
202 char val;
203 int ret;
204
205 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
206 if (ret) {
207 perror("Can't be traced?\n");
208 return;
209 }
210
211 /* Wake up father so that it sets up the first test */
212 kill(getpid(), SIGUSR1);
213
214 /* Test instruction breakpoints */
215 for (local = 0; local < 2; local++) {
216 for (global = 0; global < 2; global++) {
217 if (!local && !global)
218 continue;
219
220 for (i = 0; i < 4; i++) {
221 dummy_funcs[i]();
222 check_trapped();
223 }
224 }
225 }
226
227 /* Test write watchpoints */
228 for (len = 1; len <= sizeof(long); len <<= 1) {
229 for (local = 0; local < 2; local++) {
230 for (global = 0; global < 2; global++) {
231 if (!local && !global)
232 continue;
233 write_var(len);
234 }
235 }
236 }
237
238 /* Test read/write watchpoints (on read accesses) */
239 for (len = 1; len <= sizeof(long); len <<= 1) {
240 for (local = 0; local < 2; local++) {
241 for (global = 0; global < 2; global++) {
242 if (!local && !global)
243 continue;
244 read_var(len);
245 }
246 }
247 }
248
249 /* Icebp trap */
250 asm(".byte 0xf1\n");
251 check_trapped();
252
253 /* Int 3 trap */
254 asm("int $3\n");
255 check_trapped();
256
257 kill(getpid(), SIGUSR1);
258}
259
260static void check_success(const char *msg)
261{
262 const char *msg2;
263 int child_nr_tests;
264 int status;
265
266 /* Wait for the child to SIGTRAP */
267 wait(&status);
268
269 msg2 = "Failed";
270
271 if (WSTOPSIG(status) == SIGTRAP) {
272 child_nr_tests = ptrace(PTRACE_PEEKDATA, child_pid,
273 &nr_tests, 0);
274 if (child_nr_tests == nr_tests)
275 msg2 = "Ok";
276 if (ptrace(PTRACE_POKEDATA, child_pid, &trapped, 1)) {
277 perror("Can't poke\n");
278 exit(-1);
279 }
280 }
281
282 nr_tests++;
283
284 printf("%s [%s]\n", msg, msg2);
285}
286
287static void launch_instruction_breakpoints(char *buf, int local, int global)
288{
289 int i;
290
291 for (i = 0; i < 4; i++) {
292 set_breakpoint_addr(dummy_funcs[i], i);
293 toggle_breakpoint(i, BP_X, 1, local, global, 1);
294 ptrace(PTRACE_CONT, child_pid, NULL, 0);
295 sprintf(buf, "Test breakpoint %d with local: %d global: %d",
296 i, local, global);
297 check_success(buf);
298 toggle_breakpoint(i, BP_X, 1, local, global, 0);
299 }
300}
301
302static void launch_watchpoints(char *buf, int mode, int len,
303 int local, int global)
304{
305 const char *mode_str;
306 int i;
307
308 if (mode == BP_W)
309 mode_str = "write";
310 else
311 mode_str = "read";
312
313 for (i = 0; i < 4; i++) {
314 set_breakpoint_addr(&dummy_var[i], i);
315 toggle_breakpoint(i, mode, len, local, global, 1);
316 ptrace(PTRACE_CONT, child_pid, NULL, 0);
317 sprintf(buf, "Test %s watchpoint %d with len: %d local: "
318 "%d global: %d", mode_str, i, len, local, global);
319 check_success(buf);
320 toggle_breakpoint(i, mode, len, local, global, 0);
321 }
322}
323
324/* Set the breakpoints and check the child successfully trigger them */
325static void launch_tests(void)
326{
327 char buf[1024];
328 int len, local, global, i;
329
330 /* Instruction breakpoints */
331 for (local = 0; local < 2; local++) {
332 for (global = 0; global < 2; global++) {
333 if (!local && !global)
334 continue;
335 launch_instruction_breakpoints(buf, local, global);
336 }
337 }
338
339 /* Write watchpoint */
340 for (len = 1; len <= sizeof(long); len <<= 1) {
341 for (local = 0; local < 2; local++) {
342 for (global = 0; global < 2; global++) {
343 if (!local && !global)
344 continue;
345 launch_watchpoints(buf, BP_W, len,
346 local, global);
347 }
348 }
349 }
350
351 /* Read-Write watchpoint */
352 for (len = 1; len <= sizeof(long); len <<= 1) {
353 for (local = 0; local < 2; local++) {
354 for (global = 0; global < 2; global++) {
355 if (!local && !global)
356 continue;
357 launch_watchpoints(buf, BP_RW, len,
358 local, global);
359 }
360 }
361 }
362
363 /* Icebp traps */
364 ptrace(PTRACE_CONT, child_pid, NULL, 0);
365 check_success("Test icebp");
366
367 /* Int 3 traps */
368 ptrace(PTRACE_CONT, child_pid, NULL, 0);
369 check_success("Test int 3 trap");
370
371 ptrace(PTRACE_CONT, child_pid, NULL, 0);
372}
373
374int main(int argc, char **argv)
375{
376 pid_t pid;
377 int ret;
378
379 pid = fork();
380 if (!pid) {
381 trigger_tests();
382 return 0;
383 }
384
385 child_pid = pid;
386
387 wait(NULL);
388
389 launch_tests();
390
391 wait(NULL);
392
393 return 0;
394}
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
deleted file mode 100644
index 12657a5e4bf..00000000000
--- a/tools/testing/selftests/cpu-hotplug/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
1all:
2
3run_tests:
4 @./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
5
6clean:
diff --git a/tools/testing/selftests/cpu-hotplug/on-off-test.sh b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
deleted file mode 100644
index bdde7cf428b..00000000000
--- a/tools/testing/selftests/cpu-hotplug/on-off-test.sh
+++ /dev/null
@@ -1,221 +0,0 @@
1#!/bin/bash
2
3SYSFS=
4
5prerequisite()
6{
7 msg="skip all tests:"
8
9 if [ $UID != 0 ]; then
10 echo $msg must be run as root >&2
11 exit 0
12 fi
13
14 SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
15
16 if [ ! -d "$SYSFS" ]; then
17 echo $msg sysfs is not mounted >&2
18 exit 0
19 fi
20
21 if ! ls $SYSFS/devices/system/cpu/cpu* > /dev/null 2>&1; then
22 echo $msg cpu hotplug is not supported >&2
23 exit 0
24 fi
25}
26
27#
28# list all hot-pluggable CPUs
29#
30hotpluggable_cpus()
31{
32 local state=${1:-.\*}
33
34 for cpu in $SYSFS/devices/system/cpu/cpu*; do
35 if [ -f $cpu/online ] && grep -q $state $cpu/online; then
36 echo ${cpu##/*/cpu}
37 fi
38 done
39}
40
41hotplaggable_offline_cpus()
42{
43 hotpluggable_cpus 0
44}
45
46hotpluggable_online_cpus()
47{
48 hotpluggable_cpus 1
49}
50
51cpu_is_online()
52{
53 grep -q 1 $SYSFS/devices/system/cpu/cpu$1/online
54}
55
56cpu_is_offline()
57{
58 grep -q 0 $SYSFS/devices/system/cpu/cpu$1/online
59}
60
61online_cpu()
62{
63 echo 1 > $SYSFS/devices/system/cpu/cpu$1/online
64}
65
66offline_cpu()
67{
68 echo 0 > $SYSFS/devices/system/cpu/cpu$1/online
69}
70
71online_cpu_expect_success()
72{
73 local cpu=$1
74
75 if ! online_cpu $cpu; then
76 echo $FUNCNAME $cpu: unexpected fail >&2
77 elif ! cpu_is_online $cpu; then
78 echo $FUNCNAME $cpu: unexpected offline >&2
79 fi
80}
81
82online_cpu_expect_fail()
83{
84 local cpu=$1
85
86 if online_cpu $cpu 2> /dev/null; then
87 echo $FUNCNAME $cpu: unexpected success >&2
88 elif ! cpu_is_offline $cpu; then
89 echo $FUNCNAME $cpu: unexpected online >&2
90 fi
91}
92
93offline_cpu_expect_success()
94{
95 local cpu=$1
96
97 if ! offline_cpu $cpu; then
98 echo $FUNCNAME $cpu: unexpected fail >&2
99 elif ! cpu_is_offline $cpu; then
100 echo $FUNCNAME $cpu: unexpected offline >&2
101 fi
102}
103
104offline_cpu_expect_fail()
105{
106 local cpu=$1
107
108 if offline_cpu $cpu 2> /dev/null; then
109 echo $FUNCNAME $cpu: unexpected success >&2
110 elif ! cpu_is_online $cpu; then
111 echo $FUNCNAME $cpu: unexpected offline >&2
112 fi
113}
114
115error=-12
116priority=0
117
118while getopts e:hp: opt; do
119 case $opt in
120 e)
121 error=$OPTARG
122 ;;
123 h)
124 echo "Usage $0 [ -e errno ] [ -p notifier-priority ]"
125 exit
126 ;;
127 p)
128 priority=$OPTARG
129 ;;
130 esac
131done
132
133if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
134 echo "error code must be -4095 <= errno < 0" >&2
135 exit 1
136fi
137
138prerequisite
139
140#
141# Online all hot-pluggable CPUs
142#
143for cpu in `hotplaggable_offline_cpus`; do
144 online_cpu_expect_success $cpu
145done
146
147#
148# Offline all hot-pluggable CPUs
149#
150for cpu in `hotpluggable_online_cpus`; do
151 offline_cpu_expect_success $cpu
152done
153
154#
155# Online all hot-pluggable CPUs again
156#
157for cpu in `hotplaggable_offline_cpus`; do
158 online_cpu_expect_success $cpu
159done
160
161#
162# Test with cpu notifier error injection
163#
164
165DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
166NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/cpu
167
168prerequisite_extra()
169{
170 msg="skip extra tests:"
171
172 /sbin/modprobe -q -r cpu-notifier-error-inject
173 /sbin/modprobe -q cpu-notifier-error-inject priority=$priority
174
175 if [ ! -d "$DEBUGFS" ]; then
176 echo $msg debugfs is not mounted >&2
177 exit 0
178 fi
179
180 if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
181 echo $msg cpu-notifier-error-inject module is not available >&2
182 exit 0
183 fi
184}
185
186prerequisite_extra
187
188#
189# Offline all hot-pluggable CPUs
190#
191echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
192for cpu in `hotpluggable_online_cpus`; do
193 offline_cpu_expect_success $cpu
194done
195
196#
197# Test CPU hot-add error handling (offline => online)
198#
199echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
200for cpu in `hotplaggable_offline_cpus`; do
201 online_cpu_expect_fail $cpu
202done
203
204#
205# Online all hot-pluggable CPUs
206#
207echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
208for cpu in `hotplaggable_offline_cpus`; do
209 online_cpu_expect_success $cpu
210done
211
212#
213# Test CPU hot-remove error handling (online => offline)
214#
215echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
216for cpu in `hotpluggable_online_cpus`; do
217 offline_cpu_expect_fail $cpu
218done
219
220echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
221/sbin/modprobe -q -r cpu-notifier-error-inject
diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile
deleted file mode 100644
index 5386fd7c43a..00000000000
--- a/tools/testing/selftests/ipc/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386)
4 ARCH := X86
5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := X86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif
11
12CFLAGS += -I../../../../usr/include/
13
14all:
15ifeq ($(ARCH),X86)
16 gcc $(CFLAGS) msgque.c -o msgque_test
17else
18 echo "Not an x86 target, can't build msgque selftest"
19endif
20
21run_tests: all
22 ./msgque_test
23
24clean:
25 rm -fr ./msgque_test
diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c
deleted file mode 100644
index d66418237d2..00000000000
--- a/tools/testing/selftests/ipc/msgque.c
+++ /dev/null
@@ -1,246 +0,0 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <errno.h>
5#include <linux/msg.h>
6#include <fcntl.h>
7
8#define MAX_MSG_SIZE 32
9
10struct msg1 {
11 int msize;
12 long mtype;
13 char mtext[MAX_MSG_SIZE];
14};
15
16#define TEST_STRING "Test sysv5 msg"
17#define MSG_TYPE 1
18
19#define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
20#define ANOTHER_MSG_TYPE 26538
21
22struct msgque_data {
23 key_t key;
24 int msq_id;
25 int qbytes;
26 int qnum;
27 int mode;
28 struct msg1 *messages;
29};
30
31int restore_queue(struct msgque_data *msgque)
32{
33 int fd, ret, id, i;
34 char buf[32];
35
36 fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
37 if (fd == -1) {
38 printf("Failed to open /proc/sys/kernel/msg_next_id\n");
39 return -errno;
40 }
41 sprintf(buf, "%d", msgque->msq_id);
42
43 ret = write(fd, buf, strlen(buf));
44 if (ret != strlen(buf)) {
45 printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
46 return -errno;
47 }
48
49 id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
50 if (id == -1) {
51 printf("Failed to create queue\n");
52 return -errno;
53 }
54
55 if (id != msgque->msq_id) {
56 printf("Restored queue has wrong id (%d instead of %d)\n",
57 id, msgque->msq_id);
58 ret = -EFAULT;
59 goto destroy;
60 }
61
62 for (i = 0; i < msgque->qnum; i++) {
63 if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
64 msgque->messages[i].msize, IPC_NOWAIT) != 0) {
65 printf("msgsnd failed (%m)\n");
66 ret = -errno;
67 goto destroy;
68 };
69 }
70 return 0;
71
72destroy:
73 if (msgctl(id, IPC_RMID, 0))
74 printf("Failed to destroy queue: %d\n", -errno);
75 return ret;
76}
77
78int check_and_destroy_queue(struct msgque_data *msgque)
79{
80 struct msg1 message;
81 int cnt = 0, ret;
82
83 while (1) {
84 ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
85 0, IPC_NOWAIT);
86 if (ret < 0) {
87 if (errno == ENOMSG)
88 break;
89 printf("Failed to read IPC message: %m\n");
90 ret = -errno;
91 goto err;
92 }
93 if (ret != msgque->messages[cnt].msize) {
94 printf("Wrong message size: %d (expected %d)\n", ret,
95 msgque->messages[cnt].msize);
96 ret = -EINVAL;
97 goto err;
98 }
99 if (message.mtype != msgque->messages[cnt].mtype) {
100 printf("Wrong message type\n");
101 ret = -EINVAL;
102 goto err;
103 }
104 if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
105 printf("Wrong message content\n");
106 ret = -EINVAL;
107 goto err;
108 }
109 cnt++;
110 }
111
112 if (cnt != msgque->qnum) {
113 printf("Wrong message number\n");
114 ret = -EINVAL;
115 goto err;
116 }
117
118 ret = 0;
119err:
120 if (msgctl(msgque->msq_id, IPC_RMID, 0)) {
121 printf("Failed to destroy queue: %d\n", -errno);
122 return -errno;
123 }
124 return ret;
125}
126
127int dump_queue(struct msgque_data *msgque)
128{
129 struct msqid64_ds ds;
130 int kern_id;
131 int i, ret;
132
133 for (kern_id = 0; kern_id < 256; kern_id++) {
134 ret = msgctl(kern_id, MSG_STAT, &ds);
135 if (ret < 0) {
136 if (errno == -EINVAL)
137 continue;
138 printf("Failed to get stats for IPC queue with id %d\n",
139 kern_id);
140 return -errno;
141 }
142
143 if (ret == msgque->msq_id)
144 break;
145 }
146
147 msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
148 if (msgque->messages == NULL) {
149 printf("Failed to get stats for IPC queue\n");
150 return -ENOMEM;
151 }
152
153 msgque->qnum = ds.msg_qnum;
154 msgque->mode = ds.msg_perm.mode;
155 msgque->qbytes = ds.msg_qbytes;
156
157 for (i = 0; i < msgque->qnum; i++) {
158 ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
159 MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
160 if (ret < 0) {
161 printf("Failed to copy IPC message: %m (%d)\n", errno);
162 return -errno;
163 }
164 msgque->messages[i].msize = ret;
165 }
166 return 0;
167}
168
169int fill_msgque(struct msgque_data *msgque)
170{
171 struct msg1 msgbuf;
172
173 msgbuf.mtype = MSG_TYPE;
174 memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
175 if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
176 IPC_NOWAIT) != 0) {
177 printf("First message send failed (%m)\n");
178 return -errno;
179 };
180
181 msgbuf.mtype = ANOTHER_MSG_TYPE;
182 memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
183 if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
184 IPC_NOWAIT) != 0) {
185 printf("Second message send failed (%m)\n");
186 return -errno;
187 };
188 return 0;
189}
190
191int main(int argc, char **argv)
192{
193 int msg, pid, err;
194 struct msgque_data msgque;
195
196 msgque.key = ftok(argv[0], 822155650);
197 if (msgque.key == -1) {
198 printf("Can't make key\n");
199 return -errno;
200 }
201
202 msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
203 if (msgque.msq_id == -1) {
204 printf("Can't create queue\n");
205 goto err_out;
206 }
207
208 err = fill_msgque(&msgque);
209 if (err) {
210 printf("Failed to fill queue\n");
211 goto err_destroy;
212 }
213
214 err = dump_queue(&msgque);
215 if (err) {
216 printf("Failed to dump queue\n");
217 goto err_destroy;
218 }
219
220 err = check_and_destroy_queue(&msgque);
221 if (err) {
222 printf("Failed to check and destroy queue\n");
223 goto err_out;
224 }
225
226 err = restore_queue(&msgque);
227 if (err) {
228 printf("Failed to restore queue\n");
229 goto err_destroy;
230 }
231
232 err = check_and_destroy_queue(&msgque);
233 if (err) {
234 printf("Failed to test queue\n");
235 goto err_out;
236 }
237 return 0;
238
239err_destroy:
240 if (msgctl(msgque.msq_id, IPC_RMID, 0)) {
241 printf("Failed to destroy queue: %d\n", -errno);
242 return -errno;
243 }
244err_out:
245 return err;
246}
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
deleted file mode 100644
index 56eb5523dbb..00000000000
--- a/tools/testing/selftests/kcmp/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386)
4 ARCH := X86
5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := X86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif
11
12CFLAGS += -I../../../../arch/x86/include/generated/
13CFLAGS += -I../../../../include/
14CFLAGS += -I../../../../usr/include/
15CFLAGS += -I../../../../arch/x86/include/
16
17all:
18ifeq ($(ARCH),X86)
19 gcc $(CFLAGS) kcmp_test.c -o kcmp_test
20else
21 echo "Not an x86 target, can't build kcmp selftest"
22endif
23
24run_tests: all
25 @./kcmp_test || echo "kcmp_test: [FAIL]"
26
27clean:
28 rm -fr ./run_test
29 rm -fr ./test-file
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
deleted file mode 100644
index fa4f1b37e04..00000000000
--- a/tools/testing/selftests/kcmp/kcmp_test.c
+++ /dev/null
@@ -1,96 +0,0 @@
1#define _GNU_SOURCE
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <signal.h>
6#include <limits.h>
7#include <unistd.h>
8#include <errno.h>
9#include <string.h>
10#include <fcntl.h>
11
12#include <linux/unistd.h>
13#include <linux/kcmp.h>
14
15#include <sys/syscall.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/wait.h>
19
20static long sys_kcmp(int pid1, int pid2, int type, int fd1, int fd2)
21{
22 return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2);
23}
24
25int main(int argc, char **argv)
26{
27 const char kpath[] = "kcmp-test-file";
28 int pid1, pid2;
29 int fd1, fd2;
30 int status;
31
32 fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644);
33 pid1 = getpid();
34
35 if (fd1 < 0) {
36 perror("Can't create file");
37 exit(1);
38 }
39
40 pid2 = fork();
41 if (pid2 < 0) {
42 perror("fork failed");
43 exit(1);
44 }
45
46 if (!pid2) {
47 int pid2 = getpid();
48 int ret;
49
50 fd2 = open(kpath, O_RDWR, 0644);
51 if (fd2 < 0) {
52 perror("Can't open file");
53 exit(1);
54 }
55
56 /* An example of output and arguments */
57 printf("pid1: %6d pid2: %6d FD: %2ld FILES: %2ld VM: %2ld "
58 "FS: %2ld SIGHAND: %2ld IO: %2ld SYSVSEM: %2ld "
59 "INV: %2ld\n",
60 pid1, pid2,
61 sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd2),
62 sys_kcmp(pid1, pid2, KCMP_FILES, 0, 0),
63 sys_kcmp(pid1, pid2, KCMP_VM, 0, 0),
64 sys_kcmp(pid1, pid2, KCMP_FS, 0, 0),
65 sys_kcmp(pid1, pid2, KCMP_SIGHAND, 0, 0),
66 sys_kcmp(pid1, pid2, KCMP_IO, 0, 0),
67 sys_kcmp(pid1, pid2, KCMP_SYSVSEM, 0, 0),
68
69 /* This one should fail */
70 sys_kcmp(pid1, pid2, KCMP_TYPES + 1, 0, 0));
71
72 /* This one should return same fd */
73 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1);
74 if (ret) {
75 printf("FAIL: 0 expected but %d returned (%s)\n",
76 ret, strerror(errno));
77 ret = -1;
78 } else
79 printf("PASS: 0 returned as expected\n");
80
81 /* Compare with self */
82 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
83 if (ret) {
84 printf("FAIL: 0 expected but %li returned (%s)\n",
85 ret, strerror(errno));
86 ret = -1;
87 } else
88 printf("PASS: 0 returned as expected\n");
89
90 exit(ret);
91 }
92
93 waitpid(pid2, &status, P_ALL);
94
95 return 0;
96}
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
deleted file mode 100644
index 0f49c3f5f58..00000000000
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
1all:
2
3run_tests:
4 @./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
5
6clean:
diff --git a/tools/testing/selftests/memory-hotplug/on-off-test.sh b/tools/testing/selftests/memory-hotplug/on-off-test.sh
deleted file mode 100644
index a2816f63154..00000000000
--- a/tools/testing/selftests/memory-hotplug/on-off-test.sh
+++ /dev/null
@@ -1,230 +0,0 @@
1#!/bin/bash
2
3SYSFS=
4
5prerequisite()
6{
7 msg="skip all tests:"
8
9 if [ $UID != 0 ]; then
10 echo $msg must be run as root >&2
11 exit 0
12 fi
13
14 SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
15
16 if [ ! -d "$SYSFS" ]; then
17 echo $msg sysfs is not mounted >&2
18 exit 0
19 fi
20
21 if ! ls $SYSFS/devices/system/memory/memory* > /dev/null 2>&1; then
22 echo $msg memory hotplug is not supported >&2
23 exit 0
24 fi
25}
26
27#
28# list all hot-pluggable memory
29#
30hotpluggable_memory()
31{
32 local state=${1:-.\*}
33
34 for memory in $SYSFS/devices/system/memory/memory*; do
35 if grep -q 1 $memory/removable &&
36 grep -q $state $memory/state; then
37 echo ${memory##/*/memory}
38 fi
39 done
40}
41
42hotplaggable_offline_memory()
43{
44 hotpluggable_memory offline
45}
46
47hotpluggable_online_memory()
48{
49 hotpluggable_memory online
50}
51
52memory_is_online()
53{
54 grep -q online $SYSFS/devices/system/memory/memory$1/state
55}
56
57memory_is_offline()
58{
59 grep -q offline $SYSFS/devices/system/memory/memory$1/state
60}
61
62online_memory()
63{
64 echo online > $SYSFS/devices/system/memory/memory$1/state
65}
66
67offline_memory()
68{
69 echo offline > $SYSFS/devices/system/memory/memory$1/state
70}
71
72online_memory_expect_success()
73{
74 local memory=$1
75
76 if ! online_memory $memory; then
77 echo $FUNCNAME $memory: unexpected fail >&2
78 elif ! memory_is_online $memory; then
79 echo $FUNCNAME $memory: unexpected offline >&2
80 fi
81}
82
83online_memory_expect_fail()
84{
85 local memory=$1
86
87 if online_memory $memory 2> /dev/null; then
88 echo $FUNCNAME $memory: unexpected success >&2
89 elif ! memory_is_offline $memory; then
90 echo $FUNCNAME $memory: unexpected online >&2
91 fi
92}
93
94offline_memory_expect_success()
95{
96 local memory=$1
97
98 if ! offline_memory $memory; then
99 echo $FUNCNAME $memory: unexpected fail >&2
100 elif ! memory_is_offline $memory; then
101 echo $FUNCNAME $memory: unexpected offline >&2
102 fi
103}
104
105offline_memory_expect_fail()
106{
107 local memory=$1
108
109 if offline_memory $memory 2> /dev/null; then
110 echo $FUNCNAME $memory: unexpected success >&2
111 elif ! memory_is_online $memory; then
112 echo $FUNCNAME $memory: unexpected offline >&2
113 fi
114}
115
116error=-12
117priority=0
118ratio=10
119
120while getopts e:hp:r: opt; do
121 case $opt in
122 e)
123 error=$OPTARG
124 ;;
125 h)
126 echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]"
127 exit
128 ;;
129 p)
130 priority=$OPTARG
131 ;;
132 r)
133 ratio=$OPTARG
134 ;;
135 esac
136done
137
138if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
139 echo "error code must be -4095 <= errno < 0" >&2
140 exit 1
141fi
142
143prerequisite
144
145#
146# Online all hot-pluggable memory
147#
148for memory in `hotplaggable_offline_memory`; do
149 online_memory_expect_success $memory
150done
151
152#
153# Offline $ratio percent of hot-pluggable memory
154#
155for memory in `hotpluggable_online_memory`; do
156 if [ $((RANDOM % 100)) -lt $ratio ]; then
157 offline_memory_expect_success $memory
158 fi
159done
160
161#
162# Online all hot-pluggable memory again
163#
164for memory in `hotplaggable_offline_memory`; do
165 online_memory_expect_success $memory
166done
167
168#
169# Test with memory notifier error injection
170#
171
172DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
173NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory
174
175prerequisite_extra()
176{
177 msg="skip extra tests:"
178
179 /sbin/modprobe -q -r memory-notifier-error-inject
180 /sbin/modprobe -q memory-notifier-error-inject priority=$priority
181
182 if [ ! -d "$DEBUGFS" ]; then
183 echo $msg debugfs is not mounted >&2
184 exit 0
185 fi
186
187 if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
188 echo $msg memory-notifier-error-inject module is not available >&2
189 exit 0
190 fi
191}
192
193prerequisite_extra
194
195#
196# Offline $ratio percent of hot-pluggable memory
197#
198echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
199for memory in `hotpluggable_online_memory`; do
200 if [ $((RANDOM % 100)) -lt $ratio ]; then
201 offline_memory_expect_success $memory
202 fi
203done
204
205#
206# Test memory hot-add error handling (offline => online)
207#
208echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
209for memory in `hotplaggable_offline_memory`; do
210 online_memory_expect_fail $memory
211done
212
213#
214# Online all hot-pluggable memory
215#
216echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
217for memory in `hotplaggable_offline_memory`; do
218 online_memory_expect_success $memory
219done
220
221#
222# Test memory hot-remove error handling (online => offline)
223#
224echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
225for memory in `hotpluggable_online_memory`; do
226 offline_memory_expect_fail $memory
227done
228
229echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
230/sbin/modprobe -q -r memory-notifier-error-inject
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
deleted file mode 100644
index 218a122c795..00000000000
--- a/tools/testing/selftests/mqueue/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
1all:
2 gcc -O2 -lrt mq_open_tests.c -o mq_open_tests
3 gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c
4
5run_tests:
6 @./mq_open_tests /test1 || echo "mq_open_tests: [FAIL]"
7 @./mq_perf_tests || echo "mq_perf_tests: [FAIL]"
8
9clean:
10 rm -f mq_open_tests mq_perf_tests
diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
deleted file mode 100644
index 711cc292304..00000000000
--- a/tools/testing/selftests/mqueue/mq_open_tests.c
+++ /dev/null
@@ -1,492 +0,0 @@
1/*
2 * This application is Copyright 2012 Red Hat, Inc.
3 * Doug Ledford <dledford@redhat.com>
4 *
5 * mq_open_tests is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * mq_open_tests is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * For the full text of the license, see <http://www.gnu.org/licenses/>.
15 *
16 * mq_open_tests.c
17 * Tests the various situations that should either succeed or fail to
18 * open a posix message queue and then reports whether or not they
19 * did as they were supposed to.
20 *
21 */
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <string.h>
27#include <limits.h>
28#include <errno.h>
29#include <sys/types.h>
30#include <sys/time.h>
31#include <sys/resource.h>
32#include <sys/stat.h>
33#include <mqueue.h>
34
35static char *usage =
36"Usage:\n"
37" %s path\n"
38"\n"
39" path Path name of the message queue to create\n"
40"\n"
41" Note: this program must be run as root in order to enable all tests\n"
42"\n";
43
44char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
45char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
46char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
47char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
48
49int default_settings;
50struct rlimit saved_limits, cur_limits;
51int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
52int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
53FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
54char *queue_path;
55mqd_t queue = -1;
56
57static inline void __set(FILE *stream, int value, char *err_msg);
58void shutdown(int exit_val, char *err_cause, int line_no);
59static inline int get(FILE *stream);
60static inline void set(FILE *stream, int value);
61static inline void getr(int type, struct rlimit *rlim);
62static inline void setr(int type, struct rlimit *rlim);
63void validate_current_settings();
64static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
65static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
66
67static inline void __set(FILE *stream, int value, char *err_msg)
68{
69 rewind(stream);
70 if (fprintf(stream, "%d", value) < 0)
71 perror(err_msg);
72}
73
74
75void shutdown(int exit_val, char *err_cause, int line_no)
76{
77 static int in_shutdown = 0;
78
79 /* In case we get called recursively by a set() call below */
80 if (in_shutdown++)
81 return;
82
83 seteuid(0);
84
85 if (queue != -1)
86 if (mq_close(queue))
87 perror("mq_close() during shutdown");
88 if (queue_path)
89 /*
90 * Be silent if this fails, if we cleaned up already it's
91 * expected to fail
92 */
93 mq_unlink(queue_path);
94 if (default_settings) {
95 if (saved_def_msgs)
96 __set(def_msgs, saved_def_msgs,
97 "failed to restore saved_def_msgs");
98 if (saved_def_msgsize)
99 __set(def_msgsize, saved_def_msgsize,
100 "failed to restore saved_def_msgsize");
101 }
102 if (saved_max_msgs)
103 __set(max_msgs, saved_max_msgs,
104 "failed to restore saved_max_msgs");
105 if (saved_max_msgsize)
106 __set(max_msgsize, saved_max_msgsize,
107 "failed to restore saved_max_msgsize");
108 if (exit_val)
109 error(exit_val, errno, "%s at %d", err_cause, line_no);
110 exit(0);
111}
112
113static inline int get(FILE *stream)
114{
115 int value;
116 rewind(stream);
117 if (fscanf(stream, "%d", &value) != 1)
118 shutdown(4, "Error reading /proc entry", __LINE__ - 1);
119 return value;
120}
121
122static inline void set(FILE *stream, int value)
123{
124 int new_value;
125
126 rewind(stream);
127 if (fprintf(stream, "%d", value) < 0)
128 return shutdown(5, "Failed writing to /proc file",
129 __LINE__ - 1);
130 new_value = get(stream);
131 if (new_value != value)
132 return shutdown(5, "We didn't get what we wrote to /proc back",
133 __LINE__ - 1);
134}
135
136static inline void getr(int type, struct rlimit *rlim)
137{
138 if (getrlimit(type, rlim))
139 shutdown(6, "getrlimit()", __LINE__ - 1);
140}
141
142static inline void setr(int type, struct rlimit *rlim)
143{
144 if (setrlimit(type, rlim))
145 shutdown(7, "setrlimit()", __LINE__ - 1);
146}
147
148void validate_current_settings()
149{
150 int rlim_needed;
151
152 if (cur_limits.rlim_cur < 4096) {
153 printf("Current rlimit value for POSIX message queue bytes is "
154 "unreasonably low,\nincreasing.\n\n");
155 cur_limits.rlim_cur = 8192;
156 cur_limits.rlim_max = 16384;
157 setr(RLIMIT_MSGQUEUE, &cur_limits);
158 }
159
160 if (default_settings) {
161 rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
162 2 * sizeof(void *));
163 if (rlim_needed > cur_limits.rlim_cur) {
164 printf("Temporarily lowering default queue parameters "
165 "to something that will work\n"
166 "with the current rlimit values.\n\n");
167 set(def_msgs, 10);
168 cur_def_msgs = 10;
169 set(def_msgsize, 128);
170 cur_def_msgsize = 128;
171 }
172 } else {
173 rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
174 2 * sizeof(void *));
175 if (rlim_needed > cur_limits.rlim_cur) {
176 printf("Temporarily lowering maximum queue parameters "
177 "to something that will work\n"
178 "with the current rlimit values in case this is "
179 "a kernel that ties the default\n"
180 "queue parameters to the maximum queue "
181 "parameters.\n\n");
182 set(max_msgs, 10);
183 cur_max_msgs = 10;
184 set(max_msgsize, 128);
185 cur_max_msgsize = 128;
186 }
187 }
188}
189
190/*
191 * test_queue - Test opening a queue, shutdown if we fail. This should
192 * only be called in situations that should never fail. We clean up
193 * after ourselves and return the queue attributes in *result.
194 */
195static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
196{
197 int flags = O_RDWR | O_EXCL | O_CREAT;
198 int perms = DEFFILEMODE;
199
200 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
201 shutdown(1, "mq_open()", __LINE__);
202 if (mq_getattr(queue, result))
203 shutdown(1, "mq_getattr()", __LINE__);
204 if (mq_close(queue))
205 shutdown(1, "mq_close()", __LINE__);
206 queue = -1;
207 if (mq_unlink(queue_path))
208 shutdown(1, "mq_unlink()", __LINE__);
209}
210
211/*
212 * Same as test_queue above, but failure is not fatal.
213 * Returns:
214 * 0 - Failed to create a queue
215 * 1 - Created a queue, attributes in *result
216 */
217static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
218{
219 int flags = O_RDWR | O_EXCL | O_CREAT;
220 int perms = DEFFILEMODE;
221
222 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
223 return 0;
224 if (mq_getattr(queue, result))
225 shutdown(1, "mq_getattr()", __LINE__);
226 if (mq_close(queue))
227 shutdown(1, "mq_close()", __LINE__);
228 queue = -1;
229 if (mq_unlink(queue_path))
230 shutdown(1, "mq_unlink()", __LINE__);
231 return 1;
232}
233
234int main(int argc, char *argv[])
235{
236 struct mq_attr attr, result;
237
238 if (argc != 2) {
239 fprintf(stderr, "Must pass a valid queue name\n\n");
240 fprintf(stderr, usage, argv[0]);
241 exit(1);
242 }
243
244 /*
245 * Although we can create a msg queue with a non-absolute path name,
246 * unlink will fail. So, if the name doesn't start with a /, add one
247 * when we save it.
248 */
249 if (*argv[1] == '/')
250 queue_path = strdup(argv[1]);
251 else {
252 queue_path = malloc(strlen(argv[1]) + 2);
253 if (!queue_path) {
254 perror("malloc()");
255 exit(1);
256 }
257 queue_path[0] = '/';
258 queue_path[1] = 0;
259 strcat(queue_path, argv[1]);
260 }
261
262 if (getuid() != 0) {
263 fprintf(stderr, "Not running as root, but almost all tests "
264 "require root in order to modify\nsystem settings. "
265 "Exiting.\n");
266 exit(1);
267 }
268
269 /* Find out what files there are for us to make tweaks in */
270 def_msgs = fopen(DEF_MSGS, "r+");
271 def_msgsize = fopen(DEF_MSGSIZE, "r+");
272 max_msgs = fopen(MAX_MSGS, "r+");
273 max_msgsize = fopen(MAX_MSGSIZE, "r+");
274
275 if (!max_msgs)
276 shutdown(2, "Failed to open msg_max", __LINE__);
277 if (!max_msgsize)
278 shutdown(2, "Failed to open msgsize_max", __LINE__);
279 if (def_msgs || def_msgsize)
280 default_settings = 1;
281
282 /* Load up the current system values for everything we can */
283 getr(RLIMIT_MSGQUEUE, &saved_limits);
284 cur_limits = saved_limits;
285 if (default_settings) {
286 saved_def_msgs = cur_def_msgs = get(def_msgs);
287 saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
288 }
289 saved_max_msgs = cur_max_msgs = get(max_msgs);
290 saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
291
292 /* Tell the user our initial state */
293 printf("\nInitial system state:\n");
294 printf("\tUsing queue path:\t\t%s\n", queue_path);
295 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur);
296 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max);
297 printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
298 printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
299 if (default_settings) {
300 printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
301 printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
302 } else {
303 printf("\tDefault Message Size:\t\tNot Supported\n");
304 printf("\tDefault Queue Size:\t\tNot Supported\n");
305 }
306 printf("\n");
307
308 validate_current_settings();
309
310 printf("Adjusted system state for testing:\n");
311 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur);
312 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max);
313 printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
314 printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
315 if (default_settings) {
316 printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
317 printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
318 }
319
320 printf("\n\nTest series 1, behavior when no attr struct "
321 "passed to mq_open:\n");
322 if (!default_settings) {
323 test_queue(NULL, &result);
324 printf("Given sane system settings, mq_open without an attr "
325 "struct succeeds:\tPASS\n");
326 if (result.mq_maxmsg != cur_max_msgs ||
327 result.mq_msgsize != cur_max_msgsize) {
328 printf("Kernel does not support setting the default "
329 "mq attributes,\nbut also doesn't tie the "
330 "defaults to the maximums:\t\t\tPASS\n");
331 } else {
332 set(max_msgs, ++cur_max_msgs);
333 set(max_msgsize, ++cur_max_msgsize);
334 test_queue(NULL, &result);
335 if (result.mq_maxmsg == cur_max_msgs &&
336 result.mq_msgsize == cur_max_msgsize)
337 printf("Kernel does not support setting the "
338 "default mq attributes and\n"
339 "also ties system wide defaults to "
340 "the system wide maximums:\t\t"
341 "FAIL\n");
342 else
343 printf("Kernel does not support setting the "
344 "default mq attributes,\n"
345 "but also doesn't tie the defaults to "
346 "the maximums:\t\t\tPASS\n");
347 }
348 } else {
349 printf("Kernel supports setting defaults separately from "
350 "maximums:\t\tPASS\n");
351 /*
352 * While we are here, go ahead and test that the kernel
353 * properly follows the default settings
354 */
355 test_queue(NULL, &result);
356 printf("Given sane values, mq_open without an attr struct "
357 "succeeds:\t\tPASS\n");
358 if (result.mq_maxmsg != cur_def_msgs ||
359 result.mq_msgsize != cur_def_msgsize)
360 printf("Kernel supports setting defaults, but does "
361 "not actually honor them:\tFAIL\n\n");
362 else {
363 set(def_msgs, ++cur_def_msgs);
364 set(def_msgsize, ++cur_def_msgsize);
365 /* In case max was the same as the default */
366 set(max_msgs, ++cur_max_msgs);
367 set(max_msgsize, ++cur_max_msgsize);
368 test_queue(NULL, &result);
369 if (result.mq_maxmsg != cur_def_msgs ||
370 result.mq_msgsize != cur_def_msgsize)
371 printf("Kernel supports setting defaults, but "
372 "does not actually honor them:\t"
373 "FAIL\n");
374 else
375 printf("Kernel properly honors default setting "
376 "knobs:\t\t\t\tPASS\n");
377 }
378 set(def_msgs, cur_max_msgs + 1);
379 cur_def_msgs = cur_max_msgs + 1;
380 set(def_msgsize, cur_max_msgsize + 1);
381 cur_def_msgsize = cur_max_msgsize + 1;
382 if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
383 cur_limits.rlim_cur) {
384 cur_limits.rlim_cur = (cur_def_msgs + 2) *
385 (cur_def_msgsize + 2 * sizeof(void *));
386 cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
387 setr(RLIMIT_MSGQUEUE, &cur_limits);
388 }
389 if (test_queue_fail(NULL, &result)) {
390 if (result.mq_maxmsg == cur_max_msgs &&
391 result.mq_msgsize == cur_max_msgsize)
392 printf("Kernel properly limits default values "
393 "to lesser of default/max:\t\tPASS\n");
394 else
395 printf("Kernel does not properly set default "
396 "queue parameters when\ndefaults > "
397 "max:\t\t\t\t\t\t\t\tFAIL\n");
398 } else
399 printf("Kernel fails to open mq because defaults are "
400 "greater than maximums:\tFAIL\n");
401 set(def_msgs, --cur_def_msgs);
402 set(def_msgsize, --cur_def_msgsize);
403 cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
404 cur_def_msgsize;
405 setr(RLIMIT_MSGQUEUE, &cur_limits);
406 if (test_queue_fail(NULL, &result))
407 printf("Kernel creates queue even though defaults "
408 "would exceed\nrlimit setting:"
409 "\t\t\t\t\t\t\t\tFAIL\n");
410 else
411 printf("Kernel properly fails to create queue when "
412 "defaults would\nexceed rlimit:"
413 "\t\t\t\t\t\t\t\tPASS\n");
414 }
415
416 /*
417 * Test #2 - open with an attr struct that exceeds rlimit
418 */
419 printf("\n\nTest series 2, behavior when attr struct is "
420 "passed to mq_open:\n");
421 cur_max_msgs = 32;
422 cur_max_msgsize = cur_limits.rlim_max >> 4;
423 set(max_msgs, cur_max_msgs);
424 set(max_msgsize, cur_max_msgsize);
425 attr.mq_maxmsg = cur_max_msgs;
426 attr.mq_msgsize = cur_max_msgsize;
427 if (test_queue_fail(&attr, &result))
428 printf("Queue open in excess of rlimit max when euid = 0 "
429 "succeeded:\t\tFAIL\n");
430 else
431 printf("Queue open in excess of rlimit max when euid = 0 "
432 "failed:\t\tPASS\n");
433 attr.mq_maxmsg = cur_max_msgs + 1;
434 attr.mq_msgsize = 10;
435 if (test_queue_fail(&attr, &result))
436 printf("Queue open with mq_maxmsg > limit when euid = 0 "
437 "succeeded:\t\tPASS\n");
438 else
439 printf("Queue open with mq_maxmsg > limit when euid = 0 "
440 "failed:\t\tFAIL\n");
441 attr.mq_maxmsg = 1;
442 attr.mq_msgsize = cur_max_msgsize + 1;
443 if (test_queue_fail(&attr, &result))
444 printf("Queue open with mq_msgsize > limit when euid = 0 "
445 "succeeded:\t\tPASS\n");
446 else
447 printf("Queue open with mq_msgsize > limit when euid = 0 "
448 "failed:\t\tFAIL\n");
449 attr.mq_maxmsg = 65536;
450 attr.mq_msgsize = 65536;
451 if (test_queue_fail(&attr, &result))
452 printf("Queue open with total size > 2GB when euid = 0 "
453 "succeeded:\t\tFAIL\n");
454 else
455 printf("Queue open with total size > 2GB when euid = 0 "
456 "failed:\t\t\tPASS\n");
457 seteuid(99);
458 attr.mq_maxmsg = cur_max_msgs;
459 attr.mq_msgsize = cur_max_msgsize;
460 if (test_queue_fail(&attr, &result))
461 printf("Queue open in excess of rlimit max when euid = 99 "
462 "succeeded:\t\tFAIL\n");
463 else
464 printf("Queue open in excess of rlimit max when euid = 99 "
465 "failed:\t\tPASS\n");
466 attr.mq_maxmsg = cur_max_msgs + 1;
467 attr.mq_msgsize = 10;
468 if (test_queue_fail(&attr, &result))
469 printf("Queue open with mq_maxmsg > limit when euid = 99 "
470 "succeeded:\t\tFAIL\n");
471 else
472 printf("Queue open with mq_maxmsg > limit when euid = 99 "
473 "failed:\t\tPASS\n");
474 attr.mq_maxmsg = 1;
475 attr.mq_msgsize = cur_max_msgsize + 1;
476 if (test_queue_fail(&attr, &result))
477 printf("Queue open with mq_msgsize > limit when euid = 99 "
478 "succeeded:\t\tFAIL\n");
479 else
480 printf("Queue open with mq_msgsize > limit when euid = 99 "
481 "failed:\t\tPASS\n");
482 attr.mq_maxmsg = 65536;
483 attr.mq_msgsize = 65536;
484 if (test_queue_fail(&attr, &result))
485 printf("Queue open with total size > 2GB when euid = 99 "
486 "succeeded:\t\tFAIL\n");
487 else
488 printf("Queue open with total size > 2GB when euid = 99 "
489 "failed:\t\t\tPASS\n");
490
491 shutdown(0,"",0);
492}
diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
deleted file mode 100644
index 2fadd4b9704..00000000000
--- a/tools/testing/selftests/mqueue/mq_perf_tests.c
+++ /dev/null
@@ -1,741 +0,0 @@
1/*
2 * This application is Copyright 2012 Red Hat, Inc.
3 * Doug Ledford <dledford@redhat.com>
4 *
5 * mq_perf_tests is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * mq_perf_tests is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * For the full text of the license, see <http://www.gnu.org/licenses/>.
15 *
16 * mq_perf_tests.c
17 * Tests various types of message queue workloads, concentrating on those
18 * situations that invole large message sizes, large message queue depths,
19 * or both, and reports back useful metrics about kernel message queue
20 * performance.
21 *
22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <string.h>
29#include <limits.h>
30#include <errno.h>
31#include <signal.h>
32#include <pthread.h>
33#include <sched.h>
34#include <sys/types.h>
35#include <sys/time.h>
36#include <sys/resource.h>
37#include <sys/stat.h>
38#include <mqueue.h>
39#include <popt.h>
40
41static char *usage =
42"Usage:\n"
43" %s [-c #[,#..] -f] path\n"
44"\n"
45" -c # Skip most tests and go straight to a high queue depth test\n"
46" and then run that test continuously (useful for running at\n"
47" the same time as some other workload to see how much the\n"
48" cache thrashing caused by adding messages to a very deep\n"
49" queue impacts the performance of other programs). The number\n"
50" indicates which CPU core we should bind the process to during\n"
51" the run. If you have more than one physical CPU, then you\n"
52" will need one copy per physical CPU package, and you should\n"
53" specify the CPU cores to pin ourself to via a comma separated\n"
54" list of CPU values.\n"
55" -f Only usable with continuous mode. Pin ourself to the CPUs\n"
56" as requested, then instead of looping doing a high mq\n"
57" workload, just busy loop. This will allow us to lock up a\n"
58" single CPU just like we normally would, but without actually\n"
59" thrashing the CPU cache. This is to make it easier to get\n"
60" comparable numbers from some other workload running on the\n"
61" other CPUs. One set of numbers with # CPUs locked up running\n"
62" an mq workload, and another set of numbers with those same\n"
63" CPUs locked away from the test workload, but not doing\n"
64" anything to trash the cache like the mq workload might.\n"
65" path Path name of the message queue to create\n"
66"\n"
67" Note: this program must be run as root in order to enable all tests\n"
68"\n";
69
70char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
71char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
72
73#define min(a, b) ((a) < (b) ? (a) : (b))
74#define MAX_CPUS 64
75char *cpu_option_string;
76int cpus_to_pin[MAX_CPUS];
77int num_cpus_to_pin;
78pthread_t cpu_threads[MAX_CPUS];
79pthread_t main_thread;
80cpu_set_t *cpu_set;
81int cpu_set_size;
82int cpus_online;
83
84#define MSG_SIZE 16
85#define TEST1_LOOPS 10000000
86#define TEST2_LOOPS 100000
87int continuous_mode;
88int continuous_mode_fake;
89
90struct rlimit saved_limits, cur_limits;
91int saved_max_msgs, saved_max_msgsize;
92int cur_max_msgs, cur_max_msgsize;
93FILE *max_msgs, *max_msgsize;
94int cur_nice;
95char *queue_path = "/mq_perf_tests";
96mqd_t queue = -1;
97struct mq_attr result;
98int mq_prio_max;
99
100const struct poptOption options[] = {
101 {
102 .longName = "continuous",
103 .shortName = 'c',
104 .argInfo = POPT_ARG_STRING,
105 .arg = &cpu_option_string,
106 .val = 'c',
107 .descrip = "Run continuous tests at a high queue depth in "
108 "order to test the effects of cache thrashing on "
109 "other tasks on the system. This test is intended "
110 "to be run on one core of each physical CPU while "
111 "some other CPU intensive task is run on all the other "
112 "cores of that same physical CPU and the other task "
113 "is timed. It is assumed that the process of adding "
114 "messages to the message queue in a tight loop will "
115 "impact that other task to some degree. Once the "
116 "tests are performed in this way, you should then "
117 "re-run the tests using fake mode in order to check "
118 "the difference in time required to perform the CPU "
119 "intensive task",
120 .argDescrip = "cpu[,cpu]",
121 },
122 {
123 .longName = "fake",
124 .shortName = 'f',
125 .argInfo = POPT_ARG_NONE,
126 .arg = &continuous_mode_fake,
127 .val = 0,
128 .descrip = "Tie up the CPUs that we would normally tie up in"
129 "continuous mode, but don't actually do any mq stuff, "
130 "just keep the CPU busy so it can't be used to process "
131 "system level tasks as this would free up resources on "
132 "the other CPU cores and skew the comparison between "
133 "the no-mqueue work and mqueue work tests",
134 .argDescrip = NULL,
135 },
136 {
137 .longName = "path",
138 .shortName = 'p',
139 .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
140 .arg = &queue_path,
141 .val = 'p',
142 .descrip = "The name of the path to use in the mqueue "
143 "filesystem for our tests",
144 .argDescrip = "pathname",
145 },
146 POPT_AUTOHELP
147 POPT_TABLEEND
148};
149
150static inline void __set(FILE *stream, int value, char *err_msg);
151void shutdown(int exit_val, char *err_cause, int line_no);
152void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context);
153void sig_action(int signum, siginfo_t *info, void *context);
154static inline int get(FILE *stream);
155static inline void set(FILE *stream, int value);
156static inline int try_set(FILE *stream, int value);
157static inline void getr(int type, struct rlimit *rlim);
158static inline void setr(int type, struct rlimit *rlim);
159static inline void open_queue(struct mq_attr *attr);
160void increase_limits(void);
161
162static inline void __set(FILE *stream, int value, char *err_msg)
163{
164 rewind(stream);
165 if (fprintf(stream, "%d", value) < 0)
166 perror(err_msg);
167}
168
169
170void shutdown(int exit_val, char *err_cause, int line_no)
171{
172 static int in_shutdown = 0;
173 int errno_at_shutdown = errno;
174 int i;
175
176 /* In case we get called by multiple threads or from an sighandler */
177 if (in_shutdown++)
178 return;
179
180 for (i = 0; i < num_cpus_to_pin; i++)
181 if (cpu_threads[i]) {
182 pthread_kill(cpu_threads[i], SIGUSR1);
183 pthread_join(cpu_threads[i], NULL);
184 }
185
186 if (queue != -1)
187 if (mq_close(queue))
188 perror("mq_close() during shutdown");
189 if (queue_path)
190 /*
191 * Be silent if this fails, if we cleaned up already it's
192 * expected to fail
193 */
194 mq_unlink(queue_path);
195 if (saved_max_msgs)
196 __set(max_msgs, saved_max_msgs,
197 "failed to restore saved_max_msgs");
198 if (saved_max_msgsize)
199 __set(max_msgsize, saved_max_msgsize,
200 "failed to restore saved_max_msgsize");
201 if (exit_val)
202 error(exit_val, errno_at_shutdown, "%s at %d",
203 err_cause, line_no);
204 exit(0);
205}
206
207void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context)
208{
209 if (pthread_self() != main_thread)
210 pthread_exit(0);
211 else {
212 fprintf(stderr, "Caught signal %d in SIGUSR1 handler, "
213 "exiting\n", signum);
214 shutdown(0, "", 0);
215 fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
216 exit(0);
217 }
218}
219
220void sig_action(int signum, siginfo_t *info, void *context)
221{
222 if (pthread_self() != main_thread)
223 pthread_kill(main_thread, signum);
224 else {
225 fprintf(stderr, "Caught signal %d, exiting\n", signum);
226 shutdown(0, "", 0);
227 fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
228 exit(0);
229 }
230}
231
232static inline int get(FILE *stream)
233{
234 int value;
235 rewind(stream);
236 if (fscanf(stream, "%d", &value) != 1)
237 shutdown(4, "Error reading /proc entry", __LINE__);
238 return value;
239}
240
241static inline void set(FILE *stream, int value)
242{
243 int new_value;
244
245 rewind(stream);
246 if (fprintf(stream, "%d", value) < 0)
247 return shutdown(5, "Failed writing to /proc file", __LINE__);
248 new_value = get(stream);
249 if (new_value != value)
250 return shutdown(5, "We didn't get what we wrote to /proc back",
251 __LINE__);
252}
253
254static inline int try_set(FILE *stream, int value)
255{
256 int new_value;
257
258 rewind(stream);
259 fprintf(stream, "%d", value);
260 new_value = get(stream);
261 return new_value == value;
262}
263
264static inline void getr(int type, struct rlimit *rlim)
265{
266 if (getrlimit(type, rlim))
267 shutdown(6, "getrlimit()", __LINE__);
268}
269
270static inline void setr(int type, struct rlimit *rlim)
271{
272 if (setrlimit(type, rlim))
273 shutdown(7, "setrlimit()", __LINE__);
274}
275
276/**
277 * open_queue - open the global queue for testing
278 * @attr - An attr struct specifying the desired queue traits
279 * @result - An attr struct that lists the actual traits the queue has
280 *
281 * This open is not allowed to fail, failure will result in an orderly
282 * shutdown of the program. The global queue_path is used to set what
283 * queue to open, the queue descriptor is saved in the global queue
284 * variable.
285 */
286static inline void open_queue(struct mq_attr *attr)
287{
288 int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK;
289 int perms = DEFFILEMODE;
290
291 queue = mq_open(queue_path, flags, perms, attr);
292 if (queue == -1)
293 shutdown(1, "mq_open()", __LINE__);
294 if (mq_getattr(queue, &result))
295 shutdown(1, "mq_getattr()", __LINE__);
296 printf("\n\tQueue %s created:\n", queue_path);
297 printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
298 "O_NONBLOCK" : "(null)");
299 printf("\t\tmq_maxmsg:\t\t\t%d\n", result.mq_maxmsg);
300 printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize);
301 printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs);
302}
303
304void *fake_cont_thread(void *arg)
305{
306 int i;
307
308 for (i = 0; i < num_cpus_to_pin; i++)
309 if (cpu_threads[i] == pthread_self())
310 break;
311 printf("\tStarted fake continuous mode thread %d on CPU %d\n", i,
312 cpus_to_pin[i]);
313 while (1)
314 ;
315}
316
317void *cont_thread(void *arg)
318{
319 char buff[MSG_SIZE];
320 int i, priority;
321
322 for (i = 0; i < num_cpus_to_pin; i++)
323 if (cpu_threads[i] == pthread_self())
324 break;
325 printf("\tStarted continuous mode thread %d on CPU %d\n", i,
326 cpus_to_pin[i]);
327 while (1) {
328 while (mq_send(queue, buff, sizeof(buff), 0) == 0)
329 ;
330 mq_receive(queue, buff, sizeof(buff), &priority);
331 }
332}
333
334#define drain_queue() \
335 while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
336
337#define do_untimed_send() \
338 do { \
339 if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
340 shutdown(3, "Test send failure", __LINE__); \
341 } while (0)
342
343#define do_send_recv() \
344 do { \
345 clock_gettime(clock, &start); \
346 if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
347 shutdown(3, "Test send failure", __LINE__); \
348 clock_gettime(clock, &middle); \
349 if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \
350 shutdown(3, "Test receive failure", __LINE__); \
351 clock_gettime(clock, &end); \
352 nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \
353 (middle.tv_nsec - start.tv_nsec); \
354 send_total.tv_nsec += nsec; \
355 if (send_total.tv_nsec >= 1000000000) { \
356 send_total.tv_sec++; \
357 send_total.tv_nsec -= 1000000000; \
358 } \
359 nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \
360 (end.tv_nsec - middle.tv_nsec); \
361 recv_total.tv_nsec += nsec; \
362 if (recv_total.tv_nsec >= 1000000000) { \
363 recv_total.tv_sec++; \
364 recv_total.tv_nsec -= 1000000000; \
365 } \
366 } while (0)
367
368struct test {
369 char *desc;
370 void (*func)(int *);
371};
372
373void const_prio(int *prio)
374{
375 return;
376}
377
378void inc_prio(int *prio)
379{
380 if (++*prio == mq_prio_max)
381 *prio = 0;
382}
383
384void dec_prio(int *prio)
385{
386 if (--*prio < 0)
387 *prio = mq_prio_max - 1;
388}
389
390void random_prio(int *prio)
391{
392 *prio = random() % mq_prio_max;
393}
394
395struct test test2[] = {
396 {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n",
397 const_prio},
398 {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n",
399 inc_prio},
400 {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n",
401 dec_prio},
402 {"\n\tTest #2d: Time send/recv message, queue full, random prio\n",
403 random_prio},
404 {NULL, NULL}
405};
406
407/**
408 * Tests to perform (all done with MSG_SIZE messages):
409 *
410 * 1) Time to add/remove message with 0 messages on queue
411 * 1a) with constant prio
412 * 2) Time to add/remove message when queue close to capacity:
413 * 2a) with constant prio
414 * 2b) with increasing prio
415 * 2c) with decreasing prio
416 * 2d) with random prio
417 * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX)
418 */
419void *perf_test_thread(void *arg)
420{
421 char buff[MSG_SIZE];
422 int prio_out, prio_in;
423 int i;
424 clockid_t clock;
425 pthread_t *t;
426 struct timespec res, start, middle, end, send_total, recv_total;
427 unsigned long long nsec;
428 struct test *cur_test;
429
430 t = &cpu_threads[0];
431 printf("\n\tStarted mqueue performance test thread on CPU %d\n",
432 cpus_to_pin[0]);
433 mq_prio_max = sysconf(_SC_MQ_PRIO_MAX);
434 if (mq_prio_max == -1)
435 shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__);
436 if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0)
437 shutdown(2, "pthread_getcpuclockid", __LINE__);
438
439 if (clock_getres(clock, &res))
440 shutdown(2, "clock_getres()", __LINE__);
441
442 printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
443 printf("\t\tClock resolution:\t\t%d nsec%s\n", res.tv_nsec,
444 res.tv_nsec > 1 ? "s" : "");
445
446
447
448 printf("\n\tTest #1: Time send/recv message, queue empty\n");
449 printf("\t\t(%d iterations)\n", TEST1_LOOPS);
450 prio_out = 0;
451 send_total.tv_sec = 0;
452 send_total.tv_nsec = 0;
453 recv_total.tv_sec = 0;
454 recv_total.tv_nsec = 0;
455 for (i = 0; i < TEST1_LOOPS; i++)
456 do_send_recv();
457 printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
458 send_total.tv_sec, send_total.tv_nsec);
459 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
460 send_total.tv_nsec) / TEST1_LOOPS;
461 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
462 printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
463 recv_total.tv_sec, recv_total.tv_nsec);
464 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
465 recv_total.tv_nsec) / TEST1_LOOPS;
466 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
467
468
469 for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
470 printf(cur_test->desc);
471 printf("\t\t(%d iterations)\n", TEST2_LOOPS);
472 prio_out = 0;
473 send_total.tv_sec = 0;
474 send_total.tv_nsec = 0;
475 recv_total.tv_sec = 0;
476 recv_total.tv_nsec = 0;
477 printf("\t\tFilling queue...");
478 fflush(stdout);
479 clock_gettime(clock, &start);
480 for (i = 0; i < result.mq_maxmsg - 1; i++) {
481 do_untimed_send();
482 cur_test->func(&prio_out);
483 }
484 clock_gettime(clock, &end);
485 nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
486 1000000000) + (end.tv_nsec - start.tv_nsec);
487 printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
488 nsec % 1000000000);
489 printf("\t\tTesting...");
490 fflush(stdout);
491 for (i = 0; i < TEST2_LOOPS; i++) {
492 do_send_recv();
493 cur_test->func(&prio_out);
494 }
495 printf("done.\n");
496 printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
497 send_total.tv_sec, send_total.tv_nsec);
498 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
499 send_total.tv_nsec) / TEST2_LOOPS;
500 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
501 printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
502 recv_total.tv_sec, recv_total.tv_nsec);
503 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
504 recv_total.tv_nsec) / TEST2_LOOPS;
505 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
506 printf("\t\tDraining queue...");
507 fflush(stdout);
508 clock_gettime(clock, &start);
509 drain_queue();
510 clock_gettime(clock, &end);
511 nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
512 1000000000) + (end.tv_nsec - start.tv_nsec);
513 printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
514 nsec % 1000000000);
515 }
516 return 0;
517}
518
519void increase_limits(void)
520{
521 cur_limits.rlim_cur = RLIM_INFINITY;
522 cur_limits.rlim_max = RLIM_INFINITY;
523 setr(RLIMIT_MSGQUEUE, &cur_limits);
524 while (try_set(max_msgs, cur_max_msgs += 10))
525 ;
526 cur_max_msgs = get(max_msgs);
527 while (try_set(max_msgsize, cur_max_msgsize += 1024))
528 ;
529 cur_max_msgsize = get(max_msgsize);
530 if (setpriority(PRIO_PROCESS, 0, -20) != 0)
531 shutdown(2, "setpriority()", __LINE__);
532 cur_nice = -20;
533}
534
535int main(int argc, char *argv[])
536{
537 struct mq_attr attr;
538 char *option, *next_option;
539 int i, cpu;
540 struct sigaction sa;
541 poptContext popt_context;
542 char rc;
543 void *retval;
544
545 main_thread = pthread_self();
546 num_cpus_to_pin = 0;
547
548 if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
549 perror("sysconf(_SC_NPROCESSORS_ONLN)");
550 exit(1);
551 }
552 cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN));
553 cpu_set = CPU_ALLOC(cpus_online);
554 if (cpu_set == NULL) {
555 perror("CPU_ALLOC()");
556 exit(1);
557 }
558 cpu_set_size = CPU_ALLOC_SIZE(cpus_online);
559 CPU_ZERO_S(cpu_set_size, cpu_set);
560
561 popt_context = poptGetContext(NULL, argc, (const char **)argv,
562 options, 0);
563
564 while ((rc = poptGetNextOpt(popt_context)) > 0) {
565 switch (rc) {
566 case 'c':
567 continuous_mode = 1;
568 option = cpu_option_string;
569 do {
570 next_option = strchr(option, ',');
571 if (next_option)
572 *next_option = '\0';
573 cpu = atoi(option);
574 if (cpu >= cpus_online)
575 fprintf(stderr, "CPU %d exceeds "
576 "cpus online, ignoring.\n",
577 cpu);
578 else
579 cpus_to_pin[num_cpus_to_pin++] = cpu;
580 if (next_option)
581 option = ++next_option;
582 } while (next_option && num_cpus_to_pin < MAX_CPUS);
583 /* Double check that they didn't give us the same CPU
584 * more than once */
585 for (cpu = 0; cpu < num_cpus_to_pin; cpu++) {
586 if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
587 cpu_set)) {
588 fprintf(stderr, "Any given CPU may "
589 "only be given once.\n");
590 exit(1);
591 } else
592 CPU_SET_S(cpus_to_pin[cpu],
593 cpu_set_size, cpu_set);
594 }
595 break;
596 case 'p':
597 /*
598 * Although we can create a msg queue with a
599 * non-absolute path name, unlink will fail. So,
600 * if the name doesn't start with a /, add one
601 * when we save it.
602 */
603 option = queue_path;
604 if (*option != '/') {
605 queue_path = malloc(strlen(option) + 2);
606 if (!queue_path) {
607 perror("malloc()");
608 exit(1);
609 }
610 queue_path[0] = '/';
611 queue_path[1] = 0;
612 strcat(queue_path, option);
613 free(option);
614 }
615 break;
616 }
617 }
618
619 if (continuous_mode && num_cpus_to_pin == 0) {
620 fprintf(stderr, "Must pass at least one CPU to continuous "
621 "mode.\n");
622 poptPrintUsage(popt_context, stderr, 0);
623 exit(1);
624 } else if (!continuous_mode) {
625 num_cpus_to_pin = 1;
626 cpus_to_pin[0] = cpus_online - 1;
627 }
628
629 if (getuid() != 0) {
630 fprintf(stderr, "Not running as root, but almost all tests "
631 "require root in order to modify\nsystem settings. "
632 "Exiting.\n");
633 exit(1);
634 }
635
636 max_msgs = fopen(MAX_MSGS, "r+");
637 max_msgsize = fopen(MAX_MSGSIZE, "r+");
638 if (!max_msgs)
639 shutdown(2, "Failed to open msg_max", __LINE__);
640 if (!max_msgsize)
641 shutdown(2, "Failed to open msgsize_max", __LINE__);
642
643 /* Load up the current system values for everything we can */
644 getr(RLIMIT_MSGQUEUE, &saved_limits);
645 cur_limits = saved_limits;
646 saved_max_msgs = cur_max_msgs = get(max_msgs);
647 saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
648 errno = 0;
649 cur_nice = getpriority(PRIO_PROCESS, 0);
650 if (errno)
651 shutdown(2, "getpriority()", __LINE__);
652
653 /* Tell the user our initial state */
654 printf("\nInitial system state:\n");
655 printf("\tUsing queue path:\t\t\t%s\n", queue_path);
656 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", saved_limits.rlim_cur);
657 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max);
658 printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
659 printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
660 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
661 printf("\n");
662
663 increase_limits();
664
665 printf("Adjusted system state for testing:\n");
666 if (cur_limits.rlim_cur == RLIM_INFINITY) {
667 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
668 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
669 } else {
670 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n",
671 cur_limits.rlim_cur);
672 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n",
673 cur_limits.rlim_max);
674 }
675 printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
676 printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
677 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
678 printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
679 (continuous_mode_fake ? "fake mode" : "enabled") :
680 "disabled");
681 printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
682 for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
683 printf(",%d", cpus_to_pin[cpu]);
684 printf("\n");
685
686 sa.sa_sigaction = sig_action_SIGUSR1;
687 sigemptyset(&sa.sa_mask);
688 sigaddset(&sa.sa_mask, SIGHUP);
689 sigaddset(&sa.sa_mask, SIGINT);
690 sigaddset(&sa.sa_mask, SIGQUIT);
691 sigaddset(&sa.sa_mask, SIGTERM);
692 sa.sa_flags = SA_SIGINFO;
693 if (sigaction(SIGUSR1, &sa, NULL) == -1)
694 shutdown(1, "sigaction(SIGUSR1)", __LINE__);
695 sa.sa_sigaction = sig_action;
696 if (sigaction(SIGHUP, &sa, NULL) == -1)
697 shutdown(1, "sigaction(SIGHUP)", __LINE__);
698 if (sigaction(SIGINT, &sa, NULL) == -1)
699 shutdown(1, "sigaction(SIGINT)", __LINE__);
700 if (sigaction(SIGQUIT, &sa, NULL) == -1)
701 shutdown(1, "sigaction(SIGQUIT)", __LINE__);
702 if (sigaction(SIGTERM, &sa, NULL) == -1)
703 shutdown(1, "sigaction(SIGTERM)", __LINE__);
704
705 if (!continuous_mode_fake) {
706 attr.mq_flags = O_NONBLOCK;
707 attr.mq_maxmsg = cur_max_msgs;
708 attr.mq_msgsize = MSG_SIZE;
709 open_queue(&attr);
710 }
711 for (i = 0; i < num_cpus_to_pin; i++) {
712 pthread_attr_t thread_attr;
713 void *thread_func;
714
715 if (continuous_mode_fake)
716 thread_func = &fake_cont_thread;
717 else if (continuous_mode)
718 thread_func = &cont_thread;
719 else
720 thread_func = &perf_test_thread;
721
722 CPU_ZERO_S(cpu_set_size, cpu_set);
723 CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
724 pthread_attr_init(&thread_attr);
725 pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
726 cpu_set);
727 if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
728 NULL))
729 shutdown(1, "pthread_create()", __LINE__);
730 pthread_attr_destroy(&thread_attr);
731 }
732
733 if (!continuous_mode) {
734 pthread_join(cpu_threads[0], &retval);
735 shutdown((long)retval, "perf_test_thread()", __LINE__);
736 } else {
737 while (1)
738 sleep(1);
739 }
740 shutdown(0, "", 0);
741}
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
deleted file mode 100644
index 436d2e81868..00000000000
--- a/tools/testing/selftests/vm/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
1# Makefile for vm selftests
2
3CC = $(CROSS_COMPILE)gcc
4CFLAGS = -Wall
5
6all: hugepage-mmap hugepage-shm map_hugetlb thuge-gen
7%: %.c
8 $(CC) $(CFLAGS) -o $@ $^
9
10run_tests: all
11 @/bin/sh ./run_vmtests || echo "vmtests: [FAIL]"
12
13clean:
14 $(RM) hugepage-mmap hugepage-shm map_hugetlb
diff --git a/tools/testing/selftests/vm/hugepage-mmap.c b/tools/testing/selftests/vm/hugepage-mmap.c
deleted file mode 100644
index a10f310d236..00000000000
--- a/tools/testing/selftests/vm/hugepage-mmap.c
+++ /dev/null
@@ -1,92 +0,0 @@
1/*
2 * hugepage-mmap:
3 *
4 * Example of using huge page memory in a user application using the mmap
5 * system call. Before running this application, make sure that the
6 * administrator has mounted the hugetlbfs filesystem (on some directory
7 * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
8 * example, the app is requesting memory of size 256MB that is backed by
9 * huge pages.
10 *
11 * For the ia64 architecture, the Linux kernel reserves Region number 4 for
12 * huge pages. That means that if one requires a fixed address, a huge page
13 * aligned address starting with 0x800000... will be required. If a fixed
14 * address is not required, the kernel will select an address in the proper
15 * range.
16 * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
17 */
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <unistd.h>
22#include <sys/mman.h>
23#include <fcntl.h>
24
25#define FILE_NAME "huge/hugepagefile"
26#define LENGTH (256UL*1024*1024)
27#define PROTECTION (PROT_READ | PROT_WRITE)
28
29/* Only ia64 requires this */
30#ifdef __ia64__
31#define ADDR (void *)(0x8000000000000000UL)
32#define FLAGS (MAP_SHARED | MAP_FIXED)
33#else
34#define ADDR (void *)(0x0UL)
35#define FLAGS (MAP_SHARED)
36#endif
37
38static void check_bytes(char *addr)
39{
40 printf("First hex is %x\n", *((unsigned int *)addr));
41}
42
43static void write_bytes(char *addr)
44{
45 unsigned long i;
46
47 for (i = 0; i < LENGTH; i++)
48 *(addr + i) = (char)i;
49}
50
51static int read_bytes(char *addr)
52{
53 unsigned long i;
54
55 check_bytes(addr);
56 for (i = 0; i < LENGTH; i++)
57 if (*(addr + i) != (char)i) {
58 printf("Mismatch at %lu\n", i);
59 return 1;
60 }
61 return 0;
62}
63
64int main(void)
65{
66 void *addr;
67 int fd, ret;
68
69 fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
70 if (fd < 0) {
71 perror("Open failed");
72 exit(1);
73 }
74
75 addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
76 if (addr == MAP_FAILED) {
77 perror("mmap");
78 unlink(FILE_NAME);
79 exit(1);
80 }
81
82 printf("Returned address is %p\n", addr);
83 check_bytes(addr);
84 write_bytes(addr);
85 ret = read_bytes(addr);
86
87 munmap(addr, LENGTH);
88 close(fd);
89 unlink(FILE_NAME);
90
91 return ret;
92}
diff --git a/tools/testing/selftests/vm/hugepage-shm.c b/tools/testing/selftests/vm/hugepage-shm.c
deleted file mode 100644
index 0d0ef4fc0c0..00000000000
--- a/tools/testing/selftests/vm/hugepage-shm.c
+++ /dev/null
@@ -1,100 +0,0 @@
1/*
2 * hugepage-shm:
3 *
4 * Example of using huge page memory in a user application using Sys V shared
5 * memory system calls. In this example the app is requesting 256MB of
6 * memory that is backed by huge pages. The application uses the flag
7 * SHM_HUGETLB in the shmget system call to inform the kernel that it is
8 * requesting huge pages.
9 *
10 * For the ia64 architecture, the Linux kernel reserves Region number 4 for
11 * huge pages. That means that if one requires a fixed address, a huge page
12 * aligned address starting with 0x800000... will be required. If a fixed
13 * address is not required, the kernel will select an address in the proper
14 * range.
15 * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
16 *
17 * Note: The default shared memory limit is quite low on many kernels,
18 * you may need to increase it via:
19 *
20 * echo 268435456 > /proc/sys/kernel/shmmax
21 *
22 * This will increase the maximum size per shared memory segment to 256MB.
23 * The other limit that you will hit eventually is shmall which is the
24 * total amount of shared memory in pages. To set it to 16GB on a system
25 * with a 4kB pagesize do:
26 *
27 * echo 4194304 > /proc/sys/kernel/shmall
28 */
29
30#include <stdlib.h>
31#include <stdio.h>
32#include <sys/types.h>
33#include <sys/ipc.h>
34#include <sys/shm.h>
35#include <sys/mman.h>
36
37#ifndef SHM_HUGETLB
38#define SHM_HUGETLB 04000
39#endif
40
41#define LENGTH (256UL*1024*1024)
42
43#define dprintf(x) printf(x)
44
45/* Only ia64 requires this */
46#ifdef __ia64__
47#define ADDR (void *)(0x8000000000000000UL)
48#define SHMAT_FLAGS (SHM_RND)
49#else
50#define ADDR (void *)(0x0UL)
51#define SHMAT_FLAGS (0)
52#endif
53
54int main(void)
55{
56 int shmid;
57 unsigned long i;
58 char *shmaddr;
59
60 shmid = shmget(2, LENGTH, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
61 if (shmid < 0) {
62 perror("shmget");
63 exit(1);
64 }
65 printf("shmid: 0x%x\n", shmid);
66
67 shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
68 if (shmaddr == (char *)-1) {
69 perror("Shared memory attach failure");
70 shmctl(shmid, IPC_RMID, NULL);
71 exit(2);
72 }
73 printf("shmaddr: %p\n", shmaddr);
74
75 dprintf("Starting the writes:\n");
76 for (i = 0; i < LENGTH; i++) {
77 shmaddr[i] = (char)(i);
78 if (!(i % (1024 * 1024)))
79 dprintf(".");
80 }
81 dprintf("\n");
82
83 dprintf("Starting the Check...");
84 for (i = 0; i < LENGTH; i++)
85 if (shmaddr[i] != (char)i) {
86 printf("\nIndex %lu mismatched\n", i);
87 exit(3);
88 }
89 dprintf("Done.\n");
90
91 if (shmdt((const void *)shmaddr) != 0) {
92 perror("Detach failure");
93 shmctl(shmid, IPC_RMID, NULL);
94 exit(4);
95 }
96
97 shmctl(shmid, IPC_RMID, NULL);
98
99 return 0;
100}
diff --git a/tools/testing/selftests/vm/map_hugetlb.c b/tools/testing/selftests/vm/map_hugetlb.c
deleted file mode 100644
index ac56639dd4a..00000000000
--- a/tools/testing/selftests/vm/map_hugetlb.c
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2 * Example of using hugepage memory in a user application using the mmap
3 * system call with MAP_HUGETLB flag. Before running this program make
4 * sure the administrator has allocated enough default sized huge pages
5 * to cover the 256 MB allocation.
6 *
7 * For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
8 * That means the addresses starting with 0x800000... will need to be
9 * specified. Specifying a fixed address is not required on ppc64, i386
10 * or x86_64.
11 */
12#include <stdlib.h>
13#include <stdio.h>
14#include <unistd.h>
15#include <sys/mman.h>
16#include <fcntl.h>
17
18#define LENGTH (256UL*1024*1024)
19#define PROTECTION (PROT_READ | PROT_WRITE)
20
21#ifndef MAP_HUGETLB
22#define MAP_HUGETLB 0x40000 /* arch specific */
23#endif
24
25/* Only ia64 requires this */
26#ifdef __ia64__
27#define ADDR (void *)(0x8000000000000000UL)
28#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
29#else
30#define ADDR (void *)(0x0UL)
31#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
32#endif
33
34static void check_bytes(char *addr)
35{
36 printf("First hex is %x\n", *((unsigned int *)addr));
37}
38
39static void write_bytes(char *addr)
40{
41 unsigned long i;
42
43 for (i = 0; i < LENGTH; i++)
44 *(addr + i) = (char)i;
45}
46
47static int read_bytes(char *addr)
48{
49 unsigned long i;
50
51 check_bytes(addr);
52 for (i = 0; i < LENGTH; i++)
53 if (*(addr + i) != (char)i) {
54 printf("Mismatch at %lu\n", i);
55 return 1;
56 }
57 return 0;
58}
59
60int main(void)
61{
62 void *addr;
63 int ret;
64
65 addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
66 if (addr == MAP_FAILED) {
67 perror("mmap");
68 exit(1);
69 }
70
71 printf("Returned address is %p\n", addr);
72 check_bytes(addr);
73 write_bytes(addr);
74 ret = read_bytes(addr);
75
76 munmap(addr, LENGTH);
77
78 return ret;
79}
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
deleted file mode 100644
index 4c53cae6c27..00000000000
--- a/tools/testing/selftests/vm/run_vmtests
+++ /dev/null
@@ -1,77 +0,0 @@
1#!/bin/bash
2#please run as root
3
4#we need 256M, below is the size in kB
5needmem=262144
6mnt=./huge
7
8#get pagesize and freepages from /proc/meminfo
9while read name size unit; do
10 if [ "$name" = "HugePages_Free:" ]; then
11 freepgs=$size
12 fi
13 if [ "$name" = "Hugepagesize:" ]; then
14 pgsize=$size
15 fi
16done < /proc/meminfo
17
18#set proper nr_hugepages
19if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
20 nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
21 needpgs=`expr $needmem / $pgsize`
22 if [ $freepgs -lt $needpgs ]; then
23 lackpgs=$(( $needpgs - $freepgs ))
24 echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages
25 if [ $? -ne 0 ]; then
26 echo "Please run this test as root"
27 exit 1
28 fi
29 fi
30else
31 echo "no hugetlbfs support in kernel?"
32 exit 1
33fi
34
35mkdir $mnt
36mount -t hugetlbfs none $mnt
37
38echo "--------------------"
39echo "running hugepage-mmap"
40echo "--------------------"
41./hugepage-mmap
42if [ $? -ne 0 ]; then
43 echo "[FAIL]"
44else
45 echo "[PASS]"
46fi
47
48shmmax=`cat /proc/sys/kernel/shmmax`
49shmall=`cat /proc/sys/kernel/shmall`
50echo 268435456 > /proc/sys/kernel/shmmax
51echo 4194304 > /proc/sys/kernel/shmall
52echo "--------------------"
53echo "running hugepage-shm"
54echo "--------------------"
55./hugepage-shm
56if [ $? -ne 0 ]; then
57 echo "[FAIL]"
58else
59 echo "[PASS]"
60fi
61echo $shmmax > /proc/sys/kernel/shmmax
62echo $shmall > /proc/sys/kernel/shmall
63
64echo "--------------------"
65echo "running map_hugetlb"
66echo "--------------------"
67./map_hugetlb
68if [ $? -ne 0 ]; then
69 echo "[FAIL]"
70else
71 echo "[PASS]"
72fi
73
74#cleanup
75umount $mnt
76rm -rf $mnt
77echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
diff --git a/tools/testing/selftests/vm/thuge-gen.c b/tools/testing/selftests/vm/thuge-gen.c
deleted file mode 100644
index c87957295f7..00000000000
--- a/tools/testing/selftests/vm/thuge-gen.c
+++ /dev/null
@@ -1,254 +0,0 @@
1/* Test selecting other page sizes for mmap/shmget.
2
3 Before running this huge pages for each huge page size must have been
4 reserved.
5 For large pages beyond MAX_ORDER (like 1GB on x86) boot options must be used.
6 Also shmmax must be increased.
7 And you need to run as root to work around some weird permissions in shm.
8 And nothing using huge pages should run in parallel.
9 When the program aborts you may need to clean up the shm segments with
10 ipcrm -m by hand, like this
11 sudo ipcs | awk '$1 == "0x00000000" {print $2}' | xargs -n1 sudo ipcrm -m
12 (warning this will remove all if someone else uses them) */
13
14#define _GNU_SOURCE 1
15#include <sys/mman.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <sys/ipc.h>
19#include <sys/shm.h>
20#include <sys/stat.h>
21#include <glob.h>
22#include <assert.h>
23#include <unistd.h>
24#include <stdarg.h>
25#include <string.h>
26
27#define err(x) perror(x), exit(1)
28
29#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
30#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
31#define MAP_HUGE_SHIFT 26
32#define MAP_HUGE_MASK 0x3f
33#define MAP_HUGETLB 0x40000
34
35#define SHM_HUGETLB 04000 /* segment will use huge TLB pages */
36#define SHM_HUGE_SHIFT 26
37#define SHM_HUGE_MASK 0x3f
38#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
39#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)
40
41#define NUM_PAGESIZES 5
42
43#define NUM_PAGES 4
44
45#define Dprintf(fmt...) // printf(fmt)
46
47unsigned long page_sizes[NUM_PAGESIZES];
48int num_page_sizes;
49
50int ilog2(unsigned long v)
51{
52 int l = 0;
53 while ((1UL << l) < v)
54 l++;
55 return l;
56}
57
58void find_pagesizes(void)
59{
60 glob_t g;
61 int i;
62 glob("/sys/kernel/mm/hugepages/hugepages-*kB", 0, NULL, &g);
63 assert(g.gl_pathc <= NUM_PAGESIZES);
64 for (i = 0; i < g.gl_pathc; i++) {
65 sscanf(g.gl_pathv[i], "/sys/kernel/mm/hugepages/hugepages-%lukB",
66 &page_sizes[i]);
67 page_sizes[i] <<= 10;
68 printf("Found %luMB\n", page_sizes[i] >> 20);
69 }
70 num_page_sizes = g.gl_pathc;
71 globfree(&g);
72}
73
74unsigned long default_huge_page_size(void)
75{
76 unsigned long hps = 0;
77 char *line = NULL;
78 size_t linelen = 0;
79 FILE *f = fopen("/proc/meminfo", "r");
80 if (!f)
81 return 0;
82 while (getline(&line, &linelen, f) > 0) {
83 if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
84 hps <<= 10;
85 break;
86 }
87 }
88 free(line);
89 return hps;
90}
91
92void show(unsigned long ps)
93{
94 char buf[100];
95 if (ps == getpagesize())
96 return;
97 printf("%luMB: ", ps >> 20);
98 fflush(stdout);
99 snprintf(buf, sizeof buf,
100 "cat /sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
101 ps >> 10);
102 system(buf);
103}
104
105unsigned long read_sysfs(int warn, char *fmt, ...)
106{
107 char *line = NULL;
108 size_t linelen = 0;
109 char buf[100];
110 FILE *f;
111 va_list ap;
112 unsigned long val = 0;
113
114 va_start(ap, fmt);
115 vsnprintf(buf, sizeof buf, fmt, ap);
116 va_end(ap);
117
118 f = fopen(buf, "r");
119 if (!f) {
120 if (warn)
121 printf("missing %s\n", buf);
122 return 0;
123 }
124 if (getline(&line, &linelen, f) > 0) {
125 sscanf(line, "%lu", &val);
126 }
127 fclose(f);
128 free(line);
129 return val;
130}
131
132unsigned long read_free(unsigned long ps)
133{
134 return read_sysfs(ps != getpagesize(),
135 "/sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
136 ps >> 10);
137}
138
139void test_mmap(unsigned long size, unsigned flags)
140{
141 char *map;
142 unsigned long before, after;
143 int err;
144
145 before = read_free(size);
146 map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE,
147 MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, 0, 0);
148
149 if (map == (char *)-1) err("mmap");
150 memset(map, 0xff, size*NUM_PAGES);
151 after = read_free(size);
152 Dprintf("before %lu after %lu diff %ld size %lu\n",
153 before, after, before - after, size);
154 assert(size == getpagesize() || (before - after) == NUM_PAGES);
155 show(size);
156 err = munmap(map, size);
157 assert(!err);
158}
159
160void test_shmget(unsigned long size, unsigned flags)
161{
162 int id;
163 unsigned long before, after;
164 int err;
165
166 before = read_free(size);
167 id = shmget(IPC_PRIVATE, size * NUM_PAGES, IPC_CREAT|0600|flags);
168 if (id < 0) err("shmget");
169
170 struct shm_info i;
171 if (shmctl(id, SHM_INFO, (void *)&i) < 0) err("shmctl");
172 Dprintf("alloc %lu res %lu\n", i.shm_tot, i.shm_rss);
173
174
175 Dprintf("id %d\n", id);
176 char *map = shmat(id, NULL, 0600);
177 if (map == (char*)-1) err("shmat");
178
179 shmctl(id, IPC_RMID, NULL);
180
181 memset(map, 0xff, size*NUM_PAGES);
182 after = read_free(size);
183
184 Dprintf("before %lu after %lu diff %ld size %lu\n",
185 before, after, before - after, size);
186 assert(size == getpagesize() || (before - after) == NUM_PAGES);
187 show(size);
188 err = shmdt(map);
189 assert(!err);
190}
191
192void sanity_checks(void)
193{
194 int i;
195 unsigned long largest = getpagesize();
196
197 for (i = 0; i < num_page_sizes; i++) {
198 if (page_sizes[i] > largest)
199 largest = page_sizes[i];
200
201 if (read_free(page_sizes[i]) < NUM_PAGES) {
202 printf("Not enough huge pages for page size %lu MB, need %u\n",
203 page_sizes[i] >> 20,
204 NUM_PAGES);
205 exit(0);
206 }
207 }
208
209 if (read_sysfs(0, "/proc/sys/kernel/shmmax") < NUM_PAGES * largest) {
210 printf("Please do echo %lu > /proc/sys/kernel/shmmax", largest * NUM_PAGES);
211 exit(0);
212 }
213
214#if defined(__x86_64__)
215 if (largest != 1U<<30) {
216 printf("No GB pages available on x86-64\n"
217 "Please boot with hugepagesz=1G hugepages=%d\n", NUM_PAGES);
218 exit(0);
219 }
220#endif
221}
222
223int main(void)
224{
225 int i;
226 unsigned default_hps = default_huge_page_size();
227
228 find_pagesizes();
229
230 sanity_checks();
231
232 for (i = 0; i < num_page_sizes; i++) {
233 unsigned long ps = page_sizes[i];
234 int arg = ilog2(ps) << MAP_HUGE_SHIFT;
235 printf("Testing %luMB mmap with shift %x\n", ps >> 20, arg);
236 test_mmap(ps, MAP_HUGETLB | arg);
237 }
238 printf("Testing default huge mmap\n");
239 test_mmap(default_hps, SHM_HUGETLB);
240
241 puts("Testing non-huge shmget");
242 test_shmget(getpagesize(), 0);
243
244 for (i = 0; i < num_page_sizes; i++) {
245 unsigned long ps = page_sizes[i];
246 int arg = ilog2(ps) << SHM_HUGE_SHIFT;
247 printf("Testing %luMB shmget with shift %x\n", ps >> 20, arg);
248 test_shmget(ps, SHM_HUGETLB | arg);
249 }
250 puts("default huge shmget");
251 test_shmget(default_hps, SHM_HUGETLB);
252
253 return 0;
254}
diff --git a/tools/usb/Makefile b/tools/usb/Makefile
index 396d6c44e9d..8b704af1434 100644
--- a/tools/usb/Makefile
+++ b/tools/usb/Makefile
@@ -3,7 +3,7 @@
3CC = $(CROSS_COMPILE)gcc 3CC = $(CROSS_COMPILE)gcc
4PTHREAD_LIBS = -lpthread 4PTHREAD_LIBS = -lpthread
5WARNINGS = -Wall -Wextra 5WARNINGS = -Wall -Wextra
6CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS) -I../include 6CFLAGS = $(WARNINGS) -g $(PTHREAD_LIBS)
7 7
8all: testusb ffs-test 8all: testusb ffs-test
9%: %.c 9%: %.c
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index 8674b9ec14f..b9c79863169 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -2,7 +2,7 @@
2 * ffs-test.c.c -- user mode filesystem api for usb composite function 2 * ffs-test.c.c -- user mode filesystem api for usb composite function
3 * 3 *
4 * Copyright (C) 2010 Samsung Electronics 4 * Copyright (C) 2010 Samsung Electronics
5 * Author: Michal Nazarewicz <mina86@mina86.com> 5 * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -36,7 +36,6 @@
36#include <sys/stat.h> 36#include <sys/stat.h>
37#include <sys/types.h> 37#include <sys/types.h>
38#include <unistd.h> 38#include <unistd.h>
39#include <tools/le_byteshift.h>
40 39
41#include "../../include/linux/usb/functionfs.h" 40#include "../../include/linux/usb/functionfs.h"
42 41
@@ -48,6 +47,34 @@
48#define le32_to_cpu(x) le32toh(x) 47#define le32_to_cpu(x) le32toh(x)
49#define le16_to_cpu(x) le16toh(x) 48#define le16_to_cpu(x) le16toh(x)
50 49
50static inline __u16 get_unaligned_le16(const void *_ptr)
51{
52 const __u8 *ptr = _ptr;
53 return ptr[0] | (ptr[1] << 8);
54}
55
56static inline __u32 get_unaligned_le32(const void *_ptr)
57{
58 const __u8 *ptr = _ptr;
59 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
60}
61
62static inline void put_unaligned_le16(__u16 val, void *_ptr)
63{
64 __u8 *ptr = _ptr;
65 *ptr++ = val;
66 *ptr++ = val >> 8;
67}
68
69static inline void put_unaligned_le32(__u32 val, void *_ptr)
70{
71 __u8 *ptr = _ptr;
72 *ptr++ = val;
73 *ptr++ = val >> 8;
74 *ptr++ = val >> 16;
75 *ptr++ = val >> 24;
76}
77
51 78
52/******************** Messages and Errors ***********************************/ 79/******************** Messages and Errors ***********************************/
53 80
@@ -297,7 +324,7 @@ static void *start_thread_helper(void *arg)
297 324
298 ret = t->in(t, t->buf, t->buf_size); 325 ret = t->in(t, t->buf, t->buf_size);
299 if (ret > 0) { 326 if (ret > 0) {
300 ret = t->out(t, t->buf, ret); 327 ret = t->out(t, t->buf, t->buf_size);
301 name = out_name; 328 name = out_name;
302 op = "write"; 329 op = "write";
303 } else { 330 } else {
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index 68d0734b208..f08e8946384 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -3,7 +3,7 @@
3/* 3/*
4 * Copyright (c) 2002 by David Brownell 4 * Copyright (c) 2002 by David Brownell
5 * Copyright (c) 2010 by Samsung Electronics 5 * Copyright (c) 2010 by Samsung Electronics
6 * Author: Michal Nazarewicz <mina86@mina86.com> 6 * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify it 8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the 9 * under the terms of the GNU General Public License as published by the
@@ -253,6 +253,9 @@ static int find_testdev(const char *name, const struct stat *sb, int flag)
253 253
254 if (flag != FTW_F) 254 if (flag != FTW_F)
255 return 0; 255 return 0;
256 /* ignore /proc/bus/usb/{devices,drivers} */
257 if (strrchr(name, '/')[1] == 'd')
258 return 0;
256 259
257 fd = fopen(name, "rb"); 260 fd = fopen(name, "rb");
258 if (!fd) { 261 if (!fd) {
@@ -353,10 +356,25 @@ restart:
353 356
354static const char *usbfs_dir_find(void) 357static const char *usbfs_dir_find(void)
355{ 358{
356 static char udev_usb_path[] = "/dev/bus/usb"; 359 static char usbfs_path_0[] = "/dev/usb/devices";
357 360 static char usbfs_path_1[] = "/proc/bus/usb/devices";
358 if (access(udev_usb_path, F_OK) == 0) 361
359 return udev_usb_path; 362 static char *const usbfs_paths[] = {
363 usbfs_path_0, usbfs_path_1
364 };
365
366 static char *const *
367 end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths;
368
369 char *const *it = usbfs_paths;
370 do {
371 int fd = open(*it, O_RDONLY);
372 close(fd);
373 if (fd >= 0) {
374 strrchr(*it, '/')[0] = '\0';
375 return *it;
376 }
377 } while (++it != end);
360 378
361 return NULL; 379 return NULL;
362} 380}
@@ -402,7 +420,7 @@ int main (int argc, char **argv)
402 /* for easy use when hotplugging */ 420 /* for easy use when hotplugging */
403 device = getenv ("DEVICE"); 421 device = getenv ("DEVICE");
404 422
405 while ((c = getopt (argc, argv, "D:aA:c:g:hlns:t:v:")) != EOF) 423 while ((c = getopt (argc, argv, "D:aA:c:g:hns:t:v:")) != EOF)
406 switch (c) { 424 switch (c) {
407 case 'D': /* device, if only one */ 425 case 'D': /* device, if only one */
408 device = optarg; 426 device = optarg;
@@ -445,28 +463,17 @@ int main (int argc, char **argv)
445 case 'h': 463 case 'h':
446 default: 464 default:
447usage: 465usage:
448 fprintf (stderr, 466 fprintf (stderr, "usage: %s [-n] [-D dev | -a | -A usbfs-dir]\n"
449 "usage: %s [options]\n" 467 "\t[-c iterations] [-t testnum]\n"
450 "Options:\n" 468 "\t[-s packetsize] [-g sglen] [-v vary]\n",
451 "\t-D dev only test specific device\n" 469 argv [0]);
452 "\t-A usbfs-dir\n"
453 "\t-a test all recognized devices\n"
454 "\t-l loop forever(for stress test)\n"
455 "\t-t testnum only run specified case\n"
456 "\t-n no test running, show devices to be tested\n"
457 "Case arguments:\n"
458 "\t-c iterations default 1000\n"
459 "\t-s packetsize default 512\n"
460 "\t-g sglen default 32\n"
461 "\t-v vary default 512\n",
462 argv[0]);
463 return 1; 470 return 1;
464 } 471 }
465 if (optind != argc) 472 if (optind != argc)
466 goto usage; 473 goto usage;
467 if (!all && !device) { 474 if (!all && !device) {
468 fprintf (stderr, "must specify '-a' or '-D dev', " 475 fprintf (stderr, "must specify '-a' or '-D dev', "
469 "or DEVICE=/dev/bus/usb/BBB/DDD in env\n"); 476 "or DEVICE=/proc/bus/usb/BBB/DDD in env\n");
470 goto usage; 477 goto usage;
471 } 478 }
472 479
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index 81847dd08bd..669bcdd4580 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -181,20 +181,26 @@ struct virtqueue {
181#define smp_mb() mb() 181#define smp_mb() mb()
182# define smp_rmb() barrier() 182# define smp_rmb() barrier()
183# define smp_wmb() barrier() 183# define smp_wmb() barrier()
184/* Weak barriers should be used. If not - it's a bug */
185# define rmb() abort()
186# define wmb() abort()
187#else 184#else
188#error Please fill in barrier macros 185#error Please fill in barrier macros
189#endif 186#endif
190 187
191/* Interfaces exported by virtio_ring. */ 188/* Interfaces exported by virtio_ring. */
192int virtqueue_add_buf(struct virtqueue *vq, 189int virtqueue_add_buf_gfp(struct virtqueue *vq,
193 struct scatterlist sg[], 190 struct scatterlist sg[],
194 unsigned int out_num, 191 unsigned int out_num,
195 unsigned int in_num, 192 unsigned int in_num,
196 void *data, 193 void *data,
197 gfp_t gfp); 194 gfp_t gfp);
195
196static inline int virtqueue_add_buf(struct virtqueue *vq,
197 struct scatterlist sg[],
198 unsigned int out_num,
199 unsigned int in_num,
200 void *data)
201{
202 return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
203}
198 204
199void virtqueue_kick(struct virtqueue *vq); 205void virtqueue_kick(struct virtqueue *vq);
200 206
@@ -203,13 +209,11 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
203void virtqueue_disable_cb(struct virtqueue *vq); 209void virtqueue_disable_cb(struct virtqueue *vq);
204 210
205bool virtqueue_enable_cb(struct virtqueue *vq); 211bool virtqueue_enable_cb(struct virtqueue *vq);
206bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
207 212
208void *virtqueue_detach_unused_buf(struct virtqueue *vq); 213void *virtqueue_detach_unused_buf(struct virtqueue *vq);
209struct virtqueue *vring_new_virtqueue(unsigned int num, 214struct virtqueue *vring_new_virtqueue(unsigned int num,
210 unsigned int vring_align, 215 unsigned int vring_align,
211 struct virtio_device *vdev, 216 struct virtio_device *vdev,
212 bool weak_barriers,
213 void *pages, 217 void *pages,
214 void (*notify)(struct virtqueue *vq), 218 void (*notify)(struct virtqueue *vq),
215 void (*callback)(struct virtqueue *vq), 219 void (*callback)(struct virtqueue *vq),
diff --git a/tools/virtio/virtio-trace/Makefile b/tools/virtio/virtio-trace/Makefile
deleted file mode 100644
index 0d238163347..00000000000
--- a/tools/virtio/virtio-trace/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
1CC = gcc
2CFLAGS = -O2 -Wall -pthread
3
4all: trace-agent
5
6.c.o:
7 $(CC) $(CFLAGS) -c $^ -o $@
8
9trace-agent: trace-agent.o trace-agent-ctl.o trace-agent-rw.o
10 $(CC) $(CFLAGS) -o $@ $^
11
12clean:
13 rm -f *.o trace-agent
diff --git a/tools/virtio/virtio-trace/README b/tools/virtio/virtio-trace/README
deleted file mode 100644
index b64845b823a..00000000000
--- a/tools/virtio/virtio-trace/README
+++ /dev/null
@@ -1,118 +0,0 @@
1Trace Agent for virtio-trace
2============================
3
4Trace agent is a user tool for sending trace data of a guest to a Host in low
5overhead. Trace agent has the following functions:
6 - splice a page of ring-buffer to read_pipe without memory copying
7 - splice the page from write_pipe to virtio-console without memory copying
8 - write trace data to stdout by using -o option
9 - controlled by start/stop orders from a Host
10
11The trace agent operates as follows:
12 1) Initialize all structures.
13 2) Create a read/write thread per CPU. Each thread is bound to a CPU.
14 The read/write threads hold it.
15 3) A controller thread does poll() for a start order of a host.
16 4) After the controller of the trace agent receives a start order from a host,
17 the controller wake read/write threads.
18 5) The read/write threads start to read trace data from ring-buffers and
19 write the data to virtio-serial.
20 6) If the controller receives a stop order from a host, the read/write threads
21 stop to read trace data.
22
23
24Files
25=====
26
27README: this file
28Makefile: Makefile of trace agent for virtio-trace
29trace-agent.c: includes main function, sets up for operating trace agent
30trace-agent.h: includes all structures and some macros
31trace-agent-ctl.c: includes controller function for read/write threads
32trace-agent-rw.c: includes read/write threads function
33
34
35Setup
36=====
37
38To use this trace agent for virtio-trace, we need to prepare some virtio-serial
39I/Fs.
40
411) Make FIFO in a host
42 virtio-trace uses virtio-serial pipe as trace data paths as to the number
43of CPUs and a control path, so FIFO (named pipe) should be created as follows:
44 # mkdir /tmp/virtio-trace/
45 # mkfifo /tmp/virtio-trace/trace-path-cpu{0,1,2,...,X}.{in,out}
46 # mkfifo /tmp/virtio-trace/agent-ctl-path.{in,out}
47
48For example, if a guest use three CPUs, the names are
49 trace-path-cpu{0,1,2}.{in.out}
50and
51 agent-ctl-path.{in,out}.
52
532) Set up of virtio-serial pipe in a host
54 Add qemu option to use virtio-serial pipe.
55
56 ##virtio-serial device##
57 -device virtio-serial-pci,id=virtio-serial0\
58 ##control path##
59 -chardev pipe,id=charchannel0,path=/tmp/virtio-trace/agent-ctl-path\
60 -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,\
61 id=channel0,name=agent-ctl-path\
62 ##data path##
63 -chardev pipe,id=charchannel1,path=/tmp/virtio-trace/trace-path-cpu0\
64 -device virtserialport,bus=virtio-serial0.0,nr=2,chardev=charchannel0,\
65 id=channel1,name=trace-path-cpu0\
66 ...
67
68If you manage guests with libvirt, add the following tags to domain XML files.
69Then, libvirt passes the same command option to qemu.
70
71 <channel type='pipe'>
72 <source path='/tmp/virtio-trace/agent-ctl-path'/>
73 <target type='virtio' name='agent-ctl-path'/>
74 <address type='virtio-serial' controller='0' bus='0' port='0'/>
75 </channel>
76 <channel type='pipe'>
77 <source path='/tmp/virtio-trace/trace-path-cpu0'/>
78 <target type='virtio' name='trace-path-cpu0'/>
79 <address type='virtio-serial' controller='0' bus='0' port='1'/>
80 </channel>
81 ...
82Here, chardev names are restricted to trace-path-cpuX and agent-ctl-path. For
83example, if a guest use three CPUs, chardev names should be trace-path-cpu0,
84trace-path-cpu1, trace-path-cpu2, and agent-ctl-path.
85
863) Boot the guest
87 You can find some chardev in /dev/virtio-ports/ in the guest.
88
89
90Run
91===
92
930) Build trace agent in a guest
94 $ make
95
961) Enable ftrace in the guest
97 <Example>
98 # echo 1 > /sys/kernel/debug/tracing/events/sched/enable
99
1002) Run trace agent in the guest
101 This agent must be operated as root.
102 # ./trace-agent
103read/write threads in the agent wait for start order from host. If you add -o
104option, trace data are output via stdout in the guest.
105
1063) Open FIFO in a host
107 # cat /tmp/virtio-trace/trace-path-cpu0.out
108If a host does not open these, trace data get stuck in buffers of virtio. Then,
109the guest will stop by specification of chardev in QEMU. This blocking mode may
110be solved in the future.
111
1124) Start to read trace data by ordering from a host
113 A host injects read start order to the guest via virtio-serial.
114 # echo 1 > /tmp/virtio-trace/agent-ctl-path.in
115
1165) Stop to read trace data by ordering from a host
117 A host injects read stop order to the guest via virtio-serial.
118 # echo 0 > /tmp/virtio-trace/agent-ctl-path.in
diff --git a/tools/virtio/virtio-trace/trace-agent-ctl.c b/tools/virtio/virtio-trace/trace-agent-ctl.c
deleted file mode 100644
index a2d0403c4f9..00000000000
--- a/tools/virtio/virtio-trace/trace-agent-ctl.c
+++ /dev/null
@@ -1,137 +0,0 @@
1/*
2 * Controller of read/write threads for virtio-trace
3 *
4 * Copyright (C) 2012 Hitachi, Ltd.
5 * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
6 * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
7 *
8 * Licensed under GPL version 2 only.
9 *
10 */
11
12#define _GNU_SOURCE
13#include <fcntl.h>
14#include <poll.h>
15#include <signal.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19#include "trace-agent.h"
20
21#define HOST_MSG_SIZE 256
22#define EVENT_WAIT_MSEC 100
23
24static volatile sig_atomic_t global_signal_val;
25bool global_sig_receive; /* default false */
26bool global_run_operation; /* default false*/
27
28/* Handle SIGTERM/SIGINT/SIGQUIT to exit */
29static void signal_handler(int sig)
30{
31 global_signal_val = sig;
32}
33
34int rw_ctl_init(const char *ctl_path)
35{
36 int ctl_fd;
37
38 ctl_fd = open(ctl_path, O_RDONLY);
39 if (ctl_fd == -1) {
40 pr_err("Cannot open ctl_fd\n");
41 goto error;
42 }
43
44 return ctl_fd;
45
46error:
47 exit(EXIT_FAILURE);
48}
49
50static int wait_order(int ctl_fd)
51{
52 struct pollfd poll_fd;
53 int ret = 0;
54
55 while (!global_sig_receive) {
56 poll_fd.fd = ctl_fd;
57 poll_fd.events = POLLIN;
58
59 ret = poll(&poll_fd, 1, EVENT_WAIT_MSEC);
60
61 if (global_signal_val) {
62 global_sig_receive = true;
63 pr_info("Receive interrupt %d\n", global_signal_val);
64
65 /* Wakes rw-threads when they are sleeping */
66 if (!global_run_operation)
67 pthread_cond_broadcast(&cond_wakeup);
68
69 ret = -1;
70 break;
71 }
72
73 if (ret < 0) {
74 pr_err("Polling error\n");
75 goto error;
76 }
77
78 if (ret)
79 break;
80 };
81
82 return ret;
83
84error:
85 exit(EXIT_FAILURE);
86}
87
88/*
89 * contol read/write threads by handling global_run_operation
90 */
91void *rw_ctl_loop(int ctl_fd)
92{
93 ssize_t rlen;
94 char buf[HOST_MSG_SIZE];
95 int ret;
96
97 /* Setup signal handlers */
98 signal(SIGTERM, signal_handler);
99 signal(SIGINT, signal_handler);
100 signal(SIGQUIT, signal_handler);
101
102 while (!global_sig_receive) {
103
104 ret = wait_order(ctl_fd);
105 if (ret < 0)
106 break;
107
108 rlen = read(ctl_fd, buf, sizeof(buf));
109 if (rlen < 0) {
110 pr_err("read data error in ctl thread\n");
111 goto error;
112 }
113
114 if (rlen == 2 && buf[0] == '1') {
115 /*
116 * If host writes '1' to a control path,
117 * this controller wakes all read/write threads.
118 */
119 global_run_operation = true;
120 pthread_cond_broadcast(&cond_wakeup);
121 pr_debug("Wake up all read/write threads\n");
122 } else if (rlen == 2 && buf[0] == '0') {
123 /*
124 * If host writes '0' to a control path, read/write
125 * threads will wait for notification from Host.
126 */
127 global_run_operation = false;
128 pr_debug("Stop all read/write threads\n");
129 } else
130 pr_info("Invalid host notification: %s\n", buf);
131 }
132
133 return NULL;
134
135error:
136 exit(EXIT_FAILURE);
137}
diff --git a/tools/virtio/virtio-trace/trace-agent-rw.c b/tools/virtio/virtio-trace/trace-agent-rw.c
deleted file mode 100644
index 3aace5ea484..00000000000
--- a/tools/virtio/virtio-trace/trace-agent-rw.c
+++ /dev/null
@@ -1,192 +0,0 @@
1/*
2 * Read/write thread of a guest agent for virtio-trace
3 *
4 * Copyright (C) 2012 Hitachi, Ltd.
5 * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
6 * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
7 *
8 * Licensed under GPL version 2 only.
9 *
10 */
11
12#define _GNU_SOURCE
13#include <fcntl.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <sys/syscall.h>
18#include "trace-agent.h"
19
20#define READ_WAIT_USEC 100000
21
22void *rw_thread_info_new(void)
23{
24 struct rw_thread_info *rw_ti;
25
26 rw_ti = zalloc(sizeof(struct rw_thread_info));
27 if (rw_ti == NULL) {
28 pr_err("rw_thread_info zalloc error\n");
29 exit(EXIT_FAILURE);
30 }
31
32 rw_ti->cpu_num = -1;
33 rw_ti->in_fd = -1;
34 rw_ti->out_fd = -1;
35 rw_ti->read_pipe = -1;
36 rw_ti->write_pipe = -1;
37 rw_ti->pipe_size = PIPE_INIT;
38
39 return rw_ti;
40}
41
42void *rw_thread_init(int cpu, const char *in_path, const char *out_path,
43 bool stdout_flag, unsigned long pipe_size,
44 struct rw_thread_info *rw_ti)
45{
46 int data_pipe[2];
47
48 rw_ti->cpu_num = cpu;
49
50 /* set read(input) fd */
51 rw_ti->in_fd = open(in_path, O_RDONLY);
52 if (rw_ti->in_fd == -1) {
53 pr_err("Could not open in_fd (CPU:%d)\n", cpu);
54 goto error;
55 }
56
57 /* set write(output) fd */
58 if (!stdout_flag) {
59 /* virtio-serial output mode */
60 rw_ti->out_fd = open(out_path, O_WRONLY);
61 if (rw_ti->out_fd == -1) {
62 pr_err("Could not open out_fd (CPU:%d)\n", cpu);
63 goto error;
64 }
65 } else
66 /* stdout mode */
67 rw_ti->out_fd = STDOUT_FILENO;
68
69 if (pipe2(data_pipe, O_NONBLOCK) < 0) {
70 pr_err("Could not create pipe in rw-thread(%d)\n", cpu);
71 goto error;
72 }
73
74 /*
75 * Size of pipe is 64kB in default based on fs/pipe.c.
76 * To read/write trace data speedy, pipe size is changed.
77 */
78 if (fcntl(*data_pipe, F_SETPIPE_SZ, pipe_size) < 0) {
79 pr_err("Could not change pipe size in rw-thread(%d)\n", cpu);
80 goto error;
81 }
82
83 rw_ti->read_pipe = data_pipe[1];
84 rw_ti->write_pipe = data_pipe[0];
85 rw_ti->pipe_size = pipe_size;
86
87 return NULL;
88
89error:
90 exit(EXIT_FAILURE);
91}
92
93/* Bind a thread to a cpu */
94static void bind_cpu(int cpu_num)
95{
96 cpu_set_t mask;
97
98 CPU_ZERO(&mask);
99 CPU_SET(cpu_num, &mask);
100
101 /* bind my thread to cpu_num by assigning zero to the first argument */
102 if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
103 pr_err("Could not set CPU#%d affinity\n", (int)cpu_num);
104}
105
106static void *rw_thread_main(void *thread_info)
107{
108 ssize_t rlen, wlen;
109 ssize_t ret;
110 struct rw_thread_info *ts = (struct rw_thread_info *)thread_info;
111
112 bind_cpu(ts->cpu_num);
113
114 while (1) {
115 /* Wait for a read order of trace data by Host OS */
116 if (!global_run_operation) {
117 pthread_mutex_lock(&mutex_notify);
118 pthread_cond_wait(&cond_wakeup, &mutex_notify);
119 pthread_mutex_unlock(&mutex_notify);
120 }
121
122 if (global_sig_receive)
123 break;
124
125 /*
126 * Each thread read trace_pipe_raw of each cpu bounding the
127 * thread, so contention of multi-threads does not occur.
128 */
129 rlen = splice(ts->in_fd, NULL, ts->read_pipe, NULL,
130 ts->pipe_size, SPLICE_F_MOVE | SPLICE_F_MORE);
131
132 if (rlen < 0) {
133 pr_err("Splice_read in rw-thread(%d)\n", ts->cpu_num);
134 goto error;
135 } else if (rlen == 0) {
136 /*
137 * If trace data do not exist or are unreadable not
138 * for exceeding the page size, splice_read returns
139 * NULL. Then, this waits for being filled the data in a
140 * ring-buffer.
141 */
142 usleep(READ_WAIT_USEC);
143 pr_debug("Read retry(cpu:%d)\n", ts->cpu_num);
144 continue;
145 }
146
147 wlen = 0;
148
149 do {
150 ret = splice(ts->write_pipe, NULL, ts->out_fd, NULL,
151 rlen - wlen,
152 SPLICE_F_MOVE | SPLICE_F_MORE);
153
154 if (ret < 0) {
155 pr_err("Splice_write in rw-thread(%d)\n",
156 ts->cpu_num);
157 goto error;
158 } else if (ret == 0)
159 /*
160 * When host reader is not in time for reading
161 * trace data, guest will be stopped. This is
162 * because char dev in QEMU is not supported
163 * non-blocking mode. Then, writer might be
164 * sleep in that case.
165 * This sleep will be removed by supporting
166 * non-blocking mode.
167 */
168 sleep(1);
169 wlen += ret;
170 } while (wlen < rlen);
171 }
172
173 return NULL;
174
175error:
176 exit(EXIT_FAILURE);
177}
178
179
180pthread_t rw_thread_run(struct rw_thread_info *rw_ti)
181{
182 int ret;
183 pthread_t rw_thread_per_cpu;
184
185 ret = pthread_create(&rw_thread_per_cpu, NULL, rw_thread_main, rw_ti);
186 if (ret != 0) {
187 pr_err("Could not create a rw thread(%d)\n", rw_ti->cpu_num);
188 exit(EXIT_FAILURE);
189 }
190
191 return rw_thread_per_cpu;
192}
diff --git a/tools/virtio/virtio-trace/trace-agent.c b/tools/virtio/virtio-trace/trace-agent.c
deleted file mode 100644
index 0a0a7dd4eff..00000000000
--- a/tools/virtio/virtio-trace/trace-agent.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/*
2 * Guest agent for virtio-trace
3 *
4 * Copyright (C) 2012 Hitachi, Ltd.
5 * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
6 * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
7 *
8 * Licensed under GPL version 2 only.
9 *
10 */
11
12#define _GNU_SOURCE
13#include <limits.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include "trace-agent.h"
18
19#define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
20#define PIPE_DEF_BUFS 16
21#define PIPE_MIN_SIZE (PAGE_SIZE*PIPE_DEF_BUFS)
22#define PIPE_MAX_SIZE (1024*1024)
23#define READ_PATH_FMT \
24 "/sys/kernel/debug/tracing/per_cpu/cpu%d/trace_pipe_raw"
25#define WRITE_PATH_FMT "/dev/virtio-ports/trace-path-cpu%d"
26#define CTL_PATH "/dev/virtio-ports/agent-ctl-path"
27
28pthread_mutex_t mutex_notify = PTHREAD_MUTEX_INITIALIZER;
29pthread_cond_t cond_wakeup = PTHREAD_COND_INITIALIZER;
30
31static int get_total_cpus(void)
32{
33 int nr_cpus = (int)sysconf(_SC_NPROCESSORS_CONF);
34
35 if (nr_cpus <= 0) {
36 pr_err("Could not read cpus\n");
37 goto error;
38 } else if (nr_cpus > MAX_CPUS) {
39 pr_err("Exceed max cpus(%d)\n", (int)MAX_CPUS);
40 goto error;
41 }
42
43 return nr_cpus;
44
45error:
46 exit(EXIT_FAILURE);
47}
48
49static void *agent_info_new(void)
50{
51 struct agent_info *s;
52 int i;
53
54 s = zalloc(sizeof(struct agent_info));
55 if (s == NULL) {
56 pr_err("agent_info zalloc error\n");
57 exit(EXIT_FAILURE);
58 }
59
60 s->pipe_size = PIPE_INIT;
61 s->use_stdout = false;
62 s->cpus = get_total_cpus();
63 s->ctl_fd = -1;
64
65 /* read/write threads init */
66 for (i = 0; i < s->cpus; i++)
67 s->rw_ti[i] = rw_thread_info_new();
68
69 return s;
70}
71
72static unsigned long parse_size(const char *arg)
73{
74 unsigned long value, round;
75 char *ptr;
76
77 value = strtoul(arg, &ptr, 10);
78 switch (*ptr) {
79 case 'K': case 'k':
80 value <<= 10;
81 break;
82 case 'M': case 'm':
83 value <<= 20;
84 break;
85 default:
86 break;
87 }
88
89 if (value > PIPE_MAX_SIZE) {
90 pr_err("Pipe size must be less than 1MB\n");
91 goto error;
92 } else if (value < PIPE_MIN_SIZE) {
93 pr_err("Pipe size must be over 64KB\n");
94 goto error;
95 }
96
97 /* Align buffer size with page unit */
98 round = value & (PAGE_SIZE - 1);
99 value = value - round;
100
101 return value;
102error:
103 return 0;
104}
105
106static void usage(char const *prg)
107{
108 pr_err("usage: %s [-h] [-o] [-s <size of pipe>]\n", prg);
109}
110
111static const char *make_path(int cpu_num, bool this_is_write_path)
112{
113 int ret;
114 char *buf;
115
116 buf = zalloc(PATH_MAX);
117 if (buf == NULL) {
118 pr_err("Could not allocate buffer\n");
119 goto error;
120 }
121
122 if (this_is_write_path)
123 /* write(output) path */
124 ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num);
125 else
126 /* read(input) path */
127 ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, cpu_num);
128
129 if (ret <= 0) {
130 pr_err("Failed to generate %s path(CPU#%d):%d\n",
131 this_is_write_path ? "read" : "write", cpu_num, ret);
132 goto error;
133 }
134
135 return buf;
136
137error:
138 free(buf);
139 return NULL;
140}
141
142static const char *make_input_path(int cpu_num)
143{
144 return make_path(cpu_num, false);
145}
146
147static const char *make_output_path(int cpu_num)
148{
149 return make_path(cpu_num, true);
150}
151
152static void *agent_info_init(struct agent_info *s)
153{
154 int cpu;
155 const char *in_path = NULL;
156 const char *out_path = NULL;
157
158 /* init read/write threads */
159 for (cpu = 0; cpu < s->cpus; cpu++) {
160 /* set read(input) path per read/write thread */
161 in_path = make_input_path(cpu);
162 if (in_path == NULL)
163 goto error;
164
165 /* set write(output) path per read/write thread*/
166 if (!s->use_stdout) {
167 out_path = make_output_path(cpu);
168 if (out_path == NULL)
169 goto error;
170 } else
171 /* stdout mode */
172 pr_debug("stdout mode\n");
173
174 rw_thread_init(cpu, in_path, out_path, s->use_stdout,
175 s->pipe_size, s->rw_ti[cpu]);
176 }
177
178 /* init controller of read/write threads */
179 s->ctl_fd = rw_ctl_init((const char *)CTL_PATH);
180
181 return NULL;
182
183error:
184 exit(EXIT_FAILURE);
185}
186
187static void *parse_args(int argc, char *argv[], struct agent_info *s)
188{
189 int cmd;
190 unsigned long size;
191
192 while ((cmd = getopt(argc, argv, "hos:")) != -1) {
193 switch (cmd) {
194 /* stdout mode */
195 case 'o':
196 s->use_stdout = true;
197 break;
198 /* size of pipe */
199 case 's':
200 size = parse_size(optarg);
201 if (size == 0)
202 goto error;
203 s->pipe_size = size;
204 break;
205 case 'h':
206 default:
207 usage(argv[0]);
208 goto error;
209 }
210 }
211
212 agent_info_init(s);
213
214 return NULL;
215
216error:
217 exit(EXIT_FAILURE);
218}
219
220static void agent_main_loop(struct agent_info *s)
221{
222 int cpu;
223 pthread_t rw_thread_per_cpu[MAX_CPUS];
224
225 /* Start all read/write threads */
226 for (cpu = 0; cpu < s->cpus; cpu++)
227 rw_thread_per_cpu[cpu] = rw_thread_run(s->rw_ti[cpu]);
228
229 rw_ctl_loop(s->ctl_fd);
230
231 /* Finish all read/write threads */
232 for (cpu = 0; cpu < s->cpus; cpu++) {
233 int ret;
234
235 ret = pthread_join(rw_thread_per_cpu[cpu], NULL);
236 if (ret != 0) {
237 pr_err("pthread_join() error:%d (cpu %d)\n", ret, cpu);
238 exit(EXIT_FAILURE);
239 }
240 }
241}
242
243static void agent_info_free(struct agent_info *s)
244{
245 int i;
246
247 close(s->ctl_fd);
248 for (i = 0; i < s->cpus; i++) {
249 close(s->rw_ti[i]->in_fd);
250 close(s->rw_ti[i]->out_fd);
251 close(s->rw_ti[i]->read_pipe);
252 close(s->rw_ti[i]->write_pipe);
253 free(s->rw_ti[i]);
254 }
255 free(s);
256}
257
258int main(int argc, char *argv[])
259{
260 struct agent_info *s = NULL;
261
262 s = agent_info_new();
263 parse_args(argc, argv, s);
264
265 agent_main_loop(s);
266
267 agent_info_free(s);
268
269 return 0;
270}
diff --git a/tools/virtio/virtio-trace/trace-agent.h b/tools/virtio/virtio-trace/trace-agent.h
deleted file mode 100644
index 8de79bfeaa7..00000000000
--- a/tools/virtio/virtio-trace/trace-agent.h
+++ /dev/null
@@ -1,75 +0,0 @@
1#ifndef __TRACE_AGENT_H__
2#define __TRACE_AGENT_H__
3#include <pthread.h>
4#include <stdbool.h>
5
6#define MAX_CPUS 256
7#define PIPE_INIT (1024*1024)
8
9/*
10 * agent_info - structure managing total information of guest agent
11 * @pipe_size: size of pipe (default 1MB)
12 * @use_stdout: set to true when o option is added (default false)
13 * @cpus: total number of CPUs
14 * @ctl_fd: fd of control path, /dev/virtio-ports/agent-ctl-path
15 * @rw_ti: structure managing information of read/write threads
16 */
17struct agent_info {
18 unsigned long pipe_size;
19 bool use_stdout;
20 int cpus;
21 int ctl_fd;
22 struct rw_thread_info *rw_ti[MAX_CPUS];
23};
24
25/*
26 * rw_thread_info - structure managing a read/write thread a cpu
27 * @cpu_num: cpu number operating this read/write thread
28 * @in_fd: fd of reading trace data path in cpu_num
29 * @out_fd: fd of writing trace data path in cpu_num
30 * @read_pipe: fd of read pipe
31 * @write_pipe: fd of write pipe
32 * @pipe_size: size of pipe (default 1MB)
33 */
34struct rw_thread_info {
35 int cpu_num;
36 int in_fd;
37 int out_fd;
38 int read_pipe;
39 int write_pipe;
40 unsigned long pipe_size;
41};
42
43/* use for stopping rw threads */
44extern bool global_sig_receive;
45
46/* use for notification */
47extern bool global_run_operation;
48extern pthread_mutex_t mutex_notify;
49extern pthread_cond_t cond_wakeup;
50
51/* for controller of read/write threads */
52extern int rw_ctl_init(const char *ctl_path);
53extern void *rw_ctl_loop(int ctl_fd);
54
55/* for trace read/write thread */
56extern void *rw_thread_info_new(void);
57extern void *rw_thread_init(int cpu, const char *in_path, const char *out_path,
58 bool stdout_flag, unsigned long pipe_size,
59 struct rw_thread_info *rw_ti);
60extern pthread_t rw_thread_run(struct rw_thread_info *rw_ti);
61
62static inline void *zalloc(size_t size)
63{
64 return calloc(1, size);
65}
66
67#define pr_err(format, ...) fprintf(stderr, format, ## __VA_ARGS__)
68#define pr_info(format, ...) fprintf(stdout, format, ## __VA_ARGS__)
69#ifdef DEBUG
70#define pr_debug(format, ...) fprintf(stderr, format, ## __VA_ARGS__)
71#else
72#define pr_debug(format, ...) do {} while (0)
73#endif
74
75#endif /*__TRACE_AGENT_H__*/
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index fcc9aa25fd0..74d3331bdaf 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -92,8 +92,7 @@ static void vq_info_add(struct vdev_info *dev, int num)
92 assert(r >= 0); 92 assert(r >= 0);
93 memset(info->ring, 0, vring_size(num, 4096)); 93 memset(info->ring, 0, vring_size(num, 4096));
94 vring_init(&info->vring, num, info->ring, 4096); 94 vring_init(&info->vring, num, info->ring, 4096);
95 info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, 95 info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, info->ring,
96 true, info->ring,
97 vq_notify, vq_callback, "test"); 96 vq_notify, vq_callback, "test");
98 assert(info->vq); 97 assert(info->vq);
99 info->vq->priv = info; 98 info->vq->priv = info;
@@ -144,8 +143,7 @@ static void wait_for_interrupt(struct vdev_info *dev)
144 } 143 }
145} 144}
146 145
147static void run_test(struct vdev_info *dev, struct vq_info *vq, 146static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs)
148 bool delayed, int bufs)
149{ 147{
150 struct scatterlist sl; 148 struct scatterlist sl;
151 long started = 0, completed = 0; 149 long started = 0, completed = 0;
@@ -162,9 +160,8 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
162 if (started < bufs) { 160 if (started < bufs) {
163 sg_init_one(&sl, dev->buf, dev->buf_size); 161 sg_init_one(&sl, dev->buf, dev->buf_size);
164 r = virtqueue_add_buf(vq->vq, &sl, 1, 0, 162 r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
165 dev->buf + started, 163 dev->buf + started);
166 GFP_ATOMIC); 164 if (likely(r >= 0)) {
167 if (likely(r == 0)) {
168 ++started; 165 ++started;
169 virtqueue_kick(vq->vq); 166 virtqueue_kick(vq->vq);
170 } 167 }
@@ -177,19 +174,15 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
177 r = 0; 174 r = 0;
178 } 175 }
179 176
180 } while (r == 0); 177 } while (r >= 0);
181 if (completed == completed_before) 178 if (completed == completed_before)
182 ++spurious; 179 ++spurious;
183 assert(completed <= bufs); 180 assert(completed <= bufs);
184 assert(started <= bufs); 181 assert(started <= bufs);
185 if (completed == bufs) 182 if (completed == bufs)
186 break; 183 break;
187 if (delayed) { 184 if (virtqueue_enable_cb(vq->vq)) {
188 if (virtqueue_enable_cb_delayed(vq->vq)) 185 wait_for_interrupt(dev);
189 wait_for_interrupt(dev);
190 } else {
191 if (virtqueue_enable_cb(vq->vq))
192 wait_for_interrupt(dev);
193 } 186 }
194 } 187 }
195 test = 0; 188 test = 0;
@@ -221,23 +214,14 @@ const struct option longopts[] = {
221 .val = 'i', 214 .val = 'i',
222 }, 215 },
223 { 216 {
224 .name = "delayed-interrupt",
225 .val = 'D',
226 },
227 {
228 .name = "no-delayed-interrupt",
229 .val = 'd',
230 },
231 {
232 } 217 }
233}; 218};
234 219
235static void help(void) 220static void help()
236{ 221{
237 fprintf(stderr, "Usage: virtio_test [--help]" 222 fprintf(stderr, "Usage: virtio_test [--help]"
238 " [--no-indirect]" 223 " [--no-indirect]"
239 " [--no-event-idx]" 224 " [--no-event-idx]"
240 " [--delayed-interrupt]"
241 "\n"); 225 "\n");
242} 226}
243 227
@@ -247,7 +231,6 @@ int main(int argc, char **argv)
247 unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | 231 unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
248 (1ULL << VIRTIO_RING_F_EVENT_IDX); 232 (1ULL << VIRTIO_RING_F_EVENT_IDX);
249 int o; 233 int o;
250 bool delayed = false;
251 234
252 for (;;) { 235 for (;;) {
253 o = getopt_long(argc, argv, optstring, longopts, NULL); 236 o = getopt_long(argc, argv, optstring, longopts, NULL);
@@ -266,9 +249,6 @@ int main(int argc, char **argv)
266 case 'i': 249 case 'i':
267 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC); 250 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
268 break; 251 break;
269 case 'D':
270 delayed = true;
271 break;
272 default: 252 default:
273 assert(0); 253 assert(0);
274 break; 254 break;
@@ -278,6 +258,6 @@ int main(int argc, char **argv)
278done: 258done:
279 vdev_info_init(&dev, features); 259 vdev_info_init(&dev, features);
280 vq_info_add(&dev, 256); 260 vq_info_add(&dev, 256);
281 run_test(&dev, &dev.vqs[0], delayed, 0x100000); 261 run_test(&dev, &dev.vqs[0], 0x100000);
282 return 0; 262 return 0;
283} 263}
diff --git a/tools/vm/Makefile b/tools/vm/Makefile
deleted file mode 100644
index 8e30e5c40f8..00000000000
--- a/tools/vm/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
1# Makefile for vm tools
2
3CC = $(CROSS_COMPILE)gcc
4CFLAGS = -Wall -Wextra
5
6all: page-types slabinfo
7%: %.c
8 $(CC) $(CFLAGS) -o $@ $^
9
10clean:
11 $(RM) page-types slabinfo
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
deleted file mode 100644
index b76edf2f833..00000000000
--- a/tools/vm/page-types.c
+++ /dev/null
@@ -1,1076 +0,0 @@
1/*
2 * page-types: Tool for querying page flags
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; version 2.
7 *
8 * This program is distributed in the hope that 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 * You should find a copy of v2 of the GNU General Public License somewhere on
14 * your Linux system; if not, write to the Free Software Foundation, Inc., 59
15 * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16 *
17 * Copyright (C) 2009 Intel corporation
18 *
19 * Authors: Wu Fengguang <fengguang.wu@intel.com>
20 */
21
22#define _LARGEFILE64_SOURCE
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <stdint.h>
27#include <stdarg.h>
28#include <string.h>
29#include <getopt.h>
30#include <limits.h>
31#include <assert.h>
32#include <sys/types.h>
33#include <sys/errno.h>
34#include <sys/fcntl.h>
35#include <sys/mount.h>
36#include <sys/statfs.h>
37#include "../../include/uapi/linux/magic.h"
38#include "../../include/uapi/linux/kernel-page-flags.h"
39
40
41#ifndef MAX_PATH
42# define MAX_PATH 256
43#endif
44
45#ifndef STR
46# define _STR(x) #x
47# define STR(x) _STR(x)
48#endif
49
50/*
51 * pagemap kernel ABI bits
52 */
53
54#define PM_ENTRY_BYTES sizeof(uint64_t)
55#define PM_STATUS_BITS 3
56#define PM_STATUS_OFFSET (64 - PM_STATUS_BITS)
57#define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)
58#define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK)
59#define PM_PSHIFT_BITS 6
60#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
61#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
62#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
63#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1)
64#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK)
65
66#define PM_PRESENT PM_STATUS(4LL)
67#define PM_SWAP PM_STATUS(2LL)
68
69
70/*
71 * kernel page flags
72 */
73
74#define KPF_BYTES 8
75#define PROC_KPAGEFLAGS "/proc/kpageflags"
76
77/* [32-] kernel hacking assistances */
78#define KPF_RESERVED 32
79#define KPF_MLOCKED 33
80#define KPF_MAPPEDTODISK 34
81#define KPF_PRIVATE 35
82#define KPF_PRIVATE_2 36
83#define KPF_OWNER_PRIVATE 37
84#define KPF_ARCH 38
85#define KPF_UNCACHED 39
86
87/* [48-] take some arbitrary free slots for expanding overloaded flags
88 * not part of kernel API
89 */
90#define KPF_READAHEAD 48
91#define KPF_SLOB_FREE 49
92#define KPF_SLUB_FROZEN 50
93#define KPF_SLUB_DEBUG 51
94
95#define KPF_ALL_BITS ((uint64_t)~0ULL)
96#define KPF_HACKERS_BITS (0xffffULL << 32)
97#define KPF_OVERLOADED_BITS (0xffffULL << 48)
98#define BIT(name) (1ULL << KPF_##name)
99#define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
100
101static const char * const page_flag_names[] = {
102 [KPF_LOCKED] = "L:locked",
103 [KPF_ERROR] = "E:error",
104 [KPF_REFERENCED] = "R:referenced",
105 [KPF_UPTODATE] = "U:uptodate",
106 [KPF_DIRTY] = "D:dirty",
107 [KPF_LRU] = "l:lru",
108 [KPF_ACTIVE] = "A:active",
109 [KPF_SLAB] = "S:slab",
110 [KPF_WRITEBACK] = "W:writeback",
111 [KPF_RECLAIM] = "I:reclaim",
112 [KPF_BUDDY] = "B:buddy",
113
114 [KPF_MMAP] = "M:mmap",
115 [KPF_ANON] = "a:anonymous",
116 [KPF_SWAPCACHE] = "s:swapcache",
117 [KPF_SWAPBACKED] = "b:swapbacked",
118 [KPF_COMPOUND_HEAD] = "H:compound_head",
119 [KPF_COMPOUND_TAIL] = "T:compound_tail",
120 [KPF_HUGE] = "G:huge",
121 [KPF_UNEVICTABLE] = "u:unevictable",
122 [KPF_HWPOISON] = "X:hwpoison",
123 [KPF_NOPAGE] = "n:nopage",
124 [KPF_KSM] = "x:ksm",
125 [KPF_THP] = "t:thp",
126
127 [KPF_RESERVED] = "r:reserved",
128 [KPF_MLOCKED] = "m:mlocked",
129 [KPF_MAPPEDTODISK] = "d:mappedtodisk",
130 [KPF_PRIVATE] = "P:private",
131 [KPF_PRIVATE_2] = "p:private_2",
132 [KPF_OWNER_PRIVATE] = "O:owner_private",
133 [KPF_ARCH] = "h:arch",
134 [KPF_UNCACHED] = "c:uncached",
135
136 [KPF_READAHEAD] = "I:readahead",
137 [KPF_SLOB_FREE] = "P:slob_free",
138 [KPF_SLUB_FROZEN] = "A:slub_frozen",
139 [KPF_SLUB_DEBUG] = "E:slub_debug",
140};
141
142
143static const char * const debugfs_known_mountpoints[] = {
144 "/sys/kernel/debug",
145 "/debug",
146 0,
147};
148
149/*
150 * data structures
151 */
152
153static int opt_raw; /* for kernel developers */
154static int opt_list; /* list pages (in ranges) */
155static int opt_no_summary; /* don't show summary */
156static pid_t opt_pid; /* process to walk */
157
158#define MAX_ADDR_RANGES 1024
159static int nr_addr_ranges;
160static unsigned long opt_offset[MAX_ADDR_RANGES];
161static unsigned long opt_size[MAX_ADDR_RANGES];
162
163#define MAX_VMAS 10240
164static int nr_vmas;
165static unsigned long pg_start[MAX_VMAS];
166static unsigned long pg_end[MAX_VMAS];
167
168#define MAX_BIT_FILTERS 64
169static int nr_bit_filters;
170static uint64_t opt_mask[MAX_BIT_FILTERS];
171static uint64_t opt_bits[MAX_BIT_FILTERS];
172
173static int page_size;
174
175static int pagemap_fd;
176static int kpageflags_fd;
177
178static int opt_hwpoison;
179static int opt_unpoison;
180
181static char hwpoison_debug_fs[MAX_PATH+1];
182static int hwpoison_inject_fd;
183static int hwpoison_forget_fd;
184
185#define HASH_SHIFT 13
186#define HASH_SIZE (1 << HASH_SHIFT)
187#define HASH_MASK (HASH_SIZE - 1)
188#define HASH_KEY(flags) (flags & HASH_MASK)
189
190static unsigned long total_pages;
191static unsigned long nr_pages[HASH_SIZE];
192static uint64_t page_flags[HASH_SIZE];
193
194
195/*
196 * helper functions
197 */
198
199#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
200
201#define min_t(type, x, y) ({ \
202 type __min1 = (x); \
203 type __min2 = (y); \
204 __min1 < __min2 ? __min1 : __min2; })
205
206#define max_t(type, x, y) ({ \
207 type __max1 = (x); \
208 type __max2 = (y); \
209 __max1 > __max2 ? __max1 : __max2; })
210
211static unsigned long pages2mb(unsigned long pages)
212{
213 return (pages * page_size) >> 20;
214}
215
216static void fatal(const char *x, ...)
217{
218 va_list ap;
219
220 va_start(ap, x);
221 vfprintf(stderr, x, ap);
222 va_end(ap);
223 exit(EXIT_FAILURE);
224}
225
226static int checked_open(const char *pathname, int flags)
227{
228 int fd = open(pathname, flags);
229
230 if (fd < 0) {
231 perror(pathname);
232 exit(EXIT_FAILURE);
233 }
234
235 return fd;
236}
237
238/*
239 * pagemap/kpageflags routines
240 */
241
242static unsigned long do_u64_read(int fd, char *name,
243 uint64_t *buf,
244 unsigned long index,
245 unsigned long count)
246{
247 long bytes;
248
249 if (index > ULONG_MAX / 8)
250 fatal("index overflow: %lu\n", index);
251
252 if (lseek(fd, index * 8, SEEK_SET) < 0) {
253 perror(name);
254 exit(EXIT_FAILURE);
255 }
256
257 bytes = read(fd, buf, count * 8);
258 if (bytes < 0) {
259 perror(name);
260 exit(EXIT_FAILURE);
261 }
262 if (bytes % 8)
263 fatal("partial read: %lu bytes\n", bytes);
264
265 return bytes / 8;
266}
267
268static unsigned long kpageflags_read(uint64_t *buf,
269 unsigned long index,
270 unsigned long pages)
271{
272 return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
273}
274
275static unsigned long pagemap_read(uint64_t *buf,
276 unsigned long index,
277 unsigned long pages)
278{
279 return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);
280}
281
282static unsigned long pagemap_pfn(uint64_t val)
283{
284 unsigned long pfn;
285
286 if (val & PM_PRESENT)
287 pfn = PM_PFRAME(val);
288 else
289 pfn = 0;
290
291 return pfn;
292}
293
294
295/*
296 * page flag names
297 */
298
299static char *page_flag_name(uint64_t flags)
300{
301 static char buf[65];
302 int present;
303 size_t i, j;
304
305 for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
306 present = (flags >> i) & 1;
307 if (!page_flag_names[i]) {
308 if (present)
309 fatal("unknown flag bit %d\n", i);
310 continue;
311 }
312 buf[j++] = present ? page_flag_names[i][0] : '_';
313 }
314
315 return buf;
316}
317
318static char *page_flag_longname(uint64_t flags)
319{
320 static char buf[1024];
321 size_t i, n;
322
323 for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
324 if (!page_flag_names[i])
325 continue;
326 if ((flags >> i) & 1)
327 n += snprintf(buf + n, sizeof(buf) - n, "%s,",
328 page_flag_names[i] + 2);
329 }
330 if (n)
331 n--;
332 buf[n] = '\0';
333
334 return buf;
335}
336
337
338/*
339 * page list and summary
340 */
341
342static void show_page_range(unsigned long voffset,
343 unsigned long offset, uint64_t flags)
344{
345 static uint64_t flags0;
346 static unsigned long voff;
347 static unsigned long index;
348 static unsigned long count;
349
350 if (flags == flags0 && offset == index + count &&
351 (!opt_pid || voffset == voff + count)) {
352 count++;
353 return;
354 }
355
356 if (count) {
357 if (opt_pid)
358 printf("%lx\t", voff);
359 printf("%lx\t%lx\t%s\n",
360 index, count, page_flag_name(flags0));
361 }
362
363 flags0 = flags;
364 index = offset;
365 voff = voffset;
366 count = 1;
367}
368
369static void show_page(unsigned long voffset,
370 unsigned long offset, uint64_t flags)
371{
372 if (opt_pid)
373 printf("%lx\t", voffset);
374 printf("%lx\t%s\n", offset, page_flag_name(flags));
375}
376
377static void show_summary(void)
378{
379 size_t i;
380
381 printf(" flags\tpage-count MB"
382 " symbolic-flags\t\t\tlong-symbolic-flags\n");
383
384 for (i = 0; i < ARRAY_SIZE(nr_pages); i++) {
385 if (nr_pages[i])
386 printf("0x%016llx\t%10lu %8lu %s\t%s\n",
387 (unsigned long long)page_flags[i],
388 nr_pages[i],
389 pages2mb(nr_pages[i]),
390 page_flag_name(page_flags[i]),
391 page_flag_longname(page_flags[i]));
392 }
393
394 printf(" total\t%10lu %8lu\n",
395 total_pages, pages2mb(total_pages));
396}
397
398
399/*
400 * page flag filters
401 */
402
403static int bit_mask_ok(uint64_t flags)
404{
405 int i;
406
407 for (i = 0; i < nr_bit_filters; i++) {
408 if (opt_bits[i] == KPF_ALL_BITS) {
409 if ((flags & opt_mask[i]) == 0)
410 return 0;
411 } else {
412 if ((flags & opt_mask[i]) != opt_bits[i])
413 return 0;
414 }
415 }
416
417 return 1;
418}
419
420static uint64_t expand_overloaded_flags(uint64_t flags)
421{
422 /* SLOB/SLUB overload several page flags */
423 if (flags & BIT(SLAB)) {
424 if (flags & BIT(PRIVATE))
425 flags ^= BIT(PRIVATE) | BIT(SLOB_FREE);
426 if (flags & BIT(ACTIVE))
427 flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN);
428 if (flags & BIT(ERROR))
429 flags ^= BIT(ERROR) | BIT(SLUB_DEBUG);
430 }
431
432 /* PG_reclaim is overloaded as PG_readahead in the read path */
433 if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM))
434 flags ^= BIT(RECLAIM) | BIT(READAHEAD);
435
436 return flags;
437}
438
439static uint64_t well_known_flags(uint64_t flags)
440{
441 /* hide flags intended only for kernel hacker */
442 flags &= ~KPF_HACKERS_BITS;
443
444 /* hide non-hugeTLB compound pages */
445 if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE)))
446 flags &= ~BITS_COMPOUND;
447
448 return flags;
449}
450
451static uint64_t kpageflags_flags(uint64_t flags)
452{
453 flags = expand_overloaded_flags(flags);
454
455 if (!opt_raw)
456 flags = well_known_flags(flags);
457
458 return flags;
459}
460
461/* verify that a mountpoint is actually a debugfs instance */
462static int debugfs_valid_mountpoint(const char *debugfs)
463{
464 struct statfs st_fs;
465
466 if (statfs(debugfs, &st_fs) < 0)
467 return -ENOENT;
468 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
469 return -ENOENT;
470
471 return 0;
472}
473
474/* find the path to the mounted debugfs */
475static const char *debugfs_find_mountpoint(void)
476{
477 const char *const *ptr;
478 char type[100];
479 FILE *fp;
480
481 ptr = debugfs_known_mountpoints;
482 while (*ptr) {
483 if (debugfs_valid_mountpoint(*ptr) == 0) {
484 strcpy(hwpoison_debug_fs, *ptr);
485 return hwpoison_debug_fs;
486 }
487 ptr++;
488 }
489
490 /* give up and parse /proc/mounts */
491 fp = fopen("/proc/mounts", "r");
492 if (fp == NULL)
493 perror("Can't open /proc/mounts for read");
494
495 while (fscanf(fp, "%*s %"
496 STR(MAX_PATH)
497 "s %99s %*s %*d %*d\n",
498 hwpoison_debug_fs, type) == 2) {
499 if (strcmp(type, "debugfs") == 0)
500 break;
501 }
502 fclose(fp);
503
504 if (strcmp(type, "debugfs") != 0)
505 return NULL;
506
507 return hwpoison_debug_fs;
508}
509
510/* mount the debugfs somewhere if it's not mounted */
511
512static void debugfs_mount(void)
513{
514 const char *const *ptr;
515
516 /* see if it's already mounted */
517 if (debugfs_find_mountpoint())
518 return;
519
520 ptr = debugfs_known_mountpoints;
521 while (*ptr) {
522 if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
523 /* save the mountpoint */
524 strcpy(hwpoison_debug_fs, *ptr);
525 break;
526 }
527 ptr++;
528 }
529
530 if (*ptr == NULL) {
531 perror("mount debugfs");
532 exit(EXIT_FAILURE);
533 }
534}
535
536/*
537 * page actions
538 */
539
540static void prepare_hwpoison_fd(void)
541{
542 char buf[MAX_PATH + 1];
543
544 debugfs_mount();
545
546 if (opt_hwpoison && !hwpoison_inject_fd) {
547 snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
548 hwpoison_debug_fs);
549 hwpoison_inject_fd = checked_open(buf, O_WRONLY);
550 }
551
552 if (opt_unpoison && !hwpoison_forget_fd) {
553 snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn",
554 hwpoison_debug_fs);
555 hwpoison_forget_fd = checked_open(buf, O_WRONLY);
556 }
557}
558
559static int hwpoison_page(unsigned long offset)
560{
561 char buf[100];
562 int len;
563
564 len = sprintf(buf, "0x%lx\n", offset);
565 len = write(hwpoison_inject_fd, buf, len);
566 if (len < 0) {
567 perror("hwpoison inject");
568 return len;
569 }
570 return 0;
571}
572
573static int unpoison_page(unsigned long offset)
574{
575 char buf[100];
576 int len;
577
578 len = sprintf(buf, "0x%lx\n", offset);
579 len = write(hwpoison_forget_fd, buf, len);
580 if (len < 0) {
581 perror("hwpoison forget");
582 return len;
583 }
584 return 0;
585}
586
587/*
588 * page frame walker
589 */
590
591static size_t hash_slot(uint64_t flags)
592{
593 size_t k = HASH_KEY(flags);
594 size_t i;
595
596 /* Explicitly reserve slot 0 for flags 0: the following logic
597 * cannot distinguish an unoccupied slot from slot (flags==0).
598 */
599 if (flags == 0)
600 return 0;
601
602 /* search through the remaining (HASH_SIZE-1) slots */
603 for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
604 if (!k || k >= ARRAY_SIZE(page_flags))
605 k = 1;
606 if (page_flags[k] == 0) {
607 page_flags[k] = flags;
608 return k;
609 }
610 if (page_flags[k] == flags)
611 return k;
612 }
613
614 fatal("hash table full: bump up HASH_SHIFT?\n");
615 exit(EXIT_FAILURE);
616}
617
618static void add_page(unsigned long voffset,
619 unsigned long offset, uint64_t flags)
620{
621 flags = kpageflags_flags(flags);
622
623 if (!bit_mask_ok(flags))
624 return;
625
626 if (opt_hwpoison)
627 hwpoison_page(offset);
628 if (opt_unpoison)
629 unpoison_page(offset);
630
631 if (opt_list == 1)
632 show_page_range(voffset, offset, flags);
633 else if (opt_list == 2)
634 show_page(voffset, offset, flags);
635
636 nr_pages[hash_slot(flags)]++;
637 total_pages++;
638}
639
640#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */
641static void walk_pfn(unsigned long voffset,
642 unsigned long index,
643 unsigned long count)
644{
645 uint64_t buf[KPAGEFLAGS_BATCH];
646 unsigned long batch;
647 unsigned long pages;
648 unsigned long i;
649
650 while (count) {
651 batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
652 pages = kpageflags_read(buf, index, batch);
653 if (pages == 0)
654 break;
655
656 for (i = 0; i < pages; i++)
657 add_page(voffset + i, index + i, buf[i]);
658
659 index += pages;
660 count -= pages;
661 }
662}
663
664#define PAGEMAP_BATCH (64 << 10)
665static void walk_vma(unsigned long index, unsigned long count)
666{
667 uint64_t buf[PAGEMAP_BATCH];
668 unsigned long batch;
669 unsigned long pages;
670 unsigned long pfn;
671 unsigned long i;
672
673 while (count) {
674 batch = min_t(unsigned long, count, PAGEMAP_BATCH);
675 pages = pagemap_read(buf, index, batch);
676 if (pages == 0)
677 break;
678
679 for (i = 0; i < pages; i++) {
680 pfn = pagemap_pfn(buf[i]);
681 if (pfn)
682 walk_pfn(index + i, pfn, 1);
683 }
684
685 index += pages;
686 count -= pages;
687 }
688}
689
690static void walk_task(unsigned long index, unsigned long count)
691{
692 const unsigned long end = index + count;
693 unsigned long start;
694 int i = 0;
695
696 while (index < end) {
697
698 while (pg_end[i] <= index)
699 if (++i >= nr_vmas)
700 return;
701 if (pg_start[i] >= end)
702 return;
703
704 start = max_t(unsigned long, pg_start[i], index);
705 index = min_t(unsigned long, pg_end[i], end);
706
707 assert(start < index);
708 walk_vma(start, index - start);
709 }
710}
711
712static void add_addr_range(unsigned long offset, unsigned long size)
713{
714 if (nr_addr_ranges >= MAX_ADDR_RANGES)
715 fatal("too many addr ranges\n");
716
717 opt_offset[nr_addr_ranges] = offset;
718 opt_size[nr_addr_ranges] = min_t(unsigned long, size, ULONG_MAX-offset);
719 nr_addr_ranges++;
720}
721
722static void walk_addr_ranges(void)
723{
724 int i;
725
726 kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
727
728 if (!nr_addr_ranges)
729 add_addr_range(0, ULONG_MAX);
730
731 for (i = 0; i < nr_addr_ranges; i++)
732 if (!opt_pid)
733 walk_pfn(0, opt_offset[i], opt_size[i]);
734 else
735 walk_task(opt_offset[i], opt_size[i]);
736
737 close(kpageflags_fd);
738}
739
740
741/*
742 * user interface
743 */
744
745static const char *page_flag_type(uint64_t flag)
746{
747 if (flag & KPF_HACKERS_BITS)
748 return "(r)";
749 if (flag & KPF_OVERLOADED_BITS)
750 return "(o)";
751 return " ";
752}
753
754static void usage(void)
755{
756 size_t i, j;
757
758 printf(
759"page-types [options]\n"
760" -r|--raw Raw mode, for kernel developers\n"
761" -d|--describe flags Describe flags\n"
762" -a|--addr addr-spec Walk a range of pages\n"
763" -b|--bits bits-spec Walk pages with specified bits\n"
764" -p|--pid pid Walk process address space\n"
765#if 0 /* planned features */
766" -f|--file filename Walk file address space\n"
767#endif
768" -l|--list Show page details in ranges\n"
769" -L|--list-each Show page details one by one\n"
770" -N|--no-summary Don't show summary info\n"
771" -X|--hwpoison hwpoison pages\n"
772" -x|--unpoison unpoison pages\n"
773" -h|--help Show this usage message\n"
774"flags:\n"
775" 0x10 bitfield format, e.g.\n"
776" anon bit-name, e.g.\n"
777" 0x10,anon comma-separated list, e.g.\n"
778"addr-spec:\n"
779" N one page at offset N (unit: pages)\n"
780" N+M pages range from N to N+M-1\n"
781" N,M pages range from N to M-1\n"
782" N, pages range from N to end\n"
783" ,M pages range from 0 to M-1\n"
784"bits-spec:\n"
785" bit1,bit2 (flags & (bit1|bit2)) != 0\n"
786" bit1,bit2=bit1 (flags & (bit1|bit2)) == bit1\n"
787" bit1,~bit2 (flags & (bit1|bit2)) == bit1\n"
788" =bit1,bit2 flags == (bit1|bit2)\n"
789"bit-names:\n"
790 );
791
792 for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
793 if (!page_flag_names[i])
794 continue;
795 printf("%16s%s", page_flag_names[i] + 2,
796 page_flag_type(1ULL << i));
797 if (++j > 3) {
798 j = 0;
799 putchar('\n');
800 }
801 }
802 printf("\n "
803 "(r) raw mode bits (o) overloaded bits\n");
804}
805
806static unsigned long long parse_number(const char *str)
807{
808 unsigned long long n;
809
810 n = strtoll(str, NULL, 0);
811
812 if (n == 0 && str[0] != '0')
813 fatal("invalid name or number: %s\n", str);
814
815 return n;
816}
817
818static void parse_pid(const char *str)
819{
820 FILE *file;
821 char buf[5000];
822
823 opt_pid = parse_number(str);
824
825 sprintf(buf, "/proc/%d/pagemap", opt_pid);
826 pagemap_fd = checked_open(buf, O_RDONLY);
827
828 sprintf(buf, "/proc/%d/maps", opt_pid);
829 file = fopen(buf, "r");
830 if (!file) {
831 perror(buf);
832 exit(EXIT_FAILURE);
833 }
834
835 while (fgets(buf, sizeof(buf), file) != NULL) {
836 unsigned long vm_start;
837 unsigned long vm_end;
838 unsigned long long pgoff;
839 int major, minor;
840 char r, w, x, s;
841 unsigned long ino;
842 int n;
843
844 n = sscanf(buf, "%lx-%lx %c%c%c%c %llx %x:%x %lu",
845 &vm_start,
846 &vm_end,
847 &r, &w, &x, &s,
848 &pgoff,
849 &major, &minor,
850 &ino);
851 if (n < 10) {
852 fprintf(stderr, "unexpected line: %s\n", buf);
853 continue;
854 }
855 pg_start[nr_vmas] = vm_start / page_size;
856 pg_end[nr_vmas] = vm_end / page_size;
857 if (++nr_vmas >= MAX_VMAS) {
858 fprintf(stderr, "too many VMAs\n");
859 break;
860 }
861 }
862 fclose(file);
863}
864
865static void parse_file(const char *name)
866{
867}
868
869static void parse_addr_range(const char *optarg)
870{
871 unsigned long offset;
872 unsigned long size;
873 char *p;
874
875 p = strchr(optarg, ',');
876 if (!p)
877 p = strchr(optarg, '+');
878
879 if (p == optarg) {
880 offset = 0;
881 size = parse_number(p + 1);
882 } else if (p) {
883 offset = parse_number(optarg);
884 if (p[1] == '\0')
885 size = ULONG_MAX;
886 else {
887 size = parse_number(p + 1);
888 if (*p == ',') {
889 if (size < offset)
890 fatal("invalid range: %lu,%lu\n",
891 offset, size);
892 size -= offset;
893 }
894 }
895 } else {
896 offset = parse_number(optarg);
897 size = 1;
898 }
899
900 add_addr_range(offset, size);
901}
902
903static void add_bits_filter(uint64_t mask, uint64_t bits)
904{
905 if (nr_bit_filters >= MAX_BIT_FILTERS)
906 fatal("too much bit filters\n");
907
908 opt_mask[nr_bit_filters] = mask;
909 opt_bits[nr_bit_filters] = bits;
910 nr_bit_filters++;
911}
912
913static uint64_t parse_flag_name(const char *str, int len)
914{
915 size_t i;
916
917 if (!*str || !len)
918 return 0;
919
920 if (len <= 8 && !strncmp(str, "compound", len))
921 return BITS_COMPOUND;
922
923 for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
924 if (!page_flag_names[i])
925 continue;
926 if (!strncmp(str, page_flag_names[i] + 2, len))
927 return 1ULL << i;
928 }
929
930 return parse_number(str);
931}
932
933static uint64_t parse_flag_names(const char *str, int all)
934{
935 const char *p = str;
936 uint64_t flags = 0;
937
938 while (1) {
939 if (*p == ',' || *p == '=' || *p == '\0') {
940 if ((*str != '~') || (*str == '~' && all && *++str))
941 flags |= parse_flag_name(str, p - str);
942 if (*p != ',')
943 break;
944 str = p + 1;
945 }
946 p++;
947 }
948
949 return flags;
950}
951
952static void parse_bits_mask(const char *optarg)
953{
954 uint64_t mask;
955 uint64_t bits;
956 const char *p;
957
958 p = strchr(optarg, '=');
959 if (p == optarg) {
960 mask = KPF_ALL_BITS;
961 bits = parse_flag_names(p + 1, 0);
962 } else if (p) {
963 mask = parse_flag_names(optarg, 0);
964 bits = parse_flag_names(p + 1, 0);
965 } else if (strchr(optarg, '~')) {
966 mask = parse_flag_names(optarg, 1);
967 bits = parse_flag_names(optarg, 0);
968 } else {
969 mask = parse_flag_names(optarg, 0);
970 bits = KPF_ALL_BITS;
971 }
972
973 add_bits_filter(mask, bits);
974}
975
976static void describe_flags(const char *optarg)
977{
978 uint64_t flags = parse_flag_names(optarg, 0);
979
980 printf("0x%016llx\t%s\t%s\n",
981 (unsigned long long)flags,
982 page_flag_name(flags),
983 page_flag_longname(flags));
984}
985
986static const struct option opts[] = {
987 { "raw" , 0, NULL, 'r' },
988 { "pid" , 1, NULL, 'p' },
989 { "file" , 1, NULL, 'f' },
990 { "addr" , 1, NULL, 'a' },
991 { "bits" , 1, NULL, 'b' },
992 { "describe" , 1, NULL, 'd' },
993 { "list" , 0, NULL, 'l' },
994 { "list-each" , 0, NULL, 'L' },
995 { "no-summary", 0, NULL, 'N' },
996 { "hwpoison" , 0, NULL, 'X' },
997 { "unpoison" , 0, NULL, 'x' },
998 { "help" , 0, NULL, 'h' },
999 { NULL , 0, NULL, 0 }
1000};
1001
1002int main(int argc, char *argv[])
1003{
1004 int c;
1005
1006 page_size = getpagesize();
1007
1008 while ((c = getopt_long(argc, argv,
1009 "rp:f:a:b:d:lLNXxh", opts, NULL)) != -1) {
1010 switch (c) {
1011 case 'r':
1012 opt_raw = 1;
1013 break;
1014 case 'p':
1015 parse_pid(optarg);
1016 break;
1017 case 'f':
1018 parse_file(optarg);
1019 break;
1020 case 'a':
1021 parse_addr_range(optarg);
1022 break;
1023 case 'b':
1024 parse_bits_mask(optarg);
1025 break;
1026 case 'd':
1027 describe_flags(optarg);
1028 exit(0);
1029 case 'l':
1030 opt_list = 1;
1031 break;
1032 case 'L':
1033 opt_list = 2;
1034 break;
1035 case 'N':
1036 opt_no_summary = 1;
1037 break;
1038 case 'X':
1039 opt_hwpoison = 1;
1040 prepare_hwpoison_fd();
1041 break;
1042 case 'x':
1043 opt_unpoison = 1;
1044 prepare_hwpoison_fd();
1045 break;
1046 case 'h':
1047 usage();
1048 exit(0);
1049 default:
1050 usage();
1051 exit(1);
1052 }
1053 }
1054
1055 if (opt_list && opt_pid)
1056 printf("voffset\t");
1057 if (opt_list == 1)
1058 printf("offset\tlen\tflags\n");
1059 if (opt_list == 2)
1060 printf("offset\tflags\n");
1061
1062 walk_addr_ranges();
1063
1064 if (opt_list == 1)
1065 show_page_range(0, 0, 0); /* drain the buffer */
1066
1067 if (opt_no_summary)
1068 return 0;
1069
1070 if (opt_list)
1071 printf("\n\n");
1072
1073 show_summary();
1074
1075 return 0;
1076}
diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c
deleted file mode 100644
index 808d5a9d5dc..00000000000
--- a/tools/vm/slabinfo.c
+++ /dev/null
@@ -1,1393 +0,0 @@
1/*
2 * Slabinfo: Tool to get reports about slabs
3 *
4 * (C) 2007 sgi, Christoph Lameter
5 * (C) 2011 Linux Foundation, Christoph Lameter
6 *
7 * Compile with:
8 *
9 * gcc -o slabinfo slabinfo.c
10 */
11#include <stdio.h>
12#include <stdlib.h>
13#include <sys/types.h>
14#include <dirent.h>
15#include <strings.h>
16#include <string.h>
17#include <unistd.h>
18#include <stdarg.h>
19#include <getopt.h>
20#include <regex.h>
21#include <errno.h>
22
23#define MAX_SLABS 500
24#define MAX_ALIASES 500
25#define MAX_NODES 1024
26
27struct slabinfo {
28 char *name;
29 int alias;
30 int refs;
31 int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
32 int hwcache_align, object_size, objs_per_slab;
33 int sanity_checks, slab_size, store_user, trace;
34 int order, poison, reclaim_account, red_zone;
35 unsigned long partial, objects, slabs, objects_partial, objects_total;
36 unsigned long alloc_fastpath, alloc_slowpath;
37 unsigned long free_fastpath, free_slowpath;
38 unsigned long free_frozen, free_add_partial, free_remove_partial;
39 unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
40 unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
41 unsigned long deactivate_to_head, deactivate_to_tail;
42 unsigned long deactivate_remote_frees, order_fallback;
43 unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
44 unsigned long alloc_node_mismatch, deactivate_bypass;
45 unsigned long cpu_partial_alloc, cpu_partial_free;
46 int numa[MAX_NODES];
47 int numa_partial[MAX_NODES];
48} slabinfo[MAX_SLABS];
49
50struct aliasinfo {
51 char *name;
52 char *ref;
53 struct slabinfo *slab;
54} aliasinfo[MAX_ALIASES];
55
56int slabs = 0;
57int actual_slabs = 0;
58int aliases = 0;
59int alias_targets = 0;
60int highest_node = 0;
61
62char buffer[4096];
63
64int show_empty = 0;
65int show_report = 0;
66int show_alias = 0;
67int show_slab = 0;
68int skip_zero = 1;
69int show_numa = 0;
70int show_track = 0;
71int show_first_alias = 0;
72int validate = 0;
73int shrink = 0;
74int show_inverted = 0;
75int show_single_ref = 0;
76int show_totals = 0;
77int sort_size = 0;
78int sort_active = 0;
79int set_debug = 0;
80int show_ops = 0;
81int show_activity = 0;
82
83/* Debug options */
84int sanity = 0;
85int redzone = 0;
86int poison = 0;
87int tracking = 0;
88int tracing = 0;
89
90int page_size;
91
92regex_t pattern;
93
94static void fatal(const char *x, ...)
95{
96 va_list ap;
97
98 va_start(ap, x);
99 vfprintf(stderr, x, ap);
100 va_end(ap);
101 exit(EXIT_FAILURE);
102}
103
104static void usage(void)
105{
106 printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n"
107 "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
108 "-a|--aliases Show aliases\n"
109 "-A|--activity Most active slabs first\n"
110 "-d<options>|--debug=<options> Set/Clear Debug options\n"
111 "-D|--display-active Switch line format to activity\n"
112 "-e|--empty Show empty slabs\n"
113 "-f|--first-alias Show first alias\n"
114 "-h|--help Show usage information\n"
115 "-i|--inverted Inverted list\n"
116 "-l|--slabs Show slabs\n"
117 "-n|--numa Show NUMA information\n"
118 "-o|--ops Show kmem_cache_ops\n"
119 "-s|--shrink Shrink slabs\n"
120 "-r|--report Detailed report on single slabs\n"
121 "-S|--Size Sort by size\n"
122 "-t|--tracking Show alloc/free information\n"
123 "-T|--Totals Show summary information\n"
124 "-v|--validate Validate slabs\n"
125 "-z|--zero Include empty slabs\n"
126 "-1|--1ref Single reference\n"
127 "\nValid debug options (FZPUT may be combined)\n"
128 "a / A Switch on all debug options (=FZUP)\n"
129 "- Switch off all debug options\n"
130 "f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
131 "z / Z Redzoning\n"
132 "p / P Poisoning\n"
133 "u / U Tracking\n"
134 "t / T Tracing\n"
135 );
136}
137
138static unsigned long read_obj(const char *name)
139{
140 FILE *f = fopen(name, "r");
141
142 if (!f)
143 buffer[0] = 0;
144 else {
145 if (!fgets(buffer, sizeof(buffer), f))
146 buffer[0] = 0;
147 fclose(f);
148 if (buffer[strlen(buffer)] == '\n')
149 buffer[strlen(buffer)] = 0;
150 }
151 return strlen(buffer);
152}
153
154
155/*
156 * Get the contents of an attribute
157 */
158static unsigned long get_obj(const char *name)
159{
160 if (!read_obj(name))
161 return 0;
162
163 return atol(buffer);
164}
165
166static unsigned long get_obj_and_str(const char *name, char **x)
167{
168 unsigned long result = 0;
169 char *p;
170
171 *x = NULL;
172
173 if (!read_obj(name)) {
174 x = NULL;
175 return 0;
176 }
177 result = strtoul(buffer, &p, 10);
178 while (*p == ' ')
179 p++;
180 if (*p)
181 *x = strdup(p);
182 return result;
183}
184
185static void set_obj(struct slabinfo *s, const char *name, int n)
186{
187 char x[100];
188 FILE *f;
189
190 snprintf(x, 100, "%s/%s", s->name, name);
191 f = fopen(x, "w");
192 if (!f)
193 fatal("Cannot write to %s\n", x);
194
195 fprintf(f, "%d\n", n);
196 fclose(f);
197}
198
199static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
200{
201 char x[100];
202 FILE *f;
203 size_t l;
204
205 snprintf(x, 100, "%s/%s", s->name, name);
206 f = fopen(x, "r");
207 if (!f) {
208 buffer[0] = 0;
209 l = 0;
210 } else {
211 l = fread(buffer, 1, sizeof(buffer), f);
212 buffer[l] = 0;
213 fclose(f);
214 }
215 return l;
216}
217
218
219/*
220 * Put a size string together
221 */
222static int store_size(char *buffer, unsigned long value)
223{
224 unsigned long divisor = 1;
225 char trailer = 0;
226 int n;
227
228 if (value > 1000000000UL) {
229 divisor = 100000000UL;
230 trailer = 'G';
231 } else if (value > 1000000UL) {
232 divisor = 100000UL;
233 trailer = 'M';
234 } else if (value > 1000UL) {
235 divisor = 100;
236 trailer = 'K';
237 }
238
239 value /= divisor;
240 n = sprintf(buffer, "%ld",value);
241 if (trailer) {
242 buffer[n] = trailer;
243 n++;
244 buffer[n] = 0;
245 }
246 if (divisor != 1) {
247 memmove(buffer + n - 2, buffer + n - 3, 4);
248 buffer[n-2] = '.';
249 n++;
250 }
251 return n;
252}
253
254static void decode_numa_list(int *numa, char *t)
255{
256 int node;
257 int nr;
258
259 memset(numa, 0, MAX_NODES * sizeof(int));
260
261 if (!t)
262 return;
263
264 while (*t == 'N') {
265 t++;
266 node = strtoul(t, &t, 10);
267 if (*t == '=') {
268 t++;
269 nr = strtoul(t, &t, 10);
270 numa[node] = nr;
271 if (node > highest_node)
272 highest_node = node;
273 }
274 while (*t == ' ')
275 t++;
276 }
277}
278
279static void slab_validate(struct slabinfo *s)
280{
281 if (strcmp(s->name, "*") == 0)
282 return;
283
284 set_obj(s, "validate", 1);
285}
286
287static void slab_shrink(struct slabinfo *s)
288{
289 if (strcmp(s->name, "*") == 0)
290 return;
291
292 set_obj(s, "shrink", 1);
293}
294
295int line = 0;
296
297static void first_line(void)
298{
299 if (show_activity)
300 printf("Name Objects Alloc Free %%Fast Fallb O CmpX UL\n");
301 else
302 printf("Name Objects Objsize Space "
303 "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
304}
305
306/*
307 * Find the shortest alias of a slab
308 */
309static struct aliasinfo *find_one_alias(struct slabinfo *find)
310{
311 struct aliasinfo *a;
312 struct aliasinfo *best = NULL;
313
314 for(a = aliasinfo;a < aliasinfo + aliases; a++) {
315 if (a->slab == find &&
316 (!best || strlen(best->name) < strlen(a->name))) {
317 best = a;
318 if (strncmp(a->name,"kmall", 5) == 0)
319 return best;
320 }
321 }
322 return best;
323}
324
325static unsigned long slab_size(struct slabinfo *s)
326{
327 return s->slabs * (page_size << s->order);
328}
329
330static unsigned long slab_activity(struct slabinfo *s)
331{
332 return s->alloc_fastpath + s->free_fastpath +
333 s->alloc_slowpath + s->free_slowpath;
334}
335
336static void slab_numa(struct slabinfo *s, int mode)
337{
338 int node;
339
340 if (strcmp(s->name, "*") == 0)
341 return;
342
343 if (!highest_node) {
344 printf("\n%s: No NUMA information available.\n", s->name);
345 return;
346 }
347
348 if (skip_zero && !s->slabs)
349 return;
350
351 if (!line) {
352 printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
353 for(node = 0; node <= highest_node; node++)
354 printf(" %4d", node);
355 printf("\n----------------------");
356 for(node = 0; node <= highest_node; node++)
357 printf("-----");
358 printf("\n");
359 }
360 printf("%-21s ", mode ? "All slabs" : s->name);
361 for(node = 0; node <= highest_node; node++) {
362 char b[20];
363
364 store_size(b, s->numa[node]);
365 printf(" %4s", b);
366 }
367 printf("\n");
368 if (mode) {
369 printf("%-21s ", "Partial slabs");
370 for(node = 0; node <= highest_node; node++) {
371 char b[20];
372
373 store_size(b, s->numa_partial[node]);
374 printf(" %4s", b);
375 }
376 printf("\n");
377 }
378 line++;
379}
380
381static void show_tracking(struct slabinfo *s)
382{
383 printf("\n%s: Kernel object allocation\n", s->name);
384 printf("-----------------------------------------------------------------------\n");
385 if (read_slab_obj(s, "alloc_calls"))
386 printf("%s", buffer);
387 else
388 printf("No Data\n");
389
390 printf("\n%s: Kernel object freeing\n", s->name);
391 printf("------------------------------------------------------------------------\n");
392 if (read_slab_obj(s, "free_calls"))
393 printf("%s", buffer);
394 else
395 printf("No Data\n");
396
397}
398
399static void ops(struct slabinfo *s)
400{
401 if (strcmp(s->name, "*") == 0)
402 return;
403
404 if (read_slab_obj(s, "ops")) {
405 printf("\n%s: kmem_cache operations\n", s->name);
406 printf("--------------------------------------------\n");
407 printf("%s", buffer);
408 } else
409 printf("\n%s has no kmem_cache operations\n", s->name);
410}
411
412static const char *onoff(int x)
413{
414 if (x)
415 return "On ";
416 return "Off";
417}
418
419static void slab_stats(struct slabinfo *s)
420{
421 unsigned long total_alloc;
422 unsigned long total_free;
423 unsigned long total;
424
425 if (!s->alloc_slab)
426 return;
427
428 total_alloc = s->alloc_fastpath + s->alloc_slowpath;
429 total_free = s->free_fastpath + s->free_slowpath;
430
431 if (!total_alloc)
432 return;
433
434 printf("\n");
435 printf("Slab Perf Counter Alloc Free %%Al %%Fr\n");
436 printf("--------------------------------------------------\n");
437 printf("Fastpath %8lu %8lu %3lu %3lu\n",
438 s->alloc_fastpath, s->free_fastpath,
439 s->alloc_fastpath * 100 / total_alloc,
440 total_free ? s->free_fastpath * 100 / total_free : 0);
441 printf("Slowpath %8lu %8lu %3lu %3lu\n",
442 total_alloc - s->alloc_fastpath, s->free_slowpath,
443 (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
444 total_free ? s->free_slowpath * 100 / total_free : 0);
445 printf("Page Alloc %8lu %8lu %3lu %3lu\n",
446 s->alloc_slab, s->free_slab,
447 s->alloc_slab * 100 / total_alloc,
448 total_free ? s->free_slab * 100 / total_free : 0);
449 printf("Add partial %8lu %8lu %3lu %3lu\n",
450 s->deactivate_to_head + s->deactivate_to_tail,
451 s->free_add_partial,
452 (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
453 total_free ? s->free_add_partial * 100 / total_free : 0);
454 printf("Remove partial %8lu %8lu %3lu %3lu\n",
455 s->alloc_from_partial, s->free_remove_partial,
456 s->alloc_from_partial * 100 / total_alloc,
457 total_free ? s->free_remove_partial * 100 / total_free : 0);
458
459 printf("Cpu partial list %8lu %8lu %3lu %3lu\n",
460 s->cpu_partial_alloc, s->cpu_partial_free,
461 s->cpu_partial_alloc * 100 / total_alloc,
462 total_free ? s->cpu_partial_free * 100 / total_free : 0);
463
464 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
465 s->deactivate_remote_frees, s->free_frozen,
466 s->deactivate_remote_frees * 100 / total_alloc,
467 total_free ? s->free_frozen * 100 / total_free : 0);
468
469 printf("Total %8lu %8lu\n\n", total_alloc, total_free);
470
471 if (s->cpuslab_flush)
472 printf("Flushes %8lu\n", s->cpuslab_flush);
473
474 total = s->deactivate_full + s->deactivate_empty +
475 s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass;
476
477 if (total) {
478 printf("\nSlab Deactivation Ocurrences %%\n");
479 printf("-------------------------------------------------\n");
480 printf("Slab full %7lu %3lu%%\n",
481 s->deactivate_full, (s->deactivate_full * 100) / total);
482 printf("Slab empty %7lu %3lu%%\n",
483 s->deactivate_empty, (s->deactivate_empty * 100) / total);
484 printf("Moved to head of partial list %7lu %3lu%%\n",
485 s->deactivate_to_head, (s->deactivate_to_head * 100) / total);
486 printf("Moved to tail of partial list %7lu %3lu%%\n",
487 s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
488 printf("Deactivation bypass %7lu %3lu%%\n",
489 s->deactivate_bypass, (s->deactivate_bypass * 100) / total);
490 printf("Refilled from foreign frees %7lu %3lu%%\n",
491 s->alloc_refill, (s->alloc_refill * 100) / total);
492 printf("Node mismatch %7lu %3lu%%\n",
493 s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total);
494 }
495
496 if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail)
497 printf("\nCmpxchg_double Looping\n------------------------\n");
498 printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n",
499 s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail);
500}
501
502static void report(struct slabinfo *s)
503{
504 if (strcmp(s->name, "*") == 0)
505 return;
506
507 printf("\nSlabcache: %-20s Aliases: %2d Order : %2d Objects: %lu\n",
508 s->name, s->aliases, s->order, s->objects);
509 if (s->hwcache_align)
510 printf("** Hardware cacheline aligned\n");
511 if (s->cache_dma)
512 printf("** Memory is allocated in a special DMA zone\n");
513 if (s->destroy_by_rcu)
514 printf("** Slabs are destroyed via RCU\n");
515 if (s->reclaim_account)
516 printf("** Reclaim accounting active\n");
517
518 printf("\nSizes (bytes) Slabs Debug Memory\n");
519 printf("------------------------------------------------------------------------\n");
520 printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
521 s->object_size, s->slabs, onoff(s->sanity_checks),
522 s->slabs * (page_size << s->order));
523 printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n",
524 s->slab_size, s->slabs - s->partial - s->cpu_slabs,
525 onoff(s->red_zone), s->objects * s->object_size);
526 printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n",
527 page_size << s->order, s->partial, onoff(s->poison),
528 s->slabs * (page_size << s->order) - s->objects * s->object_size);
529 printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n",
530 s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
531 (s->slab_size - s->object_size) * s->objects);
532 printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
533 s->align, s->objs_per_slab, onoff(s->trace),
534 ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
535 s->slabs);
536
537 ops(s);
538 show_tracking(s);
539 slab_numa(s, 1);
540 slab_stats(s);
541}
542
543static void slabcache(struct slabinfo *s)
544{
545 char size_str[20];
546 char dist_str[40];
547 char flags[20];
548 char *p = flags;
549
550 if (strcmp(s->name, "*") == 0)
551 return;
552
553 if (actual_slabs == 1) {
554 report(s);
555 return;
556 }
557
558 if (skip_zero && !show_empty && !s->slabs)
559 return;
560
561 if (show_empty && s->slabs)
562 return;
563
564 store_size(size_str, slab_size(s));
565 snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
566 s->partial, s->cpu_slabs);
567
568 if (!line++)
569 first_line();
570
571 if (s->aliases)
572 *p++ = '*';
573 if (s->cache_dma)
574 *p++ = 'd';
575 if (s->hwcache_align)
576 *p++ = 'A';
577 if (s->poison)
578 *p++ = 'P';
579 if (s->reclaim_account)
580 *p++ = 'a';
581 if (s->red_zone)
582 *p++ = 'Z';
583 if (s->sanity_checks)
584 *p++ = 'F';
585 if (s->store_user)
586 *p++ = 'U';
587 if (s->trace)
588 *p++ = 'T';
589
590 *p = 0;
591 if (show_activity) {
592 unsigned long total_alloc;
593 unsigned long total_free;
594
595 total_alloc = s->alloc_fastpath + s->alloc_slowpath;
596 total_free = s->free_fastpath + s->free_slowpath;
597
598 printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n",
599 s->name, s->objects,
600 total_alloc, total_free,
601 total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
602 total_free ? (s->free_fastpath * 100 / total_free) : 0,
603 s->order_fallback, s->order, s->cmpxchg_double_fail,
604 s->cmpxchg_double_cpu_fail);
605 }
606 else
607 printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
608 s->name, s->objects, s->object_size, size_str, dist_str,
609 s->objs_per_slab, s->order,
610 s->slabs ? (s->partial * 100) / s->slabs : 100,
611 s->slabs ? (s->objects * s->object_size * 100) /
612 (s->slabs * (page_size << s->order)) : 100,
613 flags);
614}
615
616/*
617 * Analyze debug options. Return false if something is amiss.
618 */
619static int debug_opt_scan(char *opt)
620{
621 if (!opt || !opt[0] || strcmp(opt, "-") == 0)
622 return 1;
623
624 if (strcasecmp(opt, "a") == 0) {
625 sanity = 1;
626 poison = 1;
627 redzone = 1;
628 tracking = 1;
629 return 1;
630 }
631
632 for ( ; *opt; opt++)
633 switch (*opt) {
634 case 'F' : case 'f':
635 if (sanity)
636 return 0;
637 sanity = 1;
638 break;
639 case 'P' : case 'p':
640 if (poison)
641 return 0;
642 poison = 1;
643 break;
644
645 case 'Z' : case 'z':
646 if (redzone)
647 return 0;
648 redzone = 1;
649 break;
650
651 case 'U' : case 'u':
652 if (tracking)
653 return 0;
654 tracking = 1;
655 break;
656
657 case 'T' : case 't':
658 if (tracing)
659 return 0;
660 tracing = 1;
661 break;
662 default:
663 return 0;
664 }
665 return 1;
666}
667
668static int slab_empty(struct slabinfo *s)
669{
670 if (s->objects > 0)
671 return 0;
672
673 /*
674 * We may still have slabs even if there are no objects. Shrinking will
675 * remove them.
676 */
677 if (s->slabs != 0)
678 set_obj(s, "shrink", 1);
679
680 return 1;
681}
682
683static void slab_debug(struct slabinfo *s)
684{
685 if (strcmp(s->name, "*") == 0)
686 return;
687
688 if (sanity && !s->sanity_checks) {
689 set_obj(s, "sanity", 1);
690 }
691 if (!sanity && s->sanity_checks) {
692 if (slab_empty(s))
693 set_obj(s, "sanity", 0);
694 else
695 fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
696 }
697 if (redzone && !s->red_zone) {
698 if (slab_empty(s))
699 set_obj(s, "red_zone", 1);
700 else
701 fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
702 }
703 if (!redzone && s->red_zone) {
704 if (slab_empty(s))
705 set_obj(s, "red_zone", 0);
706 else
707 fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
708 }
709 if (poison && !s->poison) {
710 if (slab_empty(s))
711 set_obj(s, "poison", 1);
712 else
713 fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
714 }
715 if (!poison && s->poison) {
716 if (slab_empty(s))
717 set_obj(s, "poison", 0);
718 else
719 fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
720 }
721 if (tracking && !s->store_user) {
722 if (slab_empty(s))
723 set_obj(s, "store_user", 1);
724 else
725 fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
726 }
727 if (!tracking && s->store_user) {
728 if (slab_empty(s))
729 set_obj(s, "store_user", 0);
730 else
731 fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
732 }
733 if (tracing && !s->trace) {
734 if (slabs == 1)
735 set_obj(s, "trace", 1);
736 else
737 fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
738 }
739 if (!tracing && s->trace)
740 set_obj(s, "trace", 1);
741}
742
743static void totals(void)
744{
745 struct slabinfo *s;
746
747 int used_slabs = 0;
748 char b1[20], b2[20], b3[20], b4[20];
749 unsigned long long max = 1ULL << 63;
750
751 /* Object size */
752 unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
753
754 /* Number of partial slabs in a slabcache */
755 unsigned long long min_partial = max, max_partial = 0,
756 avg_partial, total_partial = 0;
757
758 /* Number of slabs in a slab cache */
759 unsigned long long min_slabs = max, max_slabs = 0,
760 avg_slabs, total_slabs = 0;
761
762 /* Size of the whole slab */
763 unsigned long long min_size = max, max_size = 0,
764 avg_size, total_size = 0;
765
766 /* Bytes used for object storage in a slab */
767 unsigned long long min_used = max, max_used = 0,
768 avg_used, total_used = 0;
769
770 /* Waste: Bytes used for alignment and padding */
771 unsigned long long min_waste = max, max_waste = 0,
772 avg_waste, total_waste = 0;
773 /* Number of objects in a slab */
774 unsigned long long min_objects = max, max_objects = 0,
775 avg_objects, total_objects = 0;
776 /* Waste per object */
777 unsigned long long min_objwaste = max,
778 max_objwaste = 0, avg_objwaste,
779 total_objwaste = 0;
780
781 /* Memory per object */
782 unsigned long long min_memobj = max,
783 max_memobj = 0, avg_memobj,
784 total_objsize = 0;
785
786 /* Percentage of partial slabs per slab */
787 unsigned long min_ppart = 100, max_ppart = 0,
788 avg_ppart, total_ppart = 0;
789
790 /* Number of objects in partial slabs */
791 unsigned long min_partobj = max, max_partobj = 0,
792 avg_partobj, total_partobj = 0;
793
794 /* Percentage of partial objects of all objects in a slab */
795 unsigned long min_ppartobj = 100, max_ppartobj = 0,
796 avg_ppartobj, total_ppartobj = 0;
797
798
799 for (s = slabinfo; s < slabinfo + slabs; s++) {
800 unsigned long long size;
801 unsigned long used;
802 unsigned long long wasted;
803 unsigned long long objwaste;
804 unsigned long percentage_partial_slabs;
805 unsigned long percentage_partial_objs;
806
807 if (!s->slabs || !s->objects)
808 continue;
809
810 used_slabs++;
811
812 size = slab_size(s);
813 used = s->objects * s->object_size;
814 wasted = size - used;
815 objwaste = s->slab_size - s->object_size;
816
817 percentage_partial_slabs = s->partial * 100 / s->slabs;
818 if (percentage_partial_slabs > 100)
819 percentage_partial_slabs = 100;
820
821 percentage_partial_objs = s->objects_partial * 100
822 / s->objects;
823
824 if (percentage_partial_objs > 100)
825 percentage_partial_objs = 100;
826
827 if (s->object_size < min_objsize)
828 min_objsize = s->object_size;
829 if (s->partial < min_partial)
830 min_partial = s->partial;
831 if (s->slabs < min_slabs)
832 min_slabs = s->slabs;
833 if (size < min_size)
834 min_size = size;
835 if (wasted < min_waste)
836 min_waste = wasted;
837 if (objwaste < min_objwaste)
838 min_objwaste = objwaste;
839 if (s->objects < min_objects)
840 min_objects = s->objects;
841 if (used < min_used)
842 min_used = used;
843 if (s->objects_partial < min_partobj)
844 min_partobj = s->objects_partial;
845 if (percentage_partial_slabs < min_ppart)
846 min_ppart = percentage_partial_slabs;
847 if (percentage_partial_objs < min_ppartobj)
848 min_ppartobj = percentage_partial_objs;
849 if (s->slab_size < min_memobj)
850 min_memobj = s->slab_size;
851
852 if (s->object_size > max_objsize)
853 max_objsize = s->object_size;
854 if (s->partial > max_partial)
855 max_partial = s->partial;
856 if (s->slabs > max_slabs)
857 max_slabs = s->slabs;
858 if (size > max_size)
859 max_size = size;
860 if (wasted > max_waste)
861 max_waste = wasted;
862 if (objwaste > max_objwaste)
863 max_objwaste = objwaste;
864 if (s->objects > max_objects)
865 max_objects = s->objects;
866 if (used > max_used)
867 max_used = used;
868 if (s->objects_partial > max_partobj)
869 max_partobj = s->objects_partial;
870 if (percentage_partial_slabs > max_ppart)
871 max_ppart = percentage_partial_slabs;
872 if (percentage_partial_objs > max_ppartobj)
873 max_ppartobj = percentage_partial_objs;
874 if (s->slab_size > max_memobj)
875 max_memobj = s->slab_size;
876
877 total_partial += s->partial;
878 total_slabs += s->slabs;
879 total_size += size;
880 total_waste += wasted;
881
882 total_objects += s->objects;
883 total_used += used;
884 total_partobj += s->objects_partial;
885 total_ppart += percentage_partial_slabs;
886 total_ppartobj += percentage_partial_objs;
887
888 total_objwaste += s->objects * objwaste;
889 total_objsize += s->objects * s->slab_size;
890 }
891
892 if (!total_objects) {
893 printf("No objects\n");
894 return;
895 }
896 if (!used_slabs) {
897 printf("No slabs\n");
898 return;
899 }
900
901 /* Per slab averages */
902 avg_partial = total_partial / used_slabs;
903 avg_slabs = total_slabs / used_slabs;
904 avg_size = total_size / used_slabs;
905 avg_waste = total_waste / used_slabs;
906
907 avg_objects = total_objects / used_slabs;
908 avg_used = total_used / used_slabs;
909 avg_partobj = total_partobj / used_slabs;
910 avg_ppart = total_ppart / used_slabs;
911 avg_ppartobj = total_ppartobj / used_slabs;
912
913 /* Per object object sizes */
914 avg_objsize = total_used / total_objects;
915 avg_objwaste = total_objwaste / total_objects;
916 avg_partobj = total_partobj * 100 / total_objects;
917 avg_memobj = total_objsize / total_objects;
918
919 printf("Slabcache Totals\n");
920 printf("----------------\n");
921 printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n",
922 slabs, aliases, alias_targets, used_slabs);
923
924 store_size(b1, total_size);store_size(b2, total_waste);
925 store_size(b3, total_waste * 100 / total_used);
926 printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3);
927
928 store_size(b1, total_objects);store_size(b2, total_partobj);
929 store_size(b3, total_partobj * 100 / total_objects);
930 printf("# Objects : %6s # PartObj: %6s ORatio:%6s%%\n", b1, b2, b3);
931
932 printf("\n");
933 printf("Per Cache Average Min Max Total\n");
934 printf("---------------------------------------------------------\n");
935
936 store_size(b1, avg_objects);store_size(b2, min_objects);
937 store_size(b3, max_objects);store_size(b4, total_objects);
938 printf("#Objects %10s %10s %10s %10s\n",
939 b1, b2, b3, b4);
940
941 store_size(b1, avg_slabs);store_size(b2, min_slabs);
942 store_size(b3, max_slabs);store_size(b4, total_slabs);
943 printf("#Slabs %10s %10s %10s %10s\n",
944 b1, b2, b3, b4);
945
946 store_size(b1, avg_partial);store_size(b2, min_partial);
947 store_size(b3, max_partial);store_size(b4, total_partial);
948 printf("#PartSlab %10s %10s %10s %10s\n",
949 b1, b2, b3, b4);
950 store_size(b1, avg_ppart);store_size(b2, min_ppart);
951 store_size(b3, max_ppart);
952 store_size(b4, total_partial * 100 / total_slabs);
953 printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n",
954 b1, b2, b3, b4);
955
956 store_size(b1, avg_partobj);store_size(b2, min_partobj);
957 store_size(b3, max_partobj);
958 store_size(b4, total_partobj);
959 printf("PartObjs %10s %10s %10s %10s\n",
960 b1, b2, b3, b4);
961
962 store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
963 store_size(b3, max_ppartobj);
964 store_size(b4, total_partobj * 100 / total_objects);
965 printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n",
966 b1, b2, b3, b4);
967
968 store_size(b1, avg_size);store_size(b2, min_size);
969 store_size(b3, max_size);store_size(b4, total_size);
970 printf("Memory %10s %10s %10s %10s\n",
971 b1, b2, b3, b4);
972
973 store_size(b1, avg_used);store_size(b2, min_used);
974 store_size(b3, max_used);store_size(b4, total_used);
975 printf("Used %10s %10s %10s %10s\n",
976 b1, b2, b3, b4);
977
978 store_size(b1, avg_waste);store_size(b2, min_waste);
979 store_size(b3, max_waste);store_size(b4, total_waste);
980 printf("Loss %10s %10s %10s %10s\n",
981 b1, b2, b3, b4);
982
983 printf("\n");
984 printf("Per Object Average Min Max\n");
985 printf("---------------------------------------------\n");
986
987 store_size(b1, avg_memobj);store_size(b2, min_memobj);
988 store_size(b3, max_memobj);
989 printf("Memory %10s %10s %10s\n",
990 b1, b2, b3);
991 store_size(b1, avg_objsize);store_size(b2, min_objsize);
992 store_size(b3, max_objsize);
993 printf("User %10s %10s %10s\n",
994 b1, b2, b3);
995
996 store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
997 store_size(b3, max_objwaste);
998 printf("Loss %10s %10s %10s\n",
999 b1, b2, b3);
1000}
1001
1002static void sort_slabs(void)
1003{
1004 struct slabinfo *s1,*s2;
1005
1006 for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
1007 for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
1008 int result;
1009
1010 if (sort_size)
1011 result = slab_size(s1) < slab_size(s2);
1012 else if (sort_active)
1013 result = slab_activity(s1) < slab_activity(s2);
1014 else
1015 result = strcasecmp(s1->name, s2->name);
1016
1017 if (show_inverted)
1018 result = -result;
1019
1020 if (result > 0) {
1021 struct slabinfo t;
1022
1023 memcpy(&t, s1, sizeof(struct slabinfo));
1024 memcpy(s1, s2, sizeof(struct slabinfo));
1025 memcpy(s2, &t, sizeof(struct slabinfo));
1026 }
1027 }
1028 }
1029}
1030
1031static void sort_aliases(void)
1032{
1033 struct aliasinfo *a1,*a2;
1034
1035 for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
1036 for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
1037 char *n1, *n2;
1038
1039 n1 = a1->name;
1040 n2 = a2->name;
1041 if (show_alias && !show_inverted) {
1042 n1 = a1->ref;
1043 n2 = a2->ref;
1044 }
1045 if (strcasecmp(n1, n2) > 0) {
1046 struct aliasinfo t;
1047
1048 memcpy(&t, a1, sizeof(struct aliasinfo));
1049 memcpy(a1, a2, sizeof(struct aliasinfo));
1050 memcpy(a2, &t, sizeof(struct aliasinfo));
1051 }
1052 }
1053 }
1054}
1055
1056static void link_slabs(void)
1057{
1058 struct aliasinfo *a;
1059 struct slabinfo *s;
1060
1061 for (a = aliasinfo; a < aliasinfo + aliases; a++) {
1062
1063 for (s = slabinfo; s < slabinfo + slabs; s++)
1064 if (strcmp(a->ref, s->name) == 0) {
1065 a->slab = s;
1066 s->refs++;
1067 break;
1068 }
1069 if (s == slabinfo + slabs)
1070 fatal("Unresolved alias %s\n", a->ref);
1071 }
1072}
1073
1074static void alias(void)
1075{
1076 struct aliasinfo *a;
1077 char *active = NULL;
1078
1079 sort_aliases();
1080 link_slabs();
1081
1082 for(a = aliasinfo; a < aliasinfo + aliases; a++) {
1083
1084 if (!show_single_ref && a->slab->refs == 1)
1085 continue;
1086
1087 if (!show_inverted) {
1088 if (active) {
1089 if (strcmp(a->slab->name, active) == 0) {
1090 printf(" %s", a->name);
1091 continue;
1092 }
1093 }
1094 printf("\n%-12s <- %s", a->slab->name, a->name);
1095 active = a->slab->name;
1096 }
1097 else
1098 printf("%-20s -> %s\n", a->name, a->slab->name);
1099 }
1100 if (active)
1101 printf("\n");
1102}
1103
1104
1105static void rename_slabs(void)
1106{
1107 struct slabinfo *s;
1108 struct aliasinfo *a;
1109
1110 for (s = slabinfo; s < slabinfo + slabs; s++) {
1111 if (*s->name != ':')
1112 continue;
1113
1114 if (s->refs > 1 && !show_first_alias)
1115 continue;
1116
1117 a = find_one_alias(s);
1118
1119 if (a)
1120 s->name = a->name;
1121 else {
1122 s->name = "*";
1123 actual_slabs--;
1124 }
1125 }
1126}
1127
1128static int slab_mismatch(char *slab)
1129{
1130 return regexec(&pattern, slab, 0, NULL, 0);
1131}
1132
1133static void read_slab_dir(void)
1134{
1135 DIR *dir;
1136 struct dirent *de;
1137 struct slabinfo *slab = slabinfo;
1138 struct aliasinfo *alias = aliasinfo;
1139 char *p;
1140 char *t;
1141 int count;
1142
1143 if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
1144 fatal("SYSFS support for SLUB not active\n");
1145
1146 dir = opendir(".");
1147 while ((de = readdir(dir))) {
1148 if (de->d_name[0] == '.' ||
1149 (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
1150 continue;
1151 switch (de->d_type) {
1152 case DT_LNK:
1153 alias->name = strdup(de->d_name);
1154 count = readlink(de->d_name, buffer, sizeof(buffer)-1);
1155
1156 if (count < 0)
1157 fatal("Cannot read symlink %s\n", de->d_name);
1158
1159 buffer[count] = 0;
1160 p = buffer + count;
1161 while (p > buffer && p[-1] != '/')
1162 p--;
1163 alias->ref = strdup(p);
1164 alias++;
1165 break;
1166 case DT_DIR:
1167 if (chdir(de->d_name))
1168 fatal("Unable to access slab %s\n", slab->name);
1169 slab->name = strdup(de->d_name);
1170 slab->alias = 0;
1171 slab->refs = 0;
1172 slab->aliases = get_obj("aliases");
1173 slab->align = get_obj("align");
1174 slab->cache_dma = get_obj("cache_dma");
1175 slab->cpu_slabs = get_obj("cpu_slabs");
1176 slab->destroy_by_rcu = get_obj("destroy_by_rcu");
1177 slab->hwcache_align = get_obj("hwcache_align");
1178 slab->object_size = get_obj("object_size");
1179 slab->objects = get_obj("objects");
1180 slab->objects_partial = get_obj("objects_partial");
1181 slab->objects_total = get_obj("objects_total");
1182 slab->objs_per_slab = get_obj("objs_per_slab");
1183 slab->order = get_obj("order");
1184 slab->partial = get_obj("partial");
1185 slab->partial = get_obj_and_str("partial", &t);
1186 decode_numa_list(slab->numa_partial, t);
1187 free(t);
1188 slab->poison = get_obj("poison");
1189 slab->reclaim_account = get_obj("reclaim_account");
1190 slab->red_zone = get_obj("red_zone");
1191 slab->sanity_checks = get_obj("sanity_checks");
1192 slab->slab_size = get_obj("slab_size");
1193 slab->slabs = get_obj_and_str("slabs", &t);
1194 decode_numa_list(slab->numa, t);
1195 free(t);
1196 slab->store_user = get_obj("store_user");
1197 slab->trace = get_obj("trace");
1198 slab->alloc_fastpath = get_obj("alloc_fastpath");
1199 slab->alloc_slowpath = get_obj("alloc_slowpath");
1200 slab->free_fastpath = get_obj("free_fastpath");
1201 slab->free_slowpath = get_obj("free_slowpath");
1202 slab->free_frozen= get_obj("free_frozen");
1203 slab->free_add_partial = get_obj("free_add_partial");
1204 slab->free_remove_partial = get_obj("free_remove_partial");
1205 slab->alloc_from_partial = get_obj("alloc_from_partial");
1206 slab->alloc_slab = get_obj("alloc_slab");
1207 slab->alloc_refill = get_obj("alloc_refill");
1208 slab->free_slab = get_obj("free_slab");
1209 slab->cpuslab_flush = get_obj("cpuslab_flush");
1210 slab->deactivate_full = get_obj("deactivate_full");
1211 slab->deactivate_empty = get_obj("deactivate_empty");
1212 slab->deactivate_to_head = get_obj("deactivate_to_head");
1213 slab->deactivate_to_tail = get_obj("deactivate_to_tail");
1214 slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
1215 slab->order_fallback = get_obj("order_fallback");
1216 slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
1217 slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
1218 slab->cpu_partial_alloc = get_obj("cpu_partial_alloc");
1219 slab->cpu_partial_free = get_obj("cpu_partial_free");
1220 slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
1221 slab->deactivate_bypass = get_obj("deactivate_bypass");
1222 chdir("..");
1223 if (slab->name[0] == ':')
1224 alias_targets++;
1225 slab++;
1226 break;
1227 default :
1228 fatal("Unknown file type %lx\n", de->d_type);
1229 }
1230 }
1231 closedir(dir);
1232 slabs = slab - slabinfo;
1233 actual_slabs = slabs;
1234 aliases = alias - aliasinfo;
1235 if (slabs > MAX_SLABS)
1236 fatal("Too many slabs\n");
1237 if (aliases > MAX_ALIASES)
1238 fatal("Too many aliases\n");
1239}
1240
1241static void output_slabs(void)
1242{
1243 struct slabinfo *slab;
1244
1245 for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
1246
1247 if (slab->alias)
1248 continue;
1249
1250
1251 if (show_numa)
1252 slab_numa(slab, 0);
1253 else if (show_track)
1254 show_tracking(slab);
1255 else if (validate)
1256 slab_validate(slab);
1257 else if (shrink)
1258 slab_shrink(slab);
1259 else if (set_debug)
1260 slab_debug(slab);
1261 else if (show_ops)
1262 ops(slab);
1263 else if (show_slab)
1264 slabcache(slab);
1265 else if (show_report)
1266 report(slab);
1267 }
1268}
1269
1270struct option opts[] = {
1271 { "aliases", 0, NULL, 'a' },
1272 { "activity", 0, NULL, 'A' },
1273 { "debug", 2, NULL, 'd' },
1274 { "display-activity", 0, NULL, 'D' },
1275 { "empty", 0, NULL, 'e' },
1276 { "first-alias", 0, NULL, 'f' },
1277 { "help", 0, NULL, 'h' },
1278 { "inverted", 0, NULL, 'i'},
1279 { "numa", 0, NULL, 'n' },
1280 { "ops", 0, NULL, 'o' },
1281 { "report", 0, NULL, 'r' },
1282 { "shrink", 0, NULL, 's' },
1283 { "slabs", 0, NULL, 'l' },
1284 { "track", 0, NULL, 't'},
1285 { "validate", 0, NULL, 'v' },
1286 { "zero", 0, NULL, 'z' },
1287 { "1ref", 0, NULL, '1'},
1288 { NULL, 0, NULL, 0 }
1289};
1290
1291int main(int argc, char *argv[])
1292{
1293 int c;
1294 int err;
1295 char *pattern_source;
1296
1297 page_size = getpagesize();
1298
1299 while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
1300 opts, NULL)) != -1)
1301 switch (c) {
1302 case '1':
1303 show_single_ref = 1;
1304 break;
1305 case 'a':
1306 show_alias = 1;
1307 break;
1308 case 'A':
1309 sort_active = 1;
1310 break;
1311 case 'd':
1312 set_debug = 1;
1313 if (!debug_opt_scan(optarg))
1314 fatal("Invalid debug option '%s'\n", optarg);
1315 break;
1316 case 'D':
1317 show_activity = 1;
1318 break;
1319 case 'e':
1320 show_empty = 1;
1321 break;
1322 case 'f':
1323 show_first_alias = 1;
1324 break;
1325 case 'h':
1326 usage();
1327 return 0;
1328 case 'i':
1329 show_inverted = 1;
1330 break;
1331 case 'n':
1332 show_numa = 1;
1333 break;
1334 case 'o':
1335 show_ops = 1;
1336 break;
1337 case 'r':
1338 show_report = 1;
1339 break;
1340 case 's':
1341 shrink = 1;
1342 break;
1343 case 'l':
1344 show_slab = 1;
1345 break;
1346 case 't':
1347 show_track = 1;
1348 break;
1349 case 'v':
1350 validate = 1;
1351 break;
1352 case 'z':
1353 skip_zero = 0;
1354 break;
1355 case 'T':
1356 show_totals = 1;
1357 break;
1358 case 'S':
1359 sort_size = 1;
1360 break;
1361
1362 default:
1363 fatal("%s: Invalid option '%c'\n", argv[0], optopt);
1364
1365 }
1366
1367 if (!show_slab && !show_alias && !show_track && !show_report
1368 && !validate && !shrink && !set_debug && !show_ops)
1369 show_slab = 1;
1370
1371 if (argc > optind)
1372 pattern_source = argv[optind];
1373 else
1374 pattern_source = ".*";
1375
1376 err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
1377 if (err)
1378 fatal("%s: Invalid pattern '%s' code %d\n",
1379 argv[0], pattern_source, err);
1380 read_slab_dir();
1381 if (show_alias)
1382 alias();
1383 else
1384 if (show_totals)
1385 totals();
1386 else {
1387 link_slabs();
1388 rename_slabs();
1389 sort_slabs();
1390 output_slabs();
1391 }
1392 return 0;
1393}