Merge branch 'perf/urgent' into perf/core
authorIngo Molnar <mingo@elte.hu>
Tue, 6 Dec 2011 05:42:35 +0000 (06:42 +0100)
committerIngo Molnar <mingo@elte.hu>
Tue, 6 Dec 2011 05:43:49 +0000 (06:43 +0100)
Merge reason: Add these cherry-picked commits so that future changes
              on perf/core don't conflict.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
87 files changed:
Documentation/kernel-parameters.txt
Documentation/trace/events.txt
arch/Kconfig
arch/x86/include/asm/insn.h
arch/x86/lib/inat.c
arch/x86/lib/insn.c
arch/x86/lib/x86-opcode-map.txt
arch/x86/oprofile/Makefile
arch/x86/oprofile/init.c
arch/x86/oprofile/nmi_int.c
arch/x86/oprofile/nmi_timer_int.c [deleted file]
arch/x86/tools/Makefile
arch/x86/tools/gen-insn-attr-x86.awk
arch/x86/tools/insn_sanity.c [new file with mode: 0644]
drivers/oprofile/nmi_timer_int.c [new file with mode: 0644]
drivers/oprofile/oprof.c
drivers/oprofile/oprof.h
drivers/oprofile/timer_int.c
kernel/events/Makefile
kernel/events/callchain.c [new file with mode: 0644]
kernel/events/core.c
kernel/events/internal.h
kernel/lockdep.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_events_filter.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_sched_wakeup.c
tools/perf/Documentation/perf-annotate.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-script.txt
tools/perf/Documentation/perf-test.txt
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-lock.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-test.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/perf.c
tools/perf/perf.h
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/build-id.c
tools/perf/util/build-id.h
tools/perf/util/callchain.h
tools/perf/util/cgroup.c
tools/perf/util/debugfs.c
tools/perf/util/debugfs.h
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/hist.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/probe-finder.h
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/setup.py
tools/perf/util/symbol.h
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/tool.h [new file with mode: 0644]
tools/perf/util/top.h
tools/perf/util/trace-event-info.c
tools/perf/util/trace-event-scripting.c
tools/perf/util/trace-event.h
tools/perf/util/ui/browsers/annotate.c
tools/perf/util/ui/browsers/hists.c
tools/perf/util/ui/progress.c

index a0c5c5f..fd5c913 100644 (file)
@@ -1885,6 +1885,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        arch_perfmon: [X86] Force use of architectural
                                perfmon on Intel CPUs instead of the
                                CPU specific event set.
+                       timer: [X86] Force use of architectural NMI
+                               timer mode (see also oprofile.timer
+                               for generic hr timer mode)
 
        oops=panic      Always panic on oopses. Default is to just kill the
                        process, but there is a small probability of
index b510564..bb24c2a 100644 (file)
@@ -191,8 +191,6 @@ And for string fields they are:
 
 Currently, only exact string matches are supported.
 
-Currently, the maximum number of predicates in a filter is 16.
-
 5.2 Setting filters
 -------------------
 
index 4b0669c..2505740 100644 (file)
@@ -30,6 +30,10 @@ config OPROFILE_EVENT_MULTIPLEX
 config HAVE_OPROFILE
        bool
 
+config OPROFILE_NMI_TIMER
+       def_bool y
+       depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
+
 config KPROBES
        bool "Kprobes"
        depends on MODULES
index 88c765e..74df3f1 100644 (file)
@@ -137,6 +137,13 @@ static inline int insn_is_avx(struct insn *insn)
        return (insn->vex_prefix.value != 0);
 }
 
+/* Ensure this instruction is decoded completely */
+static inline int insn_complete(struct insn *insn)
+{
+       return insn->opcode.got && insn->modrm.got && insn->sib.got &&
+               insn->displacement.got && insn->immediate.got;
+}
+
 static inline insn_byte_t insn_vex_m_bits(struct insn *insn)
 {
        if (insn->vex_prefix.nbytes == 2)       /* 2 bytes VEX */
index 46fc4ee..88ad5fb 100644 (file)
@@ -82,9 +82,16 @@ insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m,
        const insn_attr_t *table;
        if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX)
                return 0;
-       table = inat_avx_tables[vex_m][vex_p];
+       /* At first, this checks the master table */
+       table = inat_avx_tables[vex_m][0];
        if (!table)
                return 0;
+       if (!inat_is_group(table[opcode]) && vex_p) {
+               /* If this is not a group, get attribute directly */
+               table = inat_avx_tables[vex_m][vex_p];
+               if (!table)
+                       return 0;
+       }
        return table[opcode];
 }
 
index 374562e..5a1f9f3 100644 (file)
@@ -202,7 +202,7 @@ void insn_get_opcode(struct insn *insn)
                m = insn_vex_m_bits(insn);
                p = insn_vex_p_bits(insn);
                insn->attr = inat_get_avx_attribute(op, m, p);
-               if (!inat_accept_vex(insn->attr))
+               if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr))
                        insn->attr = 0; /* This instruction is bad */
                goto end;       /* VEX has only 1 byte for opcode */
        }
@@ -249,6 +249,8 @@ void insn_get_modrm(struct insn *insn)
                        pfx = insn_last_prefix(insn);
                        insn->attr = inat_get_group_attribute(mod, pfx,
                                                              insn->attr);
+                       if (insn_is_avx(insn) && !inat_accept_vex(insn->attr))
+                               insn->attr = 0; /* This is bad */
                }
        }
 
index a793da5..5b83c51 100644 (file)
@@ -1,5 +1,11 @@
 # x86 Opcode Maps
 #
+# This is (mostly) based on following documentations.
+# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2
+#   (#325383-040US, October 2011)
+# - Intel(R) Advanced Vector Extensions Programming Reference
+#   (#319433-011,JUNE 2011).
+#
 #<Opcode maps>
 # Table: table-name
 # Referrer: escaped-name
 # EndTable
 #
 # AVX Superscripts
-#  (VEX): this opcode can accept VEX prefix.
-#  (oVEX): this opcode requires VEX prefix.
-#  (o128): this opcode only supports 128bit VEX.
-#  (o256): this opcode only supports 256bit VEX.
+#  (v): this opcode requires VEX prefix.
+#  (v1): this opcode only supports 128bit VEX.
+#
+# Last Prefix Superscripts
+#  - (66): the last prefix is 0x66
+#  - (F3): the last prefix is 0xF3
+#  - (F2): the last prefix is 0xF2
 #
 
 Table: one byte opcode
@@ -199,8 +208,8 @@ a0: MOV AL,Ob
 a1: MOV rAX,Ov
 a2: MOV Ob,AL
 a3: MOV Ov,rAX
-a4: MOVS/B Xb,Yb
-a5: MOVS/W/D/Q Xv,Yv
+a4: MOVS/B Yb,Xb
+a5: MOVS/W/D/Q Yv,Xv
 a6: CMPS/B Xb,Yb
 a7: CMPS/W/D Xv,Yv
 a8: TEST AL,Ib
@@ -233,8 +242,8 @@ c0: Grp2 Eb,Ib (1A)
 c1: Grp2 Ev,Ib (1A)
 c2: RETN Iw (f64)
 c3: RETN
-c4: LES Gz,Mp (i64) | 3bytes-VEX (Prefix)
-c5: LDS Gz,Mp (i64) | 2bytes-VEX (Prefix)
+c4: LES Gz,Mp (i64) | VEX+2byte (Prefix)
+c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix)
 c6: Grp11 Eb,Ib (1A)
 c7: Grp11 Ev,Iz (1A)
 c8: ENTER Iw,Ib
@@ -320,14 +329,19 @@ AVXcode: 1
 # 3DNow! uses the last imm byte as opcode extension.
 0f: 3DNow! Pq,Qq,Ib
 # 0x0f 0x10-0x1f
-10: movups Vps,Wps (VEX) | movss Vss,Wss (F3),(VEX),(o128) | movupd Vpd,Wpd (66),(VEX) | movsd Vsd,Wsd (F2),(VEX),(o128)
-11: movups Wps,Vps (VEX) | movss Wss,Vss (F3),(VEX),(o128) | movupd Wpd,Vpd (66),(VEX) | movsd Wsd,Vsd (F2),(VEX),(o128)
-12: movlps Vq,Mq (VEX),(o128) | movlpd Vq,Mq (66),(VEX),(o128) | movhlps Vq,Uq (VEX),(o128) | movddup Vq,Wq (F2),(VEX) | movsldup Vq,Wq (F3),(VEX)
-13: mpvlps Mq,Vq (VEX),(o128) | movlpd Mq,Vq (66),(VEX),(o128)
-14: unpcklps Vps,Wq (VEX) | unpcklpd Vpd,Wq (66),(VEX)
-15: unpckhps Vps,Wq (VEX) | unpckhpd Vpd,Wq (66),(VEX)
-16: movhps Vq,Mq (VEX),(o128) | movhpd Vq,Mq (66),(VEX),(o128) | movlsps Vq,Uq (VEX),(o128) | movshdup Vq,Wq (F3),(VEX)
-17: movhps Mq,Vq (VEX),(o128) | movhpd Mq,Vq (66),(VEX),(o128)
+# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands
+# but it actually has operands. And also, vmovss and vmovsd only accept 128bit.
+# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form.
+# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming
+# Reference A.1
+10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1)
+11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1)
+12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2)
+13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1)
+14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66)
+15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66)
+16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3)
+17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1)
 18: Grp16 (1A)
 19:
 1a:
@@ -345,14 +359,14 @@ AVXcode: 1
 25:
 26:
 27:
-28: movaps Vps,Wps (VEX) | movapd Vpd,Wpd (66),(VEX)
-29: movaps Wps,Vps (VEX) | movapd Wpd,Vpd (66),(VEX)
-2a: cvtpi2ps Vps,Qpi | cvtsi2ss Vss,Ed/q (F3),(VEX),(o128) | cvtpi2pd Vpd,Qpi (66) | cvtsi2sd Vsd,Ed/q (F2),(VEX),(o128)
-2b: movntps Mps,Vps (VEX) | movntpd Mpd,Vpd (66),(VEX)
-2c: cvttps2pi Ppi,Wps | cvttss2si  Gd/q,Wss (F3),(VEX),(o128) | cvttpd2pi Ppi,Wpd (66) | cvttsd2si Gd/q,Wsd (F2),(VEX),(o128)
-2d: cvtps2pi Ppi,Wps | cvtss2si Gd/q,Wss (F3),(VEX),(o128) | cvtpd2pi Qpi,Wpd (66) | cvtsd2si Gd/q,Wsd (F2),(VEX),(o128)
-2e: ucomiss Vss,Wss (VEX),(o128) | ucomisd  Vsd,Wsd (66),(VEX),(o128)
-2f: comiss Vss,Wss (VEX),(o128) | comisd  Vsd,Wsd (66),(VEX),(o128)
+28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66)
+29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66)
+2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1)
+2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66)
+2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1)
+2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1)
+2e: vucomiss Vss,Wss (v1) | vucomisd  Vsd,Wsd (66),(v1)
+2f: vcomiss Vss,Wss (v1) | vcomisd  Vsd,Wsd (66),(v1)
 # 0x0f 0x30-0x3f
 30: WRMSR
 31: RDTSC
@@ -388,65 +402,66 @@ AVXcode: 1
 4e: CMOVLE/NG Gv,Ev
 4f: CMOVNLE/G Gv,Ev
 # 0x0f 0x50-0x5f
-50: movmskps Gd/q,Ups (VEX) | movmskpd Gd/q,Upd (66),(VEX)
-51: sqrtps Vps,Wps (VEX) | sqrtss Vss,Wss (F3),(VEX),(o128) | sqrtpd Vpd,Wpd (66),(VEX) | sqrtsd Vsd,Wsd (F2),(VEX),(o128)
-52: rsqrtps Vps,Wps (VEX) | rsqrtss Vss,Wss (F3),(VEX),(o128)
-53: rcpps Vps,Wps (VEX) | rcpss Vss,Wss (F3),(VEX),(o128)
-54: andps Vps,Wps (VEX) | andpd Vpd,Wpd (66),(VEX)
-55: andnps Vps,Wps (VEX) | andnpd Vpd,Wpd (66),(VEX)
-56: orps Vps,Wps (VEX) | orpd Vpd,Wpd (66),(VEX)
-57: xorps Vps,Wps (VEX) | xorpd Vpd,Wpd (66),(VEX)
-58: addps Vps,Wps (VEX) | addss Vss,Wss (F3),(VEX),(o128) | addpd Vpd,Wpd (66),(VEX) | addsd Vsd,Wsd (F2),(VEX),(o128)
-59: mulps Vps,Wps (VEX) | mulss Vss,Wss (F3),(VEX),(o128) | mulpd Vpd,Wpd (66),(VEX) | mulsd Vsd,Wsd (F2),(VEX),(o128)
-5a: cvtps2pd Vpd,Wps (VEX) | cvtss2sd Vsd,Wss (F3),(VEX),(o128) | cvtpd2ps Vps,Wpd (66),(VEX) | cvtsd2ss Vsd,Wsd (F2),(VEX),(o128)
-5b: cvtdq2ps Vps,Wdq (VEX) | cvtps2dq Vdq,Wps (66),(VEX) | cvttps2dq Vdq,Wps (F3),(VEX)
-5c: subps Vps,Wps (VEX) | subss Vss,Wss (F3),(VEX),(o128) | subpd Vpd,Wpd (66),(VEX) | subsd Vsd,Wsd (F2),(VEX),(o128)
-5d: minps Vps,Wps (VEX) | minss Vss,Wss (F3),(VEX),(o128) | minpd Vpd,Wpd (66),(VEX) | minsd Vsd,Wsd (F2),(VEX),(o128)
-5e: divps Vps,Wps (VEX) | divss Vss,Wss (F3),(VEX),(o128) | divpd Vpd,Wpd (66),(VEX) | divsd Vsd,Wsd (F2),(VEX),(o128)
-5f: maxps Vps,Wps (VEX) | maxss Vss,Wss (F3),(VEX),(o128) | maxpd Vpd,Wpd (66),(VEX) | maxsd Vsd,Wsd (F2),(VEX),(o128)
+50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66)
+51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1)
+52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1)
+53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1)
+54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66)
+55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66)
+56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66)
+57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66)
+58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1)
+59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1)
+5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1)
+5b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3)
+5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1)
+5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1)
+5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1)
+5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1)
 # 0x0f 0x60-0x6f
-60: punpcklbw Pq,Qd | punpcklbw Vdq,Wdq (66),(VEX),(o128)
-61: punpcklwd Pq,Qd | punpcklwd Vdq,Wdq (66),(VEX),(o128)
-62: punpckldq Pq,Qd | punpckldq Vdq,Wdq (66),(VEX),(o128)
-63: packsswb Pq,Qq | packsswb Vdq,Wdq (66),(VEX),(o128)
-64: pcmpgtb Pq,Qq | pcmpgtb Vdq,Wdq (66),(VEX),(o128)
-65: pcmpgtw Pq,Qq | pcmpgtw Vdq,Wdq (66),(VEX),(o128)
-66: pcmpgtd Pq,Qq | pcmpgtd Vdq,Wdq (66),(VEX),(o128)
-67: packuswb Pq,Qq | packuswb Vdq,Wdq (66),(VEX),(o128)
-68: punpckhbw Pq,Qd | punpckhbw Vdq,Wdq (66),(VEX),(o128)
-69: punpckhwd Pq,Qd | punpckhwd Vdq,Wdq (66),(VEX),(o128)
-6a: punpckhdq Pq,Qd | punpckhdq Vdq,Wdq (66),(VEX),(o128)
-6b: packssdw Pq,Qd | packssdw Vdq,Wdq (66),(VEX),(o128)
-6c: punpcklqdq Vdq,Wdq (66),(VEX),(o128)
-6d: punpckhqdq Vdq,Wdq (66),(VEX),(o128)
-6e: movd/q/ Pd,Ed/q | movd/q Vdq,Ed/q (66),(VEX),(o128)
-6f: movq Pq,Qq | movdqa Vdq,Wdq (66),(VEX) | movdqu Vdq,Wdq (F3),(VEX)
+60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1)
+61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1)
+62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1)
+63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1)
+64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1)
+65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1)
+66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1)
+67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1)
+68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1)
+69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1)
+6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1)
+6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1)
+6c: vpunpcklqdq Vx,Hx,Wx (66),(v1)
+6d: vpunpckhqdq Vx,Hx,Wx (66),(v1)
+6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1)
+6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3)
 # 0x0f 0x70-0x7f
-70: pshufw Pq,Qq,Ib | pshufd Vdq,Wdq,Ib (66),(VEX),(o128) | pshufhw Vdq,Wdq,Ib (F3),(VEX),(o128) | pshuflw VdqWdq,Ib (F2),(VEX),(o128)
+70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1)
 71: Grp12 (1A)
 72: Grp13 (1A)
 73: Grp14 (1A)
-74: pcmpeqb Pq,Qq | pcmpeqb Vdq,Wdq (66),(VEX),(o128)
-75: pcmpeqw Pq,Qq | pcmpeqw Vdq,Wdq (66),(VEX),(o128)
-76: pcmpeqd Pq,Qq | pcmpeqd Vdq,Wdq (66),(VEX),(o128)
-77: emms/vzeroupper/vzeroall (VEX)
-78: VMREAD Ed/q,Gd/q
-79: VMWRITE Gd/q,Ed/q
+74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1)
+75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1)
+76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1)
+# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX.
+77: emms | vzeroupper | vzeroall
+78: VMREAD Ey,Gy
+79: VMWRITE Gy,Ey
 7a:
 7b:
-7c: haddps Vps,Wps (F2),(VEX) | haddpd Vpd,Wpd (66),(VEX)
-7d: hsubps Vps,Wps (F2),(VEX) | hsubpd Vpd,Wpd (66),(VEX)
-7e: movd/q Ed/q,Pd | movd/q Ed/q,Vdq (66),(VEX),(o128) | movq Vq,Wq (F3),(VEX),(o128)
-7f: movq Qq,Pq | movdqa Wdq,Vdq (66),(VEX) | movdqu Wdq,Vdq (F3),(VEX)
+7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2)
+7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2)
+7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1)
+7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3)
 # 0x0f 0x80-0x8f
 80: JO Jz (f64)
 81: JNO Jz (f64)
-82: JB/JNAE/JC Jz (f64)
-83: JNB/JAE/JNC Jz (f64)
-84: JZ/JE Jz (f64)
-85: JNZ/JNE Jz (f64)
+82: JB/JC/JNAE Jz (f64)
+83: JAE/JNB/JNC Jz (f64)
+84: JE/JZ Jz (f64)
+85: JNE/JNZ Jz (f64)
 86: JBE/JNA Jz (f64)
-87: JNBE/JA Jz (f64)
+87: JA/JNBE Jz (f64)
 88: JS Jz (f64)
 89: JNS Jz (f64)
 8a: JP/JPE Jz (f64)
@@ -502,18 +517,18 @@ b8: JMPE | POPCNT Gv,Ev (F3)
 b9: Grp10 (1A)
 ba: Grp8 Ev,Ib (1A)
 bb: BTC Ev,Gv
-bc: BSF Gv,Ev
-bd: BSR Gv,Ev
+bc: BSF Gv,Ev | TZCNT Gv,Ev (F3)
+bd: BSR Gv,Ev | LZCNT Gv,Ev (F3)
 be: MOVSX Gv,Eb
 bf: MOVSX Gv,Ew
 # 0x0f 0xc0-0xcf
 c0: XADD Eb,Gb
 c1: XADD Ev,Gv
-c2: cmpps Vps,Wps,Ib (VEX) | cmpss Vss,Wss,Ib (F3),(VEX),(o128) | cmppd Vpd,Wpd,Ib (66),(VEX) | cmpsd Vsd,Wsd,Ib (F2),(VEX)
-c3: movnti Md/q,Gd/q
-c4: pinsrw Pq,Rd/q/Mw,Ib | pinsrw Vdq,Rd/q/Mw,Ib (66),(VEX),(o128)
-c5: pextrw Gd,Nq,Ib | pextrw Gd,Udq,Ib (66),(VEX),(o128)
-c6: shufps Vps,Wps,Ib (VEX) | shufpd Vpd,Wpd,Ib (66),(VEX)
+c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1)
+c3: movnti My,Gy
+c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1)
+c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1)
+c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66)
 c7: Grp9 (1A)
 c8: BSWAP RAX/EAX/R8/R8D
 c9: BSWAP RCX/ECX/R9/R9D
@@ -524,55 +539,55 @@ cd: BSWAP RBP/EBP/R13/R13D
 ce: BSWAP RSI/ESI/R14/R14D
 cf: BSWAP RDI/EDI/R15/R15D
 # 0x0f 0xd0-0xdf
-d0: addsubps Vps,Wps (F2),(VEX) | addsubpd Vpd,Wpd (66),(VEX)
-d1: psrlw Pq,Qq | psrlw Vdq,Wdq (66),(VEX),(o128)
-d2: psrld Pq,Qq | psrld Vdq,Wdq (66),(VEX),(o128)
-d3: psrlq Pq,Qq | psrlq Vdq,Wdq (66),(VEX),(o128)
-d4: paddq Pq,Qq | paddq Vdq,Wdq (66),(VEX),(o128)
-d5: pmullw Pq,Qq | pmullw Vdq,Wdq (66),(VEX),(o128)
-d6: movq Wq,Vq (66),(VEX),(o128) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
-d7: pmovmskb Gd,Nq | pmovmskb Gd,Udq (66),(VEX),(o128)
-d8: psubusb Pq,Qq | psubusb Vdq,Wdq (66),(VEX),(o128)
-d9: psubusw Pq,Qq | psubusw Vdq,Wdq (66),(VEX),(o128)
-da: pminub Pq,Qq | pminub Vdq,Wdq (66),(VEX),(o128)
-db: pand Pq,Qq | pand Vdq,Wdq (66),(VEX),(o128)
-dc: paddusb Pq,Qq | paddusb Vdq,Wdq (66),(VEX),(o128)
-dd: paddusw Pq,Qq | paddusw Vdq,Wdq (66),(VEX),(o128)
-de: pmaxub Pq,Qq | pmaxub Vdq,Wdq (66),(VEX),(o128)
-df: pandn Pq,Qq | pandn Vdq,Wdq (66),(VEX),(o128)
+d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2)
+d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1)
+d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1)
+d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1)
+d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1)
+d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1)
+d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
+d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1)
+d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1)
+d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1)
+da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1)
+db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1)
+dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1)
+dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1)
+de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1)
+df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1)
 # 0x0f 0xe0-0xef
-e0: pavgb Pq,Qq | pavgb Vdq,Wdq (66),(VEX),(o128)
-e1: psraw Pq,Qq | psraw Vdq,Wdq (66),(VEX),(o128)
-e2: psrad Pq,Qq | psrad Vdq,Wdq (66),(VEX),(o128)
-e3: pavgw Pq,Qq | pavgw Vdq,Wdq (66),(VEX),(o128)
-e4: pmulhuw Pq,Qq | pmulhuw Vdq,Wdq (66),(VEX),(o128)
-e5: pmulhw Pq,Qq | pmulhw Vdq,Wdq (66),(VEX),(o128)
-e6: cvtpd2dq Vdq,Wpd (F2),(VEX) | cvttpd2dq Vdq,Wpd (66),(VEX) | cvtdq2pd Vpd,Wdq (F3),(VEX)
-e7: movntq Mq,Pq | movntdq Mdq,Vdq (66),(VEX)
-e8: psubsb Pq,Qq | psubsb Vdq,Wdq (66),(VEX),(o128)
-e9: psubsw Pq,Qq | psubsw Vdq,Wdq (66),(VEX),(o128)
-ea: pminsw Pq,Qq | pminsw Vdq,Wdq (66),(VEX),(o128)
-eb: por Pq,Qq | por Vdq,Wdq (66),(VEX),(o128)
-ec: paddsb Pq,Qq | paddsb Vdq,Wdq (66),(VEX),(o128)
-ed: paddsw Pq,Qq | paddsw Vdq,Wdq (66),(VEX),(o128)
-ee: pmaxsw Pq,Qq | pmaxsw Vdq,Wdq (66),(VEX),(o128)
-ef: pxor Pq,Qq | pxor Vdq,Wdq (66),(VEX),(o128)
+e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1)
+e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1)
+e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1)
+e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1)
+e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1)
+e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1)
+e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2)
+e7: movntq Mq,Pq | vmovntdq Mx,Vx (66)
+e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1)
+e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1)
+ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1)
+eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1)
+ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1)
+ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1)
+ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1)
+ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1)
 # 0x0f 0xf0-0xff
-f0: lddqu Vdq,Mdq (F2),(VEX)
-f1: psllw Pq,Qq | psllw Vdq,Wdq (66),(VEX),(o128)
-f2: pslld Pq,Qq | pslld Vdq,Wdq (66),(VEX),(o128)
-f3: psllq Pq,Qq | psllq Vdq,Wdq (66),(VEX),(o128)
-f4: pmuludq Pq,Qq | pmuludq Vdq,Wdq (66),(VEX),(o128)
-f5: pmaddwd Pq,Qq | pmaddwd Vdq,Wdq (66),(VEX),(o128)
-f6: psadbw Pq,Qq | psadbw Vdq,Wdq (66),(VEX),(o128)
-f7: maskmovq Pq,Nq | maskmovdqu Vdq,Udq (66),(VEX),(o128)
-f8: psubb Pq,Qq | psubb Vdq,Wdq (66),(VEX),(o128)
-f9: psubw Pq,Qq | psubw Vdq,Wdq (66),(VEX),(o128)
-fa: psubd Pq,Qq | psubd Vdq,Wdq (66),(VEX),(o128)
-fb: psubq Pq,Qq | psubq Vdq,Wdq (66),(VEX),(o128)
-fc: paddb Pq,Qq | paddb Vdq,Wdq (66),(VEX),(o128)
-fd: paddw Pq,Qq | paddw Vdq,Wdq (66),(VEX),(o128)
-fe: paddd Pq,Qq | paddd Vdq,Wdq (66),(VEX),(o128)
+f0: vlddqu Vx,Mx (F2)
+f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1)
+f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1)
+f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1)
+f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1)
+f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1)
+f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1)
+f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1)
+f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1)
+f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1)
+fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1)
+fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1)
+fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1)
+fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1)
+fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1)
 ff:
 EndTable
 
@@ -580,155 +595,193 @@ Table: 3-byte opcode 1 (0x0f 0x38)
 Referrer: 3-byte escape 1
 AVXcode: 2
 # 0x0f 0x38 0x00-0x0f
-00: pshufb Pq,Qq | pshufb Vdq,Wdq (66),(VEX),(o128)
-01: phaddw Pq,Qq | phaddw Vdq,Wdq (66),(VEX),(o128)
-02: phaddd Pq,Qq | phaddd Vdq,Wdq (66),(VEX),(o128)
-03: phaddsw Pq,Qq | phaddsw Vdq,Wdq (66),(VEX),(o128)
-04: pmaddubsw Pq,Qq | pmaddubsw Vdq,Wdq (66),(VEX),(o128)
-05: phsubw Pq,Qq | phsubw Vdq,Wdq (66),(VEX),(o128)
-06: phsubd Pq,Qq | phsubd Vdq,Wdq (66),(VEX),(o128)
-07: phsubsw Pq,Qq | phsubsw Vdq,Wdq (66),(VEX),(o128)
-08: psignb Pq,Qq | psignb Vdq,Wdq (66),(VEX),(o128)
-09: psignw Pq,Qq | psignw Vdq,Wdq (66),(VEX),(o128)
-0a: psignd Pq,Qq | psignd Vdq,Wdq (66),(VEX),(o128)
-0b: pmulhrsw Pq,Qq | pmulhrsw Vdq,Wdq (66),(VEX),(o128)
-0c: Vpermilps /r (66),(oVEX)
-0d: Vpermilpd /r (66),(oVEX)
-0e: vtestps /r (66),(oVEX)
-0f: vtestpd /r (66),(oVEX)
+00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1)
+01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1)
+02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1)
+03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1)
+04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1)
+05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1)
+06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1)
+07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1)
+08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1)
+09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1)
+0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1)
+0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1)
+0c: vpermilps Vx,Hx,Wx (66),(v)
+0d: vpermilpd Vx,Hx,Wx (66),(v)
+0e: vtestps Vx,Wx (66),(v)
+0f: vtestpd Vx,Wx (66),(v)
 # 0x0f 0x38 0x10-0x1f
 10: pblendvb Vdq,Wdq (66)
 11:
 12:
-13:
+13: vcvtph2ps Vx,Wx,Ib (66),(v)
 14: blendvps Vdq,Wdq (66)
 15: blendvpd Vdq,Wdq (66)
-16:
-17: ptest Vdq,Wdq (66),(VEX)
-18: vbroadcastss /r (66),(oVEX)
-19: vbroadcastsd /r (66),(oVEX),(o256)
-1a: vbroadcastf128 /r (66),(oVEX),(o256)
+16: vpermps Vqq,Hqq,Wqq (66),(v)
+17: vptest Vx,Wx (66)
+18: vbroadcastss Vx,Wd (66),(v)
+19: vbroadcastsd Vqq,Wq (66),(v)
+1a: vbroadcastf128 Vqq,Mdq (66),(v)
 1b:
-1c: pabsb Pq,Qq | pabsb Vdq,Wdq (66),(VEX),(o128)
-1d: pabsw Pq,Qq | pabsw Vdq,Wdq (66),(VEX),(o128)
-1e: pabsd Pq,Qq | pabsd Vdq,Wdq (66),(VEX),(o128)
+1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1)
+1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1)
+1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1)
 1f:
 # 0x0f 0x38 0x20-0x2f
-20: pmovsxbw Vdq,Udq/Mq (66),(VEX),(o128)
-21: pmovsxbd Vdq,Udq/Md (66),(VEX),(o128)
-22: pmovsxbq Vdq,Udq/Mw (66),(VEX),(o128)
-23: pmovsxwd Vdq,Udq/Mq (66),(VEX),(o128)
-24: pmovsxwq Vdq,Udq/Md (66),(VEX),(o128)
-25: pmovsxdq Vdq,Udq/Mq (66),(VEX),(o128)
+20: vpmovsxbw Vx,Ux/Mq (66),(v1)
+21: vpmovsxbd Vx,Ux/Md (66),(v1)
+22: vpmovsxbq Vx,Ux/Mw (66),(v1)
+23: vpmovsxwd Vx,Ux/Mq (66),(v1)
+24: vpmovsxwq Vx,Ux/Md (66),(v1)
+25: vpmovsxdq Vx,Ux/Mq (66),(v1)
 26:
 27:
-28: pmuldq Vdq,Wdq (66),(VEX),(o128)
-29: pcmpeqq Vdq,Wdq (66),(VEX),(o128)
-2a: movntdqa Vdq,Mdq (66),(VEX),(o128)
-2b: packusdw Vdq,Wdq (66),(VEX),(o128)
-2c: vmaskmovps(ld) /r (66),(oVEX)
-2d: vmaskmovpd(ld) /r (66),(oVEX)
-2e: vmaskmovps(st) /r (66),(oVEX)
-2f: vmaskmovpd(st) /r (66),(oVEX)
+28: vpmuldq Vx,Hx,Wx (66),(v1)
+29: vpcmpeqq Vx,Hx,Wx (66),(v1)
+2a: vmovntdqa Vx,Mx (66),(v1)
+2b: vpackusdw Vx,Hx,Wx (66),(v1)
+2c: vmaskmovps Vx,Hx,Mx (66),(v)
+2d: vmaskmovpd Vx,Hx,Mx (66),(v)
+2e: vmaskmovps Mx,Hx,Vx (66),(v)
+2f: vmaskmovpd Mx,Hx,Vx (66),(v)
 # 0x0f 0x38 0x30-0x3f
-30: pmovzxbw Vdq,Udq/Mq (66),(VEX),(o128)
-31: pmovzxbd Vdq,Udq/Md (66),(VEX),(o128)
-32: pmovzxbq Vdq,Udq/Mw (66),(VEX),(o128)
-33: pmovzxwd Vdq,Udq/Mq (66),(VEX),(o128)
-34: pmovzxwq Vdq,Udq/Md (66),(VEX),(o128)
-35: pmovzxdq Vdq,Udq/Mq (66),(VEX),(o128)
-36:
-37: pcmpgtq Vdq,Wdq (66),(VEX),(o128)
-38: pminsb Vdq,Wdq (66),(VEX),(o128)
-39: pminsd Vdq,Wdq (66),(VEX),(o128)
-3a: pminuw Vdq,Wdq (66),(VEX),(o128)
-3b: pminud Vdq,Wdq (66),(VEX),(o128)
-3c: pmaxsb Vdq,Wdq (66),(VEX),(o128)
-3d: pmaxsd Vdq,Wdq (66),(VEX),(o128)
-3e: pmaxuw Vdq,Wdq (66),(VEX),(o128)
-3f: pmaxud Vdq,Wdq (66),(VEX),(o128)
+30: vpmovzxbw Vx,Ux/Mq (66),(v1)
+31: vpmovzxbd Vx,Ux/Md (66),(v1)
+32: vpmovzxbq Vx,Ux/Mw (66),(v1)
+33: vpmovzxwd Vx,Ux/Mq (66),(v1)
+34: vpmovzxwq Vx,Ux/Md (66),(v1)
+35: vpmovzxdq Vx,Ux/Mq (66),(v1)
+36: vpermd Vqq,Hqq,Wqq (66),(v)
+37: vpcmpgtq Vx,Hx,Wx (66),(v1)
+38: vpminsb Vx,Hx,Wx (66),(v1)
+39: vpminsd Vx,Hx,Wx (66),(v1)
+3a: vpminuw Vx,Hx,Wx (66),(v1)
+3b: vpminud Vx,Hx,Wx (66),(v1)
+3c: vpmaxsb Vx,Hx,Wx (66),(v1)
+3d: vpmaxsd Vx,Hx,Wx (66),(v1)
+3e: vpmaxuw Vx,Hx,Wx (66),(v1)
+3f: vpmaxud Vx,Hx,Wx (66),(v1)
 # 0x0f 0x38 0x40-0x8f
-40: pmulld Vdq,Wdq (66),(VEX),(o128)
-41: phminposuw Vdq,Wdq (66),(VEX),(o128)
-80: INVEPT Gd/q,Mdq (66)
-81: INVPID Gd/q,Mdq (66)
+40: vpmulld Vx,Hx,Wx (66),(v1)
+41: vphminposuw Vdq,Wdq (66),(v1)
+42:
+43:
+44:
+45: vpsrlvd/q Vx,Hx,Wx (66),(v)
+46: vpsravd Vx,Hx,Wx (66),(v)
+47: vpsllvd/q Vx,Hx,Wx (66),(v)
+# Skip 0x48-0x57
+58: vpbroadcastd Vx,Wx (66),(v)
+59: vpbroadcastq Vx,Wx (66),(v)
+5a: vbroadcasti128 Vqq,Mdq (66),(v)
+# Skip 0x5b-0x77
+78: vpbroadcastb Vx,Wx (66),(v)
+79: vpbroadcastw Vx,Wx (66),(v)
+# Skip 0x7a-0x7f
+80: INVEPT Gy,Mdq (66)
+81: INVPID Gy,Mdq (66)
+82: INVPCID Gy,Mdq (66)
+8c: vpmaskmovd/q Vx,Hx,Mx (66),(v)
+8e: vpmaskmovd/q Mx,Vx,Hx (66),(v)
 # 0x0f 0x38 0x90-0xbf (FMA)
-96: vfmaddsub132pd/ps /r (66),(VEX)
-97: vfmsubadd132pd/ps /r (66),(VEX)
-98: vfmadd132pd/ps /r (66),(VEX)
-99: vfmadd132sd/ss /r (66),(VEX),(o128)
-9a: vfmsub132pd/ps /r (66),(VEX)
-9b: vfmsub132sd/ss /r (66),(VEX),(o128)
-9c: vfnmadd132pd/ps /r (66),(VEX)
-9d: vfnmadd132sd/ss /r (66),(VEX),(o128)
-9e: vfnmsub132pd/ps /r (66),(VEX)
-9f: vfnmsub132sd/ss /r (66),(VEX),(o128)
-a6: vfmaddsub213pd/ps /r (66),(VEX)
-a7: vfmsubadd213pd/ps /r (66),(VEX)
-a8: vfmadd213pd/ps /r (66),(VEX)
-a9: vfmadd213sd/ss /r (66),(VEX),(o128)
-aa: vfmsub213pd/ps /r (66),(VEX)
-ab: vfmsub213sd/ss /r (66),(VEX),(o128)
-ac: vfnmadd213pd/ps /r (66),(VEX)
-ad: vfnmadd213sd/ss /r (66),(VEX),(o128)
-ae: vfnmsub213pd/ps /r (66),(VEX)
-af: vfnmsub213sd/ss /r (66),(VEX),(o128)
-b6: vfmaddsub231pd/ps /r (66),(VEX)
-b7: vfmsubadd231pd/ps /r (66),(VEX)
-b8: vfmadd231pd/ps /r (66),(VEX)
-b9: vfmadd231sd/ss /r (66),(VEX),(o128)
-ba: vfmsub231pd/ps /r (66),(VEX)
-bb: vfmsub231sd/ss /r (66),(VEX),(o128)
-bc: vfnmadd231pd/ps /r (66),(VEX)
-bd: vfnmadd231sd/ss /r (66),(VEX),(o128)
-be: vfnmsub231pd/ps /r (66),(VEX)
-bf: vfnmsub231sd/ss /r (66),(VEX),(o128)
+90: vgatherdd/q Vx,Hx,Wx (66),(v)
+91: vgatherqd/q Vx,Hx,Wx (66),(v)
+92: vgatherdps/d Vx,Hx,Wx (66),(v)
+93: vgatherqps/d Vx,Hx,Wx (66),(v)
+94:
+95:
+96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v)
+97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v)
+98: vfmadd132ps/d Vx,Hx,Wx (66),(v)
+99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
+9a: vfmsub132ps/d Vx,Hx,Wx (66),(v)
+9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
+9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v)
+9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
+9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v)
+9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
+a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v)
+a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v)
+a8: vfmadd213ps/d Vx,Hx,Wx (66),(v)
+a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
+aa: vfmsub213ps/d Vx,Hx,Wx (66),(v)
+ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
+ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v)
+ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
+ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v)
+af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
+b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v)
+b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v)
+b8: vfmadd231ps/d Vx,Hx,Wx (66),(v)
+b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
+ba: vfmsub231ps/d Vx,Hx,Wx (66),(v)
+bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
+bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v)
+bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
+be: vfnmsub231ps/d Vx,Hx,Wx (66),(v)
+bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
 # 0x0f 0x38 0xc0-0xff
-db: aesimc Vdq,Wdq (66),(VEX),(o128)
-dc: aesenc Vdq,Wdq (66),(VEX),(o128)
-dd: aesenclast Vdq,Wdq (66),(VEX),(o128)
-de: aesdec Vdq,Wdq (66),(VEX),(o128)
-df: aesdeclast Vdq,Wdq (66),(VEX),(o128)
-f0: MOVBE Gv,Mv | CRC32 Gd,Eb (F2)
-f1: MOVBE Mv,Gv | CRC32 Gd,Ev (F2)
+db: VAESIMC Vdq,Wdq (66),(v1)
+dc: VAESENC Vdq,Hdq,Wdq (66),(v1)
+dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
+de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
+df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
+f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2)
+f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2)
+f3: ANDN Gy,By,Ey (v)
+f4: Grp17 (1A)
+f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
+f6: MULX By,Gy,rDX,Ey (F2),(v)
+f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
 EndTable
 
 Table: 3-byte opcode 2 (0x0f 0x3a)
 Referrer: 3-byte escape 2
 AVXcode: 3
 # 0x0f 0x3a 0x00-0xff
-04: vpermilps /r,Ib (66),(oVEX)
-05: vpermilpd /r,Ib (66),(oVEX)
-06: vperm2f128 /r,Ib (66),(oVEX),(o256)
-08: roundps Vdq,Wdq,Ib (66),(VEX)
-09: roundpd Vdq,Wdq,Ib (66),(VEX)
-0a: roundss Vss,Wss,Ib (66),(VEX),(o128)
-0b: roundsd Vsd,Wsd,Ib (66),(VEX),(o128)
-0c: blendps Vdq,Wdq,Ib (66),(VEX)
-0d: blendpd Vdq,Wdq,Ib (66),(VEX)
-0e: pblendw Vdq,Wdq,Ib (66),(VEX),(o128)
-0f: palignr Pq,Qq,Ib | palignr Vdq,Wdq,Ib (66),(VEX),(o128)
-14: pextrb Rd/Mb,Vdq,Ib (66),(VEX),(o128)
-15: pextrw Rd/Mw,Vdq,Ib (66),(VEX),(o128)
-16: pextrd/pextrq Ed/q,Vdq,Ib (66),(VEX),(o128)
-17: extractps Ed,Vdq,Ib (66),(VEX),(o128)
-18: vinsertf128 /r,Ib (66),(oVEX),(o256)
-19: vextractf128 /r,Ib (66),(oVEX),(o256)
-20: pinsrb Vdq,Rd/q/Mb,Ib (66),(VEX),(o128)
-21: insertps Vdq,Udq/Md,Ib (66),(VEX),(o128)
-22: pinsrd/pinsrq Vdq,Ed/q,Ib (66),(VEX),(o128)
-40: dpps Vdq,Wdq,Ib (66),(VEX)
-41: dppd Vdq,Wdq,Ib (66),(VEX),(o128)
-42: mpsadbw Vdq,Wdq,Ib (66),(VEX),(o128)
-44: pclmulq Vdq,Wdq,Ib (66),(VEX),(o128)
-4a: vblendvps /r,Ib (66),(oVEX)
-4b: vblendvpd /r,Ib (66),(oVEX)
-4c: vpblendvb /r,Ib (66),(oVEX),(o128)
-60: pcmpestrm Vdq,Wdq,Ib (66),(VEX),(o128)
-61: pcmpestri Vdq,Wdq,Ib (66),(VEX),(o128)
-62: pcmpistrm Vdq,Wdq,Ib (66),(VEX),(o128)
-63: pcmpistri Vdq,Wdq,Ib (66),(VEX),(o128)
-df: aeskeygenassist Vdq,Wdq,Ib (66),(VEX),(o128)
+00: vpermq Vqq,Wqq,Ib (66),(v)
+01: vpermpd Vqq,Wqq,Ib (66),(v)
+02: vpblendd Vx,Hx,Wx,Ib (66),(v)
+03:
+04: vpermilps Vx,Wx,Ib (66),(v)
+05: vpermilpd Vx,Wx,Ib (66),(v)
+06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v)
+07:
+08: vroundps Vx,Wx,Ib (66)
+09: vroundpd Vx,Wx,Ib (66)
+0a: vroundss Vss,Wss,Ib (66),(v1)
+0b: vroundsd Vsd,Wsd,Ib (66),(v1)
+0c: vblendps Vx,Hx,Wx,Ib (66)
+0d: vblendpd Vx,Hx,Wx,Ib (66)
+0e: vpblendw Vx,Hx,Wx,Ib (66),(v1)
+0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1)
+14: vpextrb Rd/Mb,Vdq,Ib (66),(v1)
+15: vpextrw Rd/Mw,Vdq,Ib (66),(v1)
+16: vpextrd/q Ey,Vdq,Ib (66),(v1)
+17: vextractps Ed,Vdq,Ib (66),(v1)
+18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v)
+19: vextractf128 Wdq,Vqq,Ib (66),(v)
+1d: vcvtps2ph Wx,Vx,Ib (66),(v)
+20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1)
+21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1)
+22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1)
+38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v)
+39: vextracti128 Wdq,Vqq,Ib (66),(v)
+40: vdpps Vx,Hx,Wx,Ib (66)
+41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1)
+42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1)
+44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1)
+46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v)
+4a: vblendvps Vx,Hx,Wx,Lx (66),(v)
+4b: vblendvpd Vx,Hx,Wx,Lx (66),(v)
+4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1)
+60: vpcmpestrm Vdq,Wdq,Ib (66),(v1)
+61: vpcmpestri Vdq,Wdq,Ib (66),(v1)
+62: vpcmpistrm Vdq,Wdq,Ib (66),(v1)
+63: vpcmpistri Vdq,Wdq,Ib (66),(v1)
+df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1)
+f0: RORX Gy,Ey,Ib (F2),(v)
 EndTable
 
 GrpTable: Grp1
@@ -790,7 +843,7 @@ GrpTable: Grp5
 2: CALLN Ev (f64)
 3: CALLF Ep
 4: JMPN Ev (f64)
-5: JMPF Ep
+5: JMPF Mp
 6: PUSH Ev (d64)
 7:
 EndTable
@@ -807,7 +860,7 @@ EndTable
 GrpTable: Grp7
 0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
 1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001)
-2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B)
+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B)
 3: LIDT Ms
 4: SMSW Mw/Rv
 5:
@@ -824,44 +877,45 @@ EndTable
 
 GrpTable: Grp9
 1: CMPXCHG8B/16B Mq/Mdq
-6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3)
-7: VMPTRST Mq
+6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B)
+7: VMPTRST Mq | VMPTRST Mq (F3)
 EndTable
 
 GrpTable: Grp10
 EndTable
 
 GrpTable: Grp11
+# Note: the operands are given by group opcode
 0: MOV
 EndTable
 
 GrpTable: Grp12
-2: psrlw Nq,Ib (11B) | psrlw Udq,Ib (66),(11B),(VEX),(o128)
-4: psraw Nq,Ib (11B) | psraw Udq,Ib (66),(11B),(VEX),(o128)
-6: psllw Nq,Ib (11B) | psllw Udq,Ib (66),(11B),(VEX),(o128)
+2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1)
+4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1)
+6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1)
 EndTable
 
 GrpTable: Grp13
-2: psrld Nq,Ib (11B) | psrld Udq,Ib (66),(11B),(VEX),(o128)
-4: psrad Nq,Ib (11B) | psrad Udq,Ib (66),(11B),(VEX),(o128)
-6: pslld Nq,Ib (11B) | pslld Udq,Ib (66),(11B),(VEX),(o128)
+2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1)
+4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1)
+6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1)
 EndTable
 
 GrpTable: Grp14
-2: psrlq Nq,Ib (11B) | psrlq Udq,Ib (66),(11B),(VEX),(o128)
-3: psrldq Udq,Ib (66),(11B),(VEX),(o128)
-6: psllq Nq,Ib (11B) | psllq Udq,Ib (66),(11B),(VEX),(o128)
-7: pslldq Udq,Ib (66),(11B),(VEX),(o128)
+2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1)
+3: vpsrldq Hx,Ux,Ib (66),(11B),(v1)
+6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1)
+7: vpslldq Hx,Ux,Ib (66),(11B),(v1)
 EndTable
 
 GrpTable: Grp15
-0: fxsave
-1: fxstor
-2: ldmxcsr (VEX)
-3: stmxcsr (VEX)
+0: fxsave | RDFSBASE Ry (F3),(11B)
+1: fxstor | RDGSBASE Ry (F3),(11B)
+2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B)
+3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B)
 4: XSAVE
 5: XRSTOR | lfence (11B)
-6: mfence (11B)
+6: XSAVEOPT | mfence (11B)
 7: clflush | sfence (11B)
 EndTable
 
@@ -872,6 +926,12 @@ GrpTable: Grp16
 3: prefetch T2
 EndTable
 
+GrpTable: Grp17
+1: BLSR By,Ey (v)
+2: BLSMSK By,Ey (v)
+3: BLSI By,Ey (v)
+EndTable
+
 # AMD's Prefetch Group
 GrpTable: GrpP
 0: PREFETCH
index 446902b..1599f56 100644 (file)
@@ -4,9 +4,8 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                oprof.o cpu_buffer.o buffer_sync.o \
                event_buffer.o oprofile_files.o \
                oprofilefs.o oprofile_stats.o  \
-               timer_int.o )
+               timer_int.o nmi_timer_int.o )
 
 oprofile-y                             := $(DRIVER_OBJS) init.o backtrace.o
 oprofile-$(CONFIG_X86_LOCAL_APIC)      += nmi_int.o op_model_amd.o \
                                           op_model_ppro.o op_model_p4.o
-oprofile-$(CONFIG_X86_IO_APIC)         += nmi_timer_int.o
index f148cf6..9e138d0 100644 (file)
  * with the NMI mode driver.
  */
 
+#ifdef CONFIG_X86_LOCAL_APIC
 extern int op_nmi_init(struct oprofile_operations *ops);
-extern int op_nmi_timer_init(struct oprofile_operations *ops);
 extern void op_nmi_exit(void);
-extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
+#else
+static int op_nmi_init(struct oprofile_operations *ops) { return -ENODEV; }
+static void op_nmi_exit(void) { }
+#endif
 
-static int nmi_timer;
+extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       int ret;
-
-       ret = -ENODEV;
-
-#ifdef CONFIG_X86_LOCAL_APIC
-       ret = op_nmi_init(ops);
-#endif
-       nmi_timer = (ret != 0);
-#ifdef CONFIG_X86_IO_APIC
-       if (nmi_timer)
-               ret = op_nmi_timer_init(ops);
-#endif
        ops->backtrace = x86_backtrace;
-
-       return ret;
+       return op_nmi_init(ops);
 }
 
-
 void oprofile_arch_exit(void)
 {
-#ifdef CONFIG_X86_LOCAL_APIC
-       if (!nmi_timer)
-               op_nmi_exit();
-#endif
+       op_nmi_exit();
 }
index 75f9528..26b8a85 100644 (file)
@@ -595,24 +595,36 @@ static int __init p4_init(char **cpu_type)
        return 0;
 }
 
-static int force_arch_perfmon;
-static int force_cpu_type(const char *str, struct kernel_param *kp)
+enum __force_cpu_type {
+       reserved = 0,           /* do not force */
+       timer,
+       arch_perfmon,
+};
+
+static int force_cpu_type;
+
+static int set_cpu_type(const char *str, struct kernel_param *kp)
 {
-       if (!strcmp(str, "arch_perfmon")) {
-               force_arch_perfmon = 1;
+       if (!strcmp(str, "timer")) {
+               force_cpu_type = timer;
+               printk(KERN_INFO "oprofile: forcing NMI timer mode\n");
+       } else if (!strcmp(str, "arch_perfmon")) {
+               force_cpu_type = arch_perfmon;
                printk(KERN_INFO "oprofile: forcing architectural perfmon\n");
+       } else {
+               force_cpu_type = 0;
        }
 
        return 0;
 }
-module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0);
+module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0);
 
 static int __init ppro_init(char **cpu_type)
 {
        __u8 cpu_model = boot_cpu_data.x86_model;
        struct op_x86_model_spec *spec = &op_ppro_spec; /* default */
 
-       if (force_arch_perfmon && cpu_has_arch_perfmon)
+       if (force_cpu_type == arch_perfmon && cpu_has_arch_perfmon)
                return 0;
 
        /*
@@ -679,6 +691,9 @@ int __init op_nmi_init(struct oprofile_operations *ops)
        if (!cpu_has_apic)
                return -ENODEV;
 
+       if (force_cpu_type == timer)
+               return -ENODEV;
+
        switch (vendor) {
        case X86_VENDOR_AMD:
                /* Needs to be at least an Athlon (or hammer in 32bit mode) */
diff --git a/arch/x86/oprofile/nmi_timer_int.c b/arch/x86/oprofile/nmi_timer_int.c
deleted file mode 100644 (file)
index 7f8052c..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @file nmi_timer_int.c
- *
- * @remark Copyright 2003 OProfile authors
- * @remark Read the file COPYING
- *
- * @author Zwane Mwaikambo <zwane@linuxpower.ca>
- */
-
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/errno.h>
-#include <linux/oprofile.h>
-#include <linux/rcupdate.h>
-#include <linux/kdebug.h>
-
-#include <asm/nmi.h>
-#include <asm/apic.h>
-#include <asm/ptrace.h>
-
-static int profile_timer_exceptions_notify(unsigned int val, struct pt_regs *regs)
-{
-       oprofile_add_sample(regs, 0);
-       return NMI_HANDLED;
-}
-
-static int timer_start(void)
-{
-       if (register_nmi_handler(NMI_LOCAL, profile_timer_exceptions_notify,
-                                       0, "oprofile-timer"))
-               return 1;
-       return 0;
-}
-
-
-static void timer_stop(void)
-{
-       unregister_nmi_handler(NMI_LOCAL, "oprofile-timer");
-       synchronize_sched();  /* Allow already-started NMIs to complete. */
-}
-
-
-int __init op_nmi_timer_init(struct oprofile_operations *ops)
-{
-       ops->start = timer_start;
-       ops->stop = timer_stop;
-       ops->cpu_type = "timer";
-       printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
-       return 0;
-}
index f820826..d511aa9 100644 (file)
@@ -18,14 +18,21 @@ chkobjdump = $(srctree)/arch/x86/tools/chkobjdump.awk
 quiet_cmd_posttest = TEST    $@
       cmd_posttest = ($(OBJDUMP) -v | $(AWK) -f $(chkobjdump)) || $(OBJDUMP) -d -j .text $(objtree)/vmlinux | $(AWK) -f $(distill_awk) | $(obj)/test_get_len $(posttest_64bit) $(posttest_verbose)
 
-posttest: $(obj)/test_get_len vmlinux
+quiet_cmd_sanitytest = TEST    $@
+      cmd_sanitytest = $(obj)/insn_sanity $(posttest_64bit) -m 1000000
+
+posttest: $(obj)/test_get_len vmlinux $(obj)/insn_sanity
        $(call cmd,posttest)
+       $(call cmd,sanitytest)
 
-hostprogs-y    := test_get_len
+hostprogs-y    += test_get_len insn_sanity
 
 # -I needed for generated C source and C source which in the kernel tree.
 HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/
 
+HOSTCFLAGS_insn_sanity.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/
+
 # Dependencies are also needed.
 $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
 
+$(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
index eaf11f5..5f6a5b6 100644 (file)
@@ -47,7 +47,7 @@ BEGIN {
        sep_expr = "^\\|$"
        group_expr = "^Grp[0-9A-Za-z]+"
 
-       imm_expr = "^[IJAO][a-z]"
+       imm_expr = "^[IJAOL][a-z]"
        imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
        imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
        imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
@@ -59,6 +59,7 @@ BEGIN {
        imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
        imm_flag["Ob"] = "INAT_MOFFSET"
        imm_flag["Ov"] = "INAT_MOFFSET"
+       imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
 
        modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
        force64_expr = "\\([df]64\\)"
@@ -70,8 +71,12 @@ BEGIN {
        lprefix3_expr = "\\(F2\\)"
        max_lprefix = 4
 
-       vexok_expr = "\\(VEX\\)"
-       vexonly_expr = "\\(oVEX\\)"
+       # All opcodes starting with lower-case 'v' or with (v1) superscript
+       # accepts VEX prefix
+       vexok_opcode_expr = "^v.*"
+       vexok_expr = "\\(v1\\)"
+       # All opcodes with (v) superscript supports *only* VEX prefix
+       vexonly_expr = "\\(v\\)"
 
        prefix_expr = "\\(Prefix\\)"
        prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
@@ -85,8 +90,8 @@ BEGIN {
        prefix_num["SEG=GS"] = "INAT_PFX_GS"
        prefix_num["SEG=SS"] = "INAT_PFX_SS"
        prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
-       prefix_num["2bytes-VEX"] = "INAT_PFX_VEX2"
-       prefix_num["3bytes-VEX"] = "INAT_PFX_VEX3"
+       prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
+       prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
 
        clear_vars()
 }
@@ -310,12 +315,10 @@ function convert_operands(count,opnd,       i,j,imm,mod)
                if (match(opcode, fpu_expr))
                        flags = add_flags(flags, "INAT_MODRM")
 
-               # check VEX only code
+               # check VEX codes
                if (match(ext, vexonly_expr))
                        flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
-
-               # check VEX only code
-               if (match(ext, vexok_expr))
+               else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
                        flags = add_flags(flags, "INAT_VEXOK")
 
                # check prefixes
diff --git a/arch/x86/tools/insn_sanity.c b/arch/x86/tools/insn_sanity.c
new file mode 100644 (file)
index 0000000..cc2f8c1
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * x86 decoder sanity test - based on test_get_insn.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2009
+ * Copyright (C) Hitachi, Ltd., 2011
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define unlikely(cond) (cond)
+#define ARRAY_SIZE(a)  (sizeof(a)/sizeof(a[0]))
+
+#include <asm/insn.h>
+#include <inat.c>
+#include <insn.c>
+
+/*
+ * Test of instruction analysis against tampering.
+ * Feed random binary to instruction decoder and ensure not to
+ * access out-of-instruction-buffer.
+ */
+
+#define DEFAULT_MAX_ITER       10000
+#define INSN_NOP 0x90
+
+static const char      *prog;          /* Program name */
+static int             verbose;        /* Verbosity */
+static int             x86_64;         /* x86-64 bit mode flag */
+static unsigned int    seed;           /* Random seed */
+static unsigned long   iter_start;     /* Start of iteration number */
+static unsigned long   iter_end = DEFAULT_MAX_ITER;    /* End of iteration number */
+static FILE            *input_file;    /* Input file name */
+
+static void usage(const char *err)
+{
+       if (err)
+               fprintf(stderr, "Error: %s\n\n", err);
+       fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog);
+       fprintf(stderr, "\t-y   64bit mode\n");
+       fprintf(stderr, "\t-n   32bit mode\n");
+       fprintf(stderr, "\t-v   Verbosity(-vv dumps any decoded result)\n");
+       fprintf(stderr, "\t-s   Give a random seed (and iteration number)\n");
+       fprintf(stderr, "\t-m   Give a maximum iteration number\n");
+       fprintf(stderr, "\t-i   Give an input file with decoded binary\n");
+       exit(1);
+}
+
+static void dump_field(FILE *fp, const char *name, const char *indent,
+                      struct insn_field *field)
+{
+       fprintf(fp, "%s.%s = {\n", indent, name);
+       fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
+               indent, field->value, field->bytes[0], field->bytes[1],
+               field->bytes[2], field->bytes[3]);
+       fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
+               field->got, field->nbytes);
+}
+
+static void dump_insn(FILE *fp, struct insn *insn)
+{
+       fprintf(fp, "Instruction = {\n");
+       dump_field(fp, "prefixes", "\t",        &insn->prefixes);
+       dump_field(fp, "rex_prefix", "\t",      &insn->rex_prefix);
+       dump_field(fp, "vex_prefix", "\t",      &insn->vex_prefix);
+       dump_field(fp, "opcode", "\t",          &insn->opcode);
+       dump_field(fp, "modrm", "\t",           &insn->modrm);
+       dump_field(fp, "sib", "\t",             &insn->sib);
+       dump_field(fp, "displacement", "\t",    &insn->displacement);
+       dump_field(fp, "immediate1", "\t",      &insn->immediate1);
+       dump_field(fp, "immediate2", "\t",      &insn->immediate2);
+       fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
+               insn->attr, insn->opnd_bytes, insn->addr_bytes);
+       fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
+               insn->length, insn->x86_64, insn->kaddr);
+}
+
+static void dump_stream(FILE *fp, const char *msg, unsigned long nr_iter,
+                       unsigned char *insn_buf, struct insn *insn)
+{
+       int i;
+
+       fprintf(fp, "%s:\n", msg);
+
+       dump_insn(fp, insn);
+
+       fprintf(fp, "You can reproduce this with below command(s);\n");
+
+       /* Input a decoded instruction sequence directly */
+       fprintf(fp, " $ echo ");
+       for (i = 0; i < MAX_INSN_SIZE; i++)
+               fprintf(fp, " %02x", insn_buf[i]);
+       fprintf(fp, " | %s -i -\n", prog);
+
+       if (!input_file) {
+               fprintf(fp, "Or \n");
+               /* Give a seed and iteration number */
+               fprintf(fp, " $ %s -s 0x%x,%lu\n", prog, seed, nr_iter);
+       }
+}
+
+static void init_random_seed(void)
+{
+       int fd;
+
+       fd = open("/dev/urandom", O_RDONLY);
+       if (fd < 0)
+               goto fail;
+
+       if (read(fd, &seed, sizeof(seed)) != sizeof(seed))
+               goto fail;
+
+       close(fd);
+       return;
+fail:
+       usage("Failed to open /dev/urandom");
+}
+
+/* Read given instruction sequence from the input file */
+static int read_next_insn(unsigned char *insn_buf)
+{
+       char buf[256]  = "", *tmp;
+       int i;
+
+       tmp = fgets(buf, ARRAY_SIZE(buf), input_file);
+       if (tmp == NULL || feof(input_file))
+               return 0;
+
+       for (i = 0; i < MAX_INSN_SIZE; i++) {
+               insn_buf[i] = (unsigned char)strtoul(tmp, &tmp, 16);
+               if (*tmp != ' ')
+                       break;
+       }
+
+       return i;
+}
+
+static int generate_insn(unsigned char *insn_buf)
+{
+       int i;
+
+       if (input_file)
+               return read_next_insn(insn_buf);
+
+       /* Fills buffer with random binary up to MAX_INSN_SIZE */
+       for (i = 0; i < MAX_INSN_SIZE - 1; i += 2)
+               *(unsigned short *)(&insn_buf[i]) = random() & 0xffff;
+
+       while (i < MAX_INSN_SIZE)
+               insn_buf[i++] = random() & 0xff;
+
+       return i;
+}
+
+static void parse_args(int argc, char **argv)
+{
+       int c;
+       char *tmp = NULL;
+       int set_seed = 0;
+
+       prog = argv[0];
+       while ((c = getopt(argc, argv, "ynvs:m:i:")) != -1) {
+               switch (c) {
+               case 'y':
+                       x86_64 = 1;
+                       break;
+               case 'n':
+                       x86_64 = 0;
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               case 'i':
+                       if (strcmp("-", optarg) == 0)
+                               input_file = stdin;
+                       else
+                               input_file = fopen(optarg, "r");
+                       if (!input_file)
+                               usage("Failed to open input file");
+                       break;
+               case 's':
+                       seed = (unsigned int)strtoul(optarg, &tmp, 0);
+                       if (*tmp == ',') {
+                               optarg = tmp + 1;
+                               iter_start = strtoul(optarg, &tmp, 0);
+                       }
+                       if (*tmp != '\0' || tmp == optarg)
+                               usage("Failed to parse seed");
+                       set_seed = 1;
+                       break;
+               case 'm':
+                       iter_end = strtoul(optarg, &tmp, 0);
+                       if (*tmp != '\0' || tmp == optarg)
+                               usage("Failed to parse max_iter");
+                       break;
+               default:
+                       usage(NULL);
+               }
+       }
+
+       /* Check errors */
+       if (iter_end < iter_start)
+               usage("Max iteration number must be bigger than iter-num");
+
+       if (set_seed && input_file)
+               usage("Don't use input file (-i) with random seed (-s)");
+
+       /* Initialize random seed */
+       if (!input_file) {
+               if (!set_seed)  /* No seed is given */
+                       init_random_seed();
+               srand(seed);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       struct insn insn;
+       int insns = 0;
+       int errors = 0;
+       unsigned long i;
+       unsigned char insn_buf[MAX_INSN_SIZE * 2];
+
+       parse_args(argc, argv);
+
+       /* Prepare stop bytes with NOPs */
+       memset(insn_buf + MAX_INSN_SIZE, INSN_NOP, MAX_INSN_SIZE);
+
+       for (i = 0; i < iter_end; i++) {
+               if (generate_insn(insn_buf) <= 0)
+                       break;
+
+               if (i < iter_start)     /* Skip to given iteration number */
+                       continue;
+
+               /* Decode an instruction */
+               insn_init(&insn, insn_buf, x86_64);
+               insn_get_length(&insn);
+
+               if (insn.next_byte <= insn.kaddr ||
+                   insn.kaddr + MAX_INSN_SIZE < insn.next_byte) {
+                       /* Access out-of-range memory */
+                       dump_stream(stderr, "Error: Found an access violation", i, insn_buf, &insn);
+                       errors++;
+               } else if (verbose && !insn_complete(&insn))
+                       dump_stream(stdout, "Info: Found an undecodable input", i, insn_buf, &insn);
+               else if (verbose >= 2)
+                       dump_insn(stdout, &insn);
+               insns++;
+       }
+
+       fprintf(stdout, "%s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", (errors) ? "Failure" : "Success", insns, (input_file) ? "given" : "random", errors, seed);
+
+       return errors ? 1 : 0;
+}
diff --git a/drivers/oprofile/nmi_timer_int.c b/drivers/oprofile/nmi_timer_int.c
new file mode 100644 (file)
index 0000000..76f1c93
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+ * @file nmi_timer_int.c
+ *
+ * @remark Copyright 2011 Advanced Micro Devices, Inc.
+ *
+ * @author Robert Richter <robert.richter@amd.com>
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/oprofile.h>
+#include <linux/perf_event.h>
+
+#ifdef CONFIG_OPROFILE_NMI_TIMER
+
+static DEFINE_PER_CPU(struct perf_event *, nmi_timer_events);
+static int ctr_running;
+
+static struct perf_event_attr nmi_timer_attr = {
+       .type           = PERF_TYPE_HARDWARE,
+       .config         = PERF_COUNT_HW_CPU_CYCLES,
+       .size           = sizeof(struct perf_event_attr),
+       .pinned         = 1,
+       .disabled       = 1,
+};
+
+static void nmi_timer_callback(struct perf_event *event,
+                              struct perf_sample_data *data,
+                              struct pt_regs *regs)
+{
+       event->hw.interrupts = 0;       /* don't throttle interrupts */
+       oprofile_add_sample(regs, 0);
+}
+
+static int nmi_timer_start_cpu(int cpu)
+{
+       struct perf_event *event = per_cpu(nmi_timer_events, cpu);
+
+       if (!event) {
+               event = perf_event_create_kernel_counter(&nmi_timer_attr, cpu, NULL,
+                                                        nmi_timer_callback, NULL);
+               if (IS_ERR(event))
+                       return PTR_ERR(event);
+               per_cpu(nmi_timer_events, cpu) = event;
+       }
+
+       if (event && ctr_running)
+               perf_event_enable(event);
+
+       return 0;
+}
+
+static void nmi_timer_stop_cpu(int cpu)
+{
+       struct perf_event *event = per_cpu(nmi_timer_events, cpu);
+
+       if (event && ctr_running)
+               perf_event_disable(event);
+}
+
+static int nmi_timer_cpu_notifier(struct notifier_block *b, unsigned long action,
+                                 void *data)
+{
+       int cpu = (unsigned long)data;
+       switch (action) {
+       case CPU_DOWN_FAILED:
+       case CPU_ONLINE:
+               nmi_timer_start_cpu(cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+               nmi_timer_stop_cpu(cpu);
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block nmi_timer_cpu_nb = {
+       .notifier_call = nmi_timer_cpu_notifier
+};
+
+static int nmi_timer_start(void)
+{
+       int cpu;
+
+       get_online_cpus();
+       ctr_running = 1;
+       for_each_online_cpu(cpu)
+               nmi_timer_start_cpu(cpu);
+       put_online_cpus();
+
+       return 0;
+}
+
+static void nmi_timer_stop(void)
+{
+       int cpu;
+
+       get_online_cpus();
+       for_each_online_cpu(cpu)
+               nmi_timer_stop_cpu(cpu);
+       ctr_running = 0;
+       put_online_cpus();
+}
+
+static void nmi_timer_shutdown(void)
+{
+       struct perf_event *event;
+       int cpu;
+
+       get_online_cpus();
+       unregister_cpu_notifier(&nmi_timer_cpu_nb);
+       for_each_possible_cpu(cpu) {
+               event = per_cpu(nmi_timer_events, cpu);
+               if (!event)
+                       continue;
+               perf_event_disable(event);
+               per_cpu(nmi_timer_events, cpu) = NULL;
+               perf_event_release_kernel(event);
+       }
+
+       put_online_cpus();
+}
+
+static int nmi_timer_setup(void)
+{
+       int cpu, err;
+       u64 period;
+
+       /* clock cycles per tick: */
+       period = (u64)cpu_khz * 1000;
+       do_div(period, HZ);
+       nmi_timer_attr.sample_period = period;
+
+       get_online_cpus();
+       err = register_cpu_notifier(&nmi_timer_cpu_nb);
+       if (err)
+               goto out;
+       /* can't attach events to offline cpus: */
+       for_each_online_cpu(cpu) {
+               err = nmi_timer_start_cpu(cpu);
+               if (err)
+                       break;
+       }
+       if (err)
+               nmi_timer_shutdown();
+out:
+       put_online_cpus();
+       return err;
+}
+
+int __init op_nmi_timer_init(struct oprofile_operations *ops)
+{
+       int err = 0;
+
+       err = nmi_timer_setup();
+       if (err)
+               return err;
+       nmi_timer_shutdown();           /* only check, don't alloc */
+
+       ops->create_files       = NULL;
+       ops->setup              = nmi_timer_setup;
+       ops->shutdown           = nmi_timer_shutdown;
+       ops->start              = nmi_timer_start;
+       ops->stop               = nmi_timer_stop;
+       ops->cpu_type           = "timer";
+
+       printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
+
+       return 0;
+}
+
+#endif
index f8c752e..ed2c3ec 100644 (file)
@@ -246,37 +246,31 @@ static int __init oprofile_init(void)
        int err;
 
        /* always init architecture to setup backtrace support */
+       timer_mode = 0;
        err = oprofile_arch_init(&oprofile_ops);
+       if (!err) {
+               if (!timer && !oprofilefs_register())
+                       return 0;
+               oprofile_arch_exit();
+       }
 
-       timer_mode = err || timer;      /* fall back to timer mode on errors */
-       if (timer_mode) {
-               if (!err)
-                       oprofile_arch_exit();
+       /* setup timer mode: */
+       timer_mode = 1;
+       /* no nmi timer mode if oprofile.timer is set */
+       if (timer || op_nmi_timer_init(&oprofile_ops)) {
                err = oprofile_timer_init(&oprofile_ops);
                if (err)
                        return err;
        }
 
-       err = oprofilefs_register();
-       if (!err)
-               return 0;
-
-       /* failed */
-       if (timer_mode)
-               oprofile_timer_exit();
-       else
-               oprofile_arch_exit();
-
-       return err;
+       return oprofilefs_register();
 }
 
 
 static void __exit oprofile_exit(void)
 {
        oprofilefs_unregister();
-       if (timer_mode)
-               oprofile_timer_exit();
-       else
+       if (!timer_mode)
                oprofile_arch_exit();
 }
 
index 177b73d..769fb0f 100644 (file)
@@ -36,6 +36,15 @@ struct dentry;
 void oprofile_create_files(struct super_block *sb, struct dentry *root);
 int oprofile_timer_init(struct oprofile_operations *ops);
 void oprofile_timer_exit(void);
+#ifdef CONFIG_OPROFILE_NMI_TIMER
+int op_nmi_timer_init(struct oprofile_operations *ops);
+#else
+static inline int op_nmi_timer_init(struct oprofile_operations *ops)
+{
+       return -ENODEV;
+}
+#endif
+
 
 int oprofile_set_ulong(unsigned long *addr, unsigned long val);
 int oprofile_set_timeout(unsigned long time);
index 878fba1..93404f7 100644 (file)
@@ -97,24 +97,24 @@ static struct notifier_block __refdata oprofile_cpu_notifier = {
        .notifier_call = oprofile_cpu_notify,
 };
 
-int oprofile_timer_init(struct oprofile_operations *ops)
+static int oprofile_hrtimer_setup(void)
 {
-       int rc;
-
-       rc = register_hotcpu_notifier(&oprofile_cpu_notifier);
-       if (rc)
-               return rc;
-       ops->create_files = NULL;
-       ops->setup = NULL;
-       ops->shutdown = NULL;
-       ops->start = oprofile_hrtimer_start;
-       ops->stop = oprofile_hrtimer_stop;
-       ops->cpu_type = "timer";
-       printk(KERN_INFO "oprofile: using timer interrupt.\n");
-       return 0;
+       return register_hotcpu_notifier(&oprofile_cpu_notifier);
 }
 
-void oprofile_timer_exit(void)
+static void oprofile_hrtimer_shutdown(void)
 {
        unregister_hotcpu_notifier(&oprofile_cpu_notifier);
 }
+
+int oprofile_timer_init(struct oprofile_operations *ops)
+{
+       ops->create_files       = NULL;
+       ops->setup              = oprofile_hrtimer_setup;
+       ops->shutdown           = oprofile_hrtimer_shutdown;
+       ops->start              = oprofile_hrtimer_start;
+       ops->stop               = oprofile_hrtimer_stop;
+       ops->cpu_type           = "timer";
+       printk(KERN_INFO "oprofile: using timer interrupt.\n");
+       return 0;
+}
index 89e5e8a..22d901f 100644 (file)
@@ -2,5 +2,5 @@ ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_core.o = -pg
 endif
 
-obj-y := core.o ring_buffer.o
+obj-y := core.o ring_buffer.o callchain.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
new file mode 100644 (file)
index 0000000..057e24b
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Performance events callchain code, extracted from core.c:
+ *
+ *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ *  Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
+ *  Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright  Â©  2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ * For licensing details see kernel-base/COPYING
+ */
+
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+struct callchain_cpus_entries {
+       struct rcu_head                 rcu_head;
+       struct perf_callchain_entry     *cpu_entries[0];
+};
+
+static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]);
+static atomic_t nr_callchain_events;
+static DEFINE_MUTEX(callchain_mutex);
+static struct callchain_cpus_entries *callchain_cpus_entries;
+
+
+__weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
+                                 struct pt_regs *regs)
+{
+}
+
+__weak void perf_callchain_user(struct perf_callchain_entry *entry,
+                               struct pt_regs *regs)
+{
+}
+
+static void release_callchain_buffers_rcu(struct rcu_head *head)
+{
+       struct callchain_cpus_entries *entries;
+       int cpu;
+
+       entries = container_of(head, struct callchain_cpus_entries, rcu_head);
+
+       for_each_possible_cpu(cpu)
+               kfree(entries->cpu_entries[cpu]);
+
+       kfree(entries);
+}
+
+static void release_callchain_buffers(void)
+{
+       struct callchain_cpus_entries *entries;
+
+       entries = callchain_cpus_entries;
+       rcu_assign_pointer(callchain_cpus_entries, NULL);
+       call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
+}
+
+static int alloc_callchain_buffers(void)
+{
+       int cpu;
+       int size;
+       struct callchain_cpus_entries *entries;
+
+       /*
+        * We can't use the percpu allocation API for data that can be
+        * accessed from NMI. Use a temporary manual per cpu allocation
+        * until that gets sorted out.
+        */
+       size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
+
+       entries = kzalloc(size, GFP_KERNEL);
+       if (!entries)
+               return -ENOMEM;
+
+       size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS;
+
+       for_each_possible_cpu(cpu) {
+               entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL,
+                                                        cpu_to_node(cpu));
+               if (!entries->cpu_entries[cpu])
+                       goto fail;
+       }
+
+       rcu_assign_pointer(callchain_cpus_entries, entries);
+
+       return 0;
+
+fail:
+       for_each_possible_cpu(cpu)
+               kfree(entries->cpu_entries[cpu]);
+       kfree(entries);
+
+       return -ENOMEM;
+}
+
+int get_callchain_buffers(void)
+{
+       int err = 0;
+       int count;
+
+       mutex_lock(&callchain_mutex);
+
+       count = atomic_inc_return(&nr_callchain_events);
+       if (WARN_ON_ONCE(count < 1)) {
+               err = -EINVAL;
+               goto exit;
+       }
+
+       if (count > 1) {
+               /* If the allocation failed, give up */
+               if (!callchain_cpus_entries)
+                       err = -ENOMEM;
+               goto exit;
+       }
+
+       err = alloc_callchain_buffers();
+       if (err)
+               release_callchain_buffers();
+exit:
+       mutex_unlock(&callchain_mutex);
+
+       return err;
+}
+
+void put_callchain_buffers(void)
+{
+       if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) {
+               release_callchain_buffers();
+               mutex_unlock(&callchain_mutex);
+       }
+}
+
+static struct perf_callchain_entry *get_callchain_entry(int *rctx)
+{
+       int cpu;
+       struct callchain_cpus_entries *entries;
+
+       *rctx = get_recursion_context(__get_cpu_var(callchain_recursion));
+       if (*rctx == -1)
+               return NULL;
+
+       entries = rcu_dereference(callchain_cpus_entries);
+       if (!entries)
+               return NULL;
+
+       cpu = smp_processor_id();
+
+       return &entries->cpu_entries[cpu][*rctx];
+}
+
+static void
+put_callchain_entry(int rctx)
+{
+       put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
+}
+
+struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+{
+       int rctx;
+       struct perf_callchain_entry *entry;
+
+
+       entry = get_callchain_entry(&rctx);
+       if (rctx == -1)
+               return NULL;
+
+       if (!entry)
+               goto exit_put;
+
+       entry->nr = 0;
+
+       if (!user_mode(regs)) {
+               perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
+               perf_callchain_kernel(entry, regs);
+               if (current->mm)
+                       regs = task_pt_regs(current);
+               else
+                       regs = NULL;
+       }
+
+       if (regs) {
+               perf_callchain_store(entry, PERF_CONTEXT_USER);
+               perf_callchain_user(entry, regs);
+       }
+
+exit_put:
+       put_callchain_entry(rctx);
+
+       return entry;
+}
index 600c162..a355ffb 100644 (file)
@@ -1325,6 +1325,7 @@ retry:
        }
        raw_spin_unlock_irq(&ctx->lock);
 }
+EXPORT_SYMBOL_GPL(perf_event_disable);
 
 static void perf_set_shadow_time(struct perf_event *event,
                                 struct perf_event_context *ctx,
@@ -1809,6 +1810,7 @@ retry:
 out:
        raw_spin_unlock_irq(&ctx->lock);
 }
+EXPORT_SYMBOL_GPL(perf_event_enable);
 
 int perf_event_refresh(struct perf_event *event, int refresh)
 {
@@ -2574,215 +2576,6 @@ static u64 perf_event_read(struct perf_event *event)
 }
 
 /*
- * Callchain support
- */
-
-struct callchain_cpus_entries {
-       struct rcu_head                 rcu_head;
-       struct perf_callchain_entry     *cpu_entries[0];
-};
-
-static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]);
-static atomic_t nr_callchain_events;
-static DEFINE_MUTEX(callchain_mutex);
-struct callchain_cpus_entries *callchain_cpus_entries;
-
-
-__weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
-                                 struct pt_regs *regs)
-{
-}
-
-__weak void perf_callchain_user(struct perf_callchain_entry *entry,
-                               struct pt_regs *regs)
-{
-}
-
-static void release_callchain_buffers_rcu(struct rcu_head *head)
-{
-       struct callchain_cpus_entries *entries;
-       int cpu;
-
-       entries = container_of(head, struct callchain_cpus_entries, rcu_head);
-
-       for_each_possible_cpu(cpu)
-               kfree(entries->cpu_entries[cpu]);
-
-       kfree(entries);
-}
-
-static void release_callchain_buffers(void)
-{
-       struct callchain_cpus_entries *entries;
-
-       entries = callchain_cpus_entries;
-       rcu_assign_pointer(callchain_cpus_entries, NULL);
-       call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
-}
-
-static int alloc_callchain_buffers(void)
-{
-       int cpu;
-       int size;
-       struct callchain_cpus_entries *entries;
-
-       /*
-        * We can't use the percpu allocation API for data that can be
-        * accessed from NMI. Use a temporary manual per cpu allocation
-        * until that gets sorted out.
-        */
-       size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
-
-       entries = kzalloc(size, GFP_KERNEL);
-       if (!entries)
-               return -ENOMEM;
-
-       size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS;
-
-       for_each_possible_cpu(cpu) {
-               entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL,
-                                                        cpu_to_node(cpu));
-               if (!entries->cpu_entries[cpu])
-                       goto fail;
-       }
-
-       rcu_assign_pointer(callchain_cpus_entries, entries);
-
-       return 0;
-
-fail:
-       for_each_possible_cpu(cpu)
-               kfree(entries->cpu_entries[cpu]);
-       kfree(entries);
-
-       return -ENOMEM;
-}
-
-static int get_callchain_buffers(void)
-{
-       int err = 0;
-       int count;
-
-       mutex_lock(&callchain_mutex);
-
-       count = atomic_inc_return(&nr_callchain_events);
-       if (WARN_ON_ONCE(count < 1)) {
-               err = -EINVAL;
-               goto exit;
-       }
-
-       if (count > 1) {
-               /* If the allocation failed, give up */
-               if (!callchain_cpus_entries)
-                       err = -ENOMEM;
-               goto exit;
-       }
-
-       err = alloc_callchain_buffers();
-       if (err)
-               release_callchain_buffers();
-exit:
-       mutex_unlock(&callchain_mutex);
-
-       return err;
-}
-
-static void put_callchain_buffers(void)
-{
-       if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) {
-               release_callchain_buffers();
-               mutex_unlock(&callchain_mutex);
-       }
-}
-
-static int get_recursion_context(int *recursion)
-{
-       int rctx;
-
-       if (in_nmi())
-               rctx = 3;
-       else if (in_irq())
-               rctx = 2;
-       else if (in_softirq())
-               rctx = 1;
-       else
-               rctx = 0;
-
-       if (recursion[rctx])
-               return -1;
-
-       recursion[rctx]++;
-       barrier();
-
-       return rctx;
-}
-
-static inline void put_recursion_context(int *recursion, int rctx)
-{
-       barrier();
-       recursion[rctx]--;
-}
-
-static struct perf_callchain_entry *get_callchain_entry(int *rctx)
-{
-       int cpu;
-       struct callchain_cpus_entries *entries;
-
-       *rctx = get_recursion_context(__get_cpu_var(callchain_recursion));
-       if (*rctx == -1)
-               return NULL;
-
-       entries = rcu_dereference(callchain_cpus_entries);
-       if (!entries)
-               return NULL;
-
-       cpu = smp_processor_id();
-
-       return &entries->cpu_entries[cpu][*rctx];
-}
-
-static void
-put_callchain_entry(int rctx)
-{
-       put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
-}
-
-static struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
-{
-       int rctx;
-       struct perf_callchain_entry *entry;
-
-
-       entry = get_callchain_entry(&rctx);
-       if (rctx == -1)
-               return NULL;
-
-       if (!entry)
-               goto exit_put;
-
-       entry->nr = 0;
-
-       if (!user_mode(regs)) {
-               perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
-               perf_callchain_kernel(entry, regs);
-               if (current->mm)
-                       regs = task_pt_regs(current);
-               else
-                       regs = NULL;
-       }
-
-       if (regs) {
-               perf_callchain_store(entry, PERF_CONTEXT_USER);
-               perf_callchain_user(entry, regs);
-       }
-
-exit_put:
-       put_callchain_entry(rctx);
-
-       return entry;
-}
-
-/*
  * Initialize the perf_event context in a task_struct:
  */
 static void __perf_event_init_context(struct perf_event_context *ctx)
@@ -4816,7 +4609,6 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow,
        struct hw_perf_event *hwc = &event->hw;
        int throttle = 0;
 
-       data->period = event->hw.last_period;
        if (!overflow)
                overflow = perf_swevent_set_period(event);
 
@@ -4850,6 +4642,12 @@ static void perf_swevent_event(struct perf_event *event, u64 nr,
        if (!is_sampling_event(event))
                return;
 
+       if ((event->attr.sample_type & PERF_SAMPLE_PERIOD) && !event->attr.freq) {
+               data->period = nr;
+               return perf_swevent_overflow(event, 1, data, regs);
+       } else
+               data->period = event->hw.last_period;
+
        if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq)
                return perf_swevent_overflow(event, 1, data, regs);
 
index 64568a6..b0b107f 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _KERNEL_EVENTS_INTERNAL_H
 #define _KERNEL_EVENTS_INTERNAL_H
 
+#include <linux/hardirq.h>
+
+/* Buffer handling */
+
 #define RING_BUFFER_WRITABLE           0x01
 
 struct ring_buffer {
@@ -67,7 +71,7 @@ static inline int page_order(struct ring_buffer *rb)
 }
 #endif
 
-static unsigned long perf_data_size(struct ring_buffer *rb)
+static inline unsigned long perf_data_size(struct ring_buffer *rb)
 {
        return rb->nr_pages << (PAGE_SHIFT + page_order(rb));
 }
@@ -96,4 +100,37 @@ __output_copy(struct perf_output_handle *handle,
        } while (len);
 }
 
+/* Callchain handling */
+extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
+extern int get_callchain_buffers(void);
+extern void put_callchain_buffers(void);
+
+static inline int get_recursion_context(int *recursion)
+{
+       int rctx;
+
+       if (in_nmi())
+               rctx = 3;
+       else if (in_irq())
+               rctx = 2;
+       else if (in_softirq())
+               rctx = 1;
+       else
+               rctx = 0;
+
+       if (recursion[rctx])
+               return -1;
+
+       recursion[rctx]++;
+       barrier();
+
+       return rctx;
+}
+
+static inline void put_recursion_context(int *recursion, int rctx)
+{
+       barrier();
+       recursion[rctx]--;
+}
+
 #endif /* _KERNEL_EVENTS_INTERNAL_H */
index e69434b..d2fab46 100644 (file)
@@ -498,36 +498,32 @@ void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS])
        usage[i] = '\0';
 }
 
-static int __print_lock_name(struct lock_class *class)
+static void __print_lock_name(struct lock_class *class)
 {
        char str[KSYM_NAME_LEN];
        const char *name;
 
        name = class->name;
-       if (!name)
-               name = __get_key_name(class->key, str);
-
-       return printk("%s", name);
-}
-
-static void print_lock_name(struct lock_class *class)
-{
-       char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS];
-       const char *name;
-
-       get_usage_chars(class, usage);
-
-       name = class->name;
        if (!name) {
                name = __get_key_name(class->key, str);
-               printk(" (%s", name);
+               printk("%s", name);
        } else {
-               printk(" (%s", name);
+               printk("%s", name);
                if (class->name_version > 1)
                        printk("#%d", class->name_version);
                if (class->subclass)
                        printk("/%d", class->subclass);
        }
+}
+
+static void print_lock_name(struct lock_class *class)
+{
+       char usage[LOCK_USAGE_CHARS];
+
+       get_usage_chars(class, usage);
+
+       printk(" (");
+       __print_lock_name(class);
        printk("){%s}", usage);
 }
 
index f2bd275..9e158cc 100644 (file)
@@ -2140,6 +2140,21 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
        return print_trace_fmt(iter);
 }
 
+void trace_latency_header(struct seq_file *m)
+{
+       struct trace_iterator *iter = m->private;
+
+       /* print nothing if the buffers are empty */
+       if (trace_empty(iter))
+               return;
+
+       if (iter->iter_flags & TRACE_FILE_LAT_FMT)
+               print_trace_header(m, iter);
+
+       if (!(trace_flags & TRACE_ITER_VERBOSE))
+               print_lat_help_header(m);
+}
+
 void trace_default_header(struct seq_file *m)
 {
        struct trace_iterator *iter = m->private;
index 092e1f8..f8ec229 100644 (file)
@@ -370,6 +370,7 @@ void trace_graph_function(struct trace_array *tr,
                    unsigned long ip,
                    unsigned long parent_ip,
                    unsigned long flags, int pc);
+void trace_latency_header(struct seq_file *m);
 void trace_default_header(struct seq_file *m);
 void print_trace_header(struct seq_file *m, struct trace_iterator *iter);
 int trace_empty(struct trace_iterator *iter);
index 95dc31e..f04cc31 100644 (file)
 #include "trace.h"
 #include "trace_output.h"
 
+#define DEFAULT_SYS_FILTER_MESSAGE                                     \
+       "### global filter ###\n"                                       \
+       "# Use this to set filters for multiple events.\n"              \
+       "# Only events with the given fields will be affected.\n"       \
+       "# If no events are modified, an error message will be displayed here"
+
 enum filter_op_ids
 {
        OP_OR,
@@ -646,7 +652,7 @@ void print_subsystem_event_filter(struct event_subsystem *system,
        if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
-               trace_seq_printf(s, "none\n");
+               trace_seq_printf(s, DEFAULT_SYS_FILTER_MESSAGE "\n");
        mutex_unlock(&event_mutex);
 }
 
@@ -1838,7 +1844,10 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
        if (!filter)
                goto out;
 
-       replace_filter_string(filter, filter_string);
+       /* System filters just show a default message */
+       kfree(filter->filter_string);
+       filter->filter_string = NULL;
+
        /*
         * No event actually uses the system filter
         * we can free it without synchronize_sched().
@@ -1848,14 +1857,12 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
 
        parse_init(ps, filter_ops, filter_string);
        err = filter_parse(ps);
-       if (err) {
-               append_filter_err(ps, system->filter);
-               goto out;
-       }
+       if (err)
+               goto err_filter;
 
        err = replace_system_preds(system, ps, filter_string);
        if (err)
-               append_filter_err(ps, system->filter);
+               goto err_filter;
 
 out:
        filter_opstack_clear(ps);
@@ -1865,6 +1872,11 @@ out_unlock:
        mutex_unlock(&event_mutex);
 
        return err;
+
+err_filter:
+       replace_filter_string(filter, filter_string);
+       append_filter_err(ps, system->filter);
+       goto out;
 }
 
 #ifdef CONFIG_PERF_EVENTS
index 20dad0d..99d20e9 100644 (file)
@@ -280,9 +280,20 @@ static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
 }
 
 static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { }
-static void irqsoff_print_header(struct seq_file *s) { }
 static void irqsoff_trace_open(struct trace_iterator *iter) { }
 static void irqsoff_trace_close(struct trace_iterator *iter) { }
+
+#ifdef CONFIG_FUNCTION_TRACER
+static void irqsoff_print_header(struct seq_file *s)
+{
+       trace_default_header(s);
+}
+#else
+static void irqsoff_print_header(struct seq_file *s)
+{
+       trace_latency_header(s);
+}
+#endif /* CONFIG_FUNCTION_TRACER */
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 
 /*
index e4a70c0..ff791ea 100644 (file)
@@ -280,9 +280,20 @@ static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
 }
 
 static void wakeup_graph_return(struct ftrace_graph_ret *trace) { }
-static void wakeup_print_header(struct seq_file *s) { }
 static void wakeup_trace_open(struct trace_iterator *iter) { }
 static void wakeup_trace_close(struct trace_iterator *iter) { }
+
+#ifdef CONFIG_FUNCTION_TRACER
+static void wakeup_print_header(struct seq_file *s)
+{
+       trace_default_header(s);
+}
+#else
+static void wakeup_print_header(struct seq_file *s)
+{
+       trace_latency_header(s);
+}
+#endif /* CONFIG_FUNCTION_TRACER */
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 
 /*
index fe6762e..476029d 100644 (file)
@@ -66,7 +66,7 @@ OPTIONS
        used. This interfaces starts by centering on the line with more
        samples, TAB/UNTAB cycles through the lines with more samples.
 
--c::
+-C::
 --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
        be provided as a comma-separated list with no space: 0,1. Ranges of
        CPUs are specified with -: 0-2. Default is to report samples on all
index 212f24d..dc85392 100644 (file)
@@ -39,7 +39,7 @@ OPTIONS
 -T::
 --threads::
        Show per-thread event counters
--C::
+-c::
 --comms=::
        Only consider symbols in these comms. CSV that understands
        file://filename entries.
@@ -128,7 +128,7 @@ OPTIONS
 --symfs=<directory>::
         Look for files with symbols relative to this directory.
 
--c::
+-C::
 --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
        be provided as a comma-separated list with no space: 0,1. Ranges of
        CPUs are specified with -: 0-2. Default is to report samples on all
index dec87ec..7f61eaa 100644 (file)
@@ -182,12 +182,17 @@ OPTIONS
 --hide-call-graph::
         When printing symbols do not display call chain.
 
--c::
+-C::
 --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
        be provided as a comma-separated list with no space: 0,1. Ranges of
        CPUs are specified with -: 0-2. Default is to report samples on all
        CPUs.
 
+-c::
+--comms=::
+       Only display events for these comms. CSV that understands
+       file://filename entries.
+
 -I::
 --show-info::
        Display extended information about the perf.data file. This adds
index 2c3b462..b24ac40 100644 (file)
@@ -8,13 +8,19 @@ perf-test - Runs sanity tests.
 SYNOPSIS
 --------
 [verse]
-'perf test <options>'
+'perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]'
 
 DESCRIPTION
 -----------
 This command does assorted sanity tests, initially through linked routines but
 also will look for a directory with more tests in the form of scripts.
 
+To get a list of available tests use 'perf test list', specifying a test name
+fragment will show all tests that have it.
+
+To run just specific tests, inform test name fragments or the numbers obtained
+from 'perf test list'.
+
 OPTIONS
 -------
 -v::
index b98e307..ac86d67 100644 (file)
@@ -278,6 +278,7 @@ LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
 LIB_H += util/svghelper.h
+LIB_H += util/tool.h
 LIB_H += util/run-command.h
 LIB_H += util/sigchain.h
 LIB_H += util/symbol.h
index 46b4c24..d449645 100644 (file)
 #include "util/sort.h"
 #include "util/hist.h"
 #include "util/session.h"
+#include "util/tool.h"
 
 #include <linux/bitmap.h>
 
-static char            const *input_name = "perf.data";
-
-static bool            force, use_tui, use_stdio;
-
-static bool            full_paths;
-
-static bool            print_line;
-
-static const char *sym_hist_filter;
-
-static const char      *cpu_list;
-static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+struct perf_annotate {
+       struct perf_tool tool;
+       char const *input_name;
+       bool       force, use_tui, use_stdio;
+       bool       full_paths;
+       bool       print_line;
+       const char *sym_hist_filter;
+       const char *cpu_list;
+       DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+};
 
-static int perf_evlist__add_sample(struct perf_evlist *evlist,
-                                  struct perf_sample *sample,
-                                  struct perf_evsel *evsel,
-                                  struct addr_location *al)
+static int perf_evsel__add_sample(struct perf_evsel *evsel,
+                                 struct perf_sample *sample,
+                                 struct addr_location *al,
+                                 struct perf_annotate *ann)
 {
        struct hist_entry *he;
        int ret;
 
-       if (sym_hist_filter != NULL &&
-           (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
+       if (ann->sym_hist_filter != NULL &&
+           (al->sym == NULL ||
+            strcmp(ann->sym_hist_filter, al->sym->name) != 0)) {
                /* We're only interested in a symbol named sym_hist_filter */
                if (al->sym != NULL) {
                        rb_erase(&al->sym->rb_node,
@@ -69,8 +69,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
        ret = 0;
        if (he->ms.sym != NULL) {
                struct annotation *notes = symbol__annotation(he->ms.sym);
-               if (notes->src == NULL &&
-                   symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
+               if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
                        return -ENOMEM;
 
                ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
@@ -81,25 +80,26 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
        return ret;
 }
 
-static int process_sample_event(union perf_event *event,
+static int process_sample_event(struct perf_tool *tool,
+                               union perf_event *event,
                                struct perf_sample *sample,
                                struct perf_evsel *evsel,
-                               struct perf_session *session)
+                               struct machine *machine)
 {
+       struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
        struct addr_location al;
 
-       if (perf_event__preprocess_sample(event, session, &al, sample,
+       if (perf_event__preprocess_sample(event, machine, &al, sample,
                                          symbol__annotate_init) < 0) {
                pr_warning("problem processing %d event, skipping it.\n",
                           event->header.type);
                return -1;
        }
 
-       if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
+       if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
                return 0;
 
-       if (!al.filtered &&
-           perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
+       if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) {
                pr_warning("problem incrementing symbol count, "
                           "skipping event\n");
                return -1;
@@ -108,14 +108,15 @@ static int process_sample_event(union perf_event *event,
        return 0;
 }
 
-static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
+static int hist_entry__tty_annotate(struct hist_entry *he, int evidx,
+                                   struct perf_annotate *ann)
 {
        return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
-                                   print_line, full_paths, 0, 0);
+                                   ann->print_line, ann->full_paths, 0, 0);
 }
 
 static void hists__find_annotations(struct hists *self, int evidx,
-                                   int nr_events)
+                                   struct perf_annotate *ann)
 {
        struct rb_node *nd = rb_first(&self->entries), *next;
        int key = K_RIGHT;
@@ -138,8 +139,7 @@ find_next:
                }
 
                if (use_browser > 0) {
-                       key = hist_entry__tui_annotate(he, evidx, nr_events,
-                                                      NULL, NULL, 0);
+                       key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0);
                        switch (key) {
                        case K_RIGHT:
                                next = rb_next(nd);
@@ -154,7 +154,7 @@ find_next:
                        if (next != NULL)
                                nd = next;
                } else {
-                       hist_entry__tty_annotate(he, evidx);
+                       hist_entry__tty_annotate(he, evidx, ann);
                        nd = rb_next(nd);
                        /*
                         * Since we have a hist_entry per IP for the same
@@ -167,33 +167,26 @@ find_next:
        }
 }
 
-static struct perf_event_ops event_ops = {
-       .sample = process_sample_event,
-       .mmap   = perf_event__process_mmap,
-       .comm   = perf_event__process_comm,
-       .fork   = perf_event__process_task,
-       .ordered_samples = true,
-       .ordering_requires_timestamps = true,
-};
-
-static int __cmd_annotate(void)
+static int __cmd_annotate(struct perf_annotate *ann)
 {
        int ret;
        struct perf_session *session;
        struct perf_evsel *pos;
        u64 total_nr_samples;
 
-       session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
+       session = perf_session__new(ann->input_name, O_RDONLY,
+                                   ann->force, false, &ann->tool);
        if (session == NULL)
                return -ENOMEM;
 
-       if (cpu_list) {
-               ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
+       if (ann->cpu_list) {
+               ret = perf_session__cpu_bitmap(session, ann->cpu_list,
+                                              ann->cpu_bitmap);
                if (ret)
                        goto out_delete;
        }
 
-       ret = perf_session__process_events(session, &event_ops);
+       ret = perf_session__process_events(session, &ann->tool);
        if (ret)
                goto out_delete;
 
@@ -217,13 +210,12 @@ static int __cmd_annotate(void)
                        total_nr_samples += nr_samples;
                        hists__collapse_resort(hists);
                        hists__output_resort(hists);
-                       hists__find_annotations(hists, pos->idx,
-                                               session->evlist->nr_entries);
+                       hists__find_annotations(hists, pos->idx, ann);
                }
        }
 
        if (total_nr_samples == 0) {
-               ui__warning("The %s file has no samples!\n", input_name);
+               ui__warning("The %s file has no samples!\n", ann->input_name);
                goto out_delete;
        }
 out_delete:
@@ -247,29 +239,42 @@ static const char * const annotate_usage[] = {
        NULL
 };
 
-static const struct option options[] = {
-       OPT_STRING('i', "input", &input_name, "file",
+int cmd_annotate(int argc, const char **argv, const char *prefix __used)
+{
+       struct perf_annotate annotate = {
+               .tool = {
+                       .sample = process_sample_event,
+                       .mmap   = perf_event__process_mmap,
+                       .comm   = perf_event__process_comm,
+                       .fork   = perf_event__process_task,
+                       .ordered_samples = true,
+                       .ordering_requires_timestamps = true,
+               },
+               .input_name = "perf.data",
+       };
+       const struct option options[] = {
+       OPT_STRING('i', "input", &annotate.input_name, "file",
                    "input file name"),
        OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
                   "only consider symbols in these dsos"),
-       OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
+       OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
                    "symbol to annotate"),
-       OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
-       OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
-       OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
+       OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
+       OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
                   "file", "vmlinux pathname"),
        OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
-       OPT_BOOLEAN('l', "print-line", &print_line,
+       OPT_BOOLEAN('l', "print-line", &annotate.print_line,
                    "print matching source lines (may be slow)"),
-       OPT_BOOLEAN('P', "full-paths", &full_paths,
+       OPT_BOOLEAN('P', "full-paths", &annotate.full_paths,
                    "Don't shorten the displayed pathnames"),
-       OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
+       OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
                   "Look for files with symbols relative to this directory"),
        OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
@@ -279,15 +284,13 @@ static const struct option options[] = {
        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
                   "Specify disassembler style (e.g. -M intel for intel syntax)"),
        OPT_END()
-};
+       };
 
-int cmd_annotate(int argc, const char **argv, const char *prefix __used)
-{
        argc = parse_options(argc, argv, options, annotate_usage, 0);
 
-       if (use_stdio)
+       if (annotate.use_stdio)
                use_browser = 0;
-       else if (use_tui)
+       else if (annotate.use_tui)
                use_browser = 1;
 
        setup_browser(true);
@@ -308,7 +311,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
                if (argc > 1)
                        usage_with_options(annotate_usage, options);
 
-               sym_hist_filter = argv[0];
+               annotate.sym_hist_filter = argv[0];
        }
 
        if (field_sep && *field_sep == '.') {
@@ -316,5 +319,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
                return -1;
        }
 
-       return __cmd_annotate();
+       return __cmd_annotate(&annotate);
 }
index b39f3a1..4f19513 100644 (file)
@@ -9,7 +9,9 @@
 #include "util/debug.h"
 #include "util/event.h"
 #include "util/hist.h"
+#include "util/evsel.h"
 #include "util/session.h"
+#include "util/tool.h"
 #include "util/sort.h"
 #include "util/symbol.h"
 #include "util/util.h"
@@ -30,14 +32,15 @@ static int hists__add_entry(struct hists *self,
        return -ENOMEM;
 }
 
-static int diff__process_sample_event(union perf_event *event,
+static int diff__process_sample_event(struct perf_tool *tool __used,
+                                     union perf_event *event,
                                      struct perf_sample *sample,
                                      struct perf_evsel *evsel __used,
-                                     struct perf_session *session)
+                                     struct machine *machine)
 {
        struct addr_location al;
 
-       if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
+       if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
                pr_warning("problem processing %d event, skipping it.\n",
                           event->header.type);
                return -1;
@@ -46,16 +49,16 @@ static int diff__process_sample_event(union perf_event *event,
        if (al.filtered || al.sym == NULL)
                return 0;
 
-       if (hists__add_entry(&session->hists, &al, sample->period)) {
+       if (hists__add_entry(&evsel->hists, &al, sample->period)) {
                pr_warning("problem incrementing symbol period, skipping event\n");
                return -1;
        }
 
-       session->hists.stats.total_period += sample->period;
+       evsel->hists.stats.total_period += sample->period;
        return 0;
 }
 
-static struct perf_event_ops event_ops = {
+static struct perf_tool perf_diff = {
        .sample = diff__process_sample_event,
        .mmap   = perf_event__process_mmap,
        .comm   = perf_event__process_comm,
@@ -145,13 +148,13 @@ static int __cmd_diff(void)
        int ret, i;
        struct perf_session *session[2];
 
-       session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops);
-       session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
+       session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff);
+       session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff);
        if (session[0] == NULL || session[1] == NULL)
                return -ENOMEM;
 
        for (i = 0; i < 2; ++i) {
-               ret = perf_session__process_events(session[i], &event_ops);
+               ret = perf_session__process_events(session[i], &perf_diff);
                if (ret)
                        goto out_delete;
        }
index 8dfc12b..09c1061 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "perf.h"
 #include "util/session.h"
+#include "util/tool.h"
 #include "util/debug.h"
 
 #include "util/parse-options.h"
@@ -16,8 +17,9 @@
 static char            const *input_name = "-";
 static bool            inject_build_ids;
 
-static int perf_event__repipe_synth(union perf_event *event,
-                                   struct perf_session *session __used)
+static int perf_event__repipe_synth(struct perf_tool *tool __used,
+                                   union perf_event *event,
+                                   struct machine *machine __used)
 {
        uint32_t size;
        void *buf = event;
@@ -36,41 +38,70 @@ static int perf_event__repipe_synth(union perf_event *event,
        return 0;
 }
 
-static int perf_event__repipe(union perf_event *event,
+static int perf_event__repipe_op2_synth(struct perf_tool *tool,
+                                       union perf_event *event,
+                                       struct perf_session *session __used)
+{
+       return perf_event__repipe_synth(tool, event, NULL);
+}
+
+static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
+                                              union perf_event *event)
+{
+       return perf_event__repipe_synth(tool, event, NULL);
+}
+
+static int perf_event__repipe_tracing_data_synth(union perf_event *event,
+                                                struct perf_session *session __used)
+{
+       return perf_event__repipe_synth(NULL, event, NULL);
+}
+
+static int perf_event__repipe_attr(union perf_event *event,
+                                  struct perf_evlist **pevlist __used)
+{
+       return perf_event__repipe_synth(NULL, event, NULL);
+}
+
+static int perf_event__repipe(struct perf_tool *tool,
+                             union perf_event *event,
                              struct perf_sample *sample __used,
-                             struct perf_session *session)
+                             struct machine *machine)
 {
-       return perf_event__repipe_synth(event, session);
+       return perf_event__repipe_synth(tool, event, machine);
 }
 
-static int perf_event__repipe_sample(union perf_event *event,
+static int perf_event__repipe_sample(struct perf_tool *tool,
+                                    union perf_event *event,
                              struct perf_sample *sample __used,
                              struct perf_evsel *evsel __used,
-                             struct perf_session *session)
+                             struct machine *machine)
 {
-       return perf_event__repipe_synth(event, session);
+       return perf_event__repipe_synth(tool, event, machine);
 }
 
-static int perf_event__repipe_mmap(union perf_event *event,
+static int perf_event__repipe_mmap(struct perf_tool *tool,
+                                  union perf_event *event,
                                   struct perf_sample *sample,
-                                  struct perf_session *session)
+                                  struct machine *machine)
 {
        int err;
 
-       err = perf_event__process_mmap(event, sample, session);
-       perf_event__repipe(event, sample, session);
+       err = perf_event__process_mmap(tool, event, sample, machine);
+       perf_event__repipe(tool, event, sample, machine);
 
        return err;
 }
 
-static int perf_event__repipe_task(union perf_event *event,
+static int perf_event__repipe_task(struct perf_tool *tool,
+                                  union perf_event *event,
                                   struct perf_sample *sample,
-                                  struct perf_session *session)
+                                  struct machine *machine)
 {
        int err;
 
-       err = perf_event__process_task(event, sample, session);
-       perf_event__repipe(event, sample, session);
+       err = perf_event__process_task(tool, event, sample, machine);
+       perf_event__repipe(tool, event, sample, machine);
 
        return err;
 }
@@ -80,7 +111,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event,
 {
        int err;
 
-       perf_event__repipe_synth(event, session);
+       perf_event__repipe_synth(NULL, event, NULL);
        err = perf_event__process_tracing_data(event, session);
 
        return err;
@@ -100,10 +131,10 @@ static int dso__read_build_id(struct dso *self)
        return -1;
 }
 
-static int dso__inject_build_id(struct dso *self, struct perf_session *session)
+static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
+                               struct machine *machine)
 {
        u16 misc = PERF_RECORD_MISC_USER;
-       struct machine *machine;
        int err;
 
        if (dso__read_build_id(self) < 0) {
@@ -111,17 +142,11 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
                return -1;
        }
 
-       machine = perf_session__find_host_machine(session);
-       if (machine == NULL) {
-               pr_err("Can't find machine for session\n");
-               return -1;
-       }
-
        if (self->kernel)
                misc = PERF_RECORD_MISC_KERNEL;
 
-       err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
-                                             machine, session);
+       err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
+                                             machine);
        if (err) {
                pr_err("Can't synthesize build_id event for %s\n", self->long_name);
                return -1;
@@ -130,10 +155,11 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
        return 0;
 }
 
-static int perf_event__inject_buildid(union perf_event *event,
+static int perf_event__inject_buildid(struct perf_tool *tool,
+                                     union perf_event *event,
                                      struct perf_sample *sample,
                                      struct perf_evsel *evsel __used,
-                                     struct perf_session *session)
+                                     struct machine *machine)
 {
        struct addr_location al;
        struct thread *thread;
@@ -141,21 +167,21 @@ static int perf_event__inject_buildid(union perf_event *event,
 
        cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
-       thread = perf_session__findnew(session, event->ip.pid);
+       thread = machine__findnew_thread(machine, event->ip.pid);
        if (thread == NULL) {
                pr_err("problem processing %d event, skipping it.\n",
                       event->header.type);
                goto repipe;
        }
 
-       thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
-                             event->ip.pid, event->ip.ip, &al);
+       thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
+                             event->ip.ip, &al);
 
        if (al.map != NULL) {
                if (!al.map->dso->hit) {
                        al.map->dso->hit = 1;
                        if (map__load(al.map, NULL) >= 0) {
-                               dso__inject_build_id(al.map->dso, session);
+                               dso__inject_build_id(al.map->dso, tool, machine);
                                /*
                                 * If this fails, too bad, let the other side
                                 * account this as unresolved.
@@ -168,24 +194,24 @@ static int perf_event__inject_buildid(union perf_event *event,
        }
 
 repipe:
-       perf_event__repipe(event, sample, session);
+       perf_event__repipe(tool, event, sample, machine);
        return 0;
 }
 
-struct perf_event_ops inject_ops = {
+struct perf_tool perf_inject = {
        .sample         = perf_event__repipe_sample,
        .mmap           = perf_event__repipe,
        .comm           = perf_event__repipe,
        .fork           = perf_event__repipe,
        .exit           = perf_event__repipe,
        .lost           = perf_event__repipe,
-       .read           = perf_event__repipe,
+       .read           = perf_event__repipe_sample,
        .throttle       = perf_event__repipe,
        .unthrottle     = perf_event__repipe,
-       .attr           = perf_event__repipe_synth,
-       .event_type     = perf_event__repipe_synth,
-       .tracing_data   = perf_event__repipe_synth,
-       .build_id       = perf_event__repipe_synth,
+       .attr           = perf_event__repipe_attr,
+       .event_type     = perf_event__repipe_event_type_synth,
+       .tracing_data   = perf_event__repipe_tracing_data_synth,
+       .build_id       = perf_event__repipe_op2_synth,
 };
 
 extern volatile int session_done;
@@ -203,17 +229,17 @@ static int __cmd_inject(void)
        signal(SIGINT, sig_handler);
 
        if (inject_build_ids) {
-               inject_ops.sample       = perf_event__inject_buildid;
-               inject_ops.mmap         = perf_event__repipe_mmap;
-               inject_ops.fork         = perf_event__repipe_task;
-               inject_ops.tracing_data = perf_event__repipe_tracing_data;
+               perf_inject.sample       = perf_event__inject_buildid;
+               perf_inject.mmap         = perf_event__repipe_mmap;
+               perf_inject.fork         = perf_event__repipe_task;
+               perf_inject.tracing_data = perf_event__repipe_tracing_data;
        }
 
-       session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
+       session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject);
        if (session == NULL)
                return -ENOMEM;
 
-       ret = perf_session__process_events(session, &inject_ops);
+       ret = perf_session__process_events(session, &perf_inject);
 
        perf_session__delete(session);
 
index 225e963..886174e 100644 (file)
@@ -7,6 +7,7 @@
 #include "util/thread.h"
 #include "util/header.h"
 #include "util/session.h"
+#include "util/tool.h"
 
 #include "util/parse-options.h"
 #include "util/trace-event.h"
@@ -303,12 +304,13 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
        }
 }
 
-static int process_sample_event(union perf_event *event,
+static int process_sample_event(struct perf_tool *tool __used,
+                               union perf_event *event,
                                struct perf_sample *sample,
                                struct perf_evsel *evsel __used,
-                               struct perf_session *session)
+                               struct machine *machine)
 {
-       struct thread *thread = perf_session__findnew(session, event->ip.pid);
+       struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
 
        if (thread == NULL) {
                pr_debug("problem processing %d event, skipping it.\n",
@@ -324,7 +326,7 @@ static int process_sample_event(union perf_event *event,
        return 0;
 }
 
-static struct perf_event_ops event_ops = {
+static struct perf_tool perf_kmem = {
        .sample                 = process_sample_event,
        .comm                   = perf_event__process_comm,
        .ordered_samples        = true,
@@ -483,7 +485,7 @@ static int __cmd_kmem(void)
 {
        int err = -EINVAL;
        struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-                                                        0, false, &event_ops);
+                                                        0, false, &perf_kmem);
        if (session == NULL)
                return -ENOMEM;
 
@@ -494,7 +496,7 @@ static int __cmd_kmem(void)
                goto out_delete;
 
        setup_pager();
-       err = perf_session__process_events(session, &event_ops);
+       err = perf_session__process_events(session, &perf_kmem);
        if (err != 0)
                goto out_delete;
        sort_result();
index 899080a..4db5e52 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "util/debug.h"
 #include "util/session.h"
+#include "util/tool.h"
 
 #include <sys/types.h>
 #include <sys/prctl.h>
@@ -845,12 +846,13 @@ static void dump_info(void)
                die("Unknown type of information\n");
 }
 
-static int process_sample_event(union perf_event *event,
+static int process_sample_event(struct perf_tool *tool __used,
+                               union perf_event *event,
                                struct perf_sample *sample,
                                struct perf_evsel *evsel __used,
-                               struct perf_session *s)
+                               struct machine *machine)
 {
-       struct thread *thread = perf_session__findnew(s, sample->tid);
+       struct thread *thread = machine__findnew_thread(machine, sample->tid);
 
        if (thread == NULL) {
                pr_debug("problem processing %d event, skipping it.\n",
@@ -863,7 +865,7 @@ static int process_sample_event(union perf_event *event,
        return 0;
 }
 
-static struct perf_event_ops eops = {
+static struct perf_tool eops = {
        .sample                 = process_sample_event,
        .comm                   = perf_event__process_comm,
        .ordered_samples        = true,
index 710ae3d..59d43ab 100644 (file)
@@ -46,7 +46,6 @@
 
 #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
 #define DEFAULT_FUNC_FILTER "!_*"
-#define MAX_PATH_LEN 256
 
 /* Session management structure */
 static struct {
index 6ab58cc..766fa0a 100644 (file)
@@ -22,6 +22,7 @@
 #include "util/evsel.h"
 #include "util/debug.h"
 #include "util/session.h"
+#include "util/tool.h"
 #include "util/symbol.h"
 #include "util/cpumap.h"
 #include "util/thread_map.h"
@@ -35,55 +36,36 @@ enum write_mode_t {
        WRITE_APPEND
 };
 
-static u64                     user_interval                   = ULLONG_MAX;
-static u64                     default_interval                =      0;
-
-static unsigned int            page_size;
-static unsigned int            mmap_pages                      = UINT_MAX;
-static unsigned int            user_freq                       = UINT_MAX;
-static int                     freq                            =   1000;
-static int                     output;
-static int                     pipe_output                     =      0;
-static const char              *output_name                    = NULL;
-static bool                    group                           =  false;
-static int                     realtime_prio                   =      0;
-static bool                    nodelay                         =  false;
-static bool                    raw_samples                     =  false;
-static bool                    sample_id_all_avail             =   true;
-static bool                    system_wide                     =  false;
-static pid_t                   target_pid                      =     -1;
-static pid_t                   target_tid                      =     -1;
-static pid_t                   child_pid                       =     -1;
-static bool                    no_inherit                      =  false;
-static enum write_mode_t       write_mode                      = WRITE_FORCE;
-static bool                    call_graph                      =  false;
-static bool                    inherit_stat                    =  false;
-static bool                    no_samples                      =  false;
-static bool                    sample_address                  =  false;
-static bool                    sample_time                     =  false;
-static bool                    no_buildid                      =  false;
-static bool                    no_buildid_cache                =  false;
-static struct perf_evlist      *evsel_list;
-
-static long                    samples                         =      0;
-static u64                     bytes_written                   =      0;
-
-static int                     file_new                        =      1;
-static off_t                   post_processing_offset;
-
-static struct perf_session     *session;
-static const char              *cpu_list;
-static const char               *progname;
-
-static void advance_output(size_t size)
+struct perf_record {
+       struct perf_tool        tool;
+       struct perf_record_opts opts;
+       u64                     bytes_written;
+       const char              *output_name;
+       struct perf_evlist      *evlist;
+       struct perf_session     *session;
+       const char              *progname;
+       int                     output;
+       unsigned int            page_size;
+       int                     realtime_prio;
+       enum write_mode_t       write_mode;
+       bool                    no_buildid;
+       bool                    no_buildid_cache;
+       bool                    force;
+       bool                    file_new;
+       bool                    append_file;
+       long                    samples;
+       off_t                   post_processing_offset;
+};
+
+static void advance_output(struct perf_record *rec, size_t size)
 {
-       bytes_written += size;
+       rec->bytes_written += size;
 }
 
-static void write_output(void *buf, size_t size)
+static void write_output(struct perf_record *rec, void *buf, size_t size)
 {
        while (size) {
-               int ret = write(output, buf, size);
+               int ret = write(rec->output, buf, size);
 
                if (ret < 0)
                        die("failed to write");
@@ -91,30 +73,33 @@ static void write_output(void *buf, size_t size)
                size -= ret;
                buf += ret;
 
-               bytes_written += ret;
+               rec->bytes_written += ret;
        }
 }
 
-static int process_synthesized_event(union perf_event *event,
+static int process_synthesized_event(struct perf_tool *tool,
+                                    union perf_event *event,
                                     struct perf_sample *sample __used,
-                                    struct perf_session *self __used)
+                                    struct machine *machine __used)
 {
-       write_output(event, event->header.size);
+       struct perf_record *rec = container_of(tool, struct perf_record, tool);
+       write_output(rec, event, event->header.size);
        return 0;
 }
 
-static void mmap_read(struct perf_mmap *md)
+static void perf_record__mmap_read(struct perf_record *rec,
+                                  struct perf_mmap *md)
 {
        unsigned int head = perf_mmap__read_head(md);
        unsigned int old = md->prev;
-       unsigned char *data = md->base + page_size;
+       unsigned char *data = md->base + rec->page_size;
        unsigned long size;
        void *buf;
 
        if (old == head)
                return;
 
-       samples++;
+       rec->samples++;
 
        size = head - old;
 
@@ -123,14 +108,14 @@ static void mmap_read(struct perf_mmap *md)
                size = md->mask + 1 - (old & md->mask);
                old += size;
 
-               write_output(buf, size);
+               write_output(rec, buf, size);
        }
 
        buf = &data[old & md->mask];
        size = head - old;
        old += size;
 
-       write_output(buf, size);
+       write_output(rec, buf, size);
 
        md->prev = old;
        perf_mmap__write_tail(md, old);
@@ -149,17 +134,18 @@ static void sig_handler(int sig)
        signr = sig;
 }
 
-static void sig_atexit(void)
+static void perf_record__sig_exit(int exit_status __used, void *arg)
 {
+       struct perf_record *rec = arg;
        int status;
 
-       if (child_pid > 0) {
+       if (rec->evlist->workload.pid > 0) {
                if (!child_finished)
-                       kill(child_pid, SIGTERM);
+                       kill(rec->evlist->workload.pid, SIGTERM);
 
                wait(&status);
                if (WIFSIGNALED(status))
-                       psignal(WTERMSIG(status), progname);
+                       psignal(WTERMSIG(status), rec->progname);
        }
 
        if (signr == -1 || signr == SIGUSR1)
@@ -169,78 +155,6 @@ static void sig_atexit(void)
        kill(getpid(), signr);
 }
 
-static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
-{
-       struct perf_event_attr *attr = &evsel->attr;
-       int track = !evsel->idx; /* only the first counter needs these */
-
-       attr->disabled          = 1;
-       attr->inherit           = !no_inherit;
-       attr->read_format       = PERF_FORMAT_TOTAL_TIME_ENABLED |
-                                 PERF_FORMAT_TOTAL_TIME_RUNNING |
-                                 PERF_FORMAT_ID;
-
-       attr->sample_type       |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
-
-       if (evlist->nr_entries > 1)
-               attr->sample_type |= PERF_SAMPLE_ID;
-
-       /*
-        * We default some events to a 1 default interval. But keep
-        * it a weak assumption overridable by the user.
-        */
-       if (!attr->sample_period || (user_freq != UINT_MAX &&
-                                    user_interval != ULLONG_MAX)) {
-               if (freq) {
-                       attr->sample_type       |= PERF_SAMPLE_PERIOD;
-                       attr->freq              = 1;
-                       attr->sample_freq       = freq;
-               } else {
-                       attr->sample_period = default_interval;
-               }
-       }
-
-       if (no_samples)
-               attr->sample_freq = 0;
-
-       if (inherit_stat)
-               attr->inherit_stat = 1;
-
-       if (sample_address) {
-               attr->sample_type       |= PERF_SAMPLE_ADDR;
-               attr->mmap_data = track;
-       }
-
-       if (call_graph)
-               attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
-
-       if (system_wide)
-               attr->sample_type       |= PERF_SAMPLE_CPU;
-
-       if (sample_id_all_avail &&
-           (sample_time || system_wide || !no_inherit || cpu_list))
-               attr->sample_type       |= PERF_SAMPLE_TIME;
-
-       if (raw_samples) {
-               attr->sample_type       |= PERF_SAMPLE_TIME;
-               attr->sample_type       |= PERF_SAMPLE_RAW;
-               attr->sample_type       |= PERF_SAMPLE_CPU;
-       }
-
-       if (nodelay) {
-               attr->watermark = 0;
-               attr->wakeup_events = 1;
-       }
-
-       attr->mmap              = track;
-       attr->comm              = track;
-
-       if (target_pid == -1 && target_tid == -1 && !system_wide) {
-               attr->disabled = 1;
-               attr->enable_on_exec = 1;
-       }
-}
-
 static bool perf_evlist__equal(struct perf_evlist *evlist,
                               struct perf_evlist *other)
 {
@@ -260,15 +174,17 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
        return true;
 }
 
-static void open_counters(struct perf_evlist *evlist)
+static void perf_record__open(struct perf_record *rec)
 {
        struct perf_evsel *pos, *first;
-
-       if (evlist->cpus->map[0] < 0)
-               no_inherit = true;
+       struct perf_evlist *evlist = rec->evlist;
+       struct perf_session *session = rec->session;
+       struct perf_record_opts *opts = &rec->opts;
 
        first = list_entry(evlist->entries.next, struct perf_evsel, node);
 
+       perf_evlist__config_attrs(evlist, opts);
+
        list_for_each_entry(pos, &evlist->entries, node) {
                struct perf_event_attr *attr = &pos->attr;
                struct xyarray *group_fd = NULL;
@@ -286,29 +202,27 @@ static void open_counters(struct perf_evlist *evlist)
                 */
                bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
 
-               if (group && pos != first)
+               if (opts->group && pos != first)
                        group_fd = first->fd;
-
-               config_attr(pos, evlist);
 retry_sample_id:
-               attr->sample_id_all = sample_id_all_avail ? 1 : 0;
+               attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
 try_again:
-               if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group,
-                                    group_fd) < 0) {
+               if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
+                                    opts->group, group_fd) < 0) {
                        int err = errno;
 
                        if (err == EPERM || err == EACCES) {
                                ui__error_paranoid();
                                exit(EXIT_FAILURE);
-                       } else if (err ==  ENODEV && cpu_list) {
+                       } else if (err ==  ENODEV && opts->cpu_list) {
                                die("No such device - did you specify"
                                        " an out-of-range profile CPU?\n");
-                       } else if (err == EINVAL && sample_id_all_avail) {
+                       } else if (err == EINVAL && opts->sample_id_all_avail) {
                                /*
                                 * Old kernel, no attr->sample_id_type_all field
                                 */
-                               sample_id_all_avail = false;
-                               if (!sample_time && !raw_samples && !time_needed)
+                               opts->sample_id_all_avail = false;
+                               if (!opts->sample_time && !opts->raw_samples && !time_needed)
                                        attr->sample_type &= ~PERF_SAMPLE_TIME;
 
                                goto retry_sample_id;
@@ -358,10 +272,10 @@ try_again:
                exit(-1);
        }
 
-       if (perf_evlist__mmap(evlist, mmap_pages, false) < 0)
+       if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0)
                die("failed to mmap with %d (%s)\n", errno, strerror(errno));
 
-       if (file_new)
+       if (rec->file_new)
                session->evlist = evlist;
        else {
                if (!perf_evlist__equal(session->evlist, evlist)) {
@@ -373,29 +287,32 @@ try_again:
        perf_session__update_sample_type(session);
 }
 
-static int process_buildids(void)
+static int process_buildids(struct perf_record *rec)
 {
-       u64 size = lseek(output, 0, SEEK_CUR);
+       u64 size = lseek(rec->output, 0, SEEK_CUR);
 
        if (size == 0)
                return 0;
 
-       session->fd = output;
-       return __perf_session__process_events(session, post_processing_offset,
-                                             size - post_processing_offset,
+       rec->session->fd = rec->output;
+       return __perf_session__process_events(rec->session, rec->post_processing_offset,
+                                             size - rec->post_processing_offset,
                                              size, &build_id__mark_dso_hit_ops);
 }
 
-static void atexit_header(void)
+static void perf_record__exit(int status __used, void *arg)
 {
-       if (!pipe_output) {
-               session->header.data_size += bytes_written;
-
-               if (!no_buildid)
-                       process_buildids();
-               perf_session__write_header(session, evsel_list, output, true);
-               perf_session__delete(session);
-               perf_evlist__delete(evsel_list);
+       struct perf_record *rec = arg;
+
+       if (!rec->opts.pipe_output) {
+               rec->session->header.data_size += rec->bytes_written;
+
+               if (!rec->no_buildid)
+                       process_buildids(rec);
+               perf_session__write_header(rec->session, rec->evlist,
+                                          rec->output, true);
+               perf_session__delete(rec->session);
+               perf_evlist__delete(rec->evlist);
                symbol__exit();
        }
 }
@@ -403,7 +320,7 @@ static void atexit_header(void)
 static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
 {
        int err;
-       struct perf_session *psession = data;
+       struct perf_tool *tool = data;
 
        if (machine__is_host(machine))
                return;
@@ -416,8 +333,8 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
         *method is used to avoid symbol missing when the first addr is
         *in module instead of in guest kernel.
         */
-       err = perf_event__synthesize_modules(process_synthesized_event,
-                                            psession, machine);
+       err = perf_event__synthesize_modules(tool, process_synthesized_event,
+                                            machine);
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -426,12 +343,11 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
         * We use _stext for guest kernel because guest kernel's /proc/kallsyms
         * have no _text sometimes.
         */
-       err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
-                                                psession, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                machine, "_text");
        if (err < 0)
-               err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
-                                                        psession, machine,
-                                                        "_stext");
+               err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                        machine, "_stext");
        if (err < 0)
                pr_err("Couldn't record guest kernel [%d]'s reference"
                       " relocation symbol.\n", machine->pid);
@@ -442,73 +358,71 @@ static struct perf_event_header finished_round_event = {
        .type = PERF_RECORD_FINISHED_ROUND,
 };
 
-static void mmap_read_all(void)
+static void perf_record__mmap_read_all(struct perf_record *rec)
 {
        int i;
 
-       for (i = 0; i < evsel_list->nr_mmaps; i++) {
-               if (evsel_list->mmap[i].base)
-                       mmap_read(&evsel_list->mmap[i]);
+       for (i = 0; i < rec->evlist->nr_mmaps; i++) {
+               if (rec->evlist->mmap[i].base)
+                       perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
        }
 
-       if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
-               write_output(&finished_round_event, sizeof(finished_round_event));
+       if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
+               write_output(rec, &finished_round_event, sizeof(finished_round_event));
 }
 
-static int __cmd_record(int argc, const char **argv)
+static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
 {
        struct stat st;
        int flags;
-       int err;
+       int err, output;
        unsigned long waking = 0;
-       int child_ready_pipe[2], go_pipe[2];
        const bool forks = argc > 0;
-       char buf;
        struct machine *machine;
+       struct perf_tool *tool = &rec->tool;
+       struct perf_record_opts *opts = &rec->opts;
+       struct perf_evlist *evsel_list = rec->evlist;
+       const char *output_name = rec->output_name;
+       struct perf_session *session;
 
-       progname = argv[0];
+       rec->progname = argv[0];
 
-       page_size = sysconf(_SC_PAGE_SIZE);
+       rec->page_size = sysconf(_SC_PAGE_SIZE);
 
-       atexit(sig_atexit);
+       on_exit(perf_record__sig_exit, rec);
        signal(SIGCHLD, sig_handler);
        signal(SIGINT, sig_handler);
        signal(SIGUSR1, sig_handler);
 
-       if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
-               perror("failed to create pipes");
-               exit(-1);
-       }
-
        if (!output_name) {
                if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
-                       pipe_output = 1;
+                       opts->pipe_output = true;
                else
-                       output_name = "perf.data";
+                       rec->output_name = output_name = "perf.data";
        }
        if (output_name) {
                if (!strcmp(output_name, "-"))
-                       pipe_output = 1;
+                       opts->pipe_output = true;
                else if (!stat(output_name, &st) && st.st_size) {
-                       if (write_mode == WRITE_FORCE) {
+                       if (rec->write_mode == WRITE_FORCE) {
                                char oldname[PATH_MAX];
                                snprintf(oldname, sizeof(oldname), "%s.old",
                                         output_name);
                                unlink(oldname);
                                rename(output_name, oldname);
                        }
-               } else if (write_mode == WRITE_APPEND) {
-                       write_mode = WRITE_FORCE;
+               } else if (rec->write_mode == WRITE_APPEND) {
+                       rec->write_mode = WRITE_FORCE;
                }
        }
 
        flags = O_CREAT|O_RDWR;
-       if (write_mode == WRITE_APPEND)
-               file_new = 0;
+       if (rec->write_mode == WRITE_APPEND)
+               rec->file_new = 0;
        else
                flags |= O_TRUNC;
 
-       if (pipe_output)
+       if (opts->pipe_output)
                output = STDOUT_FILENO;
        else
                output = open(output_name, flags, S_IRUSR | S_IWUSR);
@@ -517,17 +431,21 @@ static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
 
+       rec->output = output;
+
        session = perf_session__new(output_name, O_WRONLY,
-                                   write_mode == WRITE_FORCE, false, NULL);
+                                   rec->write_mode == WRITE_FORCE, false, NULL);
        if (session == NULL) {
                pr_err("Not enough memory for reading perf file header\n");
                return -1;
        }
 
-       if (!no_buildid)
+       rec->session = session;
+
+       if (!rec->no_buildid)
                perf_header__set_feat(&session->header, HEADER_BUILD_ID);
 
-       if (!file_new) {
+       if (!rec->file_new) {
                err = perf_session__read_header(session, output);
                if (err < 0)
                        goto out_delete_session;
@@ -549,94 +467,50 @@ static int __cmd_record(int argc, const char **argv)
        perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
        perf_header__set_feat(&session->header, HEADER_CPUID);
 
-       /* 512 kiB: default amount of unprivileged mlocked memory */
-       if (mmap_pages == UINT_MAX)
-               mmap_pages = (512 * 1024) / page_size;
-
        if (forks) {
-               child_pid = fork();
-               if (child_pid < 0) {
-                       perror("failed to fork");
-                       exit(-1);
-               }
-
-               if (!child_pid) {
-                       if (pipe_output)
-                               dup2(2, 1);
-                       close(child_ready_pipe[0]);
-                       close(go_pipe[1]);
-                       fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
-
-                       /*
-                        * Do a dummy execvp to get the PLT entry resolved,
-                        * so we avoid the resolver overhead on the real
-                        * execvp call.
-                        */
-                       execvp("", (char **)argv);
-
-                       /*
-                        * Tell the parent we're ready to go
-                        */
-                       close(child_ready_pipe[1]);
-
-                       /*
-                        * Wait until the parent tells us to go.
-                        */
-                       if (read(go_pipe[0], &buf, 1) == -1)
-                               perror("unable to read pipe");
-
-                       execvp(argv[0], (char **)argv);
-
-                       perror(argv[0]);
-                       kill(getppid(), SIGUSR1);
-                       exit(-1);
-               }
-
-               if (!system_wide && target_tid == -1 && target_pid == -1)
-                       evsel_list->threads->map[0] = child_pid;
-
-               close(child_ready_pipe[1]);
-               close(go_pipe[0]);
-               /*
-                * wait for child to settle
-                */
-               if (read(child_ready_pipe[0], &buf, 1) == -1) {
-                       perror("unable to read pipe");
-                       exit(-1);
+               err = perf_evlist__prepare_workload(evsel_list, opts, argv);
+               if (err < 0) {
+                       pr_err("Couldn't run the workload!\n");
+                       goto out_delete_session;
                }
-               close(child_ready_pipe[0]);
        }
 
-       open_counters(evsel_list);
+       perf_record__open(rec);
 
        /*
-        * perf_session__delete(session) will be called at atexit_header()
+        * perf_session__delete(session) will be called at perf_record__exit()
         */
-       atexit(atexit_header);
+       on_exit(perf_record__exit, rec);
 
-       if (pipe_output) {
+       if (opts->pipe_output) {
                err = perf_header__write_pipe(output);
                if (err < 0)
                        return err;
-       } else if (file_new) {
+       } else if (rec->file_new) {
                err = perf_session__write_header(session, evsel_list,
                                                 output, false);
                if (err < 0)
                        return err;
        }
 
-       post_processing_offset = lseek(output, 0, SEEK_CUR);
+       rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
+
+       machine = perf_session__find_host_machine(session);
+       if (!machine) {
+               pr_err("Couldn't find native kernel information.\n");
+               return -1;
+       }
 
-       if (pipe_output) {
-               err = perf_session__synthesize_attrs(session,
-                                                    process_synthesized_event);
+       if (opts->pipe_output) {
+               err = perf_event__synthesize_attrs(tool, session,
+                                                  process_synthesized_event);
                if (err < 0) {
                        pr_err("Couldn't synthesize attrs.\n");
                        return err;
                }
 
-               err = perf_event__synthesize_event_types(process_synthesized_event,
-                                                        session);
+               err = perf_event__synthesize_event_types(tool, process_synthesized_event,
+                                                        machine);
                if (err < 0) {
                        pr_err("Couldn't synthesize event_types.\n");
                        return err;
@@ -651,56 +525,49 @@ static int __cmd_record(int argc, const char **argv)
                         * return this more properly and also
                         * propagate errors that now are calling die()
                         */
-                       err = perf_event__synthesize_tracing_data(output, evsel_list,
-                                                                 process_synthesized_event,
-                                                                 session);
+                       err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
+                                                                 process_synthesized_event);
                        if (err <= 0) {
                                pr_err("Couldn't record tracing data.\n");
                                return err;
                        }
-                       advance_output(err);
+                       advance_output(rec, err);
                }
        }
 
-       machine = perf_session__find_host_machine(session);
-       if (!machine) {
-               pr_err("Couldn't find native kernel information.\n");
-               return -1;
-       }
-
-       err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
-                                                session, machine, "_text");
+       err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                machine, "_text");
        if (err < 0)
-               err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
-                                                        session, machine, "_stext");
+               err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
+                                                        machine, "_stext");
        if (err < 0)
                pr_err("Couldn't record kernel reference relocation symbol\n"
                       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
                       "Check /proc/kallsyms permission or run as root.\n");
 
-       err = perf_event__synthesize_modules(process_synthesized_event,
-                                            session, machine);
+       err = perf_event__synthesize_modules(tool, process_synthesized_event,
+                                            machine);
        if (err < 0)
                pr_err("Couldn't record kernel module information.\n"
                       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
                       "Check /proc/modules permission or run as root.\n");
 
        if (perf_guest)
-               perf_session__process_machines(session,
+               perf_session__process_machines(session, tool,
                                               perf_event__synthesize_guest_os);
 
-       if (!system_wide)
-               perf_event__synthesize_thread_map(evsel_list->threads,
+       if (!opts->system_wide)
+               perf_event__synthesize_thread_map(tool, evsel_list->threads,
                                                  process_synthesized_event,
-                                                 session);
+                                                 machine);
        else
-               perf_event__synthesize_threads(process_synthesized_event,
-                                              session);
+               perf_event__synthesize_threads(tool, process_synthesized_event,
+                                              machine);
 
-       if (realtime_prio) {
+       if (rec->realtime_prio) {
                struct sched_param param;
 
-               param.sched_priority = realtime_prio;
+               param.sched_priority = rec->realtime_prio;
                if (sched_setscheduler(0, SCHED_FIFO, &param)) {
                        pr_err("Could not set realtime priority.\n");
                        exit(-1);
@@ -713,14 +580,14 @@ static int __cmd_record(int argc, const char **argv)
         * Let the child rip
         */
        if (forks)
-               close(go_pipe[1]);
+               perf_evlist__start_workload(evsel_list);
 
        for (;;) {
-               int hits = samples;
+               int hits = rec->samples;
 
-               mmap_read_all();
+               perf_record__mmap_read_all(rec);
 
-               if (hits == samples) {
+               if (hits == rec->samples) {
                        if (done)
                                break;
                        err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
@@ -741,9 +608,9 @@ static int __cmd_record(int argc, const char **argv)
         */
        fprintf(stderr,
                "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
-               (double)bytes_written / 1024.0 / 1024.0,
+               (double)rec->bytes_written / 1024.0 / 1024.0,
                output_name,
-               bytes_written / 24);
+               rec->bytes_written / 24);
 
        return 0;
 
@@ -758,58 +625,88 @@ static const char * const record_usage[] = {
        NULL
 };
 
-static bool force, append_file;
+/*
+ * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
+ * because we need to have access to it in perf_record__exit, that is called
+ * after cmd_record() exits, but since record_options need to be accessible to
+ * builtin-script, leave it here.
+ *
+ * At least we don't ouch it in all the other functions here directly.
+ *
+ * Just say no to tons of global variables, sigh.
+ */
+static struct perf_record record = {
+       .opts = {
+               .target_pid          = -1,
+               .target_tid          = -1,
+               .mmap_pages          = UINT_MAX,
+               .user_freq           = UINT_MAX,
+               .user_interval       = ULLONG_MAX,
+               .freq                = 1000,
+               .sample_id_all_avail = true,
+       },
+       .write_mode = WRITE_FORCE,
+       .file_new   = true,
+};
 
+/*
+ * XXX Will stay a global variable till we fix builtin-script.c to stop messing
+ * with it and switch to use the library functions in perf_evlist that came
+ * from builtin-record.c, i.e. use perf_record_opts,
+ * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
+ * using pipes, etc.
+ */
 const struct option record_options[] = {
-       OPT_CALLBACK('e', "event", &evsel_list, "event",
+       OPT_CALLBACK('e', "event", &record.evlist, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events_option),
-       OPT_CALLBACK(0, "filter", &evsel_list, "filter",
+       OPT_CALLBACK(0, "filter", &record.evlist, "filter",
                     "event filter", parse_filter),
-       OPT_INTEGER('p', "pid", &target_pid,
+       OPT_INTEGER('p', "pid", &record.opts.target_pid,
                    "record events on existing process id"),
-       OPT_INTEGER('t', "tid", &target_tid,
+       OPT_INTEGER('t', "tid", &record.opts.target_tid,
                    "record events on existing thread id"),
-       OPT_INTEGER('r', "realtime", &realtime_prio,
+       OPT_INTEGER('r', "realtime", &record.realtime_prio,
                    "collect data with this RT SCHED_FIFO priority"),
-       OPT_BOOLEAN('D', "no-delay", &nodelay,
+       OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
                    "collect data without buffering"),
-       OPT_BOOLEAN('R', "raw-samples", &raw_samples,
+       OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
                    "collect raw sample records from all opened counters"),
-       OPT_BOOLEAN('a', "all-cpus", &system_wide,
+       OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
                            "system-wide collection from all CPUs"),
-       OPT_BOOLEAN('A', "append", &append_file,
+       OPT_BOOLEAN('A', "append", &record.append_file,
                            "append to the output file to do incremental profiling"),
-       OPT_STRING('C', "cpu", &cpu_list, "cpu",
+       OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
                    "list of cpus to monitor"),
-       OPT_BOOLEAN('f', "force", &force,
+       OPT_BOOLEAN('f', "force", &record.force,
                        "overwrite existing data file (deprecated)"),
-       OPT_U64('c', "count", &user_interval, "event period to sample"),
-       OPT_STRING('o', "output", &output_name, "file",
+       OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
+       OPT_STRING('o', "output", &record.output_name, "file",
                    "output file name"),
-       OPT_BOOLEAN('i', "no-inherit", &no_inherit,
+       OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
                    "child tasks do not inherit counters"),
-       OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
-       OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
-       OPT_BOOLEAN(0, "group", &group,
+       OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
+       OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
+                    "number of mmap data pages"),
+       OPT_BOOLEAN(0, "group", &record.opts.group,
                    "put the counters into a counter group"),
-       OPT_BOOLEAN('g', "call-graph", &call_graph,
+       OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
                    "do call-graph (stack chain/backtrace) recording"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
-       OPT_BOOLEAN('s', "stat", &inherit_stat,
+       OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
                    "per thread counts"),
-       OPT_BOOLEAN('d', "data", &sample_address,
+       OPT_BOOLEAN('d', "data", &record.opts.sample_address,
                    "Sample addresses"),
-       OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
-       OPT_BOOLEAN('n', "no-samples", &no_samples,
+       OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
+       OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
                    "don't sample"),
-       OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
+       OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
                    "do not update the buildid cache"),
-       OPT_BOOLEAN('B', "no-buildid", &no_buildid,
+       OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
                    "do not collect buildids in perf.data"),
-       OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
+       OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
                     "monitor event in cgroup name only",
                     parse_cgroups),
        OPT_END()
@@ -819,6 +716,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 {
        int err = -ENOMEM;
        struct perf_evsel *pos;
+       struct perf_evlist *evsel_list;
+       struct perf_record *rec = &record;
 
        perf_header__set_cmdline(argc, argv);
 
@@ -826,23 +725,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        if (evsel_list == NULL)
                return -ENOMEM;
 
+       rec->evlist = evsel_list;
+
        argc = parse_options(argc, argv, record_options, record_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
-       if (!argc && target_pid == -1 && target_tid == -1 &&
-               !system_wide && !cpu_list)
+       if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
+               !rec->opts.system_wide && !rec->opts.cpu_list)
                usage_with_options(record_usage, record_options);
 
-       if (force && append_file) {
+       if (rec->force && rec->append_file) {
                fprintf(stderr, "Can't overwrite and append at the same time."
                                " You need to choose between -f and -A");
                usage_with_options(record_usage, record_options);
-       } else if (append_file) {
-               write_mode = WRITE_APPEND;
+       } else if (rec->append_file) {
+               rec->write_mode = WRITE_APPEND;
        } else {
-               write_mode = WRITE_FORCE;
+               rec->write_mode = WRITE_FORCE;
        }
 
-       if (nr_cgroups && !system_wide) {
+       if (nr_cgroups && !rec->opts.system_wide) {
                fprintf(stderr, "cgroup monitoring only available in"
                        " system-wide mode\n");
                usage_with_options(record_usage, record_options);
@@ -860,7 +761,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 "If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
 "even with a suitable vmlinux or kallsyms file.\n\n");
 
-       if (no_buildid_cache || no_buildid)
+       if (rec->no_buildid_cache || rec->no_buildid)
                disable_buildid_cache();
 
        if (evsel_list->nr_entries == 0 &&
@@ -869,43 +770,37 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                goto out_symbol_exit;
        }
 
-       if (target_pid != -1)
-               target_tid = target_pid;
+       if (rec->opts.target_pid != -1)
+               rec->opts.target_tid = rec->opts.target_pid;
 
-       if (perf_evlist__create_maps(evsel_list, target_pid,
-                                    target_tid, cpu_list) < 0)
+       if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
+                                    rec->opts.target_tid, rec->opts.cpu_list) < 0)
                usage_with_options(record_usage, record_options);
 
        list_for_each_entry(pos, &evsel_list->entries, node) {
-               if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
-                                        evsel_list->threads->nr) < 0)
-                       goto out_free_fd;
                if (perf_header__push_event(pos->attr.config, event_name(pos)))
                        goto out_free_fd;
        }
 
-       if (perf_evlist__alloc_pollfd(evsel_list) < 0)
-               goto out_free_fd;
-
-       if (user_interval != ULLONG_MAX)
-               default_interval = user_interval;
-       if (user_freq != UINT_MAX)
-               freq = user_freq;
+       if (rec->opts.user_interval != ULLONG_MAX)
+               rec->opts.default_interval = rec->opts.user_interval;
+       if (rec->opts.user_freq != UINT_MAX)
+               rec->opts.freq = rec->opts.user_freq;
 
        /*
         * User specified count overrides default frequency.
         */
-       if (default_interval)
-               freq = 0;
-       else if (freq) {
-               default_interval = freq;
+       if (rec->opts.default_interval)
+               rec->opts.freq = 0;
+       else if (rec->opts.freq) {
+               rec->opts.default_interval = rec->opts.freq;
        } else {
                fprintf(stderr, "frequency and count are zero, aborting\n");
                err = -EINVAL;
                goto out_free_fd;
        }
 
-       err = __cmd_record(argc, argv);
+       err = __cmd_record(&record, argc, argv);
 out_free_fd:
        perf_evlist__delete_maps(evsel_list);
 out_symbol_exit:
index 4d7c834..ece7c5d 100644 (file)
@@ -25,6 +25,7 @@
 #include "util/evsel.h"
 #include "util/header.h"
 #include "util/session.h"
+#include "util/tool.h"
 
 #include "util/parse-options.h"
 #include "util/parse-events.h"
 
 #include <linux/bitmap.h>
 
-static char            const *input_name = "perf.data";
-
-static bool            force, use_tui, use_stdio;
-static bool            hide_unresolved;
-static bool            dont_use_callchains;
-static bool            show_full_info;
-
-static bool            show_threads;
-static struct perf_read_values show_threads_values;
-
-static const char      default_pretty_printing_style[] = "normal";
-static const char      *pretty_printing_style = default_pretty_printing_style;
-
-static char            callchain_default_opt[] = "fractal,0.5,callee";
-static bool            inverted_callchain;
-static symbol_filter_t annotate_init;
-
-static const char      *cpu_list;
-static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+struct perf_report {
+       struct perf_tool        tool;
+       struct perf_session     *session;
+       char const              *input_name;
+       bool                    force, use_tui, use_stdio;
+       bool                    hide_unresolved;
+       bool                    dont_use_callchains;
+       bool                    show_full_info;
+       bool                    show_threads;
+       bool                    inverted_callchain;
+       struct perf_read_values show_threads_values;
+       const char              *pretty_printing_style;
+       symbol_filter_t         annotate_init;
+       const char              *cpu_list;
+       DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+};
 
-static int perf_session__add_hist_entry(struct perf_session *session,
-                                       struct addr_location *al,
-                                       struct perf_sample *sample,
-                                       struct perf_evsel *evsel)
+static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
+                                     struct addr_location *al,
+                                     struct perf_sample *sample,
+                                     struct machine *machine)
 {
        struct symbol *parent = NULL;
        int err = 0;
        struct hist_entry *he;
 
        if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
-               err = perf_session__resolve_callchain(session, al->thread,
-                                                     sample->callchain, &parent);
+               err = machine__resolve_callchain(machine, evsel, al->thread,
+                                                sample->callchain, &parent);
                if (err)
                        return err;
        }
@@ -76,7 +74,8 @@ static int perf_session__add_hist_entry(struct perf_session *session,
                return -ENOMEM;
 
        if (symbol_conf.use_callchain) {
-               err = callchain_append(he->callchain, &session->callchain_cursor,
+               err = callchain_append(he->callchain,
+                                      &evsel->hists.callchain_cursor,
                                       sample->period);
                if (err)
                        return err;
@@ -92,8 +91,7 @@ static int perf_session__add_hist_entry(struct perf_session *session,
                assert(evsel != NULL);
 
                err = -ENOMEM;
-               if (notes->src == NULL &&
-                   symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
+               if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
                        goto out;
 
                err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
@@ -106,30 +104,32 @@ out:
 }
 
 
-static int process_sample_event(union perf_event *event,
+static int process_sample_event(struct perf_tool *tool,
+                               union perf_event *event,
                                struct perf_sample *sample,
                                struct perf_evsel *evsel,
-                               struct perf_session *session)
+                               struct machine *machine)
 {
+       struct perf_report *rep = container_of(tool, struct perf_report, tool);
        struct addr_location al;
 
-       if (perf_event__preprocess_sample(event, session, &al, sample,
-                                         annotate_init) < 0) {
+       if (perf_event__preprocess_sample(event, machine, &al, sample,
+                                         rep->annotate_init) < 0) {
                fprintf(stderr, "problem processing %d event, skipping it.\n",
                        event->header.type);
                return -1;
        }
 
-       if (al.filtered || (hide_unresolved && al.sym == NULL))
+       if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
                return 0;
 
-       if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
+       if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
                return 0;
 
        if (al.map != NULL)
                al.map->dso->hit = 1;
 
-       if (perf_session__add_hist_entry(session, &al, sample, evsel)) {
+       if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
                pr_debug("problem incrementing symbol period, skipping event\n");
                return -1;
        }
@@ -137,15 +137,17 @@ static int process_sample_event(union perf_event *event,
        return 0;
 }
 
-static int process_read_event(union perf_event *event,
+static int process_read_event(struct perf_tool *tool,
+                             union perf_event *event,
                              struct perf_sample *sample __used,
-                             struct perf_session *session)
+                             struct perf_evsel *evsel,
+                             struct machine *machine __used)
 {
-       struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
-                                                        event->read.id);
-       if (show_threads) {
+       struct perf_report *rep = container_of(tool, struct perf_report, tool);
+
+       if (rep->show_threads) {
                const char *name = evsel ? event_name(evsel) : "unknown";
-               perf_read_values_add_value(&show_threads_values,
+               perf_read_values_add_value(&rep->show_threads_values,
                                           event->read.pid, event->read.tid,
                                           event->read.id,
                                           name,
@@ -159,8 +161,10 @@ static int process_read_event(union perf_event *event,
        return 0;
 }
 
-static int perf_session__setup_sample_type(struct perf_session *self)
+static int perf_report__setup_sample_type(struct perf_report *rep)
 {
+       struct perf_session *self = rep->session;
+
        if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
                        ui__warning("Selected --sort parent, but no "
@@ -173,7 +177,8 @@ static int perf_session__setup_sample_type(struct perf_session *self)
                                    "you call 'perf record' without -g?\n");
                        return -1;
                }
-       } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
+       } else if (!rep->dont_use_callchains &&
+                  callchain_param.mode != CHAIN_NONE &&
                   !symbol_conf.use_callchain) {
                        symbol_conf.use_callchain = true;
                        if (callchain_register_param(&callchain_param) < 0) {
@@ -186,22 +191,6 @@ static int perf_session__setup_sample_type(struct perf_session *self)
        return 0;
 }
 
-static struct perf_event_ops event_ops = {
-       .sample          = process_sample_event,
-       .mmap            = perf_event__process_mmap,
-       .comm            = perf_event__process_comm,
-       .exit            = perf_event__process_task,
-       .fork            = perf_event__process_task,
-       .lost            = perf_event__process_lost,
-       .read            = process_read_event,
-       .attr            = perf_event__process_attr,
-       .event_type      = perf_event__process_event_type,
-       .tracing_data    = perf_event__process_tracing_data,
-       .build_id        = perf_event__process_build_id,
-       .ordered_samples = true,
-       .ordering_requires_timestamps = true,
-};
-
 extern volatile int session_done;
 
 static void sig_handler(int sig __used)
@@ -224,6 +213,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
 }
 
 static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
+                                        struct perf_report *rep,
                                         const char *help)
 {
        struct perf_evsel *pos;
@@ -241,18 +231,18 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
            parent_pattern == default_parent_pattern) {
                fprintf(stdout, "#\n# (%s)\n#\n", help);
 
-               if (show_threads) {
-                       bool style = !strcmp(pretty_printing_style, "raw");
-                       perf_read_values_display(stdout, &show_threads_values,
+               if (rep->show_threads) {
+                       bool style = !strcmp(rep->pretty_printing_style, "raw");
+                       perf_read_values_display(stdout, &rep->show_threads_values,
                                                 style);
-                       perf_read_values_destroy(&show_threads_values);
+                       perf_read_values_destroy(&rep->show_threads_values);
                }
        }
 
        return 0;
 }
 
-static int __cmd_report(void)
+static int __cmd_report(struct perf_report *rep)
 {
        int ret = -EINVAL;
        u64 nr_samples;
@@ -264,27 +254,31 @@ static int __cmd_report(void)
 
        signal(SIGINT, sig_handler);
 
-       session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
+       session = perf_session__new(rep->input_name, O_RDONLY,
+                                   rep->force, false, &rep->tool);
        if (session == NULL)
                return -ENOMEM;
 
-       if (cpu_list) {
-               ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
+       rep->session = session;
+
+       if (rep->cpu_list) {
+               ret = perf_session__cpu_bitmap(session, rep->cpu_list,
+                                              rep->cpu_bitmap);
                if (ret)
                        goto out_delete;
        }
 
        if (use_browser <= 0)
-               perf_session__fprintf_info(session, stdout, show_full_info);
+               perf_session__fprintf_info(session, stdout, rep->show_full_info);
 
-       if (show_threads)
-               perf_read_values_init(&show_threads_values);
+       if (rep->show_threads)
+               perf_read_values_init(&rep->show_threads_values);
 
-       ret = perf_session__setup_sample_type(session);
+       ret = perf_report__setup_sample_type(rep);
        if (ret)
                goto out_delete;
 
-       ret = perf_session__process_events(session, &event_ops);
+       ret = perf_session__process_events(session, &rep->tool);
        if (ret)
                goto out_delete;
 
@@ -327,7 +321,8 @@ static int __cmd_report(void)
        }
 
        if (nr_samples == 0) {
-               ui__warning("The %s file has no samples!\n", input_name);
+               ui__warning("The %s file has no samples!\n",
+                           rep->input_name);
                goto out_delete;
        }
 
@@ -335,7 +330,7 @@ static int __cmd_report(void)
                perf_evlist__tui_browse_hists(session->evlist, help,
                                              NULL, NULL, 0);
        } else
-               perf_evlist__tty_browse_hists(session->evlist, help);
+               perf_evlist__tty_browse_hists(session->evlist, rep, help);
 
 out_delete:
        /*
@@ -354,9 +349,9 @@ out_delete:
 }
 
 static int
-parse_callchain_opt(const struct option *opt __used, const char *arg,
-                   int unset)
+parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 {
+       struct perf_report *rep = (struct perf_report *)opt->value;
        char *tok, *tok2;
        char *endptr;
 
@@ -364,7 +359,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
         * --no-call-graph
         */
        if (unset) {
-               dont_use_callchains = true;
+               rep->dont_use_callchains = true;
                return 0;
        }
 
@@ -433,13 +428,34 @@ setup:
        return 0;
 }
 
-static const char * const report_usage[] = {
-       "perf report [<options>] <command>",
-       NULL
-};
-
-static const struct option options[] = {
-       OPT_STRING('i', "input", &input_name, "file",
+int cmd_report(int argc, const char **argv, const char *prefix __used)
+{
+       char callchain_default_opt[] = "fractal,0.5,callee";
+       const char * const report_usage[] = {
+               "perf report [<options>] <command>",
+               NULL
+       };
+       struct perf_report report = {
+               .tool = {
+                       .sample          = process_sample_event,
+                       .mmap            = perf_event__process_mmap,
+                       .comm            = perf_event__process_comm,
+                       .exit            = perf_event__process_task,
+                       .fork            = perf_event__process_task,
+                       .lost            = perf_event__process_lost,
+                       .read            = process_read_event,
+                       .attr            = perf_event__process_attr,
+                       .event_type      = perf_event__process_event_type,
+                       .tracing_data    = perf_event__process_tracing_data,
+                       .build_id        = perf_event__process_build_id,
+                       .ordered_samples = true,
+                       .ordering_requires_timestamps = true,
+               },
+               .input_name              = "perf.data",
+               .pretty_printing_style   = "normal",
+       };
+       const struct option options[] = {
+       OPT_STRING('i', "input", &report.input_name, "file",
                    "input file name"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
@@ -449,17 +465,18 @@ static const struct option options[] = {
                   "file", "vmlinux pathname"),
        OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
                   "file", "kallsyms pathname"),
-       OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
        OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
                    "Show a column with the number of samples"),
-       OPT_BOOLEAN('T', "threads", &show_threads,
+       OPT_BOOLEAN('T', "threads", &report.show_threads,
                    "Show per-thread event counters"),
-       OPT_STRING(0, "pretty", &pretty_printing_style, "key",
+       OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
                   "pretty printing style key: normal raw"),
-       OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
-       OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
+       OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
+       OPT_BOOLEAN(0, "stdio", &report.use_stdio,
+                   "Use the stdio interface"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent"),
        OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
@@ -468,13 +485,14 @@ static const struct option options[] = {
                   "regex filter to identify parent, see: '--sort parent'"),
        OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
                    "Only display entries with parent-match"),
-       OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order",
+       OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent, call_order",
                     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
                     "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
-       OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"),
+       OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
+                   "alias for inverted call graph"),
        OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
                   "only consider symbols in these dsos"),
-       OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
+       OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
                   "only consider symbols in these comms"),
        OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
                   "only consider these symbols"),
@@ -484,12 +502,13 @@ static const struct option options[] = {
        OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
                   "separator for columns, no spaces will be added between "
                   "columns '.' is reserved."),
-       OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
+       OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
                    "Only display entries resolved to a symbol"),
        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
                    "Look for files with symbols relative to this directory"),
-       OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
-       OPT_BOOLEAN('I', "show-info", &show_full_info,
+       OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
+                  "list of cpus to profile"),
+       OPT_BOOLEAN('I', "show-info", &report.show_full_info,
                    "Display extended information about perf.data file"),
        OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
                    "Interleave source code with assembly code (default)"),
@@ -500,21 +519,19 @@ static const struct option options[] = {
        OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
                    "Show a column with the sum of periods"),
        OPT_END()
-};
+       };
 
-int cmd_report(int argc, const char **argv, const char *prefix __used)
-{
        argc = parse_options(argc, argv, options, report_usage, 0);
 
-       if (use_stdio)
+       if (report.use_stdio)
                use_browser = 0;
-       else if (use_tui)
+       else if (report.use_tui)
                use_browser = 1;
 
-       if (inverted_callchain)
+       if (report.inverted_callchain)
                callchain_param.order = ORDER_CALLER;
 
-       if (strcmp(input_name, "-") != 0)
+       if (strcmp(report.input_name, "-") != 0)
                setup_browser(true);
        else
                use_browser = 0;
@@ -525,7 +542,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
         */
        if (use_browser > 0) {
                symbol_conf.priv_size = sizeof(struct annotation);
-               annotate_init         = symbol__annotate_init;
+               report.annotate_init  = symbol__annotate_init;
                /*
                 * For searching by name on the "Browse map details".
                 * providing it only in verbose mode not to bloat too
@@ -572,5 +589,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
        sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
        sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
 
-       return __cmd_report();
+       return __cmd_report(&report);
 }
index 5177964..6284ed2 100644 (file)
@@ -2,11 +2,14 @@
 #include "perf.h"
 
 #include "util/util.h"
+#include "util/evlist.h"
 #include "util/cache.h"
+#include "util/evsel.h"
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/header.h"
 #include "util/session.h"
+#include "util/tool.h"
 
 #include "util/parse-options.h"
 #include "util/trace-event.h"
@@ -723,21 +726,21 @@ struct trace_migrate_task_event {
 
 struct trace_sched_handler {
        void (*switch_event)(struct trace_switch_event *,
-                            struct perf_session *,
+                            struct machine *,
                             struct event *,
                             int cpu,
                             u64 timestamp,
                             struct thread *thread);
 
        void (*runtime_event)(struct trace_runtime_event *,
-                             struct perf_session *,
+                             struct machine *,
                              struct event *,
                              int cpu,
                              u64 timestamp,
                              struct thread *thread);
 
        void (*wakeup_event)(struct trace_wakeup_event *,
-                            struct perf_session *,
+                            struct machine *,
                             struct event *,
                             int cpu,
                             u64 timestamp,
@@ -750,7 +753,7 @@ struct trace_sched_handler {
                           struct thread *thread);
 
        void (*migrate_task_event)(struct trace_migrate_task_event *,
-                          struct perf_session *session,
+                          struct machine *machine,
                           struct event *,
                           int cpu,
                           u64 timestamp,
@@ -760,7 +763,7 @@ struct trace_sched_handler {
 
 static void
 replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
-                   struct perf_session *session __used,
+                   struct machine *machine __used,
                    struct event *event,
                    int cpu __used,
                    u64 timestamp __used,
@@ -787,7 +790,7 @@ static u64 cpu_last_switched[MAX_CPUS];
 
 static void
 replay_switch_event(struct trace_switch_event *switch_event,
-                   struct perf_session *session __used,
+                   struct machine *machine __used,
                    struct event *event,
                    int cpu,
                    u64 timestamp,
@@ -1021,7 +1024,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
 
 static void
 latency_switch_event(struct trace_switch_event *switch_event,
-                    struct perf_session *session,
+                    struct machine *machine,
                     struct event *event __used,
                     int cpu,
                     u64 timestamp,
@@ -1045,8 +1048,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
                die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
 
 
-       sched_out = perf_session__findnew(session, switch_event->prev_pid);
-       sched_in = perf_session__findnew(session, switch_event->next_pid);
+       sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
+       sched_in = machine__findnew_thread(machine, switch_event->next_pid);
 
        out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
        if (!out_events) {
@@ -1074,13 +1077,13 @@ latency_switch_event(struct trace_switch_event *switch_event,
 
 static void
 latency_runtime_event(struct trace_runtime_event *runtime_event,
-                    struct perf_session *session,
+                    struct machine *machine,
                     struct event *event __used,
                     int cpu,
                     u64 timestamp,
                     struct thread *this_thread __used)
 {
-       struct thread *thread = perf_session__findnew(session, runtime_event->pid);
+       struct thread *thread = machine__findnew_thread(machine, runtime_event->pid);
        struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
 
        BUG_ON(cpu >= MAX_CPUS || cpu < 0);
@@ -1097,7 +1100,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
 
 static void
 latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
-                    struct perf_session *session,
+                    struct machine *machine,
                     struct event *__event __used,
                     int cpu __used,
                     u64 timestamp,
@@ -1111,7 +1114,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
        if (!wakeup_event->success)
                return;
 
-       wakee = perf_session__findnew(session, wakeup_event->pid);
+       wakee = machine__findnew_thread(machine, wakeup_event->pid);
        atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
        if (!atoms) {
                thread_atoms_insert(wakee);
@@ -1145,7 +1148,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
 
 static void
 latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
-                    struct perf_session *session,
+                    struct machine *machine,
                     struct event *__event __used,
                     int cpu __used,
                     u64 timestamp,
@@ -1161,7 +1164,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
        if (profile_cpu == -1)
                return;
 
-       migrant = perf_session__findnew(session, migrate_task_event->pid);
+       migrant = machine__findnew_thread(machine, migrate_task_event->pid);
        atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
        if (!atoms) {
                thread_atoms_insert(migrant);
@@ -1356,12 +1359,13 @@ static void sort_lat(void)
 static struct trace_sched_handler *trace_handler;
 
 static void
-process_sched_wakeup_event(void *data, struct perf_session *session,
+process_sched_wakeup_event(struct perf_tool *tool __used,
                           struct event *event,
-                          int cpu __used,
-                          u64 timestamp __used,
-                          struct thread *thread __used)
+                          struct perf_sample *sample,
+                          struct machine *machine,
+                          struct thread *thread)
 {
+       void *data = sample->raw_data;
        struct trace_wakeup_event wakeup_event;
 
        FILL_COMMON_FIELDS(wakeup_event, event, data);
@@ -1373,8 +1377,8 @@ process_sched_wakeup_event(void *data, struct perf_session *session,
        FILL_FIELD(wakeup_event, cpu, event, data);
 
        if (trace_handler->wakeup_event)
-               trace_handler->wakeup_event(&wakeup_event, session, event,
-                                           cpu, timestamp, thread);
+               trace_handler->wakeup_event(&wakeup_event, machine, event,
+                                           sample->cpu, sample->time, thread);
 }
 
 /*
@@ -1392,7 +1396,7 @@ static char next_shortname2 = '0';
 
 static void
 map_switch_event(struct trace_switch_event *switch_event,
-                struct perf_session *session,
+                struct machine *machine,
                 struct event *event __used,
                 int this_cpu,
                 u64 timestamp,
@@ -1420,8 +1424,8 @@ map_switch_event(struct trace_switch_event *switch_event,
                die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
 
 
-       sched_out = perf_session__findnew(session, switch_event->prev_pid);
-       sched_in = perf_session__findnew(session, switch_event->next_pid);
+       sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
+       sched_in = machine__findnew_thread(machine, switch_event->next_pid);
 
        curr_thread[this_cpu] = sched_in;
 
@@ -1469,14 +1473,15 @@ map_switch_event(struct trace_switch_event *switch_event,
        }
 }
 
-
 static void
-process_sched_switch_event(void *data, struct perf_session *session,
+process_sched_switch_event(struct perf_tool *tool __used,
                           struct event *event,
-                          int this_cpu,
-                          u64 timestamp __used,
-                          struct thread *thread __used)
+                          struct perf_sample *sample,
+                          struct machine *machine,
+                          struct thread *thread)
 {
+       int this_cpu = sample->cpu;
+       void *data = sample->raw_data;
        struct trace_switch_event switch_event;
 
        FILL_COMMON_FIELDS(switch_event, event, data);
@@ -1498,19 +1503,20 @@ process_sched_switch_event(void *data, struct perf_session *session,
                        nr_context_switch_bugs++;
        }
        if (trace_handler->switch_event)
-               trace_handler->switch_event(&switch_event, session, event,
-                                           this_cpu, timestamp, thread);
+               trace_handler->switch_event(&switch_event, machine, event,
+                                           this_cpu, sample->time, thread);
 
        curr_pid[this_cpu] = switch_event.next_pid;
 }
 
 static void
-process_sched_runtime_event(void *data, struct perf_session *session,
-                          struct event *event,
-                          int cpu __used,
-                          u64 timestamp __used,
-                          struct thread *thread __used)
+process_sched_runtime_event(struct perf_tool *tool __used,
+                           struct event *event,
+                           struct perf_sample *sample,
+                           struct machine *machine,
+                           struct thread *thread)
 {
+       void *data = sample->raw_data;
        struct trace_runtime_event runtime_event;
 
        FILL_ARRAY(runtime_event, comm, event, data);
@@ -1519,16 +1525,18 @@ process_sched_runtime_event(void *data, struct perf_session *session,
        FILL_FIELD(runtime_event, vruntime, event, data);
 
        if (trace_handler->runtime_event)
-               trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
+               trace_handler->runtime_event(&runtime_event, machine, event,
+                                            sample->cpu, sample->time, thread);
 }
 
 static void
-process_sched_fork_event(void *data,
+process_sched_fork_event(struct perf_tool *tool __used,
                         struct event *event,
-                        int cpu __used,
-                        u64 timestamp __used,
-                        struct thread *thread __used)
+                        struct perf_sample *sample,
+                        struct machine *machine __used,
+                        struct thread *thread)
 {
+       void *data = sample->raw_data;
        struct trace_fork_event fork_event;
 
        FILL_COMMON_FIELDS(fork_event, event, data);
@@ -1540,13 +1548,14 @@ process_sched_fork_event(void *data,
 
        if (trace_handler->fork_event)
                trace_handler->fork_event(&fork_event, event,
-                                         cpu, timestamp, thread);
+                                         sample->cpu, sample->time, thread);
 }
 
 static void
-process_sched_exit_event(struct event *event,
-                        int cpu __used,
-                        u64 timestamp __used,
+process_sched_exit_event(struct perf_tool *tool __used,
+                        struct event *event,
+                        struct perf_sample *sample __used,
+                        struct machine *machine __used,
                         struct thread *thread __used)
 {
        if (verbose)
@@ -1554,12 +1563,13 @@ process_sched_exit_event(struct event *event,
 }
 
 static void
-process_sched_migrate_task_event(void *data, struct perf_session *session,
-                          struct event *event,
-                          int cpu __used,
-                          u64 timestamp __used,
-                          struct thread *thread __used)
+process_sched_migrate_task_event(struct perf_tool *tool __used,
+                                struct event *event,
+                                struct perf_sample *sample,
+                                struct machine *machine,
+                                struct thread *thread)
 {
+       void *data = sample->raw_data;
        struct trace_migrate_task_event migrate_task_event;
 
        FILL_COMMON_FIELDS(migrate_task_event, event, data);
@@ -1570,67 +1580,47 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
        FILL_FIELD(migrate_task_event, cpu, event, data);
 
        if (trace_handler->migrate_task_event)
-               trace_handler->migrate_task_event(&migrate_task_event, session,
-                                                event, cpu, timestamp, thread);
+               trace_handler->migrate_task_event(&migrate_task_event, machine,
+                                                 event, sample->cpu,
+                                                 sample->time, thread);
 }
 
-static void process_raw_event(union perf_event *raw_event __used,
-                             struct perf_session *session, void *data, int cpu,
-                             u64 timestamp, struct thread *thread)
-{
-       struct event *event;
-       int type;
-
-
-       type = trace_parse_common_type(data);
-       event = trace_find_event(type);
-
-       if (!strcmp(event->name, "sched_switch"))
-               process_sched_switch_event(data, session, event, cpu, timestamp, thread);
-       if (!strcmp(event->name, "sched_stat_runtime"))
-               process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
-       if (!strcmp(event->name, "sched_wakeup"))
-               process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
-       if (!strcmp(event->name, "sched_wakeup_new"))
-               process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
-       if (!strcmp(event->name, "sched_process_fork"))
-               process_sched_fork_event(data, event, cpu, timestamp, thread);
-       if (!strcmp(event->name, "sched_process_exit"))
-               process_sched_exit_event(event, cpu, timestamp, thread);
-       if (!strcmp(event->name, "sched_migrate_task"))
-               process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
-}
+typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event,
+                                  struct perf_sample *sample,
+                                  struct machine *machine,
+                                  struct thread *thread);
 
-static int process_sample_event(union perf_event *event,
-                               struct perf_sample *sample,
-                               struct perf_evsel *evsel __used,
-                               struct perf_session *session)
+static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
+                                                union perf_event *event __used,
+                                                struct perf_sample *sample,
+                                                struct perf_evsel *evsel,
+                                                struct machine *machine)
 {
-       struct thread *thread;
-
-       if (!(session->sample_type & PERF_SAMPLE_RAW))
-               return 0;
+       struct thread *thread = machine__findnew_thread(machine, sample->pid);
 
-       thread = perf_session__findnew(session, sample->pid);
        if (thread == NULL) {
-               pr_debug("problem processing %d event, skipping it.\n",
-                        event->header.type);
+               pr_debug("problem processing %s event, skipping it.\n",
+                        evsel->name);
                return -1;
        }
 
-       dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+       evsel->hists.stats.total_period += sample->period;
+       hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
 
-       if (profile_cpu != -1 && profile_cpu != (int)sample->cpu)
-               return 0;
+       if (evsel->handler.func != NULL) {
+               tracepoint_handler f = evsel->handler.func;
 
-       process_raw_event(event, session, sample->raw_data, sample->cpu,
-                         sample->time, thread);
+               if (evsel->handler.data == NULL)
+                       evsel->handler.data = trace_find_event(evsel->attr.config);
+
+               f(tool, evsel->handler.data, sample, machine, thread);
+       }
 
        return 0;
 }
 
-static struct perf_event_ops event_ops = {
-       .sample                 = process_sample_event,
+static struct perf_tool perf_sched = {
+       .sample                 = perf_sched__process_tracepoint_sample,
        .comm                   = perf_event__process_comm,
        .lost                   = perf_event__process_lost,
        .fork                   = perf_event__process_task,
@@ -1640,13 +1630,25 @@ static struct perf_event_ops event_ops = {
 static void read_events(bool destroy, struct perf_session **psession)
 {
        int err = -EINVAL;
+       const struct perf_evsel_str_handler handlers[] = {
+               { "sched:sched_switch",       process_sched_switch_event, },
+               { "sched:sched_stat_runtime", process_sched_runtime_event, },
+               { "sched:sched_wakeup",       process_sched_wakeup_event, },
+               { "sched:sched_wakeup_new",   process_sched_wakeup_event, },
+               { "sched:sched_process_fork", process_sched_fork_event, },
+               { "sched:sched_process_exit", process_sched_exit_event, },
+               { "sched:sched_migrate_task", process_sched_migrate_task_event, },
+       };
        struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-                                                        0, false, &event_ops);
+                                                        0, false, &perf_sched);
        if (session == NULL)
                die("No Memory");
 
+       err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers);
+       assert(err == 0);
+
        if (perf_session__has_traces(session, "record -R")) {
-               err = perf_session__process_events(session, &event_ops);
+               err = perf_session__process_events(session, &perf_sched);
                if (err)
                        die("Failed to process events, error %d", err);
 
index 2f62a29..619d6dc 100644 (file)
@@ -7,6 +7,7 @@
 #include "util/header.h"
 #include "util/parse-options.h"
 #include "util/session.h"
+#include "util/tool.h"
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/trace-event.h"
@@ -315,7 +316,7 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
 
 static void print_sample_addr(union perf_event *event,
                          struct perf_sample *sample,
-                         struct perf_session *session,
+                         struct machine *machine,
                          struct thread *thread,
                          struct perf_event_attr *attr)
 {
@@ -328,11 +329,11 @@ static void print_sample_addr(union perf_event *event,
        if (!sample_addr_correlates_sym(attr))
                return;
 
-       thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
-                             event->ip.pid, sample->addr, &al);
+       thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
+                             sample->addr, &al);
        if (!al.map)
-               thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE,
-                                     event->ip.pid, sample->addr, &al);
+               thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
+                                     sample->addr, &al);
 
        al.cpu = sample->cpu;
        al.sym = NULL;
@@ -362,7 +363,7 @@ static void print_sample_addr(union perf_event *event,
 static void process_event(union perf_event *event __unused,
                          struct perf_sample *sample,
                          struct perf_evsel *evsel,
-                         struct perf_session *session,
+                         struct machine *machine,
                          struct thread *thread)
 {
        struct perf_event_attr *attr = &evsel->attr;
@@ -377,15 +378,15 @@ static void process_event(union perf_event *event __unused,
                                  sample->raw_size);
 
        if (PRINT_FIELD(ADDR))
-               print_sample_addr(event, sample, session, thread, attr);
+               print_sample_addr(event, sample, machine, thread, attr);
 
        if (PRINT_FIELD(IP)) {
                if (!symbol_conf.use_callchain)
                        printf(" ");
                else
                        printf("\n");
-               perf_session__print_ip(event, sample, session,
-                                             PRINT_FIELD(SYM), PRINT_FIELD(DSO));
+               perf_event__print_ip(event, sample, machine, evsel,
+                                    PRINT_FIELD(SYM), PRINT_FIELD(DSO));
        }
 
        printf("\n");
@@ -434,12 +435,14 @@ static int cleanup_scripting(void)
 
 static char const              *input_name = "perf.data";
 
-static int process_sample_event(union perf_event *event,
+static int process_sample_event(struct perf_tool *tool __used,
+                               union perf_event *event,
                                struct perf_sample *sample,
                                struct perf_evsel *evsel,
-                               struct perf_session *session)
+                               struct machine *machine)
 {
-       struct thread *thread = perf_session__findnew(session, event->ip.pid);
+       struct addr_location al;
+       struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
 
        if (thread == NULL) {
                pr_debug("problem processing %d event, skipping it.\n",
@@ -458,16 +461,25 @@ static int process_sample_event(union perf_event *event,
                return 0;
        }
 
+       if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) {
+               pr_err("problem processing %d event, skipping it.\n",
+                      event->header.type);
+               return -1;
+       }
+
+       if (al.filtered)
+               return 0;
+
        if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
                return 0;
 
-       scripting_ops->process_event(event, sample, evsel, session, thread);
+       scripting_ops->process_event(event, sample, evsel, machine, thread);
 
-       session->hists.stats.total_period += sample->period;
+       evsel->hists.stats.total_period += sample->period;
        return 0;
 }
 
-static struct perf_event_ops event_ops = {
+static struct perf_tool perf_script = {
        .sample          = process_sample_event,
        .mmap            = perf_event__process_mmap,
        .comm            = perf_event__process_comm,
@@ -494,7 +506,7 @@ static int __cmd_script(struct perf_session *session)
 
        signal(SIGINT, sig_handler);
 
-       ret = perf_session__process_events(session, &event_ops);
+       ret = perf_session__process_events(session, &perf_script);
 
        if (debug_mode)
                pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -1083,7 +1095,9 @@ static const struct option options[] = {
        OPT_CALLBACK('f', "fields", NULL, "str",
                     "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",
                     parse_output_fields),
-       OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
+       OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
+       OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
+                  "only display events for these comms"),
        OPT_BOOLEAN('I', "show-info", &show_full_info,
                    "display extended information from perf.data file"),
        OPT_END()
@@ -1261,7 +1275,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
        if (!script_name)
                setup_pager();
 
-       session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
+       session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script);
        if (session == NULL)
                return -ENOMEM;
 
index 7d98676..4356144 100644 (file)
@@ -1107,22 +1107,13 @@ static const struct option options[] = {
  */
 static int add_default_attributes(void)
 {
-       struct perf_evsel *pos;
-       size_t attr_nr = 0;
-       size_t c;
-
        /* Set attrs if no event is selected and !null_run: */
        if (null_run)
                return 0;
 
        if (!evsel_list->nr_entries) {
-               for (c = 0; c < ARRAY_SIZE(default_attrs); c++) {
-                       pos = perf_evsel__new(default_attrs + c, c + attr_nr);
-                       if (pos == NULL)
-                               return -1;
-                       perf_evlist__add(evsel_list, pos);
-               }
-               attr_nr += c;
+               if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0)
+                       return -1;
        }
 
        /* Detailed events get appended to the event list: */
@@ -1131,38 +1122,21 @@ static int add_default_attributes(void)
                return 0;
 
        /* Append detailed run extra attributes: */
-       for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) {
-               pos = perf_evsel__new(detailed_attrs + c, c + attr_nr);
-               if (pos == NULL)
-                       return -1;
-               perf_evlist__add(evsel_list, pos);
-       }
-       attr_nr += c;
+       if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0)
+               return -1;
 
        if (detailed_run < 2)
                return 0;
 
        /* Append very detailed run extra attributes: */
-       for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) {
-               pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr);
-               if (pos == NULL)
-                       return -1;
-               perf_evlist__add(evsel_list, pos);
-       }
+       if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0)
+               return -1;
 
        if (detailed_run < 3)
                return 0;
 
        /* Append very, very detailed run extra attributes: */
-       for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) {
-               pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr);
-               if (pos == NULL)
-                       return -1;
-               perf_evlist__add(evsel_list, pos);
-       }
-
-
-       return 0;
+       return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs);
 }
 
 int cmd_stat(int argc, const char **argv, const char *prefix __used)
@@ -1266,8 +1240,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
 
        list_for_each_entry(pos, &evsel_list->entries, node) {
                if (perf_evsel__alloc_stat_priv(pos) < 0 ||
-                   perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
-                   perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
+                   perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0)
                        goto out_free_fd;
        }
 
index 831d1ba..6173f78 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "util/cache.h"
 #include "util/debug.h"
+#include "util/debugfs.h"
 #include "util/evlist.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"
@@ -14,8 +15,6 @@
 #include "util/thread_map.h"
 #include "../../include/linux/hw_breakpoint.h"
 
-static long page_size;
-
 static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
 {
        bool *visited = symbol__priv(sym);
@@ -31,6 +30,7 @@ static int test__vmlinux_matches_kallsyms(void)
        struct map *kallsyms_map, *vmlinux_map;
        struct machine kallsyms, vmlinux;
        enum map_type type = MAP__FUNCTION;
+       long page_size = sysconf(_SC_PAGE_SIZE);
        struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
 
        /*
@@ -247,7 +247,7 @@ static int trace_event__id(const char *evname)
 
        if (asprintf(&filename,
                     "%s/syscalls/%s/id",
-                    debugfs_path, evname) < 0)
+                    tracing_events_path, evname) < 0)
                return -1;
 
        fd = open(filename, O_RDONLY);
@@ -841,6 +841,336 @@ static int test__parse_events(void)
 
        return ret;
 }
+
+static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
+                                        size_t *sizep)
+{
+       cpu_set_t *mask;
+       size_t size;
+       int i, cpu = -1, nrcpus = 1024;
+realloc:
+       mask = CPU_ALLOC(nrcpus);
+       size = CPU_ALLOC_SIZE(nrcpus);
+       CPU_ZERO_S(size, mask);
+
+       if (sched_getaffinity(pid, size, mask) == -1) {
+               CPU_FREE(mask);
+               if (errno == EINVAL && nrcpus < (1024 << 8)) {
+                       nrcpus = nrcpus << 2;
+                       goto realloc;
+               }
+               perror("sched_getaffinity");
+                       return -1;
+       }
+
+       for (i = 0; i < nrcpus; i++) {
+               if (CPU_ISSET_S(i, size, mask)) {
+                       if (cpu == -1) {
+                               cpu = i;
+                               *maskp = mask;
+                               *sizep = size;
+                       } else
+                               CPU_CLR_S(i, size, mask);
+               }
+       }
+
+       if (cpu == -1)
+               CPU_FREE(mask);
+
+       return cpu;
+}
+
+static int test__PERF_RECORD(void)
+{
+       struct perf_record_opts opts = {
+               .target_pid = -1,
+               .target_tid = -1,
+               .no_delay   = true,
+               .freq       = 10,
+               .mmap_pages = 256,
+               .sample_id_all_avail = true,
+       };
+       cpu_set_t *cpu_mask = NULL;
+       size_t cpu_mask_size = 0;
+       struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+       struct perf_evsel *evsel;
+       struct perf_sample sample;
+       const char *cmd = "sleep";
+       const char *argv[] = { cmd, "1", NULL, };
+       char *bname;
+       u64 sample_type, prev_time = 0;
+       bool found_cmd_mmap = false,
+            found_libc_mmap = false,
+            found_vdso_mmap = false,
+            found_ld_mmap = false;
+       int err = -1, errs = 0, i, wakeups = 0, sample_size;
+       u32 cpu;
+       int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
+
+       if (evlist == NULL || argv == NULL) {
+               pr_debug("Not enough memory to create evlist\n");
+               goto out;
+       }
+
+       /*
+        * We need at least one evsel in the evlist, use the default
+        * one: "cycles".
+        */
+       err = perf_evlist__add_default(evlist);
+       if (err < 0) {
+               pr_debug("Not enough memory to create evsel\n");
+               goto out_delete_evlist;
+       }
+
+       /*
+        * Create maps of threads and cpus to monitor. In this case
+        * we start with all threads and cpus (-1, -1) but then in
+        * perf_evlist__prepare_workload we'll fill in the only thread
+        * we're monitoring, the one forked there.
+        */
+       err = perf_evlist__create_maps(evlist, opts.target_pid,
+                                      opts.target_tid, opts.cpu_list);
+       if (err < 0) {
+               pr_debug("Not enough memory to create thread/cpu maps\n");
+               goto out_delete_evlist;
+       }
+
+       /*
+        * Prepare the workload in argv[] to run, it'll fork it, and then wait
+        * for perf_evlist__start_workload() to exec it. This is done this way
+        * so that we have time to open the evlist (calling sys_perf_event_open
+        * on all the fds) and then mmap them.
+        */
+       err = perf_evlist__prepare_workload(evlist, &opts, argv);
+       if (err < 0) {
+               pr_debug("Couldn't run the workload!\n");
+               goto out_delete_evlist;
+       }
+
+       /*
+        * Config the evsels, setting attr->comm on the first one, etc.
+        */
+       evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+       evsel->attr.sample_type |= PERF_SAMPLE_CPU;
+       evsel->attr.sample_type |= PERF_SAMPLE_TID;
+       evsel->attr.sample_type |= PERF_SAMPLE_TIME;
+       perf_evlist__config_attrs(evlist, &opts);
+
+       err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask,
+                                           &cpu_mask_size);
+       if (err < 0) {
+               pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
+               goto out_delete_evlist;
+       }
+
+       cpu = err;
+
+       /*
+        * So that we can check perf_sample.cpu on all the samples.
+        */
+       if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) {
+               pr_debug("sched_setaffinity: %s\n", strerror(errno));
+               goto out_free_cpu_mask;
+       }
+
+       /*
+        * Call sys_perf_event_open on all the fds on all the evsels,
+        * grouping them if asked to.
+        */
+       err = perf_evlist__open(evlist, opts.group);
+       if (err < 0) {
+               pr_debug("perf_evlist__open: %s\n", strerror(errno));
+               goto out_delete_evlist;
+       }
+
+       /*
+        * mmap the first fd on a given CPU and ask for events for the other
+        * fds in the same CPU to be injected in the same mmap ring buffer
+        * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
+        */
+       err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
+       if (err < 0) {
+               pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
+               goto out_delete_evlist;
+       }
+
+       /*
+        * We'll need these two to parse the PERF_SAMPLE_* fields in each
+        * event.
+        */
+       sample_type = perf_evlist__sample_type(evlist);
+       sample_size = __perf_evsel__sample_size(sample_type);
+
+       /*
+        * Now that all is properly set up, enable the events, they will
+        * count just on workload.pid, which will start...
+        */
+       perf_evlist__enable(evlist);
+
+       /*
+        * Now!
+        */
+       perf_evlist__start_workload(evlist);
+
+       while (1) {
+               int before = total_events;
+
+               for (i = 0; i < evlist->nr_mmaps; i++) {
+                       union perf_event *event;
+
+                       while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+                               const u32 type = event->header.type;
+                               const char *name = perf_event__name(type);
+
+                               ++total_events;
+                               if (type < PERF_RECORD_MAX)
+                                       nr_events[type]++;
+
+                               err = perf_event__parse_sample(event, sample_type,
+                                                              sample_size, true,
+                                                              &sample, false);
+                               if (err < 0) {
+                                       if (verbose)
+                                               perf_event__fprintf(event, stderr);
+                                       pr_debug("Couldn't parse sample\n");
+                                       goto out_err;
+                               }
+
+                               if (verbose) {
+                                       pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
+                                       perf_event__fprintf(event, stderr);
+                               }
+
+                               if (prev_time > sample.time) {
+                                       pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
+                                                name, prev_time, sample.time);
+                                       ++errs;
+                               }
+
+                               prev_time = sample.time;
+
+                               if (sample.cpu != cpu) {
+                                       pr_debug("%s with unexpected cpu, expected %d, got %d\n",
+                                                name, cpu, sample.cpu);
+                                       ++errs;
+                               }
+
+                               if ((pid_t)sample.pid != evlist->workload.pid) {
+                                       pr_debug("%s with unexpected pid, expected %d, got %d\n",
+                                                name, evlist->workload.pid, sample.pid);
+                                       ++errs;
+                               }
+
+                               if ((pid_t)sample.tid != evlist->workload.pid) {
+                                       pr_debug("%s with unexpected tid, expected %d, got %d\n",
+                                                name, evlist->workload.pid, sample.tid);
+                                       ++errs;
+                               }
+
+                               if ((type == PERF_RECORD_COMM ||
+                                    type == PERF_RECORD_MMAP ||
+                                    type == PERF_RECORD_FORK ||
+                                    type == PERF_RECORD_EXIT) &&
+                                    (pid_t)event->comm.pid != evlist->workload.pid) {
+                                       pr_debug("%s with unexpected pid/tid\n", name);
+                                       ++errs;
+                               }
+
+                               if ((type == PERF_RECORD_COMM ||
+                                    type == PERF_RECORD_MMAP) &&
+                                    event->comm.pid != event->comm.tid) {
+                                       pr_debug("%s with different pid/tid!\n", name);
+                                       ++errs;
+                               }
+
+                               switch (type) {
+                               case PERF_RECORD_COMM:
+                                       if (strcmp(event->comm.comm, cmd)) {
+                                               pr_debug("%s with unexpected comm!\n", name);
+                                               ++errs;
+                                       }
+                                       break;
+                               case PERF_RECORD_EXIT:
+                                       goto found_exit;
+                               case PERF_RECORD_MMAP:
+                                       bname = strrchr(event->mmap.filename, '/');
+                                       if (bname != NULL) {
+                                               if (!found_cmd_mmap)
+                                                       found_cmd_mmap = !strcmp(bname + 1, cmd);
+                                               if (!found_libc_mmap)
+                                                       found_libc_mmap = !strncmp(bname + 1, "libc", 4);
+                                               if (!found_ld_mmap)
+                                                       found_ld_mmap = !strncmp(bname + 1, "ld", 2);
+                                       } else if (!found_vdso_mmap)
+                                               found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
+                                       break;
+
+                               case PERF_RECORD_SAMPLE:
+                                       /* Just ignore samples for now */
+                                       break;
+                               default:
+                                       pr_debug("Unexpected perf_event->header.type %d!\n",
+                                                type);
+                                       ++errs;
+                               }
+                       }
+               }
+
+               /*
+                * We don't use poll here because at least at 3.1 times the
+                * PERF_RECORD_{!SAMPLE} events don't honour
+                * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
+                */
+               if (total_events == before && false)
+                       poll(evlist->pollfd, evlist->nr_fds, -1);
+
+               sleep(1);
+               if (++wakeups > 5) {
+                       pr_debug("No PERF_RECORD_EXIT event!\n");
+                       break;
+               }
+       }
+
+found_exit:
+       if (nr_events[PERF_RECORD_COMM] > 1) {
+               pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
+               ++errs;
+       }
+
+       if (nr_events[PERF_RECORD_COMM] == 0) {
+               pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
+               ++errs;
+       }
+
+       if (!found_cmd_mmap) {
+               pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
+               ++errs;
+       }
+
+       if (!found_libc_mmap) {
+               pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
+               ++errs;
+       }
+
+       if (!found_ld_mmap) {
+               pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
+               ++errs;
+       }
+
+       if (!found_vdso_mmap) {
+               pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
+               ++errs;
+       }
+out_err:
+       perf_evlist__munmap(evlist);
+out_free_cpu_mask:
+       CPU_FREE(cpu_mask);
+out_delete_evlist:
+       perf_evlist__delete(evlist);
+out:
+       return (err < 0 || errs > 0) ? -1 : 0;
+}
+
 static struct test {
        const char *desc;
        int (*func)(void);
@@ -866,45 +1196,89 @@ static struct test {
                .func = test__parse_events,
        },
        {
+               .desc = "Validate PERF_RECORD_* events & perf_sample fields",
+               .func = test__PERF_RECORD,
+       },
+       {
                .func = NULL,
        },
 };
 
-static int __cmd_test(void)
+static bool perf_test__matches(int curr, int argc, const char *argv[])
 {
-       int i = 0;
+       int i;
+
+       if (argc == 0)
+               return true;
 
-       page_size = sysconf(_SC_PAGE_SIZE);
+       for (i = 0; i < argc; ++i) {
+               char *end;
+               long nr = strtoul(argv[i], &end, 10);
+
+               if (*end == '\0') {
+                       if (nr == curr + 1)
+                               return true;
+                       continue;
+               }
+
+               if (strstr(tests[curr].desc, argv[i]))
+                       return true;
+       }
+
+       return false;
+}
+
+static int __cmd_test(int argc, const char *argv[])
+{
+       int i = 0;
 
        while (tests[i].func) {
-               int err;
-               pr_info("%2d: %s:", i + 1, tests[i].desc);
+               int curr = i++, err;
+
+               if (!perf_test__matches(curr, argc, argv))
+                       continue;
+
+               pr_info("%2d: %s:", i, tests[curr].desc);
                pr_debug("\n--- start ---\n");
-               err = tests[i].func();
-               pr_debug("---- end ----\n%s:", tests[i].desc);
+               err = tests[curr].func();
+               pr_debug("---- end ----\n%s:", tests[curr].desc);
                pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
-               ++i;
        }
 
        return 0;
 }
 
-static const char * const test_usage[] = {
-       "perf test [<options>]",
-       NULL,
-};
+static int perf_test__list(int argc, const char **argv)
+{
+       int i = 0;
 
-static const struct option test_options[] = {
+       while (tests[i].func) {
+               int curr = i++;
+
+               if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
+                       continue;
+
+               pr_info("%2d: %s\n", i, tests[curr].desc);
+       }
+
+       return 0;
+}
+
+int cmd_test(int argc, const char **argv, const char *prefix __used)
+{
+       const char * const test_usage[] = {
+       "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
+       NULL,
+       };
+       const struct option test_options[] = {
        OPT_INTEGER('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_END()
-};
+       };
 
-int cmd_test(int argc, const char **argv, const char *prefix __used)
-{
        argc = parse_options(argc, argv, test_options, test_usage, 0);
-       if (argc)
-               usage_with_options(test_usage, test_options);
+       if (argc >= 1 && !strcmp(argv[0], "list"))
+               return perf_test__list(argc, argv);
 
        symbol_conf.priv_size = sizeof(int);
        symbol_conf.sort_by_name = true;
@@ -915,5 +1289,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used)
 
        setup_pager();
 
-       return __cmd_test();
+       return __cmd_test(argc, argv);
 }
index aa26f4d..135376a 100644 (file)
@@ -19,6 +19,7 @@
 #include "util/color.h"
 #include <linux/list.h>
 #include "util/cache.h"
+#include "util/evsel.h"
 #include <linux/rbtree.h>
 #include "util/symbol.h"
 #include "util/callchain.h"
@@ -31,6 +32,7 @@
 #include "util/event.h"
 #include "util/session.h"
 #include "util/svghelper.h"
+#include "util/tool.h"
 
 #define SUPPORT_OLD_POWER_EVENTS 1
 #define PWR_EVENT_EXIT -1
@@ -273,25 +275,28 @@ static int cpus_cstate_state[MAX_CPUS];
 static u64 cpus_pstate_start_times[MAX_CPUS];
 static u64 cpus_pstate_state[MAX_CPUS];
 
-static int process_comm_event(union perf_event *event,
+static int process_comm_event(struct perf_tool *tool __used,
+                             union perf_event *event,
                              struct perf_sample *sample __used,
-                             struct perf_session *session __used)
+                             struct machine *machine __used)
 {
        pid_set_comm(event->comm.tid, event->comm.comm);
        return 0;
 }
 
-static int process_fork_event(union perf_event *event,
+static int process_fork_event(struct perf_tool *tool __used,
+                             union perf_event *event,
                              struct perf_sample *sample __used,
-                             struct perf_session *session __used)
+                             struct machine *machine __used)
 {
        pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
        return 0;
 }
 
-static int process_exit_event(union perf_event *event,
+static int process_exit_event(struct perf_tool *tool __used,
+                             union perf_event *event,
                              struct perf_sample *sample __used,
-                             struct perf_session *session __used)
+                             struct machine *machine __used)
 {
        pid_exit(event->fork.pid, event->fork.time);
        return 0;
@@ -486,14 +491,15 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
 }
 
 
-static int process_sample_event(union perf_event *event __used,
+static int process_sample_event(struct perf_tool *tool __used,
+                               union perf_event *event __used,
                                struct perf_sample *sample,
-                               struct perf_evsel *evsel __used,
-                               struct perf_session *session)
+                               struct perf_evsel *evsel,
+                               struct machine *machine __used)
 {
        struct trace_entry *te;
 
-       if (session->sample_type & PERF_SAMPLE_TIME) {
+       if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
                if (!first_time || first_time > sample->time)
                        first_time = sample->time;
                if (last_time < sample->time)
@@ -501,7 +507,7 @@ static int process_sample_event(union perf_event *event __used,
        }
 
        te = (void *)sample->raw_data;
-       if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
+       if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
                char *event_str;
 #ifdef SUPPORT_OLD_POWER_EVENTS
                struct power_entry_old *peo;
@@ -974,7 +980,7 @@ static void write_svg_file(const char *filename)
        svg_close();
 }
 
-static struct perf_event_ops event_ops = {
+static struct perf_tool perf_timechart = {
        .comm                   = process_comm_event,
        .fork                   = process_fork_event,
        .exit                   = process_exit_event,
@@ -985,7 +991,7 @@ static struct perf_event_ops event_ops = {
 static int __cmd_timechart(void)
 {
        struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-                                                        0, false, &event_ops);
+                                                        0, false, &perf_timechart);
        int ret = -EINVAL;
 
        if (session == NULL)
@@ -994,7 +1000,7 @@ static int __cmd_timechart(void)
        if (!perf_session__has_traces(session, "timechart record"))
                goto out_delete;
 
-       ret = perf_session__process_events(session, &event_ops);
+       ret = perf_session__process_events(session, &perf_timechart);
        if (ret)
                goto out_delete;
 
index c9cdedb..c3836b9 100644 (file)
 #include <linux/unistd.h>
 #include <linux/types.h>
 
-static struct perf_top top = {
-       .count_filter           = 5,
-       .delay_secs             = 2,
-       .target_pid             = -1,
-       .target_tid             = -1,
-       .freq                   = 1000, /* 1 KHz */
-};
-
-static bool                    system_wide                     =  false;
-
-static bool                    use_tui, use_stdio;
-
-static bool                    sort_has_symbols;
-
-static bool                    dont_use_callchains;
-static char                    callchain_default_opt[]         = "fractal,0.5,callee";
-
-
-static int                     default_interval                =      0;
-
-static bool                    kptr_restrict_warned;
-static bool                    vmlinux_warned;
-static bool                    inherit                         =  false;
-static int                     realtime_prio                   =      0;
-static bool                    group                           =  false;
-static bool                    sample_id_all_avail             =   true;
-static unsigned int            mmap_pages                      =    128;
-
-static bool                    dump_symtab                     =  false;
-
-static struct winsize          winsize;
-
-static const char              *sym_filter                     =   NULL;
-static int                     sym_pcnt_filter                 =      5;
-
-/*
- * Source functions
- */
 
 void get_term_dimensions(struct winsize *ws)
 {
@@ -125,21 +87,23 @@ void get_term_dimensions(struct winsize *ws)
        ws->ws_col = 80;
 }
 
-static void update_print_entries(struct winsize *ws)
+static void perf_top__update_print_entries(struct perf_top *top)
 {
-       top.print_entries = ws->ws_row;
+       top->print_entries = top->winsize.ws_row;
 
-       if (top.print_entries > 9)
-               top.print_entries -= 9;
+       if (top->print_entries > 9)
+               top->print_entries -= 9;
 }
 
-static void sig_winch_handler(int sig __used)
+static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg)
 {
-       get_term_dimensions(&winsize);
-       update_print_entries(&winsize);
+       struct perf_top *top = arg;
+
+       get_term_dimensions(&top->winsize);
+       perf_top__update_print_entries(top);
 }
 
-static int parse_source(struct hist_entry *he)
+static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
 {
        struct symbol *sym;
        struct annotation *notes;
@@ -170,7 +134,7 @@ static int parse_source(struct hist_entry *he)
 
        pthread_mutex_lock(&notes->lock);
 
-       if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
+       if (symbol__alloc_hist(sym) < 0) {
                pthread_mutex_unlock(&notes->lock);
                pr_err("Not enough memory for annotating '%s' symbol!\n",
                       sym->name);
@@ -181,7 +145,7 @@ static int parse_source(struct hist_entry *he)
        err = symbol__annotate(sym, map, 0);
        if (err == 0) {
 out_assign:
-               top.sym_filter_entry = he;
+               top->sym_filter_entry = he;
        }
 
        pthread_mutex_unlock(&notes->lock);
@@ -194,14 +158,16 @@ static void __zero_source_counters(struct hist_entry *he)
        symbol__annotate_zero_histograms(sym);
 }
 
-static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
+static void perf_top__record_precise_ip(struct perf_top *top,
+                                       struct hist_entry *he,
+                                       int counter, u64 ip)
 {
        struct annotation *notes;
        struct symbol *sym;
 
        if (he == NULL || he->ms.sym == NULL ||
-           ((top.sym_filter_entry == NULL ||
-             top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
+           ((top->sym_filter_entry == NULL ||
+             top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
                return;
 
        sym = he->ms.sym;
@@ -210,8 +176,7 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
        if (pthread_mutex_trylock(&notes->lock))
                return;
 
-       if (notes->src == NULL &&
-           symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
+       if (notes->src == NULL && symbol__alloc_hist(sym) < 0) {
                pthread_mutex_unlock(&notes->lock);
                pr_err("Not enough memory for annotating '%s' symbol!\n",
                       sym->name);
@@ -225,8 +190,9 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
        pthread_mutex_unlock(&notes->lock);
 }
 
-static void show_details(struct hist_entry *he)
+static void perf_top__show_details(struct perf_top *top)
 {
+       struct hist_entry *he = top->sym_filter_entry;
        struct annotation *notes;
        struct symbol *symbol;
        int more;
@@ -242,15 +208,15 @@ static void show_details(struct hist_entry *he)
        if (notes->src == NULL)
                goto out_unlock;
 
-       printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name);
-       printf("  Events  Pcnt (>=%d%%)\n", sym_pcnt_filter);
+       printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name);
+       printf("  Events  Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
 
-       more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx,
-                                      0, sym_pcnt_filter, top.print_entries, 4);
-       if (top.zero)
-               symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx);
+       more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
+                                      0, top->sym_pcnt_filter, top->print_entries, 4);
+       if (top->zero)
+               symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx);
        else
-               symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx);
+               symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx);
        if (more != 0)
                printf("%d lines not displayed, maybe increase display entries [e]\n", more);
 out_unlock:
@@ -259,11 +225,9 @@ out_unlock:
 
 static const char              CONSOLE_CLEAR[] = "\e[H\e[2J";
 
-static struct hist_entry *
-       perf_session__add_hist_entry(struct perf_session *session,
-                                    struct addr_location *al,
-                                    struct perf_sample *sample,
-                                    struct perf_evsel *evsel)
+static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
+                                                    struct addr_location *al,
+                                                    struct perf_sample *sample)
 {
        struct hist_entry *he;
 
@@ -271,50 +235,51 @@ static struct hist_entry *
        if (he == NULL)
                return NULL;
 
-       session->hists.stats.total_period += sample->period;
+       evsel->hists.stats.total_period += sample->period;
        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
        return he;
 }
 
-static void print_sym_table(void)
+static void perf_top__print_sym_table(struct perf_top *top)
 {
        char bf[160];
        int printed = 0;
-       const int win_width = winsize.ws_col - 1;
+       const int win_width = top->winsize.ws_col - 1;
 
        puts(CONSOLE_CLEAR);
 
-       perf_top__header_snprintf(&top, bf, sizeof(bf));
+       perf_top__header_snprintf(top, bf, sizeof(bf));
        printf("%s\n", bf);
 
-       perf_top__reset_sample_counters(&top);
+       perf_top__reset_sample_counters(top);
 
        printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
 
-       if (top.sym_evsel->hists.stats.nr_lost_warned !=
-           top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
-               top.sym_evsel->hists.stats.nr_lost_warned =
-                       top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
+       if (top->sym_evsel->hists.stats.nr_lost_warned !=
+           top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
+               top->sym_evsel->hists.stats.nr_lost_warned =
+                       top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
                color_fprintf(stdout, PERF_COLOR_RED,
                              "WARNING: LOST %d chunks, Check IO/CPU overload",
-                             top.sym_evsel->hists.stats.nr_lost_warned);
+                             top->sym_evsel->hists.stats.nr_lost_warned);
                ++printed;
        }
 
-       if (top.sym_filter_entry) {
-               show_details(top.sym_filter_entry);
+       if (top->sym_filter_entry) {
+               perf_top__show_details(top);
                return;
        }
 
-       hists__collapse_resort_threaded(&top.sym_evsel->hists);
-       hists__output_resort_threaded(&top.sym_evsel->hists);
-       hists__decay_entries_threaded(&top.sym_evsel->hists,
-                                     top.hide_user_symbols,
-                                     top.hide_kernel_symbols);
-       hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3);
+       hists__collapse_resort_threaded(&top->sym_evsel->hists);
+       hists__output_resort_threaded(&top->sym_evsel->hists);
+       hists__decay_entries_threaded(&top->sym_evsel->hists,
+                                     top->hide_user_symbols,
+                                     top->hide_kernel_symbols);
+       hists__output_recalc_col_len(&top->sym_evsel->hists,
+                                    top->winsize.ws_row - 3);
        putchar('\n');
-       hists__fprintf(&top.sym_evsel->hists, NULL, false, false,
-                      winsize.ws_row - 4 - printed, win_width, stdout);
+       hists__fprintf(&top->sym_evsel->hists, NULL, false, false,
+                      top->winsize.ws_row - 4 - printed, win_width, stdout);
 }
 
 static void prompt_integer(int *target, const char *msg)
@@ -352,17 +317,17 @@ static void prompt_percent(int *target, const char *msg)
                *target = tmp;
 }
 
-static void prompt_symbol(struct hist_entry **target, const char *msg)
+static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
 {
        char *buf = malloc(0), *p;
-       struct hist_entry *syme = *target, *n, *found = NULL;
+       struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
        struct rb_node *next;
        size_t dummy = 0;
 
        /* zero counters of active symbol */
        if (syme) {
                __zero_source_counters(syme);
-               *target = NULL;
+               top->sym_filter_entry = NULL;
        }
 
        fprintf(stdout, "\n%s: ", msg);
@@ -373,7 +338,7 @@ static void prompt_symbol(struct hist_entry **target, const char *msg)
        if (p)
                *p = 0;
 
-       next = rb_first(&top.sym_evsel->hists.entries);
+       next = rb_first(&top->sym_evsel->hists.entries);
        while (next) {
                n = rb_entry(next, struct hist_entry, rb_node);
                if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
@@ -388,45 +353,45 @@ static void prompt_symbol(struct hist_entry **target, const char *msg)
                sleep(1);
                return;
        } else
-               parse_source(found);
+               perf_top__parse_source(top, found);
 
 out_free:
        free(buf);
 }
 
-static void print_mapped_keys(void)
+static void perf_top__print_mapped_keys(struct perf_top *top)
 {
        char *name = NULL;
 
-       if (top.sym_filter_entry) {
-               struct symbol *sym = top.sym_filter_entry->ms.sym;
+       if (top->sym_filter_entry) {
+               struct symbol *sym = top->sym_filter_entry->ms.sym;
                name = sym->name;
        }
 
        fprintf(stdout, "\nMapped keys:\n");
-       fprintf(stdout, "\t[d]     display refresh delay.             \t(%d)\n", top.delay_secs);
-       fprintf(stdout, "\t[e]     display entries (lines).           \t(%d)\n", top.print_entries);
+       fprintf(stdout, "\t[d]     display refresh delay.             \t(%d)\n", top->delay_secs);
+       fprintf(stdout, "\t[e]     display entries (lines).           \t(%d)\n", top->print_entries);
 
-       if (top.evlist->nr_entries > 1)
-               fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(top.sym_evsel));
+       if (top->evlist->nr_entries > 1)
+               fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(top->sym_evsel));
 
-       fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", top.count_filter);
+       fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", top->count_filter);
 
-       fprintf(stdout, "\t[F]     annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
+       fprintf(stdout, "\t[F]     annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter);
        fprintf(stdout, "\t[s]     annotate symbol.                   \t(%s)\n", name?: "NULL");
        fprintf(stdout, "\t[S]     stop annotation.\n");
 
        fprintf(stdout,
                "\t[K]     hide kernel_symbols symbols.     \t(%s)\n",
-               top.hide_kernel_symbols ? "yes" : "no");
+               top->hide_kernel_symbols ? "yes" : "no");
        fprintf(stdout,
                "\t[U]     hide user symbols.               \t(%s)\n",
-               top.hide_user_symbols ? "yes" : "no");
-       fprintf(stdout, "\t[z]     toggle sample zeroing.             \t(%d)\n", top.zero ? 1 : 0);
+               top->hide_user_symbols ? "yes" : "no");
+       fprintf(stdout, "\t[z]     toggle sample zeroing.             \t(%d)\n", top->zero ? 1 : 0);
        fprintf(stdout, "\t[qQ]    quit.\n");
 }
 
-static int key_mapped(int c)
+static int perf_top__key_mapped(struct perf_top *top, int c)
 {
        switch (c) {
                case 'd':
@@ -442,7 +407,7 @@ static int key_mapped(int c)
                case 'S':
                        return 1;
                case 'E':
-                       return top.evlist->nr_entries > 1 ? 1 : 0;
+                       return top->evlist->nr_entries > 1 ? 1 : 0;
                default:
                        break;
        }
@@ -450,13 +415,13 @@ static int key_mapped(int c)
        return 0;
 }
 
-static void handle_keypress(int c)
+static void perf_top__handle_keypress(struct perf_top *top, int c)
 {
-       if (!key_mapped(c)) {
+       if (!perf_top__key_mapped(top, c)) {
                struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
                struct termios tc, save;
 
-               print_mapped_keys();
+               perf_top__print_mapped_keys(top);
                fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
                fflush(stdout);
 
@@ -471,81 +436,86 @@ static void handle_keypress(int c)
                c = getc(stdin);
 
                tcsetattr(0, TCSAFLUSH, &save);
-               if (!key_mapped(c))
+               if (!perf_top__key_mapped(top, c))
                        return;
        }
 
        switch (c) {
                case 'd':
-                       prompt_integer(&top.delay_secs, "Enter display delay");
-                       if (top.delay_secs < 1)
-                               top.delay_secs = 1;
+                       prompt_integer(&top->delay_secs, "Enter display delay");
+                       if (top->delay_secs < 1)
+                               top->delay_secs = 1;
                        break;
                case 'e':
-                       prompt_integer(&top.print_entries, "Enter display entries (lines)");
-                       if (top.print_entries == 0) {
-                               sig_winch_handler(SIGWINCH);
-                               signal(SIGWINCH, sig_winch_handler);
+                       prompt_integer(&top->print_entries, "Enter display entries (lines)");
+                       if (top->print_entries == 0) {
+                               struct sigaction act = {
+                                       .sa_sigaction = perf_top__sig_winch,
+                                       .sa_flags     = SA_SIGINFO,
+                               };
+                               perf_top__sig_winch(SIGWINCH, NULL, top);
+                               sigaction(SIGWINCH, &act, NULL);
                        } else
                                signal(SIGWINCH, SIG_DFL);
                        break;
                case 'E':
-                       if (top.evlist->nr_entries > 1) {
+                       if (top->evlist->nr_entries > 1) {
                                /* Select 0 as the default event: */
                                int counter = 0;
 
                                fprintf(stderr, "\nAvailable events:");
 
-                               list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
-                                       fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
+                               list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
+                                       fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel));
 
                                prompt_integer(&counter, "Enter details event counter");
 
-                               if (counter >= top.evlist->nr_entries) {
-                                       top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
-                                       fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
+                               if (counter >= top->evlist->nr_entries) {
+                                       top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
+                                       fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel));
                                        sleep(1);
                                        break;
                                }
-                               list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
-                                       if (top.sym_evsel->idx == counter)
+                               list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
+                                       if (top->sym_evsel->idx == counter)
                                                break;
                        } else
-                               top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
+                               top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
                        break;
                case 'f':
-                       prompt_integer(&top.count_filter, "Enter display event count filter");
+                       prompt_integer(&top->count_filter, "Enter display event count filter");
                        break;
                case 'F':
-                       prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
+                       prompt_percent(&top->sym_pcnt_filter,
+                                      "Enter details display event filter (percent)");
                        break;
                case 'K':
-                       top.hide_kernel_symbols = !top.hide_kernel_symbols;
+                       top->hide_kernel_symbols = !top->hide_kernel_symbols;
                        break;
                case 'q':
                case 'Q':
                        printf("exiting.\n");
-                       if (dump_symtab)
-                               perf_session__fprintf_dsos(top.session, stderr);
+                       if (top->dump_symtab)
+                               perf_session__fprintf_dsos(top->session, stderr);
                        exit(0);
                case 's':
-                       prompt_symbol(&top.sym_filter_entry, "Enter details symbol");
+                       perf_top__prompt_symbol(top, "Enter details symbol");
                        break;
                case 'S':
-                       if (!top.sym_filter_entry)
+                       if (!top->sym_filter_entry)
                                break;
                        else {
-                               struct hist_entry *syme = top.sym_filter_entry;
+                               struct hist_entry *syme = top->sym_filter_entry;
 
-                               top.sym_filter_entry = NULL;
+                               top->sym_filter_entry = NULL;
                                __zero_source_counters(syme);
                        }
                        break;
                case 'U':
-                       top.hide_user_symbols = !top.hide_user_symbols;
+                       top->hide_user_symbols = !top->hide_user_symbols;
                        break;
                case 'z':
-                       top.zero = !top.zero;
+                       top->zero = !top->zero;
                        break;
                default:
                        break;
@@ -563,28 +533,30 @@ static void perf_top__sort_new_samples(void *arg)
        hists__collapse_resort_threaded(&t->sym_evsel->hists);
        hists__output_resort_threaded(&t->sym_evsel->hists);
        hists__decay_entries_threaded(&t->sym_evsel->hists,
-                                     top.hide_user_symbols,
-                                     top.hide_kernel_symbols);
+                                     t->hide_user_symbols,
+                                     t->hide_kernel_symbols);
 }
 
-static void *display_thread_tui(void *arg __used)
+static void *display_thread_tui(void *arg)
 {
+       struct perf_top *top = arg;
        const char *help = "For a higher level overview, try: perf top --sort comm,dso";
 
-       perf_top__sort_new_samples(&top);
-       perf_evlist__tui_browse_hists(top.evlist, help,
+       perf_top__sort_new_samples(top);
+       perf_evlist__tui_browse_hists(top->evlist, help,
                                      perf_top__sort_new_samples,
-                                     &top, top.delay_secs);
+                                     top, top->delay_secs);
 
        exit_browser(0);
        exit(0);
        return NULL;
 }
 
-static void *display_thread(void *arg __used)
+static void *display_thread(void *arg)
 {
        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
        struct termios tc, save;
+       struct perf_top *top = arg;
        int delay_msecs, c;
 
        tcgetattr(0, &save);
@@ -595,13 +567,13 @@ static void *display_thread(void *arg __used)
 
        pthread__unblock_sigwinch();
 repeat:
-       delay_msecs = top.delay_secs * 1000;
+       delay_msecs = top->delay_secs * 1000;
        tcsetattr(0, TCSANOW, &tc);
        /* trash return*/
        getc(stdin);
 
        while (1) {
-               print_sym_table();
+               perf_top__print_sym_table(top);
                /*
                 * Either timeout expired or we got an EINTR due to SIGWINCH,
                 * refresh screen in both cases.
@@ -621,7 +593,7 @@ process_hotkey:
        c = getc(stdin);
        tcsetattr(0, TCSAFLUSH, &save);
 
-       handle_keypress(c);
+       perf_top__handle_keypress(top, c);
        goto repeat;
 
        return NULL;
@@ -673,47 +645,17 @@ static int symbol_filter(struct map *map __used, struct symbol *sym)
        return 0;
 }
 
-static void perf_event__process_sample(const union perf_event *event,
+static void perf_event__process_sample(struct perf_tool *tool,
+                                      const union perf_event *event,
                                       struct perf_evsel *evsel,
                                       struct perf_sample *sample,
-                                      struct perf_session *session)
+                                      struct machine *machine)
 {
+       struct perf_top *top = container_of(tool, struct perf_top, tool);
        struct symbol *parent = NULL;
        u64 ip = event->ip.ip;
        struct addr_location al;
-       struct machine *machine;
        int err;
-       u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-
-       ++top.samples;
-
-       switch (origin) {
-       case PERF_RECORD_MISC_USER:
-               ++top.us_samples;
-               if (top.hide_user_symbols)
-                       return;
-               machine = perf_session__find_host_machine(session);
-               break;
-       case PERF_RECORD_MISC_KERNEL:
-               ++top.kernel_samples;
-               if (top.hide_kernel_symbols)
-                       return;
-               machine = perf_session__find_host_machine(session);
-               break;
-       case PERF_RECORD_MISC_GUEST_KERNEL:
-               ++top.guest_kernel_samples;
-               machine = perf_session__find_machine(session, event->ip.pid);
-               break;
-       case PERF_RECORD_MISC_GUEST_USER:
-               ++top.guest_us_samples;
-               /*
-                * TODO: we don't process guest user from host side
-                * except simple counting.
-                */
-               return;
-       default:
-               return;
-       }
 
        if (!machine && perf_guest) {
                pr_err("Can't find guest [%d]'s kernel information\n",
@@ -722,14 +664,14 @@ static void perf_event__process_sample(const union perf_event *event,
        }
 
        if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
-               top.exact_samples++;
+               top->exact_samples++;
 
-       if (perf_event__preprocess_sample(event, session, &al, sample,
+       if (perf_event__preprocess_sample(event, machine, &al, sample,
                                          symbol_filter) < 0 ||
            al.filtered)
                return;
 
-       if (!kptr_restrict_warned &&
+       if (!top->kptr_restrict_warned &&
            symbol_conf.kptr_restrict &&
            al.cpumode == PERF_RECORD_MISC_KERNEL) {
                ui__warning(
@@ -740,7 +682,7 @@ static void perf_event__process_sample(const union perf_event *event,
                          " modules" : "");
                if (use_browser <= 0)
                        sleep(5);
-               kptr_restrict_warned = true;
+               top->kptr_restrict_warned = true;
        }
 
        if (al.sym == NULL) {
@@ -756,7 +698,7 @@ static void perf_event__process_sample(const union perf_event *event,
                 * --hide-kernel-symbols, even if the user specifies an
                 * invalid --vmlinux ;-)
                 */
-               if (!kptr_restrict_warned && !vmlinux_warned &&
+               if (!top->kptr_restrict_warned && !top->vmlinux_warned &&
                    al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
                    RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
                        if (symbol_conf.vmlinux_name) {
@@ -769,7 +711,7 @@ static void perf_event__process_sample(const union perf_event *event,
 
                        if (use_browser <= 0)
                                sleep(5);
-                       vmlinux_warned = true;
+                       top->vmlinux_warned = true;
                }
        }
 
@@ -778,70 +720,109 @@ static void perf_event__process_sample(const union perf_event *event,
 
                if ((sort__has_parent || symbol_conf.use_callchain) &&
                    sample->callchain) {
-                       err = perf_session__resolve_callchain(session, al.thread,
-                                                             sample->callchain, &parent);
+                       err = machine__resolve_callchain(machine, evsel, al.thread,
+                                                        sample->callchain, &parent);
                        if (err)
                                return;
                }
 
-               he = perf_session__add_hist_entry(session, &al, sample, evsel);
+               he = perf_evsel__add_hist_entry(evsel, &al, sample);
                if (he == NULL) {
                        pr_err("Problem incrementing symbol period, skipping event\n");
                        return;
                }
 
                if (symbol_conf.use_callchain) {
-                       err = callchain_append(he->callchain, &session->callchain_cursor,
+                       err = callchain_append(he->callchain, &evsel->hists.callchain_cursor,
                                               sample->period);
                        if (err)
                                return;
                }
 
-               if (sort_has_symbols)
-                       record_precise_ip(he, evsel->idx, ip);
+               if (top->sort_has_symbols)
+                       perf_top__record_precise_ip(top, he, evsel->idx, ip);
        }
 
        return;
 }
 
-static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
+static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
 {
        struct perf_sample sample;
        struct perf_evsel *evsel;
+       struct perf_session *session = top->session;
        union perf_event *event;
+       struct machine *machine;
+       u8 origin;
        int ret;
 
-       while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
-               ret = perf_session__parse_sample(self, event, &sample);
+       while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
+               ret = perf_session__parse_sample(session, event, &sample);
                if (ret) {
                        pr_err("Can't parse sample, err = %d\n", ret);
                        continue;
                }
 
-               evsel = perf_evlist__id2evsel(self->evlist, sample.id);
+               evsel = perf_evlist__id2evsel(session->evlist, sample.id);
                assert(evsel != NULL);
 
+               origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+
                if (event->header.type == PERF_RECORD_SAMPLE)
-                       perf_event__process_sample(event, evsel, &sample, self);
-               else if (event->header.type < PERF_RECORD_MAX) {
+                       ++top->samples;
+
+               switch (origin) {
+               case PERF_RECORD_MISC_USER:
+                       ++top->us_samples;
+                       if (top->hide_user_symbols)
+                               continue;
+                       machine = perf_session__find_host_machine(session);
+                       break;
+               case PERF_RECORD_MISC_KERNEL:
+                       ++top->kernel_samples;
+                       if (top->hide_kernel_symbols)
+                               continue;
+                       machine = perf_session__find_host_machine(session);
+                       break;
+               case PERF_RECORD_MISC_GUEST_KERNEL:
+                       ++top->guest_kernel_samples;
+                       machine = perf_session__find_machine(session, event->ip.pid);
+                       break;
+               case PERF_RECORD_MISC_GUEST_USER:
+                       ++top->guest_us_samples;
+                       /*
+                        * TODO: we don't process guest user from host side
+                        * except simple counting.
+                        */
+                       /* Fall thru */
+               default:
+                       continue;
+               }
+
+
+               if (event->header.type == PERF_RECORD_SAMPLE) {
+                       perf_event__process_sample(&top->tool, event, evsel,
+                                                  &sample, machine);
+               } else if (event->header.type < PERF_RECORD_MAX) {
                        hists__inc_nr_events(&evsel->hists, event->header.type);
-                       perf_event__process(event, &sample, self);
+                       perf_event__process(&top->tool, event, &sample, machine);
                } else
-                       ++self->hists.stats.nr_unknown_events;
+                       ++session->hists.stats.nr_unknown_events;
        }
 }
 
-static void perf_session__mmap_read(struct perf_session *self)
+static void perf_top__mmap_read(struct perf_top *top)
 {
        int i;
 
-       for (i = 0; i < top.evlist->nr_mmaps; i++)
-               perf_session__mmap_read_idx(self, i);
+       for (i = 0; i < top->evlist->nr_mmaps; i++)
+               perf_top__mmap_read_idx(top, i);
 }
 
-static void start_counters(struct perf_evlist *evlist)
+static void perf_top__start_counters(struct perf_top *top)
 {
        struct perf_evsel *counter, *first;
+       struct perf_evlist *evlist = top->evlist;
 
        first = list_entry(evlist->entries.next, struct perf_evsel, node);
 
@@ -849,15 +830,15 @@ static void start_counters(struct perf_evlist *evlist)
                struct perf_event_attr *attr = &counter->attr;
                struct xyarray *group_fd = NULL;
 
-               if (group && counter != first)
+               if (top->group && counter != first)
                        group_fd = first->fd;
 
                attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 
-               if (top.freq) {
+               if (top->freq) {
                        attr->sample_type |= PERF_SAMPLE_PERIOD;
                        attr->freq        = 1;
-                       attr->sample_freq = top.freq;
+                       attr->sample_freq = top->freq;
                }
 
                if (evlist->nr_entries > 1) {
@@ -870,23 +851,23 @@ static void start_counters(struct perf_evlist *evlist)
 
                attr->mmap = 1;
                attr->comm = 1;
-               attr->inherit = inherit;
+               attr->inherit = top->inherit;
 retry_sample_id:
-               attr->sample_id_all = sample_id_all_avail ? 1 : 0;
+               attr->sample_id_all = top->sample_id_all_avail ? 1 : 0;
 try_again:
-               if (perf_evsel__open(counter, top.evlist->cpus,
-                                    top.evlist->threads, group,
+               if (perf_evsel__open(counter, top->evlist->cpus,
+                                    top->evlist->threads, top->group,
                                     group_fd) < 0) {
                        int err = errno;
 
                        if (err == EPERM || err == EACCES) {
                                ui__error_paranoid();
                                goto out_err;
-                       } else if (err == EINVAL && sample_id_all_avail) {
+                       } else if (err == EINVAL && top->sample_id_all_avail) {
                                /*
                                 * Old kernel, no attr->sample_id_type_all field
                                 */
-                               sample_id_all_avail = false;
+                               top->sample_id_all_avail = false;
                                goto retry_sample_id;
                        }
                        /*
@@ -920,7 +901,7 @@ try_again:
                }
        }
 
-       if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) {
+       if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) {
                ui__warning("Failed to mmap with %d (%s)\n",
                            errno, strerror(errno));
                goto out_err;
@@ -933,14 +914,14 @@ out_err:
        exit(0);
 }
 
-static int setup_sample_type(void)
+static int perf_top__setup_sample_type(struct perf_top *top)
 {
-       if (!sort_has_symbols) {
+       if (!top->sort_has_symbols) {
                if (symbol_conf.use_callchain) {
                        ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
                        return -EINVAL;
                }
-       } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
+       } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
                if (callchain_register_param(&callchain_param) < 0) {
                        ui__warning("Can't register callchain params.\n");
                        return -EINVAL;
@@ -950,7 +931,7 @@ static int setup_sample_type(void)
        return 0;
 }
 
-static int __cmd_top(void)
+static int __cmd_top(struct perf_top *top)
 {
        pthread_t thread;
        int ret;
@@ -958,39 +939,40 @@ static int __cmd_top(void)
         * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
         * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
         */
-       top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
-       if (top.session == NULL)
+       top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
+       if (top->session == NULL)
                return -ENOMEM;
 
-       ret = setup_sample_type();
+       ret = perf_top__setup_sample_type(top);
        if (ret)
                goto out_delete;
 
-       if (top.target_tid != -1)
-               perf_event__synthesize_thread_map(top.evlist->threads,
-                                                 perf_event__process, top.session);
+       if (top->target_tid != -1)
+               perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
+                                                 perf_event__process,
+                                                 &top->session->host_machine);
        else
-               perf_event__synthesize_threads(perf_event__process, top.session);
-
-       start_counters(top.evlist);
-       top.session->evlist = top.evlist;
-       perf_session__update_sample_type(top.session);
+               perf_event__synthesize_threads(&top->tool, perf_event__process,
+                                              &top->session->host_machine);
+       perf_top__start_counters(top);
+       top->session->evlist = top->evlist;
+       perf_session__update_sample_type(top->session);
 
        /* Wait for a minimal set of events before starting the snapshot */
-       poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
+       poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
 
-       perf_session__mmap_read(top.session);
+       perf_top__mmap_read(top);
 
        if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
-                                                            display_thread), NULL)) {
+                                                           display_thread), top)) {
                printf("Could not create display thread.\n");
                exit(-1);
        }
 
-       if (realtime_prio) {
+       if (top->realtime_prio) {
                struct sched_param param;
 
-               param.sched_priority = realtime_prio;
+               param.sched_priority = top->realtime_prio;
                if (sched_setscheduler(0, SCHED_FIFO, &param)) {
                        printf("Could not set realtime priority.\n");
                        exit(-1);
@@ -998,25 +980,25 @@ static int __cmd_top(void)
        }
 
        while (1) {
-               u64 hits = top.samples;
+               u64 hits = top->samples;
 
-               perf_session__mmap_read(top.session);
+               perf_top__mmap_read(top);
 
-               if (hits == top.samples)
-                       ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100);
+               if (hits == top->samples)
+                       ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
        }
 
 out_delete:
-       perf_session__delete(top.session);
-       top.session = NULL;
+       perf_session__delete(top->session);
+       top->session = NULL;
 
        return 0;
 }
 
 static int
-parse_callchain_opt(const struct option *opt __used, const char *arg,
-                   int unset)
+parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 {
+       struct perf_top *top = (struct perf_top *)opt->value;
        char *tok, *tok2;
        char *endptr;
 
@@ -1024,7 +1006,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
         * --no-call-graph
         */
        if (unset) {
-               dont_use_callchains = true;
+               top->dont_use_callchains = true;
                return 0;
        }
 
@@ -1052,9 +1034,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
                symbol_conf.use_callchain = false;
 
                return 0;
-       }
-
-       else
+       } else
                return -1;
 
        /* get the min percentage */
@@ -1098,17 +1078,32 @@ static const char * const top_usage[] = {
        NULL
 };
 
-static const struct option options[] = {
+int cmd_top(int argc, const char **argv, const char *prefix __used)
+{
+       struct perf_evsel *pos;
+       int status = -ENOMEM;
+       struct perf_top top = {
+               .count_filter        = 5,
+               .delay_secs          = 2,
+               .target_pid          = -1,
+               .target_tid          = -1,
+               .freq                = 1000, /* 1 KHz */
+               .sample_id_all_avail = true,
+               .mmap_pages          = 128,
+               .sym_pcnt_filter     = 5,
+       };
+       char callchain_default_opt[] = "fractal,0.5,callee";
+       const struct option options[] = {
        OPT_CALLBACK('e', "event", &top.evlist, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events_option),
-       OPT_INTEGER('c', "count", &default_interval,
+       OPT_INTEGER('c', "count", &top.default_interval,
                    "event period to sample"),
        OPT_INTEGER('p', "pid", &top.target_pid,
                    "profile events on existing process id"),
        OPT_INTEGER('t', "tid", &top.target_tid,
                    "profile events on existing thread id"),
-       OPT_BOOLEAN('a', "all-cpus", &system_wide,
+       OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
                            "system-wide collection from all CPUs"),
        OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
                    "list of cpus to monitor"),
@@ -1116,20 +1111,20 @@ static const struct option options[] = {
                   "file", "vmlinux pathname"),
        OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
                    "hide kernel symbols"),
-       OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
-       OPT_INTEGER('r', "realtime", &realtime_prio,
+       OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"),
+       OPT_INTEGER('r', "realtime", &top.realtime_prio,
                    "collect data with this RT SCHED_FIFO priority"),
        OPT_INTEGER('d', "delay", &top.delay_secs,
                    "number of seconds to delay between refreshes"),
-       OPT_BOOLEAN('D', "dump-symtab", &dump_symtab,
+       OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab,
                            "dump the symbol table used for profiling"),
        OPT_INTEGER('f', "count-filter", &top.count_filter,
                    "only display functions with more events than this"),
-       OPT_BOOLEAN('g', "group", &group,
+       OPT_BOOLEAN('g', "group", &top.group,
                            "put the counters into a counter group"),
-       OPT_BOOLEAN('i', "inherit", &inherit,
+       OPT_BOOLEAN('i', "inherit", &top.inherit,
                    "child tasks inherit counters"),
-       OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name",
+       OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
                    "symbol to annotate"),
        OPT_BOOLEAN('z', "zero", &top.zero,
                    "zero history across updates"),
@@ -1139,15 +1134,15 @@ static const struct option options[] = {
                    "display this many functions"),
        OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
                    "hide user symbols"),
-       OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
-       OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
+       OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"),
+       OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent"),
        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
                    "Show a column with the number of samples"),
-       OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order",
+       OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order",
                     "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
                     "Default: fractal,0.5,callee", &parse_callchain_opt,
                     callchain_default_opt),
@@ -1166,12 +1161,7 @@ static const struct option options[] = {
        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
                   "Specify disassembler style (e.g. -M intel for intel syntax)"),
        OPT_END()
-};
-
-int cmd_top(int argc, const char **argv, const char *prefix __used)
-{
-       struct perf_evsel *pos;
-       int status = -ENOMEM;
+       };
 
        top.evlist = perf_evlist__new(NULL, NULL);
        if (top.evlist == NULL)
@@ -1188,9 +1178,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
 
        setup_sorting(top_usage, options);
 
-       if (use_stdio)
+       if (top.use_stdio)
                use_browser = 0;
-       else if (use_tui)
+       else if (top.use_tui)
                use_browser = 1;
 
        setup_browser(false);
@@ -1215,38 +1205,31 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
                return -ENOMEM;
        }
 
+       symbol_conf.nr_events = top.evlist->nr_entries;
+
        if (top.delay_secs < 1)
                top.delay_secs = 1;
 
        /*
         * User specified count overrides default frequency.
         */
-       if (default_interval)
+       if (top.default_interval)
                top.freq = 0;
        else if (top.freq) {
-               default_interval = top.freq;
+               top.default_interval = top.freq;
        } else {
                fprintf(stderr, "frequency and count are zero, aborting\n");
                exit(EXIT_FAILURE);
        }
 
        list_for_each_entry(pos, &top.evlist->entries, node) {
-               if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
-                                        top.evlist->threads->nr) < 0)
-                       goto out_free_fd;
                /*
                 * Fill in the ones not specifically initialized via -c:
                 */
-               if (pos->attr.sample_period)
-                       continue;
-
-               pos->attr.sample_period = default_interval;
+               if (!pos->attr.sample_period)
+                       pos->attr.sample_period = top.default_interval;
        }
 
-       if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
-           perf_evlist__alloc_mmap(top.evlist) < 0)
-               goto out_free_fd;
-
        top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
 
        symbol_conf.priv_size = sizeof(struct annotation);
@@ -1263,16 +1246,20 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
         * Avoid annotation data structures overhead when symbols aren't on the
         * sort list.
         */
-       sort_has_symbols = sort_sym.list.next != NULL;
+       top.sort_has_symbols = sort_sym.list.next != NULL;
 
-       get_term_dimensions(&winsize);
+       get_term_dimensions(&top.winsize);
        if (top.print_entries == 0) {
-               update_print_entries(&winsize);
-               signal(SIGWINCH, sig_winch_handler);
+               struct sigaction act = {
+                       .sa_sigaction = perf_top__sig_winch,
+                       .sa_flags     = SA_SIGINFO,
+               };
+               perf_top__update_print_entries(&top);
+               sigaction(SIGWINCH, &act, NULL);
        }
 
-       status = __cmd_top();
-out_free_fd:
+       status = __cmd_top(&top);
+
        perf_evlist__delete(top.evlist);
 
        return status;
index 73d0cac..2b2e225 100644 (file)
@@ -29,8 +29,6 @@ struct pager_config {
        int val;
 };
 
-static char debugfs_mntpt[MAXPATHLEN];
-
 static int pager_command_config(const char *var, const char *value, void *data)
 {
        struct pager_config *c = data;
@@ -81,15 +79,6 @@ static void commit_pager_choice(void)
        }
 }
 
-static void set_debugfs_path(void)
-{
-       char *path;
-
-       path = getenv(PERF_DEBUGFS_ENVIRONMENT);
-       snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
-                "tracing/events");
-}
-
 static int handle_options(const char ***argv, int *argc, int *envchanged)
 {
        int handled = 0;
@@ -161,15 +150,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                                fprintf(stderr, "No directory given for --debugfs-dir.\n");
                                usage(perf_usage_string);
                        }
-                       strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN);
-                       debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+                       debugfs_set_path((*argv)[1]);
                        if (envchanged)
                                *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
                } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
-                       strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
-                       debugfs_mntpt[MAXPATHLEN - 1] = '\0';
+                       debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
+                       fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
                        if (envchanged)
                                *envchanged = 1;
                } else {
@@ -281,7 +269,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        if (use_pager == -1 && p->option & USE_PAGER)
                use_pager = 1;
        commit_pager_choice();
-       set_debugfs_path();
 
        status = p->fn(argc, argv, prefix);
        exit_browser(status);
@@ -416,17 +403,6 @@ static int run_argv(int *argcp, const char ***argv)
        return done_alias;
 }
 
-/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
-static void get_debugfs_mntpt(void)
-{
-       const char *path = debugfs_mount(NULL);
-
-       if (path)
-               strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
-       else
-               debugfs_mntpt[0] = '\0';
-}
-
 static void pthread__block_sigwinch(void)
 {
        sigset_t set;
@@ -453,7 +429,7 @@ int main(int argc, const char **argv)
        if (!cmd)
                cmd = "perf-help";
        /* get debugfs mount point from /proc/mounts */
-       get_debugfs_mntpt();
+       debugfs_mount(NULL);
        /*
         * "perf-xxxx" is the same as "perf xxxx", but we obviously:
         *
@@ -476,7 +452,6 @@ int main(int argc, const char **argv)
        argc--;
        handle_options(&argv, &argc, NULL);
        commit_pager_choice();
-       set_debugfs_path();
        set_buildid_dir();
 
        if (argc > 0) {
index 914c895..ea804f5 100644 (file)
@@ -185,4 +185,27 @@ extern const char perf_version_string[];
 
 void pthread__unblock_sigwinch(void);
 
+struct perf_record_opts {
+       pid_t        target_pid;
+       pid_t        target_tid;
+       bool         call_graph;
+       bool         group;
+       bool         inherit_stat;
+       bool         no_delay;
+       bool         no_inherit;
+       bool         no_samples;
+       bool         pipe_output;
+       bool         raw_samples;
+       bool         sample_address;
+       bool         sample_time;
+       bool         sample_id_all_avail;
+       bool         system_wide;
+       unsigned int freq;
+       unsigned int mmap_pages;
+       unsigned int user_freq;
+       u64          default_interval;
+       u64          user_interval;
+       const char   *cpu_list;
+};
+
 #endif
index 119e996..376e643 100644 (file)
@@ -25,17 +25,17 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
        return 0;
 }
 
-int symbol__alloc_hist(struct symbol *sym, int nevents)
+int symbol__alloc_hist(struct symbol *sym)
 {
        struct annotation *notes = symbol__annotation(sym);
        size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
                                  (sym->end - sym->start) * sizeof(u64));
 
-       notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist);
+       notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
        if (notes->src == NULL)
                return -1;
        notes->src->sizeof_sym_hist = sizeof_sym_hist;
-       notes->src->nr_histograms   = nevents;
+       notes->src->nr_histograms   = symbol_conf.nr_events;
        INIT_LIST_HEAD(&notes->src->source);
        return 0;
 }
index d907252..efa5dc8 100644 (file)
@@ -72,7 +72,7 @@ static inline struct annotation *symbol__annotation(struct symbol *sym)
 
 int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
                             int evidx, u64 addr);
-int symbol__alloc_hist(struct symbol *sym, int nevents);
+int symbol__alloc_hist(struct symbol *sym);
 void symbol__annotate_zero_histograms(struct symbol *sym);
 
 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
@@ -99,8 +99,7 @@ static inline int symbol__tui_annotate(struct symbol *sym __used,
 }
 #else
 int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
-                        int nr_events, void(*timer)(void *arg), void *arg,
-                        int delay_secs);
+                        void(*timer)(void *arg), void *arg, int delay_secs);
 #endif
 
 extern const char      *disassembler_style;
index a91cd99..dff9c7a 100644 (file)
 #include "symbol.h"
 #include <linux/kernel.h>
 #include "debug.h"
+#include "session.h"
+#include "tool.h"
 
-static int build_id__mark_dso_hit(union perf_event *event,
+static int build_id__mark_dso_hit(struct perf_tool *tool __used,
+                                 union perf_event *event,
                                  struct perf_sample *sample __used,
                                  struct perf_evsel *evsel __used,
-                                 struct perf_session *session)
+                                 struct machine *machine)
 {
        struct addr_location al;
        u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-       struct thread *thread = perf_session__findnew(session, event->ip.pid);
+       struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
 
        if (thread == NULL) {
                pr_err("problem processing %d event, skipping it.\n",
@@ -29,8 +32,8 @@ static int build_id__mark_dso_hit(union perf_event *event,
                return -1;
        }
 
-       thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
-                             event->ip.pid, event->ip.ip, &al);
+       thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
+                             event->ip.ip, &al);
 
        if (al.map != NULL)
                al.map->dso->hit = 1;
@@ -38,25 +41,26 @@ static int build_id__mark_dso_hit(union perf_event *event,
        return 0;
 }
 
-static int perf_event__exit_del_thread(union perf_event *event,
+static int perf_event__exit_del_thread(struct perf_tool *tool __used,
+                                      union perf_event *event,
                                       struct perf_sample *sample __used,
-                                      struct perf_session *session)
+                                      struct machine *machine)
 {
-       struct thread *thread = perf_session__findnew(session, event->fork.tid);
+       struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
 
        dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
                    event->fork.ppid, event->fork.ptid);
 
        if (thread) {
-               rb_erase(&thread->rb_node, &session->threads);
-               session->last_match = NULL;
+               rb_erase(&thread->rb_node, &machine->threads);
+               machine->last_match = NULL;
                thread__delete(thread);
        }
 
        return 0;
 }
 
-struct perf_event_ops build_id__mark_dso_hit_ops = {
+struct perf_tool build_id__mark_dso_hit_ops = {
        .sample = build_id__mark_dso_hit,
        .mmap   = perf_event__process_mmap,
        .fork   = perf_event__process_task,
index 5dafb00..a993ba8 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "session.h"
 
-extern struct perf_event_ops build_id__mark_dso_hit_ops;
+extern struct perf_tool build_id__mark_dso_hit_ops;
 
 char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
 
index 9b4ff16..7f9c0f1 100644 (file)
@@ -101,6 +101,9 @@ int callchain_append(struct callchain_root *root,
 int callchain_merge(struct callchain_cursor *cursor,
                    struct callchain_root *dst, struct callchain_root *src);
 
+struct ip_callchain;
+union perf_event;
+
 bool ip_callchain__valid(struct ip_callchain *chain,
                         const union perf_event *event);
 /*
index 96bee5c..dbe2f16 100644 (file)
@@ -3,7 +3,6 @@
 #include "parse-options.h"
 #include "evsel.h"
 #include "cgroup.h"
-#include "debugfs.h" /* MAX_PATH, STR() */
 #include "evlist.h"
 
 int nr_cgroups;
@@ -12,7 +11,7 @@ static int
 cgroupfs_find_mountpoint(char *buf, size_t maxlen)
 {
        FILE *fp;
-       char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1];
+       char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
        char *token, *saved_ptr = NULL;
        int found = 0;
 
@@ -25,8 +24,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
         * and inspect every cgroupfs mount point to find one that has
         * perf_event subsystem
         */
-       while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %"
-                               STR(MAX_PATH)"s %*d %*d\n",
+       while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %"
+                               STR(PATH_MAX)"s %*d %*d\n",
                                mountpoint, type, tokens) == 3) {
 
                if (!strcmp(type, "cgroup")) {
@@ -57,15 +56,15 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
 
 static int open_cgroup(char *name)
 {
-       char path[MAX_PATH+1];
-       char mnt[MAX_PATH+1];
+       char path[PATH_MAX + 1];
+       char mnt[PATH_MAX + 1];
        int fd;
 
 
-       if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1))
+       if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
                return -1;
 
-       snprintf(path, MAX_PATH, "%s/%s", mnt, name);
+       snprintf(path, PATH_MAX, "%s/%s", mnt, name);
 
        fd = open(path, O_RDONLY);
        if (fd == -1)
index a88fefc..ffc35e7 100644 (file)
@@ -2,8 +2,12 @@
 #include "debugfs.h"
 #include "cache.h"
 
+#include <linux/kernel.h>
+#include <sys/mount.h>
+
 static int debugfs_premounted;
-static char debugfs_mountpoint[MAX_PATH+1];
+char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
+char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
 
 static const char *debugfs_known_mountpoints[] = {
        "/sys/kernel/debug/",
@@ -62,11 +66,9 @@ const char *debugfs_find_mountpoint(void)
        /* give up and parse /proc/mounts */
        fp = fopen("/proc/mounts", "r");
        if (fp == NULL)
-               die("Can't open /proc/mounts for read");
+               return NULL;
 
-       while (fscanf(fp, "%*s %"
-                     STR(MAX_PATH)
-                     "s %99s %*s %*d %*d\n",
+       while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
                      debugfs_mountpoint, type) == 2) {
                if (strcmp(type, "debugfs") == 0)
                        break;
@@ -106,6 +108,12 @@ int debugfs_valid_entry(const char *path)
        return 0;
 }
 
+static void debugfs_set_tracing_events_path(const char *mountpoint)
+{
+       snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
+                mountpoint, "tracing/events");
+}
+
 /* mount the debugfs somewhere if it's not mounted */
 
 char *debugfs_mount(const char *mountpoint)
@@ -113,7 +121,7 @@ char *debugfs_mount(const char *mountpoint)
        /* see if it's already mounted */
        if (debugfs_find_mountpoint()) {
                debugfs_premounted = 1;
-               return debugfs_mountpoint;
+               goto out;
        }
 
        /* if not mounted and no argument */
@@ -129,12 +137,19 @@ char *debugfs_mount(const char *mountpoint)
                return NULL;
 
        /* save the mountpoint */
-       strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
        debugfs_found = 1;
-
+       strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
+out:
+       debugfs_set_tracing_events_path(debugfs_mountpoint);
        return debugfs_mountpoint;
 }
 
+void debugfs_set_path(const char *mountpoint)
+{
+       snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
+       debugfs_set_tracing_events_path(mountpoint);
+}
+
 /* umount the debugfs */
 
 int debugfs_umount(void)
@@ -158,7 +173,7 @@ int debugfs_umount(void)
 
 int debugfs_write(const char *entry, const char *value)
 {
-       char path[MAX_PATH+1];
+       char path[PATH_MAX + 1];
        int ret, count;
        int fd;
 
@@ -203,7 +218,7 @@ int debugfs_write(const char *entry, const char *value)
  */
 int debugfs_read(const char *entry, char *buffer, size_t size)
 {
-       char path[MAX_PATH+1];
+       char path[PATH_MAX + 1];
        int ret;
        int fd;
 
index 83a0287..4a878f7 100644 (file)
@@ -1,25 +1,18 @@
 #ifndef __DEBUGFS_H__
 #define __DEBUGFS_H__
 
-#include <sys/mount.h>
+const char *debugfs_find_mountpoint(void);
+int debugfs_valid_mountpoint(const char *debugfs);
+int debugfs_valid_entry(const char *path);
+char *debugfs_mount(const char *mountpoint);
+int debugfs_umount(void);
+void debugfs_set_path(const char *mountpoint);
+int debugfs_write(const char *entry, const char *value);
+int debugfs_read(const char *entry, char *buffer, size_t size);
+void debugfs_force_cleanup(void);
+int debugfs_make_path(const char *element, char *buffer, int size);
 
-#ifndef MAX_PATH
-# define MAX_PATH 256
-#endif
-
-#ifndef STR
-# define _STR(x) #x
-# define STR(x) _STR(x)
-#endif
-
-extern const char *debugfs_find_mountpoint(void);
-extern int debugfs_valid_mountpoint(const char *debugfs);
-extern int debugfs_valid_entry(const char *path);
-extern char *debugfs_mount(const char *mountpoint);
-extern int debugfs_umount(void);
-extern int debugfs_write(const char *entry, const char *value);
-extern int debugfs_read(const char *entry, char *buffer, size_t size);
-extern void debugfs_force_cleanup(void);
-extern int debugfs_make_path(const char *element, char *buffer, int size);
+extern char debugfs_mountpoint[];
+extern char tracing_events_path[];
 
 #endif /* __DEBUGFS_H__ */
index 437f8ca..97c479b 100644 (file)
@@ -1,7 +1,6 @@
 #include <linux/types.h>
 #include "event.h"
 #include "debug.h"
-#include "session.h"
 #include "sort.h"
 #include "string.h"
 #include "strlist.h"
@@ -44,9 +43,10 @@ static struct perf_sample synth_sample = {
        .period    = 1,
 };
 
-static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid,
+static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
+                                        union perf_event *event, pid_t pid,
                                         int full, perf_event__handler_t process,
-                                        struct perf_session *session)
+                                        struct machine *machine)
 {
        char filename[PATH_MAX];
        char bf[BUFSIZ];
@@ -92,14 +92,14 @@ out_race:
 
        event->comm.header.type = PERF_RECORD_COMM;
        size = ALIGN(size, sizeof(u64));
-       memset(event->comm.comm + size, 0, session->id_hdr_size);
+       memset(event->comm.comm + size, 0, machine->id_hdr_size);
        event->comm.header.size = (sizeof(event->comm) -
                                (sizeof(event->comm.comm) - size) +
-                               session->id_hdr_size);
+                               machine->id_hdr_size);
        if (!full) {
                event->comm.tid = pid;
 
-               process(event, &synth_sample, session);
+               process(tool, event, &synth_sample, machine);
                goto out;
        }
 
@@ -117,7 +117,7 @@ out_race:
 
                event->comm.tid = pid;
 
-               process(event, &synth_sample, session);
+               process(tool, event, &synth_sample, machine);
        }
 
        closedir(tasks);
@@ -127,10 +127,11 @@ out:
        return tgid;
 }
 
-static int perf_event__synthesize_mmap_events(union perf_event *event,
+static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
+                                             union perf_event *event,
                                              pid_t pid, pid_t tgid,
                                              perf_event__handler_t process,
-                                             struct perf_session *session)
+                                             struct machine *machine)
 {
        char filename[PATH_MAX];
        FILE *fp;
@@ -193,12 +194,12 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
                        event->mmap.len -= event->mmap.start;
                        event->mmap.header.size = (sizeof(event->mmap) -
                                                (sizeof(event->mmap.filename) - size));
-                       memset(event->mmap.filename + size, 0, session->id_hdr_size);
-                       event->mmap.header.size += session->id_hdr_size;
+                       memset(event->mmap.filename + size, 0, machine->id_hdr_size);
+                       event->mmap.header.size += machine->id_hdr_size;
                        event->mmap.pid = tgid;
                        event->mmap.tid = pid;
 
-                       process(event, &synth_sample, session);
+                       process(tool, event, &synth_sample, machine);
                }
        }
 
@@ -206,14 +207,14 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
        return 0;
 }
 
-int perf_event__synthesize_modules(perf_event__handler_t process,
-                                  struct perf_session *session,
+int perf_event__synthesize_modules(struct perf_tool *tool,
+                                  perf_event__handler_t process,
                                   struct machine *machine)
 {
        struct rb_node *nd;
        struct map_groups *kmaps = &machine->kmaps;
        union perf_event *event = zalloc((sizeof(event->mmap) +
-                                         session->id_hdr_size));
+                                         machine->id_hdr_size));
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
@@ -243,15 +244,15 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
                event->mmap.header.type = PERF_RECORD_MMAP;
                event->mmap.header.size = (sizeof(event->mmap) -
                                        (sizeof(event->mmap.filename) - size));
-               memset(event->mmap.filename + size, 0, session->id_hdr_size);
-               event->mmap.header.size += session->id_hdr_size;
+               memset(event->mmap.filename + size, 0, machine->id_hdr_size);
+               event->mmap.header.size += machine->id_hdr_size;
                event->mmap.start = pos->start;
                event->mmap.len   = pos->end - pos->start;
                event->mmap.pid   = machine->pid;
 
                memcpy(event->mmap.filename, pos->dso->long_name,
                       pos->dso->long_name_len + 1);
-               process(event, &synth_sample, session);
+               process(tool, event, &synth_sample, machine);
        }
 
        free(event);
@@ -261,28 +262,30 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
 static int __event__synthesize_thread(union perf_event *comm_event,
                                      union perf_event *mmap_event,
                                      pid_t pid, perf_event__handler_t process,
-                                     struct perf_session *session)
+                                     struct perf_tool *tool,
+                                     struct machine *machine)
 {
-       pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process,
-                                           session);
+       pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, 1,
+                                                process, machine);
        if (tgid == -1)
                return -1;
-       return perf_event__synthesize_mmap_events(mmap_event, pid, tgid,
-                                            process, session);
+       return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
+                                                 process, machine);
 }
 
-int perf_event__synthesize_thread_map(struct thread_map *threads,
+int perf_event__synthesize_thread_map(struct perf_tool *tool,
+                                     struct thread_map *threads,
                                      perf_event__handler_t process,
-                                     struct perf_session *session)
+                                     struct machine *machine)
 {
        union perf_event *comm_event, *mmap_event;
        int err = -1, thread;
 
-       comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
+       comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
        if (comm_event == NULL)
                goto out;
 
-       mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
+       mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
        if (mmap_event == NULL)
                goto out_free_comm;
 
@@ -290,7 +293,7 @@ int perf_event__synthesize_thread_map(struct thread_map *threads,
        for (thread = 0; thread < threads->nr; ++thread) {
                if (__event__synthesize_thread(comm_event, mmap_event,
                                               threads->map[thread],
-                                              process, session)) {
+                                              process, tool, machine)) {
                        err = -1;
                        break;
                }
@@ -302,19 +305,20 @@ out:
        return err;
 }
 
-int perf_event__synthesize_threads(perf_event__handler_t process,
-                                  struct perf_session *session)
+int perf_event__synthesize_threads(struct perf_tool *tool,
+                                  perf_event__handler_t process,
+                                  struct machine *machine)
 {
        DIR *proc;
        struct dirent dirent, *next;
        union perf_event *comm_event, *mmap_event;
        int err = -1;
 
-       comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
+       comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
        if (comm_event == NULL)
                goto out;
 
-       mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
+       mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
        if (mmap_event == NULL)
                goto out_free_comm;
 
@@ -330,7 +334,7 @@ int perf_event__synthesize_threads(perf_event__handler_t process,
                        continue;
 
                __event__synthesize_thread(comm_event, mmap_event, pid,
-                                          process, session);
+                                          process, tool, machine);
        }
 
        closedir(proc);
@@ -365,8 +369,8 @@ static int find_symbol_cb(void *arg, const char *name, char type,
        return 1;
 }
 
-int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
-                                      struct perf_session *session,
+int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
+                                      perf_event__handler_t process,
                                       struct machine *machine,
                                       const char *symbol_name)
 {
@@ -383,7 +387,7 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
         */
        struct process_symbol_args args = { .name = symbol_name, };
        union perf_event *event = zalloc((sizeof(event->mmap) +
-                                         session->id_hdr_size));
+                                         machine->id_hdr_size));
        if (event == NULL) {
                pr_debug("Not enough memory synthesizing mmap event "
                         "for kernel modules\n");
@@ -417,25 +421,32 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
        size = ALIGN(size, sizeof(u64));
        event->mmap.header.type = PERF_RECORD_MMAP;
        event->mmap.header.size = (sizeof(event->mmap) -
-                       (sizeof(event->mmap.filename) - size) + session->id_hdr_size);
+                       (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
        event->mmap.pgoff = args.start;
        event->mmap.start = map->start;
        event->mmap.len   = map->end - event->mmap.start;
        event->mmap.pid   = machine->pid;
 
-       err = process(event, &synth_sample, session);
+       err = process(tool, event, &synth_sample, machine);
        free(event);
 
        return err;
 }
 
-int perf_event__process_comm(union perf_event *event,
+size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
+{
+       return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid);
+}
+
+int perf_event__process_comm(struct perf_tool *tool __used,
+                            union perf_event *event,
                             struct perf_sample *sample __used,
-                            struct perf_session *session)
+                            struct machine *machine)
 {
-       struct thread *thread = perf_session__findnew(session, event->comm.tid);
+       struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
 
-       dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid);
+       if (dump_trace)
+               perf_event__fprintf_comm(event, stdout);
 
        if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
                dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
@@ -445,13 +456,13 @@ int perf_event__process_comm(union perf_event *event,
        return 0;
 }
 
-int perf_event__process_lost(union perf_event *event,
+int perf_event__process_lost(struct perf_tool *tool __used,
+                            union perf_event *event,
                             struct perf_sample *sample __used,
-                            struct perf_session *session)
+                            struct machine *machine __used)
 {
        dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
                    event->lost.id, event->lost.lost);
-       session->hists.stats.total_lost += event->lost.lost;
        return 0;
 }
 
@@ -468,21 +479,15 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event,
                maps[MAP__FUNCTION]->end = ~0ULL;
 }
 
-static int perf_event__process_kernel_mmap(union perf_event *event,
-                                          struct perf_session *session)
+static int perf_event__process_kernel_mmap(struct perf_tool *tool __used,
+                                          union perf_event *event,
+                                          struct machine *machine)
 {
        struct map *map;
        char kmmap_prefix[PATH_MAX];
-       struct machine *machine;
        enum dso_kernel_type kernel_type;
        bool is_kernel_mmap;
 
-       machine = perf_session__findnew_machine(session, event->mmap.pid);
-       if (!machine) {
-               pr_err("Can't find id %d's machine\n", event->mmap.pid);
-               goto out_problem;
-       }
-
        machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
        if (machine__is_host(machine))
                kernel_type = DSO_TYPE_KERNEL;
@@ -549,9 +554,9 @@ static int perf_event__process_kernel_mmap(union perf_event *event,
                 * time /proc/sys/kernel/kptr_restrict was non zero.
                 */
                if (event->mmap.pgoff != 0) {
-                       perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
-                                                                symbol_name,
-                                                                event->mmap.pgoff);
+                       maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
+                                                        symbol_name,
+                                                        event->mmap.pgoff);
                }
 
                if (machine__is_default_guest(machine)) {
@@ -567,32 +572,35 @@ out_problem:
        return -1;
 }
 
-int perf_event__process_mmap(union perf_event *event,
+size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
+{
+       return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
+                      event->mmap.pid, event->mmap.tid, event->mmap.start,
+                      event->mmap.len, event->mmap.pgoff, event->mmap.filename);
+}
+
+int perf_event__process_mmap(struct perf_tool *tool,
+                            union perf_event *event,
                             struct perf_sample *sample __used,
-                            struct perf_session *session)
+                            struct machine *machine)
 {
-       struct machine *machine;
        struct thread *thread;
        struct map *map;
        u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
        int ret = 0;
 
-       dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
-                       event->mmap.pid, event->mmap.tid, event->mmap.start,
-                       event->mmap.len, event->mmap.pgoff, event->mmap.filename);
+       if (dump_trace)
+               perf_event__fprintf_mmap(event, stdout);
 
        if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
            cpumode == PERF_RECORD_MISC_KERNEL) {
-               ret = perf_event__process_kernel_mmap(event, session);
+               ret = perf_event__process_kernel_mmap(tool, event, machine);
                if (ret < 0)
                        goto out_problem;
                return 0;
        }
 
-       machine = perf_session__find_host_machine(session);
-       if (machine == NULL)
-               goto out_problem;
-       thread = perf_session__findnew(session, event->mmap.pid);
+       thread = machine__findnew_thread(machine, event->mmap.pid);
        if (thread == NULL)
                goto out_problem;
        map = map__new(&machine->user_dsos, event->mmap.start,
@@ -610,18 +618,26 @@ out_problem:
        return 0;
 }
 
-int perf_event__process_task(union perf_event *event,
+size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
+{
+       return fprintf(fp, "(%d:%d):(%d:%d)\n",
+                      event->fork.pid, event->fork.tid,
+                      event->fork.ppid, event->fork.ptid);
+}
+
+int perf_event__process_task(struct perf_tool *tool __used,
+                            union perf_event *event,
                             struct perf_sample *sample __used,
-                            struct perf_session *session)
+                             struct machine *machine)
 {
-       struct thread *thread = perf_session__findnew(session, event->fork.tid);
-       struct thread *parent = perf_session__findnew(session, event->fork.ptid);
+       struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
+       struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
 
-       dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
-                   event->fork.ppid, event->fork.ptid);
+       if (dump_trace)
+               perf_event__fprintf_task(event, stdout);
 
        if (event->header.type == PERF_RECORD_EXIT) {
-               perf_session__remove_thread(session, thread);
+               machine__remove_thread(machine, thread);
                return 0;
        }
 
@@ -634,22 +650,45 @@ int perf_event__process_task(union perf_event *event,
        return 0;
 }
 
-int perf_event__process(union perf_event *event, struct perf_sample *sample,
-                       struct perf_session *session)
+size_t perf_event__fprintf(union perf_event *event, FILE *fp)
 {
+       size_t ret = fprintf(fp, "PERF_RECORD_%s",
+                            perf_event__name(event->header.type));
+
        switch (event->header.type) {
        case PERF_RECORD_COMM:
-               perf_event__process_comm(event, sample, session);
+               ret += perf_event__fprintf_comm(event, fp);
+               break;
+       case PERF_RECORD_FORK:
+       case PERF_RECORD_EXIT:
+               ret += perf_event__fprintf_task(event, fp);
                break;
        case PERF_RECORD_MMAP:
-               perf_event__process_mmap(event, sample, session);
+               ret += perf_event__fprintf_mmap(event, fp);
+               break;
+       default:
+               ret += fprintf(fp, "\n");
+       }
+
+       return ret;
+}
+
+int perf_event__process(struct perf_tool *tool, union perf_event *event,
+                       struct perf_sample *sample, struct machine *machine)
+{
+       switch (event->header.type) {
+       case PERF_RECORD_COMM:
+               perf_event__process_comm(tool, event, sample, machine);
+               break;
+       case PERF_RECORD_MMAP:
+               perf_event__process_mmap(tool, event, sample, machine);
                break;
        case PERF_RECORD_FORK:
        case PERF_RECORD_EXIT:
-               perf_event__process_task(event, sample, session);
+               perf_event__process_task(tool, event, sample, machine);
                break;
        case PERF_RECORD_LOST:
-               perf_event__process_lost(event, sample, session);
+               perf_event__process_lost(tool, event, sample, machine);
        default:
                break;
        }
@@ -658,36 +697,29 @@ int perf_event__process(union perf_event *event, struct perf_sample *sample,
 }
 
 void thread__find_addr_map(struct thread *self,
-                          struct perf_session *session, u8 cpumode,
-                          enum map_type type, pid_t pid, u64 addr,
+                          struct machine *machine, u8 cpumode,
+                          enum map_type type, u64 addr,
                           struct addr_location *al)
 {
        struct map_groups *mg = &self->mg;
-       struct machine *machine = NULL;
 
        al->thread = self;
        al->addr = addr;
        al->cpumode = cpumode;
        al->filtered = false;
 
+       if (machine == NULL) {
+               al->map = NULL;
+               return;
+       }
+
        if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
                al->level = 'k';
-               machine = perf_session__find_host_machine(session);
-               if (machine == NULL) {
-                       al->map = NULL;
-                       return;
-               }
                mg = &machine->kmaps;
        } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
                al->level = '.';
-               machine = perf_session__find_host_machine(session);
        } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
                al->level = 'g';
-               machine = perf_session__find_machine(session, pid);
-               if (machine == NULL) {
-                       al->map = NULL;
-                       return;
-               }
                mg = &machine->kmaps;
        } else {
                /*
@@ -733,13 +765,12 @@ try_again:
                al->addr = al->map->map_ip(al->map, al->addr);
 }
 
-void thread__find_addr_location(struct thread *self,
-                               struct perf_session *session, u8 cpumode,
-                               enum map_type type, pid_t pid, u64 addr,
+void thread__find_addr_location(struct thread *thread, struct machine *machine,
+                               u8 cpumode, enum map_type type, u64 addr,
                                struct addr_location *al,
                                symbol_filter_t filter)
 {
-       thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
+       thread__find_addr_map(thread, machine, cpumode, type, addr, al);
        if (al->map != NULL)
                al->sym = map__find_symbol(al->map, al->addr, filter);
        else
@@ -747,13 +778,13 @@ void thread__find_addr_location(struct thread *self,
 }
 
 int perf_event__preprocess_sample(const union perf_event *event,
-                                 struct perf_session *session,
+                                 struct machine *machine,
                                  struct addr_location *al,
                                  struct perf_sample *sample,
                                  symbol_filter_t filter)
 {
        u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-       struct thread *thread = perf_session__findnew(session, event->ip.pid);
+       struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
 
        if (thread == NULL)
                return -1;
@@ -764,18 +795,18 @@ int perf_event__preprocess_sample(const union perf_event *event,
 
        dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
        /*
-        * Have we already created the kernel maps for the host machine?
+        * Have we already created the kernel maps for this machine?
         *
         * This should have happened earlier, when we processed the kernel MMAP
         * events, but for older perf.data files there was no such thing, so do
         * it now.
         */
        if (cpumode == PERF_RECORD_MISC_KERNEL &&
-           session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL)
-               machine__create_kernel_maps(&session->host_machine);
+           machine->vmlinux_maps[MAP__FUNCTION] == NULL)
+               machine__create_kernel_maps(machine);
 
-       thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
-                             event->ip.pid, event->ip.ip, al);
+       thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
+                             event->ip.ip, al);
        dump_printf(" ...... dso: %s\n",
                    al->map ? al->map->dso->long_name :
                        al->level == 'H' ? "[hypervisor]" : "<not found>");
index 357a85b..0d80201 100644 (file)
@@ -2,6 +2,7 @@
 #define __PERF_RECORD_H
 
 #include <limits.h>
+#include <stdio.h>
 
 #include "../perf.h"
 #include "map.h"
@@ -141,43 +142,54 @@ union perf_event {
 
 void perf_event__print_totals(void);
 
-struct perf_session;
+struct perf_tool;
 struct thread_map;
 
-typedef int (*perf_event__handler_synth_t)(union perf_event *event, 
-                                          struct perf_session *session);
-typedef int (*perf_event__handler_t)(union perf_event *event,
+typedef int (*perf_event__handler_t)(struct perf_tool *tool,
+                                    union perf_event *event,
                                     struct perf_sample *sample,
-                                     struct perf_session *session);
+                                    struct machine *machine);
 
-int perf_event__synthesize_thread_map(struct thread_map *threads,
+int perf_event__synthesize_thread_map(struct perf_tool *tool,
+                                     struct thread_map *threads,
                                      perf_event__handler_t process,
-                                     struct perf_session *session);
-int perf_event__synthesize_threads(perf_event__handler_t process,
-                                  struct perf_session *session);
-int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
-                                      struct perf_session *session,
+                                     struct machine *machine);
+int perf_event__synthesize_threads(struct perf_tool *tool,
+                                  perf_event__handler_t process,
+                                  struct machine *machine);
+int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
+                                      perf_event__handler_t process,
                                       struct machine *machine,
                                       const char *symbol_name);
 
-int perf_event__synthesize_modules(perf_event__handler_t process,
-                                  struct perf_session *session,
+int perf_event__synthesize_modules(struct perf_tool *tool,
+                                  perf_event__handler_t process,
                                   struct machine *machine);
 
-int perf_event__process_comm(union perf_event *event, struct perf_sample *sample,
-                            struct perf_session *session);
-int perf_event__process_lost(union perf_event *event, struct perf_sample *sample,
-                            struct perf_session *session);
-int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample,
-                            struct perf_session *session);
-int perf_event__process_task(union perf_event *event, struct perf_sample *sample,
-                            struct perf_session *session);
-int perf_event__process(union perf_event *event, struct perf_sample *sample,
-                       struct perf_session *session);
+int perf_event__process_comm(struct perf_tool *tool,
+                            union perf_event *event,
+                            struct perf_sample *sample,
+                            struct machine *machine);
+int perf_event__process_lost(struct perf_tool *tool,
+                            union perf_event *event,
+                            struct perf_sample *sample,
+                            struct machine *machine);
+int perf_event__process_mmap(struct perf_tool *tool,
+                            union perf_event *event,
+                            struct perf_sample *sample,
+                            struct machine *machine);
+int perf_event__process_task(struct perf_tool *tool,
+                            union perf_event *event,
+                            struct perf_sample *sample,
+                            struct machine *machine);
+int perf_event__process(struct perf_tool *tool,
+                       union perf_event *event,
+                       struct perf_sample *sample,
+                       struct machine *machine);
 
 struct addr_location;
 int perf_event__preprocess_sample(const union perf_event *self,
-                                 struct perf_session *session,
+                                 struct machine *machine,
                                  struct addr_location *al,
                                  struct perf_sample *sample,
                                  symbol_filter_t filter);
@@ -188,4 +200,9 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
                             int sample_size, bool sample_id_all,
                             struct perf_sample *sample, bool swapped);
 
+size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf(union perf_event *event, FILE *fp);
+
 #endif /* __PERF_RECORD_H */
index fbb4b4a..8b19e7a 100644 (file)
@@ -6,12 +6,16 @@
  *
  * Released under the GPL v2. (and only v2, not any later version)
  */
+#include "util.h"
+#include "debugfs.h"
 #include <poll.h>
 #include "cpumap.h"
 #include "thread_map.h"
 #include "evlist.h"
 #include "evsel.h"
-#include "util.h"
+#include <unistd.h>
+
+#include "parse-events.h"
 
 #include <sys/mman.h>
 
@@ -30,6 +34,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
                INIT_HLIST_HEAD(&evlist->heads[i]);
        INIT_LIST_HEAD(&evlist->entries);
        perf_evlist__set_maps(evlist, cpus, threads);
+       evlist->workload.pid = -1;
 }
 
 struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -43,6 +48,22 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
        return evlist;
 }
 
+void perf_evlist__config_attrs(struct perf_evlist *evlist,
+                              struct perf_record_opts *opts)
+{
+       struct perf_evsel *evsel;
+
+       if (evlist->cpus->map[0] < 0)
+               opts->no_inherit = true;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               perf_evsel__config(evsel, opts);
+
+               if (evlist->nr_entries > 1)
+                       evsel->attr.sample_type |= PERF_SAMPLE_ID;
+       }
+}
+
 static void perf_evlist__purge(struct perf_evlist *evlist)
 {
        struct perf_evsel *pos, *n;
@@ -76,6 +97,14 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
        ++evlist->nr_entries;
 }
 
+static void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
+                                         struct list_head *list,
+                                         int nr_entries)
+{
+       list_splice_tail(list, &evlist->entries);
+       evlist->nr_entries += nr_entries;
+}
+
 int perf_evlist__add_default(struct perf_evlist *evlist)
 {
        struct perf_event_attr attr = {
@@ -100,6 +129,126 @@ error:
        return -ENOMEM;
 }
 
+int perf_evlist__add_attrs(struct perf_evlist *evlist,
+                          struct perf_event_attr *attrs, size_t nr_attrs)
+{
+       struct perf_evsel *evsel, *n;
+       LIST_HEAD(head);
+       size_t i;
+
+       for (i = 0; i < nr_attrs; i++) {
+               evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i);
+               if (evsel == NULL)
+                       goto out_delete_partial_list;
+               list_add_tail(&evsel->node, &head);
+       }
+
+       perf_evlist__splice_list_tail(evlist, &head, nr_attrs);
+
+       return 0;
+
+out_delete_partial_list:
+       list_for_each_entry_safe(evsel, n, &head, node)
+               perf_evsel__delete(evsel);
+       return -1;
+}
+
+static int trace_event__id(const char *evname)
+{
+       char *filename, *colon;
+       int err = -1, fd;
+
+       if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0)
+               return -1;
+
+       colon = strrchr(filename, ':');
+       if (colon != NULL)
+               *colon = '/';
+
+       fd = open(filename, O_RDONLY);
+       if (fd >= 0) {
+               char id[16];
+               if (read(fd, id, sizeof(id)) > 0)
+                       err = atoi(id);
+               close(fd);
+       }
+
+       free(filename);
+       return err;
+}
+
+int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
+                                const char *tracepoints[],
+                                size_t nr_tracepoints)
+{
+       int err;
+       size_t i;
+       struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs));
+
+       if (attrs == NULL)
+               return -1;
+
+       for (i = 0; i < nr_tracepoints; i++) {
+               err = trace_event__id(tracepoints[i]);
+
+               if (err < 0)
+                       goto out_free_attrs;
+
+               attrs[i].type          = PERF_TYPE_TRACEPOINT;
+               attrs[i].config        = err;
+               attrs[i].sample_type   = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
+                                         PERF_SAMPLE_CPU);
+               attrs[i].sample_period = 1;
+       }
+
+       err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints);
+out_free_attrs:
+       free(attrs);
+       return err;
+}
+
+static struct perf_evsel *
+       perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
+{
+       struct perf_evsel *evsel;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               if (evsel->attr.type   == PERF_TYPE_TRACEPOINT &&
+                   (int)evsel->attr.config == id)
+                       return evsel;
+       }
+
+       return NULL;
+}
+
+int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
+                                         const struct perf_evsel_str_handler *assocs,
+                                         size_t nr_assocs)
+{
+       struct perf_evsel *evsel;
+       int err;
+       size_t i;
+
+       for (i = 0; i < nr_assocs; i++) {
+               err = trace_event__id(assocs[i].name);
+               if (err < 0)
+                       goto out;
+
+               evsel = perf_evlist__find_tracepoint_by_id(evlist, err);
+               if (evsel == NULL)
+                       continue;
+
+               err = -EEXIST;
+               if (evsel->handler.func != NULL)
+                       goto out;
+               evsel->handler.func = assocs[i].handler;
+       }
+
+       err = 0;
+out:
+       return err;
+}
+
 void perf_evlist__disable(struct perf_evlist *evlist)
 {
        int cpu, thread;
@@ -126,7 +275,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
        }
 }
 
-int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
+static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
        int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
        evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
@@ -282,7 +431,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
        evlist->mmap = NULL;
 }
 
-int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
+static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 {
        evlist->nr_mmaps = evlist->cpus->nr;
        if (evlist->cpus->map[0] == -1)
@@ -400,14 +549,20 @@ out_unmap:
  *
  * Using perf_evlist__read_on_cpu does this automatically.
  */
-int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite)
+int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
+                     bool overwrite)
 {
        unsigned int page_size = sysconf(_SC_PAGE_SIZE);
-       int mask = pages * page_size - 1;
        struct perf_evsel *evsel;
        const struct cpu_map *cpus = evlist->cpus;
        const struct thread_map *threads = evlist->threads;
-       int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE);
+       int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
+
+        /* 512 kiB: default amount of unprivileged mlocked memory */
+        if (pages == UINT_MAX)
+                pages = (512 * 1024) / page_size;
+
+       mask = pages * page_size - 1;
 
        if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
                return -ENOMEM;
@@ -512,6 +667,38 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
        return first->attr.sample_type;
 }
 
+u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist)
+{
+       struct perf_evsel *first;
+       struct perf_sample *data;
+       u64 sample_type;
+       u16 size = 0;
+
+       first = list_entry(evlist->entries.next, struct perf_evsel, node);
+
+       if (!first->attr.sample_id_all)
+               goto out;
+
+       sample_type = first->attr.sample_type;
+
+       if (sample_type & PERF_SAMPLE_TID)
+               size += sizeof(data->tid) * 2;
+
+       if (sample_type & PERF_SAMPLE_TIME)
+               size += sizeof(data->time);
+
+       if (sample_type & PERF_SAMPLE_ID)
+               size += sizeof(data->id);
+
+       if (sample_type & PERF_SAMPLE_STREAM_ID)
+               size += sizeof(data->stream_id);
+
+       if (sample_type & PERF_SAMPLE_CPU)
+               size += sizeof(data->cpu) * 2;
+out:
+       return size;
+}
+
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
 {
        struct perf_evsel *pos, *first;
@@ -569,3 +756,97 @@ out_err:
 
        return err;
 }
+
+int perf_evlist__prepare_workload(struct perf_evlist *evlist,
+                                 struct perf_record_opts *opts,
+                                 const char *argv[])
+{
+       int child_ready_pipe[2], go_pipe[2];
+       char bf;
+
+       if (pipe(child_ready_pipe) < 0) {
+               perror("failed to create 'ready' pipe");
+               return -1;
+       }
+
+       if (pipe(go_pipe) < 0) {
+               perror("failed to create 'go' pipe");
+               goto out_close_ready_pipe;
+       }
+
+       evlist->workload.pid = fork();
+       if (evlist->workload.pid < 0) {
+               perror("failed to fork");
+               goto out_close_pipes;
+       }
+
+       if (!evlist->workload.pid) {
+               if (opts->pipe_output)
+                       dup2(2, 1);
+
+               close(child_ready_pipe[0]);
+               close(go_pipe[1]);
+               fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
+
+               /*
+                * Do a dummy execvp to get the PLT entry resolved,
+                * so we avoid the resolver overhead on the real
+                * execvp call.
+                */
+               execvp("", (char **)argv);
+
+               /*
+                * Tell the parent we're ready to go
+                */
+               close(child_ready_pipe[1]);
+
+               /*
+                * Wait until the parent tells us to go.
+                */
+               if (read(go_pipe[0], &bf, 1) == -1)
+                       perror("unable to read pipe");
+
+               execvp(argv[0], (char **)argv);
+
+               perror(argv[0]);
+               kill(getppid(), SIGUSR1);
+               exit(-1);
+       }
+
+       if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1)
+               evlist->threads->map[0] = evlist->workload.pid;
+
+       close(child_ready_pipe[1]);
+       close(go_pipe[0]);
+       /*
+        * wait for child to settle
+        */
+       if (read(child_ready_pipe[0], &bf, 1) == -1) {
+               perror("unable to read pipe");
+               goto out_close_pipes;
+       }
+
+       evlist->workload.cork_fd = go_pipe[1];
+       close(child_ready_pipe[0]);
+       return 0;
+
+out_close_pipes:
+       close(go_pipe[0]);
+       close(go_pipe[1]);
+out_close_ready_pipe:
+       close(child_ready_pipe[0]);
+       close(child_ready_pipe[1]);
+       return -1;
+}
+
+int perf_evlist__start_workload(struct perf_evlist *evlist)
+{
+       if (evlist->workload.cork_fd > 0) {
+               /*
+                * Remove the cork, let it rip!
+                */
+               return close(evlist->workload.cork_fd);
+       }
+
+       return 0;
+}
index 1779ffe..8922aee 100644 (file)
@@ -2,12 +2,16 @@
 #define __PERF_EVLIST_H 1
 
 #include <linux/list.h>
+#include <stdio.h>
 #include "../perf.h"
 #include "event.h"
+#include "util.h"
+#include <unistd.h>
 
 struct pollfd;
 struct thread_map;
 struct cpu_map;
+struct perf_record_opts;
 
 #define PERF_EVLIST__HLIST_BITS 8
 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
@@ -19,6 +23,10 @@ struct perf_evlist {
        int              nr_fds;
        int              nr_mmaps;
        int              mmap_len;
+       struct {
+               int     cork_fd;
+               pid_t   pid;
+       } workload;
        bool             overwrite;
        union perf_event event_copy;
        struct perf_mmap *mmap;
@@ -28,6 +36,11 @@ struct perf_evlist {
        struct perf_evsel *selected;
 };
 
+struct perf_evsel_str_handler {
+       const char *name;
+       void       *handler;
+};
+
 struct perf_evsel;
 
 struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -39,11 +52,26 @@ void perf_evlist__delete(struct perf_evlist *evlist);
 
 void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
 int perf_evlist__add_default(struct perf_evlist *evlist);
+int perf_evlist__add_attrs(struct perf_evlist *evlist,
+                          struct perf_event_attr *attrs, size_t nr_attrs);
+int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
+                                const char *tracepoints[], size_t nr_tracepoints);
+int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
+                                         const struct perf_evsel_str_handler *assocs,
+                                         size_t nr_assocs);
+
+#define perf_evlist__add_attrs_array(evlist, array) \
+       perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array))
+
+#define perf_evlist__add_tracepoints_array(evlist, array) \
+       perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array))
+
+#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
+       perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
 
 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
                         int cpu, int thread, u64 id);
 
-int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
 void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
 
 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
@@ -52,8 +80,16 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
 
 int perf_evlist__open(struct perf_evlist *evlist, bool group);
 
-int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
-int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
+void perf_evlist__config_attrs(struct perf_evlist *evlist,
+                              struct perf_record_opts *opts);
+
+int perf_evlist__prepare_workload(struct perf_evlist *evlist,
+                                 struct perf_record_opts *opts,
+                                 const char *argv[]);
+int perf_evlist__start_workload(struct perf_evlist *evlist);
+
+int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
+                     bool overwrite);
 void perf_evlist__munmap(struct perf_evlist *evlist);
 
 void perf_evlist__disable(struct perf_evlist *evlist);
@@ -77,6 +113,7 @@ int perf_evlist__set_filters(struct perf_evlist *evlist);
 
 u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
+u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
 
 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
index d7915d4..ee68d69 100644 (file)
@@ -63,6 +63,76 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
        return evsel;
 }
 
+void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
+{
+       struct perf_event_attr *attr = &evsel->attr;
+       int track = !evsel->idx; /* only the first counter needs these */
+
+       attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
+       attr->inherit       = !opts->no_inherit;
+       attr->read_format   = PERF_FORMAT_TOTAL_TIME_ENABLED |
+                             PERF_FORMAT_TOTAL_TIME_RUNNING |
+                             PERF_FORMAT_ID;
+
+       attr->sample_type  |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
+
+       /*
+        * We default some events to a 1 default interval. But keep
+        * it a weak assumption overridable by the user.
+        */
+       if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
+                                    opts->user_interval != ULLONG_MAX)) {
+               if (opts->freq) {
+                       attr->sample_type       |= PERF_SAMPLE_PERIOD;
+                       attr->freq              = 1;
+                       attr->sample_freq       = opts->freq;
+               } else {
+                       attr->sample_period = opts->default_interval;
+               }
+       }
+
+       if (opts->no_samples)
+               attr->sample_freq = 0;
+
+       if (opts->inherit_stat)
+               attr->inherit_stat = 1;
+
+       if (opts->sample_address) {
+               attr->sample_type       |= PERF_SAMPLE_ADDR;
+               attr->mmap_data = track;
+       }
+
+       if (opts->call_graph)
+               attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
+
+       if (opts->system_wide)
+               attr->sample_type       |= PERF_SAMPLE_CPU;
+
+       if (opts->sample_id_all_avail &&
+           (opts->sample_time || opts->system_wide ||
+            !opts->no_inherit || opts->cpu_list))
+               attr->sample_type       |= PERF_SAMPLE_TIME;
+
+       if (opts->raw_samples) {
+               attr->sample_type       |= PERF_SAMPLE_TIME;
+               attr->sample_type       |= PERF_SAMPLE_RAW;
+               attr->sample_type       |= PERF_SAMPLE_CPU;
+       }
+
+       if (opts->no_delay) {
+               attr->watermark = 0;
+               attr->wakeup_events = 1;
+       }
+
+       attr->mmap = track;
+       attr->comm = track;
+
+       if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) {
+               attr->disabled = 1;
+               attr->enable_on_exec = 1;
+       }
+}
+
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
        int cpu, thread;
index b1d15e6..326b8e4 100644 (file)
@@ -61,12 +61,17 @@ struct perf_evsel {
                off_t           id_offset;
        };
        struct cgroup_sel       *cgrp;
+       struct {
+               void            *func;
+               void            *data;
+       } handler;
        bool                    supported;
 };
 
 struct cpu_map;
 struct thread_map;
 struct perf_evlist;
+struct perf_record_opts;
 
 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
 void perf_evsel__init(struct perf_evsel *evsel,
@@ -74,6 +79,9 @@ void perf_evsel__init(struct perf_evsel *evsel,
 void perf_evsel__exit(struct perf_evsel *evsel);
 void perf_evsel__delete(struct perf_evsel *evsel);
 
+void perf_evsel__config(struct perf_evsel *evsel,
+                       struct perf_record_opts *opts);
+
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
index bcd05d0..9272f3a 100644 (file)
@@ -2041,6 +2041,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
                lseek(fd, tmp, SEEK_SET);
        }
 
+       symbol_conf.nr_events = nr_attrs;
+
        if (f_header.event_types.size) {
                lseek(fd, f_header.event_types.offset, SEEK_SET);
                events = malloc(f_header.event_types.size);
@@ -2068,9 +2070,9 @@ out_delete_evlist:
        return -ENOMEM;
 }
 
-int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
-                               perf_event__handler_t process,
-                               struct perf_session *session)
+int perf_event__synthesize_attr(struct perf_tool *tool,
+                               struct perf_event_attr *attr, u16 ids, u64 *id,
+                               perf_event__handler_t process)
 {
        union perf_event *ev;
        size_t size;
@@ -2092,22 +2094,23 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
        ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
        ev->attr.header.size = size;
 
-       err = process(ev, NULL, session);
+       err = process(tool, ev, NULL, NULL);
 
        free(ev);
 
        return err;
 }
 
-int perf_session__synthesize_attrs(struct perf_session *session,
+int perf_event__synthesize_attrs(struct perf_tool *tool,
+                                  struct perf_session *session,
                                   perf_event__handler_t process)
 {
        struct perf_evsel *attr;
        int err = 0;
 
        list_for_each_entry(attr, &session->evlist->entries, node) {
-               err = perf_event__synthesize_attr(&attr->attr, attr->ids,
-                                                 attr->id, process, session);
+               err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids,
+                                                 attr->id, process);
                if (err) {
                        pr_debug("failed to create perf header attribute\n");
                        return err;
@@ -2118,23 +2121,23 @@ int perf_session__synthesize_attrs(struct perf_session *session,
 }
 
 int perf_event__process_attr(union perf_event *event,
-                            struct perf_session *session)
+                            struct perf_evlist **pevlist)
 {
        unsigned int i, ids, n_ids;
        struct perf_evsel *evsel;
+       struct perf_evlist *evlist = *pevlist;
 
-       if (session->evlist == NULL) {
-               session->evlist = perf_evlist__new(NULL, NULL);
-               if (session->evlist == NULL)
+       if (evlist == NULL) {
+               *pevlist = evlist = perf_evlist__new(NULL, NULL);
+               if (evlist == NULL)
                        return -ENOMEM;
        }
 
-       evsel = perf_evsel__new(&event->attr.attr,
-                               session->evlist->nr_entries);
+       evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries);
        if (evsel == NULL)
                return -ENOMEM;
 
-       perf_evlist__add(session->evlist, evsel);
+       perf_evlist__add(evlist, evsel);
 
        ids = event->header.size;
        ids -= (void *)&event->attr.id - (void *)event;
@@ -2148,18 +2151,16 @@ int perf_event__process_attr(union perf_event *event,
                return -ENOMEM;
 
        for (i = 0; i < n_ids; i++) {
-               perf_evlist__id_add(session->evlist, evsel, 0, i,
-                                   event->attr.id[i]);
+               perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]);
        }
 
-       perf_session__update_sample_type(session);
-
        return 0;
 }
 
-int perf_event__synthesize_event_type(u64 event_id, char *name,
+int perf_event__synthesize_event_type(struct perf_tool *tool,
+                                     u64 event_id, char *name,
                                      perf_event__handler_t process,
-                                     struct perf_session *session)
+                                     struct machine *machine)
 {
        union perf_event ev;
        size_t size = 0;
@@ -2177,13 +2178,14 @@ int perf_event__synthesize_event_type(u64 event_id, char *name,
        ev.event_type.header.size = sizeof(ev.event_type) -
                (sizeof(ev.event_type.event_type.name) - size);
 
-       err = process(&ev, NULL, session);
+       err = process(tool, &ev, NULL, machine);
 
        return err;
 }
 
-int perf_event__synthesize_event_types(perf_event__handler_t process,
-                                      struct perf_session *session)
+int perf_event__synthesize_event_types(struct perf_tool *tool,
+                                      perf_event__handler_t process,
+                                      struct machine *machine)
 {
        struct perf_trace_event_type *type;
        int i, err = 0;
@@ -2191,9 +2193,9 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
        for (i = 0; i < event_count; i++) {
                type = &events[i];
 
-               err = perf_event__synthesize_event_type(type->event_id,
+               err = perf_event__synthesize_event_type(tool, type->event_id,
                                                        type->name, process,
-                                                       session);
+                                                       machine);
                if (err) {
                        pr_debug("failed to create perf header event type\n");
                        return err;
@@ -2203,8 +2205,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
        return err;
 }
 
-int perf_event__process_event_type(union perf_event *event,
-                                  struct perf_session *session __unused)
+int perf_event__process_event_type(struct perf_tool *tool __unused,
+                                  union perf_event *event)
 {
        if (perf_header__push_event(event->event_type.event_type.event_id,
                                    event->event_type.event_type.name) < 0)
@@ -2213,9 +2215,9 @@ int perf_event__process_event_type(union perf_event *event,
        return 0;
 }
 
-int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
-                                        perf_event__handler_t process,
-                                  struct perf_session *session __unused)
+int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
+                                       struct perf_evlist *evlist,
+                                       perf_event__handler_t process)
 {
        union perf_event ev;
        struct tracing_data *tdata;
@@ -2246,7 +2248,7 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
        ev.tracing_data.header.size = sizeof(ev.tracing_data);
        ev.tracing_data.size = aligned_size;
 
-       process(&ev, NULL, session);
+       process(tool, &ev, NULL, NULL);
 
        /*
         * The put function will copy all the tracing data
@@ -2288,10 +2290,10 @@ int perf_event__process_tracing_data(union perf_event *event,
        return size_read + padding;
 }
 
-int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
+int perf_event__synthesize_build_id(struct perf_tool *tool,
+                                   struct dso *pos, u16 misc,
                                    perf_event__handler_t process,
-                                   struct machine *machine,
-                                   struct perf_session *session)
+                                   struct machine *machine)
 {
        union perf_event ev;
        size_t len;
@@ -2311,12 +2313,13 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
        ev.build_id.header.size = sizeof(ev.build_id) + len;
        memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
 
-       err = process(&ev, NULL, session);
+       err = process(tool, &ev, NULL, machine);
 
        return err;
 }
 
-int perf_event__process_build_id(union perf_event *event,
+int perf_event__process_build_id(struct perf_tool *tool __used,
+                                union perf_event *event,
                                 struct perf_session *session)
 {
        __event_process_build_id(&event->build_id,
index 3d5a742..09365b3 100644 (file)
@@ -68,6 +68,7 @@ struct perf_header {
 };
 
 struct perf_evlist;
+struct perf_session;
 
 int perf_session__read_header(struct perf_session *session, int fd);
 int perf_session__write_header(struct perf_session *session,
@@ -96,32 +97,36 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
                          const char *name, bool is_kallsyms);
 int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
 
-int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
-                               perf_event__handler_t process,
-                               struct perf_session *session);
-int perf_session__synthesize_attrs(struct perf_session *session,
-                                  perf_event__handler_t process);
-int perf_event__process_attr(union perf_event *event, struct perf_session *session);
+int perf_event__synthesize_attr(struct perf_tool *tool,
+                               struct perf_event_attr *attr, u16 ids, u64 *id,
+                               perf_event__handler_t process);
+int perf_event__synthesize_attrs(struct perf_tool *tool,
+                                struct perf_session *session,
+                                perf_event__handler_t process);
+int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
 
-int perf_event__synthesize_event_type(u64 event_id, char *name,
+int perf_event__synthesize_event_type(struct perf_tool *tool,
+                                     u64 event_id, char *name,
                                      perf_event__handler_t process,
-                                     struct perf_session *session);
-int perf_event__synthesize_event_types(perf_event__handler_t process,
-                                      struct perf_session *session);
-int perf_event__process_event_type(union perf_event *event,
-                                  struct perf_session *session);
-
-int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
-                                       perf_event__handler_t process,
-                                       struct perf_session *session);
+                                     struct machine *machine);
+int perf_event__synthesize_event_types(struct perf_tool *tool,
+                                      perf_event__handler_t process,
+                                      struct machine *machine);
+int perf_event__process_event_type(struct perf_tool *tool,
+                                  union perf_event *event);
+
+int perf_event__synthesize_tracing_data(struct perf_tool *tool,
+                                       int fd, struct perf_evlist *evlist,
+                                       perf_event__handler_t process);
 int perf_event__process_tracing_data(union perf_event *event,
                                     struct perf_session *session);
 
-int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
+int perf_event__synthesize_build_id(struct perf_tool *tool,
+                                   struct dso *pos, u16 misc,
                                    perf_event__handler_t process,
-                                   struct machine *machine,
-                                   struct perf_session *session);
-int perf_event__process_build_id(union perf_event *event,
+                                   struct machine *machine);
+int perf_event__process_build_id(struct perf_tool *tool,
+                                union perf_event *event,
                                 struct perf_session *session);
 
 /*
index 89289c8..ff6f9d5 100644 (file)
@@ -117,7 +117,6 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
 
 static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
                                           int evidx __used,
-                                          int nr_events __used,
                                           void(*timer)(void *arg) __used,
                                           void *arg __used,
                                           int delay_secs __used)
@@ -128,7 +127,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
 #define K_RIGHT -2
 #else
 #include "ui/keysyms.h"
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
                             void(*timer)(void *arg), void *arg, int delay_secs);
 
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
index 78284b1..316aa0a 100644 (file)
@@ -562,6 +562,10 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
        INIT_LIST_HEAD(&self->user_dsos);
        INIT_LIST_HEAD(&self->kernel_dsos);
 
+       self->threads = RB_ROOT;
+       INIT_LIST_HEAD(&self->dead_threads);
+       self->last_match = NULL;
+
        self->kmaps.machine = self;
        self->pid           = pid;
        self->root_dir      = strdup(root_dir);
index 890d855..2b8017f 100644 (file)
@@ -18,9 +18,11 @@ enum map_type {
 extern const char *map_type__name[MAP__NR_TYPES];
 
 struct dso;
+struct ip_callchain;
 struct ref_reloc_sym;
 struct map_groups;
 struct machine;
+struct perf_evsel;
 
 struct map {
        union {
@@ -61,7 +63,11 @@ struct map_groups {
 struct machine {
        struct rb_node    rb_node;
        pid_t             pid;
+       u16               id_hdr_size;
        char              *root_dir;
+       struct rb_root    threads;
+       struct list_head  dead_threads;
+       struct thread     *last_match;
        struct list_head  user_dsos;
        struct list_head  kernel_dsos;
        struct map_groups kmaps;
@@ -148,6 +154,13 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid);
 void machine__exit(struct machine *self);
 void machine__delete(struct machine *self);
 
+int machine__resolve_callchain(struct machine *machine,
+                              struct perf_evsel *evsel, struct thread *thread,
+                              struct ip_callchain *chain,
+                              struct symbol **parent);
+int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
+                                    u64 addr);
+
 /*
  * Default guest kernel is defined by parameter --guestkallsyms
  * and --guestmodules
@@ -190,6 +203,12 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
                                               struct map **mapp,
                                               symbol_filter_t filter);
 
+
+struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
+void machine__remove_thread(struct machine *machine, struct thread *th);
+
+size_t machine__fprintf(struct machine *machine, FILE *fp);
+
 static inline
 struct symbol *machine__find_kernel_symbol(struct machine *self,
                                           enum map_type type, u64 addr,
index 928918b..586ab3f 100644 (file)
@@ -25,8 +25,6 @@ enum event_result {
        EVT_HANDLED_ALL
 };
 
-char debugfs_path[MAXPATHLEN];
-
 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
 
@@ -140,7 +138,7 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
        char evt_path[MAXPATHLEN];
        int fd;
 
-       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
+       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
                        sys_dir->d_name, evt_dir->d_name);
        fd = open(evt_path, O_RDONLY);
        if (fd < 0)
@@ -171,16 +169,16 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
 
-       if (debugfs_valid_mountpoint(debugfs_path))
+       if (debugfs_valid_mountpoint(tracing_events_path))
                return NULL;
 
-       sys_dir = opendir(debugfs_path);
+       sys_dir = opendir(tracing_events_path);
        if (!sys_dir)
                return NULL;
 
        for_each_subsystem(sys_dir, sys_dirent, sys_next) {
 
-               snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
+               snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
                         sys_dirent.d_name);
                evt_dir = opendir(dir_path);
                if (!evt_dir)
@@ -447,7 +445,7 @@ parse_single_tracepoint_event(char *sys_name,
        u64 id;
        int fd;
 
-       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
+       snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
                 sys_name, evt_name);
 
        fd = open(evt_path, O_RDONLY);
@@ -485,7 +483,7 @@ parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
        struct dirent *evt_ent;
        DIR *evt_dir;
 
-       snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name);
+       snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
        evt_dir = opendir(evt_path);
 
        if (!evt_dir) {
@@ -528,7 +526,7 @@ parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
        char sys_name[MAX_EVENT_LENGTH];
        unsigned int sys_length, evt_length;
 
-       if (debugfs_valid_mountpoint(debugfs_path))
+       if (debugfs_valid_mountpoint(tracing_events_path))
                return 0;
 
        evt_name = strchr(*strp, ':');
@@ -920,10 +918,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
 
-       if (debugfs_valid_mountpoint(debugfs_path))
+       if (debugfs_valid_mountpoint(tracing_events_path))
                return;
 
-       sys_dir = opendir(debugfs_path);
+       sys_dir = opendir(tracing_events_path);
        if (!sys_dir)
                return;
 
@@ -932,7 +930,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
                    !strglobmatch(sys_dirent.d_name, subsys_glob))
                        continue;
 
-               snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
+               snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
                         sys_dirent.d_name);
                evt_dir = opendir(dir_path);
                if (!evt_dir)
@@ -964,16 +962,16 @@ int is_valid_tracepoint(const char *event_string)
        char evt_path[MAXPATHLEN];
        char dir_path[MAXPATHLEN];
 
-       if (debugfs_valid_mountpoint(debugfs_path))
+       if (debugfs_valid_mountpoint(tracing_events_path))
                return 0;
 
-       sys_dir = opendir(debugfs_path);
+       sys_dir = opendir(tracing_events_path);
        if (!sys_dir)
                return 0;
 
        for_each_subsystem(sys_dir, sys_dirent, sys_next) {
 
-               snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
+               snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
                         sys_dirent.d_name);
                evt_dir = opendir(dir_path);
                if (!evt_dir)
index 2f8e375..7e0cbe7 100644 (file)
@@ -39,7 +39,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
 int print_hwcache_events(const char *event_glob);
 extern int is_valid_tracepoint(const char *event_string);
 
-extern char debugfs_path[];
 extern int valid_debugfs_mount(const char *debugfs);
 
 #endif /* __PERF_PARSE_EVENTS_H */
index 1132c8f..17e94d0 100644 (file)
@@ -5,7 +5,6 @@
 #include "util.h"
 #include "probe-event.h"
 
-#define MAX_PATH_LEN            256
 #define MAX_PROBE_BUFFER       1024
 #define MAX_PROBES              128
 
index 74350ff..a82ce43 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "../../perf.h"
 #include "../util.h"
+#include "../thread.h"
+#include "../event.h"
 #include "../trace-event.h"
 
 #include <EXTERN.h>
@@ -248,7 +250,7 @@ static inline struct event *find_cache_event(int type)
 static void perl_process_event(union perf_event *pevent __unused,
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
-                              struct perf_session *session __unused,
+                              struct machine *machine __unused,
                               struct thread *thread)
 {
        struct format_field *field;
index 6ccf70e..0b2a487 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "../../perf.h"
 #include "../util.h"
+#include "../event.h"
+#include "../thread.h"
 #include "../trace-event.h"
 
 PyMODINIT_FUNC initperf_trace_context(void);
@@ -207,7 +209,7 @@ static inline struct event *find_cache_event(int type)
 static void python_process_event(union perf_event *pevent __unused,
                                 struct perf_sample *sample,
                                 struct perf_evsel *evsel __unused,
-                                struct perf_session *session __unused,
+                                struct machine *machine __unused,
                                 struct thread *thread)
 {
        PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
index 0f4555c..d9318d8 100644 (file)
@@ -10,6 +10,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "session.h"
+#include "tool.h"
 #include "sort.h"
 #include "util.h"
 #include "cpumap.h"
@@ -78,39 +79,13 @@ out_close:
        return -1;
 }
 
-static void perf_session__id_header_size(struct perf_session *session)
-{
-       struct perf_sample *data;
-       u64 sample_type = session->sample_type;
-       u16 size = 0;
-
-       if (!session->sample_id_all)
-               goto out;
-
-       if (sample_type & PERF_SAMPLE_TID)
-               size += sizeof(data->tid) * 2;
-
-       if (sample_type & PERF_SAMPLE_TIME)
-               size += sizeof(data->time);
-
-       if (sample_type & PERF_SAMPLE_ID)
-               size += sizeof(data->id);
-
-       if (sample_type & PERF_SAMPLE_STREAM_ID)
-               size += sizeof(data->stream_id);
-
-       if (sample_type & PERF_SAMPLE_CPU)
-               size += sizeof(data->cpu) * 2;
-out:
-       session->id_hdr_size = size;
-}
-
 void perf_session__update_sample_type(struct perf_session *self)
 {
        self->sample_type = perf_evlist__sample_type(self->evlist);
        self->sample_size = __perf_evsel__sample_size(self->sample_type);
        self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
-       perf_session__id_header_size(self);
+       self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
+       self->host_machine.id_hdr_size = self->id_hdr_size;
 }
 
 int perf_session__create_kernel_maps(struct perf_session *self)
@@ -130,7 +105,7 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
 
 struct perf_session *perf_session__new(const char *filename, int mode,
                                       bool force, bool repipe,
-                                      struct perf_event_ops *ops)
+                                      struct perf_tool *tool)
 {
        size_t len = filename ? strlen(filename) + 1 : 0;
        struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -139,9 +114,6 @@ struct perf_session *perf_session__new(const char *filename, int mode,
                goto out;
 
        memcpy(self->filename, filename, len);
-       self->threads = RB_ROOT;
-       INIT_LIST_HEAD(&self->dead_threads);
-       self->last_match = NULL;
        /*
         * On 64bit we can mmap the data file in one go. No need for tiny mmap
         * slices. On 32bit we use 32MB.
@@ -171,10 +143,10 @@ struct perf_session *perf_session__new(const char *filename, int mode,
                        goto out_delete;
        }
 
-       if (ops && ops->ordering_requires_timestamps &&
-           ops->ordered_samples && !self->sample_id_all) {
+       if (tool && tool->ordering_requires_timestamps &&
+           tool->ordered_samples && !self->sample_id_all) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
-               ops->ordered_samples = false;
+               tool->ordered_samples = false;
        }
 
 out:
@@ -184,17 +156,22 @@ out_delete:
        return NULL;
 }
 
-static void perf_session__delete_dead_threads(struct perf_session *self)
+static void machine__delete_dead_threads(struct machine *machine)
 {
        struct thread *n, *t;
 
-       list_for_each_entry_safe(t, n, &self->dead_threads, node) {
+       list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
                list_del(&t->node);
                thread__delete(t);
        }
 }
 
-static void perf_session__delete_threads(struct perf_session *self)
+static void perf_session__delete_dead_threads(struct perf_session *session)
+{
+       machine__delete_dead_threads(&session->host_machine);
+}
+
+static void machine__delete_threads(struct machine *self)
 {
        struct rb_node *nd = rb_first(&self->threads);
 
@@ -207,6 +184,11 @@ static void perf_session__delete_threads(struct perf_session *self)
        }
 }
 
+static void perf_session__delete_threads(struct perf_session *session)
+{
+       machine__delete_threads(&session->host_machine);
+}
+
 void perf_session__delete(struct perf_session *self)
 {
        perf_session__destroy_kernel_maps(self);
@@ -217,7 +199,7 @@ void perf_session__delete(struct perf_session *self)
        free(self);
 }
 
-void perf_session__remove_thread(struct perf_session *self, struct thread *th)
+void machine__remove_thread(struct machine *self, struct thread *th)
 {
        self->last_match = NULL;
        rb_erase(&th->rb_node, &self->threads);
@@ -236,16 +218,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
        return 0;
 }
 
-int perf_session__resolve_callchain(struct perf_session *self,
-                                   struct thread *thread,
-                                   struct ip_callchain *chain,
-                                   struct symbol **parent)
+int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
+                              struct thread *thread,
+                              struct ip_callchain *chain,
+                              struct symbol **parent)
 {
        u8 cpumode = PERF_RECORD_MISC_USER;
        unsigned int i;
        int err;
 
-       callchain_cursor_reset(&self->callchain_cursor);
+       callchain_cursor_reset(&evsel->hists.callchain_cursor);
 
        for (i = 0; i < chain->nr; i++) {
                u64 ip;
@@ -272,7 +254,7 @@ int perf_session__resolve_callchain(struct perf_session *self,
 
                al.filtered = false;
                thread__find_addr_location(thread, self, cpumode,
-                               MAP__FUNCTION, thread->pid, ip, &al, NULL);
+                                          MAP__FUNCTION, ip, &al, NULL);
                if (al.sym != NULL) {
                        if (sort__has_parent && !*parent &&
                            symbol__match_parent_regex(al.sym))
@@ -281,7 +263,7 @@ int perf_session__resolve_callchain(struct perf_session *self,
                                break;
                }
 
-               err = callchain_cursor_append(&self->callchain_cursor,
+               err = callchain_cursor_append(&evsel->hists.callchain_cursor,
                                              ip, al.map, al.sym);
                if (err)
                        return err;
@@ -290,75 +272,91 @@ int perf_session__resolve_callchain(struct perf_session *self,
        return 0;
 }
 
-static int process_event_synth_stub(union perf_event *event __used,
-                                   struct perf_session *session __used)
+static int process_event_synth_tracing_data_stub(union perf_event *event __used,
+                                                struct perf_session *session __used)
+{
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+static int process_event_synth_attr_stub(union perf_event *event __used,
+                                        struct perf_evlist **pevlist __used)
 {
        dump_printf(": unhandled!\n");
        return 0;
 }
 
-static int process_event_sample_stub(union perf_event *event __used,
+static int process_event_sample_stub(struct perf_tool *tool __used,
+                                    union perf_event *event __used,
                                     struct perf_sample *sample __used,
                                     struct perf_evsel *evsel __used,
-                                    struct perf_session *session __used)
+                                    struct machine *machine __used)
 {
        dump_printf(": unhandled!\n");
        return 0;
 }
 
-static int process_event_stub(union perf_event *event __used,
+static int process_event_stub(struct perf_tool *tool __used,
+                             union perf_event *event __used,
                              struct perf_sample *sample __used,
-                             struct perf_session *session __used)
+                             struct machine *machine __used)
+{
+       dump_printf(": unhandled!\n");
+       return 0;
+}
+
+static int process_finished_round_stub(struct perf_tool *tool __used,
+                                      union perf_event *event __used,
+                                      struct perf_session *perf_session __used)
 {
        dump_printf(": unhandled!\n");
        return 0;
 }
 
-static int process_finished_round_stub(union perf_event *event __used,
-                                      struct perf_session *session __used,
-                                      struct perf_event_ops *ops __used)
+static int process_event_type_stub(struct perf_tool *tool __used,
+                                  union perf_event *event __used)
 {
        dump_printf(": unhandled!\n");
        return 0;
 }
 
-static int process_finished_round(union perf_event *event,
-                                 struct perf_session *session,
-                                 struct perf_event_ops *ops);
+static int process_finished_round(struct perf_tool *tool,
+                                 union perf_event *event,
+                                 struct perf_session *session);
 
-static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
+static void perf_tool__fill_defaults(struct perf_tool *tool)
 {
-       if (handler->sample == NULL)
-               handler->sample = process_event_sample_stub;
-       if (handler->mmap == NULL)
-               handler->mmap = process_event_stub;
-       if (handler->comm == NULL)
-               handler->comm = process_event_stub;
-       if (handler->fork == NULL)
-               handler->fork = process_event_stub;
-       if (handler->exit == NULL)
-               handler->exit = process_event_stub;
-       if (handler->lost == NULL)
-               handler->lost = perf_event__process_lost;
-       if (handler->read == NULL)
-               handler->read = process_event_stub;
-       if (handler->throttle == NULL)
-               handler->throttle = process_event_stub;
-       if (handler->unthrottle == NULL)
-               handler->unthrottle = process_event_stub;
-       if (handler->attr == NULL)
-               handler->attr = process_event_synth_stub;
-       if (handler->event_type == NULL)
-               handler->event_type = process_event_synth_stub;
-       if (handler->tracing_data == NULL)
-               handler->tracing_data = process_event_synth_stub;
-       if (handler->build_id == NULL)
-               handler->build_id = process_event_synth_stub;
-       if (handler->finished_round == NULL) {
-               if (handler->ordered_samples)
-                       handler->finished_round = process_finished_round;
+       if (tool->sample == NULL)
+               tool->sample = process_event_sample_stub;
+       if (tool->mmap == NULL)
+               tool->mmap = process_event_stub;
+       if (tool->comm == NULL)
+               tool->comm = process_event_stub;
+       if (tool->fork == NULL)
+               tool->fork = process_event_stub;
+       if (tool->exit == NULL)
+               tool->exit = process_event_stub;
+       if (tool->lost == NULL)
+               tool->lost = perf_event__process_lost;
+       if (tool->read == NULL)
+               tool->read = process_event_sample_stub;
+       if (tool->throttle == NULL)
+               tool->throttle = process_event_stub;
+       if (tool->unthrottle == NULL)
+               tool->unthrottle = process_event_stub;
+       if (tool->attr == NULL)
+               tool->attr = process_event_synth_attr_stub;
+       if (tool->event_type == NULL)
+               tool->event_type = process_event_type_stub;
+       if (tool->tracing_data == NULL)
+               tool->tracing_data = process_event_synth_tracing_data_stub;
+       if (tool->build_id == NULL)
+               tool->build_id = process_finished_round_stub;
+       if (tool->finished_round == NULL) {
+               if (tool->ordered_samples)
+                       tool->finished_round = process_finished_round;
                else
-                       handler->finished_round = process_finished_round_stub;
+                       tool->finished_round = process_finished_round_stub;
        }
 }
 
@@ -490,11 +488,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
 static int perf_session_deliver_event(struct perf_session *session,
                                      union perf_event *event,
                                      struct perf_sample *sample,
-                                     struct perf_event_ops *ops,
+                                     struct perf_tool *tool,
                                      u64 file_offset);
 
 static void flush_sample_queue(struct perf_session *s,
-                              struct perf_event_ops *ops)
+                              struct perf_tool *tool)
 {
        struct ordered_samples *os = &s->ordered_samples;
        struct list_head *head = &os->samples;
@@ -505,7 +503,7 @@ static void flush_sample_queue(struct perf_session *s,
        unsigned idx = 0, progress_next = os->nr_samples / 16;
        int ret;
 
-       if (!ops->ordered_samples || !limit)
+       if (!tool->ordered_samples || !limit)
                return;
 
        list_for_each_entry_safe(iter, tmp, head, list) {
@@ -516,7 +514,7 @@ static void flush_sample_queue(struct perf_session *s,
                if (ret)
                        pr_err("Can't parse sample, err = %d\n", ret);
                else
-                       perf_session_deliver_event(s, iter->event, &sample, ops,
+                       perf_session_deliver_event(s, iter->event, &sample, tool,
                                                   iter->file_offset);
 
                os->last_flush = iter->timestamp;
@@ -578,11 +576,11 @@ static void flush_sample_queue(struct perf_session *s,
  *      Flush every events below timestamp 7
  *      etc...
  */
-static int process_finished_round(union perf_event *event __used,
-                                 struct perf_session *session,
-                                 struct perf_event_ops *ops)
+static int process_finished_round(struct perf_tool *tool,
+                                 union perf_event *event __used,
+                                 struct perf_session *session)
 {
-       flush_sample_queue(session, ops);
+       flush_sample_queue(session, tool);
        session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
 
        return 0;
@@ -737,13 +735,26 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
                callchain__printf(sample);
 }
 
+static struct machine *
+       perf_session__find_machine_for_cpumode(struct perf_session *session,
+                                              union perf_event *event)
+{
+       const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+
+       if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest)
+               return perf_session__find_machine(session, event->ip.pid);
+
+       return perf_session__find_host_machine(session);
+}
+
 static int perf_session_deliver_event(struct perf_session *session,
                                      union perf_event *event,
                                      struct perf_sample *sample,
-                                     struct perf_event_ops *ops,
+                                     struct perf_tool *tool,
                                      u64 file_offset)
 {
        struct perf_evsel *evsel;
+       struct machine *machine;
 
        dump_event(session, event, file_offset, sample);
 
@@ -765,6 +776,8 @@ static int perf_session_deliver_event(struct perf_session *session,
                hists__inc_nr_events(&evsel->hists, event->header.type);
        }
 
+       machine = perf_session__find_machine_for_cpumode(session, event);
+
        switch (event->header.type) {
        case PERF_RECORD_SAMPLE:
                dump_sample(session, event, sample);
@@ -772,23 +785,25 @@ static int perf_session_deliver_event(struct perf_session *session,
                        ++session->hists.stats.nr_unknown_id;
                        return -1;
                }
-               return ops->sample(event, sample, evsel, session);
+               return tool->sample(tool, event, sample, evsel, machine);
        case PERF_RECORD_MMAP:
-               return ops->mmap(event, sample, session);
+               return tool->mmap(tool, event, sample, machine);
        case PERF_RECORD_COMM:
-               return ops->comm(event, sample, session);
+               return tool->comm(tool, event, sample, machine);
        case PERF_RECORD_FORK:
-               return ops->fork(event, sample, session);
+               return tool->fork(tool, event, sample, machine);
        case PERF_RECORD_EXIT:
-               return ops->exit(event, sample, session);
+               return tool->exit(tool, event, sample, machine);
        case PERF_RECORD_LOST:
-               return ops->lost(event, sample, session);
+               if (tool->lost == perf_event__process_lost)
+                       session->hists.stats.total_lost += event->lost.lost;
+               return tool->lost(tool, event, sample, machine);
        case PERF_RECORD_READ:
-               return ops->read(event, sample, session);
+               return tool->read(tool, event, sample, evsel, machine);
        case PERF_RECORD_THROTTLE:
-               return ops->throttle(event, sample, session);
+               return tool->throttle(tool, event, sample, machine);
        case PERF_RECORD_UNTHROTTLE:
-               return ops->unthrottle(event, sample, session);
+               return tool->unthrottle(tool, event, sample, machine);
        default:
                ++session->hists.stats.nr_unknown_events;
                return -1;
@@ -812,24 +827,29 @@ static int perf_session__preprocess_sample(struct perf_session *session,
 }
 
 static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
-                                           struct perf_event_ops *ops, u64 file_offset)
+                                           struct perf_tool *tool, u64 file_offset)
 {
+       int err;
+
        dump_event(session, event, file_offset, NULL);
 
        /* These events are processed right away */
        switch (event->header.type) {
        case PERF_RECORD_HEADER_ATTR:
-               return ops->attr(event, session);
+               err = tool->attr(event, &session->evlist);
+               if (err == 0)
+                       perf_session__update_sample_type(session);
+               return err;
        case PERF_RECORD_HEADER_EVENT_TYPE:
-               return ops->event_type(event, session);
+               return tool->event_type(tool, event);
        case PERF_RECORD_HEADER_TRACING_DATA:
                /* setup for reading amidst mmap */
                lseek(session->fd, file_offset, SEEK_SET);
-               return ops->tracing_data(event, session);
+               return tool->tracing_data(event, session);
        case PERF_RECORD_HEADER_BUILD_ID:
-               return ops->build_id(event, session);
+               return tool->build_id(tool, event, session);
        case PERF_RECORD_FINISHED_ROUND:
-               return ops->finished_round(event, session, ops);
+               return tool->finished_round(tool, event, session);
        default:
                return -EINVAL;
        }
@@ -837,7 +857,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
 
 static int perf_session__process_event(struct perf_session *session,
                                       union perf_event *event,
-                                      struct perf_event_ops *ops,
+                                      struct perf_tool *tool,
                                       u64 file_offset)
 {
        struct perf_sample sample;
@@ -853,7 +873,7 @@ static int perf_session__process_event(struct perf_session *session,
        hists__inc_nr_events(&session->hists, event->header.type);
 
        if (event->header.type >= PERF_RECORD_USER_TYPE_START)
-               return perf_session__process_user_event(session, event, ops, file_offset);
+               return perf_session__process_user_event(session, event, tool, file_offset);
 
        /*
         * For all kernel events we get the sample data
@@ -866,14 +886,14 @@ static int perf_session__process_event(struct perf_session *session,
        if (perf_session__preprocess_sample(session, event, &sample))
                return 0;
 
-       if (ops->ordered_samples) {
+       if (tool->ordered_samples) {
                ret = perf_session_queue_event(session, event, &sample,
                                               file_offset);
                if (ret != -ETIME)
                        return ret;
        }
 
-       return perf_session_deliver_event(session, event, &sample, ops,
+       return perf_session_deliver_event(session, event, &sample, tool,
                                          file_offset);
 }
 
@@ -884,6 +904,11 @@ void perf_event_header__bswap(struct perf_event_header *self)
        self->size = bswap_16(self->size);
 }
 
+struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
+{
+       return machine__findnew_thread(&session->host_machine, pid);
+}
+
 static struct thread *perf_session__register_idle_thread(struct perf_session *self)
 {
        struct thread *thread = perf_session__findnew(self, 0);
@@ -897,9 +922,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
 }
 
 static void perf_session__warn_about_errors(const struct perf_session *session,
-                                           const struct perf_event_ops *ops)
+                                           const struct perf_tool *tool)
 {
-       if (ops->lost == perf_event__process_lost &&
+       if (tool->lost == perf_event__process_lost &&
            session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
                ui__warning("Processed %d events and lost %d chunks!\n\n"
                            "Check IO/CPU overload!\n\n",
@@ -934,7 +959,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
 volatile int session_done;
 
 static int __perf_session__process_pipe_events(struct perf_session *self,
-                                              struct perf_event_ops *ops)
+                                              struct perf_tool *tool)
 {
        union perf_event event;
        uint32_t size;
@@ -943,7 +968,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
        int err;
        void *p;
 
-       perf_event_ops__fill_defaults(ops);
+       perf_tool__fill_defaults(tool);
 
        head = 0;
 more:
@@ -980,7 +1005,7 @@ more:
        }
 
        if (size == 0 ||
-           (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
+           (skip = perf_session__process_event(self, &event, tool, head)) < 0) {
                dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
                            head, event.header.size, event.header.type);
                /*
@@ -1003,7 +1028,7 @@ more:
 done:
        err = 0;
 out_err:
-       perf_session__warn_about_errors(self, ops);
+       perf_session__warn_about_errors(self, tool);
        perf_session_free_sample_buffers(self);
        return err;
 }
@@ -1034,7 +1059,7 @@ fetch_mmaped_event(struct perf_session *session,
 
 int __perf_session__process_events(struct perf_session *session,
                                   u64 data_offset, u64 data_size,
-                                  u64 file_size, struct perf_event_ops *ops)
+                                  u64 file_size, struct perf_tool *tool)
 {
        u64 head, page_offset, file_offset, file_pos, progress_next;
        int err, mmap_prot, mmap_flags, map_idx = 0;
@@ -1043,7 +1068,7 @@ int __perf_session__process_events(struct perf_session *session,
        union perf_event *event;
        uint32_t size;
 
-       perf_event_ops__fill_defaults(ops);
+       perf_tool__fill_defaults(tool);
 
        page_size = sysconf(_SC_PAGESIZE);
 
@@ -1098,7 +1123,7 @@ more:
        size = event->header.size;
 
        if (size == 0 ||
-           perf_session__process_event(session, event, ops, file_pos) < 0) {
+           perf_session__process_event(session, event, tool, file_pos) < 0) {
                dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
                            file_offset + head, event->header.size,
                            event->header.type);
@@ -1127,15 +1152,15 @@ more:
        err = 0;
        /* do the final flush for ordered samples */
        session->ordered_samples.next_flush = ULLONG_MAX;
-       flush_sample_queue(session, ops);
+       flush_sample_queue(session, tool);
 out_err:
-       perf_session__warn_about_errors(session, ops);
+       perf_session__warn_about_errors(session, tool);
        perf_session_free_sample_buffers(session);
        return err;
 }
 
 int perf_session__process_events(struct perf_session *self,
-                                struct perf_event_ops *ops)
+                                struct perf_tool *tool)
 {
        int err;
 
@@ -1146,9 +1171,9 @@ int perf_session__process_events(struct perf_session *self,
                err = __perf_session__process_events(self,
                                                     self->header.data_offset,
                                                     self->header.data_size,
-                                                    self->size, ops);
+                                                    self->size, tool);
        else
-               err = __perf_session__process_pipe_events(self, ops);
+               err = __perf_session__process_pipe_events(self, tool);
 
        return err;
 }
@@ -1163,9 +1188,8 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg)
        return true;
 }
 
-int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
-                                            const char *symbol_name,
-                                            u64 addr)
+int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
+                                    const char *symbol_name, u64 addr)
 {
        char *bracket;
        enum map_type i;
@@ -1224,6 +1248,27 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
        return ret;
 }
 
+size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
+{
+       /*
+        * FIXME: Here we have to actually print all the machines in this
+        * session, not just the host...
+        */
+       return machine__fprintf(&session->host_machine, fp);
+}
+
+void perf_session__remove_thread(struct perf_session *session,
+                                struct thread *th)
+{
+       /*
+        * FIXME: This one makes no sense, we need to remove the thread from
+        * the machine it belongs to, perf_session can have many machines, so
+        * doing it always on ->host_machine is wrong.  Fix when auditing all
+        * the 'perf kvm' code.
+        */
+       machine__remove_thread(&session->host_machine, th);
+}
+
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
                                              unsigned int type)
 {
@@ -1236,17 +1281,16 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
        return NULL;
 }
 
-void perf_session__print_ip(union perf_event *event,
-                           struct perf_sample *sample,
-                           struct perf_session *session,
-                           int print_sym, int print_dso)
+void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
+                         struct machine *machine, struct perf_evsel *evsel,
+                         int print_sym, int print_dso)
 {
        struct addr_location al;
        const char *symname, *dsoname;
-       struct callchain_cursor *cursor = &session->callchain_cursor;
+       struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
        struct callchain_cursor_node *node;
 
-       if (perf_event__preprocess_sample(event, session, &al, sample,
+       if (perf_event__preprocess_sample(event, machine, &al, sample,
                                          NULL) < 0) {
                error("problem processing %d event, skipping it.\n",
                        event->header.type);
@@ -1255,7 +1299,7 @@ void perf_session__print_ip(union perf_event *event,
 
        if (symbol_conf.use_callchain && sample->callchain) {
 
-               if (perf_session__resolve_callchain(session, al.thread,
+               if (machine__resolve_callchain(machine, evsel, al.thread,
                                                sample->callchain, NULL) != 0) {
                        if (verbose)
                                error("Failed to resolve callchain. Skipping\n");
index 6e393c9..30e9c6b 100644 (file)
@@ -30,9 +30,6 @@ struct perf_session {
        struct perf_header      header;
        unsigned long           size;
        unsigned long           mmap_window;
-       struct rb_root          threads;
-       struct list_head        dead_threads;
-       struct thread           *last_match;
        struct machine          host_machine;
        struct rb_root          machines;
        struct perf_evlist      *evlist;
@@ -53,65 +50,31 @@ struct perf_session {
        int                     cwdlen;
        char                    *cwd;
        struct ordered_samples  ordered_samples;
-       struct callchain_cursor callchain_cursor;
        char                    filename[0];
 };
 
-struct perf_evsel;
-struct perf_event_ops;
-
-typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
-                           struct perf_evsel *evsel, struct perf_session *session);
-typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
-                       struct perf_session *session);
-typedef int (*event_synth_op)(union perf_event *self,
-                             struct perf_session *session);
-typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
-                        struct perf_event_ops *ops);
-
-struct perf_event_ops {
-       event_sample    sample;
-       event_op        mmap,
-                       comm,
-                       fork,
-                       exit,
-                       lost,
-                       read,
-                       throttle,
-                       unthrottle;
-       event_synth_op  attr,
-                       event_type,
-                       tracing_data,
-                       build_id;
-       event_op2       finished_round;
-       bool            ordered_samples;
-       bool            ordering_requires_timestamps;
-};
+struct perf_tool;
 
 struct perf_session *perf_session__new(const char *filename, int mode,
                                       bool force, bool repipe,
-                                      struct perf_event_ops *ops);
+                                      struct perf_tool *tool);
 void perf_session__delete(struct perf_session *self);
 
 void perf_event_header__bswap(struct perf_event_header *self);
 
 int __perf_session__process_events(struct perf_session *self,
                                   u64 data_offset, u64 data_size, u64 size,
-                                  struct perf_event_ops *ops);
+                                  struct perf_tool *tool);
 int perf_session__process_events(struct perf_session *self,
-                                struct perf_event_ops *event_ops);
+                                struct perf_tool *tool);
 
-int perf_session__resolve_callchain(struct perf_session *self,
+int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel,
                                    struct thread *thread,
                                    struct ip_callchain *chain,
                                    struct symbol **parent);
 
 bool perf_session__has_traces(struct perf_session *self, const char *msg);
 
-int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
-                                            const char *symbol_name,
-                                            u64 addr);
-
 void mem_bswap_64(void *src, int byte_size);
 void perf_event__attr_swap(struct perf_event_attr *attr);
 
@@ -144,12 +107,16 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p
 
 static inline
 void perf_session__process_machines(struct perf_session *self,
+                                   struct perf_tool *tool,
                                    machine__process_t process)
 {
-       process(&self->host_machine, self);
-       return machines__process(&self->machines, process, self);
+       process(&self->host_machine, tool);
+       return machines__process(&self->machines, process, tool);
 }
 
+struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
+size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
+
 size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
 
 size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
@@ -170,10 +137,9 @@ static inline int perf_session__parse_sample(struct perf_session *session,
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
                                            unsigned int type);
 
-void perf_session__print_ip(union perf_event *event,
-                                struct perf_sample *sample,
-                                struct perf_session *session,
-                                int print_sym, int print_dso);
+void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
+                         struct machine *machine, struct perf_evsel *evsel,
+                         int print_sym, int print_dso);
 
 int perf_session__cpu_bitmap(struct perf_session *session,
                             const char *cpu_list, unsigned long *cpu_bitmap);
index 95d3700..36d4c56 100644 (file)
@@ -27,7 +27,8 @@ build_tmp = getenv('PYTHON_EXTBUILD_TMP')
 perf = Extension('perf',
                  sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
                             'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
-                            'util/util.c', 'util/xyarray.c', 'util/cgroup.c'],
+                            'util/util.c', 'util/xyarray.c', 'util/cgroup.c',
+                            'util/debugfs.c'],
                  include_dirs = ['util/include'],
                  extra_compile_args = cflags,
                  )
index 29f8d74..123c2e1 100644 (file)
@@ -68,6 +68,7 @@ struct strlist;
 
 struct symbol_conf {
        unsigned short  priv_size;
+       unsigned short  nr_events;
        bool            try_vmlinux_path,
                        use_modules,
                        sort_by_name,
index d5d3b22..fb4b7ea 100644 (file)
@@ -61,7 +61,7 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
               map_groups__fprintf(&self->mg, verbose, fp);
 }
 
-struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
+struct thread *machine__findnew_thread(struct machine *self, pid_t pid)
 {
        struct rb_node **p = &self->threads.rb_node;
        struct rb_node *parent = NULL;
@@ -125,12 +125,12 @@ int thread__fork(struct thread *self, struct thread *parent)
        return 0;
 }
 
-size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
+size_t machine__fprintf(struct machine *machine, FILE *fp)
 {
        size_t ret = 0;
        struct rb_node *nd;
 
-       for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
                struct thread *pos = rb_entry(nd, struct thread, rb_node);
 
                ret += thread__fprintf(pos, fp);
index e5f2401..70c2c13 100644 (file)
@@ -18,16 +18,14 @@ struct thread {
        int                     comm_len;
 };
 
-struct perf_session;
+struct machine;
 
 void thread__delete(struct thread *self);
 
 int thread__set_comm(struct thread *self, const char *comm);
 int thread__comm_len(struct thread *self);
-struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
 void thread__insert_map(struct thread *self, struct map *map);
 int thread__fork(struct thread *self, struct thread *parent);
-size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
 
 static inline struct map *thread__find_map(struct thread *self,
                                           enum map_type type, u64 addr)
@@ -35,14 +33,12 @@ static inline struct map *thread__find_map(struct thread *self,
        return self ? map_groups__find(&self->mg, type, addr) : NULL;
 }
 
-void thread__find_addr_map(struct thread *self,
-                          struct perf_session *session, u8 cpumode,
-                          enum map_type type, pid_t pid, u64 addr,
+void thread__find_addr_map(struct thread *thread, struct machine *machine,
+                          u8 cpumode, enum map_type type, u64 addr,
                           struct addr_location *al);
 
-void thread__find_addr_location(struct thread *self,
-                               struct perf_session *session, u8 cpumode,
-                               enum map_type type, pid_t pid, u64 addr,
+void thread__find_addr_location(struct thread *thread, struct machine *machine,
+                               u8 cpumode, enum map_type type, u64 addr,
                                struct addr_location *al,
                                symbol_filter_t filter);
 #endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
new file mode 100644 (file)
index 0000000..b0e1aad
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __PERF_TOOL_H
+#define __PERF_TOOL_H
+
+#include <stdbool.h>
+
+struct perf_session;
+union perf_event;
+struct perf_evlist;
+struct perf_evsel;
+struct perf_sample;
+struct perf_tool;
+struct machine;
+
+typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
+                           struct perf_sample *sample,
+                           struct perf_evsel *evsel, struct machine *machine);
+
+typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
+                       struct perf_sample *sample, struct machine *machine);
+
+typedef int (*event_attr_op)(union perf_event *event,
+                            struct perf_evlist **pevlist);
+typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
+
+typedef int (*event_synth_op)(union perf_event *event,
+                             struct perf_session *session);
+
+typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
+                        struct perf_session *session);
+
+struct perf_tool {
+       event_sample    sample,
+                       read;
+       event_op        mmap,
+                       comm,
+                       fork,
+                       exit,
+                       lost,
+                       throttle,
+                       unthrottle;
+       event_attr_op   attr;
+       event_synth_op  tracing_data;
+       event_simple_op event_type;
+       event_op2       finished_round,
+                       build_id;
+       bool            ordered_samples;
+       bool            ordering_requires_timestamps;
+};
+
+#endif /* __PERF_TOOL_H */
index 3996509..a248f3c 100644 (file)
@@ -1,15 +1,17 @@
 #ifndef __PERF_TOP_H
 #define __PERF_TOP_H 1
 
+#include "tool.h"
 #include "types.h"
-#include "../perf.h"
 #include <stddef.h>
+#include <stdbool.h>
 
 struct perf_evlist;
 struct perf_evsel;
 struct perf_session;
 
 struct perf_top {
+       struct perf_tool   tool;
        struct perf_evlist *evlist;
        /*
         * Symbols will be added here in perf_event__process_sample and will
@@ -23,10 +25,26 @@ struct perf_top {
        int                freq;
        pid_t              target_pid, target_tid;
        bool               hide_kernel_symbols, hide_user_symbols, zero;
+       bool               system_wide;
+       bool               use_tui, use_stdio;
+       bool               sort_has_symbols;
+       bool               dont_use_callchains;
+       bool               kptr_restrict_warned;
+       bool               vmlinux_warned;
+       bool               inherit;
+       bool               group;
+       bool               sample_id_all_avail;
+       bool               dump_symtab;
        const char         *cpu_list;
        struct hist_entry  *sym_filter_entry;
        struct perf_evsel  *sym_evsel;
        struct perf_session *session;
+       struct winsize     winsize;
+       unsigned int       mmap_pages;
+       int                default_interval;
+       int                realtime_prio;
+       int                sym_pcnt_filter;
+       const char         *sym_filter;
 };
 
 size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
index d2655f0..ac6830d 100644 (file)
@@ -18,7 +18,8 @@
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
-#define _GNU_SOURCE
+#include <ctype.h>
+#include "util.h"
 #include <dirent.h>
 #include <mntent.h>
 #include <stdio.h>
@@ -31,7 +32,6 @@
 #include <pthread.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <ctype.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <linux/list.h>
 
 #define VERSION "0.5"
 
-#define _STR(x) #x
-#define STR(x) _STR(x)
-#define MAX_PATH 256
-
 #define TRACE_CTRL     "tracing_on"
 #define TRACE          "trace"
 #define AVAILABLE      "available_tracers"
@@ -73,26 +69,6 @@ struct events {
 };
 
 
-
-static void die(const char *fmt, ...)
-{
-       va_list ap;
-       int ret = errno;
-
-       if (errno)
-               perror("perf");
-       else
-               ret = -1;
-
-       va_start(ap, fmt);
-       fprintf(stderr, "  ");
-       vfprintf(stderr, fmt, ap);
-       va_end(ap);
-
-       fprintf(stderr, "\n");
-       exit(ret);
-}
-
 void *malloc_or_die(unsigned int size)
 {
        void *data;
index c9dcbec..a3fdf55 100644 (file)
@@ -39,7 +39,7 @@ static int stop_script_unsupported(void)
 static void process_event_unsupported(union perf_event *event __unused,
                                      struct perf_sample *sample __unused,
                                      struct perf_evsel *evsel __unused,
-                                     struct perf_session *session __unused,
+                                     struct machine *machine __unused,
                                      struct thread *thread __unused)
 {
 }
index a841008..58ae14c 100644 (file)
@@ -3,7 +3,11 @@
 
 #include <stdbool.h>
 #include "parse-events.h"
-#include "session.h"
+
+struct machine;
+struct perf_sample;
+union perf_event;
+struct thread;
 
 #define __unused __attribute__((unused))
 
@@ -292,7 +296,7 @@ struct scripting_ops {
        void (*process_event) (union perf_event *event,
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
-                              struct perf_session *session,
+                              struct machine *machine,
                               struct thread *thread);
        int (*generate_script) (const char *outfile);
 };
index 0575905..295a9c9 100644 (file)
@@ -224,7 +224,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser)
 }
 
 static int annotate_browser__run(struct annotate_browser *self, int evidx,
-                                int nr_events, void(*timer)(void *arg),
+                                void(*timer)(void *arg),
                                 void *arg, int delay_secs)
 {
        struct rb_node *nd = NULL;
@@ -328,8 +328,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
                                notes = symbol__annotation(target);
                                pthread_mutex_lock(&notes->lock);
 
-                               if (notes->src == NULL &&
-                                   symbol__alloc_hist(target, nr_events) < 0) {
+                               if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
                                        pthread_mutex_unlock(&notes->lock);
                                        ui__warning("Not enough memory for annotating '%s' symbol!\n",
                                                    target->name);
@@ -337,7 +336,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
                                }
 
                                pthread_mutex_unlock(&notes->lock);
-                               symbol__tui_annotate(target, ms->map, evidx, nr_events,
+                               symbol__tui_annotate(target, ms->map, evidx,
                                                     timer, arg, delay_secs);
                        }
                        continue;
@@ -358,15 +357,15 @@ out:
        return key;
 }
 
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events,
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
                             void(*timer)(void *arg), void *arg, int delay_secs)
 {
-       return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events,
+       return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
                                    timer, arg, delay_secs);
 }
 
 int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
-                        int nr_events, void(*timer)(void *arg), void *arg,
+                        void(*timer)(void *arg), void *arg,
                         int delay_secs)
 {
        struct objdump_line *pos, *n;
@@ -419,8 +418,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
        browser.b.nr_entries = browser.nr_entries;
        browser.b.entries = &notes->src->source,
        browser.b.width += 18; /* Percentage */
-       ret = annotate_browser__run(&browser, evidx, nr_events,
-                                   timer, arg, delay_secs);
+       ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
        list_for_each_entry_safe(pos, n, &notes->src->source, node) {
                list_del(&pos->node);
                objdump_line__free(pos);
index d0c94b4..1212a38 100644 (file)
@@ -1020,7 +1020,7 @@ do_annotate:
                         * Don't let this be freed, say, by hists__decay_entry.
                         */
                        he->used = true;
-                       err = hist_entry__tui_annotate(he, evsel->idx, nr_events,
+                       err = hist_entry__tui_annotate(he, evsel->idx,
                                                       timer, arg, delay_secs);
                        he->used = false;
                        ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
index 295e366..13aa64e 100644 (file)
@@ -14,6 +14,9 @@ void ui_progress__update(u64 curr, u64 total, const char *title)
        if (use_browser <= 0)
                return;
 
+       if (total == 0)
+               return;
+
        ui__refresh_dimensions(true);
        pthread_mutex_lock(&ui__lock);
        y = SLtt_Screen_Rows / 2 - 2;