aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt3
-rw-r--r--Documentation/trace/events.txt2
-rw-r--r--arch/Kconfig4
-rw-r--r--arch/x86/include/asm/insn.h7
-rw-r--r--arch/x86/include/asm/perf_event.h29
-rw-r--r--arch/x86/kernel/cpu/perf_event.c254
-rw-r--r--arch/x86/kernel/cpu/perf_event.h51
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c72
-rw-r--r--arch/x86/kernel/jump_label.c2
-rw-r--r--arch/x86/lib/inat.c9
-rw-r--r--arch/x86/lib/insn.c4
-rw-r--r--arch/x86/lib/x86-opcode-map.txt606
-rw-r--r--arch/x86/oprofile/Makefile3
-rw-r--r--arch/x86/oprofile/init.c30
-rw-r--r--arch/x86/oprofile/nmi_int.c27
-rw-r--r--arch/x86/oprofile/nmi_timer_int.c50
-rw-r--r--arch/x86/tools/Makefile11
-rw-r--r--arch/x86/tools/gen-insn-attr-x86.awk21
-rw-r--r--arch/x86/tools/insn_sanity.c275
-rw-r--r--drivers/oprofile/nmi_timer_int.c173
-rw-r--r--drivers/oprofile/oprof.c30
-rw-r--r--drivers/oprofile/oprof.h9
-rw-r--r--drivers/oprofile/timer_int.c30
-rw-r--r--include/linux/bitops.h10
-rw-r--r--include/linux/jump_label.h27
-rw-r--r--include/linux/perf_event.h7
-rw-r--r--kernel/events/Makefile2
-rw-r--r--kernel/events/callchain.c191
-rw-r--r--kernel/events/core.c296
-rw-r--r--kernel/events/internal.h39
-rw-r--r--kernel/jump_label.c49
-rw-r--r--kernel/lockdep.c30
-rw-r--r--kernel/trace/trace.c105
-rw-r--r--kernel/trace/trace.h2
-rw-r--r--kernel/trace/trace_events_filter.c26
-rw-r--r--kernel/trace/trace_irqsoff.c13
-rw-r--r--kernel/trace/trace_output.c16
-rw-r--r--kernel/trace/trace_sched_wakeup.c13
-rw-r--r--tools/perf/Documentation/perf-annotate.txt2
-rw-r--r--tools/perf/Documentation/perf-report.txt4
-rw-r--r--tools/perf/Documentation/perf-script.txt7
-rw-r--r--tools/perf/Documentation/perf-test.txt8
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/builtin-annotate.c133
-rw-r--r--tools/perf/builtin-diff.c21
-rw-r--r--tools/perf/builtin-inject.c118
-rw-r--r--tools/perf/builtin-kmem.c14
-rw-r--r--tools/perf/builtin-lock.c10
-rw-r--r--tools/perf/builtin-probe.c1
-rw-r--r--tools/perf/builtin-record.c585
-rw-r--r--tools/perf/builtin-report.c225
-rw-r--r--tools/perf/builtin-sched.c198
-rw-r--r--tools/perf/builtin-script.c50
-rw-r--r--tools/perf/builtin-stat.c43
-rw-r--r--tools/perf/builtin-test.c418
-rw-r--r--tools/perf/builtin-timechart.c34
-rw-r--r--tools/perf/builtin-top.c557
-rw-r--r--tools/perf/perf.c33
-rw-r--r--tools/perf/perf.h23
-rw-r--r--tools/perf/util/annotate.c6
-rw-r--r--tools/perf/util/annotate.h5
-rw-r--r--tools/perf/util/build-id.c26
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/callchain.h3
-rw-r--r--tools/perf/util/cgroup.c15
-rw-r--r--tools/perf/util/debugfs.c35
-rw-r--r--tools/perf/util/debugfs.h31
-rw-r--r--tools/perf/util/event.c243
-rw-r--r--tools/perf/util/event.h65
-rw-r--r--tools/perf/util/evlist.c293
-rw-r--r--tools/perf/util/evlist.h43
-rw-r--r--tools/perf/util/evsel.c70
-rw-r--r--tools/perf/util/evsel.h8
-rw-r--r--tools/perf/util/header.c75
-rw-r--r--tools/perf/util/header.h45
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/map.c4
-rw-r--r--tools/perf/util/map.h19
-rw-r--r--tools/perf/util/parse-events.c28
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/probe-finder.h1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c4
-rw-r--r--tools/perf/util/session.c326
-rw-r--r--tools/perf/util/session.h62
-rw-r--r--tools/perf/util/setup.py3
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/thread.c6
-rw-r--r--tools/perf/util/thread.h14
-rw-r--r--tools/perf/util/tool.h50
-rw-r--r--tools/perf/util/top.h20
-rw-r--r--tools/perf/util/trace-event-info.c28
-rw-r--r--tools/perf/util/trace-event-scripting.c2
-rw-r--r--tools/perf/util/trace-event.h8
-rw-r--r--tools/perf/util/ui/browsers/annotate.c16
-rw-r--r--tools/perf/util/ui/browsers/hists.c2
-rw-r--r--tools/perf/util/ui/progress.c3
98 files changed, 4196 insertions, 2389 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 6e7cce096e6..e35c1efffdf 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1882,6 +1882,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
1882 arch_perfmon: [X86] Force use of architectural 1882 arch_perfmon: [X86] Force use of architectural
1883 perfmon on Intel CPUs instead of the 1883 perfmon on Intel CPUs instead of the
1884 CPU specific event set. 1884 CPU specific event set.
1885 timer: [X86] Force use of architectural NMI
1886 timer mode (see also oprofile.timer
1887 for generic hr timer mode)
1885 1888
1886 oops=panic Always panic on oopses. Default is to just kill the 1889 oops=panic Always panic on oopses. Default is to just kill the
1887 process, but there is a small probability of 1890 process, but there is a small probability of
diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt
index b510564aac7..bb24c2a0e87 100644
--- a/Documentation/trace/events.txt
+++ b/Documentation/trace/events.txt
@@ -191,8 +191,6 @@ And for string fields they are:
191 191
192Currently, only exact string matches are supported. 192Currently, only exact string matches are supported.
193 193
194Currently, the maximum number of predicates in a filter is 16.
195
1965.2 Setting filters 1945.2 Setting filters
197------------------- 195-------------------
198 196
diff --git a/arch/Kconfig b/arch/Kconfig
index 4b0669cbb3b..2505740b81d 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -30,6 +30,10 @@ config OPROFILE_EVENT_MULTIPLEX
30config HAVE_OPROFILE 30config HAVE_OPROFILE
31 bool 31 bool
32 32
33config OPROFILE_NMI_TIMER
34 def_bool y
35 depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
36
33config KPROBES 37config KPROBES
34 bool "Kprobes" 38 bool "Kprobes"
35 depends on MODULES 39 depends on MODULES
diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
index 88c765e1641..74df3f1eddf 100644
--- a/arch/x86/include/asm/insn.h
+++ b/arch/x86/include/asm/insn.h
@@ -137,6 +137,13 @@ static inline int insn_is_avx(struct insn *insn)
137 return (insn->vex_prefix.value != 0); 137 return (insn->vex_prefix.value != 0);
138} 138}
139 139
140/* Ensure this instruction is decoded completely */
141static inline int insn_complete(struct insn *insn)
142{
143 return insn->opcode.got && insn->modrm.got && insn->sib.got &&
144 insn->displacement.got && insn->immediate.got;
145}
146
140static inline insn_byte_t insn_vex_m_bits(struct insn *insn) 147static inline insn_byte_t insn_vex_m_bits(struct insn *insn)
141{ 148{
142 if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 149 if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index f61c62f7d5d..b50e9d15aae 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -57,6 +57,7 @@
57 (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) 57 (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
58 58
59#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6 59#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6
60#define ARCH_PERFMON_EVENTS_COUNT 7
60 61
61/* 62/*
62 * Intel "Architectural Performance Monitoring" CPUID 63 * Intel "Architectural Performance Monitoring" CPUID
@@ -72,6 +73,19 @@ union cpuid10_eax {
72 unsigned int full; 73 unsigned int full;
73}; 74};
74 75
76union cpuid10_ebx {
77 struct {
78 unsigned int no_unhalted_core_cycles:1;
79 unsigned int no_instructions_retired:1;
80 unsigned int no_unhalted_reference_cycles:1;
81 unsigned int no_llc_reference:1;
82 unsigned int no_llc_misses:1;
83 unsigned int no_branch_instruction_retired:1;
84 unsigned int no_branch_misses_retired:1;
85 } split;
86 unsigned int full;
87};
88
75union cpuid10_edx { 89union cpuid10_edx {
76 struct { 90 struct {
77 unsigned int num_counters_fixed:5; 91 unsigned int num_counters_fixed:5;
@@ -81,6 +95,15 @@ union cpuid10_edx {
81 unsigned int full; 95 unsigned int full;
82}; 96};
83 97
98struct x86_pmu_capability {
99 int version;
100 int num_counters_gp;
101 int num_counters_fixed;
102 int bit_width_gp;
103 int bit_width_fixed;
104 unsigned int events_mask;
105 int events_mask_len;
106};
84 107
85/* 108/*
86 * Fixed-purpose performance events: 109 * Fixed-purpose performance events:
@@ -202,6 +225,7 @@ struct perf_guest_switch_msr {
202}; 225};
203 226
204extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr); 227extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr);
228extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap);
205#else 229#else
206static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr) 230static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
207{ 231{
@@ -209,6 +233,11 @@ static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
209 return NULL; 233 return NULL;
210} 234}
211 235
236static inline void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
237{
238 memset(cap, 0, sizeof(*cap));
239}
240
212static inline void perf_events_lapic_init(void) { } 241static inline void perf_events_lapic_init(void) { }
213#endif 242#endif
214 243
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 2bda212a001..930fe487954 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -484,18 +484,195 @@ static inline int is_x86_event(struct perf_event *event)
484 return event->pmu == &pmu; 484 return event->pmu == &pmu;
485} 485}
486 486
487/*
488 * Event scheduler state:
489 *
490 * Assign events iterating over all events and counters, beginning
491 * with events with least weights first. Keep the current iterator
492 * state in struct sched_state.
493 */
494struct sched_state {
495 int weight;
496 int event; /* event index */
497 int counter; /* counter index */
498 int unassigned; /* number of events to be assigned left */
499 unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
500};
501
502/* Total max is X86_PMC_IDX_MAX, but we are O(n!) limited */
503#define SCHED_STATES_MAX 2
504
505struct perf_sched {
506 int max_weight;
507 int max_events;
508 struct event_constraint **constraints;
509 struct sched_state state;
510 int saved_states;
511 struct sched_state saved[SCHED_STATES_MAX];
512};
513
514/*
515 * Initialize interator that runs through all events and counters.
516 */
517static void perf_sched_init(struct perf_sched *sched, struct event_constraint **c,
518 int num, int wmin, int wmax)
519{
520 int idx;
521
522 memset(sched, 0, sizeof(*sched));
523 sched->max_events = num;
524 sched->max_weight = wmax;
525 sched->constraints = c;
526
527 for (idx = 0; idx < num; idx++) {
528 if (c[idx]->weight == wmin)
529 break;
530 }
531
532 sched->state.event = idx; /* start with min weight */
533 sched->state.weight = wmin;
534 sched->state.unassigned = num;
535}
536
537static void perf_sched_save_state(struct perf_sched *sched)
538{
539 if (WARN_ON_ONCE(sched->saved_states >= SCHED_STATES_MAX))
540 return;
541
542 sched->saved[sched->saved_states] = sched->state;
543 sched->saved_states++;
544}
545
546static bool perf_sched_restore_state(struct perf_sched *sched)
547{
548 if (!sched->saved_states)
549 return false;
550
551 sched->saved_states--;
552 sched->state = sched->saved[sched->saved_states];
553
554 /* continue with next counter: */
555 clear_bit(sched->state.counter++, sched->state.used);
556
557 return true;
558}
559
560/*
561 * Select a counter for the current event to schedule. Return true on
562 * success.
563 */
564static bool __perf_sched_find_counter(struct perf_sched *sched)
565{
566 struct event_constraint *c;
567 int idx;
568
569 if (!sched->state.unassigned)
570 return false;
571
572 if (sched->state.event >= sched->max_events)
573 return false;
574
575 c = sched->constraints[sched->state.event];
576
577 /* Prefer fixed purpose counters */
578 if (x86_pmu.num_counters_fixed) {
579 idx = X86_PMC_IDX_FIXED;
580 for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_MAX) {
581 if (!__test_and_set_bit(idx, sched->state.used))
582 goto done;
583 }
584 }
585 /* Grab the first unused counter starting with idx */
586 idx = sched->state.counter;
587 for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_FIXED) {
588 if (!__test_and_set_bit(idx, sched->state.used))
589 goto done;
590 }
591
592 return false;
593
594done:
595 sched->state.counter = idx;
596
597 if (c->overlap)
598 perf_sched_save_state(sched);
599
600 return true;
601}
602
603static bool perf_sched_find_counter(struct perf_sched *sched)
604{
605 while (!__perf_sched_find_counter(sched)) {
606 if (!perf_sched_restore_state(sched))
607 return false;
608 }
609
610 return true;
611}
612
613/*
614 * Go through all unassigned events and find the next one to schedule.
615 * Take events with the least weight first. Return true on success.
616 */
617static bool perf_sched_next_event(struct perf_sched *sched)
618{
619 struct event_constraint *c;
620
621 if (!sched->state.unassigned || !--sched->state.unassigned)
622 return false;
623
624 do {
625 /* next event */
626 sched->state.event++;
627 if (sched->state.event >= sched->max_events) {
628 /* next weight */
629 sched->state.event = 0;
630 sched->state.weight++;
631 if (sched->state.weight > sched->max_weight)
632 return false;
633 }
634 c = sched->constraints[sched->state.event];
635 } while (c->weight != sched->state.weight);
636
637 sched->state.counter = 0; /* start with first counter */
638
639 return true;
640}
641
642/*
643 * Assign a counter for each event.
644 */
645static int perf_assign_events(struct event_constraint **constraints, int n,
646 int wmin, int wmax, int *assign)
647{
648 struct perf_sched sched;
649
650 perf_sched_init(&sched, constraints, n, wmin, wmax);
651
652 do {
653 if (!perf_sched_find_counter(&sched))
654 break; /* failed */
655 if (assign)
656 assign[sched.state.event] = sched.state.counter;
657 } while (perf_sched_next_event(&sched));
658
659 return sched.state.unassigned;
660}
661
487int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) 662int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
488{ 663{
489 struct event_constraint *c, *constraints[X86_PMC_IDX_MAX]; 664 struct event_constraint *c, *constraints[X86_PMC_IDX_MAX];
490 unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; 665 unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
491 int i, j, w, wmax, num = 0; 666 int i, wmin, wmax, num = 0;
492 struct hw_perf_event *hwc; 667 struct hw_perf_event *hwc;
493 668
494 bitmap_zero(used_mask, X86_PMC_IDX_MAX); 669 bitmap_zero(used_mask, X86_PMC_IDX_MAX);
495 670
496 for (i = 0; i < n; i++) { 671 for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) {
497 c = x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]); 672 c = x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]);
498 constraints[i] = c; 673 constraints[i] = c;
674 wmin = min(wmin, c->weight);
675 wmax = max(wmax, c->weight);
499 } 676 }
500 677
501 /* 678 /*
@@ -521,59 +698,11 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
521 if (assign) 698 if (assign)
522 assign[i] = hwc->idx; 699 assign[i] = hwc->idx;
523 } 700 }
524 if (i == n)
525 goto done;
526
527 /*
528 * begin slow path
529 */
530
531 bitmap_zero(used_mask, X86_PMC_IDX_MAX);
532
533 /*
534 * weight = number of possible counters
535 *
536 * 1 = most constrained, only works on one counter
537 * wmax = least constrained, works on any counter
538 *
539 * assign events to counters starting with most
540 * constrained events.
541 */
542 wmax = x86_pmu.num_counters;
543
544 /*
545 * when fixed event counters are present,
546 * wmax is incremented by 1 to account
547 * for one more choice
548 */
549 if (x86_pmu.num_counters_fixed)
550 wmax++;
551
552 for (w = 1, num = n; num && w <= wmax; w++) {
553 /* for each event */
554 for (i = 0; num && i < n; i++) {
555 c = constraints[i];
556 hwc = &cpuc->event_list[i]->hw;
557
558 if (c->weight != w)
559 continue;
560
561 for_each_set_bit(j, c->idxmsk, X86_PMC_IDX_MAX) {
562 if (!test_bit(j, used_mask))
563 break;
564 }
565
566 if (j == X86_PMC_IDX_MAX)
567 break;
568 701
569 __set_bit(j, used_mask); 702 /* slow path */
703 if (i != n)
704 num = perf_assign_events(constraints, n, wmin, wmax, assign);
570 705
571 if (assign)
572 assign[i] = j;
573 num--;
574 }
575 }
576done:
577 /* 706 /*
578 * scheduling failed or is just a simulation, 707 * scheduling failed or is just a simulation,
579 * free resources if necessary 708 * free resources if necessary
@@ -1119,6 +1248,7 @@ static void __init pmu_check_apic(void)
1119 1248
1120static int __init init_hw_perf_events(void) 1249static int __init init_hw_perf_events(void)
1121{ 1250{
1251 struct x86_pmu_quirk *quirk;
1122 struct event_constraint *c; 1252 struct event_constraint *c;
1123 int err; 1253 int err;
1124 1254
@@ -1147,8 +1277,8 @@ static int __init init_hw_perf_events(void)
1147 1277
1148 pr_cont("%s PMU driver.\n", x86_pmu.name); 1278 pr_cont("%s PMU driver.\n", x86_pmu.name);
1149 1279
1150 if (x86_pmu.quirks) 1280 for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
1151 x86_pmu.quirks(); 1281 quirk->func();
1152 1282
1153 if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) { 1283 if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) {
1154 WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!", 1284 WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!",
@@ -1171,7 +1301,7 @@ static int __init init_hw_perf_events(void)
1171 1301
1172 unconstrained = (struct event_constraint) 1302 unconstrained = (struct event_constraint)
1173 __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1, 1303 __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
1174 0, x86_pmu.num_counters); 1304 0, x86_pmu.num_counters, 0);
1175 1305
1176 if (x86_pmu.event_constraints) { 1306 if (x86_pmu.event_constraints) {
1177 for_each_event_constraint(c, x86_pmu.event_constraints) { 1307 for_each_event_constraint(c, x86_pmu.event_constraints) {
@@ -1566,3 +1696,15 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
1566 1696
1567 return misc; 1697 return misc;
1568} 1698}
1699
1700void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
1701{
1702 cap->version = x86_pmu.version;
1703 cap->num_counters_gp = x86_pmu.num_counters;
1704 cap->num_counters_fixed = x86_pmu.num_counters_fixed;
1705 cap->bit_width_gp = x86_pmu.cntval_bits;
1706 cap->bit_width_fixed = x86_pmu.cntval_bits;
1707 cap->events_mask = (unsigned int)x86_pmu.events_maskl;
1708 cap->events_mask_len = x86_pmu.events_mask_len;
1709}
1710EXPORT_SYMBOL_GPL(perf_get_x86_pmu_capability);
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index b9698d40ac4..8944062f46e 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -45,6 +45,7 @@ struct event_constraint {
45 u64 code; 45 u64 code;
46 u64 cmask; 46 u64 cmask;
47 int weight; 47 int weight;
48 int overlap;
48}; 49};
49 50
50struct amd_nb { 51struct amd_nb {
@@ -151,15 +152,40 @@ struct cpu_hw_events {
151 void *kfree_on_online; 152 void *kfree_on_online;
152}; 153};
153 154
154#define __EVENT_CONSTRAINT(c, n, m, w) {\ 155#define __EVENT_CONSTRAINT(c, n, m, w, o) {\
155 { .idxmsk64 = (n) }, \ 156 { .idxmsk64 = (n) }, \
156 .code = (c), \ 157 .code = (c), \
157 .cmask = (m), \ 158 .cmask = (m), \
158 .weight = (w), \ 159 .weight = (w), \
160 .overlap = (o), \
159} 161}
160 162
161#define EVENT_CONSTRAINT(c, n, m) \ 163#define EVENT_CONSTRAINT(c, n, m) \
162 __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n)) 164 __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0)
165
166/*
167 * The overlap flag marks event constraints with overlapping counter
168 * masks. This is the case if the counter mask of such an event is not
169 * a subset of any other counter mask of a constraint with an equal or
170 * higher weight, e.g.:
171 *
172 * c_overlaps = EVENT_CONSTRAINT_OVERLAP(0, 0x09, 0);
173 * c_another1 = EVENT_CONSTRAINT(0, 0x07, 0);
174 * c_another2 = EVENT_CONSTRAINT(0, 0x38, 0);
175 *
176 * The event scheduler may not select the correct counter in the first
177 * cycle because it needs to know which subsequent events will be
178 * scheduled. It may fail to schedule the events then. So we set the
179 * overlap flag for such constraints to give the scheduler a hint which
180 * events to select for counter rescheduling.
181 *
182 * Care must be taken as the rescheduling algorithm is O(n!) which
183 * will increase scheduling cycles for an over-commited system
184 * dramatically. The number of such EVENT_CONSTRAINT_OVERLAP() macros
185 * and its counter masks must be kept at a minimum.
186 */
187#define EVENT_CONSTRAINT_OVERLAP(c, n, m) \
188 __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 1)
163 189
164/* 190/*
165 * Constraint on the Event code. 191 * Constraint on the Event code.
@@ -235,6 +261,11 @@ union perf_capabilities {
235 u64 capabilities; 261 u64 capabilities;
236}; 262};
237 263
264struct x86_pmu_quirk {
265 struct x86_pmu_quirk *next;
266 void (*func)(void);
267};
268
238/* 269/*
239 * struct x86_pmu - generic x86 pmu 270 * struct x86_pmu - generic x86 pmu
240 */ 271 */
@@ -259,6 +290,11 @@ struct x86_pmu {
259 int num_counters_fixed; 290 int num_counters_fixed;
260 int cntval_bits; 291 int cntval_bits;
261 u64 cntval_mask; 292 u64 cntval_mask;
293 union {
294 unsigned long events_maskl;
295 unsigned long events_mask[BITS_TO_LONGS(ARCH_PERFMON_EVENTS_COUNT)];
296 };
297 int events_mask_len;
262 int apic; 298 int apic;
263 u64 max_period; 299 u64 max_period;
264 struct event_constraint * 300 struct event_constraint *
@@ -268,7 +304,7 @@ struct x86_pmu {
268 void (*put_event_constraints)(struct cpu_hw_events *cpuc, 304 void (*put_event_constraints)(struct cpu_hw_events *cpuc,
269 struct perf_event *event); 305 struct perf_event *event);
270 struct event_constraint *event_constraints; 306 struct event_constraint *event_constraints;
271 void (*quirks)(void); 307 struct x86_pmu_quirk *quirks;
272 int perfctr_second_write; 308 int perfctr_second_write;
273 309
274 int (*cpu_prepare)(int cpu); 310 int (*cpu_prepare)(int cpu);
@@ -309,6 +345,15 @@ struct x86_pmu {
309 struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr); 345 struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr);
310}; 346};
311 347
348#define x86_add_quirk(func_) \
349do { \
350 static struct x86_pmu_quirk __quirk __initdata = { \
351 .func = func_, \
352 }; \
353 __quirk.next = x86_pmu.quirks; \
354 x86_pmu.quirks = &__quirk; \
355} while (0)
356
312#define ERF_NO_HT_SHARING 1 357#define ERF_NO_HT_SHARING 1
313#define ERF_HAS_RSP_1 2 358#define ERF_HAS_RSP_1 2
314 359
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index aeefd45697a..0397b23be8e 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -492,7 +492,7 @@ static __initconst const struct x86_pmu amd_pmu = {
492static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0); 492static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0);
493static struct event_constraint amd_f15_PMC20 = EVENT_CONSTRAINT(0, 0x07, 0); 493static struct event_constraint amd_f15_PMC20 = EVENT_CONSTRAINT(0, 0x07, 0);
494static struct event_constraint amd_f15_PMC3 = EVENT_CONSTRAINT(0, 0x08, 0); 494static struct event_constraint amd_f15_PMC3 = EVENT_CONSTRAINT(0, 0x08, 0);
495static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT(0, 0x09, 0); 495static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT_OVERLAP(0, 0x09, 0);
496static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0); 496static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0);
497static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0); 497static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0);
498 498
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 8d601b18bf9..2c3bf53d030 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1519,7 +1519,7 @@ static __initconst const struct x86_pmu intel_pmu = {
1519 .guest_get_msrs = intel_guest_get_msrs, 1519 .guest_get_msrs = intel_guest_get_msrs,
1520}; 1520};
1521 1521
1522static void intel_clovertown_quirks(void) 1522static __init void intel_clovertown_quirk(void)
1523{ 1523{
1524 /* 1524 /*
1525 * PEBS is unreliable due to: 1525 * PEBS is unreliable due to:
@@ -1545,19 +1545,60 @@ static void intel_clovertown_quirks(void)
1545 x86_pmu.pebs_constraints = NULL; 1545 x86_pmu.pebs_constraints = NULL;
1546} 1546}
1547 1547
1548static void intel_sandybridge_quirks(void) 1548static __init void intel_sandybridge_quirk(void)
1549{ 1549{
1550 printk(KERN_WARNING "PEBS disabled due to CPU errata.\n"); 1550 printk(KERN_WARNING "PEBS disabled due to CPU errata.\n");
1551 x86_pmu.pebs = 0; 1551 x86_pmu.pebs = 0;
1552 x86_pmu.pebs_constraints = NULL; 1552 x86_pmu.pebs_constraints = NULL;
1553} 1553}
1554 1554
1555static const struct { int id; char *name; } intel_arch_events_map[] __initconst = {
1556 { PERF_COUNT_HW_CPU_CYCLES, "cpu cycles" },
1557 { PERF_COUNT_HW_INSTRUCTIONS, "instructions" },
1558 { PERF_COUNT_HW_BUS_CYCLES, "bus cycles" },
1559 { PERF_COUNT_HW_CACHE_REFERENCES, "cache references" },
1560 { PERF_COUNT_HW_CACHE_MISSES, "cache misses" },
1561 { PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branch instructions" },
1562 { PERF_COUNT_HW_BRANCH_MISSES, "branch misses" },
1563};
1564
1565static __init void intel_arch_events_quirk(void)
1566{
1567 int bit;
1568
1569 /* disable event that reported as not presend by cpuid */
1570 for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_arch_events_map)) {
1571 intel_perfmon_event_map[intel_arch_events_map[bit].id] = 0;
1572 printk(KERN_WARNING "CPUID marked event: \'%s\' unavailable\n",
1573 intel_arch_events_map[bit].name);
1574 }
1575}
1576
1577static __init void intel_nehalem_quirk(void)
1578{
1579 union cpuid10_ebx ebx;
1580
1581 ebx.full = x86_pmu.events_maskl;
1582 if (ebx.split.no_branch_misses_retired) {
1583 /*
1584 * Erratum AAJ80 detected, we work it around by using
1585 * the BR_MISP_EXEC.ANY event. This will over-count
1586 * branch-misses, but it's still much better than the
1587 * architectural event which is often completely bogus:
1588 */
1589 intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89;
1590 ebx.split.no_branch_misses_retired = 0;
1591 x86_pmu.events_maskl = ebx.full;
1592 printk(KERN_INFO "CPU erratum AAJ80 worked around\n");
1593 }
1594}
1595
1555__init int intel_pmu_init(void) 1596__init int intel_pmu_init(void)
1556{ 1597{
1557 union cpuid10_edx edx; 1598 union cpuid10_edx edx;
1558 union cpuid10_eax eax; 1599 union cpuid10_eax eax;
1600 union cpuid10_ebx ebx;
1559 unsigned int unused; 1601 unsigned int unused;
1560 unsigned int ebx;
1561 int version; 1602 int version;
1562 1603
1563 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { 1604 if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
@@ -1574,8 +1615,8 @@ __init int intel_pmu_init(void)
1574 * Check whether the Architectural PerfMon supports 1615 * Check whether the Architectural PerfMon supports
1575 * Branch Misses Retired hw_event or not. 1616 * Branch Misses Retired hw_event or not.
1576 */ 1617 */
1577 cpuid(10, &eax.full, &ebx, &unused, &edx.full); 1618 cpuid(10, &eax.full, &ebx.full, &unused, &edx.full);
1578 if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED) 1619 if (eax.split.mask_length < ARCH_PERFMON_EVENTS_COUNT)
1579 return -ENODEV; 1620 return -ENODEV;
1580 1621
1581 version = eax.split.version_id; 1622 version = eax.split.version_id;
@@ -1589,6 +1630,9 @@ __init int intel_pmu_init(void)
1589 x86_pmu.cntval_bits = eax.split.bit_width; 1630 x86_pmu.cntval_bits = eax.split.bit_width;
1590 x86_pmu.cntval_mask = (1ULL << eax.split.bit_width) - 1; 1631 x86_pmu.cntval_mask = (1ULL << eax.split.bit_width) - 1;
1591 1632
1633 x86_pmu.events_maskl = ebx.full;
1634 x86_pmu.events_mask_len = eax.split.mask_length;
1635
1592 /* 1636 /*
1593 * Quirk: v2 perfmon does not report fixed-purpose events, so 1637 * Quirk: v2 perfmon does not report fixed-purpose events, so
1594 * assume at least 3 events: 1638 * assume at least 3 events:
@@ -1608,6 +1652,8 @@ __init int intel_pmu_init(void)
1608 1652
1609 intel_ds_init(); 1653 intel_ds_init();
1610 1654
1655 x86_add_quirk(intel_arch_events_quirk); /* Install first, so it runs last */
1656
1611 /* 1657 /*
1612 * Install the hw-cache-events table: 1658 * Install the hw-cache-events table:
1613 */ 1659 */
@@ -1617,7 +1663,7 @@ __init int intel_pmu_init(void)
1617 break; 1663 break;
1618 1664
1619 case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ 1665 case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */
1620 x86_pmu.quirks = intel_clovertown_quirks; 1666 x86_add_quirk(intel_clovertown_quirk);
1621 case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ 1667 case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */
1622 case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ 1668 case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */
1623 case 29: /* six-core 45 nm xeon "Dunnington" */ 1669 case 29: /* six-core 45 nm xeon "Dunnington" */
@@ -1651,17 +1697,8 @@ __init int intel_pmu_init(void)
1651 /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ 1697 /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
1652 intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; 1698 intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1;
1653 1699
1654 if (ebx & 0x40) { 1700 x86_add_quirk(intel_nehalem_quirk);
1655 /*
1656 * Erratum AAJ80 detected, we work it around by using
1657 * the BR_MISP_EXEC.ANY event. This will over-count
1658 * branch-misses, but it's still much better than the
1659 * architectural event which is often completely bogus:
1660 */
1661 intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89;
1662 1701
1663 pr_cont("erratum AAJ80 worked around, ");
1664 }
1665 pr_cont("Nehalem events, "); 1702 pr_cont("Nehalem events, ");
1666 break; 1703 break;
1667 1704
@@ -1701,7 +1738,7 @@ __init int intel_pmu_init(void)
1701 break; 1738 break;
1702 1739
1703 case 42: /* SandyBridge */ 1740 case 42: /* SandyBridge */
1704 x86_pmu.quirks = intel_sandybridge_quirks; 1741 x86_add_quirk(intel_sandybridge_quirk);
1705 case 45: /* SandyBridge, "Romely-EP" */ 1742 case 45: /* SandyBridge, "Romely-EP" */
1706 memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, 1743 memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
1707 sizeof(hw_cache_event_ids)); 1744 sizeof(hw_cache_event_ids));
@@ -1738,5 +1775,6 @@ __init int intel_pmu_init(void)
1738 break; 1775 break;
1739 } 1776 }
1740 } 1777 }
1778
1741 return 0; 1779 return 0;
1742} 1780}
diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c
index ea9d5f2f13e..2889b3d4388 100644
--- a/arch/x86/kernel/jump_label.c
+++ b/arch/x86/kernel/jump_label.c
@@ -50,7 +50,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
50 put_online_cpus(); 50 put_online_cpus();
51} 51}
52 52
53void arch_jump_label_transform_static(struct jump_entry *entry, 53__init_or_module void arch_jump_label_transform_static(struct jump_entry *entry,
54 enum jump_label_type type) 54 enum jump_label_type type)
55{ 55{
56 __jump_label_transform(entry, type, text_poke_early); 56 __jump_label_transform(entry, type, text_poke_early);
diff --git a/arch/x86/lib/inat.c b/arch/x86/lib/inat.c
index 46fc4ee09fc..88ad5fbda6e 100644
--- a/arch/x86/lib/inat.c
+++ b/arch/x86/lib/inat.c
@@ -82,9 +82,16 @@ insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m,
82 const insn_attr_t *table; 82 const insn_attr_t *table;
83 if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) 83 if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX)
84 return 0; 84 return 0;
85 table = inat_avx_tables[vex_m][vex_p]; 85 /* At first, this checks the master table */
86 table = inat_avx_tables[vex_m][0];
86 if (!table) 87 if (!table)
87 return 0; 88 return 0;
89 if (!inat_is_group(table[opcode]) && vex_p) {
90 /* If this is not a group, get attribute directly */
91 table = inat_avx_tables[vex_m][vex_p];
92 if (!table)
93 return 0;
94 }
88 return table[opcode]; 95 return table[opcode];
89} 96}
90 97
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
index 374562ed670..5a1f9f3e3fb 100644
--- a/arch/x86/lib/insn.c
+++ b/arch/x86/lib/insn.c
@@ -202,7 +202,7 @@ void insn_get_opcode(struct insn *insn)
202 m = insn_vex_m_bits(insn); 202 m = insn_vex_m_bits(insn);
203 p = insn_vex_p_bits(insn); 203 p = insn_vex_p_bits(insn);
204 insn->attr = inat_get_avx_attribute(op, m, p); 204 insn->attr = inat_get_avx_attribute(op, m, p);
205 if (!inat_accept_vex(insn->attr)) 205 if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr))
206 insn->attr = 0; /* This instruction is bad */ 206 insn->attr = 0; /* This instruction is bad */
207 goto end; /* VEX has only 1 byte for opcode */ 207 goto end; /* VEX has only 1 byte for opcode */
208 } 208 }
@@ -249,6 +249,8 @@ void insn_get_modrm(struct insn *insn)
249 pfx = insn_last_prefix(insn); 249 pfx = insn_last_prefix(insn);
250 insn->attr = inat_get_group_attribute(mod, pfx, 250 insn->attr = inat_get_group_attribute(mod, pfx,
251 insn->attr); 251 insn->attr);
252 if (insn_is_avx(insn) && !inat_accept_vex(insn->attr))
253 insn->attr = 0; /* This is bad */
252 } 254 }
253 } 255 }
254 256
diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt
index a793da5e560..5b83c51c12e 100644
--- a/arch/x86/lib/x86-opcode-map.txt
+++ b/arch/x86/lib/x86-opcode-map.txt
@@ -1,5 +1,11 @@
1# x86 Opcode Maps 1# x86 Opcode Maps
2# 2#
3# This is (mostly) based on following documentations.
4# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2
5# (#325383-040US, October 2011)
6# - Intel(R) Advanced Vector Extensions Programming Reference
7# (#319433-011,JUNE 2011).
8#
3#<Opcode maps> 9#<Opcode maps>
4# Table: table-name 10# Table: table-name
5# Referrer: escaped-name 11# Referrer: escaped-name
@@ -15,10 +21,13 @@
15# EndTable 21# EndTable
16# 22#
17# AVX Superscripts 23# AVX Superscripts
18# (VEX): this opcode can accept VEX prefix. 24# (v): this opcode requires VEX prefix.
19# (oVEX): this opcode requires VEX prefix. 25# (v1): this opcode only supports 128bit VEX.
20# (o128): this opcode only supports 128bit VEX. 26#
21# (o256): this opcode only supports 256bit VEX. 27# Last Prefix Superscripts
28# - (66): the last prefix is 0x66
29# - (F3): the last prefix is 0xF3
30# - (F2): the last prefix is 0xF2
22# 31#
23 32
24Table: one byte opcode 33Table: one byte opcode
@@ -199,8 +208,8 @@ a0: MOV AL,Ob
199a1: MOV rAX,Ov 208a1: MOV rAX,Ov
200a2: MOV Ob,AL 209a2: MOV Ob,AL
201a3: MOV Ov,rAX 210a3: MOV Ov,rAX
202a4: MOVS/B Xb,Yb 211a4: MOVS/B Yb,Xb
203a5: MOVS/W/D/Q Xv,Yv 212a5: MOVS/W/D/Q Yv,Xv
204a6: CMPS/B Xb,Yb 213a6: CMPS/B Xb,Yb
205a7: CMPS/W/D Xv,Yv 214a7: CMPS/W/D Xv,Yv
206a8: TEST AL,Ib 215a8: TEST AL,Ib
@@ -233,8 +242,8 @@ c0: Grp2 Eb,Ib (1A)
233c1: Grp2 Ev,Ib (1A) 242c1: Grp2 Ev,Ib (1A)
234c2: RETN Iw (f64) 243c2: RETN Iw (f64)
235c3: RETN 244c3: RETN
236c4: LES Gz,Mp (i64) | 3bytes-VEX (Prefix) 245c4: LES Gz,Mp (i64) | VEX+2byte (Prefix)
237c5: LDS Gz,Mp (i64) | 2bytes-VEX (Prefix) 246c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix)
238c6: Grp11 Eb,Ib (1A) 247c6: Grp11 Eb,Ib (1A)
239c7: Grp11 Ev,Iz (1A) 248c7: Grp11 Ev,Iz (1A)
240c8: ENTER Iw,Ib 249c8: ENTER Iw,Ib
@@ -320,14 +329,19 @@ AVXcode: 1
320# 3DNow! uses the last imm byte as opcode extension. 329# 3DNow! uses the last imm byte as opcode extension.
3210f: 3DNow! Pq,Qq,Ib 3300f: 3DNow! Pq,Qq,Ib
322# 0x0f 0x10-0x1f 331# 0x0f 0x10-0x1f
32310: movups Vps,Wps (VEX) | movss Vss,Wss (F3),(VEX),(o128) | movupd Vpd,Wpd (66),(VEX) | movsd Vsd,Wsd (F2),(VEX),(o128) 332# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands
32411: movups Wps,Vps (VEX) | movss Wss,Vss (F3),(VEX),(o128) | movupd Wpd,Vpd (66),(VEX) | movsd Wsd,Vsd (F2),(VEX),(o128) 333# but it actually has operands. And also, vmovss and vmovsd only accept 128bit.
32512: 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) 334# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form.
32613: mpvlps Mq,Vq (VEX),(o128) | movlpd Mq,Vq (66),(VEX),(o128) 335# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming
32714: unpcklps Vps,Wq (VEX) | unpcklpd Vpd,Wq (66),(VEX) 336# Reference A.1
32815: unpckhps Vps,Wq (VEX) | unpckhpd Vpd,Wq (66),(VEX) 33710: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1)
32916: movhps Vq,Mq (VEX),(o128) | movhpd Vq,Mq (66),(VEX),(o128) | movlsps Vq,Uq (VEX),(o128) | movshdup Vq,Wq (F3),(VEX) 33811: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1)
33017: movhps Mq,Vq (VEX),(o128) | movhpd Mq,Vq (66),(VEX),(o128) 33912: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2)
34013: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1)
34114: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66)
34215: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66)
34316: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3)
34417: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1)
33118: Grp16 (1A) 34518: Grp16 (1A)
33219: 34619:
3331a: 3471a:
@@ -345,14 +359,14 @@ AVXcode: 1
34525: 35925:
34626: 36026:
34727: 36127:
34828: movaps Vps,Wps (VEX) | movapd Vpd,Wpd (66),(VEX) 36228: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66)
34929: movaps Wps,Vps (VEX) | movapd Wpd,Vpd (66),(VEX) 36329: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66)
3502a: cvtpi2ps Vps,Qpi | cvtsi2ss Vss,Ed/q (F3),(VEX),(o128) | cvtpi2pd Vpd,Qpi (66) | cvtsi2sd Vsd,Ed/q (F2),(VEX),(o128) 3642a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1)
3512b: movntps Mps,Vps (VEX) | movntpd Mpd,Vpd (66),(VEX) 3652b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66)
3522c: cvttps2pi Ppi,Wps | cvttss2si Gd/q,Wss (F3),(VEX),(o128) | cvttpd2pi Ppi,Wpd (66) | cvttsd2si Gd/q,Wsd (F2),(VEX),(o128) 3662c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1)
3532d: cvtps2pi Ppi,Wps | cvtss2si Gd/q,Wss (F3),(VEX),(o128) | cvtpd2pi Qpi,Wpd (66) | cvtsd2si Gd/q,Wsd (F2),(VEX),(o128) 3672d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1)
3542e: ucomiss Vss,Wss (VEX),(o128) | ucomisd Vsd,Wsd (66),(VEX),(o128) 3682e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1)
3552f: comiss Vss,Wss (VEX),(o128) | comisd Vsd,Wsd (66),(VEX),(o128) 3692f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1)
356# 0x0f 0x30-0x3f 370# 0x0f 0x30-0x3f
35730: WRMSR 37130: WRMSR
35831: RDTSC 37231: RDTSC
@@ -388,65 +402,66 @@ AVXcode: 1
3884e: CMOVLE/NG Gv,Ev 4024e: CMOVLE/NG Gv,Ev
3894f: CMOVNLE/G Gv,Ev 4034f: CMOVNLE/G Gv,Ev
390# 0x0f 0x50-0x5f 404# 0x0f 0x50-0x5f
39150: movmskps Gd/q,Ups (VEX) | movmskpd Gd/q,Upd (66),(VEX) 40550: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66)
39251: sqrtps Vps,Wps (VEX) | sqrtss Vss,Wss (F3),(VEX),(o128) | sqrtpd Vpd,Wpd (66),(VEX) | sqrtsd Vsd,Wsd (F2),(VEX),(o128) 40651: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1)
39352: rsqrtps Vps,Wps (VEX) | rsqrtss Vss,Wss (F3),(VEX),(o128) 40752: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1)
39453: rcpps Vps,Wps (VEX) | rcpss Vss,Wss (F3),(VEX),(o128) 40853: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1)
39554: andps Vps,Wps (VEX) | andpd Vpd,Wpd (66),(VEX) 40954: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66)
39655: andnps Vps,Wps (VEX) | andnpd Vpd,Wpd (66),(VEX) 41055: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66)
39756: orps Vps,Wps (VEX) | orpd Vpd,Wpd (66),(VEX) 41156: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66)
39857: xorps Vps,Wps (VEX) | xorpd Vpd,Wpd (66),(VEX) 41257: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66)
39958: addps Vps,Wps (VEX) | addss Vss,Wss (F3),(VEX),(o128) | addpd Vpd,Wpd (66),(VEX) | addsd Vsd,Wsd (F2),(VEX),(o128) 41358: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1)
40059: mulps Vps,Wps (VEX) | mulss Vss,Wss (F3),(VEX),(o128) | mulpd Vpd,Wpd (66),(VEX) | mulsd Vsd,Wsd (F2),(VEX),(o128) 41459: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1)
4015a: cvtps2pd Vpd,Wps (VEX) | cvtss2sd Vsd,Wss (F3),(VEX),(o128) | cvtpd2ps Vps,Wpd (66),(VEX) | cvtsd2ss Vsd,Wsd (F2),(VEX),(o128) 4155a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1)
4025b: cvtdq2ps Vps,Wdq (VEX) | cvtps2dq Vdq,Wps (66),(VEX) | cvttps2dq Vdq,Wps (F3),(VEX) 4165b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3)
4035c: subps Vps,Wps (VEX) | subss Vss,Wss (F3),(VEX),(o128) | subpd Vpd,Wpd (66),(VEX) | subsd Vsd,Wsd (F2),(VEX),(o128) 4175c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1)
4045d: minps Vps,Wps (VEX) | minss Vss,Wss (F3),(VEX),(o128) | minpd Vpd,Wpd (66),(VEX) | minsd Vsd,Wsd (F2),(VEX),(o128) 4185d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1)
4055e: divps Vps,Wps (VEX) | divss Vss,Wss (F3),(VEX),(o128) | divpd Vpd,Wpd (66),(VEX) | divsd Vsd,Wsd (F2),(VEX),(o128) 4195e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1)
4065f: maxps Vps,Wps (VEX) | maxss Vss,Wss (F3),(VEX),(o128) | maxpd Vpd,Wpd (66),(VEX) | maxsd Vsd,Wsd (F2),(VEX),(o128) 4205f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1)
407# 0x0f 0x60-0x6f 421# 0x0f 0x60-0x6f
40860: punpcklbw Pq,Qd | punpcklbw Vdq,Wdq (66),(VEX),(o128) 42260: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1)
40961: punpcklwd Pq,Qd | punpcklwd Vdq,Wdq (66),(VEX),(o128) 42361: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1)
41062: punpckldq Pq,Qd | punpckldq Vdq,Wdq (66),(VEX),(o128) 42462: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1)
41163: packsswb Pq,Qq | packsswb Vdq,Wdq (66),(VEX),(o128) 42563: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1)
41264: pcmpgtb Pq,Qq | pcmpgtb Vdq,Wdq (66),(VEX),(o128) 42664: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1)
41365: pcmpgtw Pq,Qq | pcmpgtw Vdq,Wdq (66),(VEX),(o128) 42765: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1)
41466: pcmpgtd Pq,Qq | pcmpgtd Vdq,Wdq (66),(VEX),(o128) 42866: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1)
41567: packuswb Pq,Qq | packuswb Vdq,Wdq (66),(VEX),(o128) 42967: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1)
41668: punpckhbw Pq,Qd | punpckhbw Vdq,Wdq (66),(VEX),(o128) 43068: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1)
41769: punpckhwd Pq,Qd | punpckhwd Vdq,Wdq (66),(VEX),(o128) 43169: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1)
4186a: punpckhdq Pq,Qd | punpckhdq Vdq,Wdq (66),(VEX),(o128) 4326a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1)
4196b: packssdw Pq,Qd | packssdw Vdq,Wdq (66),(VEX),(o128) 4336b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1)
4206c: punpcklqdq Vdq,Wdq (66),(VEX),(o128) 4346c: vpunpcklqdq Vx,Hx,Wx (66),(v1)
4216d: punpckhqdq Vdq,Wdq (66),(VEX),(o128) 4356d: vpunpckhqdq Vx,Hx,Wx (66),(v1)
4226e: movd/q/ Pd,Ed/q | movd/q Vdq,Ed/q (66),(VEX),(o128) 4366e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1)
4236f: movq Pq,Qq | movdqa Vdq,Wdq (66),(VEX) | movdqu Vdq,Wdq (F3),(VEX) 4376f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3)
424# 0x0f 0x70-0x7f 438# 0x0f 0x70-0x7f
42570: pshufw Pq,Qq,Ib | pshufd Vdq,Wdq,Ib (66),(VEX),(o128) | pshufhw Vdq,Wdq,Ib (F3),(VEX),(o128) | pshuflw VdqWdq,Ib (F2),(VEX),(o128) 43970: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1)
42671: Grp12 (1A) 44071: Grp12 (1A)
42772: Grp13 (1A) 44172: Grp13 (1A)
42873: Grp14 (1A) 44273: Grp14 (1A)
42974: pcmpeqb Pq,Qq | pcmpeqb Vdq,Wdq (66),(VEX),(o128) 44374: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1)
43075: pcmpeqw Pq,Qq | pcmpeqw Vdq,Wdq (66),(VEX),(o128) 44475: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1)
43176: pcmpeqd Pq,Qq | pcmpeqd Vdq,Wdq (66),(VEX),(o128) 44576: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1)
43277: emms/vzeroupper/vzeroall (VEX) 446# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX.
43378: VMREAD Ed/q,Gd/q 44777: emms | vzeroupper | vzeroall
43479: VMWRITE Gd/q,Ed/q 44878: VMREAD Ey,Gy
44979: VMWRITE Gy,Ey
4357a: 4507a:
4367b: 4517b:
4377c: haddps Vps,Wps (F2),(VEX) | haddpd Vpd,Wpd (66),(VEX) 4527c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2)
4387d: hsubps Vps,Wps (F2),(VEX) | hsubpd Vpd,Wpd (66),(VEX) 4537d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2)
4397e: movd/q Ed/q,Pd | movd/q Ed/q,Vdq (66),(VEX),(o128) | movq Vq,Wq (F3),(VEX),(o128) 4547e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1)
4407f: movq Qq,Pq | movdqa Wdq,Vdq (66),(VEX) | movdqu Wdq,Vdq (F3),(VEX) 4557f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3)
441# 0x0f 0x80-0x8f 456# 0x0f 0x80-0x8f
44280: JO Jz (f64) 45780: JO Jz (f64)
44381: JNO Jz (f64) 45881: JNO Jz (f64)
44482: JB/JNAE/JC Jz (f64) 45982: JB/JC/JNAE Jz (f64)
44583: JNB/JAE/JNC Jz (f64) 46083: JAE/JNB/JNC Jz (f64)
44684: JZ/JE Jz (f64) 46184: JE/JZ Jz (f64)
44785: JNZ/JNE Jz (f64) 46285: JNE/JNZ Jz (f64)
44886: JBE/JNA Jz (f64) 46386: JBE/JNA Jz (f64)
44987: JNBE/JA Jz (f64) 46487: JA/JNBE Jz (f64)
45088: JS Jz (f64) 46588: JS Jz (f64)
45189: JNS Jz (f64) 46689: JNS Jz (f64)
4528a: JP/JPE Jz (f64) 4678a: JP/JPE Jz (f64)
@@ -502,18 +517,18 @@ b8: JMPE | POPCNT Gv,Ev (F3)
502b9: Grp10 (1A) 517b9: Grp10 (1A)
503ba: Grp8 Ev,Ib (1A) 518ba: Grp8 Ev,Ib (1A)
504bb: BTC Ev,Gv 519bb: BTC Ev,Gv
505bc: BSF Gv,Ev 520bc: BSF Gv,Ev | TZCNT Gv,Ev (F3)
506bd: BSR Gv,Ev 521bd: BSR Gv,Ev | LZCNT Gv,Ev (F3)
507be: MOVSX Gv,Eb 522be: MOVSX Gv,Eb
508bf: MOVSX Gv,Ew 523bf: MOVSX Gv,Ew
509# 0x0f 0xc0-0xcf 524# 0x0f 0xc0-0xcf
510c0: XADD Eb,Gb 525c0: XADD Eb,Gb
511c1: XADD Ev,Gv 526c1: XADD Ev,Gv
512c2: cmpps Vps,Wps,Ib (VEX) | cmpss Vss,Wss,Ib (F3),(VEX),(o128) | cmppd Vpd,Wpd,Ib (66),(VEX) | cmpsd Vsd,Wsd,Ib (F2),(VEX) 527c2: 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)
513c3: movnti Md/q,Gd/q 528c3: movnti My,Gy
514c4: pinsrw Pq,Rd/q/Mw,Ib | pinsrw Vdq,Rd/q/Mw,Ib (66),(VEX),(o128) 529c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1)
515c5: pextrw Gd,Nq,Ib | pextrw Gd,Udq,Ib (66),(VEX),(o128) 530c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1)
516c6: shufps Vps,Wps,Ib (VEX) | shufpd Vpd,Wpd,Ib (66),(VEX) 531c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66)
517c7: Grp9 (1A) 532c7: Grp9 (1A)
518c8: BSWAP RAX/EAX/R8/R8D 533c8: BSWAP RAX/EAX/R8/R8D
519c9: BSWAP RCX/ECX/R9/R9D 534c9: BSWAP RCX/ECX/R9/R9D
@@ -524,55 +539,55 @@ cd: BSWAP RBP/EBP/R13/R13D
524ce: BSWAP RSI/ESI/R14/R14D 539ce: BSWAP RSI/ESI/R14/R14D
525cf: BSWAP RDI/EDI/R15/R15D 540cf: BSWAP RDI/EDI/R15/R15D
526# 0x0f 0xd0-0xdf 541# 0x0f 0xd0-0xdf
527d0: addsubps Vps,Wps (F2),(VEX) | addsubpd Vpd,Wpd (66),(VEX) 542d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2)
528d1: psrlw Pq,Qq | psrlw Vdq,Wdq (66),(VEX),(o128) 543d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1)
529d2: psrld Pq,Qq | psrld Vdq,Wdq (66),(VEX),(o128) 544d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1)
530d3: psrlq Pq,Qq | psrlq Vdq,Wdq (66),(VEX),(o128) 545d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1)
531d4: paddq Pq,Qq | paddq Vdq,Wdq (66),(VEX),(o128) 546d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1)
532d5: pmullw Pq,Qq | pmullw Vdq,Wdq (66),(VEX),(o128) 547d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1)
533d6: movq Wq,Vq (66),(VEX),(o128) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) 548d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
534d7: pmovmskb Gd,Nq | pmovmskb Gd,Udq (66),(VEX),(o128) 549d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1)
535d8: psubusb Pq,Qq | psubusb Vdq,Wdq (66),(VEX),(o128) 550d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1)
536d9: psubusw Pq,Qq | psubusw Vdq,Wdq (66),(VEX),(o128) 551d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1)
537da: pminub Pq,Qq | pminub Vdq,Wdq (66),(VEX),(o128) 552da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1)
538db: pand Pq,Qq | pand Vdq,Wdq (66),(VEX),(o128) 553db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1)
539dc: paddusb Pq,Qq | paddusb Vdq,Wdq (66),(VEX),(o128) 554dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1)
540dd: paddusw Pq,Qq | paddusw Vdq,Wdq (66),(VEX),(o128) 555dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1)
541de: pmaxub Pq,Qq | pmaxub Vdq,Wdq (66),(VEX),(o128) 556de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1)
542df: pandn Pq,Qq | pandn Vdq,Wdq (66),(VEX),(o128) 557df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1)
543# 0x0f 0xe0-0xef 558# 0x0f 0xe0-0xef
544e0: pavgb Pq,Qq | pavgb Vdq,Wdq (66),(VEX),(o128) 559e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1)
545e1: psraw Pq,Qq | psraw Vdq,Wdq (66),(VEX),(o128) 560e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1)
546e2: psrad Pq,Qq | psrad Vdq,Wdq (66),(VEX),(o128) 561e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1)
547e3: pavgw Pq,Qq | pavgw Vdq,Wdq (66),(VEX),(o128) 562e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1)
548e4: pmulhuw Pq,Qq | pmulhuw Vdq,Wdq (66),(VEX),(o128) 563e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1)
549e5: pmulhw Pq,Qq | pmulhw Vdq,Wdq (66),(VEX),(o128) 564e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1)
550e6: cvtpd2dq Vdq,Wpd (F2),(VEX) | cvttpd2dq Vdq,Wpd (66),(VEX) | cvtdq2pd Vpd,Wdq (F3),(VEX) 565e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2)
551e7: movntq Mq,Pq | movntdq Mdq,Vdq (66),(VEX) 566e7: movntq Mq,Pq | vmovntdq Mx,Vx (66)
552e8: psubsb Pq,Qq | psubsb Vdq,Wdq (66),(VEX),(o128) 567e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1)
553e9: psubsw Pq,Qq | psubsw Vdq,Wdq (66),(VEX),(o128) 568e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1)
554ea: pminsw Pq,Qq | pminsw Vdq,Wdq (66),(VEX),(o128) 569ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1)
555eb: por Pq,Qq | por Vdq,Wdq (66),(VEX),(o128) 570eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1)
556ec: paddsb Pq,Qq | paddsb Vdq,Wdq (66),(VEX),(o128) 571ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1)
557ed: paddsw Pq,Qq | paddsw Vdq,Wdq (66),(VEX),(o128) 572ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1)
558ee: pmaxsw Pq,Qq | pmaxsw Vdq,Wdq (66),(VEX),(o128) 573ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1)
559ef: pxor Pq,Qq | pxor Vdq,Wdq (66),(VEX),(o128) 574ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1)
560# 0x0f 0xf0-0xff 575# 0x0f 0xf0-0xff
561f0: lddqu Vdq,Mdq (F2),(VEX) 576f0: vlddqu Vx,Mx (F2)
562f1: psllw Pq,Qq | psllw Vdq,Wdq (66),(VEX),(o128) 577f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1)
563f2: pslld Pq,Qq | pslld Vdq,Wdq (66),(VEX),(o128) 578f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1)
564f3: psllq Pq,Qq | psllq Vdq,Wdq (66),(VEX),(o128) 579f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1)
565f4: pmuludq Pq,Qq | pmuludq Vdq,Wdq (66),(VEX),(o128) 580f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1)
566f5: pmaddwd Pq,Qq | pmaddwd Vdq,Wdq (66),(VEX),(o128) 581f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1)
567f6: psadbw Pq,Qq | psadbw Vdq,Wdq (66),(VEX),(o128) 582f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1)
568f7: maskmovq Pq,Nq | maskmovdqu Vdq,Udq (66),(VEX),(o128) 583f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1)
569f8: psubb Pq,Qq | psubb Vdq,Wdq (66),(VEX),(o128) 584f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1)
570f9: psubw Pq,Qq | psubw Vdq,Wdq (66),(VEX),(o128) 585f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1)
571fa: psubd Pq,Qq | psubd Vdq,Wdq (66),(VEX),(o128) 586fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1)
572fb: psubq Pq,Qq | psubq Vdq,Wdq (66),(VEX),(o128) 587fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1)
573fc: paddb Pq,Qq | paddb Vdq,Wdq (66),(VEX),(o128) 588fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1)
574fd: paddw Pq,Qq | paddw Vdq,Wdq (66),(VEX),(o128) 589fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1)
575fe: paddd Pq,Qq | paddd Vdq,Wdq (66),(VEX),(o128) 590fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1)
576ff: 591ff:
577EndTable 592EndTable
578 593
@@ -580,155 +595,193 @@ Table: 3-byte opcode 1 (0x0f 0x38)
580Referrer: 3-byte escape 1 595Referrer: 3-byte escape 1
581AVXcode: 2 596AVXcode: 2
582# 0x0f 0x38 0x00-0x0f 597# 0x0f 0x38 0x00-0x0f
58300: pshufb Pq,Qq | pshufb Vdq,Wdq (66),(VEX),(o128) 59800: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1)
58401: phaddw Pq,Qq | phaddw Vdq,Wdq (66),(VEX),(o128) 59901: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1)
58502: phaddd Pq,Qq | phaddd Vdq,Wdq (66),(VEX),(o128) 60002: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1)
58603: phaddsw Pq,Qq | phaddsw Vdq,Wdq (66),(VEX),(o128) 60103: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1)
58704: pmaddubsw Pq,Qq | pmaddubsw Vdq,Wdq (66),(VEX),(o128) 60204: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1)
58805: phsubw Pq,Qq | phsubw Vdq,Wdq (66),(VEX),(o128) 60305: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1)
58906: phsubd Pq,Qq | phsubd Vdq,Wdq (66),(VEX),(o128) 60406: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1)
59007: phsubsw Pq,Qq | phsubsw Vdq,Wdq (66),(VEX),(o128) 60507: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1)
59108: psignb Pq,Qq | psignb Vdq,Wdq (66),(VEX),(o128) 60608: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1)
59209: psignw Pq,Qq | psignw Vdq,Wdq (66),(VEX),(o128) 60709: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1)
5930a: psignd Pq,Qq | psignd Vdq,Wdq (66),(VEX),(o128) 6080a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1)
5940b: pmulhrsw Pq,Qq | pmulhrsw Vdq,Wdq (66),(VEX),(o128) 6090b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1)
5950c: Vpermilps /r (66),(oVEX) 6100c: vpermilps Vx,Hx,Wx (66),(v)
5960d: Vpermilpd /r (66),(oVEX) 6110d: vpermilpd Vx,Hx,Wx (66),(v)
5970e: vtestps /r (66),(oVEX) 6120e: vtestps Vx,Wx (66),(v)
5980f: vtestpd /r (66),(oVEX) 6130f: vtestpd Vx,Wx (66),(v)
599# 0x0f 0x38 0x10-0x1f 614# 0x0f 0x38 0x10-0x1f
60010: pblendvb Vdq,Wdq (66) 61510: pblendvb Vdq,Wdq (66)
60111: 61611:
60212: 61712:
60313: 61813: vcvtph2ps Vx,Wx,Ib (66),(v)
60414: blendvps Vdq,Wdq (66) 61914: blendvps Vdq,Wdq (66)
60515: blendvpd Vdq,Wdq (66) 62015: blendvpd Vdq,Wdq (66)
60616: 62116: vpermps Vqq,Hqq,Wqq (66),(v)
60717: ptest Vdq,Wdq (66),(VEX) 62217: vptest Vx,Wx (66)
60818: vbroadcastss /r (66),(oVEX) 62318: vbroadcastss Vx,Wd (66),(v)
60919: vbroadcastsd /r (66),(oVEX),(o256) 62419: vbroadcastsd Vqq,Wq (66),(v)
6101a: vbroadcastf128 /r (66),(oVEX),(o256) 6251a: vbroadcastf128 Vqq,Mdq (66),(v)
6111b: 6261b:
6121c: pabsb Pq,Qq | pabsb Vdq,Wdq (66),(VEX),(o128) 6271c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1)
6131d: pabsw Pq,Qq | pabsw Vdq,Wdq (66),(VEX),(o128) 6281d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1)
6141e: pabsd Pq,Qq | pabsd Vdq,Wdq (66),(VEX),(o128) 6291e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1)
6151f: 6301f:
616# 0x0f 0x38 0x20-0x2f 631# 0x0f 0x38 0x20-0x2f
61720: pmovsxbw Vdq,Udq/Mq (66),(VEX),(o128) 63220: vpmovsxbw Vx,Ux/Mq (66),(v1)
61821: pmovsxbd Vdq,Udq/Md (66),(VEX),(o128) 63321: vpmovsxbd Vx,Ux/Md (66),(v1)
61922: pmovsxbq Vdq,Udq/Mw (66),(VEX),(o128) 63422: vpmovsxbq Vx,Ux/Mw (66),(v1)
62023: pmovsxwd Vdq,Udq/Mq (66),(VEX),(o128) 63523: vpmovsxwd Vx,Ux/Mq (66),(v1)
62124: pmovsxwq Vdq,Udq/Md (66),(VEX),(o128) 63624: vpmovsxwq Vx,Ux/Md (66),(v1)
62225: pmovsxdq Vdq,Udq/Mq (66),(VEX),(o128) 63725: vpmovsxdq Vx,Ux/Mq (66),(v1)
62326: 63826:
62427: 63927:
62528: pmuldq Vdq,Wdq (66),(VEX),(o128) 64028: vpmuldq Vx,Hx,Wx (66),(v1)
62629: pcmpeqq Vdq,Wdq (66),(VEX),(o128) 64129: vpcmpeqq Vx,Hx,Wx (66),(v1)
6272a: movntdqa Vdq,Mdq (66),(VEX),(o128) 6422a: vmovntdqa Vx,Mx (66),(v1)
6282b: packusdw Vdq,Wdq (66),(VEX),(o128) 6432b: vpackusdw Vx,Hx,Wx (66),(v1)
6292c: vmaskmovps(ld) /r (66),(oVEX) 6442c: vmaskmovps Vx,Hx,Mx (66),(v)
6302d: vmaskmovpd(ld) /r (66),(oVEX) 6452d: vmaskmovpd Vx,Hx,Mx (66),(v)
6312e: vmaskmovps(st) /r (66),(oVEX) 6462e: vmaskmovps Mx,Hx,Vx (66),(v)
6322f: vmaskmovpd(st) /r (66),(oVEX) 6472f: vmaskmovpd Mx,Hx,Vx (66),(v)
633# 0x0f 0x38 0x30-0x3f 648# 0x0f 0x38 0x30-0x3f
63430: pmovzxbw Vdq,Udq/Mq (66),(VEX),(o128) 64930: vpmovzxbw Vx,Ux/Mq (66),(v1)
63531: pmovzxbd Vdq,Udq/Md (66),(VEX),(o128) 65031: vpmovzxbd Vx,Ux/Md (66),(v1)
63632: pmovzxbq Vdq,Udq/Mw (66),(VEX),(o128) 65132: vpmovzxbq Vx,Ux/Mw (66),(v1)
63733: pmovzxwd Vdq,Udq/Mq (66),(VEX),(o128) 65233: vpmovzxwd Vx,Ux/Mq (66),(v1)
63834: pmovzxwq Vdq,Udq/Md (66),(VEX),(o128) 65334: vpmovzxwq Vx,Ux/Md (66),(v1)
63935: pmovzxdq Vdq,Udq/Mq (66),(VEX),(o128) 65435: vpmovzxdq Vx,Ux/Mq (66),(v1)
64036: 65536: vpermd Vqq,Hqq,Wqq (66),(v)
64137: pcmpgtq Vdq,Wdq (66),(VEX),(o128) 65637: vpcmpgtq Vx,Hx,Wx (66),(v1)
64238: pminsb Vdq,Wdq (66),(VEX),(o128) 65738: vpminsb Vx,Hx,Wx (66),(v1)
64339: pminsd Vdq,Wdq (66),(VEX),(o128) 65839: vpminsd Vx,Hx,Wx (66),(v1)
6443a: pminuw Vdq,Wdq (66),(VEX),(o128) 6593a: vpminuw Vx,Hx,Wx (66),(v1)
6453b: pminud Vdq,Wdq (66),(VEX),(o128) 6603b: vpminud Vx,Hx,Wx (66),(v1)
6463c: pmaxsb Vdq,Wdq (66),(VEX),(o128) 6613c: vpmaxsb Vx,Hx,Wx (66),(v1)
6473d: pmaxsd Vdq,Wdq (66),(VEX),(o128) 6623d: vpmaxsd Vx,Hx,Wx (66),(v1)
6483e: pmaxuw Vdq,Wdq (66),(VEX),(o128) 6633e: vpmaxuw Vx,Hx,Wx (66),(v1)
6493f: pmaxud Vdq,Wdq (66),(VEX),(o128) 6643f: vpmaxud Vx,Hx,Wx (66),(v1)
650# 0x0f 0x38 0x40-0x8f 665# 0x0f 0x38 0x40-0x8f
65140: pmulld Vdq,Wdq (66),(VEX),(o128) 66640: vpmulld Vx,Hx,Wx (66),(v1)
65241: phminposuw Vdq,Wdq (66),(VEX),(o128) 66741: vphminposuw Vdq,Wdq (66),(v1)
65380: INVEPT Gd/q,Mdq (66) 66842:
65481: INVPID Gd/q,Mdq (66) 66943:
67044:
67145: vpsrlvd/q Vx,Hx,Wx (66),(v)
67246: vpsravd Vx,Hx,Wx (66),(v)
67347: vpsllvd/q Vx,Hx,Wx (66),(v)
674# Skip 0x48-0x57
67558: vpbroadcastd Vx,Wx (66),(v)
67659: vpbroadcastq Vx,Wx (66),(v)
6775a: vbroadcasti128 Vqq,Mdq (66),(v)
678# Skip 0x5b-0x77
67978: vpbroadcastb Vx,Wx (66),(v)
68079: vpbroadcastw Vx,Wx (66),(v)
681# Skip 0x7a-0x7f
68280: INVEPT Gy,Mdq (66)
68381: INVPID Gy,Mdq (66)
68482: INVPCID Gy,Mdq (66)
6858c: vpmaskmovd/q Vx,Hx,Mx (66),(v)
6868e: vpmaskmovd/q Mx,Vx,Hx (66),(v)
655# 0x0f 0x38 0x90-0xbf (FMA) 687# 0x0f 0x38 0x90-0xbf (FMA)
65696: vfmaddsub132pd/ps /r (66),(VEX) 68890: vgatherdd/q Vx,Hx,Wx (66),(v)
65797: vfmsubadd132pd/ps /r (66),(VEX) 68991: vgatherqd/q Vx,Hx,Wx (66),(v)
65898: vfmadd132pd/ps /r (66),(VEX) 69092: vgatherdps/d Vx,Hx,Wx (66),(v)
65999: vfmadd132sd/ss /r (66),(VEX),(o128) 69193: vgatherqps/d Vx,Hx,Wx (66),(v)
6609a: vfmsub132pd/ps /r (66),(VEX) 69294:
6619b: vfmsub132sd/ss /r (66),(VEX),(o128) 69395:
6629c: vfnmadd132pd/ps /r (66),(VEX) 69496: vfmaddsub132ps/d Vx,Hx,Wx (66),(v)
6639d: vfnmadd132sd/ss /r (66),(VEX),(o128) 69597: vfmsubadd132ps/d Vx,Hx,Wx (66),(v)
6649e: vfnmsub132pd/ps /r (66),(VEX) 69698: vfmadd132ps/d Vx,Hx,Wx (66),(v)
6659f: vfnmsub132sd/ss /r (66),(VEX),(o128) 69799: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
666a6: vfmaddsub213pd/ps /r (66),(VEX) 6989a: vfmsub132ps/d Vx,Hx,Wx (66),(v)
667a7: vfmsubadd213pd/ps /r (66),(VEX) 6999b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
668a8: vfmadd213pd/ps /r (66),(VEX) 7009c: vfnmadd132ps/d Vx,Hx,Wx (66),(v)
669a9: vfmadd213sd/ss /r (66),(VEX),(o128) 7019d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
670aa: vfmsub213pd/ps /r (66),(VEX) 7029e: vfnmsub132ps/d Vx,Hx,Wx (66),(v)
671ab: vfmsub213sd/ss /r (66),(VEX),(o128) 7039f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
672ac: vfnmadd213pd/ps /r (66),(VEX) 704a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v)
673ad: vfnmadd213sd/ss /r (66),(VEX),(o128) 705a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v)
674ae: vfnmsub213pd/ps /r (66),(VEX) 706a8: vfmadd213ps/d Vx,Hx,Wx (66),(v)
675af: vfnmsub213sd/ss /r (66),(VEX),(o128) 707a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
676b6: vfmaddsub231pd/ps /r (66),(VEX) 708aa: vfmsub213ps/d Vx,Hx,Wx (66),(v)
677b7: vfmsubadd231pd/ps /r (66),(VEX) 709ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
678b8: vfmadd231pd/ps /r (66),(VEX) 710ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v)
679b9: vfmadd231sd/ss /r (66),(VEX),(o128) 711ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
680ba: vfmsub231pd/ps /r (66),(VEX) 712ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v)
681bb: vfmsub231sd/ss /r (66),(VEX),(o128) 713af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
682bc: vfnmadd231pd/ps /r (66),(VEX) 714b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v)
683bd: vfnmadd231sd/ss /r (66),(VEX),(o128) 715b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v)
684be: vfnmsub231pd/ps /r (66),(VEX) 716b8: vfmadd231ps/d Vx,Hx,Wx (66),(v)
685bf: vfnmsub231sd/ss /r (66),(VEX),(o128) 717b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
718ba: vfmsub231ps/d Vx,Hx,Wx (66),(v)
719bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
720bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v)
721bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
722be: vfnmsub231ps/d Vx,Hx,Wx (66),(v)
723bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
686# 0x0f 0x38 0xc0-0xff 724# 0x0f 0x38 0xc0-0xff
687db: aesimc Vdq,Wdq (66),(VEX),(o128) 725db: VAESIMC Vdq,Wdq (66),(v1)
688dc: aesenc Vdq,Wdq (66),(VEX),(o128) 726dc: VAESENC Vdq,Hdq,Wdq (66),(v1)
689dd: aesenclast Vdq,Wdq (66),(VEX),(o128) 727dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
690de: aesdec Vdq,Wdq (66),(VEX),(o128) 728de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
691df: aesdeclast Vdq,Wdq (66),(VEX),(o128) 729df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
692f0: MOVBE Gv,Mv | CRC32 Gd,Eb (F2) 730f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2)
693f1: MOVBE Mv,Gv | CRC32 Gd,Ev (F2) 731f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2)
732f3: ANDN Gy,By,Ey (v)
733f4: Grp17 (1A)
734f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
735f6: MULX By,Gy,rDX,Ey (F2),(v)
736f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
694EndTable 737EndTable
695 738
696Table: 3-byte opcode 2 (0x0f 0x3a) 739Table: 3-byte opcode 2 (0x0f 0x3a)
697Referrer: 3-byte escape 2 740Referrer: 3-byte escape 2
698AVXcode: 3 741AVXcode: 3
699# 0x0f 0x3a 0x00-0xff 742# 0x0f 0x3a 0x00-0xff
70004: vpermilps /r,Ib (66),(oVEX) 74300: vpermq Vqq,Wqq,Ib (66),(v)
70105: vpermilpd /r,Ib (66),(oVEX) 74401: vpermpd Vqq,Wqq,Ib (66),(v)
70206: vperm2f128 /r,Ib (66),(oVEX),(o256) 74502: vpblendd Vx,Hx,Wx,Ib (66),(v)
70308: roundps Vdq,Wdq,Ib (66),(VEX) 74603:
70409: roundpd Vdq,Wdq,Ib (66),(VEX) 74704: vpermilps Vx,Wx,Ib (66),(v)
7050a: roundss Vss,Wss,Ib (66),(VEX),(o128) 74805: vpermilpd Vx,Wx,Ib (66),(v)
7060b: roundsd Vsd,Wsd,Ib (66),(VEX),(o128) 74906: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v)
7070c: blendps Vdq,Wdq,Ib (66),(VEX) 75007:
7080d: blendpd Vdq,Wdq,Ib (66),(VEX) 75108: vroundps Vx,Wx,Ib (66)
7090e: pblendw Vdq,Wdq,Ib (66),(VEX),(o128) 75209: vroundpd Vx,Wx,Ib (66)
7100f: palignr Pq,Qq,Ib | palignr Vdq,Wdq,Ib (66),(VEX),(o128) 7530a: vroundss Vss,Wss,Ib (66),(v1)
71114: pextrb Rd/Mb,Vdq,Ib (66),(VEX),(o128) 7540b: vroundsd Vsd,Wsd,Ib (66),(v1)
71215: pextrw Rd/Mw,Vdq,Ib (66),(VEX),(o128) 7550c: vblendps Vx,Hx,Wx,Ib (66)
71316: pextrd/pextrq Ed/q,Vdq,Ib (66),(VEX),(o128) 7560d: vblendpd Vx,Hx,Wx,Ib (66)
71417: extractps Ed,Vdq,Ib (66),(VEX),(o128) 7570e: vpblendw Vx,Hx,Wx,Ib (66),(v1)
71518: vinsertf128 /r,Ib (66),(oVEX),(o256) 7580f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1)
71619: vextractf128 /r,Ib (66),(oVEX),(o256) 75914: vpextrb Rd/Mb,Vdq,Ib (66),(v1)
71720: pinsrb Vdq,Rd/q/Mb,Ib (66),(VEX),(o128) 76015: vpextrw Rd/Mw,Vdq,Ib (66),(v1)
71821: insertps Vdq,Udq/Md,Ib (66),(VEX),(o128) 76116: vpextrd/q Ey,Vdq,Ib (66),(v1)
71922: pinsrd/pinsrq Vdq,Ed/q,Ib (66),(VEX),(o128) 76217: vextractps Ed,Vdq,Ib (66),(v1)
72040: dpps Vdq,Wdq,Ib (66),(VEX) 76318: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v)
72141: dppd Vdq,Wdq,Ib (66),(VEX),(o128) 76419: vextractf128 Wdq,Vqq,Ib (66),(v)
72242: mpsadbw Vdq,Wdq,Ib (66),(VEX),(o128) 7651d: vcvtps2ph Wx,Vx,Ib (66),(v)
72344: pclmulq Vdq,Wdq,Ib (66),(VEX),(o128) 76620: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1)
7244a: vblendvps /r,Ib (66),(oVEX) 76721: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1)
7254b: vblendvpd /r,Ib (66),(oVEX) 76822: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1)
7264c: vpblendvb /r,Ib (66),(oVEX),(o128) 76938: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v)
72760: pcmpestrm Vdq,Wdq,Ib (66),(VEX),(o128) 77039: vextracti128 Wdq,Vqq,Ib (66),(v)
72861: pcmpestri Vdq,Wdq,Ib (66),(VEX),(o128) 77140: vdpps Vx,Hx,Wx,Ib (66)
72962: pcmpistrm Vdq,Wdq,Ib (66),(VEX),(o128) 77241: vdppd Vdq,Hdq,Wdq,Ib (66),(v1)
73063: pcmpistri Vdq,Wdq,Ib (66),(VEX),(o128) 77342: vmpsadbw Vx,Hx,Wx,Ib (66),(v1)
731df: aeskeygenassist Vdq,Wdq,Ib (66),(VEX),(o128) 77444: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1)
77546: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v)
7764a: vblendvps Vx,Hx,Wx,Lx (66),(v)
7774b: vblendvpd Vx,Hx,Wx,Lx (66),(v)
7784c: vpblendvb Vx,Hx,Wx,Lx (66),(v1)
77960: vpcmpestrm Vdq,Wdq,Ib (66),(v1)
78061: vpcmpestri Vdq,Wdq,Ib (66),(v1)
78162: vpcmpistrm Vdq,Wdq,Ib (66),(v1)
78263: vpcmpistri Vdq,Wdq,Ib (66),(v1)
783df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1)
784f0: RORX Gy,Ey,Ib (F2),(v)
732EndTable 785EndTable
733 786
734GrpTable: Grp1 787GrpTable: Grp1
@@ -790,7 +843,7 @@ GrpTable: Grp5
7902: CALLN Ev (f64) 8432: CALLN Ev (f64)
7913: CALLF Ep 8443: CALLF Ep
7924: JMPN Ev (f64) 8454: JMPN Ev (f64)
7935: JMPF Ep 8465: JMPF Mp
7946: PUSH Ev (d64) 8476: PUSH Ev (d64)
7957: 8487:
796EndTable 849EndTable
@@ -807,7 +860,7 @@ EndTable
807GrpTable: Grp7 860GrpTable: Grp7
8080: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) 8610: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
8091: SIDT Ms | MONITOR (000),(11B) | MWAIT (001) 8621: SIDT Ms | MONITOR (000),(11B) | MWAIT (001)
8102: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) 8632: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B)
8113: LIDT Ms 8643: LIDT Ms
8124: SMSW Mw/Rv 8654: SMSW Mw/Rv
8135: 8665:
@@ -824,44 +877,45 @@ EndTable
824 877
825GrpTable: Grp9 878GrpTable: Grp9
8261: CMPXCHG8B/16B Mq/Mdq 8791: CMPXCHG8B/16B Mq/Mdq
8276: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) 8806: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B)
8287: VMPTRST Mq 8817: VMPTRST Mq | VMPTRST Mq (F3)
829EndTable 882EndTable
830 883
831GrpTable: Grp10 884GrpTable: Grp10
832EndTable 885EndTable
833 886
834GrpTable: Grp11 887GrpTable: Grp11
888# Note: the operands are given by group opcode
8350: MOV 8890: MOV
836EndTable 890EndTable
837 891
838GrpTable: Grp12 892GrpTable: Grp12
8392: psrlw Nq,Ib (11B) | psrlw Udq,Ib (66),(11B),(VEX),(o128) 8932: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1)
8404: psraw Nq,Ib (11B) | psraw Udq,Ib (66),(11B),(VEX),(o128) 8944: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1)
8416: psllw Nq,Ib (11B) | psllw Udq,Ib (66),(11B),(VEX),(o128) 8956: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1)
842EndTable 896EndTable
843 897
844GrpTable: Grp13 898GrpTable: Grp13
8452: psrld Nq,Ib (11B) | psrld Udq,Ib (66),(11B),(VEX),(o128) 8992: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1)
8464: psrad Nq,Ib (11B) | psrad Udq,Ib (66),(11B),(VEX),(o128) 9004: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1)
8476: pslld Nq,Ib (11B) | pslld Udq,Ib (66),(11B),(VEX),(o128) 9016: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1)
848EndTable 902EndTable
849 903
850GrpTable: Grp14 904GrpTable: Grp14
8512: psrlq Nq,Ib (11B) | psrlq Udq,Ib (66),(11B),(VEX),(o128) 9052: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1)
8523: psrldq Udq,Ib (66),(11B),(VEX),(o128) 9063: vpsrldq Hx,Ux,Ib (66),(11B),(v1)
8536: psllq Nq,Ib (11B) | psllq Udq,Ib (66),(11B),(VEX),(o128) 9076: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1)
8547: pslldq Udq,Ib (66),(11B),(VEX),(o128) 9087: vpslldq Hx,Ux,Ib (66),(11B),(v1)
855EndTable 909EndTable
856 910
857GrpTable: Grp15 911GrpTable: Grp15
8580: fxsave 9120: fxsave | RDFSBASE Ry (F3),(11B)
8591: fxstor 9131: fxstor | RDGSBASE Ry (F3),(11B)
8602: ldmxcsr (VEX) 9142: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B)
8613: stmxcsr (VEX) 9153: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B)
8624: XSAVE 9164: XSAVE
8635: XRSTOR | lfence (11B) 9175: XRSTOR | lfence (11B)
8646: mfence (11B) 9186: XSAVEOPT | mfence (11B)
8657: clflush | sfence (11B) 9197: clflush | sfence (11B)
866EndTable 920EndTable
867 921
@@ -872,6 +926,12 @@ GrpTable: Grp16
8723: prefetch T2 9263: prefetch T2
873EndTable 927EndTable
874 928
929GrpTable: Grp17
9301: BLSR By,Ey (v)
9312: BLSMSK By,Ey (v)
9323: BLSI By,Ey (v)
933EndTable
934
875# AMD's Prefetch Group 935# AMD's Prefetch Group
876GrpTable: GrpP 936GrpTable: GrpP
8770: PREFETCH 9370: PREFETCH
diff --git a/arch/x86/oprofile/Makefile b/arch/x86/oprofile/Makefile
index 446902b2a6b..1599f568f0e 100644
--- a/arch/x86/oprofile/Makefile
+++ b/arch/x86/oprofile/Makefile
@@ -4,9 +4,8 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
4 oprof.o cpu_buffer.o buffer_sync.o \ 4 oprof.o cpu_buffer.o buffer_sync.o \
5 event_buffer.o oprofile_files.o \ 5 event_buffer.o oprofile_files.o \
6 oprofilefs.o oprofile_stats.o \ 6 oprofilefs.o oprofile_stats.o \
7 timer_int.o ) 7 timer_int.o nmi_timer_int.o )
8 8
9oprofile-y := $(DRIVER_OBJS) init.o backtrace.o 9oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
10oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_amd.o \ 10oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_amd.o \
11 op_model_ppro.o op_model_p4.o 11 op_model_ppro.o op_model_p4.o
12oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o
diff --git a/arch/x86/oprofile/init.c b/arch/x86/oprofile/init.c
index f148cf65267..9e138d00ad3 100644
--- a/arch/x86/oprofile/init.c
+++ b/arch/x86/oprofile/init.c
@@ -16,37 +16,23 @@
16 * with the NMI mode driver. 16 * with the NMI mode driver.
17 */ 17 */
18 18
19#ifdef CONFIG_X86_LOCAL_APIC
19extern int op_nmi_init(struct oprofile_operations *ops); 20extern int op_nmi_init(struct oprofile_operations *ops);
20extern int op_nmi_timer_init(struct oprofile_operations *ops);
21extern void op_nmi_exit(void); 21extern void op_nmi_exit(void);
22extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth); 22#else
23static int op_nmi_init(struct oprofile_operations *ops) { return -ENODEV; }
24static void op_nmi_exit(void) { }
25#endif
23 26
24static int nmi_timer; 27extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth);
25 28
26int __init oprofile_arch_init(struct oprofile_operations *ops) 29int __init oprofile_arch_init(struct oprofile_operations *ops)
27{ 30{
28 int ret;
29
30 ret = -ENODEV;
31
32#ifdef CONFIG_X86_LOCAL_APIC
33 ret = op_nmi_init(ops);
34#endif
35 nmi_timer = (ret != 0);
36#ifdef CONFIG_X86_IO_APIC
37 if (nmi_timer)
38 ret = op_nmi_timer_init(ops);
39#endif
40 ops->backtrace = x86_backtrace; 31 ops->backtrace = x86_backtrace;
41 32 return op_nmi_init(ops);
42 return ret;
43} 33}
44 34
45
46void oprofile_arch_exit(void) 35void oprofile_arch_exit(void)
47{ 36{
48#ifdef CONFIG_X86_LOCAL_APIC 37 op_nmi_exit();
49 if (!nmi_timer)
50 op_nmi_exit();
51#endif
52} 38}
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index 75f9528e037..26b8a8514ee 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -595,24 +595,36 @@ static int __init p4_init(char **cpu_type)
595 return 0; 595 return 0;
596} 596}
597 597
598static int force_arch_perfmon; 598enum __force_cpu_type {
599static int force_cpu_type(const char *str, struct kernel_param *kp) 599 reserved = 0, /* do not force */
600 timer,
601 arch_perfmon,
602};
603
604static int force_cpu_type;
605
606static int set_cpu_type(const char *str, struct kernel_param *kp)
600{ 607{
601 if (!strcmp(str, "arch_perfmon")) { 608 if (!strcmp(str, "timer")) {
602 force_arch_perfmon = 1; 609 force_cpu_type = timer;
610 printk(KERN_INFO "oprofile: forcing NMI timer mode\n");
611 } else if (!strcmp(str, "arch_perfmon")) {
612 force_cpu_type = arch_perfmon;
603 printk(KERN_INFO "oprofile: forcing architectural perfmon\n"); 613 printk(KERN_INFO "oprofile: forcing architectural perfmon\n");
614 } else {
615 force_cpu_type = 0;
604 } 616 }
605 617
606 return 0; 618 return 0;
607} 619}
608module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0); 620module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0);
609 621
610static int __init ppro_init(char **cpu_type) 622static int __init ppro_init(char **cpu_type)
611{ 623{
612 __u8 cpu_model = boot_cpu_data.x86_model; 624 __u8 cpu_model = boot_cpu_data.x86_model;
613 struct op_x86_model_spec *spec = &op_ppro_spec; /* default */ 625 struct op_x86_model_spec *spec = &op_ppro_spec; /* default */
614 626
615 if (force_arch_perfmon && cpu_has_arch_perfmon) 627 if (force_cpu_type == arch_perfmon && cpu_has_arch_perfmon)
616 return 0; 628 return 0;
617 629
618 /* 630 /*
@@ -679,6 +691,9 @@ int __init op_nmi_init(struct oprofile_operations *ops)
679 if (!cpu_has_apic) 691 if (!cpu_has_apic)
680 return -ENODEV; 692 return -ENODEV;
681 693
694 if (force_cpu_type == timer)
695 return -ENODEV;
696
682 switch (vendor) { 697 switch (vendor) {
683 case X86_VENDOR_AMD: 698 case X86_VENDOR_AMD:
684 /* Needs to be at least an Athlon (or hammer in 32bit mode) */ 699 /* 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
index 7f8052cd662..00000000000
--- a/arch/x86/oprofile/nmi_timer_int.c
+++ /dev/null
@@ -1,50 +0,0 @@
1/**
2 * @file nmi_timer_int.c
3 *
4 * @remark Copyright 2003 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author Zwane Mwaikambo <zwane@linuxpower.ca>
8 */
9
10#include <linux/init.h>
11#include <linux/smp.h>
12#include <linux/errno.h>
13#include <linux/oprofile.h>
14#include <linux/rcupdate.h>
15#include <linux/kdebug.h>
16
17#include <asm/nmi.h>
18#include <asm/apic.h>
19#include <asm/ptrace.h>
20
21static int profile_timer_exceptions_notify(unsigned int val, struct pt_regs *regs)
22{
23 oprofile_add_sample(regs, 0);
24 return NMI_HANDLED;
25}
26
27static int timer_start(void)
28{
29 if (register_nmi_handler(NMI_LOCAL, profile_timer_exceptions_notify,
30 0, "oprofile-timer"))
31 return 1;
32 return 0;
33}
34
35
36static void timer_stop(void)
37{
38 unregister_nmi_handler(NMI_LOCAL, "oprofile-timer");
39 synchronize_sched(); /* Allow already-started NMIs to complete. */
40}
41
42
43int __init op_nmi_timer_init(struct oprofile_operations *ops)
44{
45 ops->start = timer_start;
46 ops->stop = timer_stop;
47 ops->cpu_type = "timer";
48 printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
49 return 0;
50}
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index f8208267733..d511aa97533 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -18,14 +18,21 @@ chkobjdump = $(srctree)/arch/x86/tools/chkobjdump.awk
18quiet_cmd_posttest = TEST $@ 18quiet_cmd_posttest = TEST $@
19 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) 19 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)
20 20
21posttest: $(obj)/test_get_len vmlinux 21quiet_cmd_sanitytest = TEST $@
22 cmd_sanitytest = $(obj)/insn_sanity $(posttest_64bit) -m 1000000
23
24posttest: $(obj)/test_get_len vmlinux $(obj)/insn_sanity
22 $(call cmd,posttest) 25 $(call cmd,posttest)
26 $(call cmd,sanitytest)
23 27
24hostprogs-y := test_get_len 28hostprogs-y += test_get_len insn_sanity
25 29
26# -I needed for generated C source and C source which in the kernel tree. 30# -I needed for generated C source and C source which in the kernel tree.
27HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/ 31HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/
28 32
33HOSTCFLAGS_insn_sanity.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/
34
29# Dependencies are also needed. 35# Dependencies are also needed.
30$(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 36$(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
31 37
38$(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
diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk
index eaf11f52fc0..5f6a5b6c3a1 100644
--- a/arch/x86/tools/gen-insn-attr-x86.awk
+++ b/arch/x86/tools/gen-insn-attr-x86.awk
@@ -47,7 +47,7 @@ BEGIN {
47 sep_expr = "^\\|$" 47 sep_expr = "^\\|$"
48 group_expr = "^Grp[0-9A-Za-z]+" 48 group_expr = "^Grp[0-9A-Za-z]+"
49 49
50 imm_expr = "^[IJAO][a-z]" 50 imm_expr = "^[IJAOL][a-z]"
51 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 51 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
52 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 52 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
53 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" 53 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
@@ -59,6 +59,7 @@ BEGIN {
59 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" 59 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
60 imm_flag["Ob"] = "INAT_MOFFSET" 60 imm_flag["Ob"] = "INAT_MOFFSET"
61 imm_flag["Ov"] = "INAT_MOFFSET" 61 imm_flag["Ov"] = "INAT_MOFFSET"
62 imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
62 63
63 modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" 64 modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
64 force64_expr = "\\([df]64\\)" 65 force64_expr = "\\([df]64\\)"
@@ -70,8 +71,12 @@ BEGIN {
70 lprefix3_expr = "\\(F2\\)" 71 lprefix3_expr = "\\(F2\\)"
71 max_lprefix = 4 72 max_lprefix = 4
72 73
73 vexok_expr = "\\(VEX\\)" 74 # All opcodes starting with lower-case 'v' or with (v1) superscript
74 vexonly_expr = "\\(oVEX\\)" 75 # accepts VEX prefix
76 vexok_opcode_expr = "^v.*"
77 vexok_expr = "\\(v1\\)"
78 # All opcodes with (v) superscript supports *only* VEX prefix
79 vexonly_expr = "\\(v\\)"
75 80
76 prefix_expr = "\\(Prefix\\)" 81 prefix_expr = "\\(Prefix\\)"
77 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" 82 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
@@ -85,8 +90,8 @@ BEGIN {
85 prefix_num["SEG=GS"] = "INAT_PFX_GS" 90 prefix_num["SEG=GS"] = "INAT_PFX_GS"
86 prefix_num["SEG=SS"] = "INAT_PFX_SS" 91 prefix_num["SEG=SS"] = "INAT_PFX_SS"
87 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" 92 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
88 prefix_num["2bytes-VEX"] = "INAT_PFX_VEX2" 93 prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
89 prefix_num["3bytes-VEX"] = "INAT_PFX_VEX3" 94 prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
90 95
91 clear_vars() 96 clear_vars()
92} 97}
@@ -310,12 +315,10 @@ function convert_operands(count,opnd, i,j,imm,mod)
310 if (match(opcode, fpu_expr)) 315 if (match(opcode, fpu_expr))
311 flags = add_flags(flags, "INAT_MODRM") 316 flags = add_flags(flags, "INAT_MODRM")
312 317
313 # check VEX only code 318 # check VEX codes
314 if (match(ext, vexonly_expr)) 319 if (match(ext, vexonly_expr))
315 flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") 320 flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
316 321 else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
317 # check VEX only code
318 if (match(ext, vexok_expr))
319 flags = add_flags(flags, "INAT_VEXOK") 322 flags = add_flags(flags, "INAT_VEXOK")
320 323
321 # check prefixes 324 # check prefixes
diff --git a/arch/x86/tools/insn_sanity.c b/arch/x86/tools/insn_sanity.c
new file mode 100644
index 00000000000..cc2f8c13128
--- /dev/null
+++ b/arch/x86/tools/insn_sanity.c
@@ -0,0 +1,275 @@
1/*
2 * x86 decoder sanity test - based on test_get_insn.c
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Copyright (C) IBM Corporation, 2009
19 * Copyright (C) Hitachi, Ltd., 2011
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <assert.h>
26#include <unistd.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30
31#define unlikely(cond) (cond)
32#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
33
34#include <asm/insn.h>
35#include <inat.c>
36#include <insn.c>
37
38/*
39 * Test of instruction analysis against tampering.
40 * Feed random binary to instruction decoder and ensure not to
41 * access out-of-instruction-buffer.
42 */
43
44#define DEFAULT_MAX_ITER 10000
45#define INSN_NOP 0x90
46
47static const char *prog; /* Program name */
48static int verbose; /* Verbosity */
49static int x86_64; /* x86-64 bit mode flag */
50static unsigned int seed; /* Random seed */
51static unsigned long iter_start; /* Start of iteration number */
52static unsigned long iter_end = DEFAULT_MAX_ITER; /* End of iteration number */
53static FILE *input_file; /* Input file name */
54
55static void usage(const char *err)
56{
57 if (err)
58 fprintf(stderr, "Error: %s\n\n", err);
59 fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog);
60 fprintf(stderr, "\t-y 64bit mode\n");
61 fprintf(stderr, "\t-n 32bit mode\n");
62 fprintf(stderr, "\t-v Verbosity(-vv dumps any decoded result)\n");
63 fprintf(stderr, "\t-s Give a random seed (and iteration number)\n");
64 fprintf(stderr, "\t-m Give a maximum iteration number\n");
65 fprintf(stderr, "\t-i Give an input file with decoded binary\n");
66 exit(1);
67}
68
69static void dump_field(FILE *fp, const char *name, const char *indent,
70 struct insn_field *field)
71{
72 fprintf(fp, "%s.%s = {\n", indent, name);
73 fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n",
74 indent, field->value, field->bytes[0], field->bytes[1],
75 field->bytes[2], field->bytes[3]);
76 fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent,
77 field->got, field->nbytes);
78}
79
80static void dump_insn(FILE *fp, struct insn *insn)
81{
82 fprintf(fp, "Instruction = {\n");
83 dump_field(fp, "prefixes", "\t", &insn->prefixes);
84 dump_field(fp, "rex_prefix", "\t", &insn->rex_prefix);
85 dump_field(fp, "vex_prefix", "\t", &insn->vex_prefix);
86 dump_field(fp, "opcode", "\t", &insn->opcode);
87 dump_field(fp, "modrm", "\t", &insn->modrm);
88 dump_field(fp, "sib", "\t", &insn->sib);
89 dump_field(fp, "displacement", "\t", &insn->displacement);
90 dump_field(fp, "immediate1", "\t", &insn->immediate1);
91 dump_field(fp, "immediate2", "\t", &insn->immediate2);
92 fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n",
93 insn->attr, insn->opnd_bytes, insn->addr_bytes);
94 fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n",
95 insn->length, insn->x86_64, insn->kaddr);
96}
97
98static void dump_stream(FILE *fp, const char *msg, unsigned long nr_iter,
99 unsigned char *insn_buf, struct insn *insn)
100{
101 int i;
102
103 fprintf(fp, "%s:\n", msg);
104
105 dump_insn(fp, insn);
106
107 fprintf(fp, "You can reproduce this with below command(s);\n");
108
109 /* Input a decoded instruction sequence directly */
110 fprintf(fp, " $ echo ");
111 for (i = 0; i < MAX_INSN_SIZE; i++)
112 fprintf(fp, " %02x", insn_buf[i]);
113 fprintf(fp, " | %s -i -\n", prog);
114
115 if (!input_file) {
116 fprintf(fp, "Or \n");
117 /* Give a seed and iteration number */
118 fprintf(fp, " $ %s -s 0x%x,%lu\n", prog, seed, nr_iter);
119 }
120}
121
122static void init_random_seed(void)
123{
124 int fd;
125
126 fd = open("/dev/urandom", O_RDONLY);
127 if (fd < 0)
128 goto fail;
129
130 if (read(fd, &seed, sizeof(seed)) != sizeof(seed))
131 goto fail;
132
133 close(fd);
134 return;
135fail:
136 usage("Failed to open /dev/urandom");
137}
138
139/* Read given instruction sequence from the input file */
140static int read_next_insn(unsigned char *insn_buf)
141{
142 char buf[256] = "", *tmp;
143 int i;
144
145 tmp = fgets(buf, ARRAY_SIZE(buf), input_file);
146 if (tmp == NULL || feof(input_file))
147 return 0;
148
149 for (i = 0; i < MAX_INSN_SIZE; i++) {
150 insn_buf[i] = (unsigned char)strtoul(tmp, &tmp, 16);
151 if (*tmp != ' ')
152 break;
153 }
154
155 return i;
156}
157
158static int generate_insn(unsigned char *insn_buf)
159{
160 int i;
161
162 if (input_file)
163 return read_next_insn(insn_buf);
164
165 /* Fills buffer with random binary up to MAX_INSN_SIZE */
166 for (i = 0; i < MAX_INSN_SIZE - 1; i += 2)
167 *(unsigned short *)(&insn_buf[i]) = random() & 0xffff;
168
169 while (i < MAX_INSN_SIZE)
170 insn_buf[i++] = random() & 0xff;
171
172 return i;
173}
174
175static void parse_args(int argc, char **argv)
176{
177 int c;
178 char *tmp = NULL;
179 int set_seed = 0;
180
181 prog = argv[0];
182 while ((c = getopt(argc, argv, "ynvs:m:i:")) != -1) {
183 switch (c) {
184 case 'y':
185 x86_64 = 1;
186 break;
187 case 'n':
188 x86_64 = 0;
189 break;
190 case 'v':
191 verbose++;
192 break;
193 case 'i':
194 if (strcmp("-", optarg) == 0)
195 input_file = stdin;
196 else
197 input_file = fopen(optarg, "r");
198 if (!input_file)
199 usage("Failed to open input file");
200 break;
201 case 's':
202 seed = (unsigned int)strtoul(optarg, &tmp, 0);
203 if (*tmp == ',') {
204 optarg = tmp + 1;
205 iter_start = strtoul(optarg, &tmp, 0);
206 }
207 if (*tmp != '\0' || tmp == optarg)
208 usage("Failed to parse seed");
209 set_seed = 1;
210 break;
211 case 'm':
212 iter_end = strtoul(optarg, &tmp, 0);
213 if (*tmp != '\0' || tmp == optarg)
214 usage("Failed to parse max_iter");
215 break;
216 default:
217 usage(NULL);
218 }
219 }
220
221 /* Check errors */
222 if (iter_end < iter_start)
223 usage("Max iteration number must be bigger than iter-num");
224
225 if (set_seed && input_file)
226 usage("Don't use input file (-i) with random seed (-s)");
227
228 /* Initialize random seed */
229 if (!input_file) {
230 if (!set_seed) /* No seed is given */
231 init_random_seed();
232 srand(seed);
233 }
234}
235
236int main(int argc, char **argv)
237{
238 struct insn insn;
239 int insns = 0;
240 int errors = 0;
241 unsigned long i;
242 unsigned char insn_buf[MAX_INSN_SIZE * 2];
243
244 parse_args(argc, argv);
245
246 /* Prepare stop bytes with NOPs */
247 memset(insn_buf + MAX_INSN_SIZE, INSN_NOP, MAX_INSN_SIZE);
248
249 for (i = 0; i < iter_end; i++) {
250 if (generate_insn(insn_buf) <= 0)
251 break;
252
253 if (i < iter_start) /* Skip to given iteration number */
254 continue;
255
256 /* Decode an instruction */
257 insn_init(&insn, insn_buf, x86_64);
258 insn_get_length(&insn);
259
260 if (insn.next_byte <= insn.kaddr ||
261 insn.kaddr + MAX_INSN_SIZE < insn.next_byte) {
262 /* Access out-of-range memory */
263 dump_stream(stderr, "Error: Found an access violation", i, insn_buf, &insn);
264 errors++;
265 } else if (verbose && !insn_complete(&insn))
266 dump_stream(stdout, "Info: Found an undecodable input", i, insn_buf, &insn);
267 else if (verbose >= 2)
268 dump_insn(stdout, &insn);
269 insns++;
270 }
271
272 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);
273
274 return errors ? 1 : 0;
275}
diff --git a/drivers/oprofile/nmi_timer_int.c b/drivers/oprofile/nmi_timer_int.c
new file mode 100644
index 00000000000..76f1c9357f3
--- /dev/null
+++ b/drivers/oprofile/nmi_timer_int.c
@@ -0,0 +1,173 @@
1/**
2 * @file nmi_timer_int.c
3 *
4 * @remark Copyright 2011 Advanced Micro Devices, Inc.
5 *
6 * @author Robert Richter <robert.richter@amd.com>
7 */
8
9#include <linux/init.h>
10#include <linux/smp.h>
11#include <linux/errno.h>
12#include <linux/oprofile.h>
13#include <linux/perf_event.h>
14
15#ifdef CONFIG_OPROFILE_NMI_TIMER
16
17static DEFINE_PER_CPU(struct perf_event *, nmi_timer_events);
18static int ctr_running;
19
20static struct perf_event_attr nmi_timer_attr = {
21 .type = PERF_TYPE_HARDWARE,
22 .config = PERF_COUNT_HW_CPU_CYCLES,
23 .size = sizeof(struct perf_event_attr),
24 .pinned = 1,
25 .disabled = 1,
26};
27
28static void nmi_timer_callback(struct perf_event *event,
29 struct perf_sample_data *data,
30 struct pt_regs *regs)
31{
32 event->hw.interrupts = 0; /* don't throttle interrupts */
33 oprofile_add_sample(regs, 0);
34}
35
36static int nmi_timer_start_cpu(int cpu)
37{
38 struct perf_event *event = per_cpu(nmi_timer_events, cpu);
39
40 if (!event) {
41 event = perf_event_create_kernel_counter(&nmi_timer_attr, cpu, NULL,
42 nmi_timer_callback, NULL);
43 if (IS_ERR(event))
44 return PTR_ERR(event);
45 per_cpu(nmi_timer_events, cpu) = event;
46 }
47
48 if (event && ctr_running)
49 perf_event_enable(event);
50
51 return 0;
52}
53
54static void nmi_timer_stop_cpu(int cpu)
55{
56 struct perf_event *event = per_cpu(nmi_timer_events, cpu);
57
58 if (event && ctr_running)
59 perf_event_disable(event);
60}
61
62static int nmi_timer_cpu_notifier(struct notifier_block *b, unsigned long action,
63 void *data)
64{
65 int cpu = (unsigned long)data;
66 switch (action) {
67 case CPU_DOWN_FAILED:
68 case CPU_ONLINE:
69 nmi_timer_start_cpu(cpu);
70 break;
71 case CPU_DOWN_PREPARE:
72 nmi_timer_stop_cpu(cpu);
73 break;
74 }
75 return NOTIFY_DONE;
76}
77
78static struct notifier_block nmi_timer_cpu_nb = {
79 .notifier_call = nmi_timer_cpu_notifier
80};
81
82static int nmi_timer_start(void)
83{
84 int cpu;
85
86 get_online_cpus();
87 ctr_running = 1;
88 for_each_online_cpu(cpu)
89 nmi_timer_start_cpu(cpu);
90 put_online_cpus();
91
92 return 0;
93}
94
95static void nmi_timer_stop(void)
96{
97 int cpu;
98
99 get_online_cpus();
100 for_each_online_cpu(cpu)
101 nmi_timer_stop_cpu(cpu);
102 ctr_running = 0;
103 put_online_cpus();
104}
105
106static void nmi_timer_shutdown(void)
107{
108 struct perf_event *event;
109 int cpu;
110
111 get_online_cpus();
112 unregister_cpu_notifier(&nmi_timer_cpu_nb);
113 for_each_possible_cpu(cpu) {
114 event = per_cpu(nmi_timer_events, cpu);
115 if (!event)
116 continue;
117 perf_event_disable(event);
118 per_cpu(nmi_timer_events, cpu) = NULL;
119 perf_event_release_kernel(event);
120 }
121
122 put_online_cpus();
123}
124
125static int nmi_timer_setup(void)
126{
127 int cpu, err;
128 u64 period;
129
130 /* clock cycles per tick: */
131 period = (u64)cpu_khz * 1000;
132 do_div(period, HZ);
133 nmi_timer_attr.sample_period = period;
134
135 get_online_cpus();
136 err = register_cpu_notifier(&nmi_timer_cpu_nb);
137 if (err)
138 goto out;
139 /* can't attach events to offline cpus: */
140 for_each_online_cpu(cpu) {
141 err = nmi_timer_start_cpu(cpu);
142 if (err)
143 break;
144 }
145 if (err)
146 nmi_timer_shutdown();
147out:
148 put_online_cpus();
149 return err;
150}
151
152int __init op_nmi_timer_init(struct oprofile_operations *ops)
153{
154 int err = 0;
155
156 err = nmi_timer_setup();
157 if (err)
158 return err;
159 nmi_timer_shutdown(); /* only check, don't alloc */
160
161 ops->create_files = NULL;
162 ops->setup = nmi_timer_setup;
163 ops->shutdown = nmi_timer_shutdown;
164 ops->start = nmi_timer_start;
165 ops->stop = nmi_timer_stop;
166 ops->cpu_type = "timer";
167
168 printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
169
170 return 0;
171}
172
173#endif
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index f8c752e408a..ed2c3ec0702 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -246,37 +246,31 @@ static int __init oprofile_init(void)
246 int err; 246 int err;
247 247
248 /* always init architecture to setup backtrace support */ 248 /* always init architecture to setup backtrace support */
249 timer_mode = 0;
249 err = oprofile_arch_init(&oprofile_ops); 250 err = oprofile_arch_init(&oprofile_ops);
251 if (!err) {
252 if (!timer && !oprofilefs_register())
253 return 0;
254 oprofile_arch_exit();
255 }
250 256
251 timer_mode = err || timer; /* fall back to timer mode on errors */ 257 /* setup timer mode: */
252 if (timer_mode) { 258 timer_mode = 1;
253 if (!err) 259 /* no nmi timer mode if oprofile.timer is set */
254 oprofile_arch_exit(); 260 if (timer || op_nmi_timer_init(&oprofile_ops)) {
255 err = oprofile_timer_init(&oprofile_ops); 261 err = oprofile_timer_init(&oprofile_ops);
256 if (err) 262 if (err)
257 return err; 263 return err;
258 } 264 }
259 265
260 err = oprofilefs_register(); 266 return oprofilefs_register();
261 if (!err)
262 return 0;
263
264 /* failed */
265 if (timer_mode)
266 oprofile_timer_exit();
267 else
268 oprofile_arch_exit();
269
270 return err;
271} 267}
272 268
273 269
274static void __exit oprofile_exit(void) 270static void __exit oprofile_exit(void)
275{ 271{
276 oprofilefs_unregister(); 272 oprofilefs_unregister();
277 if (timer_mode) 273 if (!timer_mode)
278 oprofile_timer_exit();
279 else
280 oprofile_arch_exit(); 274 oprofile_arch_exit();
281} 275}
282 276
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
index 177b73de5e5..769fb0fcac4 100644
--- a/drivers/oprofile/oprof.h
+++ b/drivers/oprofile/oprof.h
@@ -36,6 +36,15 @@ struct dentry;
36void oprofile_create_files(struct super_block *sb, struct dentry *root); 36void oprofile_create_files(struct super_block *sb, struct dentry *root);
37int oprofile_timer_init(struct oprofile_operations *ops); 37int oprofile_timer_init(struct oprofile_operations *ops);
38void oprofile_timer_exit(void); 38void oprofile_timer_exit(void);
39#ifdef CONFIG_OPROFILE_NMI_TIMER
40int op_nmi_timer_init(struct oprofile_operations *ops);
41#else
42static inline int op_nmi_timer_init(struct oprofile_operations *ops)
43{
44 return -ENODEV;
45}
46#endif
47
39 48
40int oprofile_set_ulong(unsigned long *addr, unsigned long val); 49int oprofile_set_ulong(unsigned long *addr, unsigned long val);
41int oprofile_set_timeout(unsigned long time); 50int oprofile_set_timeout(unsigned long time);
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index 878fba12658..93404f72dfa 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -97,24 +97,24 @@ static struct notifier_block __refdata oprofile_cpu_notifier = {
97 .notifier_call = oprofile_cpu_notify, 97 .notifier_call = oprofile_cpu_notify,
98}; 98};
99 99
100int oprofile_timer_init(struct oprofile_operations *ops) 100static int oprofile_hrtimer_setup(void)
101{ 101{
102 int rc; 102 return register_hotcpu_notifier(&oprofile_cpu_notifier);
103
104 rc = register_hotcpu_notifier(&oprofile_cpu_notifier);
105 if (rc)
106 return rc;
107 ops->create_files = NULL;
108 ops->setup = NULL;
109 ops->shutdown = NULL;
110 ops->start = oprofile_hrtimer_start;
111 ops->stop = oprofile_hrtimer_stop;
112 ops->cpu_type = "timer";
113 printk(KERN_INFO "oprofile: using timer interrupt.\n");
114 return 0;
115} 103}
116 104
117void oprofile_timer_exit(void) 105static void oprofile_hrtimer_shutdown(void)
118{ 106{
119 unregister_hotcpu_notifier(&oprofile_cpu_notifier); 107 unregister_hotcpu_notifier(&oprofile_cpu_notifier);
120} 108}
109
110int oprofile_timer_init(struct oprofile_operations *ops)
111{
112 ops->create_files = NULL;
113 ops->setup = oprofile_hrtimer_setup;
114 ops->shutdown = oprofile_hrtimer_shutdown;
115 ops->start = oprofile_hrtimer_start;
116 ops->stop = oprofile_hrtimer_stop;
117 ops->cpu_type = "timer";
118 printk(KERN_INFO "oprofile: using timer interrupt.\n");
119 return 0;
120}
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index a3ef66a2a08..3c1063acb2a 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -22,8 +22,14 @@ extern unsigned long __sw_hweight64(__u64 w);
22#include <asm/bitops.h> 22#include <asm/bitops.h>
23 23
24#define for_each_set_bit(bit, addr, size) \ 24#define for_each_set_bit(bit, addr, size) \
25 for ((bit) = find_first_bit((addr), (size)); \ 25 for ((bit) = find_first_bit((addr), (size)); \
26 (bit) < (size); \ 26 (bit) < (size); \
27 (bit) = find_next_bit((addr), (size), (bit) + 1))
28
29/* same as for_each_set_bit() but use bit as value to start with */
30#define for_each_set_bit_cont(bit, addr, size) \
31 for ((bit) = find_next_bit((addr), (size), (bit)); \
32 (bit) < (size); \
27 (bit) = find_next_bit((addr), (size), (bit) + 1)) 33 (bit) = find_next_bit((addr), (size), (bit) + 1))
28 34
29static __inline__ int get_bitmask_order(unsigned int count) 35static __inline__ int get_bitmask_order(unsigned int count)
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
index 388b0d425b5..5ce8b140428 100644
--- a/include/linux/jump_label.h
+++ b/include/linux/jump_label.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/compiler.h> 5#include <linux/compiler.h>
6#include <linux/workqueue.h>
6 7
7#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) 8#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL)
8 9
@@ -14,6 +15,12 @@ struct jump_label_key {
14#endif 15#endif
15}; 16};
16 17
18struct jump_label_key_deferred {
19 struct jump_label_key key;
20 unsigned long timeout;
21 struct delayed_work work;
22};
23
17# include <asm/jump_label.h> 24# include <asm/jump_label.h>
18# define HAVE_JUMP_LABEL 25# define HAVE_JUMP_LABEL
19#endif /* CC_HAVE_ASM_GOTO && CONFIG_JUMP_LABEL */ 26#endif /* CC_HAVE_ASM_GOTO && CONFIG_JUMP_LABEL */
@@ -51,8 +58,11 @@ extern void arch_jump_label_transform_static(struct jump_entry *entry,
51extern int jump_label_text_reserved(void *start, void *end); 58extern int jump_label_text_reserved(void *start, void *end);
52extern void jump_label_inc(struct jump_label_key *key); 59extern void jump_label_inc(struct jump_label_key *key);
53extern void jump_label_dec(struct jump_label_key *key); 60extern void jump_label_dec(struct jump_label_key *key);
61extern void jump_label_dec_deferred(struct jump_label_key_deferred *key);
54extern bool jump_label_enabled(struct jump_label_key *key); 62extern bool jump_label_enabled(struct jump_label_key *key);
55extern void jump_label_apply_nops(struct module *mod); 63extern void jump_label_apply_nops(struct module *mod);
64extern void jump_label_rate_limit(struct jump_label_key_deferred *key,
65 unsigned long rl);
56 66
57#else /* !HAVE_JUMP_LABEL */ 67#else /* !HAVE_JUMP_LABEL */
58 68
@@ -68,6 +78,10 @@ static __always_inline void jump_label_init(void)
68{ 78{
69} 79}
70 80
81struct jump_label_key_deferred {
82 struct jump_label_key key;
83};
84
71static __always_inline bool static_branch(struct jump_label_key *key) 85static __always_inline bool static_branch(struct jump_label_key *key)
72{ 86{
73 if (unlikely(atomic_read(&key->enabled))) 87 if (unlikely(atomic_read(&key->enabled)))
@@ -85,6 +99,11 @@ static inline void jump_label_dec(struct jump_label_key *key)
85 atomic_dec(&key->enabled); 99 atomic_dec(&key->enabled);
86} 100}
87 101
102static inline void jump_label_dec_deferred(struct jump_label_key_deferred *key)
103{
104 jump_label_dec(&key->key);
105}
106
88static inline int jump_label_text_reserved(void *start, void *end) 107static inline int jump_label_text_reserved(void *start, void *end)
89{ 108{
90 return 0; 109 return 0;
@@ -102,6 +121,14 @@ static inline int jump_label_apply_nops(struct module *mod)
102{ 121{
103 return 0; 122 return 0;
104} 123}
124
125static inline void jump_label_rate_limit(struct jump_label_key_deferred *key,
126 unsigned long rl)
127{
128}
105#endif /* HAVE_JUMP_LABEL */ 129#endif /* HAVE_JUMP_LABEL */
106 130
131#define jump_label_key_enabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(1), })
132#define jump_label_key_disabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(0), })
133
107#endif /* _LINUX_JUMP_LABEL_H */ 134#endif /* _LINUX_JUMP_LABEL_H */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index b1f89122bf6..564769cdb47 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -890,6 +890,7 @@ struct perf_event_context {
890 int nr_active; 890 int nr_active;
891 int is_active; 891 int is_active;
892 int nr_stat; 892 int nr_stat;
893 int nr_freq;
893 int rotate_disable; 894 int rotate_disable;
894 atomic_t refcount; 895 atomic_t refcount;
895 struct task_struct *task; 896 struct task_struct *task;
@@ -1063,12 +1064,12 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr)
1063 } 1064 }
1064} 1065}
1065 1066
1066extern struct jump_label_key perf_sched_events; 1067extern struct jump_label_key_deferred perf_sched_events;
1067 1068
1068static inline void perf_event_task_sched_in(struct task_struct *prev, 1069static inline void perf_event_task_sched_in(struct task_struct *prev,
1069 struct task_struct *task) 1070 struct task_struct *task)
1070{ 1071{
1071 if (static_branch(&perf_sched_events)) 1072 if (static_branch(&perf_sched_events.key))
1072 __perf_event_task_sched_in(prev, task); 1073 __perf_event_task_sched_in(prev, task);
1073} 1074}
1074 1075
@@ -1077,7 +1078,7 @@ static inline void perf_event_task_sched_out(struct task_struct *prev,
1077{ 1078{
1078 perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); 1079 perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0);
1079 1080
1080 if (static_branch(&perf_sched_events)) 1081 if (static_branch(&perf_sched_events.key))
1081 __perf_event_task_sched_out(prev, next); 1082 __perf_event_task_sched_out(prev, next);
1082} 1083}
1083 1084
diff --git a/kernel/events/Makefile b/kernel/events/Makefile
index 89e5e8aa4c3..22d901f9caf 100644
--- a/kernel/events/Makefile
+++ b/kernel/events/Makefile
@@ -2,5 +2,5 @@ ifdef CONFIG_FUNCTION_TRACER
2CFLAGS_REMOVE_core.o = -pg 2CFLAGS_REMOVE_core.o = -pg
3endif 3endif
4 4
5obj-y := core.o ring_buffer.o 5obj-y := core.o ring_buffer.o callchain.o
6obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o 6obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
new file mode 100644
index 00000000000..057e24b665c
--- /dev/null
+++ b/kernel/events/callchain.c
@@ -0,0 +1,191 @@
1/*
2 * Performance events callchain code, extracted from core.c:
3 *
4 * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
5 * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
6 * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
7 * Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
8 *
9 * For licensing details see kernel-base/COPYING
10 */
11
12#include <linux/perf_event.h>
13#include <linux/slab.h>
14#include "internal.h"
15
16struct callchain_cpus_entries {
17 struct rcu_head rcu_head;
18 struct perf_callchain_entry *cpu_entries[0];
19};
20
21static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]);
22static atomic_t nr_callchain_events;
23static DEFINE_MUTEX(callchain_mutex);
24static struct callchain_cpus_entries *callchain_cpus_entries;
25
26
27__weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
28 struct pt_regs *regs)
29{
30}
31
32__weak void perf_callchain_user(struct perf_callchain_entry *entry,
33 struct pt_regs *regs)
34{
35}
36
37static void release_callchain_buffers_rcu(struct rcu_head *head)
38{
39 struct callchain_cpus_entries *entries;
40 int cpu;
41
42 entries = container_of(head, struct callchain_cpus_entries, rcu_head);
43
44 for_each_possible_cpu(cpu)
45 kfree(entries->cpu_entries[cpu]);
46
47 kfree(entries);
48}
49
50static void release_callchain_buffers(void)
51{
52 struct callchain_cpus_entries *entries;
53
54 entries = callchain_cpus_entries;
55 rcu_assign_pointer(callchain_cpus_entries, NULL);
56 call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
57}
58
59static int alloc_callchain_buffers(void)
60{
61 int cpu;
62 int size;
63 struct callchain_cpus_entries *entries;
64
65 /*
66 * We can't use the percpu allocation API for data that can be
67 * accessed from NMI. Use a temporary manual per cpu allocation
68 * until that gets sorted out.
69 */
70 size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
71
72 entries = kzalloc(size, GFP_KERNEL);
73 if (!entries)
74 return -ENOMEM;
75
76 size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS;
77
78 for_each_possible_cpu(cpu) {
79 entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL,
80 cpu_to_node(cpu));
81 if (!entries->cpu_entries[cpu])
82 goto fail;
83 }
84
85 rcu_assign_pointer(callchain_cpus_entries, entries);
86
87 return 0;
88
89fail:
90 for_each_possible_cpu(cpu)
91 kfree(entries->cpu_entries[cpu]);
92 kfree(entries);
93
94 return -ENOMEM;
95}
96
97int get_callchain_buffers(void)
98{
99 int err = 0;
100 int count;
101
102 mutex_lock(&callchain_mutex);
103
104 count = atomic_inc_return(&nr_callchain_events);
105 if (WARN_ON_ONCE(count < 1)) {
106 err = -EINVAL;
107 goto exit;
108 }
109
110 if (count > 1) {
111 /* If the allocation failed, give up */
112 if (!callchain_cpus_entries)
113 err = -ENOMEM;
114 goto exit;
115 }
116
117 err = alloc_callchain_buffers();
118 if (err)
119 release_callchain_buffers();
120exit:
121 mutex_unlock(&callchain_mutex);
122
123 return err;
124}
125
126void put_callchain_buffers(void)
127{
128 if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) {
129 release_callchain_buffers();
130 mutex_unlock(&callchain_mutex);
131 }
132}
133
134static struct perf_callchain_entry *get_callchain_entry(int *rctx)
135{
136 int cpu;
137 struct callchain_cpus_entries *entries;
138
139 *rctx = get_recursion_context(__get_cpu_var(callchain_recursion));
140 if (*rctx == -1)
141 return NULL;
142
143 entries = rcu_dereference(callchain_cpus_entries);
144 if (!entries)
145 return NULL;
146
147 cpu = smp_processor_id();
148
149 return &entries->cpu_entries[cpu][*rctx];
150}
151
152static void
153put_callchain_entry(int rctx)
154{
155 put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
156}
157
158struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
159{
160 int rctx;
161 struct perf_callchain_entry *entry;
162
163
164 entry = get_callchain_entry(&rctx);
165 if (rctx == -1)
166 return NULL;
167
168 if (!entry)
169 goto exit_put;
170
171 entry->nr = 0;
172
173 if (!user_mode(regs)) {
174 perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
175 perf_callchain_kernel(entry, regs);
176 if (current->mm)
177 regs = task_pt_regs(current);
178 else
179 regs = NULL;
180 }
181
182 if (regs) {
183 perf_callchain_store(entry, PERF_CONTEXT_USER);
184 perf_callchain_user(entry, regs);
185 }
186
187exit_put:
188 put_callchain_entry(rctx);
189
190 return entry;
191}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 58690af323e..24e3a4b1c89 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -128,7 +128,7 @@ enum event_type_t {
128 * perf_sched_events : >0 events exist 128 * perf_sched_events : >0 events exist
129 * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu 129 * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu
130 */ 130 */
131struct jump_label_key perf_sched_events __read_mostly; 131struct jump_label_key_deferred perf_sched_events __read_mostly;
132static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); 132static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
133 133
134static atomic_t nr_mmap_events __read_mostly; 134static atomic_t nr_mmap_events __read_mostly;
@@ -1130,6 +1130,8 @@ event_sched_out(struct perf_event *event,
1130 if (!is_software_event(event)) 1130 if (!is_software_event(event))
1131 cpuctx->active_oncpu--; 1131 cpuctx->active_oncpu--;
1132 ctx->nr_active--; 1132 ctx->nr_active--;
1133 if (event->attr.freq && event->attr.sample_freq)
1134 ctx->nr_freq--;
1133 if (event->attr.exclusive || !cpuctx->active_oncpu) 1135 if (event->attr.exclusive || !cpuctx->active_oncpu)
1134 cpuctx->exclusive = 0; 1136 cpuctx->exclusive = 0;
1135} 1137}
@@ -1325,6 +1327,7 @@ retry:
1325 } 1327 }
1326 raw_spin_unlock_irq(&ctx->lock); 1328 raw_spin_unlock_irq(&ctx->lock);
1327} 1329}
1330EXPORT_SYMBOL_GPL(perf_event_disable);
1328 1331
1329static void perf_set_shadow_time(struct perf_event *event, 1332static void perf_set_shadow_time(struct perf_event *event,
1330 struct perf_event_context *ctx, 1333 struct perf_event_context *ctx,
@@ -1406,6 +1409,8 @@ event_sched_in(struct perf_event *event,
1406 if (!is_software_event(event)) 1409 if (!is_software_event(event))
1407 cpuctx->active_oncpu++; 1410 cpuctx->active_oncpu++;
1408 ctx->nr_active++; 1411 ctx->nr_active++;
1412 if (event->attr.freq && event->attr.sample_freq)
1413 ctx->nr_freq++;
1409 1414
1410 if (event->attr.exclusive) 1415 if (event->attr.exclusive)
1411 cpuctx->exclusive = 1; 1416 cpuctx->exclusive = 1;
@@ -1662,8 +1667,7 @@ retry:
1662 * Note: this works for group members as well as group leaders 1667 * Note: this works for group members as well as group leaders
1663 * since the non-leader members' sibling_lists will be empty. 1668 * since the non-leader members' sibling_lists will be empty.
1664 */ 1669 */
1665static void __perf_event_mark_enabled(struct perf_event *event, 1670static void __perf_event_mark_enabled(struct perf_event *event)
1666 struct perf_event_context *ctx)
1667{ 1671{
1668 struct perf_event *sub; 1672 struct perf_event *sub;
1669 u64 tstamp = perf_event_time(event); 1673 u64 tstamp = perf_event_time(event);
@@ -1701,7 +1705,7 @@ static int __perf_event_enable(void *info)
1701 */ 1705 */
1702 perf_cgroup_set_timestamp(current, ctx); 1706 perf_cgroup_set_timestamp(current, ctx);
1703 1707
1704 __perf_event_mark_enabled(event, ctx); 1708 __perf_event_mark_enabled(event);
1705 1709
1706 if (!event_filter_match(event)) { 1710 if (!event_filter_match(event)) {
1707 if (is_cgroup_event(event)) 1711 if (is_cgroup_event(event))
@@ -1782,7 +1786,7 @@ void perf_event_enable(struct perf_event *event)
1782 1786
1783retry: 1787retry:
1784 if (!ctx->is_active) { 1788 if (!ctx->is_active) {
1785 __perf_event_mark_enabled(event, ctx); 1789 __perf_event_mark_enabled(event);
1786 goto out; 1790 goto out;
1787 } 1791 }
1788 1792
@@ -1809,6 +1813,7 @@ retry:
1809out: 1813out:
1810 raw_spin_unlock_irq(&ctx->lock); 1814 raw_spin_unlock_irq(&ctx->lock);
1811} 1815}
1816EXPORT_SYMBOL_GPL(perf_event_enable);
1812 1817
1813int perf_event_refresh(struct perf_event *event, int refresh) 1818int perf_event_refresh(struct perf_event *event, int refresh)
1814{ 1819{
@@ -2327,6 +2332,9 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period)
2327 u64 interrupts, now; 2332 u64 interrupts, now;
2328 s64 delta; 2333 s64 delta;
2329 2334
2335 if (!ctx->nr_freq)
2336 return;
2337
2330 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { 2338 list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
2331 if (event->state != PERF_EVENT_STATE_ACTIVE) 2339 if (event->state != PERF_EVENT_STATE_ACTIVE)
2332 continue; 2340 continue;
@@ -2382,12 +2390,14 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx)
2382{ 2390{
2383 u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC; 2391 u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC;
2384 struct perf_event_context *ctx = NULL; 2392 struct perf_event_context *ctx = NULL;
2385 int rotate = 0, remove = 1; 2393 int rotate = 0, remove = 1, freq = 0;
2386 2394
2387 if (cpuctx->ctx.nr_events) { 2395 if (cpuctx->ctx.nr_events) {
2388 remove = 0; 2396 remove = 0;
2389 if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active) 2397 if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active)
2390 rotate = 1; 2398 rotate = 1;
2399 if (cpuctx->ctx.nr_freq)
2400 freq = 1;
2391 } 2401 }
2392 2402
2393 ctx = cpuctx->task_ctx; 2403 ctx = cpuctx->task_ctx;
@@ -2395,33 +2405,40 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx)
2395 remove = 0; 2405 remove = 0;
2396 if (ctx->nr_events != ctx->nr_active) 2406 if (ctx->nr_events != ctx->nr_active)
2397 rotate = 1; 2407 rotate = 1;
2408 if (ctx->nr_freq)
2409 freq = 1;
2398 } 2410 }
2399 2411
2412 if (!rotate && !freq)
2413 goto done;
2414
2400 perf_ctx_lock(cpuctx, cpuctx->task_ctx); 2415 perf_ctx_lock(cpuctx, cpuctx->task_ctx);
2401 perf_pmu_disable(cpuctx->ctx.pmu); 2416 perf_pmu_disable(cpuctx->ctx.pmu);
2402 perf_ctx_adjust_freq(&cpuctx->ctx, interval);
2403 if (ctx)
2404 perf_ctx_adjust_freq(ctx, interval);
2405 2417
2406 if (!rotate) 2418 if (freq) {
2407 goto done; 2419 perf_ctx_adjust_freq(&cpuctx->ctx, interval);
2420 if (ctx)
2421 perf_ctx_adjust_freq(ctx, interval);
2422 }
2408 2423
2409 cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); 2424 if (rotate) {
2410 if (ctx) 2425 cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
2411 ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE); 2426 if (ctx)
2427 ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE);
2412 2428
2413 rotate_ctx(&cpuctx->ctx); 2429 rotate_ctx(&cpuctx->ctx);
2414 if (ctx) 2430 if (ctx)
2415 rotate_ctx(ctx); 2431 rotate_ctx(ctx);
2416 2432
2417 perf_event_sched_in(cpuctx, ctx, current); 2433 perf_event_sched_in(cpuctx, ctx, current);
2434 }
2435
2436 perf_pmu_enable(cpuctx->ctx.pmu);
2437 perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
2418 2438
2419done: 2439done:
2420 if (remove) 2440 if (remove)
2421 list_del_init(&cpuctx->rotation_list); 2441 list_del_init(&cpuctx->rotation_list);
2422
2423 perf_pmu_enable(cpuctx->ctx.pmu);
2424 perf_ctx_unlock(cpuctx, cpuctx->task_ctx);
2425} 2442}
2426 2443
2427void perf_event_task_tick(void) 2444void perf_event_task_tick(void)
@@ -2448,7 +2465,7 @@ static int event_enable_on_exec(struct perf_event *event,
2448 if (event->state >= PERF_EVENT_STATE_INACTIVE) 2465 if (event->state >= PERF_EVENT_STATE_INACTIVE)
2449 return 0; 2466 return 0;
2450 2467
2451 __perf_event_mark_enabled(event, ctx); 2468 __perf_event_mark_enabled(event);
2452 2469
2453 return 1; 2470 return 1;
2454} 2471}
@@ -2480,13 +2497,7 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
2480 raw_spin_lock(&ctx->lock); 2497 raw_spin_lock(&ctx->lock);
2481 task_ctx_sched_out(ctx); 2498 task_ctx_sched_out(ctx);
2482 2499
2483 list_for_each_entry(event, &ctx->pinned_groups, group_entry) { 2500 list_for_each_entry(event, &ctx->event_list, event_entry) {
2484 ret = event_enable_on_exec(event, ctx);
2485 if (ret)
2486 enabled = 1;
2487 }
2488
2489 list_for_each_entry(event, &ctx->flexible_groups, group_entry) {
2490 ret = event_enable_on_exec(event, ctx); 2501 ret = event_enable_on_exec(event, ctx);
2491 if (ret) 2502 if (ret)
2492 enabled = 1; 2503 enabled = 1;
@@ -2574,215 +2585,6 @@ static u64 perf_event_read(struct perf_event *event)
2574} 2585}
2575 2586
2576/* 2587/*
2577 * Callchain support
2578 */
2579
2580struct callchain_cpus_entries {
2581 struct rcu_head rcu_head;
2582 struct perf_callchain_entry *cpu_entries[0];
2583};
2584
2585static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]);
2586static atomic_t nr_callchain_events;
2587static DEFINE_MUTEX(callchain_mutex);
2588struct callchain_cpus_entries *callchain_cpus_entries;
2589
2590
2591__weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
2592 struct pt_regs *regs)
2593{
2594}
2595
2596__weak void perf_callchain_user(struct perf_callchain_entry *entry,
2597 struct pt_regs *regs)
2598{
2599}
2600
2601static void release_callchain_buffers_rcu(struct rcu_head *head)
2602{
2603 struct callchain_cpus_entries *entries;
2604 int cpu;
2605
2606 entries = container_of(head, struct callchain_cpus_entries, rcu_head);
2607
2608 for_each_possible_cpu(cpu)
2609 kfree(entries->cpu_entries[cpu]);
2610
2611 kfree(entries);
2612}
2613
2614static void release_callchain_buffers(void)
2615{
2616 struct callchain_cpus_entries *entries;
2617
2618 entries = callchain_cpus_entries;
2619 rcu_assign_pointer(callchain_cpus_entries, NULL);
2620 call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
2621}
2622
2623static int alloc_callchain_buffers(void)
2624{
2625 int cpu;
2626 int size;
2627 struct callchain_cpus_entries *entries;
2628
2629 /*
2630 * We can't use the percpu allocation API for data that can be
2631 * accessed from NMI. Use a temporary manual per cpu allocation
2632 * until that gets sorted out.
2633 */
2634 size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]);
2635
2636 entries = kzalloc(size, GFP_KERNEL);
2637 if (!entries)
2638 return -ENOMEM;
2639
2640 size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS;
2641
2642 for_each_possible_cpu(cpu) {
2643 entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL,
2644 cpu_to_node(cpu));
2645 if (!entries->cpu_entries[cpu])
2646 goto fail;
2647 }
2648
2649 rcu_assign_pointer(callchain_cpus_entries, entries);
2650
2651 return 0;
2652
2653fail:
2654 for_each_possible_cpu(cpu)
2655 kfree(entries->cpu_entries[cpu]);
2656 kfree(entries);
2657
2658 return -ENOMEM;
2659}
2660
2661static int get_callchain_buffers(void)
2662{
2663 int err = 0;
2664 int count;
2665
2666 mutex_lock(&callchain_mutex);
2667
2668 count = atomic_inc_return(&nr_callchain_events);
2669 if (WARN_ON_ONCE(count < 1)) {
2670 err = -EINVAL;
2671 goto exit;
2672 }
2673
2674 if (count > 1) {
2675 /* If the allocation failed, give up */
2676 if (!callchain_cpus_entries)
2677 err = -ENOMEM;
2678 goto exit;
2679 }
2680
2681 err = alloc_callchain_buffers();
2682 if (err)
2683 release_callchain_buffers();
2684exit:
2685 mutex_unlock(&callchain_mutex);
2686
2687 return err;
2688}
2689
2690static void put_callchain_buffers(void)
2691{
2692 if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) {
2693 release_callchain_buffers();
2694 mutex_unlock(&callchain_mutex);
2695 }
2696}
2697
2698static int get_recursion_context(int *recursion)
2699{
2700 int rctx;
2701
2702 if (in_nmi())
2703 rctx = 3;
2704 else if (in_irq())
2705 rctx = 2;
2706 else if (in_softirq())
2707 rctx = 1;
2708 else
2709 rctx = 0;
2710
2711 if (recursion[rctx])
2712 return -1;
2713
2714 recursion[rctx]++;
2715 barrier();
2716
2717 return rctx;
2718}
2719
2720static inline void put_recursion_context(int *recursion, int rctx)
2721{
2722 barrier();
2723 recursion[rctx]--;
2724}
2725
2726static struct perf_callchain_entry *get_callchain_entry(int *rctx)
2727{
2728 int cpu;
2729 struct callchain_cpus_entries *entries;
2730
2731 *rctx = get_recursion_context(__get_cpu_var(callchain_recursion));
2732 if (*rctx == -1)
2733 return NULL;
2734
2735 entries = rcu_dereference(callchain_cpus_entries);
2736 if (!entries)
2737 return NULL;
2738
2739 cpu = smp_processor_id();
2740
2741 return &entries->cpu_entries[cpu][*rctx];
2742}
2743
2744static void
2745put_callchain_entry(int rctx)
2746{
2747 put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
2748}
2749
2750static struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
2751{
2752 int rctx;
2753 struct perf_callchain_entry *entry;
2754
2755
2756 entry = get_callchain_entry(&rctx);
2757 if (rctx == -1)
2758 return NULL;
2759
2760 if (!entry)
2761 goto exit_put;
2762
2763 entry->nr = 0;
2764
2765 if (!user_mode(regs)) {
2766 perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
2767 perf_callchain_kernel(entry, regs);
2768 if (current->mm)
2769 regs = task_pt_regs(current);
2770 else
2771 regs = NULL;
2772 }
2773
2774 if (regs) {
2775 perf_callchain_store(entry, PERF_CONTEXT_USER);
2776 perf_callchain_user(entry, regs);
2777 }
2778
2779exit_put:
2780 put_callchain_entry(rctx);
2781
2782 return entry;
2783}
2784
2785/*
2786 * Initialize the perf_event context in a task_struct: 2588 * Initialize the perf_event context in a task_struct:
2787 */ 2589 */
2788static void __perf_event_init_context(struct perf_event_context *ctx) 2590static void __perf_event_init_context(struct perf_event_context *ctx)
@@ -2946,7 +2748,7 @@ static void free_event(struct perf_event *event)
2946 2748
2947 if (!event->parent) { 2749 if (!event->parent) {
2948 if (event->attach_state & PERF_ATTACH_TASK) 2750 if (event->attach_state & PERF_ATTACH_TASK)
2949 jump_label_dec(&perf_sched_events); 2751 jump_label_dec_deferred(&perf_sched_events);
2950 if (event->attr.mmap || event->attr.mmap_data) 2752 if (event->attr.mmap || event->attr.mmap_data)
2951 atomic_dec(&nr_mmap_events); 2753 atomic_dec(&nr_mmap_events);
2952 if (event->attr.comm) 2754 if (event->attr.comm)
@@ -2957,7 +2759,7 @@ static void free_event(struct perf_event *event)
2957 put_callchain_buffers(); 2759 put_callchain_buffers();
2958 if (is_cgroup_event(event)) { 2760 if (is_cgroup_event(event)) {
2959 atomic_dec(&per_cpu(perf_cgroup_events, event->cpu)); 2761 atomic_dec(&per_cpu(perf_cgroup_events, event->cpu));
2960 jump_label_dec(&perf_sched_events); 2762 jump_label_dec_deferred(&perf_sched_events);
2961 } 2763 }
2962 } 2764 }
2963 2765
@@ -4820,7 +4622,6 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow,
4820 struct hw_perf_event *hwc = &event->hw; 4622 struct hw_perf_event *hwc = &event->hw;
4821 int throttle = 0; 4623 int throttle = 0;
4822 4624
4823 data->period = event->hw.last_period;
4824 if (!overflow) 4625 if (!overflow)
4825 overflow = perf_swevent_set_period(event); 4626 overflow = perf_swevent_set_period(event);
4826 4627
@@ -4854,6 +4655,12 @@ static void perf_swevent_event(struct perf_event *event, u64 nr,
4854 if (!is_sampling_event(event)) 4655 if (!is_sampling_event(event))
4855 return; 4656 return;
4856 4657
4658 if ((event->attr.sample_type & PERF_SAMPLE_PERIOD) && !event->attr.freq) {
4659 data->period = nr;
4660 return perf_swevent_overflow(event, 1, data, regs);
4661 } else
4662 data->period = event->hw.last_period;
4663
4857 if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq) 4664 if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq)
4858 return perf_swevent_overflow(event, 1, data, regs); 4665 return perf_swevent_overflow(event, 1, data, regs);
4859 4666
@@ -5981,7 +5788,7 @@ done:
5981 5788
5982 if (!event->parent) { 5789 if (!event->parent) {
5983 if (event->attach_state & PERF_ATTACH_TASK) 5790 if (event->attach_state & PERF_ATTACH_TASK)
5984 jump_label_inc(&perf_sched_events); 5791 jump_label_inc(&perf_sched_events.key);
5985 if (event->attr.mmap || event->attr.mmap_data) 5792 if (event->attr.mmap || event->attr.mmap_data)
5986 atomic_inc(&nr_mmap_events); 5793 atomic_inc(&nr_mmap_events);
5987 if (event->attr.comm) 5794 if (event->attr.comm)
@@ -6219,7 +6026,7 @@ SYSCALL_DEFINE5(perf_event_open,
6219 * - that may need work on context switch 6026 * - that may need work on context switch
6220 */ 6027 */
6221 atomic_inc(&per_cpu(perf_cgroup_events, event->cpu)); 6028 atomic_inc(&per_cpu(perf_cgroup_events, event->cpu));
6222 jump_label_inc(&perf_sched_events); 6029 jump_label_inc(&perf_sched_events.key);
6223 } 6030 }
6224 6031
6225 /* 6032 /*
@@ -7065,6 +6872,9 @@ void __init perf_event_init(void)
7065 6872
7066 ret = init_hw_breakpoint(); 6873 ret = init_hw_breakpoint();
7067 WARN(ret, "hw_breakpoint initialization failed with: %d", ret); 6874 WARN(ret, "hw_breakpoint initialization failed with: %d", ret);
6875
6876 /* do not patch jump label more than once per second */
6877 jump_label_rate_limit(&perf_sched_events, HZ);
7068} 6878}
7069 6879
7070static int __init perf_event_sysfs_init(void) 6880static int __init perf_event_sysfs_init(void)
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index 64568a69937..b0b107f90af 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -1,6 +1,10 @@
1#ifndef _KERNEL_EVENTS_INTERNAL_H 1#ifndef _KERNEL_EVENTS_INTERNAL_H
2#define _KERNEL_EVENTS_INTERNAL_H 2#define _KERNEL_EVENTS_INTERNAL_H
3 3
4#include <linux/hardirq.h>
5
6/* Buffer handling */
7
4#define RING_BUFFER_WRITABLE 0x01 8#define RING_BUFFER_WRITABLE 0x01
5 9
6struct ring_buffer { 10struct ring_buffer {
@@ -67,7 +71,7 @@ static inline int page_order(struct ring_buffer *rb)
67} 71}
68#endif 72#endif
69 73
70static unsigned long perf_data_size(struct ring_buffer *rb) 74static inline unsigned long perf_data_size(struct ring_buffer *rb)
71{ 75{
72 return rb->nr_pages << (PAGE_SHIFT + page_order(rb)); 76 return rb->nr_pages << (PAGE_SHIFT + page_order(rb));
73} 77}
@@ -96,4 +100,37 @@ __output_copy(struct perf_output_handle *handle,
96 } while (len); 100 } while (len);
97} 101}
98 102
103/* Callchain handling */
104extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
105extern int get_callchain_buffers(void);
106extern void put_callchain_buffers(void);
107
108static inline int get_recursion_context(int *recursion)
109{
110 int rctx;
111
112 if (in_nmi())
113 rctx = 3;
114 else if (in_irq())
115 rctx = 2;
116 else if (in_softirq())
117 rctx = 1;
118 else
119 rctx = 0;
120
121 if (recursion[rctx])
122 return -1;
123
124 recursion[rctx]++;
125 barrier();
126
127 return rctx;
128}
129
130static inline void put_recursion_context(int *recursion, int rctx)
131{
132 barrier();
133 recursion[rctx]--;
134}
135
99#endif /* _KERNEL_EVENTS_INTERNAL_H */ 136#endif /* _KERNEL_EVENTS_INTERNAL_H */
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index 2af9027106a..01d3b70fc98 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -73,16 +73,47 @@ void jump_label_inc(struct jump_label_key *key)
73} 73}
74EXPORT_SYMBOL_GPL(jump_label_inc); 74EXPORT_SYMBOL_GPL(jump_label_inc);
75 75
76void jump_label_dec(struct jump_label_key *key) 76static void __jump_label_dec(struct jump_label_key *key,
77 unsigned long rate_limit, struct delayed_work *work)
77{ 78{
78 if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) 79 if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex))
79 return; 80 return;
80 81
81 jump_label_update(key, JUMP_LABEL_DISABLE); 82 if (rate_limit) {
83 atomic_inc(&key->enabled);
84 schedule_delayed_work(work, rate_limit);
85 } else
86 jump_label_update(key, JUMP_LABEL_DISABLE);
87
82 jump_label_unlock(); 88 jump_label_unlock();
83} 89}
84EXPORT_SYMBOL_GPL(jump_label_dec); 90EXPORT_SYMBOL_GPL(jump_label_dec);
85 91
92static void jump_label_update_timeout(struct work_struct *work)
93{
94 struct jump_label_key_deferred *key =
95 container_of(work, struct jump_label_key_deferred, work.work);
96 __jump_label_dec(&key->key, 0, NULL);
97}
98
99void jump_label_dec(struct jump_label_key *key)
100{
101 __jump_label_dec(key, 0, NULL);
102}
103
104void jump_label_dec_deferred(struct jump_label_key_deferred *key)
105{
106 __jump_label_dec(&key->key, key->timeout, &key->work);
107}
108
109
110void jump_label_rate_limit(struct jump_label_key_deferred *key,
111 unsigned long rl)
112{
113 key->timeout = rl;
114 INIT_DELAYED_WORK(&key->work, jump_label_update_timeout);
115}
116
86static int addr_conflict(struct jump_entry *entry, void *start, void *end) 117static int addr_conflict(struct jump_entry *entry, void *start, void *end)
87{ 118{
88 if (entry->code <= (unsigned long)end && 119 if (entry->code <= (unsigned long)end &&
@@ -113,7 +144,7 @@ static int __jump_label_text_reserved(struct jump_entry *iter_start,
113 * running code can override this to make the non-live update case 144 * running code can override this to make the non-live update case
114 * cheaper. 145 * cheaper.
115 */ 146 */
116void __weak arch_jump_label_transform_static(struct jump_entry *entry, 147void __weak __init_or_module arch_jump_label_transform_static(struct jump_entry *entry,
117 enum jump_label_type type) 148 enum jump_label_type type)
118{ 149{
119 arch_jump_label_transform(entry, type); 150 arch_jump_label_transform(entry, type);
@@ -219,8 +250,13 @@ void jump_label_apply_nops(struct module *mod)
219 if (iter_start == iter_stop) 250 if (iter_start == iter_stop)
220 return; 251 return;
221 252
222 for (iter = iter_start; iter < iter_stop; iter++) 253 for (iter = iter_start; iter < iter_stop; iter++) {
223 arch_jump_label_transform_static(iter, JUMP_LABEL_DISABLE); 254 struct jump_label_key *iterk;
255
256 iterk = (struct jump_label_key *)(unsigned long)iter->key;
257 arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ?
258 JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE);
259 }
224} 260}
225 261
226static int jump_label_add_module(struct module *mod) 262static int jump_label_add_module(struct module *mod)
@@ -260,8 +296,7 @@ static int jump_label_add_module(struct module *mod)
260 key->next = jlm; 296 key->next = jlm;
261 297
262 if (jump_label_enabled(key)) 298 if (jump_label_enabled(key))
263 __jump_label_update(key, iter, iter_stop, 299 __jump_label_update(key, iter, iter_stop, JUMP_LABEL_ENABLE);
264 JUMP_LABEL_ENABLE);
265 } 300 }
266 301
267 return 0; 302 return 0;
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index b2e08c932d9..24f176c9fc9 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -499,36 +499,32 @@ void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS])
499 usage[i] = '\0'; 499 usage[i] = '\0';
500} 500}
501 501
502static int __print_lock_name(struct lock_class *class) 502static void __print_lock_name(struct lock_class *class)
503{ 503{
504 char str[KSYM_NAME_LEN]; 504 char str[KSYM_NAME_LEN];
505 const char *name; 505 const char *name;
506 506
507 name = class->name; 507 name = class->name;
508 if (!name)
509 name = __get_key_name(class->key, str);
510
511 return printk("%s", name);
512}
513
514static void print_lock_name(struct lock_class *class)
515{
516 char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS];
517 const char *name;
518
519 get_usage_chars(class, usage);
520
521 name = class->name;
522 if (!name) { 508 if (!name) {
523 name = __get_key_name(class->key, str); 509 name = __get_key_name(class->key, str);
524 printk(" (%s", name); 510 printk("%s", name);
525 } else { 511 } else {
526 printk(" (%s", name); 512 printk("%s", name);
527 if (class->name_version > 1) 513 if (class->name_version > 1)
528 printk("#%d", class->name_version); 514 printk("#%d", class->name_version);
529 if (class->subclass) 515 if (class->subclass)
530 printk("/%d", class->subclass); 516 printk("/%d", class->subclass);
531 } 517 }
518}
519
520static void print_lock_name(struct lock_class *class)
521{
522 char usage[LOCK_USAGE_CHARS];
523
524 get_usage_chars(class, usage);
525
526 printk(" (");
527 __print_lock_name(class);
532 printk("){%s}", usage); 528 printk("){%s}", usage);
533} 529}
534 530
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index f2bd275bb60..7392070ffc3 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -338,7 +338,8 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
338/* trace_flags holds trace_options default values */ 338/* trace_flags holds trace_options default values */
339unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | 339unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
340 TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME | 340 TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
341 TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE; 341 TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
342 TRACE_ITER_IRQ_INFO;
342 343
343static int trace_stop_count; 344static int trace_stop_count;
344static DEFINE_RAW_SPINLOCK(tracing_start_lock); 345static DEFINE_RAW_SPINLOCK(tracing_start_lock);
@@ -426,6 +427,7 @@ static const char *trace_options[] = {
426 "record-cmd", 427 "record-cmd",
427 "overwrite", 428 "overwrite",
428 "disable_on_free", 429 "disable_on_free",
430 "irq-info",
429 NULL 431 NULL
430}; 432};
431 433
@@ -1843,6 +1845,33 @@ static void s_stop(struct seq_file *m, void *p)
1843 trace_event_read_unlock(); 1845 trace_event_read_unlock();
1844} 1846}
1845 1847
1848static void
1849get_total_entries(struct trace_array *tr, unsigned long *total, unsigned long *entries)
1850{
1851 unsigned long count;
1852 int cpu;
1853
1854 *total = 0;
1855 *entries = 0;
1856
1857 for_each_tracing_cpu(cpu) {
1858 count = ring_buffer_entries_cpu(tr->buffer, cpu);
1859 /*
1860 * If this buffer has skipped entries, then we hold all
1861 * entries for the trace and we need to ignore the
1862 * ones before the time stamp.
1863 */
1864 if (tr->data[cpu]->skipped_entries) {
1865 count -= tr->data[cpu]->skipped_entries;
1866 /* total is the same as the entries */
1867 *total += count;
1868 } else
1869 *total += count +
1870 ring_buffer_overrun_cpu(tr->buffer, cpu);
1871 *entries += count;
1872 }
1873}
1874
1846static void print_lat_help_header(struct seq_file *m) 1875static void print_lat_help_header(struct seq_file *m)
1847{ 1876{
1848 seq_puts(m, "# _------=> CPU# \n"); 1877 seq_puts(m, "# _------=> CPU# \n");
@@ -1855,12 +1884,35 @@ static void print_lat_help_header(struct seq_file *m)
1855 seq_puts(m, "# \\ / ||||| \\ | / \n"); 1884 seq_puts(m, "# \\ / ||||| \\ | / \n");
1856} 1885}
1857 1886
1858static void print_func_help_header(struct seq_file *m) 1887static void print_event_info(struct trace_array *tr, struct seq_file *m)
1888{
1889 unsigned long total;
1890 unsigned long entries;
1891
1892 get_total_entries(tr, &total, &entries);
1893 seq_printf(m, "# entries-in-buffer/entries-written: %lu/%lu #P:%d\n",
1894 entries, total, num_online_cpus());
1895 seq_puts(m, "#\n");
1896}
1897
1898static void print_func_help_header(struct trace_array *tr, struct seq_file *m)
1859{ 1899{
1860 seq_puts(m, "# TASK-PID CPU# TIMESTAMP FUNCTION\n"); 1900 print_event_info(tr, m);
1901 seq_puts(m, "# TASK-PID CPU# TIMESTAMP FUNCTION\n");
1861 seq_puts(m, "# | | | | |\n"); 1902 seq_puts(m, "# | | | | |\n");
1862} 1903}
1863 1904
1905static void print_func_help_header_irq(struct trace_array *tr, struct seq_file *m)
1906{
1907 print_event_info(tr, m);
1908 seq_puts(m, "# _-----=> irqs-off\n");
1909 seq_puts(m, "# / _----=> need-resched\n");
1910 seq_puts(m, "# | / _---=> hardirq/softirq\n");
1911 seq_puts(m, "# || / _--=> preempt-depth\n");
1912 seq_puts(m, "# ||| / delay\n");
1913 seq_puts(m, "# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n");
1914 seq_puts(m, "# | | | |||| | |\n");
1915}
1864 1916
1865void 1917void
1866print_trace_header(struct seq_file *m, struct trace_iterator *iter) 1918print_trace_header(struct seq_file *m, struct trace_iterator *iter)
@@ -1869,32 +1921,14 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
1869 struct trace_array *tr = iter->tr; 1921 struct trace_array *tr = iter->tr;
1870 struct trace_array_cpu *data = tr->data[tr->cpu]; 1922 struct trace_array_cpu *data = tr->data[tr->cpu];
1871 struct tracer *type = current_trace; 1923 struct tracer *type = current_trace;
1872 unsigned long entries = 0; 1924 unsigned long entries;
1873 unsigned long total = 0; 1925 unsigned long total;
1874 unsigned long count;
1875 const char *name = "preemption"; 1926 const char *name = "preemption";
1876 int cpu;
1877 1927
1878 if (type) 1928 if (type)
1879 name = type->name; 1929 name = type->name;
1880 1930
1881 1931 get_total_entries(tr, &total, &entries);
1882 for_each_tracing_cpu(cpu) {
1883 count = ring_buffer_entries_cpu(tr->buffer, cpu);
1884 /*
1885 * If this buffer has skipped entries, then we hold all
1886 * entries for the trace and we need to ignore the
1887 * ones before the time stamp.
1888 */
1889 if (tr->data[cpu]->skipped_entries) {
1890 count -= tr->data[cpu]->skipped_entries;
1891 /* total is the same as the entries */
1892 total += count;
1893 } else
1894 total += count +
1895 ring_buffer_overrun_cpu(tr->buffer, cpu);
1896 entries += count;
1897 }
1898 1932
1899 seq_printf(m, "# %s latency trace v1.1.5 on %s\n", 1933 seq_printf(m, "# %s latency trace v1.1.5 on %s\n",
1900 name, UTS_RELEASE); 1934 name, UTS_RELEASE);
@@ -2140,6 +2174,21 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
2140 return print_trace_fmt(iter); 2174 return print_trace_fmt(iter);
2141} 2175}
2142 2176
2177void trace_latency_header(struct seq_file *m)
2178{
2179 struct trace_iterator *iter = m->private;
2180
2181 /* print nothing if the buffers are empty */
2182 if (trace_empty(iter))
2183 return;
2184
2185 if (iter->iter_flags & TRACE_FILE_LAT_FMT)
2186 print_trace_header(m, iter);
2187
2188 if (!(trace_flags & TRACE_ITER_VERBOSE))
2189 print_lat_help_header(m);
2190}
2191
2143void trace_default_header(struct seq_file *m) 2192void trace_default_header(struct seq_file *m)
2144{ 2193{
2145 struct trace_iterator *iter = m->private; 2194 struct trace_iterator *iter = m->private;
@@ -2155,8 +2204,12 @@ void trace_default_header(struct seq_file *m)
2155 if (!(trace_flags & TRACE_ITER_VERBOSE)) 2204 if (!(trace_flags & TRACE_ITER_VERBOSE))
2156 print_lat_help_header(m); 2205 print_lat_help_header(m);
2157 } else { 2206 } else {
2158 if (!(trace_flags & TRACE_ITER_VERBOSE)) 2207 if (!(trace_flags & TRACE_ITER_VERBOSE)) {
2159 print_func_help_header(m); 2208 if (trace_flags & TRACE_ITER_IRQ_INFO)
2209 print_func_help_header_irq(iter->tr, m);
2210 else
2211 print_func_help_header(iter->tr, m);
2212 }
2160 } 2213 }
2161} 2214}
2162 2215
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 092e1f8d18d..2c2657462ac 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -370,6 +370,7 @@ void trace_graph_function(struct trace_array *tr,
370 unsigned long ip, 370 unsigned long ip,
371 unsigned long parent_ip, 371 unsigned long parent_ip,
372 unsigned long flags, int pc); 372 unsigned long flags, int pc);
373void trace_latency_header(struct seq_file *m);
373void trace_default_header(struct seq_file *m); 374void trace_default_header(struct seq_file *m);
374void print_trace_header(struct seq_file *m, struct trace_iterator *iter); 375void print_trace_header(struct seq_file *m, struct trace_iterator *iter);
375int trace_empty(struct trace_iterator *iter); 376int trace_empty(struct trace_iterator *iter);
@@ -654,6 +655,7 @@ enum trace_iterator_flags {
654 TRACE_ITER_RECORD_CMD = 0x100000, 655 TRACE_ITER_RECORD_CMD = 0x100000,
655 TRACE_ITER_OVERWRITE = 0x200000, 656 TRACE_ITER_OVERWRITE = 0x200000,
656 TRACE_ITER_STOP_ON_FREE = 0x400000, 657 TRACE_ITER_STOP_ON_FREE = 0x400000,
658 TRACE_ITER_IRQ_INFO = 0x800000,
657}; 659};
658 660
659/* 661/*
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 95dc31efd6d..f04cc3136bd 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -27,6 +27,12 @@
27#include "trace.h" 27#include "trace.h"
28#include "trace_output.h" 28#include "trace_output.h"
29 29
30#define DEFAULT_SYS_FILTER_MESSAGE \
31 "### global filter ###\n" \
32 "# Use this to set filters for multiple events.\n" \
33 "# Only events with the given fields will be affected.\n" \
34 "# If no events are modified, an error message will be displayed here"
35
30enum filter_op_ids 36enum filter_op_ids
31{ 37{
32 OP_OR, 38 OP_OR,
@@ -646,7 +652,7 @@ void print_subsystem_event_filter(struct event_subsystem *system,
646 if (filter && filter->filter_string) 652 if (filter && filter->filter_string)
647 trace_seq_printf(s, "%s\n", filter->filter_string); 653 trace_seq_printf(s, "%s\n", filter->filter_string);
648 else 654 else
649 trace_seq_printf(s, "none\n"); 655 trace_seq_printf(s, DEFAULT_SYS_FILTER_MESSAGE "\n");
650 mutex_unlock(&event_mutex); 656 mutex_unlock(&event_mutex);
651} 657}
652 658
@@ -1838,7 +1844,10 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
1838 if (!filter) 1844 if (!filter)
1839 goto out; 1845 goto out;
1840 1846
1841 replace_filter_string(filter, filter_string); 1847 /* System filters just show a default message */
1848 kfree(filter->filter_string);
1849 filter->filter_string = NULL;
1850
1842 /* 1851 /*
1843 * No event actually uses the system filter 1852 * No event actually uses the system filter
1844 * we can free it without synchronize_sched(). 1853 * we can free it without synchronize_sched().
@@ -1848,14 +1857,12 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
1848 1857
1849 parse_init(ps, filter_ops, filter_string); 1858 parse_init(ps, filter_ops, filter_string);
1850 err = filter_parse(ps); 1859 err = filter_parse(ps);
1851 if (err) { 1860 if (err)
1852 append_filter_err(ps, system->filter); 1861 goto err_filter;
1853 goto out;
1854 }
1855 1862
1856 err = replace_system_preds(system, ps, filter_string); 1863 err = replace_system_preds(system, ps, filter_string);
1857 if (err) 1864 if (err)
1858 append_filter_err(ps, system->filter); 1865 goto err_filter;
1859 1866
1860out: 1867out:
1861 filter_opstack_clear(ps); 1868 filter_opstack_clear(ps);
@@ -1865,6 +1872,11 @@ out_unlock:
1865 mutex_unlock(&event_mutex); 1872 mutex_unlock(&event_mutex);
1866 1873
1867 return err; 1874 return err;
1875
1876err_filter:
1877 replace_filter_string(filter, filter_string);
1878 append_filter_err(ps, system->filter);
1879 goto out;
1868} 1880}
1869 1881
1870#ifdef CONFIG_PERF_EVENTS 1882#ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 20dad0d7a16..99d20e92036 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -280,9 +280,20 @@ static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
280} 280}
281 281
282static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { } 282static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { }
283static void irqsoff_print_header(struct seq_file *s) { }
284static void irqsoff_trace_open(struct trace_iterator *iter) { } 283static void irqsoff_trace_open(struct trace_iterator *iter) { }
285static void irqsoff_trace_close(struct trace_iterator *iter) { } 284static void irqsoff_trace_close(struct trace_iterator *iter) { }
285
286#ifdef CONFIG_FUNCTION_TRACER
287static void irqsoff_print_header(struct seq_file *s)
288{
289 trace_default_header(s);
290}
291#else
292static void irqsoff_print_header(struct seq_file *s)
293{
294 trace_latency_header(s);
295}
296#endif /* CONFIG_FUNCTION_TRACER */
286#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 297#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
287 298
288/* 299/*
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 51999309a6c..0d6ff355594 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -627,11 +627,23 @@ int trace_print_context(struct trace_iterator *iter)
627 unsigned long usec_rem = do_div(t, USEC_PER_SEC); 627 unsigned long usec_rem = do_div(t, USEC_PER_SEC);
628 unsigned long secs = (unsigned long)t; 628 unsigned long secs = (unsigned long)t;
629 char comm[TASK_COMM_LEN]; 629 char comm[TASK_COMM_LEN];
630 int ret;
630 631
631 trace_find_cmdline(entry->pid, comm); 632 trace_find_cmdline(entry->pid, comm);
632 633
633 return trace_seq_printf(s, "%16s-%-5d [%03d] %5lu.%06lu: ", 634 ret = trace_seq_printf(s, "%16s-%-5d [%03d] ",
634 comm, entry->pid, iter->cpu, secs, usec_rem); 635 comm, entry->pid, iter->cpu);
636 if (!ret)
637 return 0;
638
639 if (trace_flags & TRACE_ITER_IRQ_INFO) {
640 ret = trace_print_lat_fmt(s, entry);
641 if (!ret)
642 return 0;
643 }
644
645 return trace_seq_printf(s, " %5lu.%06lu: ",
646 secs, usec_rem);
635} 647}
636 648
637int trace_print_lat_context(struct trace_iterator *iter) 649int trace_print_lat_context(struct trace_iterator *iter)
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index e4a70c0c71b..ff791ea48b5 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -280,9 +280,20 @@ static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
280} 280}
281 281
282static void wakeup_graph_return(struct ftrace_graph_ret *trace) { } 282static void wakeup_graph_return(struct ftrace_graph_ret *trace) { }
283static void wakeup_print_header(struct seq_file *s) { }
284static void wakeup_trace_open(struct trace_iterator *iter) { } 283static void wakeup_trace_open(struct trace_iterator *iter) { }
285static void wakeup_trace_close(struct trace_iterator *iter) { } 284static void wakeup_trace_close(struct trace_iterator *iter) { }
285
286#ifdef CONFIG_FUNCTION_TRACER
287static void wakeup_print_header(struct seq_file *s)
288{
289 trace_default_header(s);
290}
291#else
292static void wakeup_print_header(struct seq_file *s)
293{
294 trace_latency_header(s);
295}
296#endif /* CONFIG_FUNCTION_TRACER */
286#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 297#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
287 298
288/* 299/*
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index fe6762ed56b..476029d3062 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -66,7 +66,7 @@ OPTIONS
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69-c:: 69-C::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of 71 be provided as a comma-separated list with no space: 0,1. Ranges of
72 CPUs are specified with -: 0-2. Default is to report samples on all 72 CPUs are specified with -: 0-2. Default is to report samples on all
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 212f24d672e..dc85392a5ac 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -39,7 +39,7 @@ OPTIONS
39-T:: 39-T::
40--threads:: 40--threads::
41 Show per-thread event counters 41 Show per-thread event counters
42-C:: 42-c::
43--comms=:: 43--comms=::
44 Only consider symbols in these comms. CSV that understands 44 Only consider symbols in these comms. CSV that understands
45 file://filename entries. 45 file://filename entries.
@@ -128,7 +128,7 @@ OPTIONS
128--symfs=<directory>:: 128--symfs=<directory>::
129 Look for files with symbols relative to this directory. 129 Look for files with symbols relative to this directory.
130 130
131-c:: 131-C::
132--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 132--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
133 be provided as a comma-separated list with no space: 0,1. Ranges of 133 be provided as a comma-separated list with no space: 0,1. Ranges of
134 CPUs are specified with -: 0-2. Default is to report samples on all 134 CPUs are specified with -: 0-2. Default is to report samples on all
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index dec87ecb530..7f61eaaf9ab 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -182,12 +182,17 @@ OPTIONS
182--hide-call-graph:: 182--hide-call-graph::
183 When printing symbols do not display call chain. 183 When printing symbols do not display call chain.
184 184
185-c:: 185-C::
186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
187 be provided as a comma-separated list with no space: 0,1. Ranges of 187 be provided as a comma-separated list with no space: 0,1. Ranges of
188 CPUs are specified with -: 0-2. Default is to report samples on all 188 CPUs are specified with -: 0-2. Default is to report samples on all
189 CPUs. 189 CPUs.
190 190
191-c::
192--comms=::
193 Only display events for these comms. CSV that understands
194 file://filename entries.
195
191-I:: 196-I::
192--show-info:: 197--show-info::
193 Display extended information about the perf.data file. This adds 198 Display extended information about the perf.data file. This adds
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 2c3b462f64b..b24ac40fcd5 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -8,13 +8,19 @@ perf-test - Runs sanity tests.
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf test <options>' 11'perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]'
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command does assorted sanity tests, initially through linked routines but 15This command does assorted sanity tests, initially through linked routines but
16also will look for a directory with more tests in the form of scripts. 16also will look for a directory with more tests in the form of scripts.
17 17
18To get a list of available tests use 'perf test list', specifying a test name
19fragment will show all tests that have it.
20
21To run just specific tests, inform test name fragments or the numbers obtained
22from 'perf test list'.
23
18OPTIONS 24OPTIONS
19------- 25-------
20-v:: 26-v::
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index b98e3075646..ac86d67b636 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -278,6 +278,7 @@ LIB_H += util/strbuf.h
278LIB_H += util/strlist.h 278LIB_H += util/strlist.h
279LIB_H += util/strfilter.h 279LIB_H += util/strfilter.h
280LIB_H += util/svghelper.h 280LIB_H += util/svghelper.h
281LIB_H += util/tool.h
281LIB_H += util/run-command.h 282LIB_H += util/run-command.h
282LIB_H += util/sigchain.h 283LIB_H += util/sigchain.h
283LIB_H += util/symbol.h 284LIB_H += util/symbol.h
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 46b4c24f338..d449645c5ef 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -27,32 +27,32 @@
27#include "util/sort.h" 27#include "util/sort.h"
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30#include "util/tool.h"
30 31
31#include <linux/bitmap.h> 32#include <linux/bitmap.h>
32 33
33static char const *input_name = "perf.data"; 34struct perf_annotate {
34 35 struct perf_tool tool;
35static bool force, use_tui, use_stdio; 36 char const *input_name;
36 37 bool force, use_tui, use_stdio;
37static bool full_paths; 38 bool full_paths;
38 39 bool print_line;
39static bool print_line; 40 const char *sym_hist_filter;
40 41 const char *cpu_list;
41static const char *sym_hist_filter; 42 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
42 43};
43static const char *cpu_list;
44static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
45 44
46static int perf_evlist__add_sample(struct perf_evlist *evlist, 45static int perf_evsel__add_sample(struct perf_evsel *evsel,
47 struct perf_sample *sample, 46 struct perf_sample *sample,
48 struct perf_evsel *evsel, 47 struct addr_location *al,
49 struct addr_location *al) 48 struct perf_annotate *ann)
50{ 49{
51 struct hist_entry *he; 50 struct hist_entry *he;
52 int ret; 51 int ret;
53 52
54 if (sym_hist_filter != NULL && 53 if (ann->sym_hist_filter != NULL &&
55 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { 54 (al->sym == NULL ||
55 strcmp(ann->sym_hist_filter, al->sym->name) != 0)) {
56 /* We're only interested in a symbol named sym_hist_filter */ 56 /* We're only interested in a symbol named sym_hist_filter */
57 if (al->sym != NULL) { 57 if (al->sym != NULL) {
58 rb_erase(&al->sym->rb_node, 58 rb_erase(&al->sym->rb_node,
@@ -69,8 +69,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
69 ret = 0; 69 ret = 0;
70 if (he->ms.sym != NULL) { 70 if (he->ms.sym != NULL) {
71 struct annotation *notes = symbol__annotation(he->ms.sym); 71 struct annotation *notes = symbol__annotation(he->ms.sym);
72 if (notes->src == NULL && 72 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
73 symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
74 return -ENOMEM; 73 return -ENOMEM;
75 74
76 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 75 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,
81 return ret; 80 return ret;
82} 81}
83 82
84static int process_sample_event(union perf_event *event, 83static int process_sample_event(struct perf_tool *tool,
84 union perf_event *event,
85 struct perf_sample *sample, 85 struct perf_sample *sample,
86 struct perf_evsel *evsel, 86 struct perf_evsel *evsel,
87 struct perf_session *session) 87 struct machine *machine)
88{ 88{
89 struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
89 struct addr_location al; 90 struct addr_location al;
90 91
91 if (perf_event__preprocess_sample(event, session, &al, sample, 92 if (perf_event__preprocess_sample(event, machine, &al, sample,
92 symbol__annotate_init) < 0) { 93 symbol__annotate_init) < 0) {
93 pr_warning("problem processing %d event, skipping it.\n", 94 pr_warning("problem processing %d event, skipping it.\n",
94 event->header.type); 95 event->header.type);
95 return -1; 96 return -1;
96 } 97 }
97 98
98 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 99 if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
99 return 0; 100 return 0;
100 101
101 if (!al.filtered && 102 if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) {
102 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
103 pr_warning("problem incrementing symbol count, " 103 pr_warning("problem incrementing symbol count, "
104 "skipping event\n"); 104 "skipping event\n");
105 return -1; 105 return -1;
@@ -108,14 +108,15 @@ static int process_sample_event(union perf_event *event,
108 return 0; 108 return 0;
109} 109}
110 110
111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) 111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx,
112 struct perf_annotate *ann)
112{ 113{
113 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, 114 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
114 print_line, full_paths, 0, 0); 115 ann->print_line, ann->full_paths, 0, 0);
115} 116}
116 117
117static void hists__find_annotations(struct hists *self, int evidx, 118static void hists__find_annotations(struct hists *self, int evidx,
118 int nr_events) 119 struct perf_annotate *ann)
119{ 120{
120 struct rb_node *nd = rb_first(&self->entries), *next; 121 struct rb_node *nd = rb_first(&self->entries), *next;
121 int key = K_RIGHT; 122 int key = K_RIGHT;
@@ -138,8 +139,7 @@ find_next:
138 } 139 }
139 140
140 if (use_browser > 0) { 141 if (use_browser > 0) {
141 key = hist_entry__tui_annotate(he, evidx, nr_events, 142 key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0);
142 NULL, NULL, 0);
143 switch (key) { 143 switch (key) {
144 case K_RIGHT: 144 case K_RIGHT:
145 next = rb_next(nd); 145 next = rb_next(nd);
@@ -154,7 +154,7 @@ find_next:
154 if (next != NULL) 154 if (next != NULL)
155 nd = next; 155 nd = next;
156 } else { 156 } else {
157 hist_entry__tty_annotate(he, evidx); 157 hist_entry__tty_annotate(he, evidx, ann);
158 nd = rb_next(nd); 158 nd = rb_next(nd);
159 /* 159 /*
160 * Since we have a hist_entry per IP for the same 160 * Since we have a hist_entry per IP for the same
@@ -167,33 +167,26 @@ find_next:
167 } 167 }
168} 168}
169 169
170static struct perf_event_ops event_ops = { 170static int __cmd_annotate(struct perf_annotate *ann)
171 .sample = process_sample_event,
172 .mmap = perf_event__process_mmap,
173 .comm = perf_event__process_comm,
174 .fork = perf_event__process_task,
175 .ordered_samples = true,
176 .ordering_requires_timestamps = true,
177};
178
179static int __cmd_annotate(void)
180{ 171{
181 int ret; 172 int ret;
182 struct perf_session *session; 173 struct perf_session *session;
183 struct perf_evsel *pos; 174 struct perf_evsel *pos;
184 u64 total_nr_samples; 175 u64 total_nr_samples;
185 176
186 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); 177 session = perf_session__new(ann->input_name, O_RDONLY,
178 ann->force, false, &ann->tool);
187 if (session == NULL) 179 if (session == NULL)
188 return -ENOMEM; 180 return -ENOMEM;
189 181
190 if (cpu_list) { 182 if (ann->cpu_list) {
191 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); 183 ret = perf_session__cpu_bitmap(session, ann->cpu_list,
184 ann->cpu_bitmap);
192 if (ret) 185 if (ret)
193 goto out_delete; 186 goto out_delete;
194 } 187 }
195 188
196 ret = perf_session__process_events(session, &event_ops); 189 ret = perf_session__process_events(session, &ann->tool);
197 if (ret) 190 if (ret)
198 goto out_delete; 191 goto out_delete;
199 192
@@ -217,13 +210,12 @@ static int __cmd_annotate(void)
217 total_nr_samples += nr_samples; 210 total_nr_samples += nr_samples;
218 hists__collapse_resort(hists); 211 hists__collapse_resort(hists);
219 hists__output_resort(hists); 212 hists__output_resort(hists);
220 hists__find_annotations(hists, pos->idx, 213 hists__find_annotations(hists, pos->idx, ann);
221 session->evlist->nr_entries);
222 } 214 }
223 } 215 }
224 216
225 if (total_nr_samples == 0) { 217 if (total_nr_samples == 0) {
226 ui__warning("The %s file has no samples!\n", input_name); 218 ui__warning("The %s file has no samples!\n", ann->input_name);
227 goto out_delete; 219 goto out_delete;
228 } 220 }
229out_delete: 221out_delete:
@@ -247,29 +239,42 @@ static const char * const annotate_usage[] = {
247 NULL 239 NULL
248}; 240};
249 241
250static const struct option options[] = { 242int cmd_annotate(int argc, const char **argv, const char *prefix __used)
251 OPT_STRING('i', "input", &input_name, "file", 243{
244 struct perf_annotate annotate = {
245 .tool = {
246 .sample = process_sample_event,
247 .mmap = perf_event__process_mmap,
248 .comm = perf_event__process_comm,
249 .fork = perf_event__process_task,
250 .ordered_samples = true,
251 .ordering_requires_timestamps = true,
252 },
253 .input_name = "perf.data",
254 };
255 const struct option options[] = {
256 OPT_STRING('i', "input", &annotate.input_name, "file",
252 "input file name"), 257 "input file name"),
253 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 258 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
254 "only consider symbols in these dsos"), 259 "only consider symbols in these dsos"),
255 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 260 OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
256 "symbol to annotate"), 261 "symbol to annotate"),
257 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 262 OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"),
258 OPT_INCR('v', "verbose", &verbose, 263 OPT_INCR('v', "verbose", &verbose,
259 "be more verbose (show symbol address, etc)"), 264 "be more verbose (show symbol address, etc)"),
260 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 265 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
261 "dump raw trace in ASCII"), 266 "dump raw trace in ASCII"),
262 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), 267 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
263 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 268 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
264 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 269 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
265 "file", "vmlinux pathname"), 270 "file", "vmlinux pathname"),
266 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 271 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
267 "load module symbols - WARNING: use only with -k and LIVE kernel"), 272 "load module symbols - WARNING: use only with -k and LIVE kernel"),
268 OPT_BOOLEAN('l', "print-line", &print_line, 273 OPT_BOOLEAN('l', "print-line", &annotate.print_line,
269 "print matching source lines (may be slow)"), 274 "print matching source lines (may be slow)"),
270 OPT_BOOLEAN('P', "full-paths", &full_paths, 275 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths,
271 "Don't shorten the displayed pathnames"), 276 "Don't shorten the displayed pathnames"),
272 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 277 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
273 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 278 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
274 "Look for files with symbols relative to this directory"), 279 "Look for files with symbols relative to this directory"),
275 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, 280 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
@@ -279,15 +284,13 @@ static const struct option options[] = {
279 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 284 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
280 "Specify disassembler style (e.g. -M intel for intel syntax)"), 285 "Specify disassembler style (e.g. -M intel for intel syntax)"),
281 OPT_END() 286 OPT_END()
282}; 287 };
283 288
284int cmd_annotate(int argc, const char **argv, const char *prefix __used)
285{
286 argc = parse_options(argc, argv, options, annotate_usage, 0); 289 argc = parse_options(argc, argv, options, annotate_usage, 0);
287 290
288 if (use_stdio) 291 if (annotate.use_stdio)
289 use_browser = 0; 292 use_browser = 0;
290 else if (use_tui) 293 else if (annotate.use_tui)
291 use_browser = 1; 294 use_browser = 1;
292 295
293 setup_browser(true); 296 setup_browser(true);
@@ -308,7 +311,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
308 if (argc > 1) 311 if (argc > 1)
309 usage_with_options(annotate_usage, options); 312 usage_with_options(annotate_usage, options);
310 313
311 sym_hist_filter = argv[0]; 314 annotate.sym_hist_filter = argv[0];
312 } 315 }
313 316
314 if (field_sep && *field_sep == '.') { 317 if (field_sep && *field_sep == '.') {
@@ -316,5 +319,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
316 return -1; 319 return -1;
317 } 320 }
318 321
319 return __cmd_annotate(); 322 return __cmd_annotate(&annotate);
320} 323}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index b39f3a1ee7d..4f19513d7dd 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -9,7 +9,9 @@
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/event.h" 10#include "util/event.h"
11#include "util/hist.h" 11#include "util/hist.h"
12#include "util/evsel.h"
12#include "util/session.h" 13#include "util/session.h"
14#include "util/tool.h"
13#include "util/sort.h" 15#include "util/sort.h"
14#include "util/symbol.h" 16#include "util/symbol.h"
15#include "util/util.h" 17#include "util/util.h"
@@ -30,14 +32,15 @@ static int hists__add_entry(struct hists *self,
30 return -ENOMEM; 32 return -ENOMEM;
31} 33}
32 34
33static int diff__process_sample_event(union perf_event *event, 35static int diff__process_sample_event(struct perf_tool *tool __used,
36 union perf_event *event,
34 struct perf_sample *sample, 37 struct perf_sample *sample,
35 struct perf_evsel *evsel __used, 38 struct perf_evsel *evsel __used,
36 struct perf_session *session) 39 struct machine *machine)
37{ 40{
38 struct addr_location al; 41 struct addr_location al;
39 42
40 if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { 43 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
41 pr_warning("problem processing %d event, skipping it.\n", 44 pr_warning("problem processing %d event, skipping it.\n",
42 event->header.type); 45 event->header.type);
43 return -1; 46 return -1;
@@ -46,16 +49,16 @@ static int diff__process_sample_event(union perf_event *event,
46 if (al.filtered || al.sym == NULL) 49 if (al.filtered || al.sym == NULL)
47 return 0; 50 return 0;
48 51
49 if (hists__add_entry(&session->hists, &al, sample->period)) { 52 if (hists__add_entry(&evsel->hists, &al, sample->period)) {
50 pr_warning("problem incrementing symbol period, skipping event\n"); 53 pr_warning("problem incrementing symbol period, skipping event\n");
51 return -1; 54 return -1;
52 } 55 }
53 56
54 session->hists.stats.total_period += sample->period; 57 evsel->hists.stats.total_period += sample->period;
55 return 0; 58 return 0;
56} 59}
57 60
58static struct perf_event_ops event_ops = { 61static struct perf_tool perf_diff = {
59 .sample = diff__process_sample_event, 62 .sample = diff__process_sample_event,
60 .mmap = perf_event__process_mmap, 63 .mmap = perf_event__process_mmap,
61 .comm = perf_event__process_comm, 64 .comm = perf_event__process_comm,
@@ -145,13 +148,13 @@ static int __cmd_diff(void)
145 int ret, i; 148 int ret, i;
146 struct perf_session *session[2]; 149 struct perf_session *session[2];
147 150
148 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops); 151 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff);
149 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops); 152 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff);
150 if (session[0] == NULL || session[1] == NULL) 153 if (session[0] == NULL || session[1] == NULL)
151 return -ENOMEM; 154 return -ENOMEM;
152 155
153 for (i = 0; i < 2; ++i) { 156 for (i = 0; i < 2; ++i) {
154 ret = perf_session__process_events(session[i], &event_ops); 157 ret = perf_session__process_events(session[i], &perf_diff);
155 if (ret) 158 if (ret)
156 goto out_delete; 159 goto out_delete;
157 } 160 }
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 8dfc12bb119..09c106193e6 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -9,6 +9,7 @@
9 9
10#include "perf.h" 10#include "perf.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h"
12#include "util/debug.h" 13#include "util/debug.h"
13 14
14#include "util/parse-options.h" 15#include "util/parse-options.h"
@@ -16,8 +17,9 @@
16static char const *input_name = "-"; 17static char const *input_name = "-";
17static bool inject_build_ids; 18static bool inject_build_ids;
18 19
19static int perf_event__repipe_synth(union perf_event *event, 20static int perf_event__repipe_synth(struct perf_tool *tool __used,
20 struct perf_session *session __used) 21 union perf_event *event,
22 struct machine *machine __used)
21{ 23{
22 uint32_t size; 24 uint32_t size;
23 void *buf = event; 25 void *buf = event;
@@ -36,41 +38,70 @@ static int perf_event__repipe_synth(union perf_event *event,
36 return 0; 38 return 0;
37} 39}
38 40
39static int perf_event__repipe(union perf_event *event, 41static int perf_event__repipe_op2_synth(struct perf_tool *tool,
42 union perf_event *event,
43 struct perf_session *session __used)
44{
45 return perf_event__repipe_synth(tool, event, NULL);
46}
47
48static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
49 union perf_event *event)
50{
51 return perf_event__repipe_synth(tool, event, NULL);
52}
53
54static int perf_event__repipe_tracing_data_synth(union perf_event *event,
55 struct perf_session *session __used)
56{
57 return perf_event__repipe_synth(NULL, event, NULL);
58}
59
60static int perf_event__repipe_attr(union perf_event *event,
61 struct perf_evlist **pevlist __used)
62{
63 return perf_event__repipe_synth(NULL, event, NULL);
64}
65
66static int perf_event__repipe(struct perf_tool *tool,
67 union perf_event *event,
40 struct perf_sample *sample __used, 68 struct perf_sample *sample __used,
41 struct perf_session *session) 69 struct machine *machine)
42{ 70{
43 return perf_event__repipe_synth(event, session); 71 return perf_event__repipe_synth(tool, event, machine);
44} 72}
45 73
46static int perf_event__repipe_sample(union perf_event *event, 74static int perf_event__repipe_sample(struct perf_tool *tool,
75 union perf_event *event,
47 struct perf_sample *sample __used, 76 struct perf_sample *sample __used,
48 struct perf_evsel *evsel __used, 77 struct perf_evsel *evsel __used,
49 struct perf_session *session) 78 struct machine *machine)
50{ 79{
51 return perf_event__repipe_synth(event, session); 80 return perf_event__repipe_synth(tool, event, machine);
52} 81}
53 82
54static int perf_event__repipe_mmap(union perf_event *event, 83static int perf_event__repipe_mmap(struct perf_tool *tool,
84 union perf_event *event,
55 struct perf_sample *sample, 85 struct perf_sample *sample,
56 struct perf_session *session) 86 struct machine *machine)
57{ 87{
58 int err; 88 int err;
59 89
60 err = perf_event__process_mmap(event, sample, session); 90 err = perf_event__process_mmap(tool, event, sample, machine);
61 perf_event__repipe(event, sample, session); 91 perf_event__repipe(tool, event, sample, machine);
62 92
63 return err; 93 return err;
64} 94}
65 95
66static int perf_event__repipe_task(union perf_event *event, 96static int perf_event__repipe_task(struct perf_tool *tool,
97 union perf_event *event,
67 struct perf_sample *sample, 98 struct perf_sample *sample,
68 struct perf_session *session) 99 struct machine *machine)
69{ 100{
70 int err; 101 int err;
71 102
72 err = perf_event__process_task(event, sample, session); 103 err = perf_event__process_task(tool, event, sample, machine);
73 perf_event__repipe(event, sample, session); 104 perf_event__repipe(tool, event, sample, machine);
74 105
75 return err; 106 return err;
76} 107}
@@ -80,7 +111,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event,
80{ 111{
81 int err; 112 int err;
82 113
83 perf_event__repipe_synth(event, session); 114 perf_event__repipe_synth(NULL, event, NULL);
84 err = perf_event__process_tracing_data(event, session); 115 err = perf_event__process_tracing_data(event, session);
85 116
86 return err; 117 return err;
@@ -100,10 +131,10 @@ static int dso__read_build_id(struct dso *self)
100 return -1; 131 return -1;
101} 132}
102 133
103static int dso__inject_build_id(struct dso *self, struct perf_session *session) 134static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
135 struct machine *machine)
104{ 136{
105 u16 misc = PERF_RECORD_MISC_USER; 137 u16 misc = PERF_RECORD_MISC_USER;
106 struct machine *machine;
107 int err; 138 int err;
108 139
109 if (dso__read_build_id(self) < 0) { 140 if (dso__read_build_id(self) < 0) {
@@ -111,17 +142,11 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
111 return -1; 142 return -1;
112 } 143 }
113 144
114 machine = perf_session__find_host_machine(session);
115 if (machine == NULL) {
116 pr_err("Can't find machine for session\n");
117 return -1;
118 }
119
120 if (self->kernel) 145 if (self->kernel)
121 misc = PERF_RECORD_MISC_KERNEL; 146 misc = PERF_RECORD_MISC_KERNEL;
122 147
123 err = perf_event__synthesize_build_id(self, misc, perf_event__repipe, 148 err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
124 machine, session); 149 machine);
125 if (err) { 150 if (err) {
126 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 151 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
127 return -1; 152 return -1;
@@ -130,10 +155,11 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
130 return 0; 155 return 0;
131} 156}
132 157
133static int perf_event__inject_buildid(union perf_event *event, 158static int perf_event__inject_buildid(struct perf_tool *tool,
159 union perf_event *event,
134 struct perf_sample *sample, 160 struct perf_sample *sample,
135 struct perf_evsel *evsel __used, 161 struct perf_evsel *evsel __used,
136 struct perf_session *session) 162 struct machine *machine)
137{ 163{
138 struct addr_location al; 164 struct addr_location al;
139 struct thread *thread; 165 struct thread *thread;
@@ -141,21 +167,21 @@ static int perf_event__inject_buildid(union perf_event *event,
141 167
142 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 168 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
143 169
144 thread = perf_session__findnew(session, event->ip.pid); 170 thread = machine__findnew_thread(machine, event->ip.pid);
145 if (thread == NULL) { 171 if (thread == NULL) {
146 pr_err("problem processing %d event, skipping it.\n", 172 pr_err("problem processing %d event, skipping it.\n",
147 event->header.type); 173 event->header.type);
148 goto repipe; 174 goto repipe;
149 } 175 }
150 176
151 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 177 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
152 event->ip.pid, event->ip.ip, &al); 178 event->ip.ip, &al);
153 179
154 if (al.map != NULL) { 180 if (al.map != NULL) {
155 if (!al.map->dso->hit) { 181 if (!al.map->dso->hit) {
156 al.map->dso->hit = 1; 182 al.map->dso->hit = 1;
157 if (map__load(al.map, NULL) >= 0) { 183 if (map__load(al.map, NULL) >= 0) {
158 dso__inject_build_id(al.map->dso, session); 184 dso__inject_build_id(al.map->dso, tool, machine);
159 /* 185 /*
160 * If this fails, too bad, let the other side 186 * If this fails, too bad, let the other side
161 * account this as unresolved. 187 * account this as unresolved.
@@ -168,24 +194,24 @@ static int perf_event__inject_buildid(union perf_event *event,
168 } 194 }
169 195
170repipe: 196repipe:
171 perf_event__repipe(event, sample, session); 197 perf_event__repipe(tool, event, sample, machine);
172 return 0; 198 return 0;
173} 199}
174 200
175struct perf_event_ops inject_ops = { 201struct perf_tool perf_inject = {
176 .sample = perf_event__repipe_sample, 202 .sample = perf_event__repipe_sample,
177 .mmap = perf_event__repipe, 203 .mmap = perf_event__repipe,
178 .comm = perf_event__repipe, 204 .comm = perf_event__repipe,
179 .fork = perf_event__repipe, 205 .fork = perf_event__repipe,
180 .exit = perf_event__repipe, 206 .exit = perf_event__repipe,
181 .lost = perf_event__repipe, 207 .lost = perf_event__repipe,
182 .read = perf_event__repipe, 208 .read = perf_event__repipe_sample,
183 .throttle = perf_event__repipe, 209 .throttle = perf_event__repipe,
184 .unthrottle = perf_event__repipe, 210 .unthrottle = perf_event__repipe,
185 .attr = perf_event__repipe_synth, 211 .attr = perf_event__repipe_attr,
186 .event_type = perf_event__repipe_synth, 212 .event_type = perf_event__repipe_event_type_synth,
187 .tracing_data = perf_event__repipe_synth, 213 .tracing_data = perf_event__repipe_tracing_data_synth,
188 .build_id = perf_event__repipe_synth, 214 .build_id = perf_event__repipe_op2_synth,
189}; 215};
190 216
191extern volatile int session_done; 217extern volatile int session_done;
@@ -203,17 +229,17 @@ static int __cmd_inject(void)
203 signal(SIGINT, sig_handler); 229 signal(SIGINT, sig_handler);
204 230
205 if (inject_build_ids) { 231 if (inject_build_ids) {
206 inject_ops.sample = perf_event__inject_buildid; 232 perf_inject.sample = perf_event__inject_buildid;
207 inject_ops.mmap = perf_event__repipe_mmap; 233 perf_inject.mmap = perf_event__repipe_mmap;
208 inject_ops.fork = perf_event__repipe_task; 234 perf_inject.fork = perf_event__repipe_task;
209 inject_ops.tracing_data = perf_event__repipe_tracing_data; 235 perf_inject.tracing_data = perf_event__repipe_tracing_data;
210 } 236 }
211 237
212 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); 238 session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject);
213 if (session == NULL) 239 if (session == NULL)
214 return -ENOMEM; 240 return -ENOMEM;
215 241
216 ret = perf_session__process_events(session, &inject_ops); 242 ret = perf_session__process_events(session, &perf_inject);
217 243
218 perf_session__delete(session); 244 perf_session__delete(session);
219 245
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 225e963df10..886174e9525 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -7,6 +7,7 @@
7#include "util/thread.h" 7#include "util/thread.h"
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h" 9#include "util/session.h"
10#include "util/tool.h"
10 11
11#include "util/parse-options.h" 12#include "util/parse-options.h"
12#include "util/trace-event.h" 13#include "util/trace-event.h"
@@ -303,12 +304,13 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
303 } 304 }
304} 305}
305 306
306static int process_sample_event(union perf_event *event, 307static int process_sample_event(struct perf_tool *tool __used,
308 union perf_event *event,
307 struct perf_sample *sample, 309 struct perf_sample *sample,
308 struct perf_evsel *evsel __used, 310 struct perf_evsel *evsel __used,
309 struct perf_session *session) 311 struct machine *machine)
310{ 312{
311 struct thread *thread = perf_session__findnew(session, event->ip.pid); 313 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
312 314
313 if (thread == NULL) { 315 if (thread == NULL) {
314 pr_debug("problem processing %d event, skipping it.\n", 316 pr_debug("problem processing %d event, skipping it.\n",
@@ -324,7 +326,7 @@ static int process_sample_event(union perf_event *event,
324 return 0; 326 return 0;
325} 327}
326 328
327static struct perf_event_ops event_ops = { 329static struct perf_tool perf_kmem = {
328 .sample = process_sample_event, 330 .sample = process_sample_event,
329 .comm = perf_event__process_comm, 331 .comm = perf_event__process_comm,
330 .ordered_samples = true, 332 .ordered_samples = true,
@@ -483,7 +485,7 @@ static int __cmd_kmem(void)
483{ 485{
484 int err = -EINVAL; 486 int err = -EINVAL;
485 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 487 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
486 0, false, &event_ops); 488 0, false, &perf_kmem);
487 if (session == NULL) 489 if (session == NULL)
488 return -ENOMEM; 490 return -ENOMEM;
489 491
@@ -494,7 +496,7 @@ static int __cmd_kmem(void)
494 goto out_delete; 496 goto out_delete;
495 497
496 setup_pager(); 498 setup_pager();
497 err = perf_session__process_events(session, &event_ops); 499 err = perf_session__process_events(session, &perf_kmem);
498 if (err != 0) 500 if (err != 0)
499 goto out_delete; 501 goto out_delete;
500 sort_result(); 502 sort_result();
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 899080ace26..4db5e529306 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -12,6 +12,7 @@
12 12
13#include "util/debug.h" 13#include "util/debug.h"
14#include "util/session.h" 14#include "util/session.h"
15#include "util/tool.h"
15 16
16#include <sys/types.h> 17#include <sys/types.h>
17#include <sys/prctl.h> 18#include <sys/prctl.h>
@@ -845,12 +846,13 @@ static void dump_info(void)
845 die("Unknown type of information\n"); 846 die("Unknown type of information\n");
846} 847}
847 848
848static int process_sample_event(union perf_event *event, 849static int process_sample_event(struct perf_tool *tool __used,
850 union perf_event *event,
849 struct perf_sample *sample, 851 struct perf_sample *sample,
850 struct perf_evsel *evsel __used, 852 struct perf_evsel *evsel __used,
851 struct perf_session *s) 853 struct machine *machine)
852{ 854{
853 struct thread *thread = perf_session__findnew(s, sample->tid); 855 struct thread *thread = machine__findnew_thread(machine, sample->tid);
854 856
855 if (thread == NULL) { 857 if (thread == NULL) {
856 pr_debug("problem processing %d event, skipping it.\n", 858 pr_debug("problem processing %d event, skipping it.\n",
@@ -863,7 +865,7 @@ static int process_sample_event(union perf_event *event,
863 return 0; 865 return 0;
864} 866}
865 867
866static struct perf_event_ops eops = { 868static struct perf_tool eops = {
867 .sample = process_sample_event, 869 .sample = process_sample_event,
868 .comm = perf_event__process_comm, 870 .comm = perf_event__process_comm,
869 .ordered_samples = true, 871 .ordered_samples = true,
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 710ae3d0a48..59d43abfbfe 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -46,7 +46,6 @@
46 46
47#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" 47#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
48#define DEFAULT_FUNC_FILTER "!_*" 48#define DEFAULT_FUNC_FILTER "!_*"
49#define MAX_PATH_LEN 256
50 49
51/* Session management structure */ 50/* Session management structure */
52static struct { 51static struct {
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6ab58cc99d5..766fa0a91a3 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -22,6 +22,7 @@
22#include "util/evsel.h" 22#include "util/evsel.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/session.h" 24#include "util/session.h"
25#include "util/tool.h"
25#include "util/symbol.h" 26#include "util/symbol.h"
26#include "util/cpumap.h" 27#include "util/cpumap.h"
27#include "util/thread_map.h" 28#include "util/thread_map.h"
@@ -35,55 +36,36 @@ enum write_mode_t {
35 WRITE_APPEND 36 WRITE_APPEND
36}; 37};
37 38
38static u64 user_interval = ULLONG_MAX; 39struct perf_record {
39static u64 default_interval = 0; 40 struct perf_tool tool;
40 41 struct perf_record_opts opts;
41static unsigned int page_size; 42 u64 bytes_written;
42static unsigned int mmap_pages = UINT_MAX; 43 const char *output_name;
43static unsigned int user_freq = UINT_MAX; 44 struct perf_evlist *evlist;
44static int freq = 1000; 45 struct perf_session *session;
45static int output; 46 const char *progname;
46static int pipe_output = 0; 47 int output;
47static const char *output_name = NULL; 48 unsigned int page_size;
48static bool group = false; 49 int realtime_prio;
49static int realtime_prio = 0; 50 enum write_mode_t write_mode;
50static bool nodelay = false; 51 bool no_buildid;
51static bool raw_samples = false; 52 bool no_buildid_cache;
52static bool sample_id_all_avail = true; 53 bool force;
53static bool system_wide = false; 54 bool file_new;
54static pid_t target_pid = -1; 55 bool append_file;
55static pid_t target_tid = -1; 56 long samples;
56static pid_t child_pid = -1; 57 off_t post_processing_offset;
57static bool no_inherit = false; 58};
58static enum write_mode_t write_mode = WRITE_FORCE; 59
59static bool call_graph = false; 60static void advance_output(struct perf_record *rec, size_t size)
60static bool inherit_stat = false;
61static bool no_samples = false;
62static bool sample_address = false;
63static bool sample_time = false;
64static bool no_buildid = false;
65static bool no_buildid_cache = false;
66static struct perf_evlist *evsel_list;
67
68static long samples = 0;
69static u64 bytes_written = 0;
70
71static int file_new = 1;
72static off_t post_processing_offset;
73
74static struct perf_session *session;
75static const char *cpu_list;
76static const char *progname;
77
78static void advance_output(size_t size)
79{ 61{
80 bytes_written += size; 62 rec->bytes_written += size;
81} 63}
82 64
83static void write_output(void *buf, size_t size) 65static void write_output(struct perf_record *rec, void *buf, size_t size)
84{ 66{
85 while (size) { 67 while (size) {
86 int ret = write(output, buf, size); 68 int ret = write(rec->output, buf, size);
87 69
88 if (ret < 0) 70 if (ret < 0)
89 die("failed to write"); 71 die("failed to write");
@@ -91,30 +73,33 @@ static void write_output(void *buf, size_t size)
91 size -= ret; 73 size -= ret;
92 buf += ret; 74 buf += ret;
93 75
94 bytes_written += ret; 76 rec->bytes_written += ret;
95 } 77 }
96} 78}
97 79
98static int process_synthesized_event(union perf_event *event, 80static int process_synthesized_event(struct perf_tool *tool,
81 union perf_event *event,
99 struct perf_sample *sample __used, 82 struct perf_sample *sample __used,
100 struct perf_session *self __used) 83 struct machine *machine __used)
101{ 84{
102 write_output(event, event->header.size); 85 struct perf_record *rec = container_of(tool, struct perf_record, tool);
86 write_output(rec, event, event->header.size);
103 return 0; 87 return 0;
104} 88}
105 89
106static void mmap_read(struct perf_mmap *md) 90static void perf_record__mmap_read(struct perf_record *rec,
91 struct perf_mmap *md)
107{ 92{
108 unsigned int head = perf_mmap__read_head(md); 93 unsigned int head = perf_mmap__read_head(md);
109 unsigned int old = md->prev; 94 unsigned int old = md->prev;
110 unsigned char *data = md->base + page_size; 95 unsigned char *data = md->base + rec->page_size;
111 unsigned long size; 96 unsigned long size;
112 void *buf; 97 void *buf;
113 98
114 if (old == head) 99 if (old == head)
115 return; 100 return;
116 101
117 samples++; 102 rec->samples++;
118 103
119 size = head - old; 104 size = head - old;
120 105
@@ -123,14 +108,14 @@ static void mmap_read(struct perf_mmap *md)
123 size = md->mask + 1 - (old & md->mask); 108 size = md->mask + 1 - (old & md->mask);
124 old += size; 109 old += size;
125 110
126 write_output(buf, size); 111 write_output(rec, buf, size);
127 } 112 }
128 113
129 buf = &data[old & md->mask]; 114 buf = &data[old & md->mask];
130 size = head - old; 115 size = head - old;
131 old += size; 116 old += size;
132 117
133 write_output(buf, size); 118 write_output(rec, buf, size);
134 119
135 md->prev = old; 120 md->prev = old;
136 perf_mmap__write_tail(md, old); 121 perf_mmap__write_tail(md, old);
@@ -149,17 +134,18 @@ static void sig_handler(int sig)
149 signr = sig; 134 signr = sig;
150} 135}
151 136
152static void sig_atexit(void) 137static void perf_record__sig_exit(int exit_status __used, void *arg)
153{ 138{
139 struct perf_record *rec = arg;
154 int status; 140 int status;
155 141
156 if (child_pid > 0) { 142 if (rec->evlist->workload.pid > 0) {
157 if (!child_finished) 143 if (!child_finished)
158 kill(child_pid, SIGTERM); 144 kill(rec->evlist->workload.pid, SIGTERM);
159 145
160 wait(&status); 146 wait(&status);
161 if (WIFSIGNALED(status)) 147 if (WIFSIGNALED(status))
162 psignal(WTERMSIG(status), progname); 148 psignal(WTERMSIG(status), rec->progname);
163 } 149 }
164 150
165 if (signr == -1 || signr == SIGUSR1) 151 if (signr == -1 || signr == SIGUSR1)
@@ -169,78 +155,6 @@ static void sig_atexit(void)
169 kill(getpid(), signr); 155 kill(getpid(), signr);
170} 156}
171 157
172static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
173{
174 struct perf_event_attr *attr = &evsel->attr;
175 int track = !evsel->idx; /* only the first counter needs these */
176
177 attr->disabled = 1;
178 attr->inherit = !no_inherit;
179 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
180 PERF_FORMAT_TOTAL_TIME_RUNNING |
181 PERF_FORMAT_ID;
182
183 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
184
185 if (evlist->nr_entries > 1)
186 attr->sample_type |= PERF_SAMPLE_ID;
187
188 /*
189 * We default some events to a 1 default interval. But keep
190 * it a weak assumption overridable by the user.
191 */
192 if (!attr->sample_period || (user_freq != UINT_MAX &&
193 user_interval != ULLONG_MAX)) {
194 if (freq) {
195 attr->sample_type |= PERF_SAMPLE_PERIOD;
196 attr->freq = 1;
197 attr->sample_freq = freq;
198 } else {
199 attr->sample_period = default_interval;
200 }
201 }
202
203 if (no_samples)
204 attr->sample_freq = 0;
205
206 if (inherit_stat)
207 attr->inherit_stat = 1;
208
209 if (sample_address) {
210 attr->sample_type |= PERF_SAMPLE_ADDR;
211 attr->mmap_data = track;
212 }
213
214 if (call_graph)
215 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
216
217 if (system_wide)
218 attr->sample_type |= PERF_SAMPLE_CPU;
219
220 if (sample_id_all_avail &&
221 (sample_time || system_wide || !no_inherit || cpu_list))
222 attr->sample_type |= PERF_SAMPLE_TIME;
223
224 if (raw_samples) {
225 attr->sample_type |= PERF_SAMPLE_TIME;
226 attr->sample_type |= PERF_SAMPLE_RAW;
227 attr->sample_type |= PERF_SAMPLE_CPU;
228 }
229
230 if (nodelay) {
231 attr->watermark = 0;
232 attr->wakeup_events = 1;
233 }
234
235 attr->mmap = track;
236 attr->comm = track;
237
238 if (target_pid == -1 && target_tid == -1 && !system_wide) {
239 attr->disabled = 1;
240 attr->enable_on_exec = 1;
241 }
242}
243
244static bool perf_evlist__equal(struct perf_evlist *evlist, 158static bool perf_evlist__equal(struct perf_evlist *evlist,
245 struct perf_evlist *other) 159 struct perf_evlist *other)
246{ 160{
@@ -260,15 +174,17 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
260 return true; 174 return true;
261} 175}
262 176
263static void open_counters(struct perf_evlist *evlist) 177static void perf_record__open(struct perf_record *rec)
264{ 178{
265 struct perf_evsel *pos, *first; 179 struct perf_evsel *pos, *first;
266 180 struct perf_evlist *evlist = rec->evlist;
267 if (evlist->cpus->map[0] < 0) 181 struct perf_session *session = rec->session;
268 no_inherit = true; 182 struct perf_record_opts *opts = &rec->opts;
269 183
270 first = list_entry(evlist->entries.next, struct perf_evsel, node); 184 first = list_entry(evlist->entries.next, struct perf_evsel, node);
271 185
186 perf_evlist__config_attrs(evlist, opts);
187
272 list_for_each_entry(pos, &evlist->entries, node) { 188 list_for_each_entry(pos, &evlist->entries, node) {
273 struct perf_event_attr *attr = &pos->attr; 189 struct perf_event_attr *attr = &pos->attr;
274 struct xyarray *group_fd = NULL; 190 struct xyarray *group_fd = NULL;
@@ -286,29 +202,27 @@ static void open_counters(struct perf_evlist *evlist)
286 */ 202 */
287 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 203 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
288 204
289 if (group && pos != first) 205 if (opts->group && pos != first)
290 group_fd = first->fd; 206 group_fd = first->fd;
291
292 config_attr(pos, evlist);
293retry_sample_id: 207retry_sample_id:
294 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 208 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
295try_again: 209try_again:
296 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, 210 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
297 group_fd) < 0) { 211 opts->group, group_fd) < 0) {
298 int err = errno; 212 int err = errno;
299 213
300 if (err == EPERM || err == EACCES) { 214 if (err == EPERM || err == EACCES) {
301 ui__error_paranoid(); 215 ui__error_paranoid();
302 exit(EXIT_FAILURE); 216 exit(EXIT_FAILURE);
303 } else if (err == ENODEV && cpu_list) { 217 } else if (err == ENODEV && opts->cpu_list) {
304 die("No such device - did you specify" 218 die("No such device - did you specify"
305 " an out-of-range profile CPU?\n"); 219 " an out-of-range profile CPU?\n");
306 } else if (err == EINVAL && sample_id_all_avail) { 220 } else if (err == EINVAL && opts->sample_id_all_avail) {
307 /* 221 /*
308 * Old kernel, no attr->sample_id_type_all field 222 * Old kernel, no attr->sample_id_type_all field
309 */ 223 */
310 sample_id_all_avail = false; 224 opts->sample_id_all_avail = false;
311 if (!sample_time && !raw_samples && !time_needed) 225 if (!opts->sample_time && !opts->raw_samples && !time_needed)
312 attr->sample_type &= ~PERF_SAMPLE_TIME; 226 attr->sample_type &= ~PERF_SAMPLE_TIME;
313 227
314 goto retry_sample_id; 228 goto retry_sample_id;
@@ -358,10 +272,10 @@ try_again:
358 exit(-1); 272 exit(-1);
359 } 273 }
360 274
361 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) 275 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0)
362 die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 276 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
363 277
364 if (file_new) 278 if (rec->file_new)
365 session->evlist = evlist; 279 session->evlist = evlist;
366 else { 280 else {
367 if (!perf_evlist__equal(session->evlist, evlist)) { 281 if (!perf_evlist__equal(session->evlist, evlist)) {
@@ -373,29 +287,32 @@ try_again:
373 perf_session__update_sample_type(session); 287 perf_session__update_sample_type(session);
374} 288}
375 289
376static int process_buildids(void) 290static int process_buildids(struct perf_record *rec)
377{ 291{
378 u64 size = lseek(output, 0, SEEK_CUR); 292 u64 size = lseek(rec->output, 0, SEEK_CUR);
379 293
380 if (size == 0) 294 if (size == 0)
381 return 0; 295 return 0;
382 296
383 session->fd = output; 297 rec->session->fd = rec->output;
384 return __perf_session__process_events(session, post_processing_offset, 298 return __perf_session__process_events(rec->session, rec->post_processing_offset,
385 size - post_processing_offset, 299 size - rec->post_processing_offset,
386 size, &build_id__mark_dso_hit_ops); 300 size, &build_id__mark_dso_hit_ops);
387} 301}
388 302
389static void atexit_header(void) 303static void perf_record__exit(int status __used, void *arg)
390{ 304{
391 if (!pipe_output) { 305 struct perf_record *rec = arg;
392 session->header.data_size += bytes_written; 306
393 307 if (!rec->opts.pipe_output) {
394 if (!no_buildid) 308 rec->session->header.data_size += rec->bytes_written;
395 process_buildids(); 309
396 perf_session__write_header(session, evsel_list, output, true); 310 if (!rec->no_buildid)
397 perf_session__delete(session); 311 process_buildids(rec);
398 perf_evlist__delete(evsel_list); 312 perf_session__write_header(rec->session, rec->evlist,
313 rec->output, true);
314 perf_session__delete(rec->session);
315 perf_evlist__delete(rec->evlist);
399 symbol__exit(); 316 symbol__exit();
400 } 317 }
401} 318}
@@ -403,7 +320,7 @@ static void atexit_header(void)
403static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 320static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
404{ 321{
405 int err; 322 int err;
406 struct perf_session *psession = data; 323 struct perf_tool *tool = data;
407 324
408 if (machine__is_host(machine)) 325 if (machine__is_host(machine))
409 return; 326 return;
@@ -416,8 +333,8 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
416 *method is used to avoid symbol missing when the first addr is 333 *method is used to avoid symbol missing when the first addr is
417 *in module instead of in guest kernel. 334 *in module instead of in guest kernel.
418 */ 335 */
419 err = perf_event__synthesize_modules(process_synthesized_event, 336 err = perf_event__synthesize_modules(tool, process_synthesized_event,
420 psession, machine); 337 machine);
421 if (err < 0) 338 if (err < 0)
422 pr_err("Couldn't record guest kernel [%d]'s reference" 339 pr_err("Couldn't record guest kernel [%d]'s reference"
423 " relocation symbol.\n", machine->pid); 340 " relocation symbol.\n", machine->pid);
@@ -426,12 +343,11 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
426 * We use _stext for guest kernel because guest kernel's /proc/kallsyms 343 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
427 * have no _text sometimes. 344 * have no _text sometimes.
428 */ 345 */
429 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 346 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
430 psession, machine, "_text"); 347 machine, "_text");
431 if (err < 0) 348 if (err < 0)
432 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 349 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
433 psession, machine, 350 machine, "_stext");
434 "_stext");
435 if (err < 0) 351 if (err < 0)
436 pr_err("Couldn't record guest kernel [%d]'s reference" 352 pr_err("Couldn't record guest kernel [%d]'s reference"
437 " relocation symbol.\n", machine->pid); 353 " relocation symbol.\n", machine->pid);
@@ -442,73 +358,71 @@ static struct perf_event_header finished_round_event = {
442 .type = PERF_RECORD_FINISHED_ROUND, 358 .type = PERF_RECORD_FINISHED_ROUND,
443}; 359};
444 360
445static void mmap_read_all(void) 361static void perf_record__mmap_read_all(struct perf_record *rec)
446{ 362{
447 int i; 363 int i;
448 364
449 for (i = 0; i < evsel_list->nr_mmaps; i++) { 365 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
450 if (evsel_list->mmap[i].base) 366 if (rec->evlist->mmap[i].base)
451 mmap_read(&evsel_list->mmap[i]); 367 perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
452 } 368 }
453 369
454 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 370 if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
455 write_output(&finished_round_event, sizeof(finished_round_event)); 371 write_output(rec, &finished_round_event, sizeof(finished_round_event));
456} 372}
457 373
458static int __cmd_record(int argc, const char **argv) 374static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
459{ 375{
460 struct stat st; 376 struct stat st;
461 int flags; 377 int flags;
462 int err; 378 int err, output;
463 unsigned long waking = 0; 379 unsigned long waking = 0;
464 int child_ready_pipe[2], go_pipe[2];
465 const bool forks = argc > 0; 380 const bool forks = argc > 0;
466 char buf;
467 struct machine *machine; 381 struct machine *machine;
382 struct perf_tool *tool = &rec->tool;
383 struct perf_record_opts *opts = &rec->opts;
384 struct perf_evlist *evsel_list = rec->evlist;
385 const char *output_name = rec->output_name;
386 struct perf_session *session;
468 387
469 progname = argv[0]; 388 rec->progname = argv[0];
470 389
471 page_size = sysconf(_SC_PAGE_SIZE); 390 rec->page_size = sysconf(_SC_PAGE_SIZE);
472 391
473 atexit(sig_atexit); 392 on_exit(perf_record__sig_exit, rec);
474 signal(SIGCHLD, sig_handler); 393 signal(SIGCHLD, sig_handler);
475 signal(SIGINT, sig_handler); 394 signal(SIGINT, sig_handler);
476 signal(SIGUSR1, sig_handler); 395 signal(SIGUSR1, sig_handler);
477 396
478 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
479 perror("failed to create pipes");
480 exit(-1);
481 }
482
483 if (!output_name) { 397 if (!output_name) {
484 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 398 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
485 pipe_output = 1; 399 opts->pipe_output = true;
486 else 400 else
487 output_name = "perf.data"; 401 rec->output_name = output_name = "perf.data";
488 } 402 }
489 if (output_name) { 403 if (output_name) {
490 if (!strcmp(output_name, "-")) 404 if (!strcmp(output_name, "-"))
491 pipe_output = 1; 405 opts->pipe_output = true;
492 else if (!stat(output_name, &st) && st.st_size) { 406 else if (!stat(output_name, &st) && st.st_size) {
493 if (write_mode == WRITE_FORCE) { 407 if (rec->write_mode == WRITE_FORCE) {
494 char oldname[PATH_MAX]; 408 char oldname[PATH_MAX];
495 snprintf(oldname, sizeof(oldname), "%s.old", 409 snprintf(oldname, sizeof(oldname), "%s.old",
496 output_name); 410 output_name);
497 unlink(oldname); 411 unlink(oldname);
498 rename(output_name, oldname); 412 rename(output_name, oldname);
499 } 413 }
500 } else if (write_mode == WRITE_APPEND) { 414 } else if (rec->write_mode == WRITE_APPEND) {
501 write_mode = WRITE_FORCE; 415 rec->write_mode = WRITE_FORCE;
502 } 416 }
503 } 417 }
504 418
505 flags = O_CREAT|O_RDWR; 419 flags = O_CREAT|O_RDWR;
506 if (write_mode == WRITE_APPEND) 420 if (rec->write_mode == WRITE_APPEND)
507 file_new = 0; 421 rec->file_new = 0;
508 else 422 else
509 flags |= O_TRUNC; 423 flags |= O_TRUNC;
510 424
511 if (pipe_output) 425 if (opts->pipe_output)
512 output = STDOUT_FILENO; 426 output = STDOUT_FILENO;
513 else 427 else
514 output = open(output_name, flags, S_IRUSR | S_IWUSR); 428 output = open(output_name, flags, S_IRUSR | S_IWUSR);
@@ -517,17 +431,21 @@ static int __cmd_record(int argc, const char **argv)
517 exit(-1); 431 exit(-1);
518 } 432 }
519 433
434 rec->output = output;
435
520 session = perf_session__new(output_name, O_WRONLY, 436 session = perf_session__new(output_name, O_WRONLY,
521 write_mode == WRITE_FORCE, false, NULL); 437 rec->write_mode == WRITE_FORCE, false, NULL);
522 if (session == NULL) { 438 if (session == NULL) {
523 pr_err("Not enough memory for reading perf file header\n"); 439 pr_err("Not enough memory for reading perf file header\n");
524 return -1; 440 return -1;
525 } 441 }
526 442
527 if (!no_buildid) 443 rec->session = session;
444
445 if (!rec->no_buildid)
528 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 446 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
529 447
530 if (!file_new) { 448 if (!rec->file_new) {
531 err = perf_session__read_header(session, output); 449 err = perf_session__read_header(session, output);
532 if (err < 0) 450 if (err < 0)
533 goto out_delete_session; 451 goto out_delete_session;
@@ -549,94 +467,50 @@ static int __cmd_record(int argc, const char **argv)
549 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY); 467 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
550 perf_header__set_feat(&session->header, HEADER_CPUID); 468 perf_header__set_feat(&session->header, HEADER_CPUID);
551 469
552 /* 512 kiB: default amount of unprivileged mlocked memory */
553 if (mmap_pages == UINT_MAX)
554 mmap_pages = (512 * 1024) / page_size;
555
556 if (forks) { 470 if (forks) {
557 child_pid = fork(); 471 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
558 if (child_pid < 0) { 472 if (err < 0) {
559 perror("failed to fork"); 473 pr_err("Couldn't run the workload!\n");
560 exit(-1); 474 goto out_delete_session;
561 }
562
563 if (!child_pid) {
564 if (pipe_output)
565 dup2(2, 1);
566 close(child_ready_pipe[0]);
567 close(go_pipe[1]);
568 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
569
570 /*
571 * Do a dummy execvp to get the PLT entry resolved,
572 * so we avoid the resolver overhead on the real
573 * execvp call.
574 */
575 execvp("", (char **)argv);
576
577 /*
578 * Tell the parent we're ready to go
579 */
580 close(child_ready_pipe[1]);
581
582 /*
583 * Wait until the parent tells us to go.
584 */
585 if (read(go_pipe[0], &buf, 1) == -1)
586 perror("unable to read pipe");
587
588 execvp(argv[0], (char **)argv);
589
590 perror(argv[0]);
591 kill(getppid(), SIGUSR1);
592 exit(-1);
593 }
594
595 if (!system_wide && target_tid == -1 && target_pid == -1)
596 evsel_list->threads->map[0] = child_pid;
597
598 close(child_ready_pipe[1]);
599 close(go_pipe[0]);
600 /*
601 * wait for child to settle
602 */
603 if (read(child_ready_pipe[0], &buf, 1) == -1) {
604 perror("unable to read pipe");
605 exit(-1);
606 } 475 }
607 close(child_ready_pipe[0]);
608 } 476 }
609 477
610 open_counters(evsel_list); 478 perf_record__open(rec);
611 479
612 /* 480 /*
613 * perf_session__delete(session) will be called at atexit_header() 481 * perf_session__delete(session) will be called at perf_record__exit()
614 */ 482 */
615 atexit(atexit_header); 483 on_exit(perf_record__exit, rec);
616 484
617 if (pipe_output) { 485 if (opts->pipe_output) {
618 err = perf_header__write_pipe(output); 486 err = perf_header__write_pipe(output);
619 if (err < 0) 487 if (err < 0)
620 return err; 488 return err;
621 } else if (file_new) { 489 } else if (rec->file_new) {
622 err = perf_session__write_header(session, evsel_list, 490 err = perf_session__write_header(session, evsel_list,
623 output, false); 491 output, false);
624 if (err < 0) 492 if (err < 0)
625 return err; 493 return err;
626 } 494 }
627 495
628 post_processing_offset = lseek(output, 0, SEEK_CUR); 496 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
497
498 machine = perf_session__find_host_machine(session);
499 if (!machine) {
500 pr_err("Couldn't find native kernel information.\n");
501 return -1;
502 }
629 503
630 if (pipe_output) { 504 if (opts->pipe_output) {
631 err = perf_session__synthesize_attrs(session, 505 err = perf_event__synthesize_attrs(tool, session,
632 process_synthesized_event); 506 process_synthesized_event);
633 if (err < 0) { 507 if (err < 0) {
634 pr_err("Couldn't synthesize attrs.\n"); 508 pr_err("Couldn't synthesize attrs.\n");
635 return err; 509 return err;
636 } 510 }
637 511
638 err = perf_event__synthesize_event_types(process_synthesized_event, 512 err = perf_event__synthesize_event_types(tool, process_synthesized_event,
639 session); 513 machine);
640 if (err < 0) { 514 if (err < 0) {
641 pr_err("Couldn't synthesize event_types.\n"); 515 pr_err("Couldn't synthesize event_types.\n");
642 return err; 516 return err;
@@ -651,56 +525,49 @@ static int __cmd_record(int argc, const char **argv)
651 * return this more properly and also 525 * return this more properly and also
652 * propagate errors that now are calling die() 526 * propagate errors that now are calling die()
653 */ 527 */
654 err = perf_event__synthesize_tracing_data(output, evsel_list, 528 err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
655 process_synthesized_event, 529 process_synthesized_event);
656 session);
657 if (err <= 0) { 530 if (err <= 0) {
658 pr_err("Couldn't record tracing data.\n"); 531 pr_err("Couldn't record tracing data.\n");
659 return err; 532 return err;
660 } 533 }
661 advance_output(err); 534 advance_output(rec, err);
662 } 535 }
663 } 536 }
664 537
665 machine = perf_session__find_host_machine(session); 538 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
666 if (!machine) { 539 machine, "_text");
667 pr_err("Couldn't find native kernel information.\n");
668 return -1;
669 }
670
671 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
672 session, machine, "_text");
673 if (err < 0) 540 if (err < 0)
674 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 541 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
675 session, machine, "_stext"); 542 machine, "_stext");
676 if (err < 0) 543 if (err < 0)
677 pr_err("Couldn't record kernel reference relocation symbol\n" 544 pr_err("Couldn't record kernel reference relocation symbol\n"
678 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 545 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
679 "Check /proc/kallsyms permission or run as root.\n"); 546 "Check /proc/kallsyms permission or run as root.\n");
680 547
681 err = perf_event__synthesize_modules(process_synthesized_event, 548 err = perf_event__synthesize_modules(tool, process_synthesized_event,
682 session, machine); 549 machine);
683 if (err < 0) 550 if (err < 0)
684 pr_err("Couldn't record kernel module information.\n" 551 pr_err("Couldn't record kernel module information.\n"
685 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 552 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
686 "Check /proc/modules permission or run as root.\n"); 553 "Check /proc/modules permission or run as root.\n");
687 554
688 if (perf_guest) 555 if (perf_guest)
689 perf_session__process_machines(session, 556 perf_session__process_machines(session, tool,
690 perf_event__synthesize_guest_os); 557 perf_event__synthesize_guest_os);
691 558
692 if (!system_wide) 559 if (!opts->system_wide)
693 perf_event__synthesize_thread_map(evsel_list->threads, 560 perf_event__synthesize_thread_map(tool, evsel_list->threads,
694 process_synthesized_event, 561 process_synthesized_event,
695 session); 562 machine);
696 else 563 else
697 perf_event__synthesize_threads(process_synthesized_event, 564 perf_event__synthesize_threads(tool, process_synthesized_event,
698 session); 565 machine);
699 566
700 if (realtime_prio) { 567 if (rec->realtime_prio) {
701 struct sched_param param; 568 struct sched_param param;
702 569
703 param.sched_priority = realtime_prio; 570 param.sched_priority = rec->realtime_prio;
704 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 571 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
705 pr_err("Could not set realtime priority.\n"); 572 pr_err("Could not set realtime priority.\n");
706 exit(-1); 573 exit(-1);
@@ -713,14 +580,14 @@ static int __cmd_record(int argc, const char **argv)
713 * Let the child rip 580 * Let the child rip
714 */ 581 */
715 if (forks) 582 if (forks)
716 close(go_pipe[1]); 583 perf_evlist__start_workload(evsel_list);
717 584
718 for (;;) { 585 for (;;) {
719 int hits = samples; 586 int hits = rec->samples;
720 587
721 mmap_read_all(); 588 perf_record__mmap_read_all(rec);
722 589
723 if (hits == samples) { 590 if (hits == rec->samples) {
724 if (done) 591 if (done)
725 break; 592 break;
726 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 593 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
@@ -741,9 +608,9 @@ static int __cmd_record(int argc, const char **argv)
741 */ 608 */
742 fprintf(stderr, 609 fprintf(stderr,
743 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 610 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
744 (double)bytes_written / 1024.0 / 1024.0, 611 (double)rec->bytes_written / 1024.0 / 1024.0,
745 output_name, 612 output_name,
746 bytes_written / 24); 613 rec->bytes_written / 24);
747 614
748 return 0; 615 return 0;
749 616
@@ -758,58 +625,88 @@ static const char * const record_usage[] = {
758 NULL 625 NULL
759}; 626};
760 627
761static bool force, append_file; 628/*
629 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
630 * because we need to have access to it in perf_record__exit, that is called
631 * after cmd_record() exits, but since record_options need to be accessible to
632 * builtin-script, leave it here.
633 *
634 * At least we don't ouch it in all the other functions here directly.
635 *
636 * Just say no to tons of global variables, sigh.
637 */
638static struct perf_record record = {
639 .opts = {
640 .target_pid = -1,
641 .target_tid = -1,
642 .mmap_pages = UINT_MAX,
643 .user_freq = UINT_MAX,
644 .user_interval = ULLONG_MAX,
645 .freq = 1000,
646 .sample_id_all_avail = true,
647 },
648 .write_mode = WRITE_FORCE,
649 .file_new = true,
650};
762 651
652/*
653 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
654 * with it and switch to use the library functions in perf_evlist that came
655 * from builtin-record.c, i.e. use perf_record_opts,
656 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
657 * using pipes, etc.
658 */
763const struct option record_options[] = { 659const struct option record_options[] = {
764 OPT_CALLBACK('e', "event", &evsel_list, "event", 660 OPT_CALLBACK('e', "event", &record.evlist, "event",
765 "event selector. use 'perf list' to list available events", 661 "event selector. use 'perf list' to list available events",
766 parse_events_option), 662 parse_events_option),
767 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 663 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
768 "event filter", parse_filter), 664 "event filter", parse_filter),
769 OPT_INTEGER('p', "pid", &target_pid, 665 OPT_INTEGER('p', "pid", &record.opts.target_pid,
770 "record events on existing process id"), 666 "record events on existing process id"),
771 OPT_INTEGER('t', "tid", &target_tid, 667 OPT_INTEGER('t', "tid", &record.opts.target_tid,
772 "record events on existing thread id"), 668 "record events on existing thread id"),
773 OPT_INTEGER('r', "realtime", &realtime_prio, 669 OPT_INTEGER('r', "realtime", &record.realtime_prio,
774 "collect data with this RT SCHED_FIFO priority"), 670 "collect data with this RT SCHED_FIFO priority"),
775 OPT_BOOLEAN('D', "no-delay", &nodelay, 671 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
776 "collect data without buffering"), 672 "collect data without buffering"),
777 OPT_BOOLEAN('R', "raw-samples", &raw_samples, 673 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
778 "collect raw sample records from all opened counters"), 674 "collect raw sample records from all opened counters"),
779 OPT_BOOLEAN('a', "all-cpus", &system_wide, 675 OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
780 "system-wide collection from all CPUs"), 676 "system-wide collection from all CPUs"),
781 OPT_BOOLEAN('A', "append", &append_file, 677 OPT_BOOLEAN('A', "append", &record.append_file,
782 "append to the output file to do incremental profiling"), 678 "append to the output file to do incremental profiling"),
783 OPT_STRING('C', "cpu", &cpu_list, "cpu", 679 OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
784 "list of cpus to monitor"), 680 "list of cpus to monitor"),
785 OPT_BOOLEAN('f', "force", &force, 681 OPT_BOOLEAN('f', "force", &record.force,
786 "overwrite existing data file (deprecated)"), 682 "overwrite existing data file (deprecated)"),
787 OPT_U64('c', "count", &user_interval, "event period to sample"), 683 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
788 OPT_STRING('o', "output", &output_name, "file", 684 OPT_STRING('o', "output", &record.output_name, "file",
789 "output file name"), 685 "output file name"),
790 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 686 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
791 "child tasks do not inherit counters"), 687 "child tasks do not inherit counters"),
792 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), 688 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
793 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 689 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
794 OPT_BOOLEAN(0, "group", &group, 690 "number of mmap data pages"),
691 OPT_BOOLEAN(0, "group", &record.opts.group,
795 "put the counters into a counter group"), 692 "put the counters into a counter group"),
796 OPT_BOOLEAN('g', "call-graph", &call_graph, 693 OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
797 "do call-graph (stack chain/backtrace) recording"), 694 "do call-graph (stack chain/backtrace) recording"),
798 OPT_INCR('v', "verbose", &verbose, 695 OPT_INCR('v', "verbose", &verbose,
799 "be more verbose (show counter open errors, etc)"), 696 "be more verbose (show counter open errors, etc)"),
800 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 697 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
801 OPT_BOOLEAN('s', "stat", &inherit_stat, 698 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
802 "per thread counts"), 699 "per thread counts"),
803 OPT_BOOLEAN('d', "data", &sample_address, 700 OPT_BOOLEAN('d', "data", &record.opts.sample_address,
804 "Sample addresses"), 701 "Sample addresses"),
805 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"), 702 OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
806 OPT_BOOLEAN('n', "no-samples", &no_samples, 703 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
807 "don't sample"), 704 "don't sample"),
808 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, 705 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
809 "do not update the buildid cache"), 706 "do not update the buildid cache"),
810 OPT_BOOLEAN('B', "no-buildid", &no_buildid, 707 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
811 "do not collect buildids in perf.data"), 708 "do not collect buildids in perf.data"),
812 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 709 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
813 "monitor event in cgroup name only", 710 "monitor event in cgroup name only",
814 parse_cgroups), 711 parse_cgroups),
815 OPT_END() 712 OPT_END()
@@ -819,6 +716,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
819{ 716{
820 int err = -ENOMEM; 717 int err = -ENOMEM;
821 struct perf_evsel *pos; 718 struct perf_evsel *pos;
719 struct perf_evlist *evsel_list;
720 struct perf_record *rec = &record;
822 721
823 perf_header__set_cmdline(argc, argv); 722 perf_header__set_cmdline(argc, argv);
824 723
@@ -826,23 +725,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
826 if (evsel_list == NULL) 725 if (evsel_list == NULL)
827 return -ENOMEM; 726 return -ENOMEM;
828 727
728 rec->evlist = evsel_list;
729
829 argc = parse_options(argc, argv, record_options, record_usage, 730 argc = parse_options(argc, argv, record_options, record_usage,
830 PARSE_OPT_STOP_AT_NON_OPTION); 731 PARSE_OPT_STOP_AT_NON_OPTION);
831 if (!argc && target_pid == -1 && target_tid == -1 && 732 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
832 !system_wide && !cpu_list) 733 !rec->opts.system_wide && !rec->opts.cpu_list)
833 usage_with_options(record_usage, record_options); 734 usage_with_options(record_usage, record_options);
834 735
835 if (force && append_file) { 736 if (rec->force && rec->append_file) {
836 fprintf(stderr, "Can't overwrite and append at the same time." 737 fprintf(stderr, "Can't overwrite and append at the same time."
837 " You need to choose between -f and -A"); 738 " You need to choose between -f and -A");
838 usage_with_options(record_usage, record_options); 739 usage_with_options(record_usage, record_options);
839 } else if (append_file) { 740 } else if (rec->append_file) {
840 write_mode = WRITE_APPEND; 741 rec->write_mode = WRITE_APPEND;
841 } else { 742 } else {
842 write_mode = WRITE_FORCE; 743 rec->write_mode = WRITE_FORCE;
843 } 744 }
844 745
845 if (nr_cgroups && !system_wide) { 746 if (nr_cgroups && !rec->opts.system_wide) {
846 fprintf(stderr, "cgroup monitoring only available in" 747 fprintf(stderr, "cgroup monitoring only available in"
847 " system-wide mode\n"); 748 " system-wide mode\n");
848 usage_with_options(record_usage, record_options); 749 usage_with_options(record_usage, record_options);
@@ -860,7 +761,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
860"If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 761"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
861"even with a suitable vmlinux or kallsyms file.\n\n"); 762"even with a suitable vmlinux or kallsyms file.\n\n");
862 763
863 if (no_buildid_cache || no_buildid) 764 if (rec->no_buildid_cache || rec->no_buildid)
864 disable_buildid_cache(); 765 disable_buildid_cache();
865 766
866 if (evsel_list->nr_entries == 0 && 767 if (evsel_list->nr_entries == 0 &&
@@ -869,43 +770,37 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
869 goto out_symbol_exit; 770 goto out_symbol_exit;
870 } 771 }
871 772
872 if (target_pid != -1) 773 if (rec->opts.target_pid != -1)
873 target_tid = target_pid; 774 rec->opts.target_tid = rec->opts.target_pid;
874 775
875 if (perf_evlist__create_maps(evsel_list, target_pid, 776 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
876 target_tid, cpu_list) < 0) 777 rec->opts.target_tid, rec->opts.cpu_list) < 0)
877 usage_with_options(record_usage, record_options); 778 usage_with_options(record_usage, record_options);
878 779
879 list_for_each_entry(pos, &evsel_list->entries, node) { 780 list_for_each_entry(pos, &evsel_list->entries, node) {
880 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
881 evsel_list->threads->nr) < 0)
882 goto out_free_fd;
883 if (perf_header__push_event(pos->attr.config, event_name(pos))) 781 if (perf_header__push_event(pos->attr.config, event_name(pos)))
884 goto out_free_fd; 782 goto out_free_fd;
885 } 783 }
886 784
887 if (perf_evlist__alloc_pollfd(evsel_list) < 0) 785 if (rec->opts.user_interval != ULLONG_MAX)
888 goto out_free_fd; 786 rec->opts.default_interval = rec->opts.user_interval;
889 787 if (rec->opts.user_freq != UINT_MAX)
890 if (user_interval != ULLONG_MAX) 788 rec->opts.freq = rec->opts.user_freq;
891 default_interval = user_interval;
892 if (user_freq != UINT_MAX)
893 freq = user_freq;
894 789
895 /* 790 /*
896 * User specified count overrides default frequency. 791 * User specified count overrides default frequency.
897 */ 792 */
898 if (default_interval) 793 if (rec->opts.default_interval)
899 freq = 0; 794 rec->opts.freq = 0;
900 else if (freq) { 795 else if (rec->opts.freq) {
901 default_interval = freq; 796 rec->opts.default_interval = rec->opts.freq;
902 } else { 797 } else {
903 fprintf(stderr, "frequency and count are zero, aborting\n"); 798 fprintf(stderr, "frequency and count are zero, aborting\n");
904 err = -EINVAL; 799 err = -EINVAL;
905 goto out_free_fd; 800 goto out_free_fd;
906 } 801 }
907 802
908 err = __cmd_record(argc, argv); 803 err = __cmd_record(&record, argc, argv);
909out_free_fd: 804out_free_fd:
910 perf_evlist__delete_maps(evsel_list); 805 perf_evlist__delete_maps(evsel_list);
911out_symbol_exit: 806out_symbol_exit:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4d7c8340c32..ece7c5d3f50 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -25,6 +25,7 @@
25#include "util/evsel.h" 25#include "util/evsel.h"
26#include "util/header.h" 26#include "util/header.h"
27#include "util/session.h" 27#include "util/session.h"
28#include "util/tool.h"
28 29
29#include "util/parse-options.h" 30#include "util/parse-options.h"
30#include "util/parse-events.h" 31#include "util/parse-events.h"
@@ -35,38 +36,35 @@
35 36
36#include <linux/bitmap.h> 37#include <linux/bitmap.h>
37 38
38static char const *input_name = "perf.data"; 39struct perf_report {
39 40 struct perf_tool tool;
40static bool force, use_tui, use_stdio; 41 struct perf_session *session;
41static bool hide_unresolved; 42 char const *input_name;
42static bool dont_use_callchains; 43 bool force, use_tui, use_stdio;
43static bool show_full_info; 44 bool hide_unresolved;
44 45 bool dont_use_callchains;
45static bool show_threads; 46 bool show_full_info;
46static struct perf_read_values show_threads_values; 47 bool show_threads;
47 48 bool inverted_callchain;
48static const char default_pretty_printing_style[] = "normal"; 49 struct perf_read_values show_threads_values;
49static const char *pretty_printing_style = default_pretty_printing_style; 50 const char *pretty_printing_style;
50 51 symbol_filter_t annotate_init;
51static char callchain_default_opt[] = "fractal,0.5,callee"; 52 const char *cpu_list;
52static bool inverted_callchain; 53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
53static symbol_filter_t annotate_init; 54};
54
55static const char *cpu_list;
56static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
57 55
58static int perf_session__add_hist_entry(struct perf_session *session, 56static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
59 struct addr_location *al, 57 struct addr_location *al,
60 struct perf_sample *sample, 58 struct perf_sample *sample,
61 struct perf_evsel *evsel) 59 struct machine *machine)
62{ 60{
63 struct symbol *parent = NULL; 61 struct symbol *parent = NULL;
64 int err = 0; 62 int err = 0;
65 struct hist_entry *he; 63 struct hist_entry *he;
66 64
67 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 65 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
68 err = perf_session__resolve_callchain(session, al->thread, 66 err = machine__resolve_callchain(machine, evsel, al->thread,
69 sample->callchain, &parent); 67 sample->callchain, &parent);
70 if (err) 68 if (err)
71 return err; 69 return err;
72 } 70 }
@@ -76,7 +74,8 @@ static int perf_session__add_hist_entry(struct perf_session *session,
76 return -ENOMEM; 74 return -ENOMEM;
77 75
78 if (symbol_conf.use_callchain) { 76 if (symbol_conf.use_callchain) {
79 err = callchain_append(he->callchain, &session->callchain_cursor, 77 err = callchain_append(he->callchain,
78 &evsel->hists.callchain_cursor,
80 sample->period); 79 sample->period);
81 if (err) 80 if (err)
82 return err; 81 return err;
@@ -92,8 +91,7 @@ static int perf_session__add_hist_entry(struct perf_session *session,
92 assert(evsel != NULL); 91 assert(evsel != NULL);
93 92
94 err = -ENOMEM; 93 err = -ENOMEM;
95 if (notes->src == NULL && 94 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
96 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
97 goto out; 95 goto out;
98 96
99 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 97 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
@@ -106,30 +104,32 @@ out:
106} 104}
107 105
108 106
109static int process_sample_event(union perf_event *event, 107static int process_sample_event(struct perf_tool *tool,
108 union perf_event *event,
110 struct perf_sample *sample, 109 struct perf_sample *sample,
111 struct perf_evsel *evsel, 110 struct perf_evsel *evsel,
112 struct perf_session *session) 111 struct machine *machine)
113{ 112{
113 struct perf_report *rep = container_of(tool, struct perf_report, tool);
114 struct addr_location al; 114 struct addr_location al;
115 115
116 if (perf_event__preprocess_sample(event, session, &al, sample, 116 if (perf_event__preprocess_sample(event, machine, &al, sample,
117 annotate_init) < 0) { 117 rep->annotate_init) < 0) {
118 fprintf(stderr, "problem processing %d event, skipping it.\n", 118 fprintf(stderr, "problem processing %d event, skipping it.\n",
119 event->header.type); 119 event->header.type);
120 return -1; 120 return -1;
121 } 121 }
122 122
123 if (al.filtered || (hide_unresolved && al.sym == NULL)) 123 if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
124 return 0; 124 return 0;
125 125
126 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 126 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
127 return 0; 127 return 0;
128 128
129 if (al.map != NULL) 129 if (al.map != NULL)
130 al.map->dso->hit = 1; 130 al.map->dso->hit = 1;
131 131
132 if (perf_session__add_hist_entry(session, &al, sample, evsel)) { 132 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
133 pr_debug("problem incrementing symbol period, skipping event\n"); 133 pr_debug("problem incrementing symbol period, skipping event\n");
134 return -1; 134 return -1;
135 } 135 }
@@ -137,15 +137,17 @@ static int process_sample_event(union perf_event *event,
137 return 0; 137 return 0;
138} 138}
139 139
140static int process_read_event(union perf_event *event, 140static int process_read_event(struct perf_tool *tool,
141 union perf_event *event,
141 struct perf_sample *sample __used, 142 struct perf_sample *sample __used,
142 struct perf_session *session) 143 struct perf_evsel *evsel,
144 struct machine *machine __used)
143{ 145{
144 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, 146 struct perf_report *rep = container_of(tool, struct perf_report, tool);
145 event->read.id); 147
146 if (show_threads) { 148 if (rep->show_threads) {
147 const char *name = evsel ? event_name(evsel) : "unknown"; 149 const char *name = evsel ? event_name(evsel) : "unknown";
148 perf_read_values_add_value(&show_threads_values, 150 perf_read_values_add_value(&rep->show_threads_values,
149 event->read.pid, event->read.tid, 151 event->read.pid, event->read.tid,
150 event->read.id, 152 event->read.id,
151 name, 153 name,
@@ -159,8 +161,10 @@ static int process_read_event(union perf_event *event,
159 return 0; 161 return 0;
160} 162}
161 163
162static int perf_session__setup_sample_type(struct perf_session *self) 164static int perf_report__setup_sample_type(struct perf_report *rep)
163{ 165{
166 struct perf_session *self = rep->session;
167
164 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 168 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
165 if (sort__has_parent) { 169 if (sort__has_parent) {
166 ui__warning("Selected --sort parent, but no " 170 ui__warning("Selected --sort parent, but no "
@@ -173,7 +177,8 @@ static int perf_session__setup_sample_type(struct perf_session *self)
173 "you call 'perf record' without -g?\n"); 177 "you call 'perf record' without -g?\n");
174 return -1; 178 return -1;
175 } 179 }
176 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 180 } else if (!rep->dont_use_callchains &&
181 callchain_param.mode != CHAIN_NONE &&
177 !symbol_conf.use_callchain) { 182 !symbol_conf.use_callchain) {
178 symbol_conf.use_callchain = true; 183 symbol_conf.use_callchain = true;
179 if (callchain_register_param(&callchain_param) < 0) { 184 if (callchain_register_param(&callchain_param) < 0) {
@@ -186,22 +191,6 @@ static int perf_session__setup_sample_type(struct perf_session *self)
186 return 0; 191 return 0;
187} 192}
188 193
189static struct perf_event_ops event_ops = {
190 .sample = process_sample_event,
191 .mmap = perf_event__process_mmap,
192 .comm = perf_event__process_comm,
193 .exit = perf_event__process_task,
194 .fork = perf_event__process_task,
195 .lost = perf_event__process_lost,
196 .read = process_read_event,
197 .attr = perf_event__process_attr,
198 .event_type = perf_event__process_event_type,
199 .tracing_data = perf_event__process_tracing_data,
200 .build_id = perf_event__process_build_id,
201 .ordered_samples = true,
202 .ordering_requires_timestamps = true,
203};
204
205extern volatile int session_done; 194extern volatile int session_done;
206 195
207static void sig_handler(int sig __used) 196static void sig_handler(int sig __used)
@@ -224,6 +213,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
224} 213}
225 214
226static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, 215static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
216 struct perf_report *rep,
227 const char *help) 217 const char *help)
228{ 218{
229 struct perf_evsel *pos; 219 struct perf_evsel *pos;
@@ -241,18 +231,18 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
241 parent_pattern == default_parent_pattern) { 231 parent_pattern == default_parent_pattern) {
242 fprintf(stdout, "#\n# (%s)\n#\n", help); 232 fprintf(stdout, "#\n# (%s)\n#\n", help);
243 233
244 if (show_threads) { 234 if (rep->show_threads) {
245 bool style = !strcmp(pretty_printing_style, "raw"); 235 bool style = !strcmp(rep->pretty_printing_style, "raw");
246 perf_read_values_display(stdout, &show_threads_values, 236 perf_read_values_display(stdout, &rep->show_threads_values,
247 style); 237 style);
248 perf_read_values_destroy(&show_threads_values); 238 perf_read_values_destroy(&rep->show_threads_values);
249 } 239 }
250 } 240 }
251 241
252 return 0; 242 return 0;
253} 243}
254 244
255static int __cmd_report(void) 245static int __cmd_report(struct perf_report *rep)
256{ 246{
257 int ret = -EINVAL; 247 int ret = -EINVAL;
258 u64 nr_samples; 248 u64 nr_samples;
@@ -264,27 +254,31 @@ static int __cmd_report(void)
264 254
265 signal(SIGINT, sig_handler); 255 signal(SIGINT, sig_handler);
266 256
267 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); 257 session = perf_session__new(rep->input_name, O_RDONLY,
258 rep->force, false, &rep->tool);
268 if (session == NULL) 259 if (session == NULL)
269 return -ENOMEM; 260 return -ENOMEM;
270 261
271 if (cpu_list) { 262 rep->session = session;
272 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); 263
264 if (rep->cpu_list) {
265 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
266 rep->cpu_bitmap);
273 if (ret) 267 if (ret)
274 goto out_delete; 268 goto out_delete;
275 } 269 }
276 270
277 if (use_browser <= 0) 271 if (use_browser <= 0)
278 perf_session__fprintf_info(session, stdout, show_full_info); 272 perf_session__fprintf_info(session, stdout, rep->show_full_info);
279 273
280 if (show_threads) 274 if (rep->show_threads)
281 perf_read_values_init(&show_threads_values); 275 perf_read_values_init(&rep->show_threads_values);
282 276
283 ret = perf_session__setup_sample_type(session); 277 ret = perf_report__setup_sample_type(rep);
284 if (ret) 278 if (ret)
285 goto out_delete; 279 goto out_delete;
286 280
287 ret = perf_session__process_events(session, &event_ops); 281 ret = perf_session__process_events(session, &rep->tool);
288 if (ret) 282 if (ret)
289 goto out_delete; 283 goto out_delete;
290 284
@@ -327,7 +321,8 @@ static int __cmd_report(void)
327 } 321 }
328 322
329 if (nr_samples == 0) { 323 if (nr_samples == 0) {
330 ui__warning("The %s file has no samples!\n", input_name); 324 ui__warning("The %s file has no samples!\n",
325 rep->input_name);
331 goto out_delete; 326 goto out_delete;
332 } 327 }
333 328
@@ -335,7 +330,7 @@ static int __cmd_report(void)
335 perf_evlist__tui_browse_hists(session->evlist, help, 330 perf_evlist__tui_browse_hists(session->evlist, help,
336 NULL, NULL, 0); 331 NULL, NULL, 0);
337 } else 332 } else
338 perf_evlist__tty_browse_hists(session->evlist, help); 333 perf_evlist__tty_browse_hists(session->evlist, rep, help);
339 334
340out_delete: 335out_delete:
341 /* 336 /*
@@ -354,9 +349,9 @@ out_delete:
354} 349}
355 350
356static int 351static int
357parse_callchain_opt(const struct option *opt __used, const char *arg, 352parse_callchain_opt(const struct option *opt, const char *arg, int unset)
358 int unset)
359{ 353{
354 struct perf_report *rep = (struct perf_report *)opt->value;
360 char *tok, *tok2; 355 char *tok, *tok2;
361 char *endptr; 356 char *endptr;
362 357
@@ -364,7 +359,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
364 * --no-call-graph 359 * --no-call-graph
365 */ 360 */
366 if (unset) { 361 if (unset) {
367 dont_use_callchains = true; 362 rep->dont_use_callchains = true;
368 return 0; 363 return 0;
369 } 364 }
370 365
@@ -433,13 +428,34 @@ setup:
433 return 0; 428 return 0;
434} 429}
435 430
436static const char * const report_usage[] = { 431int cmd_report(int argc, const char **argv, const char *prefix __used)
437 "perf report [<options>] <command>", 432{
438 NULL 433 char callchain_default_opt[] = "fractal,0.5,callee";
439}; 434 const char * const report_usage[] = {
440 435 "perf report [<options>] <command>",
441static const struct option options[] = { 436 NULL
442 OPT_STRING('i', "input", &input_name, "file", 437 };
438 struct perf_report report = {
439 .tool = {
440 .sample = process_sample_event,
441 .mmap = perf_event__process_mmap,
442 .comm = perf_event__process_comm,
443 .exit = perf_event__process_task,
444 .fork = perf_event__process_task,
445 .lost = perf_event__process_lost,
446 .read = process_read_event,
447 .attr = perf_event__process_attr,
448 .event_type = perf_event__process_event_type,
449 .tracing_data = perf_event__process_tracing_data,
450 .build_id = perf_event__process_build_id,
451 .ordered_samples = true,
452 .ordering_requires_timestamps = true,
453 },
454 .input_name = "perf.data",
455 .pretty_printing_style = "normal",
456 };
457 const struct option options[] = {
458 OPT_STRING('i', "input", &report.input_name, "file",
443 "input file name"), 459 "input file name"),
444 OPT_INCR('v', "verbose", &verbose, 460 OPT_INCR('v', "verbose", &verbose,
445 "be more verbose (show symbol address, etc)"), 461 "be more verbose (show symbol address, etc)"),
@@ -449,17 +465,18 @@ static const struct option options[] = {
449 "file", "vmlinux pathname"), 465 "file", "vmlinux pathname"),
450 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 466 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
451 "file", "kallsyms pathname"), 467 "file", "kallsyms pathname"),
452 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 468 OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
453 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 469 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
454 "load module symbols - WARNING: use only with -k and LIVE kernel"), 470 "load module symbols - WARNING: use only with -k and LIVE kernel"),
455 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 471 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
456 "Show a column with the number of samples"), 472 "Show a column with the number of samples"),
457 OPT_BOOLEAN('T', "threads", &show_threads, 473 OPT_BOOLEAN('T', "threads", &report.show_threads,
458 "Show per-thread event counters"), 474 "Show per-thread event counters"),
459 OPT_STRING(0, "pretty", &pretty_printing_style, "key", 475 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
460 "pretty printing style key: normal raw"), 476 "pretty printing style key: normal raw"),
461 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), 477 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
462 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 478 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
479 "Use the stdio interface"),
463 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 480 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
464 "sort by key(s): pid, comm, dso, symbol, parent"), 481 "sort by key(s): pid, comm, dso, symbol, parent"),
465 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 482 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
@@ -468,13 +485,14 @@ static const struct option options[] = {
468 "regex filter to identify parent, see: '--sort parent'"), 485 "regex filter to identify parent, see: '--sort parent'"),
469 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 486 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
470 "Only display entries with parent-match"), 487 "Only display entries with parent-match"),
471 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", 488 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent, call_order",
472 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " 489 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. "
473 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), 490 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
474 OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"), 491 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
492 "alias for inverted call graph"),
475 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 493 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
476 "only consider symbols in these dsos"), 494 "only consider symbols in these dsos"),
477 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 495 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
478 "only consider symbols in these comms"), 496 "only consider symbols in these comms"),
479 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 497 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
480 "only consider these symbols"), 498 "only consider these symbols"),
@@ -484,12 +502,13 @@ static const struct option options[] = {
484 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 502 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
485 "separator for columns, no spaces will be added between " 503 "separator for columns, no spaces will be added between "
486 "columns '.' is reserved."), 504 "columns '.' is reserved."),
487 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, 505 OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
488 "Only display entries resolved to a symbol"), 506 "Only display entries resolved to a symbol"),
489 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 507 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
490 "Look for files with symbols relative to this directory"), 508 "Look for files with symbols relative to this directory"),
491 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 509 OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
492 OPT_BOOLEAN('I', "show-info", &show_full_info, 510 "list of cpus to profile"),
511 OPT_BOOLEAN('I', "show-info", &report.show_full_info,
493 "Display extended information about perf.data file"), 512 "Display extended information about perf.data file"),
494 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, 513 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
495 "Interleave source code with assembly code (default)"), 514 "Interleave source code with assembly code (default)"),
@@ -500,21 +519,19 @@ static const struct option options[] = {
500 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 519 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
501 "Show a column with the sum of periods"), 520 "Show a column with the sum of periods"),
502 OPT_END() 521 OPT_END()
503}; 522 };
504 523
505int cmd_report(int argc, const char **argv, const char *prefix __used)
506{
507 argc = parse_options(argc, argv, options, report_usage, 0); 524 argc = parse_options(argc, argv, options, report_usage, 0);
508 525
509 if (use_stdio) 526 if (report.use_stdio)
510 use_browser = 0; 527 use_browser = 0;
511 else if (use_tui) 528 else if (report.use_tui)
512 use_browser = 1; 529 use_browser = 1;
513 530
514 if (inverted_callchain) 531 if (report.inverted_callchain)
515 callchain_param.order = ORDER_CALLER; 532 callchain_param.order = ORDER_CALLER;
516 533
517 if (strcmp(input_name, "-") != 0) 534 if (strcmp(report.input_name, "-") != 0)
518 setup_browser(true); 535 setup_browser(true);
519 else 536 else
520 use_browser = 0; 537 use_browser = 0;
@@ -525,7 +542,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
525 */ 542 */
526 if (use_browser > 0) { 543 if (use_browser > 0) {
527 symbol_conf.priv_size = sizeof(struct annotation); 544 symbol_conf.priv_size = sizeof(struct annotation);
528 annotate_init = symbol__annotate_init; 545 report.annotate_init = symbol__annotate_init;
529 /* 546 /*
530 * For searching by name on the "Browse map details". 547 * For searching by name on the "Browse map details".
531 * providing it only in verbose mode not to bloat too 548 * 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)
572 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 589 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
573 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); 590 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
574 591
575 return __cmd_report(); 592 return __cmd_report(&report);
576} 593}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 5177964943e..6284ed2317f 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -2,11 +2,14 @@
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/util.h" 4#include "util/util.h"
5#include "util/evlist.h"
5#include "util/cache.h" 6#include "util/cache.h"
7#include "util/evsel.h"
6#include "util/symbol.h" 8#include "util/symbol.h"
7#include "util/thread.h" 9#include "util/thread.h"
8#include "util/header.h" 10#include "util/header.h"
9#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h"
10 13
11#include "util/parse-options.h" 14#include "util/parse-options.h"
12#include "util/trace-event.h" 15#include "util/trace-event.h"
@@ -723,21 +726,21 @@ struct trace_migrate_task_event {
723 726
724struct trace_sched_handler { 727struct trace_sched_handler {
725 void (*switch_event)(struct trace_switch_event *, 728 void (*switch_event)(struct trace_switch_event *,
726 struct perf_session *, 729 struct machine *,
727 struct event *, 730 struct event *,
728 int cpu, 731 int cpu,
729 u64 timestamp, 732 u64 timestamp,
730 struct thread *thread); 733 struct thread *thread);
731 734
732 void (*runtime_event)(struct trace_runtime_event *, 735 void (*runtime_event)(struct trace_runtime_event *,
733 struct perf_session *, 736 struct machine *,
734 struct event *, 737 struct event *,
735 int cpu, 738 int cpu,
736 u64 timestamp, 739 u64 timestamp,
737 struct thread *thread); 740 struct thread *thread);
738 741
739 void (*wakeup_event)(struct trace_wakeup_event *, 742 void (*wakeup_event)(struct trace_wakeup_event *,
740 struct perf_session *, 743 struct machine *,
741 struct event *, 744 struct event *,
742 int cpu, 745 int cpu,
743 u64 timestamp, 746 u64 timestamp,
@@ -750,7 +753,7 @@ struct trace_sched_handler {
750 struct thread *thread); 753 struct thread *thread);
751 754
752 void (*migrate_task_event)(struct trace_migrate_task_event *, 755 void (*migrate_task_event)(struct trace_migrate_task_event *,
753 struct perf_session *session, 756 struct machine *machine,
754 struct event *, 757 struct event *,
755 int cpu, 758 int cpu,
756 u64 timestamp, 759 u64 timestamp,
@@ -760,7 +763,7 @@ struct trace_sched_handler {
760 763
761static void 764static void
762replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 765replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
763 struct perf_session *session __used, 766 struct machine *machine __used,
764 struct event *event, 767 struct event *event,
765 int cpu __used, 768 int cpu __used,
766 u64 timestamp __used, 769 u64 timestamp __used,
@@ -787,7 +790,7 @@ static u64 cpu_last_switched[MAX_CPUS];
787 790
788static void 791static void
789replay_switch_event(struct trace_switch_event *switch_event, 792replay_switch_event(struct trace_switch_event *switch_event,
790 struct perf_session *session __used, 793 struct machine *machine __used,
791 struct event *event, 794 struct event *event,
792 int cpu, 795 int cpu,
793 u64 timestamp, 796 u64 timestamp,
@@ -1021,7 +1024,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1021 1024
1022static void 1025static void
1023latency_switch_event(struct trace_switch_event *switch_event, 1026latency_switch_event(struct trace_switch_event *switch_event,
1024 struct perf_session *session, 1027 struct machine *machine,
1025 struct event *event __used, 1028 struct event *event __used,
1026 int cpu, 1029 int cpu,
1027 u64 timestamp, 1030 u64 timestamp,
@@ -1045,8 +1048,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1045 die("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1048 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1046 1049
1047 1050
1048 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1051 sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
1049 sched_in = perf_session__findnew(session, switch_event->next_pid); 1052 sched_in = machine__findnew_thread(machine, switch_event->next_pid);
1050 1053
1051 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1054 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1052 if (!out_events) { 1055 if (!out_events) {
@@ -1074,13 +1077,13 @@ latency_switch_event(struct trace_switch_event *switch_event,
1074 1077
1075static void 1078static void
1076latency_runtime_event(struct trace_runtime_event *runtime_event, 1079latency_runtime_event(struct trace_runtime_event *runtime_event,
1077 struct perf_session *session, 1080 struct machine *machine,
1078 struct event *event __used, 1081 struct event *event __used,
1079 int cpu, 1082 int cpu,
1080 u64 timestamp, 1083 u64 timestamp,
1081 struct thread *this_thread __used) 1084 struct thread *this_thread __used)
1082{ 1085{
1083 struct thread *thread = perf_session__findnew(session, runtime_event->pid); 1086 struct thread *thread = machine__findnew_thread(machine, runtime_event->pid);
1084 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1087 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1085 1088
1086 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1089 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
@@ -1097,7 +1100,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1097 1100
1098static void 1101static void
1099latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1102latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1100 struct perf_session *session, 1103 struct machine *machine,
1101 struct event *__event __used, 1104 struct event *__event __used,
1102 int cpu __used, 1105 int cpu __used,
1103 u64 timestamp, 1106 u64 timestamp,
@@ -1111,7 +1114,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1111 if (!wakeup_event->success) 1114 if (!wakeup_event->success)
1112 return; 1115 return;
1113 1116
1114 wakee = perf_session__findnew(session, wakeup_event->pid); 1117 wakee = machine__findnew_thread(machine, wakeup_event->pid);
1115 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1118 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1116 if (!atoms) { 1119 if (!atoms) {
1117 thread_atoms_insert(wakee); 1120 thread_atoms_insert(wakee);
@@ -1145,7 +1148,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1145 1148
1146static void 1149static void
1147latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, 1150latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1148 struct perf_session *session, 1151 struct machine *machine,
1149 struct event *__event __used, 1152 struct event *__event __used,
1150 int cpu __used, 1153 int cpu __used,
1151 u64 timestamp, 1154 u64 timestamp,
@@ -1161,7 +1164,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1161 if (profile_cpu == -1) 1164 if (profile_cpu == -1)
1162 return; 1165 return;
1163 1166
1164 migrant = perf_session__findnew(session, migrate_task_event->pid); 1167 migrant = machine__findnew_thread(machine, migrate_task_event->pid);
1165 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); 1168 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1166 if (!atoms) { 1169 if (!atoms) {
1167 thread_atoms_insert(migrant); 1170 thread_atoms_insert(migrant);
@@ -1356,12 +1359,13 @@ static void sort_lat(void)
1356static struct trace_sched_handler *trace_handler; 1359static struct trace_sched_handler *trace_handler;
1357 1360
1358static void 1361static void
1359process_sched_wakeup_event(void *data, struct perf_session *session, 1362process_sched_wakeup_event(struct perf_tool *tool __used,
1360 struct event *event, 1363 struct event *event,
1361 int cpu __used, 1364 struct perf_sample *sample,
1362 u64 timestamp __used, 1365 struct machine *machine,
1363 struct thread *thread __used) 1366 struct thread *thread)
1364{ 1367{
1368 void *data = sample->raw_data;
1365 struct trace_wakeup_event wakeup_event; 1369 struct trace_wakeup_event wakeup_event;
1366 1370
1367 FILL_COMMON_FIELDS(wakeup_event, event, data); 1371 FILL_COMMON_FIELDS(wakeup_event, event, data);
@@ -1373,8 +1377,8 @@ process_sched_wakeup_event(void *data, struct perf_session *session,
1373 FILL_FIELD(wakeup_event, cpu, event, data); 1377 FILL_FIELD(wakeup_event, cpu, event, data);
1374 1378
1375 if (trace_handler->wakeup_event) 1379 if (trace_handler->wakeup_event)
1376 trace_handler->wakeup_event(&wakeup_event, session, event, 1380 trace_handler->wakeup_event(&wakeup_event, machine, event,
1377 cpu, timestamp, thread); 1381 sample->cpu, sample->time, thread);
1378} 1382}
1379 1383
1380/* 1384/*
@@ -1392,7 +1396,7 @@ static char next_shortname2 = '0';
1392 1396
1393static void 1397static void
1394map_switch_event(struct trace_switch_event *switch_event, 1398map_switch_event(struct trace_switch_event *switch_event,
1395 struct perf_session *session, 1399 struct machine *machine,
1396 struct event *event __used, 1400 struct event *event __used,
1397 int this_cpu, 1401 int this_cpu,
1398 u64 timestamp, 1402 u64 timestamp,
@@ -1420,8 +1424,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1420 die("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1424 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1421 1425
1422 1426
1423 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1427 sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
1424 sched_in = perf_session__findnew(session, switch_event->next_pid); 1428 sched_in = machine__findnew_thread(machine, switch_event->next_pid);
1425 1429
1426 curr_thread[this_cpu] = sched_in; 1430 curr_thread[this_cpu] = sched_in;
1427 1431
@@ -1469,14 +1473,15 @@ map_switch_event(struct trace_switch_event *switch_event,
1469 } 1473 }
1470} 1474}
1471 1475
1472
1473static void 1476static void
1474process_sched_switch_event(void *data, struct perf_session *session, 1477process_sched_switch_event(struct perf_tool *tool __used,
1475 struct event *event, 1478 struct event *event,
1476 int this_cpu, 1479 struct perf_sample *sample,
1477 u64 timestamp __used, 1480 struct machine *machine,
1478 struct thread *thread __used) 1481 struct thread *thread)
1479{ 1482{
1483 int this_cpu = sample->cpu;
1484 void *data = sample->raw_data;
1480 struct trace_switch_event switch_event; 1485 struct trace_switch_event switch_event;
1481 1486
1482 FILL_COMMON_FIELDS(switch_event, event, data); 1487 FILL_COMMON_FIELDS(switch_event, event, data);
@@ -1498,19 +1503,20 @@ process_sched_switch_event(void *data, struct perf_session *session,
1498 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1499 } 1504 }
1500 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1501 trace_handler->switch_event(&switch_event, session, event, 1506 trace_handler->switch_event(&switch_event, machine, event,
1502 this_cpu, timestamp, thread); 1507 this_cpu, sample->time, thread);
1503 1508
1504 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1505} 1510}
1506 1511
1507static void 1512static void
1508process_sched_runtime_event(void *data, struct perf_session *session, 1513process_sched_runtime_event(struct perf_tool *tool __used,
1509 struct event *event, 1514 struct event *event,
1510 int cpu __used, 1515 struct perf_sample *sample,
1511 u64 timestamp __used, 1516 struct machine *machine,
1512 struct thread *thread __used) 1517 struct thread *thread)
1513{ 1518{
1519 void *data = sample->raw_data;
1514 struct trace_runtime_event runtime_event; 1520 struct trace_runtime_event runtime_event;
1515 1521
1516 FILL_ARRAY(runtime_event, comm, event, data); 1522 FILL_ARRAY(runtime_event, comm, event, data);
@@ -1519,16 +1525,18 @@ process_sched_runtime_event(void *data, struct perf_session *session,
1519 FILL_FIELD(runtime_event, vruntime, event, data); 1525 FILL_FIELD(runtime_event, vruntime, event, data);
1520 1526
1521 if (trace_handler->runtime_event) 1527 if (trace_handler->runtime_event)
1522 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread); 1528 trace_handler->runtime_event(&runtime_event, machine, event,
1529 sample->cpu, sample->time, thread);
1523} 1530}
1524 1531
1525static void 1532static void
1526process_sched_fork_event(void *data, 1533process_sched_fork_event(struct perf_tool *tool __used,
1527 struct event *event, 1534 struct event *event,
1528 int cpu __used, 1535 struct perf_sample *sample,
1529 u64 timestamp __used, 1536 struct machine *machine __used,
1530 struct thread *thread __used) 1537 struct thread *thread)
1531{ 1538{
1539 void *data = sample->raw_data;
1532 struct trace_fork_event fork_event; 1540 struct trace_fork_event fork_event;
1533 1541
1534 FILL_COMMON_FIELDS(fork_event, event, data); 1542 FILL_COMMON_FIELDS(fork_event, event, data);
@@ -1540,13 +1548,14 @@ process_sched_fork_event(void *data,
1540 1548
1541 if (trace_handler->fork_event) 1549 if (trace_handler->fork_event)
1542 trace_handler->fork_event(&fork_event, event, 1550 trace_handler->fork_event(&fork_event, event,
1543 cpu, timestamp, thread); 1551 sample->cpu, sample->time, thread);
1544} 1552}
1545 1553
1546static void 1554static void
1547process_sched_exit_event(struct event *event, 1555process_sched_exit_event(struct perf_tool *tool __used,
1548 int cpu __used, 1556 struct event *event,
1549 u64 timestamp __used, 1557 struct perf_sample *sample __used,
1558 struct machine *machine __used,
1550 struct thread *thread __used) 1559 struct thread *thread __used)
1551{ 1560{
1552 if (verbose) 1561 if (verbose)
@@ -1554,12 +1563,13 @@ process_sched_exit_event(struct event *event,
1554} 1563}
1555 1564
1556static void 1565static void
1557process_sched_migrate_task_event(void *data, struct perf_session *session, 1566process_sched_migrate_task_event(struct perf_tool *tool __used,
1558 struct event *event, 1567 struct event *event,
1559 int cpu __used, 1568 struct perf_sample *sample,
1560 u64 timestamp __used, 1569 struct machine *machine,
1561 struct thread *thread __used) 1570 struct thread *thread)
1562{ 1571{
1572 void *data = sample->raw_data;
1563 struct trace_migrate_task_event migrate_task_event; 1573 struct trace_migrate_task_event migrate_task_event;
1564 1574
1565 FILL_COMMON_FIELDS(migrate_task_event, event, data); 1575 FILL_COMMON_FIELDS(migrate_task_event, event, data);
@@ -1570,67 +1580,47 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
1570 FILL_FIELD(migrate_task_event, cpu, event, data); 1580 FILL_FIELD(migrate_task_event, cpu, event, data);
1571 1581
1572 if (trace_handler->migrate_task_event) 1582 if (trace_handler->migrate_task_event)
1573 trace_handler->migrate_task_event(&migrate_task_event, session, 1583 trace_handler->migrate_task_event(&migrate_task_event, machine,
1574 event, cpu, timestamp, thread); 1584 event, sample->cpu,
1585 sample->time, thread);
1575} 1586}
1576 1587
1577static void process_raw_event(union perf_event *raw_event __used, 1588typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event,
1578 struct perf_session *session, void *data, int cpu, 1589 struct perf_sample *sample,
1579 u64 timestamp, struct thread *thread) 1590 struct machine *machine,
1580{ 1591 struct thread *thread);
1581 struct event *event;
1582 int type;
1583
1584
1585 type = trace_parse_common_type(data);
1586 event = trace_find_event(type);
1587
1588 if (!strcmp(event->name, "sched_switch"))
1589 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1590 if (!strcmp(event->name, "sched_stat_runtime"))
1591 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1592 if (!strcmp(event->name, "sched_wakeup"))
1593 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1594 if (!strcmp(event->name, "sched_wakeup_new"))
1595 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1596 if (!strcmp(event->name, "sched_process_fork"))
1597 process_sched_fork_event(data, event, cpu, timestamp, thread);
1598 if (!strcmp(event->name, "sched_process_exit"))
1599 process_sched_exit_event(event, cpu, timestamp, thread);
1600 if (!strcmp(event->name, "sched_migrate_task"))
1601 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1602}
1603 1592
1604static int process_sample_event(union perf_event *event, 1593static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
1605 struct perf_sample *sample, 1594 union perf_event *event __used,
1606 struct perf_evsel *evsel __used, 1595 struct perf_sample *sample,
1607 struct perf_session *session) 1596 struct perf_evsel *evsel,
1597 struct machine *machine)
1608{ 1598{
1609 struct thread *thread; 1599 struct thread *thread = machine__findnew_thread(machine, sample->pid);
1610
1611 if (!(session->sample_type & PERF_SAMPLE_RAW))
1612 return 0;
1613 1600
1614 thread = perf_session__findnew(session, sample->pid);
1615 if (thread == NULL) { 1601 if (thread == NULL) {
1616 pr_debug("problem processing %d event, skipping it.\n", 1602 pr_debug("problem processing %s event, skipping it.\n",
1617 event->header.type); 1603 evsel->name);
1618 return -1; 1604 return -1;
1619 } 1605 }
1620 1606
1621 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1607 evsel->hists.stats.total_period += sample->period;
1608 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
1622 1609
1623 if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) 1610 if (evsel->handler.func != NULL) {
1624 return 0; 1611 tracepoint_handler f = evsel->handler.func;
1625 1612
1626 process_raw_event(event, session, sample->raw_data, sample->cpu, 1613 if (evsel->handler.data == NULL)
1627 sample->time, thread); 1614 evsel->handler.data = trace_find_event(evsel->attr.config);
1615
1616 f(tool, evsel->handler.data, sample, machine, thread);
1617 }
1628 1618
1629 return 0; 1619 return 0;
1630} 1620}
1631 1621
1632static struct perf_event_ops event_ops = { 1622static struct perf_tool perf_sched = {
1633 .sample = process_sample_event, 1623 .sample = perf_sched__process_tracepoint_sample,
1634 .comm = perf_event__process_comm, 1624 .comm = perf_event__process_comm,
1635 .lost = perf_event__process_lost, 1625 .lost = perf_event__process_lost,
1636 .fork = perf_event__process_task, 1626 .fork = perf_event__process_task,
@@ -1640,13 +1630,25 @@ static struct perf_event_ops event_ops = {
1640static void read_events(bool destroy, struct perf_session **psession) 1630static void read_events(bool destroy, struct perf_session **psession)
1641{ 1631{
1642 int err = -EINVAL; 1632 int err = -EINVAL;
1633 const struct perf_evsel_str_handler handlers[] = {
1634 { "sched:sched_switch", process_sched_switch_event, },
1635 { "sched:sched_stat_runtime", process_sched_runtime_event, },
1636 { "sched:sched_wakeup", process_sched_wakeup_event, },
1637 { "sched:sched_wakeup_new", process_sched_wakeup_event, },
1638 { "sched:sched_process_fork", process_sched_fork_event, },
1639 { "sched:sched_process_exit", process_sched_exit_event, },
1640 { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1641 };
1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 1642 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1644 0, false, &event_ops); 1643 0, false, &perf_sched);
1645 if (session == NULL) 1644 if (session == NULL)
1646 die("No Memory"); 1645 die("No Memory");
1647 1646
1647 err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers);
1648 assert(err == 0);
1649
1648 if (perf_session__has_traces(session, "record -R")) { 1650 if (perf_session__has_traces(session, "record -R")) {
1649 err = perf_session__process_events(session, &event_ops); 1651 err = perf_session__process_events(session, &perf_sched);
1650 if (err) 1652 if (err)
1651 die("Failed to process events, error %d", err); 1653 die("Failed to process events, error %d", err);
1652 1654
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 2f62a295226..619d6dcaa1d 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -7,6 +7,7 @@
7#include "util/header.h" 7#include "util/header.h"
8#include "util/parse-options.h" 8#include "util/parse-options.h"
9#include "util/session.h" 9#include "util/session.h"
10#include "util/tool.h"
10#include "util/symbol.h" 11#include "util/symbol.h"
11#include "util/thread.h" 12#include "util/thread.h"
12#include "util/trace-event.h" 13#include "util/trace-event.h"
@@ -315,7 +316,7 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
315 316
316static void print_sample_addr(union perf_event *event, 317static void print_sample_addr(union perf_event *event,
317 struct perf_sample *sample, 318 struct perf_sample *sample,
318 struct perf_session *session, 319 struct machine *machine,
319 struct thread *thread, 320 struct thread *thread,
320 struct perf_event_attr *attr) 321 struct perf_event_attr *attr)
321{ 322{
@@ -328,11 +329,11 @@ static void print_sample_addr(union perf_event *event,
328 if (!sample_addr_correlates_sym(attr)) 329 if (!sample_addr_correlates_sym(attr))
329 return; 330 return;
330 331
331 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 332 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
332 event->ip.pid, sample->addr, &al); 333 sample->addr, &al);
333 if (!al.map) 334 if (!al.map)
334 thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE, 335 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
335 event->ip.pid, sample->addr, &al); 336 sample->addr, &al);
336 337
337 al.cpu = sample->cpu; 338 al.cpu = sample->cpu;
338 al.sym = NULL; 339 al.sym = NULL;
@@ -362,7 +363,7 @@ static void print_sample_addr(union perf_event *event,
362static void process_event(union perf_event *event __unused, 363static void process_event(union perf_event *event __unused,
363 struct perf_sample *sample, 364 struct perf_sample *sample,
364 struct perf_evsel *evsel, 365 struct perf_evsel *evsel,
365 struct perf_session *session, 366 struct machine *machine,
366 struct thread *thread) 367 struct thread *thread)
367{ 368{
368 struct perf_event_attr *attr = &evsel->attr; 369 struct perf_event_attr *attr = &evsel->attr;
@@ -377,15 +378,15 @@ static void process_event(union perf_event *event __unused,
377 sample->raw_size); 378 sample->raw_size);
378 379
379 if (PRINT_FIELD(ADDR)) 380 if (PRINT_FIELD(ADDR))
380 print_sample_addr(event, sample, session, thread, attr); 381 print_sample_addr(event, sample, machine, thread, attr);
381 382
382 if (PRINT_FIELD(IP)) { 383 if (PRINT_FIELD(IP)) {
383 if (!symbol_conf.use_callchain) 384 if (!symbol_conf.use_callchain)
384 printf(" "); 385 printf(" ");
385 else 386 else
386 printf("\n"); 387 printf("\n");
387 perf_session__print_ip(event, sample, session, 388 perf_event__print_ip(event, sample, machine, evsel,
388 PRINT_FIELD(SYM), PRINT_FIELD(DSO)); 389 PRINT_FIELD(SYM), PRINT_FIELD(DSO));
389 } 390 }
390 391
391 printf("\n"); 392 printf("\n");
@@ -434,12 +435,14 @@ static int cleanup_scripting(void)
434 435
435static char const *input_name = "perf.data"; 436static char const *input_name = "perf.data";
436 437
437static int process_sample_event(union perf_event *event, 438static int process_sample_event(struct perf_tool *tool __used,
439 union perf_event *event,
438 struct perf_sample *sample, 440 struct perf_sample *sample,
439 struct perf_evsel *evsel, 441 struct perf_evsel *evsel,
440 struct perf_session *session) 442 struct machine *machine)
441{ 443{
442 struct thread *thread = perf_session__findnew(session, event->ip.pid); 444 struct addr_location al;
445 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
443 446
444 if (thread == NULL) { 447 if (thread == NULL) {
445 pr_debug("problem processing %d event, skipping it.\n", 448 pr_debug("problem processing %d event, skipping it.\n",
@@ -458,16 +461,25 @@ static int process_sample_event(union perf_event *event,
458 return 0; 461 return 0;
459 } 462 }
460 463
464 if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) {
465 pr_err("problem processing %d event, skipping it.\n",
466 event->header.type);
467 return -1;
468 }
469
470 if (al.filtered)
471 return 0;
472
461 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 473 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
462 return 0; 474 return 0;
463 475
464 scripting_ops->process_event(event, sample, evsel, session, thread); 476 scripting_ops->process_event(event, sample, evsel, machine, thread);
465 477
466 session->hists.stats.total_period += sample->period; 478 evsel->hists.stats.total_period += sample->period;
467 return 0; 479 return 0;
468} 480}
469 481
470static struct perf_event_ops event_ops = { 482static struct perf_tool perf_script = {
471 .sample = process_sample_event, 483 .sample = process_sample_event,
472 .mmap = perf_event__process_mmap, 484 .mmap = perf_event__process_mmap,
473 .comm = perf_event__process_comm, 485 .comm = perf_event__process_comm,
@@ -494,7 +506,7 @@ static int __cmd_script(struct perf_session *session)
494 506
495 signal(SIGINT, sig_handler); 507 signal(SIGINT, sig_handler);
496 508
497 ret = perf_session__process_events(session, &event_ops); 509 ret = perf_session__process_events(session, &perf_script);
498 510
499 if (debug_mode) 511 if (debug_mode)
500 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); 512 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -1083,7 +1095,9 @@ static const struct option options[] = {
1083 OPT_CALLBACK('f', "fields", NULL, "str", 1095 OPT_CALLBACK('f', "fields", NULL, "str",
1084 "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", 1096 "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",
1085 parse_output_fields), 1097 parse_output_fields),
1086 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 1098 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1099 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1100 "only display events for these comms"),
1087 OPT_BOOLEAN('I', "show-info", &show_full_info, 1101 OPT_BOOLEAN('I', "show-info", &show_full_info,
1088 "display extended information from perf.data file"), 1102 "display extended information from perf.data file"),
1089 OPT_END() 1103 OPT_END()
@@ -1261,7 +1275,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1261 if (!script_name) 1275 if (!script_name)
1262 setup_pager(); 1276 setup_pager();
1263 1277
1264 session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops); 1278 session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script);
1265 if (session == NULL) 1279 if (session == NULL)
1266 return -ENOMEM; 1280 return -ENOMEM;
1267 1281
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 955930e0a5c..cc53de335ce 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1108,22 +1108,13 @@ static const struct option options[] = {
1108 */ 1108 */
1109static int add_default_attributes(void) 1109static int add_default_attributes(void)
1110{ 1110{
1111 struct perf_evsel *pos;
1112 size_t attr_nr = 0;
1113 size_t c;
1114
1115 /* Set attrs if no event is selected and !null_run: */ 1111 /* Set attrs if no event is selected and !null_run: */
1116 if (null_run) 1112 if (null_run)
1117 return 0; 1113 return 0;
1118 1114
1119 if (!evsel_list->nr_entries) { 1115 if (!evsel_list->nr_entries) {
1120 for (c = 0; c < ARRAY_SIZE(default_attrs); c++) { 1116 if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0)
1121 pos = perf_evsel__new(default_attrs + c, c + attr_nr); 1117 return -1;
1122 if (pos == NULL)
1123 return -1;
1124 perf_evlist__add(evsel_list, pos);
1125 }
1126 attr_nr += c;
1127 } 1118 }
1128 1119
1129 /* Detailed events get appended to the event list: */ 1120 /* Detailed events get appended to the event list: */
@@ -1132,38 +1123,21 @@ static int add_default_attributes(void)
1132 return 0; 1123 return 0;
1133 1124
1134 /* Append detailed run extra attributes: */ 1125 /* Append detailed run extra attributes: */
1135 for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) { 1126 if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0)
1136 pos = perf_evsel__new(detailed_attrs + c, c + attr_nr); 1127 return -1;
1137 if (pos == NULL)
1138 return -1;
1139 perf_evlist__add(evsel_list, pos);
1140 }
1141 attr_nr += c;
1142 1128
1143 if (detailed_run < 2) 1129 if (detailed_run < 2)
1144 return 0; 1130 return 0;
1145 1131
1146 /* Append very detailed run extra attributes: */ 1132 /* Append very detailed run extra attributes: */
1147 for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) { 1133 if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0)
1148 pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr); 1134 return -1;
1149 if (pos == NULL)
1150 return -1;
1151 perf_evlist__add(evsel_list, pos);
1152 }
1153 1135
1154 if (detailed_run < 3) 1136 if (detailed_run < 3)
1155 return 0; 1137 return 0;
1156 1138
1157 /* Append very, very detailed run extra attributes: */ 1139 /* Append very, very detailed run extra attributes: */
1158 for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) { 1140 return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs);
1159 pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr);
1160 if (pos == NULL)
1161 return -1;
1162 perf_evlist__add(evsel_list, pos);
1163 }
1164
1165
1166 return 0;
1167} 1141}
1168 1142
1169int cmd_stat(int argc, const char **argv, const char *prefix __used) 1143int cmd_stat(int argc, const char **argv, const char *prefix __used)
@@ -1267,8 +1241,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1267 1241
1268 list_for_each_entry(pos, &evsel_list->entries, node) { 1242 list_for_each_entry(pos, &evsel_list->entries, node) {
1269 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1243 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
1270 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 || 1244 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0)
1271 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
1272 goto out_free_fd; 1245 goto out_free_fd;
1273 } 1246 }
1274 1247
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 831d1baeac3..6173f780dce 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -7,6 +7,7 @@
7 7
8#include "util/cache.h" 8#include "util/cache.h"
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/debugfs.h"
10#include "util/evlist.h" 11#include "util/evlist.h"
11#include "util/parse-options.h" 12#include "util/parse-options.h"
12#include "util/parse-events.h" 13#include "util/parse-events.h"
@@ -14,8 +15,6 @@
14#include "util/thread_map.h" 15#include "util/thread_map.h"
15#include "../../include/linux/hw_breakpoint.h" 16#include "../../include/linux/hw_breakpoint.h"
16 17
17static long page_size;
18
19static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) 18static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
20{ 19{
21 bool *visited = symbol__priv(sym); 20 bool *visited = symbol__priv(sym);
@@ -31,6 +30,7 @@ static int test__vmlinux_matches_kallsyms(void)
31 struct map *kallsyms_map, *vmlinux_map; 30 struct map *kallsyms_map, *vmlinux_map;
32 struct machine kallsyms, vmlinux; 31 struct machine kallsyms, vmlinux;
33 enum map_type type = MAP__FUNCTION; 32 enum map_type type = MAP__FUNCTION;
33 long page_size = sysconf(_SC_PAGE_SIZE);
34 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; 34 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
35 35
36 /* 36 /*
@@ -247,7 +247,7 @@ static int trace_event__id(const char *evname)
247 247
248 if (asprintf(&filename, 248 if (asprintf(&filename,
249 "%s/syscalls/%s/id", 249 "%s/syscalls/%s/id",
250 debugfs_path, evname) < 0) 250 tracing_events_path, evname) < 0)
251 return -1; 251 return -1;
252 252
253 fd = open(filename, O_RDONLY); 253 fd = open(filename, O_RDONLY);
@@ -841,6 +841,336 @@ static int test__parse_events(void)
841 841
842 return ret; 842 return ret;
843} 843}
844
845static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
846 size_t *sizep)
847{
848 cpu_set_t *mask;
849 size_t size;
850 int i, cpu = -1, nrcpus = 1024;
851realloc:
852 mask = CPU_ALLOC(nrcpus);
853 size = CPU_ALLOC_SIZE(nrcpus);
854 CPU_ZERO_S(size, mask);
855
856 if (sched_getaffinity(pid, size, mask) == -1) {
857 CPU_FREE(mask);
858 if (errno == EINVAL && nrcpus < (1024 << 8)) {
859 nrcpus = nrcpus << 2;
860 goto realloc;
861 }
862 perror("sched_getaffinity");
863 return -1;
864 }
865
866 for (i = 0; i < nrcpus; i++) {
867 if (CPU_ISSET_S(i, size, mask)) {
868 if (cpu == -1) {
869 cpu = i;
870 *maskp = mask;
871 *sizep = size;
872 } else
873 CPU_CLR_S(i, size, mask);
874 }
875 }
876
877 if (cpu == -1)
878 CPU_FREE(mask);
879
880 return cpu;
881}
882
883static int test__PERF_RECORD(void)
884{
885 struct perf_record_opts opts = {
886 .target_pid = -1,
887 .target_tid = -1,
888 .no_delay = true,
889 .freq = 10,
890 .mmap_pages = 256,
891 .sample_id_all_avail = true,
892 };
893 cpu_set_t *cpu_mask = NULL;
894 size_t cpu_mask_size = 0;
895 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
896 struct perf_evsel *evsel;
897 struct perf_sample sample;
898 const char *cmd = "sleep";
899 const char *argv[] = { cmd, "1", NULL, };
900 char *bname;
901 u64 sample_type, prev_time = 0;
902 bool found_cmd_mmap = false,
903 found_libc_mmap = false,
904 found_vdso_mmap = false,
905 found_ld_mmap = false;
906 int err = -1, errs = 0, i, wakeups = 0, sample_size;
907 u32 cpu;
908 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
909
910 if (evlist == NULL || argv == NULL) {
911 pr_debug("Not enough memory to create evlist\n");
912 goto out;
913 }
914
915 /*
916 * We need at least one evsel in the evlist, use the default
917 * one: "cycles".
918 */
919 err = perf_evlist__add_default(evlist);
920 if (err < 0) {
921 pr_debug("Not enough memory to create evsel\n");
922 goto out_delete_evlist;
923 }
924
925 /*
926 * Create maps of threads and cpus to monitor. In this case
927 * we start with all threads and cpus (-1, -1) but then in
928 * perf_evlist__prepare_workload we'll fill in the only thread
929 * we're monitoring, the one forked there.
930 */
931 err = perf_evlist__create_maps(evlist, opts.target_pid,
932 opts.target_tid, opts.cpu_list);
933 if (err < 0) {
934 pr_debug("Not enough memory to create thread/cpu maps\n");
935 goto out_delete_evlist;
936 }
937
938 /*
939 * Prepare the workload in argv[] to run, it'll fork it, and then wait
940 * for perf_evlist__start_workload() to exec it. This is done this way
941 * so that we have time to open the evlist (calling sys_perf_event_open
942 * on all the fds) and then mmap them.
943 */
944 err = perf_evlist__prepare_workload(evlist, &opts, argv);
945 if (err < 0) {
946 pr_debug("Couldn't run the workload!\n");
947 goto out_delete_evlist;
948 }
949
950 /*
951 * Config the evsels, setting attr->comm on the first one, etc.
952 */
953 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
954 evsel->attr.sample_type |= PERF_SAMPLE_CPU;
955 evsel->attr.sample_type |= PERF_SAMPLE_TID;
956 evsel->attr.sample_type |= PERF_SAMPLE_TIME;
957 perf_evlist__config_attrs(evlist, &opts);
958
959 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask,
960 &cpu_mask_size);
961 if (err < 0) {
962 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
963 goto out_delete_evlist;
964 }
965
966 cpu = err;
967
968 /*
969 * So that we can check perf_sample.cpu on all the samples.
970 */
971 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) {
972 pr_debug("sched_setaffinity: %s\n", strerror(errno));
973 goto out_free_cpu_mask;
974 }
975
976 /*
977 * Call sys_perf_event_open on all the fds on all the evsels,
978 * grouping them if asked to.
979 */
980 err = perf_evlist__open(evlist, opts.group);
981 if (err < 0) {
982 pr_debug("perf_evlist__open: %s\n", strerror(errno));
983 goto out_delete_evlist;
984 }
985
986 /*
987 * mmap the first fd on a given CPU and ask for events for the other
988 * fds in the same CPU to be injected in the same mmap ring buffer
989 * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
990 */
991 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
992 if (err < 0) {
993 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
994 goto out_delete_evlist;
995 }
996
997 /*
998 * We'll need these two to parse the PERF_SAMPLE_* fields in each
999 * event.
1000 */
1001 sample_type = perf_evlist__sample_type(evlist);
1002 sample_size = __perf_evsel__sample_size(sample_type);
1003
1004 /*
1005 * Now that all is properly set up, enable the events, they will
1006 * count just on workload.pid, which will start...
1007 */
1008 perf_evlist__enable(evlist);
1009
1010 /*
1011 * Now!
1012 */
1013 perf_evlist__start_workload(evlist);
1014
1015 while (1) {
1016 int before = total_events;
1017
1018 for (i = 0; i < evlist->nr_mmaps; i++) {
1019 union perf_event *event;
1020
1021 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1022 const u32 type = event->header.type;
1023 const char *name = perf_event__name(type);
1024
1025 ++total_events;
1026 if (type < PERF_RECORD_MAX)
1027 nr_events[type]++;
1028
1029 err = perf_event__parse_sample(event, sample_type,
1030 sample_size, true,
1031 &sample, false);
1032 if (err < 0) {
1033 if (verbose)
1034 perf_event__fprintf(event, stderr);
1035 pr_debug("Couldn't parse sample\n");
1036 goto out_err;
1037 }
1038
1039 if (verbose) {
1040 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
1041 perf_event__fprintf(event, stderr);
1042 }
1043
1044 if (prev_time > sample.time) {
1045 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
1046 name, prev_time, sample.time);
1047 ++errs;
1048 }
1049
1050 prev_time = sample.time;
1051
1052 if (sample.cpu != cpu) {
1053 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
1054 name, cpu, sample.cpu);
1055 ++errs;
1056 }
1057
1058 if ((pid_t)sample.pid != evlist->workload.pid) {
1059 pr_debug("%s with unexpected pid, expected %d, got %d\n",
1060 name, evlist->workload.pid, sample.pid);
1061 ++errs;
1062 }
1063
1064 if ((pid_t)sample.tid != evlist->workload.pid) {
1065 pr_debug("%s with unexpected tid, expected %d, got %d\n",
1066 name, evlist->workload.pid, sample.tid);
1067 ++errs;
1068 }
1069
1070 if ((type == PERF_RECORD_COMM ||
1071 type == PERF_RECORD_MMAP ||
1072 type == PERF_RECORD_FORK ||
1073 type == PERF_RECORD_EXIT) &&
1074 (pid_t)event->comm.pid != evlist->workload.pid) {
1075 pr_debug("%s with unexpected pid/tid\n", name);
1076 ++errs;
1077 }
1078
1079 if ((type == PERF_RECORD_COMM ||
1080 type == PERF_RECORD_MMAP) &&
1081 event->comm.pid != event->comm.tid) {
1082 pr_debug("%s with different pid/tid!\n", name);
1083 ++errs;
1084 }
1085
1086 switch (type) {
1087 case PERF_RECORD_COMM:
1088 if (strcmp(event->comm.comm, cmd)) {
1089 pr_debug("%s with unexpected comm!\n", name);
1090 ++errs;
1091 }
1092 break;
1093 case PERF_RECORD_EXIT:
1094 goto found_exit;
1095 case PERF_RECORD_MMAP:
1096 bname = strrchr(event->mmap.filename, '/');
1097 if (bname != NULL) {
1098 if (!found_cmd_mmap)
1099 found_cmd_mmap = !strcmp(bname + 1, cmd);
1100 if (!found_libc_mmap)
1101 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
1102 if (!found_ld_mmap)
1103 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
1104 } else if (!found_vdso_mmap)
1105 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
1106 break;
1107
1108 case PERF_RECORD_SAMPLE:
1109 /* Just ignore samples for now */
1110 break;
1111 default:
1112 pr_debug("Unexpected perf_event->header.type %d!\n",
1113 type);
1114 ++errs;
1115 }
1116 }
1117 }
1118
1119 /*
1120 * We don't use poll here because at least at 3.1 times the
1121 * PERF_RECORD_{!SAMPLE} events don't honour
1122 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
1123 */
1124 if (total_events == before && false)
1125 poll(evlist->pollfd, evlist->nr_fds, -1);
1126
1127 sleep(1);
1128 if (++wakeups > 5) {
1129 pr_debug("No PERF_RECORD_EXIT event!\n");
1130 break;
1131 }
1132 }
1133
1134found_exit:
1135 if (nr_events[PERF_RECORD_COMM] > 1) {
1136 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
1137 ++errs;
1138 }
1139
1140 if (nr_events[PERF_RECORD_COMM] == 0) {
1141 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
1142 ++errs;
1143 }
1144
1145 if (!found_cmd_mmap) {
1146 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
1147 ++errs;
1148 }
1149
1150 if (!found_libc_mmap) {
1151 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
1152 ++errs;
1153 }
1154
1155 if (!found_ld_mmap) {
1156 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
1157 ++errs;
1158 }
1159
1160 if (!found_vdso_mmap) {
1161 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
1162 ++errs;
1163 }
1164out_err:
1165 perf_evlist__munmap(evlist);
1166out_free_cpu_mask:
1167 CPU_FREE(cpu_mask);
1168out_delete_evlist:
1169 perf_evlist__delete(evlist);
1170out:
1171 return (err < 0 || errs > 0) ? -1 : 0;
1172}
1173
844static struct test { 1174static struct test {
845 const char *desc; 1175 const char *desc;
846 int (*func)(void); 1176 int (*func)(void);
@@ -866,45 +1196,89 @@ static struct test {
866 .func = test__parse_events, 1196 .func = test__parse_events,
867 }, 1197 },
868 { 1198 {
1199 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
1200 .func = test__PERF_RECORD,
1201 },
1202 {
869 .func = NULL, 1203 .func = NULL,
870 }, 1204 },
871}; 1205};
872 1206
873static int __cmd_test(void) 1207static bool perf_test__matches(int curr, int argc, const char *argv[])
874{ 1208{
875 int i = 0; 1209 int i;
1210
1211 if (argc == 0)
1212 return true;
876 1213
877 page_size = sysconf(_SC_PAGE_SIZE); 1214 for (i = 0; i < argc; ++i) {
1215 char *end;
1216 long nr = strtoul(argv[i], &end, 10);
1217
1218 if (*end == '\0') {
1219 if (nr == curr + 1)
1220 return true;
1221 continue;
1222 }
1223
1224 if (strstr(tests[curr].desc, argv[i]))
1225 return true;
1226 }
1227
1228 return false;
1229}
1230
1231static int __cmd_test(int argc, const char *argv[])
1232{
1233 int i = 0;
878 1234
879 while (tests[i].func) { 1235 while (tests[i].func) {
880 int err; 1236 int curr = i++, err;
881 pr_info("%2d: %s:", i + 1, tests[i].desc); 1237
1238 if (!perf_test__matches(curr, argc, argv))
1239 continue;
1240
1241 pr_info("%2d: %s:", i, tests[curr].desc);
882 pr_debug("\n--- start ---\n"); 1242 pr_debug("\n--- start ---\n");
883 err = tests[i].func(); 1243 err = tests[curr].func();
884 pr_debug("---- end ----\n%s:", tests[i].desc); 1244 pr_debug("---- end ----\n%s:", tests[curr].desc);
885 pr_info(" %s\n", err ? "FAILED!\n" : "Ok"); 1245 pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
886 ++i;
887 } 1246 }
888 1247
889 return 0; 1248 return 0;
890} 1249}
891 1250
892static const char * const test_usage[] = { 1251static int perf_test__list(int argc, const char **argv)
893 "perf test [<options>]", 1252{
894 NULL, 1253 int i = 0;
895};
896 1254
897static const struct option test_options[] = { 1255 while (tests[i].func) {
1256 int curr = i++;
1257
1258 if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
1259 continue;
1260
1261 pr_info("%2d: %s\n", i, tests[curr].desc);
1262 }
1263
1264 return 0;
1265}
1266
1267int cmd_test(int argc, const char **argv, const char *prefix __used)
1268{
1269 const char * const test_usage[] = {
1270 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
1271 NULL,
1272 };
1273 const struct option test_options[] = {
898 OPT_INTEGER('v', "verbose", &verbose, 1274 OPT_INTEGER('v', "verbose", &verbose,
899 "be more verbose (show symbol address, etc)"), 1275 "be more verbose (show symbol address, etc)"),
900 OPT_END() 1276 OPT_END()
901}; 1277 };
902 1278
903int cmd_test(int argc, const char **argv, const char *prefix __used)
904{
905 argc = parse_options(argc, argv, test_options, test_usage, 0); 1279 argc = parse_options(argc, argv, test_options, test_usage, 0);
906 if (argc) 1280 if (argc >= 1 && !strcmp(argv[0], "list"))
907 usage_with_options(test_usage, test_options); 1281 return perf_test__list(argc, argv);
908 1282
909 symbol_conf.priv_size = sizeof(int); 1283 symbol_conf.priv_size = sizeof(int);
910 symbol_conf.sort_by_name = true; 1284 symbol_conf.sort_by_name = true;
@@ -915,5 +1289,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used)
915 1289
916 setup_pager(); 1290 setup_pager();
917 1291
918 return __cmd_test(); 1292 return __cmd_test(argc, argv);
919} 1293}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index aa26f4d66d1..135376a37f9 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -19,6 +19,7 @@
19#include "util/color.h" 19#include "util/color.h"
20#include <linux/list.h> 20#include <linux/list.h>
21#include "util/cache.h" 21#include "util/cache.h"
22#include "util/evsel.h"
22#include <linux/rbtree.h> 23#include <linux/rbtree.h>
23#include "util/symbol.h" 24#include "util/symbol.h"
24#include "util/callchain.h" 25#include "util/callchain.h"
@@ -31,6 +32,7 @@
31#include "util/event.h" 32#include "util/event.h"
32#include "util/session.h" 33#include "util/session.h"
33#include "util/svghelper.h" 34#include "util/svghelper.h"
35#include "util/tool.h"
34 36
35#define SUPPORT_OLD_POWER_EVENTS 1 37#define SUPPORT_OLD_POWER_EVENTS 1
36#define PWR_EVENT_EXIT -1 38#define PWR_EVENT_EXIT -1
@@ -273,25 +275,28 @@ static int cpus_cstate_state[MAX_CPUS];
273static u64 cpus_pstate_start_times[MAX_CPUS]; 275static u64 cpus_pstate_start_times[MAX_CPUS];
274static u64 cpus_pstate_state[MAX_CPUS]; 276static u64 cpus_pstate_state[MAX_CPUS];
275 277
276static int process_comm_event(union perf_event *event, 278static int process_comm_event(struct perf_tool *tool __used,
279 union perf_event *event,
277 struct perf_sample *sample __used, 280 struct perf_sample *sample __used,
278 struct perf_session *session __used) 281 struct machine *machine __used)
279{ 282{
280 pid_set_comm(event->comm.tid, event->comm.comm); 283 pid_set_comm(event->comm.tid, event->comm.comm);
281 return 0; 284 return 0;
282} 285}
283 286
284static int process_fork_event(union perf_event *event, 287static int process_fork_event(struct perf_tool *tool __used,
288 union perf_event *event,
285 struct perf_sample *sample __used, 289 struct perf_sample *sample __used,
286 struct perf_session *session __used) 290 struct machine *machine __used)
287{ 291{
288 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 292 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
289 return 0; 293 return 0;
290} 294}
291 295
292static int process_exit_event(union perf_event *event, 296static int process_exit_event(struct perf_tool *tool __used,
297 union perf_event *event,
293 struct perf_sample *sample __used, 298 struct perf_sample *sample __used,
294 struct perf_session *session __used) 299 struct machine *machine __used)
295{ 300{
296 pid_exit(event->fork.pid, event->fork.time); 301 pid_exit(event->fork.pid, event->fork.time);
297 return 0; 302 return 0;
@@ -486,14 +491,15 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
486} 491}
487 492
488 493
489static int process_sample_event(union perf_event *event __used, 494static int process_sample_event(struct perf_tool *tool __used,
495 union perf_event *event __used,
490 struct perf_sample *sample, 496 struct perf_sample *sample,
491 struct perf_evsel *evsel __used, 497 struct perf_evsel *evsel,
492 struct perf_session *session) 498 struct machine *machine __used)
493{ 499{
494 struct trace_entry *te; 500 struct trace_entry *te;
495 501
496 if (session->sample_type & PERF_SAMPLE_TIME) { 502 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
497 if (!first_time || first_time > sample->time) 503 if (!first_time || first_time > sample->time)
498 first_time = sample->time; 504 first_time = sample->time;
499 if (last_time < sample->time) 505 if (last_time < sample->time)
@@ -501,7 +507,7 @@ static int process_sample_event(union perf_event *event __used,
501 } 507 }
502 508
503 te = (void *)sample->raw_data; 509 te = (void *)sample->raw_data;
504 if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) { 510 if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
505 char *event_str; 511 char *event_str;
506#ifdef SUPPORT_OLD_POWER_EVENTS 512#ifdef SUPPORT_OLD_POWER_EVENTS
507 struct power_entry_old *peo; 513 struct power_entry_old *peo;
@@ -974,7 +980,7 @@ static void write_svg_file(const char *filename)
974 svg_close(); 980 svg_close();
975} 981}
976 982
977static struct perf_event_ops event_ops = { 983static struct perf_tool perf_timechart = {
978 .comm = process_comm_event, 984 .comm = process_comm_event,
979 .fork = process_fork_event, 985 .fork = process_fork_event,
980 .exit = process_exit_event, 986 .exit = process_exit_event,
@@ -985,7 +991,7 @@ static struct perf_event_ops event_ops = {
985static int __cmd_timechart(void) 991static int __cmd_timechart(void)
986{ 992{
987 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 993 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
988 0, false, &event_ops); 994 0, false, &perf_timechart);
989 int ret = -EINVAL; 995 int ret = -EINVAL;
990 996
991 if (session == NULL) 997 if (session == NULL)
@@ -994,7 +1000,7 @@ static int __cmd_timechart(void)
994 if (!perf_session__has_traces(session, "timechart record")) 1000 if (!perf_session__has_traces(session, "timechart record"))
995 goto out_delete; 1001 goto out_delete;
996 1002
997 ret = perf_session__process_events(session, &event_ops); 1003 ret = perf_session__process_events(session, &perf_timechart);
998 if (ret) 1004 if (ret)
999 goto out_delete; 1005 goto out_delete;
1000 1006
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9cdedb5813..c3836b966cc 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -64,44 +64,6 @@
64#include <linux/unistd.h> 64#include <linux/unistd.h>
65#include <linux/types.h> 65#include <linux/types.h>
66 66
67static struct perf_top top = {
68 .count_filter = 5,
69 .delay_secs = 2,
70 .target_pid = -1,
71 .target_tid = -1,
72 .freq = 1000, /* 1 KHz */
73};
74
75static bool system_wide = false;
76
77static bool use_tui, use_stdio;
78
79static bool sort_has_symbols;
80
81static bool dont_use_callchains;
82static char callchain_default_opt[] = "fractal,0.5,callee";
83
84
85static int default_interval = 0;
86
87static bool kptr_restrict_warned;
88static bool vmlinux_warned;
89static bool inherit = false;
90static int realtime_prio = 0;
91static bool group = false;
92static bool sample_id_all_avail = true;
93static unsigned int mmap_pages = 128;
94
95static bool dump_symtab = false;
96
97static struct winsize winsize;
98
99static const char *sym_filter = NULL;
100static int sym_pcnt_filter = 5;
101
102/*
103 * Source functions
104 */
105 67
106void get_term_dimensions(struct winsize *ws) 68void get_term_dimensions(struct winsize *ws)
107{ 69{
@@ -125,21 +87,23 @@ void get_term_dimensions(struct winsize *ws)
125 ws->ws_col = 80; 87 ws->ws_col = 80;
126} 88}
127 89
128static void update_print_entries(struct winsize *ws) 90static void perf_top__update_print_entries(struct perf_top *top)
129{ 91{
130 top.print_entries = ws->ws_row; 92 top->print_entries = top->winsize.ws_row;
131 93
132 if (top.print_entries > 9) 94 if (top->print_entries > 9)
133 top.print_entries -= 9; 95 top->print_entries -= 9;
134} 96}
135 97
136static void sig_winch_handler(int sig __used) 98static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg)
137{ 99{
138 get_term_dimensions(&winsize); 100 struct perf_top *top = arg;
139 update_print_entries(&winsize); 101
102 get_term_dimensions(&top->winsize);
103 perf_top__update_print_entries(top);
140} 104}
141 105
142static int parse_source(struct hist_entry *he) 106static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
143{ 107{
144 struct symbol *sym; 108 struct symbol *sym;
145 struct annotation *notes; 109 struct annotation *notes;
@@ -170,7 +134,7 @@ static int parse_source(struct hist_entry *he)
170 134
171 pthread_mutex_lock(&notes->lock); 135 pthread_mutex_lock(&notes->lock);
172 136
173 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { 137 if (symbol__alloc_hist(sym) < 0) {
174 pthread_mutex_unlock(&notes->lock); 138 pthread_mutex_unlock(&notes->lock);
175 pr_err("Not enough memory for annotating '%s' symbol!\n", 139 pr_err("Not enough memory for annotating '%s' symbol!\n",
176 sym->name); 140 sym->name);
@@ -181,7 +145,7 @@ static int parse_source(struct hist_entry *he)
181 err = symbol__annotate(sym, map, 0); 145 err = symbol__annotate(sym, map, 0);
182 if (err == 0) { 146 if (err == 0) {
183out_assign: 147out_assign:
184 top.sym_filter_entry = he; 148 top->sym_filter_entry = he;
185 } 149 }
186 150
187 pthread_mutex_unlock(&notes->lock); 151 pthread_mutex_unlock(&notes->lock);
@@ -194,14 +158,16 @@ static void __zero_source_counters(struct hist_entry *he)
194 symbol__annotate_zero_histograms(sym); 158 symbol__annotate_zero_histograms(sym);
195} 159}
196 160
197static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) 161static void perf_top__record_precise_ip(struct perf_top *top,
162 struct hist_entry *he,
163 int counter, u64 ip)
198{ 164{
199 struct annotation *notes; 165 struct annotation *notes;
200 struct symbol *sym; 166 struct symbol *sym;
201 167
202 if (he == NULL || he->ms.sym == NULL || 168 if (he == NULL || he->ms.sym == NULL ||
203 ((top.sym_filter_entry == NULL || 169 ((top->sym_filter_entry == NULL ||
204 top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) 170 top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
205 return; 171 return;
206 172
207 sym = he->ms.sym; 173 sym = he->ms.sym;
@@ -210,8 +176,7 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
210 if (pthread_mutex_trylock(&notes->lock)) 176 if (pthread_mutex_trylock(&notes->lock))
211 return; 177 return;
212 178
213 if (notes->src == NULL && 179 if (notes->src == NULL && symbol__alloc_hist(sym) < 0) {
214 symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
215 pthread_mutex_unlock(&notes->lock); 180 pthread_mutex_unlock(&notes->lock);
216 pr_err("Not enough memory for annotating '%s' symbol!\n", 181 pr_err("Not enough memory for annotating '%s' symbol!\n",
217 sym->name); 182 sym->name);
@@ -225,8 +190,9 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
225 pthread_mutex_unlock(&notes->lock); 190 pthread_mutex_unlock(&notes->lock);
226} 191}
227 192
228static void show_details(struct hist_entry *he) 193static void perf_top__show_details(struct perf_top *top)
229{ 194{
195 struct hist_entry *he = top->sym_filter_entry;
230 struct annotation *notes; 196 struct annotation *notes;
231 struct symbol *symbol; 197 struct symbol *symbol;
232 int more; 198 int more;
@@ -242,15 +208,15 @@ static void show_details(struct hist_entry *he)
242 if (notes->src == NULL) 208 if (notes->src == NULL)
243 goto out_unlock; 209 goto out_unlock;
244 210
245 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); 211 printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name);
246 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 212 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
247 213
248 more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx, 214 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
249 0, sym_pcnt_filter, top.print_entries, 4); 215 0, top->sym_pcnt_filter, top->print_entries, 4);
250 if (top.zero) 216 if (top->zero)
251 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); 217 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx);
252 else 218 else
253 symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); 219 symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx);
254 if (more != 0) 220 if (more != 0)
255 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 221 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
256out_unlock: 222out_unlock:
@@ -259,11 +225,9 @@ out_unlock:
259 225
260static const char CONSOLE_CLEAR[] = ""; 226static const char CONSOLE_CLEAR[] = "";
261 227
262static struct hist_entry * 228static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
263 perf_session__add_hist_entry(struct perf_session *session, 229 struct addr_location *al,
264 struct addr_location *al, 230 struct perf_sample *sample)
265 struct perf_sample *sample,
266 struct perf_evsel *evsel)
267{ 231{
268 struct hist_entry *he; 232 struct hist_entry *he;
269 233
@@ -271,50 +235,51 @@ static struct hist_entry *
271 if (he == NULL) 235 if (he == NULL)
272 return NULL; 236 return NULL;
273 237
274 session->hists.stats.total_period += sample->period; 238 evsel->hists.stats.total_period += sample->period;
275 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 239 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
276 return he; 240 return he;
277} 241}
278 242
279static void print_sym_table(void) 243static void perf_top__print_sym_table(struct perf_top *top)
280{ 244{
281 char bf[160]; 245 char bf[160];
282 int printed = 0; 246 int printed = 0;
283 const int win_width = winsize.ws_col - 1; 247 const int win_width = top->winsize.ws_col - 1;
284 248
285 puts(CONSOLE_CLEAR); 249 puts(CONSOLE_CLEAR);
286 250
287 perf_top__header_snprintf(&top, bf, sizeof(bf)); 251 perf_top__header_snprintf(top, bf, sizeof(bf));
288 printf("%s\n", bf); 252 printf("%s\n", bf);
289 253
290 perf_top__reset_sample_counters(&top); 254 perf_top__reset_sample_counters(top);
291 255
292 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 256 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
293 257
294 if (top.sym_evsel->hists.stats.nr_lost_warned != 258 if (top->sym_evsel->hists.stats.nr_lost_warned !=
295 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { 259 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
296 top.sym_evsel->hists.stats.nr_lost_warned = 260 top->sym_evsel->hists.stats.nr_lost_warned =
297 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 261 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
298 color_fprintf(stdout, PERF_COLOR_RED, 262 color_fprintf(stdout, PERF_COLOR_RED,
299 "WARNING: LOST %d chunks, Check IO/CPU overload", 263 "WARNING: LOST %d chunks, Check IO/CPU overload",
300 top.sym_evsel->hists.stats.nr_lost_warned); 264 top->sym_evsel->hists.stats.nr_lost_warned);
301 ++printed; 265 ++printed;
302 } 266 }
303 267
304 if (top.sym_filter_entry) { 268 if (top->sym_filter_entry) {
305 show_details(top.sym_filter_entry); 269 perf_top__show_details(top);
306 return; 270 return;
307 } 271 }
308 272
309 hists__collapse_resort_threaded(&top.sym_evsel->hists); 273 hists__collapse_resort_threaded(&top->sym_evsel->hists);
310 hists__output_resort_threaded(&top.sym_evsel->hists); 274 hists__output_resort_threaded(&top->sym_evsel->hists);
311 hists__decay_entries_threaded(&top.sym_evsel->hists, 275 hists__decay_entries_threaded(&top->sym_evsel->hists,
312 top.hide_user_symbols, 276 top->hide_user_symbols,
313 top.hide_kernel_symbols); 277 top->hide_kernel_symbols);
314 hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); 278 hists__output_recalc_col_len(&top->sym_evsel->hists,
279 top->winsize.ws_row - 3);
315 putchar('\n'); 280 putchar('\n');
316 hists__fprintf(&top.sym_evsel->hists, NULL, false, false, 281 hists__fprintf(&top->sym_evsel->hists, NULL, false, false,
317 winsize.ws_row - 4 - printed, win_width, stdout); 282 top->winsize.ws_row - 4 - printed, win_width, stdout);
318} 283}
319 284
320static void prompt_integer(int *target, const char *msg) 285static void prompt_integer(int *target, const char *msg)
@@ -352,17 +317,17 @@ static void prompt_percent(int *target, const char *msg)
352 *target = tmp; 317 *target = tmp;
353} 318}
354 319
355static void prompt_symbol(struct hist_entry **target, const char *msg) 320static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
356{ 321{
357 char *buf = malloc(0), *p; 322 char *buf = malloc(0), *p;
358 struct hist_entry *syme = *target, *n, *found = NULL; 323 struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
359 struct rb_node *next; 324 struct rb_node *next;
360 size_t dummy = 0; 325 size_t dummy = 0;
361 326
362 /* zero counters of active symbol */ 327 /* zero counters of active symbol */
363 if (syme) { 328 if (syme) {
364 __zero_source_counters(syme); 329 __zero_source_counters(syme);
365 *target = NULL; 330 top->sym_filter_entry = NULL;
366 } 331 }
367 332
368 fprintf(stdout, "\n%s: ", msg); 333 fprintf(stdout, "\n%s: ", msg);
@@ -373,7 +338,7 @@ static void prompt_symbol(struct hist_entry **target, const char *msg)
373 if (p) 338 if (p)
374 *p = 0; 339 *p = 0;
375 340
376 next = rb_first(&top.sym_evsel->hists.entries); 341 next = rb_first(&top->sym_evsel->hists.entries);
377 while (next) { 342 while (next) {
378 n = rb_entry(next, struct hist_entry, rb_node); 343 n = rb_entry(next, struct hist_entry, rb_node);
379 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { 344 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)
388 sleep(1); 353 sleep(1);
389 return; 354 return;
390 } else 355 } else
391 parse_source(found); 356 perf_top__parse_source(top, found);
392 357
393out_free: 358out_free:
394 free(buf); 359 free(buf);
395} 360}
396 361
397static void print_mapped_keys(void) 362static void perf_top__print_mapped_keys(struct perf_top *top)
398{ 363{
399 char *name = NULL; 364 char *name = NULL;
400 365
401 if (top.sym_filter_entry) { 366 if (top->sym_filter_entry) {
402 struct symbol *sym = top.sym_filter_entry->ms.sym; 367 struct symbol *sym = top->sym_filter_entry->ms.sym;
403 name = sym->name; 368 name = sym->name;
404 } 369 }
405 370
406 fprintf(stdout, "\nMapped keys:\n"); 371 fprintf(stdout, "\nMapped keys:\n");
407 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs); 372 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs);
408 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries); 373 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries);
409 374
410 if (top.evlist->nr_entries > 1) 375 if (top->evlist->nr_entries > 1)
411 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel)); 376 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel));
412 377
413 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter); 378 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
414 379
415 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 380 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter);
416 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 381 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
417 fprintf(stdout, "\t[S] stop annotation.\n"); 382 fprintf(stdout, "\t[S] stop annotation.\n");
418 383
419 fprintf(stdout, 384 fprintf(stdout,
420 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 385 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
421 top.hide_kernel_symbols ? "yes" : "no"); 386 top->hide_kernel_symbols ? "yes" : "no");
422 fprintf(stdout, 387 fprintf(stdout,
423 "\t[U] hide user symbols. \t(%s)\n", 388 "\t[U] hide user symbols. \t(%s)\n",
424 top.hide_user_symbols ? "yes" : "no"); 389 top->hide_user_symbols ? "yes" : "no");
425 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0); 390 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0);
426 fprintf(stdout, "\t[qQ] quit.\n"); 391 fprintf(stdout, "\t[qQ] quit.\n");
427} 392}
428 393
429static int key_mapped(int c) 394static int perf_top__key_mapped(struct perf_top *top, int c)
430{ 395{
431 switch (c) { 396 switch (c) {
432 case 'd': 397 case 'd':
@@ -442,7 +407,7 @@ static int key_mapped(int c)
442 case 'S': 407 case 'S':
443 return 1; 408 return 1;
444 case 'E': 409 case 'E':
445 return top.evlist->nr_entries > 1 ? 1 : 0; 410 return top->evlist->nr_entries > 1 ? 1 : 0;
446 default: 411 default:
447 break; 412 break;
448 } 413 }
@@ -450,13 +415,13 @@ static int key_mapped(int c)
450 return 0; 415 return 0;
451} 416}
452 417
453static void handle_keypress(int c) 418static void perf_top__handle_keypress(struct perf_top *top, int c)
454{ 419{
455 if (!key_mapped(c)) { 420 if (!perf_top__key_mapped(top, c)) {
456 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 421 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
457 struct termios tc, save; 422 struct termios tc, save;
458 423
459 print_mapped_keys(); 424 perf_top__print_mapped_keys(top);
460 fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); 425 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
461 fflush(stdout); 426 fflush(stdout);
462 427
@@ -471,81 +436,86 @@ static void handle_keypress(int c)
471 c = getc(stdin); 436 c = getc(stdin);
472 437
473 tcsetattr(0, TCSAFLUSH, &save); 438 tcsetattr(0, TCSAFLUSH, &save);
474 if (!key_mapped(c)) 439 if (!perf_top__key_mapped(top, c))
475 return; 440 return;
476 } 441 }
477 442
478 switch (c) { 443 switch (c) {
479 case 'd': 444 case 'd':
480 prompt_integer(&top.delay_secs, "Enter display delay"); 445 prompt_integer(&top->delay_secs, "Enter display delay");
481 if (top.delay_secs < 1) 446 if (top->delay_secs < 1)
482 top.delay_secs = 1; 447 top->delay_secs = 1;
483 break; 448 break;
484 case 'e': 449 case 'e':
485 prompt_integer(&top.print_entries, "Enter display entries (lines)"); 450 prompt_integer(&top->print_entries, "Enter display entries (lines)");
486 if (top.print_entries == 0) { 451 if (top->print_entries == 0) {
487 sig_winch_handler(SIGWINCH); 452 struct sigaction act = {
488 signal(SIGWINCH, sig_winch_handler); 453 .sa_sigaction = perf_top__sig_winch,
454 .sa_flags = SA_SIGINFO,
455 };
456 perf_top__sig_winch(SIGWINCH, NULL, top);
457 sigaction(SIGWINCH, &act, NULL);
489 } else 458 } else
490 signal(SIGWINCH, SIG_DFL); 459 signal(SIGWINCH, SIG_DFL);
491 break; 460 break;
492 case 'E': 461 case 'E':
493 if (top.evlist->nr_entries > 1) { 462 if (top->evlist->nr_entries > 1) {
494 /* Select 0 as the default event: */ 463 /* Select 0 as the default event: */
495 int counter = 0; 464 int counter = 0;
496 465
497 fprintf(stderr, "\nAvailable events:"); 466 fprintf(stderr, "\nAvailable events:");
498 467
499 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) 468 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
500 fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); 469 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel));
501 470
502 prompt_integer(&counter, "Enter details event counter"); 471 prompt_integer(&counter, "Enter details event counter");
503 472
504 if (counter >= top.evlist->nr_entries) { 473 if (counter >= top->evlist->nr_entries) {
505 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 474 top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
506 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); 475 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel));
507 sleep(1); 476 sleep(1);
508 break; 477 break;
509 } 478 }
510 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) 479 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
511 if (top.sym_evsel->idx == counter) 480 if (top->sym_evsel->idx == counter)
512 break; 481 break;
513 } else 482 } else
514 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 483 top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
515 break; 484 break;
516 case 'f': 485 case 'f':
517 prompt_integer(&top.count_filter, "Enter display event count filter"); 486 prompt_integer(&top->count_filter, "Enter display event count filter");
518 break; 487 break;
519 case 'F': 488 case 'F':
520 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 489 prompt_percent(&top->sym_pcnt_filter,
490 "Enter details display event filter (percent)");
521 break; 491 break;
522 case 'K': 492 case 'K':
523 top.hide_kernel_symbols = !top.hide_kernel_symbols; 493 top->hide_kernel_symbols = !top->hide_kernel_symbols;
524 break; 494 break;
525 case 'q': 495 case 'q':
526 case 'Q': 496 case 'Q':
527 printf("exiting.\n"); 497 printf("exiting.\n");
528 if (dump_symtab) 498 if (top->dump_symtab)
529 perf_session__fprintf_dsos(top.session, stderr); 499 perf_session__fprintf_dsos(top->session, stderr);
530 exit(0); 500 exit(0);
531 case 's': 501 case 's':
532 prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); 502 perf_top__prompt_symbol(top, "Enter details symbol");
533 break; 503 break;
534 case 'S': 504 case 'S':
535 if (!top.sym_filter_entry) 505 if (!top->sym_filter_entry)
536 break; 506 break;
537 else { 507 else {
538 struct hist_entry *syme = top.sym_filter_entry; 508 struct hist_entry *syme = top->sym_filter_entry;
539 509
540 top.sym_filter_entry = NULL; 510 top->sym_filter_entry = NULL;
541 __zero_source_counters(syme); 511 __zero_source_counters(syme);
542 } 512 }
543 break; 513 break;
544 case 'U': 514 case 'U':
545 top.hide_user_symbols = !top.hide_user_symbols; 515 top->hide_user_symbols = !top->hide_user_symbols;
546 break; 516 break;
547 case 'z': 517 case 'z':
548 top.zero = !top.zero; 518 top->zero = !top->zero;
549 break; 519 break;
550 default: 520 default:
551 break; 521 break;
@@ -563,28 +533,30 @@ static void perf_top__sort_new_samples(void *arg)
563 hists__collapse_resort_threaded(&t->sym_evsel->hists); 533 hists__collapse_resort_threaded(&t->sym_evsel->hists);
564 hists__output_resort_threaded(&t->sym_evsel->hists); 534 hists__output_resort_threaded(&t->sym_evsel->hists);
565 hists__decay_entries_threaded(&t->sym_evsel->hists, 535 hists__decay_entries_threaded(&t->sym_evsel->hists,
566 top.hide_user_symbols, 536 t->hide_user_symbols,
567 top.hide_kernel_symbols); 537 t->hide_kernel_symbols);
568} 538}
569 539
570static void *display_thread_tui(void *arg __used) 540static void *display_thread_tui(void *arg)
571{ 541{
542 struct perf_top *top = arg;
572 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 543 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
573 544
574 perf_top__sort_new_samples(&top); 545 perf_top__sort_new_samples(top);
575 perf_evlist__tui_browse_hists(top.evlist, help, 546 perf_evlist__tui_browse_hists(top->evlist, help,
576 perf_top__sort_new_samples, 547 perf_top__sort_new_samples,
577 &top, top.delay_secs); 548 top, top->delay_secs);
578 549
579 exit_browser(0); 550 exit_browser(0);
580 exit(0); 551 exit(0);
581 return NULL; 552 return NULL;
582} 553}
583 554
584static void *display_thread(void *arg __used) 555static void *display_thread(void *arg)
585{ 556{
586 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 557 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
587 struct termios tc, save; 558 struct termios tc, save;
559 struct perf_top *top = arg;
588 int delay_msecs, c; 560 int delay_msecs, c;
589 561
590 tcgetattr(0, &save); 562 tcgetattr(0, &save);
@@ -595,13 +567,13 @@ static void *display_thread(void *arg __used)
595 567
596 pthread__unblock_sigwinch(); 568 pthread__unblock_sigwinch();
597repeat: 569repeat:
598 delay_msecs = top.delay_secs * 1000; 570 delay_msecs = top->delay_secs * 1000;
599 tcsetattr(0, TCSANOW, &tc); 571 tcsetattr(0, TCSANOW, &tc);
600 /* trash return*/ 572 /* trash return*/
601 getc(stdin); 573 getc(stdin);
602 574
603 while (1) { 575 while (1) {
604 print_sym_table(); 576 perf_top__print_sym_table(top);
605 /* 577 /*
606 * Either timeout expired or we got an EINTR due to SIGWINCH, 578 * Either timeout expired or we got an EINTR due to SIGWINCH,
607 * refresh screen in both cases. 579 * refresh screen in both cases.
@@ -621,7 +593,7 @@ process_hotkey:
621 c = getc(stdin); 593 c = getc(stdin);
622 tcsetattr(0, TCSAFLUSH, &save); 594 tcsetattr(0, TCSAFLUSH, &save);
623 595
624 handle_keypress(c); 596 perf_top__handle_keypress(top, c);
625 goto repeat; 597 goto repeat;
626 598
627 return NULL; 599 return NULL;
@@ -673,47 +645,17 @@ static int symbol_filter(struct map *map __used, struct symbol *sym)
673 return 0; 645 return 0;
674} 646}
675 647
676static void perf_event__process_sample(const union perf_event *event, 648static void perf_event__process_sample(struct perf_tool *tool,
649 const union perf_event *event,
677 struct perf_evsel *evsel, 650 struct perf_evsel *evsel,
678 struct perf_sample *sample, 651 struct perf_sample *sample,
679 struct perf_session *session) 652 struct machine *machine)
680{ 653{
654 struct perf_top *top = container_of(tool, struct perf_top, tool);
681 struct symbol *parent = NULL; 655 struct symbol *parent = NULL;
682 u64 ip = event->ip.ip; 656 u64 ip = event->ip.ip;
683 struct addr_location al; 657 struct addr_location al;
684 struct machine *machine;
685 int err; 658 int err;
686 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
687
688 ++top.samples;
689
690 switch (origin) {
691 case PERF_RECORD_MISC_USER:
692 ++top.us_samples;
693 if (top.hide_user_symbols)
694 return;
695 machine = perf_session__find_host_machine(session);
696 break;
697 case PERF_RECORD_MISC_KERNEL:
698 ++top.kernel_samples;
699 if (top.hide_kernel_symbols)
700 return;
701 machine = perf_session__find_host_machine(session);
702 break;
703 case PERF_RECORD_MISC_GUEST_KERNEL:
704 ++top.guest_kernel_samples;
705 machine = perf_session__find_machine(session, event->ip.pid);
706 break;
707 case PERF_RECORD_MISC_GUEST_USER:
708 ++top.guest_us_samples;
709 /*
710 * TODO: we don't process guest user from host side
711 * except simple counting.
712 */
713 return;
714 default:
715 return;
716 }
717 659
718 if (!machine && perf_guest) { 660 if (!machine && perf_guest) {
719 pr_err("Can't find guest [%d]'s kernel information\n", 661 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,
722 } 664 }
723 665
724 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 666 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
725 top.exact_samples++; 667 top->exact_samples++;
726 668
727 if (perf_event__preprocess_sample(event, session, &al, sample, 669 if (perf_event__preprocess_sample(event, machine, &al, sample,
728 symbol_filter) < 0 || 670 symbol_filter) < 0 ||
729 al.filtered) 671 al.filtered)
730 return; 672 return;
731 673
732 if (!kptr_restrict_warned && 674 if (!top->kptr_restrict_warned &&
733 symbol_conf.kptr_restrict && 675 symbol_conf.kptr_restrict &&
734 al.cpumode == PERF_RECORD_MISC_KERNEL) { 676 al.cpumode == PERF_RECORD_MISC_KERNEL) {
735 ui__warning( 677 ui__warning(
@@ -740,7 +682,7 @@ static void perf_event__process_sample(const union perf_event *event,
740 " modules" : ""); 682 " modules" : "");
741 if (use_browser <= 0) 683 if (use_browser <= 0)
742 sleep(5); 684 sleep(5);
743 kptr_restrict_warned = true; 685 top->kptr_restrict_warned = true;
744 } 686 }
745 687
746 if (al.sym == NULL) { 688 if (al.sym == NULL) {
@@ -756,7 +698,7 @@ static void perf_event__process_sample(const union perf_event *event,
756 * --hide-kernel-symbols, even if the user specifies an 698 * --hide-kernel-symbols, even if the user specifies an
757 * invalid --vmlinux ;-) 699 * invalid --vmlinux ;-)
758 */ 700 */
759 if (!kptr_restrict_warned && !vmlinux_warned && 701 if (!top->kptr_restrict_warned && !top->vmlinux_warned &&
760 al.map == machine->vmlinux_maps[MAP__FUNCTION] && 702 al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
761 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 703 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
762 if (symbol_conf.vmlinux_name) { 704 if (symbol_conf.vmlinux_name) {
@@ -769,7 +711,7 @@ static void perf_event__process_sample(const union perf_event *event,
769 711
770 if (use_browser <= 0) 712 if (use_browser <= 0)
771 sleep(5); 713 sleep(5);
772 vmlinux_warned = true; 714 top->vmlinux_warned = true;
773 } 715 }
774 } 716 }
775 717
@@ -778,70 +720,109 @@ static void perf_event__process_sample(const union perf_event *event,
778 720
779 if ((sort__has_parent || symbol_conf.use_callchain) && 721 if ((sort__has_parent || symbol_conf.use_callchain) &&
780 sample->callchain) { 722 sample->callchain) {
781 err = perf_session__resolve_callchain(session, al.thread, 723 err = machine__resolve_callchain(machine, evsel, al.thread,
782 sample->callchain, &parent); 724 sample->callchain, &parent);
783 if (err) 725 if (err)
784 return; 726 return;
785 } 727 }
786 728
787 he = perf_session__add_hist_entry(session, &al, sample, evsel); 729 he = perf_evsel__add_hist_entry(evsel, &al, sample);
788 if (he == NULL) { 730 if (he == NULL) {
789 pr_err("Problem incrementing symbol period, skipping event\n"); 731 pr_err("Problem incrementing symbol period, skipping event\n");
790 return; 732 return;
791 } 733 }
792 734
793 if (symbol_conf.use_callchain) { 735 if (symbol_conf.use_callchain) {
794 err = callchain_append(he->callchain, &session->callchain_cursor, 736 err = callchain_append(he->callchain, &evsel->hists.callchain_cursor,
795 sample->period); 737 sample->period);
796 if (err) 738 if (err)
797 return; 739 return;
798 } 740 }
799 741
800 if (sort_has_symbols) 742 if (top->sort_has_symbols)
801 record_precise_ip(he, evsel->idx, ip); 743 perf_top__record_precise_ip(top, he, evsel->idx, ip);
802 } 744 }
803 745
804 return; 746 return;
805} 747}
806 748
807static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 749static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
808{ 750{
809 struct perf_sample sample; 751 struct perf_sample sample;
810 struct perf_evsel *evsel; 752 struct perf_evsel *evsel;
753 struct perf_session *session = top->session;
811 union perf_event *event; 754 union perf_event *event;
755 struct machine *machine;
756 u8 origin;
812 int ret; 757 int ret;
813 758
814 while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { 759 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
815 ret = perf_session__parse_sample(self, event, &sample); 760 ret = perf_session__parse_sample(session, event, &sample);
816 if (ret) { 761 if (ret) {
817 pr_err("Can't parse sample, err = %d\n", ret); 762 pr_err("Can't parse sample, err = %d\n", ret);
818 continue; 763 continue;
819 } 764 }
820 765
821 evsel = perf_evlist__id2evsel(self->evlist, sample.id); 766 evsel = perf_evlist__id2evsel(session->evlist, sample.id);
822 assert(evsel != NULL); 767 assert(evsel != NULL);
823 768
769 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
770
824 if (event->header.type == PERF_RECORD_SAMPLE) 771 if (event->header.type == PERF_RECORD_SAMPLE)
825 perf_event__process_sample(event, evsel, &sample, self); 772 ++top->samples;
826 else if (event->header.type < PERF_RECORD_MAX) { 773
774 switch (origin) {
775 case PERF_RECORD_MISC_USER:
776 ++top->us_samples;
777 if (top->hide_user_symbols)
778 continue;
779 machine = perf_session__find_host_machine(session);
780 break;
781 case PERF_RECORD_MISC_KERNEL:
782 ++top->kernel_samples;
783 if (top->hide_kernel_symbols)
784 continue;
785 machine = perf_session__find_host_machine(session);
786 break;
787 case PERF_RECORD_MISC_GUEST_KERNEL:
788 ++top->guest_kernel_samples;
789 machine = perf_session__find_machine(session, event->ip.pid);
790 break;
791 case PERF_RECORD_MISC_GUEST_USER:
792 ++top->guest_us_samples;
793 /*
794 * TODO: we don't process guest user from host side
795 * except simple counting.
796 */
797 /* Fall thru */
798 default:
799 continue;
800 }
801
802
803 if (event->header.type == PERF_RECORD_SAMPLE) {
804 perf_event__process_sample(&top->tool, event, evsel,
805 &sample, machine);
806 } else if (event->header.type < PERF_RECORD_MAX) {
827 hists__inc_nr_events(&evsel->hists, event->header.type); 807 hists__inc_nr_events(&evsel->hists, event->header.type);
828 perf_event__process(event, &sample, self); 808 perf_event__process(&top->tool, event, &sample, machine);
829 } else 809 } else
830 ++self->hists.stats.nr_unknown_events; 810 ++session->hists.stats.nr_unknown_events;
831 } 811 }
832} 812}
833 813
834static void perf_session__mmap_read(struct perf_session *self) 814static void perf_top__mmap_read(struct perf_top *top)
835{ 815{
836 int i; 816 int i;
837 817
838 for (i = 0; i < top.evlist->nr_mmaps; i++) 818 for (i = 0; i < top->evlist->nr_mmaps; i++)
839 perf_session__mmap_read_idx(self, i); 819 perf_top__mmap_read_idx(top, i);
840} 820}
841 821
842static void start_counters(struct perf_evlist *evlist) 822static void perf_top__start_counters(struct perf_top *top)
843{ 823{
844 struct perf_evsel *counter, *first; 824 struct perf_evsel *counter, *first;
825 struct perf_evlist *evlist = top->evlist;
845 826
846 first = list_entry(evlist->entries.next, struct perf_evsel, node); 827 first = list_entry(evlist->entries.next, struct perf_evsel, node);
847 828
@@ -849,15 +830,15 @@ static void start_counters(struct perf_evlist *evlist)
849 struct perf_event_attr *attr = &counter->attr; 830 struct perf_event_attr *attr = &counter->attr;
850 struct xyarray *group_fd = NULL; 831 struct xyarray *group_fd = NULL;
851 832
852 if (group && counter != first) 833 if (top->group && counter != first)
853 group_fd = first->fd; 834 group_fd = first->fd;
854 835
855 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 836 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
856 837
857 if (top.freq) { 838 if (top->freq) {
858 attr->sample_type |= PERF_SAMPLE_PERIOD; 839 attr->sample_type |= PERF_SAMPLE_PERIOD;
859 attr->freq = 1; 840 attr->freq = 1;
860 attr->sample_freq = top.freq; 841 attr->sample_freq = top->freq;
861 } 842 }
862 843
863 if (evlist->nr_entries > 1) { 844 if (evlist->nr_entries > 1) {
@@ -870,23 +851,23 @@ static void start_counters(struct perf_evlist *evlist)
870 851
871 attr->mmap = 1; 852 attr->mmap = 1;
872 attr->comm = 1; 853 attr->comm = 1;
873 attr->inherit = inherit; 854 attr->inherit = top->inherit;
874retry_sample_id: 855retry_sample_id:
875 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 856 attr->sample_id_all = top->sample_id_all_avail ? 1 : 0;
876try_again: 857try_again:
877 if (perf_evsel__open(counter, top.evlist->cpus, 858 if (perf_evsel__open(counter, top->evlist->cpus,
878 top.evlist->threads, group, 859 top->evlist->threads, top->group,
879 group_fd) < 0) { 860 group_fd) < 0) {
880 int err = errno; 861 int err = errno;
881 862
882 if (err == EPERM || err == EACCES) { 863 if (err == EPERM || err == EACCES) {
883 ui__error_paranoid(); 864 ui__error_paranoid();
884 goto out_err; 865 goto out_err;
885 } else if (err == EINVAL && sample_id_all_avail) { 866 } else if (err == EINVAL && top->sample_id_all_avail) {
886 /* 867 /*
887 * Old kernel, no attr->sample_id_type_all field 868 * Old kernel, no attr->sample_id_type_all field
888 */ 869 */
889 sample_id_all_avail = false; 870 top->sample_id_all_avail = false;
890 goto retry_sample_id; 871 goto retry_sample_id;
891 } 872 }
892 /* 873 /*
@@ -920,7 +901,7 @@ try_again:
920 } 901 }
921 } 902 }
922 903
923 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) { 904 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) {
924 ui__warning("Failed to mmap with %d (%s)\n", 905 ui__warning("Failed to mmap with %d (%s)\n",
925 errno, strerror(errno)); 906 errno, strerror(errno));
926 goto out_err; 907 goto out_err;
@@ -933,14 +914,14 @@ out_err:
933 exit(0); 914 exit(0);
934} 915}
935 916
936static int setup_sample_type(void) 917static int perf_top__setup_sample_type(struct perf_top *top)
937{ 918{
938 if (!sort_has_symbols) { 919 if (!top->sort_has_symbols) {
939 if (symbol_conf.use_callchain) { 920 if (symbol_conf.use_callchain) {
940 ui__warning("Selected -g but \"sym\" not present in --sort/-s."); 921 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
941 return -EINVAL; 922 return -EINVAL;
942 } 923 }
943 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) { 924 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
944 if (callchain_register_param(&callchain_param) < 0) { 925 if (callchain_register_param(&callchain_param) < 0) {
945 ui__warning("Can't register callchain params.\n"); 926 ui__warning("Can't register callchain params.\n");
946 return -EINVAL; 927 return -EINVAL;
@@ -950,7 +931,7 @@ static int setup_sample_type(void)
950 return 0; 931 return 0;
951} 932}
952 933
953static int __cmd_top(void) 934static int __cmd_top(struct perf_top *top)
954{ 935{
955 pthread_t thread; 936 pthread_t thread;
956 int ret; 937 int ret;
@@ -958,39 +939,40 @@ static int __cmd_top(void)
958 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 939 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
959 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 940 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
960 */ 941 */
961 top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL); 942 top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
962 if (top.session == NULL) 943 if (top->session == NULL)
963 return -ENOMEM; 944 return -ENOMEM;
964 945
965 ret = setup_sample_type(); 946 ret = perf_top__setup_sample_type(top);
966 if (ret) 947 if (ret)
967 goto out_delete; 948 goto out_delete;
968 949
969 if (top.target_tid != -1) 950 if (top->target_tid != -1)
970 perf_event__synthesize_thread_map(top.evlist->threads, 951 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
971 perf_event__process, top.session); 952 perf_event__process,
953 &top->session->host_machine);
972 else 954 else
973 perf_event__synthesize_threads(perf_event__process, top.session); 955 perf_event__synthesize_threads(&top->tool, perf_event__process,
974 956 &top->session->host_machine);
975 start_counters(top.evlist); 957 perf_top__start_counters(top);
976 top.session->evlist = top.evlist; 958 top->session->evlist = top->evlist;
977 perf_session__update_sample_type(top.session); 959 perf_session__update_sample_type(top->session);
978 960
979 /* Wait for a minimal set of events before starting the snapshot */ 961 /* Wait for a minimal set of events before starting the snapshot */
980 poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 962 poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
981 963
982 perf_session__mmap_read(top.session); 964 perf_top__mmap_read(top);
983 965
984 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 966 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
985 display_thread), NULL)) { 967 display_thread), top)) {
986 printf("Could not create display thread.\n"); 968 printf("Could not create display thread.\n");
987 exit(-1); 969 exit(-1);
988 } 970 }
989 971
990 if (realtime_prio) { 972 if (top->realtime_prio) {
991 struct sched_param param; 973 struct sched_param param;
992 974
993 param.sched_priority = realtime_prio; 975 param.sched_priority = top->realtime_prio;
994 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 976 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
995 printf("Could not set realtime priority.\n"); 977 printf("Could not set realtime priority.\n");
996 exit(-1); 978 exit(-1);
@@ -998,25 +980,25 @@ static int __cmd_top(void)
998 } 980 }
999 981
1000 while (1) { 982 while (1) {
1001 u64 hits = top.samples; 983 u64 hits = top->samples;
1002 984
1003 perf_session__mmap_read(top.session); 985 perf_top__mmap_read(top);
1004 986
1005 if (hits == top.samples) 987 if (hits == top->samples)
1006 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 988 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1007 } 989 }
1008 990
1009out_delete: 991out_delete:
1010 perf_session__delete(top.session); 992 perf_session__delete(top->session);
1011 top.session = NULL; 993 top->session = NULL;
1012 994
1013 return 0; 995 return 0;
1014} 996}
1015 997
1016static int 998static int
1017parse_callchain_opt(const struct option *opt __used, const char *arg, 999parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1018 int unset)
1019{ 1000{
1001 struct perf_top *top = (struct perf_top *)opt->value;
1020 char *tok, *tok2; 1002 char *tok, *tok2;
1021 char *endptr; 1003 char *endptr;
1022 1004
@@ -1024,7 +1006,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1024 * --no-call-graph 1006 * --no-call-graph
1025 */ 1007 */
1026 if (unset) { 1008 if (unset) {
1027 dont_use_callchains = true; 1009 top->dont_use_callchains = true;
1028 return 0; 1010 return 0;
1029 } 1011 }
1030 1012
@@ -1052,9 +1034,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1052 symbol_conf.use_callchain = false; 1034 symbol_conf.use_callchain = false;
1053 1035
1054 return 0; 1036 return 0;
1055 } 1037 } else
1056
1057 else
1058 return -1; 1038 return -1;
1059 1039
1060 /* get the min percentage */ 1040 /* get the min percentage */
@@ -1098,17 +1078,32 @@ static const char * const top_usage[] = {
1098 NULL 1078 NULL
1099}; 1079};
1100 1080
1101static const struct option options[] = { 1081int cmd_top(int argc, const char **argv, const char *prefix __used)
1082{
1083 struct perf_evsel *pos;
1084 int status = -ENOMEM;
1085 struct perf_top top = {
1086 .count_filter = 5,
1087 .delay_secs = 2,
1088 .target_pid = -1,
1089 .target_tid = -1,
1090 .freq = 1000, /* 1 KHz */
1091 .sample_id_all_avail = true,
1092 .mmap_pages = 128,
1093 .sym_pcnt_filter = 5,
1094 };
1095 char callchain_default_opt[] = "fractal,0.5,callee";
1096 const struct option options[] = {
1102 OPT_CALLBACK('e', "event", &top.evlist, "event", 1097 OPT_CALLBACK('e', "event", &top.evlist, "event",
1103 "event selector. use 'perf list' to list available events", 1098 "event selector. use 'perf list' to list available events",
1104 parse_events_option), 1099 parse_events_option),
1105 OPT_INTEGER('c', "count", &default_interval, 1100 OPT_INTEGER('c', "count", &top.default_interval,
1106 "event period to sample"), 1101 "event period to sample"),
1107 OPT_INTEGER('p', "pid", &top.target_pid, 1102 OPT_INTEGER('p', "pid", &top.target_pid,
1108 "profile events on existing process id"), 1103 "profile events on existing process id"),
1109 OPT_INTEGER('t', "tid", &top.target_tid, 1104 OPT_INTEGER('t', "tid", &top.target_tid,
1110 "profile events on existing thread id"), 1105 "profile events on existing thread id"),
1111 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1106 OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
1112 "system-wide collection from all CPUs"), 1107 "system-wide collection from all CPUs"),
1113 OPT_STRING('C', "cpu", &top.cpu_list, "cpu", 1108 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1114 "list of cpus to monitor"), 1109 "list of cpus to monitor"),
@@ -1116,20 +1111,20 @@ static const struct option options[] = {
1116 "file", "vmlinux pathname"), 1111 "file", "vmlinux pathname"),
1117 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, 1112 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1118 "hide kernel symbols"), 1113 "hide kernel symbols"),
1119 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 1114 OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"),
1120 OPT_INTEGER('r', "realtime", &realtime_prio, 1115 OPT_INTEGER('r', "realtime", &top.realtime_prio,
1121 "collect data with this RT SCHED_FIFO priority"), 1116 "collect data with this RT SCHED_FIFO priority"),
1122 OPT_INTEGER('d', "delay", &top.delay_secs, 1117 OPT_INTEGER('d', "delay", &top.delay_secs,
1123 "number of seconds to delay between refreshes"), 1118 "number of seconds to delay between refreshes"),
1124 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 1119 OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab,
1125 "dump the symbol table used for profiling"), 1120 "dump the symbol table used for profiling"),
1126 OPT_INTEGER('f', "count-filter", &top.count_filter, 1121 OPT_INTEGER('f', "count-filter", &top.count_filter,
1127 "only display functions with more events than this"), 1122 "only display functions with more events than this"),
1128 OPT_BOOLEAN('g', "group", &group, 1123 OPT_BOOLEAN('g', "group", &top.group,
1129 "put the counters into a counter group"), 1124 "put the counters into a counter group"),
1130 OPT_BOOLEAN('i', "inherit", &inherit, 1125 OPT_BOOLEAN('i', "inherit", &top.inherit,
1131 "child tasks inherit counters"), 1126 "child tasks inherit counters"),
1132 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name", 1127 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
1133 "symbol to annotate"), 1128 "symbol to annotate"),
1134 OPT_BOOLEAN('z', "zero", &top.zero, 1129 OPT_BOOLEAN('z', "zero", &top.zero,
1135 "zero history across updates"), 1130 "zero history across updates"),
@@ -1139,15 +1134,15 @@ static const struct option options[] = {
1139 "display this many functions"), 1134 "display this many functions"),
1140 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, 1135 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1141 "hide user symbols"), 1136 "hide user symbols"),
1142 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), 1137 OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"),
1143 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 1138 OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"),
1144 OPT_INCR('v', "verbose", &verbose, 1139 OPT_INCR('v', "verbose", &verbose,
1145 "be more verbose (show counter open errors, etc)"), 1140 "be more verbose (show counter open errors, etc)"),
1146 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1141 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1147 "sort by key(s): pid, comm, dso, symbol, parent"), 1142 "sort by key(s): pid, comm, dso, symbol, parent"),
1148 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1143 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1149 "Show a column with the number of samples"), 1144 "Show a column with the number of samples"),
1150 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order", 1145 OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order",
1151 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " 1146 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1152 "Default: fractal,0.5,callee", &parse_callchain_opt, 1147 "Default: fractal,0.5,callee", &parse_callchain_opt,
1153 callchain_default_opt), 1148 callchain_default_opt),
@@ -1166,12 +1161,7 @@ static const struct option options[] = {
1166 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1161 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1167 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1162 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1168 OPT_END() 1163 OPT_END()
1169}; 1164 };
1170
1171int cmd_top(int argc, const char **argv, const char *prefix __used)
1172{
1173 struct perf_evsel *pos;
1174 int status = -ENOMEM;
1175 1165
1176 top.evlist = perf_evlist__new(NULL, NULL); 1166 top.evlist = perf_evlist__new(NULL, NULL);
1177 if (top.evlist == NULL) 1167 if (top.evlist == NULL)
@@ -1188,9 +1178,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1188 1178
1189 setup_sorting(top_usage, options); 1179 setup_sorting(top_usage, options);
1190 1180
1191 if (use_stdio) 1181 if (top.use_stdio)
1192 use_browser = 0; 1182 use_browser = 0;
1193 else if (use_tui) 1183 else if (top.use_tui)
1194 use_browser = 1; 1184 use_browser = 1;
1195 1185
1196 setup_browser(false); 1186 setup_browser(false);
@@ -1215,38 +1205,31 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1215 return -ENOMEM; 1205 return -ENOMEM;
1216 } 1206 }
1217 1207
1208 symbol_conf.nr_events = top.evlist->nr_entries;
1209
1218 if (top.delay_secs < 1) 1210 if (top.delay_secs < 1)
1219 top.delay_secs = 1; 1211 top.delay_secs = 1;
1220 1212
1221 /* 1213 /*
1222 * User specified count overrides default frequency. 1214 * User specified count overrides default frequency.
1223 */ 1215 */
1224 if (default_interval) 1216 if (top.default_interval)
1225 top.freq = 0; 1217 top.freq = 0;
1226 else if (top.freq) { 1218 else if (top.freq) {
1227 default_interval = top.freq; 1219 top.default_interval = top.freq;
1228 } else { 1220 } else {
1229 fprintf(stderr, "frequency and count are zero, aborting\n"); 1221 fprintf(stderr, "frequency and count are zero, aborting\n");
1230 exit(EXIT_FAILURE); 1222 exit(EXIT_FAILURE);
1231 } 1223 }
1232 1224
1233 list_for_each_entry(pos, &top.evlist->entries, node) { 1225 list_for_each_entry(pos, &top.evlist->entries, node) {
1234 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1235 top.evlist->threads->nr) < 0)
1236 goto out_free_fd;
1237 /* 1226 /*
1238 * Fill in the ones not specifically initialized via -c: 1227 * Fill in the ones not specifically initialized via -c:
1239 */ 1228 */
1240 if (pos->attr.sample_period) 1229 if (!pos->attr.sample_period)
1241 continue; 1230 pos->attr.sample_period = top.default_interval;
1242
1243 pos->attr.sample_period = default_interval;
1244 } 1231 }
1245 1232
1246 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1247 perf_evlist__alloc_mmap(top.evlist) < 0)
1248 goto out_free_fd;
1249
1250 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1233 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1251 1234
1252 symbol_conf.priv_size = sizeof(struct annotation); 1235 symbol_conf.priv_size = sizeof(struct annotation);
@@ -1263,16 +1246,20 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1263 * Avoid annotation data structures overhead when symbols aren't on the 1246 * Avoid annotation data structures overhead when symbols aren't on the
1264 * sort list. 1247 * sort list.
1265 */ 1248 */
1266 sort_has_symbols = sort_sym.list.next != NULL; 1249 top.sort_has_symbols = sort_sym.list.next != NULL;
1267 1250
1268 get_term_dimensions(&winsize); 1251 get_term_dimensions(&top.winsize);
1269 if (top.print_entries == 0) { 1252 if (top.print_entries == 0) {
1270 update_print_entries(&winsize); 1253 struct sigaction act = {
1271 signal(SIGWINCH, sig_winch_handler); 1254 .sa_sigaction = perf_top__sig_winch,
1255 .sa_flags = SA_SIGINFO,
1256 };
1257 perf_top__update_print_entries(&top);
1258 sigaction(SIGWINCH, &act, NULL);
1272 } 1259 }
1273 1260
1274 status = __cmd_top(); 1261 status = __cmd_top(&top);
1275out_free_fd: 1262
1276 perf_evlist__delete(top.evlist); 1263 perf_evlist__delete(top.evlist);
1277 1264
1278 return status; 1265 return status;
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 73d0cac8b67..2b2e225a4d4 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -29,8 +29,6 @@ struct pager_config {
29 int val; 29 int val;
30}; 30};
31 31
32static char debugfs_mntpt[MAXPATHLEN];
33
34static int pager_command_config(const char *var, const char *value, void *data) 32static int pager_command_config(const char *var, const char *value, void *data)
35{ 33{
36 struct pager_config *c = data; 34 struct pager_config *c = data;
@@ -81,15 +79,6 @@ static void commit_pager_choice(void)
81 } 79 }
82} 80}
83 81
84static void set_debugfs_path(void)
85{
86 char *path;
87
88 path = getenv(PERF_DEBUGFS_ENVIRONMENT);
89 snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
90 "tracing/events");
91}
92
93static int handle_options(const char ***argv, int *argc, int *envchanged) 82static int handle_options(const char ***argv, int *argc, int *envchanged)
94{ 83{
95 int handled = 0; 84 int handled = 0;
@@ -161,15 +150,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
161 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 150 fprintf(stderr, "No directory given for --debugfs-dir.\n");
162 usage(perf_usage_string); 151 usage(perf_usage_string);
163 } 152 }
164 strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN); 153 debugfs_set_path((*argv)[1]);
165 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
166 if (envchanged) 154 if (envchanged)
167 *envchanged = 1; 155 *envchanged = 1;
168 (*argv)++; 156 (*argv)++;
169 (*argc)--; 157 (*argc)--;
170 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { 158 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
171 strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN); 159 debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
172 debugfs_mntpt[MAXPATHLEN - 1] = '\0'; 160 fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
173 if (envchanged) 161 if (envchanged)
174 *envchanged = 1; 162 *envchanged = 1;
175 } else { 163 } else {
@@ -281,7 +269,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
281 if (use_pager == -1 && p->option & USE_PAGER) 269 if (use_pager == -1 && p->option & USE_PAGER)
282 use_pager = 1; 270 use_pager = 1;
283 commit_pager_choice(); 271 commit_pager_choice();
284 set_debugfs_path();
285 272
286 status = p->fn(argc, argv, prefix); 273 status = p->fn(argc, argv, prefix);
287 exit_browser(status); 274 exit_browser(status);
@@ -416,17 +403,6 @@ static int run_argv(int *argcp, const char ***argv)
416 return done_alias; 403 return done_alias;
417} 404}
418 405
419/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
420static void get_debugfs_mntpt(void)
421{
422 const char *path = debugfs_mount(NULL);
423
424 if (path)
425 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
426 else
427 debugfs_mntpt[0] = '\0';
428}
429
430static void pthread__block_sigwinch(void) 406static void pthread__block_sigwinch(void)
431{ 407{
432 sigset_t set; 408 sigset_t set;
@@ -453,7 +429,7 @@ int main(int argc, const char **argv)
453 if (!cmd) 429 if (!cmd)
454 cmd = "perf-help"; 430 cmd = "perf-help";
455 /* get debugfs mount point from /proc/mounts */ 431 /* get debugfs mount point from /proc/mounts */
456 get_debugfs_mntpt(); 432 debugfs_mount(NULL);
457 /* 433 /*
458 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 434 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
459 * 435 *
@@ -476,7 +452,6 @@ int main(int argc, const char **argv)
476 argc--; 452 argc--;
477 handle_options(&argv, &argc, NULL); 453 handle_options(&argv, &argc, NULL);
478 commit_pager_choice(); 454 commit_pager_choice();
479 set_debugfs_path();
480 set_buildid_dir(); 455 set_buildid_dir();
481 456
482 if (argc > 0) { 457 if (argc > 0) {
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 914c895510f..ea804f5a8cc 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -185,4 +185,27 @@ extern const char perf_version_string[];
185 185
186void pthread__unblock_sigwinch(void); 186void pthread__unblock_sigwinch(void);
187 187
188struct perf_record_opts {
189 pid_t target_pid;
190 pid_t target_tid;
191 bool call_graph;
192 bool group;
193 bool inherit_stat;
194 bool no_delay;
195 bool no_inherit;
196 bool no_samples;
197 bool pipe_output;
198 bool raw_samples;
199 bool sample_address;
200 bool sample_time;
201 bool sample_id_all_avail;
202 bool system_wide;
203 unsigned int freq;
204 unsigned int mmap_pages;
205 unsigned int user_freq;
206 u64 default_interval;
207 u64 user_interval;
208 const char *cpu_list;
209};
210
188#endif 211#endif
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 119e996035c..376e643f706 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -25,17 +25,17 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
25 return 0; 25 return 0;
26} 26}
27 27
28int symbol__alloc_hist(struct symbol *sym, int nevents) 28int symbol__alloc_hist(struct symbol *sym)
29{ 29{
30 struct annotation *notes = symbol__annotation(sym); 30 struct annotation *notes = symbol__annotation(sym);
31 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + 31 size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
32 (sym->end - sym->start) * sizeof(u64)); 32 (sym->end - sym->start) * sizeof(u64));
33 33
34 notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist); 34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
35 if (notes->src == NULL) 35 if (notes->src == NULL)
36 return -1; 36 return -1;
37 notes->src->sizeof_sym_hist = sizeof_sym_hist; 37 notes->src->sizeof_sym_hist = sizeof_sym_hist;
38 notes->src->nr_histograms = nevents; 38 notes->src->nr_histograms = symbol_conf.nr_events;
39 INIT_LIST_HEAD(&notes->src->source); 39 INIT_LIST_HEAD(&notes->src->source);
40 return 0; 40 return 0;
41} 41}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index d9072523d34..efa5dc82bfa 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -72,7 +72,7 @@ static inline struct annotation *symbol__annotation(struct symbol *sym)
72 72
73int symbol__inc_addr_samples(struct symbol *sym, struct map *map, 73int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
74 int evidx, u64 addr); 74 int evidx, u64 addr);
75int symbol__alloc_hist(struct symbol *sym, int nevents); 75int symbol__alloc_hist(struct symbol *sym);
76void symbol__annotate_zero_histograms(struct symbol *sym); 76void symbol__annotate_zero_histograms(struct symbol *sym);
77 77
78int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 78int 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,
99} 99}
100#else 100#else
101int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 101int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
102 int nr_events, void(*timer)(void *arg), void *arg, 102 void(*timer)(void *arg), void *arg, int delay_secs);
103 int delay_secs);
104#endif 103#endif
105 104
106extern const char *disassembler_style; 105extern const char *disassembler_style;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index a91cd99f26e..dff9c7a725f 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -13,15 +13,18 @@
13#include "symbol.h" 13#include "symbol.h"
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include "debug.h" 15#include "debug.h"
16#include "session.h"
17#include "tool.h"
16 18
17static int build_id__mark_dso_hit(union perf_event *event, 19static int build_id__mark_dso_hit(struct perf_tool *tool __used,
20 union perf_event *event,
18 struct perf_sample *sample __used, 21 struct perf_sample *sample __used,
19 struct perf_evsel *evsel __used, 22 struct perf_evsel *evsel __used,
20 struct perf_session *session) 23 struct machine *machine)
21{ 24{
22 struct addr_location al; 25 struct addr_location al;
23 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
24 struct thread *thread = perf_session__findnew(session, event->ip.pid); 27 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
25 28
26 if (thread == NULL) { 29 if (thread == NULL) {
27 pr_err("problem processing %d event, skipping it.\n", 30 pr_err("problem processing %d event, skipping it.\n",
@@ -29,8 +32,8 @@ static int build_id__mark_dso_hit(union perf_event *event,
29 return -1; 32 return -1;
30 } 33 }
31 34
32 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 35 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
33 event->ip.pid, event->ip.ip, &al); 36 event->ip.ip, &al);
34 37
35 if (al.map != NULL) 38 if (al.map != NULL)
36 al.map->dso->hit = 1; 39 al.map->dso->hit = 1;
@@ -38,25 +41,26 @@ static int build_id__mark_dso_hit(union perf_event *event,
38 return 0; 41 return 0;
39} 42}
40 43
41static int perf_event__exit_del_thread(union perf_event *event, 44static int perf_event__exit_del_thread(struct perf_tool *tool __used,
45 union perf_event *event,
42 struct perf_sample *sample __used, 46 struct perf_sample *sample __used,
43 struct perf_session *session) 47 struct machine *machine)
44{ 48{
45 struct thread *thread = perf_session__findnew(session, event->fork.tid); 49 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
46 50
47 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 51 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
48 event->fork.ppid, event->fork.ptid); 52 event->fork.ppid, event->fork.ptid);
49 53
50 if (thread) { 54 if (thread) {
51 rb_erase(&thread->rb_node, &session->threads); 55 rb_erase(&thread->rb_node, &machine->threads);
52 session->last_match = NULL; 56 machine->last_match = NULL;
53 thread__delete(thread); 57 thread__delete(thread);
54 } 58 }
55 59
56 return 0; 60 return 0;
57} 61}
58 62
59struct perf_event_ops build_id__mark_dso_hit_ops = { 63struct perf_tool build_id__mark_dso_hit_ops = {
60 .sample = build_id__mark_dso_hit, 64 .sample = build_id__mark_dso_hit,
61 .mmap = perf_event__process_mmap, 65 .mmap = perf_event__process_mmap,
62 .fork = perf_event__process_task, 66 .fork = perf_event__process_task,
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 5dafb00eaa0..a993ba87d99 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -3,7 +3,7 @@
3 3
4#include "session.h" 4#include "session.h"
5 5
6extern struct perf_event_ops build_id__mark_dso_hit_ops; 6extern struct perf_tool build_id__mark_dso_hit_ops;
7 7
8char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 8char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
9 9
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 9b4ff16cac9..7f9c0f1ae3a 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -101,6 +101,9 @@ int callchain_append(struct callchain_root *root,
101int callchain_merge(struct callchain_cursor *cursor, 101int callchain_merge(struct callchain_cursor *cursor,
102 struct callchain_root *dst, struct callchain_root *src); 102 struct callchain_root *dst, struct callchain_root *src);
103 103
104struct ip_callchain;
105union perf_event;
106
104bool ip_callchain__valid(struct ip_callchain *chain, 107bool ip_callchain__valid(struct ip_callchain *chain,
105 const union perf_event *event); 108 const union perf_event *event);
106/* 109/*
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 96bee5c4600..dbe2f16b1a1 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -3,7 +3,6 @@
3#include "parse-options.h" 3#include "parse-options.h"
4#include "evsel.h" 4#include "evsel.h"
5#include "cgroup.h" 5#include "cgroup.h"
6#include "debugfs.h" /* MAX_PATH, STR() */
7#include "evlist.h" 6#include "evlist.h"
8 7
9int nr_cgroups; 8int nr_cgroups;
@@ -12,7 +11,7 @@ static int
12cgroupfs_find_mountpoint(char *buf, size_t maxlen) 11cgroupfs_find_mountpoint(char *buf, size_t maxlen)
13{ 12{
14 FILE *fp; 13 FILE *fp;
15 char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; 14 char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
16 char *token, *saved_ptr = NULL; 15 char *token, *saved_ptr = NULL;
17 int found = 0; 16 int found = 0;
18 17
@@ -25,8 +24,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
25 * and inspect every cgroupfs mount point to find one that has 24 * and inspect every cgroupfs mount point to find one that has
26 * perf_event subsystem 25 * perf_event subsystem
27 */ 26 */
28 while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %" 27 while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %"
29 STR(MAX_PATH)"s %*d %*d\n", 28 STR(PATH_MAX)"s %*d %*d\n",
30 mountpoint, type, tokens) == 3) { 29 mountpoint, type, tokens) == 3) {
31 30
32 if (!strcmp(type, "cgroup")) { 31 if (!strcmp(type, "cgroup")) {
@@ -57,15 +56,15 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
57 56
58static int open_cgroup(char *name) 57static int open_cgroup(char *name)
59{ 58{
60 char path[MAX_PATH+1]; 59 char path[PATH_MAX + 1];
61 char mnt[MAX_PATH+1]; 60 char mnt[PATH_MAX + 1];
62 int fd; 61 int fd;
63 62
64 63
65 if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1)) 64 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
66 return -1; 65 return -1;
67 66
68 snprintf(path, MAX_PATH, "%s/%s", mnt, name); 67 snprintf(path, PATH_MAX, "%s/%s", mnt, name);
69 68
70 fd = open(path, O_RDONLY); 69 fd = open(path, O_RDONLY);
71 if (fd == -1) 70 if (fd == -1)
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index a88fefc0cc0..ffc35e748e8 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -2,8 +2,12 @@
2#include "debugfs.h" 2#include "debugfs.h"
3#include "cache.h" 3#include "cache.h"
4 4
5#include <linux/kernel.h>
6#include <sys/mount.h>
7
5static int debugfs_premounted; 8static int debugfs_premounted;
6static char debugfs_mountpoint[MAX_PATH+1]; 9char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
10char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
7 11
8static const char *debugfs_known_mountpoints[] = { 12static const char *debugfs_known_mountpoints[] = {
9 "/sys/kernel/debug/", 13 "/sys/kernel/debug/",
@@ -62,11 +66,9 @@ const char *debugfs_find_mountpoint(void)
62 /* give up and parse /proc/mounts */ 66 /* give up and parse /proc/mounts */
63 fp = fopen("/proc/mounts", "r"); 67 fp = fopen("/proc/mounts", "r");
64 if (fp == NULL) 68 if (fp == NULL)
65 die("Can't open /proc/mounts for read"); 69 return NULL;
66 70
67 while (fscanf(fp, "%*s %" 71 while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
70 debugfs_mountpoint, type) == 2) { 72 debugfs_mountpoint, type) == 2) {
71 if (strcmp(type, "debugfs") == 0) 73 if (strcmp(type, "debugfs") == 0)
72 break; 74 break;
@@ -106,6 +108,12 @@ int debugfs_valid_entry(const char *path)
106 return 0; 108 return 0;
107} 109}
108 110
111static void debugfs_set_tracing_events_path(const char *mountpoint)
112{
113 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
114 mountpoint, "tracing/events");
115}
116
109/* mount the debugfs somewhere if it's not mounted */ 117/* mount the debugfs somewhere if it's not mounted */
110 118
111char *debugfs_mount(const char *mountpoint) 119char *debugfs_mount(const char *mountpoint)
@@ -113,7 +121,7 @@ char *debugfs_mount(const char *mountpoint)
113 /* see if it's already mounted */ 121 /* see if it's already mounted */
114 if (debugfs_find_mountpoint()) { 122 if (debugfs_find_mountpoint()) {
115 debugfs_premounted = 1; 123 debugfs_premounted = 1;
116 return debugfs_mountpoint; 124 goto out;
117 } 125 }
118 126
119 /* if not mounted and no argument */ 127 /* if not mounted and no argument */
@@ -129,12 +137,19 @@ char *debugfs_mount(const char *mountpoint)
129 return NULL; 137 return NULL;
130 138
131 /* save the mountpoint */ 139 /* save the mountpoint */
132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1; 140 debugfs_found = 1;
134 141 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
142out:
143 debugfs_set_tracing_events_path(debugfs_mountpoint);
135 return debugfs_mountpoint; 144 return debugfs_mountpoint;
136} 145}
137 146
147void debugfs_set_path(const char *mountpoint)
148{
149 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
150 debugfs_set_tracing_events_path(mountpoint);
151}
152
138/* umount the debugfs */ 153/* umount the debugfs */
139 154
140int debugfs_umount(void) 155int debugfs_umount(void)
@@ -158,7 +173,7 @@ int debugfs_umount(void)
158 173
159int debugfs_write(const char *entry, const char *value) 174int debugfs_write(const char *entry, const char *value)
160{ 175{
161 char path[MAX_PATH+1]; 176 char path[PATH_MAX + 1];
162 int ret, count; 177 int ret, count;
163 int fd; 178 int fd;
164 179
@@ -203,7 +218,7 @@ int debugfs_write(const char *entry, const char *value)
203 */ 218 */
204int debugfs_read(const char *entry, char *buffer, size_t size) 219int debugfs_read(const char *entry, char *buffer, size_t size)
205{ 220{
206 char path[MAX_PATH+1]; 221 char path[PATH_MAX + 1];
207 int ret; 222 int ret;
208 int fd; 223 int fd;
209 224
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 83a02879745..4a878f735eb 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -1,25 +1,18 @@
1#ifndef __DEBUGFS_H__ 1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__ 2#define __DEBUGFS_H__
3 3
4#include <sys/mount.h> 4const char *debugfs_find_mountpoint(void);
5int debugfs_valid_mountpoint(const char *debugfs);
6int debugfs_valid_entry(const char *path);
7char *debugfs_mount(const char *mountpoint);
8int debugfs_umount(void);
9void debugfs_set_path(const char *mountpoint);
10int debugfs_write(const char *entry, const char *value);
11int debugfs_read(const char *entry, char *buffer, size_t size);
12void debugfs_force_cleanup(void);
13int debugfs_make_path(const char *element, char *buffer, int size);
5 14
6#ifndef MAX_PATH 15extern char debugfs_mountpoint[];
7# define MAX_PATH 256 16extern char tracing_events_path[];
8#endif
9
10#ifndef STR
11# define _STR(x) #x
12# define STR(x) _STR(x)
13#endif
14
15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path);
18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size);
22extern void debugfs_force_cleanup(void);
23extern int debugfs_make_path(const char *element, char *buffer, int size);
24 17
25#endif /* __DEBUGFS_H__ */ 18#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 437f8ca679a..97c479bcb0d 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,7 +1,6 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "session.h"
5#include "sort.h" 4#include "sort.h"
6#include "string.h" 5#include "string.h"
7#include "strlist.h" 6#include "strlist.h"
@@ -44,9 +43,10 @@ static struct perf_sample synth_sample = {
44 .period = 1, 43 .period = 1,
45}; 44};
46 45
47static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, 46static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
47 union perf_event *event, pid_t pid,
48 int full, perf_event__handler_t process, 48 int full, perf_event__handler_t process,
49 struct perf_session *session) 49 struct machine *machine)
50{ 50{
51 char filename[PATH_MAX]; 51 char filename[PATH_MAX];
52 char bf[BUFSIZ]; 52 char bf[BUFSIZ];
@@ -92,14 +92,14 @@ out_race:
92 92
93 event->comm.header.type = PERF_RECORD_COMM; 93 event->comm.header.type = PERF_RECORD_COMM;
94 size = ALIGN(size, sizeof(u64)); 94 size = ALIGN(size, sizeof(u64));
95 memset(event->comm.comm + size, 0, session->id_hdr_size); 95 memset(event->comm.comm + size, 0, machine->id_hdr_size);
96 event->comm.header.size = (sizeof(event->comm) - 96 event->comm.header.size = (sizeof(event->comm) -
97 (sizeof(event->comm.comm) - size) + 97 (sizeof(event->comm.comm) - size) +
98 session->id_hdr_size); 98 machine->id_hdr_size);
99 if (!full) { 99 if (!full) {
100 event->comm.tid = pid; 100 event->comm.tid = pid;
101 101
102 process(event, &synth_sample, session); 102 process(tool, event, &synth_sample, machine);
103 goto out; 103 goto out;
104 } 104 }
105 105
@@ -117,7 +117,7 @@ out_race:
117 117
118 event->comm.tid = pid; 118 event->comm.tid = pid;
119 119
120 process(event, &synth_sample, session); 120 process(tool, event, &synth_sample, machine);
121 } 121 }
122 122
123 closedir(tasks); 123 closedir(tasks);
@@ -127,10 +127,11 @@ out:
127 return tgid; 127 return tgid;
128} 128}
129 129
130static int perf_event__synthesize_mmap_events(union perf_event *event, 130static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
131 union perf_event *event,
131 pid_t pid, pid_t tgid, 132 pid_t pid, pid_t tgid,
132 perf_event__handler_t process, 133 perf_event__handler_t process,
133 struct perf_session *session) 134 struct machine *machine)
134{ 135{
135 char filename[PATH_MAX]; 136 char filename[PATH_MAX];
136 FILE *fp; 137 FILE *fp;
@@ -193,12 +194,12 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
193 event->mmap.len -= event->mmap.start; 194 event->mmap.len -= event->mmap.start;
194 event->mmap.header.size = (sizeof(event->mmap) - 195 event->mmap.header.size = (sizeof(event->mmap) -
195 (sizeof(event->mmap.filename) - size)); 196 (sizeof(event->mmap.filename) - size));
196 memset(event->mmap.filename + size, 0, session->id_hdr_size); 197 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
197 event->mmap.header.size += session->id_hdr_size; 198 event->mmap.header.size += machine->id_hdr_size;
198 event->mmap.pid = tgid; 199 event->mmap.pid = tgid;
199 event->mmap.tid = pid; 200 event->mmap.tid = pid;
200 201
201 process(event, &synth_sample, session); 202 process(tool, event, &synth_sample, machine);
202 } 203 }
203 } 204 }
204 205
@@ -206,14 +207,14 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
206 return 0; 207 return 0;
207} 208}
208 209
209int perf_event__synthesize_modules(perf_event__handler_t process, 210int perf_event__synthesize_modules(struct perf_tool *tool,
210 struct perf_session *session, 211 perf_event__handler_t process,
211 struct machine *machine) 212 struct machine *machine)
212{ 213{
213 struct rb_node *nd; 214 struct rb_node *nd;
214 struct map_groups *kmaps = &machine->kmaps; 215 struct map_groups *kmaps = &machine->kmaps;
215 union perf_event *event = zalloc((sizeof(event->mmap) + 216 union perf_event *event = zalloc((sizeof(event->mmap) +
216 session->id_hdr_size)); 217 machine->id_hdr_size));
217 if (event == NULL) { 218 if (event == NULL) {
218 pr_debug("Not enough memory synthesizing mmap event " 219 pr_debug("Not enough memory synthesizing mmap event "
219 "for kernel modules\n"); 220 "for kernel modules\n");
@@ -243,15 +244,15 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
243 event->mmap.header.type = PERF_RECORD_MMAP; 244 event->mmap.header.type = PERF_RECORD_MMAP;
244 event->mmap.header.size = (sizeof(event->mmap) - 245 event->mmap.header.size = (sizeof(event->mmap) -
245 (sizeof(event->mmap.filename) - size)); 246 (sizeof(event->mmap.filename) - size));
246 memset(event->mmap.filename + size, 0, session->id_hdr_size); 247 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
247 event->mmap.header.size += session->id_hdr_size; 248 event->mmap.header.size += machine->id_hdr_size;
248 event->mmap.start = pos->start; 249 event->mmap.start = pos->start;
249 event->mmap.len = pos->end - pos->start; 250 event->mmap.len = pos->end - pos->start;
250 event->mmap.pid = machine->pid; 251 event->mmap.pid = machine->pid;
251 252
252 memcpy(event->mmap.filename, pos->dso->long_name, 253 memcpy(event->mmap.filename, pos->dso->long_name,
253 pos->dso->long_name_len + 1); 254 pos->dso->long_name_len + 1);
254 process(event, &synth_sample, session); 255 process(tool, event, &synth_sample, machine);
255 } 256 }
256 257
257 free(event); 258 free(event);
@@ -261,28 +262,30 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
261static int __event__synthesize_thread(union perf_event *comm_event, 262static int __event__synthesize_thread(union perf_event *comm_event,
262 union perf_event *mmap_event, 263 union perf_event *mmap_event,
263 pid_t pid, perf_event__handler_t process, 264 pid_t pid, perf_event__handler_t process,
264 struct perf_session *session) 265 struct perf_tool *tool,
266 struct machine *machine)
265{ 267{
266 pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process, 268 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, 1,
267 session); 269 process, machine);
268 if (tgid == -1) 270 if (tgid == -1)
269 return -1; 271 return -1;
270 return perf_event__synthesize_mmap_events(mmap_event, pid, tgid, 272 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
271 process, session); 273 process, machine);
272} 274}
273 275
274int perf_event__synthesize_thread_map(struct thread_map *threads, 276int perf_event__synthesize_thread_map(struct perf_tool *tool,
277 struct thread_map *threads,
275 perf_event__handler_t process, 278 perf_event__handler_t process,
276 struct perf_session *session) 279 struct machine *machine)
277{ 280{
278 union perf_event *comm_event, *mmap_event; 281 union perf_event *comm_event, *mmap_event;
279 int err = -1, thread; 282 int err = -1, thread;
280 283
281 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 284 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
282 if (comm_event == NULL) 285 if (comm_event == NULL)
283 goto out; 286 goto out;
284 287
285 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); 288 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
286 if (mmap_event == NULL) 289 if (mmap_event == NULL)
287 goto out_free_comm; 290 goto out_free_comm;
288 291
@@ -290,7 +293,7 @@ int perf_event__synthesize_thread_map(struct thread_map *threads,
290 for (thread = 0; thread < threads->nr; ++thread) { 293 for (thread = 0; thread < threads->nr; ++thread) {
291 if (__event__synthesize_thread(comm_event, mmap_event, 294 if (__event__synthesize_thread(comm_event, mmap_event,
292 threads->map[thread], 295 threads->map[thread],
293 process, session)) { 296 process, tool, machine)) {
294 err = -1; 297 err = -1;
295 break; 298 break;
296 } 299 }
@@ -302,19 +305,20 @@ out:
302 return err; 305 return err;
303} 306}
304 307
305int perf_event__synthesize_threads(perf_event__handler_t process, 308int perf_event__synthesize_threads(struct perf_tool *tool,
306 struct perf_session *session) 309 perf_event__handler_t process,
310 struct machine *machine)
307{ 311{
308 DIR *proc; 312 DIR *proc;
309 struct dirent dirent, *next; 313 struct dirent dirent, *next;
310 union perf_event *comm_event, *mmap_event; 314 union perf_event *comm_event, *mmap_event;
311 int err = -1; 315 int err = -1;
312 316
313 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 317 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
314 if (comm_event == NULL) 318 if (comm_event == NULL)
315 goto out; 319 goto out;
316 320
317 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); 321 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
318 if (mmap_event == NULL) 322 if (mmap_event == NULL)
319 goto out_free_comm; 323 goto out_free_comm;
320 324
@@ -330,7 +334,7 @@ int perf_event__synthesize_threads(perf_event__handler_t process,
330 continue; 334 continue;
331 335
332 __event__synthesize_thread(comm_event, mmap_event, pid, 336 __event__synthesize_thread(comm_event, mmap_event, pid,
333 process, session); 337 process, tool, machine);
334 } 338 }
335 339
336 closedir(proc); 340 closedir(proc);
@@ -365,8 +369,8 @@ static int find_symbol_cb(void *arg, const char *name, char type,
365 return 1; 369 return 1;
366} 370}
367 371
368int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, 372int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
369 struct perf_session *session, 373 perf_event__handler_t process,
370 struct machine *machine, 374 struct machine *machine,
371 const char *symbol_name) 375 const char *symbol_name)
372{ 376{
@@ -383,7 +387,7 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
383 */ 387 */
384 struct process_symbol_args args = { .name = symbol_name, }; 388 struct process_symbol_args args = { .name = symbol_name, };
385 union perf_event *event = zalloc((sizeof(event->mmap) + 389 union perf_event *event = zalloc((sizeof(event->mmap) +
386 session->id_hdr_size)); 390 machine->id_hdr_size));
387 if (event == NULL) { 391 if (event == NULL) {
388 pr_debug("Not enough memory synthesizing mmap event " 392 pr_debug("Not enough memory synthesizing mmap event "
389 "for kernel modules\n"); 393 "for kernel modules\n");
@@ -417,25 +421,32 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
417 size = ALIGN(size, sizeof(u64)); 421 size = ALIGN(size, sizeof(u64));
418 event->mmap.header.type = PERF_RECORD_MMAP; 422 event->mmap.header.type = PERF_RECORD_MMAP;
419 event->mmap.header.size = (sizeof(event->mmap) - 423 event->mmap.header.size = (sizeof(event->mmap) -
420 (sizeof(event->mmap.filename) - size) + session->id_hdr_size); 424 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
421 event->mmap.pgoff = args.start; 425 event->mmap.pgoff = args.start;
422 event->mmap.start = map->start; 426 event->mmap.start = map->start;
423 event->mmap.len = map->end - event->mmap.start; 427 event->mmap.len = map->end - event->mmap.start;
424 event->mmap.pid = machine->pid; 428 event->mmap.pid = machine->pid;
425 429
426 err = process(event, &synth_sample, session); 430 err = process(tool, event, &synth_sample, machine);
427 free(event); 431 free(event);
428 432
429 return err; 433 return err;
430} 434}
431 435
432int perf_event__process_comm(union perf_event *event, 436size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
437{
438 return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid);
439}
440
441int perf_event__process_comm(struct perf_tool *tool __used,
442 union perf_event *event,
433 struct perf_sample *sample __used, 443 struct perf_sample *sample __used,
434 struct perf_session *session) 444 struct machine *machine)
435{ 445{
436 struct thread *thread = perf_session__findnew(session, event->comm.tid); 446 struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
437 447
438 dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid); 448 if (dump_trace)
449 perf_event__fprintf_comm(event, stdout);
439 450
440 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { 451 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
441 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 452 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
@@ -445,13 +456,13 @@ int perf_event__process_comm(union perf_event *event,
445 return 0; 456 return 0;
446} 457}
447 458
448int perf_event__process_lost(union perf_event *event, 459int perf_event__process_lost(struct perf_tool *tool __used,
460 union perf_event *event,
449 struct perf_sample *sample __used, 461 struct perf_sample *sample __used,
450 struct perf_session *session) 462 struct machine *machine __used)
451{ 463{
452 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", 464 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
453 event->lost.id, event->lost.lost); 465 event->lost.id, event->lost.lost);
454 session->hists.stats.total_lost += event->lost.lost;
455 return 0; 466 return 0;
456} 467}
457 468
@@ -468,21 +479,15 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event,
468 maps[MAP__FUNCTION]->end = ~0ULL; 479 maps[MAP__FUNCTION]->end = ~0ULL;
469} 480}
470 481
471static int perf_event__process_kernel_mmap(union perf_event *event, 482static int perf_event__process_kernel_mmap(struct perf_tool *tool __used,
472 struct perf_session *session) 483 union perf_event *event,
484 struct machine *machine)
473{ 485{
474 struct map *map; 486 struct map *map;
475 char kmmap_prefix[PATH_MAX]; 487 char kmmap_prefix[PATH_MAX];
476 struct machine *machine;
477 enum dso_kernel_type kernel_type; 488 enum dso_kernel_type kernel_type;
478 bool is_kernel_mmap; 489 bool is_kernel_mmap;
479 490
480 machine = perf_session__findnew_machine(session, event->mmap.pid);
481 if (!machine) {
482 pr_err("Can't find id %d's machine\n", event->mmap.pid);
483 goto out_problem;
484 }
485
486 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); 491 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
487 if (machine__is_host(machine)) 492 if (machine__is_host(machine))
488 kernel_type = DSO_TYPE_KERNEL; 493 kernel_type = DSO_TYPE_KERNEL;
@@ -549,9 +554,9 @@ static int perf_event__process_kernel_mmap(union perf_event *event,
549 * time /proc/sys/kernel/kptr_restrict was non zero. 554 * time /proc/sys/kernel/kptr_restrict was non zero.
550 */ 555 */
551 if (event->mmap.pgoff != 0) { 556 if (event->mmap.pgoff != 0) {
552 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, 557 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
553 symbol_name, 558 symbol_name,
554 event->mmap.pgoff); 559 event->mmap.pgoff);
555 } 560 }
556 561
557 if (machine__is_default_guest(machine)) { 562 if (machine__is_default_guest(machine)) {
@@ -567,32 +572,35 @@ out_problem:
567 return -1; 572 return -1;
568} 573}
569 574
570int perf_event__process_mmap(union perf_event *event, 575size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
576{
577 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
578 event->mmap.pid, event->mmap.tid, event->mmap.start,
579 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
580}
581
582int perf_event__process_mmap(struct perf_tool *tool,
583 union perf_event *event,
571 struct perf_sample *sample __used, 584 struct perf_sample *sample __used,
572 struct perf_session *session) 585 struct machine *machine)
573{ 586{
574 struct machine *machine;
575 struct thread *thread; 587 struct thread *thread;
576 struct map *map; 588 struct map *map;
577 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 589 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
578 int ret = 0; 590 int ret = 0;
579 591
580 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 592 if (dump_trace)
581 event->mmap.pid, event->mmap.tid, event->mmap.start, 593 perf_event__fprintf_mmap(event, stdout);
582 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
583 594
584 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 595 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
585 cpumode == PERF_RECORD_MISC_KERNEL) { 596 cpumode == PERF_RECORD_MISC_KERNEL) {
586 ret = perf_event__process_kernel_mmap(event, session); 597 ret = perf_event__process_kernel_mmap(tool, event, machine);
587 if (ret < 0) 598 if (ret < 0)
588 goto out_problem; 599 goto out_problem;
589 return 0; 600 return 0;
590 } 601 }
591 602
592 machine = perf_session__find_host_machine(session); 603 thread = machine__findnew_thread(machine, event->mmap.pid);
593 if (machine == NULL)
594 goto out_problem;
595 thread = perf_session__findnew(session, event->mmap.pid);
596 if (thread == NULL) 604 if (thread == NULL)
597 goto out_problem; 605 goto out_problem;
598 map = map__new(&machine->user_dsos, event->mmap.start, 606 map = map__new(&machine->user_dsos, event->mmap.start,
@@ -610,18 +618,26 @@ out_problem:
610 return 0; 618 return 0;
611} 619}
612 620
613int perf_event__process_task(union perf_event *event, 621size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
622{
623 return fprintf(fp, "(%d:%d):(%d:%d)\n",
624 event->fork.pid, event->fork.tid,
625 event->fork.ppid, event->fork.ptid);
626}
627
628int perf_event__process_task(struct perf_tool *tool __used,
629 union perf_event *event,
614 struct perf_sample *sample __used, 630 struct perf_sample *sample __used,
615 struct perf_session *session) 631 struct machine *machine)
616{ 632{
617 struct thread *thread = perf_session__findnew(session, event->fork.tid); 633 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
618 struct thread *parent = perf_session__findnew(session, event->fork.ptid); 634 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
619 635
620 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 636 if (dump_trace)
621 event->fork.ppid, event->fork.ptid); 637 perf_event__fprintf_task(event, stdout);
622 638
623 if (event->header.type == PERF_RECORD_EXIT) { 639 if (event->header.type == PERF_RECORD_EXIT) {
624 perf_session__remove_thread(session, thread); 640 machine__remove_thread(machine, thread);
625 return 0; 641 return 0;
626 } 642 }
627 643
@@ -634,22 +650,45 @@ int perf_event__process_task(union perf_event *event,
634 return 0; 650 return 0;
635} 651}
636 652
637int perf_event__process(union perf_event *event, struct perf_sample *sample, 653size_t perf_event__fprintf(union perf_event *event, FILE *fp)
638 struct perf_session *session)
639{ 654{
655 size_t ret = fprintf(fp, "PERF_RECORD_%s",
656 perf_event__name(event->header.type));
657
640 switch (event->header.type) { 658 switch (event->header.type) {
641 case PERF_RECORD_COMM: 659 case PERF_RECORD_COMM:
642 perf_event__process_comm(event, sample, session); 660 ret += perf_event__fprintf_comm(event, fp);
661 break;
662 case PERF_RECORD_FORK:
663 case PERF_RECORD_EXIT:
664 ret += perf_event__fprintf_task(event, fp);
643 break; 665 break;
644 case PERF_RECORD_MMAP: 666 case PERF_RECORD_MMAP:
645 perf_event__process_mmap(event, sample, session); 667 ret += perf_event__fprintf_mmap(event, fp);
668 break;
669 default:
670 ret += fprintf(fp, "\n");
671 }
672
673 return ret;
674}
675
676int perf_event__process(struct perf_tool *tool, union perf_event *event,
677 struct perf_sample *sample, struct machine *machine)
678{
679 switch (event->header.type) {
680 case PERF_RECORD_COMM:
681 perf_event__process_comm(tool, event, sample, machine);
682 break;
683 case PERF_RECORD_MMAP:
684 perf_event__process_mmap(tool, event, sample, machine);
646 break; 685 break;
647 case PERF_RECORD_FORK: 686 case PERF_RECORD_FORK:
648 case PERF_RECORD_EXIT: 687 case PERF_RECORD_EXIT:
649 perf_event__process_task(event, sample, session); 688 perf_event__process_task(tool, event, sample, machine);
650 break; 689 break;
651 case PERF_RECORD_LOST: 690 case PERF_RECORD_LOST:
652 perf_event__process_lost(event, sample, session); 691 perf_event__process_lost(tool, event, sample, machine);
653 default: 692 default:
654 break; 693 break;
655 } 694 }
@@ -658,36 +697,29 @@ int perf_event__process(union perf_event *event, struct perf_sample *sample,
658} 697}
659 698
660void thread__find_addr_map(struct thread *self, 699void thread__find_addr_map(struct thread *self,
661 struct perf_session *session, u8 cpumode, 700 struct machine *machine, u8 cpumode,
662 enum map_type type, pid_t pid, u64 addr, 701 enum map_type type, u64 addr,
663 struct addr_location *al) 702 struct addr_location *al)
664{ 703{
665 struct map_groups *mg = &self->mg; 704 struct map_groups *mg = &self->mg;
666 struct machine *machine = NULL;
667 705
668 al->thread = self; 706 al->thread = self;
669 al->addr = addr; 707 al->addr = addr;
670 al->cpumode = cpumode; 708 al->cpumode = cpumode;
671 al->filtered = false; 709 al->filtered = false;
672 710
711 if (machine == NULL) {
712 al->map = NULL;
713 return;
714 }
715
673 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 716 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
674 al->level = 'k'; 717 al->level = 'k';
675 machine = perf_session__find_host_machine(session);
676 if (machine == NULL) {
677 al->map = NULL;
678 return;
679 }
680 mg = &machine->kmaps; 718 mg = &machine->kmaps;
681 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 719 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
682 al->level = '.'; 720 al->level = '.';
683 machine = perf_session__find_host_machine(session);
684 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 721 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
685 al->level = 'g'; 722 al->level = 'g';
686 machine = perf_session__find_machine(session, pid);
687 if (machine == NULL) {
688 al->map = NULL;
689 return;
690 }
691 mg = &machine->kmaps; 723 mg = &machine->kmaps;
692 } else { 724 } else {
693 /* 725 /*
@@ -733,13 +765,12 @@ try_again:
733 al->addr = al->map->map_ip(al->map, al->addr); 765 al->addr = al->map->map_ip(al->map, al->addr);
734} 766}
735 767
736void thread__find_addr_location(struct thread *self, 768void thread__find_addr_location(struct thread *thread, struct machine *machine,
737 struct perf_session *session, u8 cpumode, 769 u8 cpumode, enum map_type type, u64 addr,
738 enum map_type type, pid_t pid, u64 addr,
739 struct addr_location *al, 770 struct addr_location *al,
740 symbol_filter_t filter) 771 symbol_filter_t filter)
741{ 772{
742 thread__find_addr_map(self, session, cpumode, type, pid, addr, al); 773 thread__find_addr_map(thread, machine, cpumode, type, addr, al);
743 if (al->map != NULL) 774 if (al->map != NULL)
744 al->sym = map__find_symbol(al->map, al->addr, filter); 775 al->sym = map__find_symbol(al->map, al->addr, filter);
745 else 776 else
@@ -747,13 +778,13 @@ void thread__find_addr_location(struct thread *self,
747} 778}
748 779
749int perf_event__preprocess_sample(const union perf_event *event, 780int perf_event__preprocess_sample(const union perf_event *event,
750 struct perf_session *session, 781 struct machine *machine,
751 struct addr_location *al, 782 struct addr_location *al,
752 struct perf_sample *sample, 783 struct perf_sample *sample,
753 symbol_filter_t filter) 784 symbol_filter_t filter)
754{ 785{
755 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 786 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
756 struct thread *thread = perf_session__findnew(session, event->ip.pid); 787 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
757 788
758 if (thread == NULL) 789 if (thread == NULL)
759 return -1; 790 return -1;
@@ -764,18 +795,18 @@ int perf_event__preprocess_sample(const union perf_event *event,
764 795
765 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 796 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
766 /* 797 /*
767 * Have we already created the kernel maps for the host machine? 798 * Have we already created the kernel maps for this machine?
768 * 799 *
769 * This should have happened earlier, when we processed the kernel MMAP 800 * This should have happened earlier, when we processed the kernel MMAP
770 * events, but for older perf.data files there was no such thing, so do 801 * events, but for older perf.data files there was no such thing, so do
771 * it now. 802 * it now.
772 */ 803 */
773 if (cpumode == PERF_RECORD_MISC_KERNEL && 804 if (cpumode == PERF_RECORD_MISC_KERNEL &&
774 session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL) 805 machine->vmlinux_maps[MAP__FUNCTION] == NULL)
775 machine__create_kernel_maps(&session->host_machine); 806 machine__create_kernel_maps(machine);
776 807
777 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 808 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
778 event->ip.pid, event->ip.ip, al); 809 event->ip.ip, al);
779 dump_printf(" ...... dso: %s\n", 810 dump_printf(" ...... dso: %s\n",
780 al->map ? al->map->dso->long_name : 811 al->map ? al->map->dso->long_name :
781 al->level == 'H' ? "[hypervisor]" : "<not found>"); 812 al->level == 'H' ? "[hypervisor]" : "<not found>");
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 357a85b8524..0d80201ce84 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -2,6 +2,7 @@
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h> 4#include <limits.h>
5#include <stdio.h>
5 6
6#include "../perf.h" 7#include "../perf.h"
7#include "map.h" 8#include "map.h"
@@ -141,43 +142,54 @@ union perf_event {
141 142
142void perf_event__print_totals(void); 143void perf_event__print_totals(void);
143 144
144struct perf_session; 145struct perf_tool;
145struct thread_map; 146struct thread_map;
146 147
147typedef int (*perf_event__handler_synth_t)(union perf_event *event, 148typedef int (*perf_event__handler_t)(struct perf_tool *tool,
148 struct perf_session *session); 149 union perf_event *event,
149typedef int (*perf_event__handler_t)(union perf_event *event,
150 struct perf_sample *sample, 150 struct perf_sample *sample,
151 struct perf_session *session); 151 struct machine *machine);
152 152
153int perf_event__synthesize_thread_map(struct thread_map *threads, 153int perf_event__synthesize_thread_map(struct perf_tool *tool,
154 struct thread_map *threads,
154 perf_event__handler_t process, 155 perf_event__handler_t process,
155 struct perf_session *session); 156 struct machine *machine);
156int perf_event__synthesize_threads(perf_event__handler_t process, 157int perf_event__synthesize_threads(struct perf_tool *tool,
157 struct perf_session *session); 158 perf_event__handler_t process,
158int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, 159 struct machine *machine);
159 struct perf_session *session, 160int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
161 perf_event__handler_t process,
160 struct machine *machine, 162 struct machine *machine,
161 const char *symbol_name); 163 const char *symbol_name);
162 164
163int perf_event__synthesize_modules(perf_event__handler_t process, 165int perf_event__synthesize_modules(struct perf_tool *tool,
164 struct perf_session *session, 166 perf_event__handler_t process,
165 struct machine *machine); 167 struct machine *machine);
166 168
167int perf_event__process_comm(union perf_event *event, struct perf_sample *sample, 169int perf_event__process_comm(struct perf_tool *tool,
168 struct perf_session *session); 170 union perf_event *event,
169int perf_event__process_lost(union perf_event *event, struct perf_sample *sample, 171 struct perf_sample *sample,
170 struct perf_session *session); 172 struct machine *machine);
171int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample, 173int perf_event__process_lost(struct perf_tool *tool,
172 struct perf_session *session); 174 union perf_event *event,
173int perf_event__process_task(union perf_event *event, struct perf_sample *sample, 175 struct perf_sample *sample,
174 struct perf_session *session); 176 struct machine *machine);
175int perf_event__process(union perf_event *event, struct perf_sample *sample, 177int perf_event__process_mmap(struct perf_tool *tool,
176 struct perf_session *session); 178 union perf_event *event,
179 struct perf_sample *sample,
180 struct machine *machine);
181int perf_event__process_task(struct perf_tool *tool,
182 union perf_event *event,
183 struct perf_sample *sample,
184 struct machine *machine);
185int perf_event__process(struct perf_tool *tool,
186 union perf_event *event,
187 struct perf_sample *sample,
188 struct machine *machine);
177 189
178struct addr_location; 190struct addr_location;
179int perf_event__preprocess_sample(const union perf_event *self, 191int perf_event__preprocess_sample(const union perf_event *self,
180 struct perf_session *session, 192 struct machine *machine,
181 struct addr_location *al, 193 struct addr_location *al,
182 struct perf_sample *sample, 194 struct perf_sample *sample,
183 symbol_filter_t filter); 195 symbol_filter_t filter);
@@ -188,4 +200,9 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
188 int sample_size, bool sample_id_all, 200 int sample_size, bool sample_id_all,
189 struct perf_sample *sample, bool swapped); 201 struct perf_sample *sample, bool swapped);
190 202
203size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
204size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
205size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
206size_t perf_event__fprintf(union perf_event *event, FILE *fp);
207
191#endif /* __PERF_RECORD_H */ 208#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index fbb4b4ab9cc..8b19e7a1e88 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -6,12 +6,16 @@
6 * 6 *
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9#include "util.h"
10#include "debugfs.h"
9#include <poll.h> 11#include <poll.h>
10#include "cpumap.h" 12#include "cpumap.h"
11#include "thread_map.h" 13#include "thread_map.h"
12#include "evlist.h" 14#include "evlist.h"
13#include "evsel.h" 15#include "evsel.h"
14#include "util.h" 16#include <unistd.h>
17
18#include "parse-events.h"
15 19
16#include <sys/mman.h> 20#include <sys/mman.h>
17 21
@@ -30,6 +34,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
30 INIT_HLIST_HEAD(&evlist->heads[i]); 34 INIT_HLIST_HEAD(&evlist->heads[i]);
31 INIT_LIST_HEAD(&evlist->entries); 35 INIT_LIST_HEAD(&evlist->entries);
32 perf_evlist__set_maps(evlist, cpus, threads); 36 perf_evlist__set_maps(evlist, cpus, threads);
37 evlist->workload.pid = -1;
33} 38}
34 39
35struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 40struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -43,6 +48,22 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
43 return evlist; 48 return evlist;
44} 49}
45 50
51void perf_evlist__config_attrs(struct perf_evlist *evlist,
52 struct perf_record_opts *opts)
53{
54 struct perf_evsel *evsel;
55
56 if (evlist->cpus->map[0] < 0)
57 opts->no_inherit = true;
58
59 list_for_each_entry(evsel, &evlist->entries, node) {
60 perf_evsel__config(evsel, opts);
61
62 if (evlist->nr_entries > 1)
63 evsel->attr.sample_type |= PERF_SAMPLE_ID;
64 }
65}
66
46static void perf_evlist__purge(struct perf_evlist *evlist) 67static void perf_evlist__purge(struct perf_evlist *evlist)
47{ 68{
48 struct perf_evsel *pos, *n; 69 struct perf_evsel *pos, *n;
@@ -76,6 +97,14 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
76 ++evlist->nr_entries; 97 ++evlist->nr_entries;
77} 98}
78 99
100static void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
101 struct list_head *list,
102 int nr_entries)
103{
104 list_splice_tail(list, &evlist->entries);
105 evlist->nr_entries += nr_entries;
106}
107
79int perf_evlist__add_default(struct perf_evlist *evlist) 108int perf_evlist__add_default(struct perf_evlist *evlist)
80{ 109{
81 struct perf_event_attr attr = { 110 struct perf_event_attr attr = {
@@ -100,6 +129,126 @@ error:
100 return -ENOMEM; 129 return -ENOMEM;
101} 130}
102 131
132int perf_evlist__add_attrs(struct perf_evlist *evlist,
133 struct perf_event_attr *attrs, size_t nr_attrs)
134{
135 struct perf_evsel *evsel, *n;
136 LIST_HEAD(head);
137 size_t i;
138
139 for (i = 0; i < nr_attrs; i++) {
140 evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i);
141 if (evsel == NULL)
142 goto out_delete_partial_list;
143 list_add_tail(&evsel->node, &head);
144 }
145
146 perf_evlist__splice_list_tail(evlist, &head, nr_attrs);
147
148 return 0;
149
150out_delete_partial_list:
151 list_for_each_entry_safe(evsel, n, &head, node)
152 perf_evsel__delete(evsel);
153 return -1;
154}
155
156static int trace_event__id(const char *evname)
157{
158 char *filename, *colon;
159 int err = -1, fd;
160
161 if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0)
162 return -1;
163
164 colon = strrchr(filename, ':');
165 if (colon != NULL)
166 *colon = '/';
167
168 fd = open(filename, O_RDONLY);
169 if (fd >= 0) {
170 char id[16];
171 if (read(fd, id, sizeof(id)) > 0)
172 err = atoi(id);
173 close(fd);
174 }
175
176 free(filename);
177 return err;
178}
179
180int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
181 const char *tracepoints[],
182 size_t nr_tracepoints)
183{
184 int err;
185 size_t i;
186 struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs));
187
188 if (attrs == NULL)
189 return -1;
190
191 for (i = 0; i < nr_tracepoints; i++) {
192 err = trace_event__id(tracepoints[i]);
193
194 if (err < 0)
195 goto out_free_attrs;
196
197 attrs[i].type = PERF_TYPE_TRACEPOINT;
198 attrs[i].config = err;
199 attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
200 PERF_SAMPLE_CPU);
201 attrs[i].sample_period = 1;
202 }
203
204 err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints);
205out_free_attrs:
206 free(attrs);
207 return err;
208}
209
210static struct perf_evsel *
211 perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
212{
213 struct perf_evsel *evsel;
214
215 list_for_each_entry(evsel, &evlist->entries, node) {
216 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
217 (int)evsel->attr.config == id)
218 return evsel;
219 }
220
221 return NULL;
222}
223
224int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
225 const struct perf_evsel_str_handler *assocs,
226 size_t nr_assocs)
227{
228 struct perf_evsel *evsel;
229 int err;
230 size_t i;
231
232 for (i = 0; i < nr_assocs; i++) {
233 err = trace_event__id(assocs[i].name);
234 if (err < 0)
235 goto out;
236
237 evsel = perf_evlist__find_tracepoint_by_id(evlist, err);
238 if (evsel == NULL)
239 continue;
240
241 err = -EEXIST;
242 if (evsel->handler.func != NULL)
243 goto out;
244 evsel->handler.func = assocs[i].handler;
245 }
246
247 err = 0;
248out:
249 return err;
250}
251
103void perf_evlist__disable(struct perf_evlist *evlist) 252void perf_evlist__disable(struct perf_evlist *evlist)
104{ 253{
105 int cpu, thread; 254 int cpu, thread;
@@ -126,7 +275,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
126 } 275 }
127} 276}
128 277
129int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 278static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
130{ 279{
131 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; 280 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
132 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 281 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
@@ -282,7 +431,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
282 evlist->mmap = NULL; 431 evlist->mmap = NULL;
283} 432}
284 433
285int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 434static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
286{ 435{
287 evlist->nr_mmaps = evlist->cpus->nr; 436 evlist->nr_mmaps = evlist->cpus->nr;
288 if (evlist->cpus->map[0] == -1) 437 if (evlist->cpus->map[0] == -1)
@@ -400,14 +549,20 @@ out_unmap:
400 * 549 *
401 * Using perf_evlist__read_on_cpu does this automatically. 550 * Using perf_evlist__read_on_cpu does this automatically.
402 */ 551 */
403int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) 552int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
553 bool overwrite)
404{ 554{
405 unsigned int page_size = sysconf(_SC_PAGE_SIZE); 555 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
406 int mask = pages * page_size - 1;
407 struct perf_evsel *evsel; 556 struct perf_evsel *evsel;
408 const struct cpu_map *cpus = evlist->cpus; 557 const struct cpu_map *cpus = evlist->cpus;
409 const struct thread_map *threads = evlist->threads; 558 const struct thread_map *threads = evlist->threads;
410 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE); 559 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
560
561 /* 512 kiB: default amount of unprivileged mlocked memory */
562 if (pages == UINT_MAX)
563 pages = (512 * 1024) / page_size;
564
565 mask = pages * page_size - 1;
411 566
412 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 567 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
413 return -ENOMEM; 568 return -ENOMEM;
@@ -512,6 +667,38 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
512 return first->attr.sample_type; 667 return first->attr.sample_type;
513} 668}
514 669
670u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist)
671{
672 struct perf_evsel *first;
673 struct perf_sample *data;
674 u64 sample_type;
675 u16 size = 0;
676
677 first = list_entry(evlist->entries.next, struct perf_evsel, node);
678
679 if (!first->attr.sample_id_all)
680 goto out;
681
682 sample_type = first->attr.sample_type;
683
684 if (sample_type & PERF_SAMPLE_TID)
685 size += sizeof(data->tid) * 2;
686
687 if (sample_type & PERF_SAMPLE_TIME)
688 size += sizeof(data->time);
689
690 if (sample_type & PERF_SAMPLE_ID)
691 size += sizeof(data->id);
692
693 if (sample_type & PERF_SAMPLE_STREAM_ID)
694 size += sizeof(data->stream_id);
695
696 if (sample_type & PERF_SAMPLE_CPU)
697 size += sizeof(data->cpu) * 2;
698out:
699 return size;
700}
701
515bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist) 702bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
516{ 703{
517 struct perf_evsel *pos, *first; 704 struct perf_evsel *pos, *first;
@@ -569,3 +756,97 @@ out_err:
569 756
570 return err; 757 return err;
571} 758}
759
760int perf_evlist__prepare_workload(struct perf_evlist *evlist,
761 struct perf_record_opts *opts,
762 const char *argv[])
763{
764 int child_ready_pipe[2], go_pipe[2];
765 char bf;
766
767 if (pipe(child_ready_pipe) < 0) {
768 perror("failed to create 'ready' pipe");
769 return -1;
770 }
771
772 if (pipe(go_pipe) < 0) {
773 perror("failed to create 'go' pipe");
774 goto out_close_ready_pipe;
775 }
776
777 evlist->workload.pid = fork();
778 if (evlist->workload.pid < 0) {
779 perror("failed to fork");
780 goto out_close_pipes;
781 }
782
783 if (!evlist->workload.pid) {
784 if (opts->pipe_output)
785 dup2(2, 1);
786
787 close(child_ready_pipe[0]);
788 close(go_pipe[1]);
789 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
790
791 /*
792 * Do a dummy execvp to get the PLT entry resolved,
793 * so we avoid the resolver overhead on the real
794 * execvp call.
795 */
796 execvp("", (char **)argv);
797
798 /*
799 * Tell the parent we're ready to go
800 */
801 close(child_ready_pipe[1]);
802
803 /*
804 * Wait until the parent tells us to go.
805 */
806 if (read(go_pipe[0], &bf, 1) == -1)
807 perror("unable to read pipe");
808
809 execvp(argv[0], (char **)argv);
810
811 perror(argv[0]);
812 kill(getppid(), SIGUSR1);
813 exit(-1);
814 }
815
816 if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1)
817 evlist->threads->map[0] = evlist->workload.pid;
818
819 close(child_ready_pipe[1]);
820 close(go_pipe[0]);
821 /*
822 * wait for child to settle
823 */
824 if (read(child_ready_pipe[0], &bf, 1) == -1) {
825 perror("unable to read pipe");
826 goto out_close_pipes;
827 }
828
829 evlist->workload.cork_fd = go_pipe[1];
830 close(child_ready_pipe[0]);
831 return 0;
832
833out_close_pipes:
834 close(go_pipe[0]);
835 close(go_pipe[1]);
836out_close_ready_pipe:
837 close(child_ready_pipe[0]);
838 close(child_ready_pipe[1]);
839 return -1;
840}
841
842int perf_evlist__start_workload(struct perf_evlist *evlist)
843{
844 if (evlist->workload.cork_fd > 0) {
845 /*
846 * Remove the cork, let it rip!
847 */
848 return close(evlist->workload.cork_fd);
849 }
850
851 return 0;
852}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 1779ffef782..8922aeed046 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -2,12 +2,16 @@
2#define __PERF_EVLIST_H 1 2#define __PERF_EVLIST_H 1
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include <stdio.h>
5#include "../perf.h" 6#include "../perf.h"
6#include "event.h" 7#include "event.h"
8#include "util.h"
9#include <unistd.h>
7 10
8struct pollfd; 11struct pollfd;
9struct thread_map; 12struct thread_map;
10struct cpu_map; 13struct cpu_map;
14struct perf_record_opts;
11 15
12#define PERF_EVLIST__HLIST_BITS 8 16#define PERF_EVLIST__HLIST_BITS 8
13#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 17#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
@@ -19,6 +23,10 @@ struct perf_evlist {
19 int nr_fds; 23 int nr_fds;
20 int nr_mmaps; 24 int nr_mmaps;
21 int mmap_len; 25 int mmap_len;
26 struct {
27 int cork_fd;
28 pid_t pid;
29 } workload;
22 bool overwrite; 30 bool overwrite;
23 union perf_event event_copy; 31 union perf_event event_copy;
24 struct perf_mmap *mmap; 32 struct perf_mmap *mmap;
@@ -28,6 +36,11 @@ struct perf_evlist {
28 struct perf_evsel *selected; 36 struct perf_evsel *selected;
29}; 37};
30 38
39struct perf_evsel_str_handler {
40 const char *name;
41 void *handler;
42};
43
31struct perf_evsel; 44struct perf_evsel;
32 45
33struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 46struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -39,11 +52,26 @@ void perf_evlist__delete(struct perf_evlist *evlist);
39 52
40void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); 53void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
41int perf_evlist__add_default(struct perf_evlist *evlist); 54int perf_evlist__add_default(struct perf_evlist *evlist);
55int perf_evlist__add_attrs(struct perf_evlist *evlist,
56 struct perf_event_attr *attrs, size_t nr_attrs);
57int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
58 const char *tracepoints[], size_t nr_tracepoints);
59int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
60 const struct perf_evsel_str_handler *assocs,
61 size_t nr_assocs);
62
63#define perf_evlist__add_attrs_array(evlist, array) \
64 perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array))
65
66#define perf_evlist__add_tracepoints_array(evlist, array) \
67 perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array))
68
69#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
70 perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
42 71
43void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 72void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
44 int cpu, int thread, u64 id); 73 int cpu, int thread, u64 id);
45 74
46int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
47void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); 75void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
48 76
49struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); 77struct 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);
52 80
53int perf_evlist__open(struct perf_evlist *evlist, bool group); 81int perf_evlist__open(struct perf_evlist *evlist, bool group);
54 82
55int perf_evlist__alloc_mmap(struct perf_evlist *evlist); 83void perf_evlist__config_attrs(struct perf_evlist *evlist,
56int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); 84 struct perf_record_opts *opts);
85
86int perf_evlist__prepare_workload(struct perf_evlist *evlist,
87 struct perf_record_opts *opts,
88 const char *argv[]);
89int perf_evlist__start_workload(struct perf_evlist *evlist);
90
91int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
92 bool overwrite);
57void perf_evlist__munmap(struct perf_evlist *evlist); 93void perf_evlist__munmap(struct perf_evlist *evlist);
58 94
59void perf_evlist__disable(struct perf_evlist *evlist); 95void perf_evlist__disable(struct perf_evlist *evlist);
@@ -77,6 +113,7 @@ int perf_evlist__set_filters(struct perf_evlist *evlist);
77 113
78u64 perf_evlist__sample_type(const struct perf_evlist *evlist); 114u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
79bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); 115bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
116u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
80 117
81bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); 118bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
82bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); 119bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d7915d4e77c..ee68d6944e6 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -63,6 +63,76 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 63 return evsel;
64} 64}
65 65
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
67{
68 struct perf_event_attr *attr = &evsel->attr;
69 int track = !evsel->idx; /* only the first counter needs these */
70
71 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
72 attr->inherit = !opts->no_inherit;
73 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
74 PERF_FORMAT_TOTAL_TIME_RUNNING |
75 PERF_FORMAT_ID;
76
77 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
78
79 /*
80 * We default some events to a 1 default interval. But keep
81 * it a weak assumption overridable by the user.
82 */
83 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
84 opts->user_interval != ULLONG_MAX)) {
85 if (opts->freq) {
86 attr->sample_type |= PERF_SAMPLE_PERIOD;
87 attr->freq = 1;
88 attr->sample_freq = opts->freq;
89 } else {
90 attr->sample_period = opts->default_interval;
91 }
92 }
93
94 if (opts->no_samples)
95 attr->sample_freq = 0;
96
97 if (opts->inherit_stat)
98 attr->inherit_stat = 1;
99
100 if (opts->sample_address) {
101 attr->sample_type |= PERF_SAMPLE_ADDR;
102 attr->mmap_data = track;
103 }
104
105 if (opts->call_graph)
106 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
107
108 if (opts->system_wide)
109 attr->sample_type |= PERF_SAMPLE_CPU;
110
111 if (opts->sample_id_all_avail &&
112 (opts->sample_time || opts->system_wide ||
113 !opts->no_inherit || opts->cpu_list))
114 attr->sample_type |= PERF_SAMPLE_TIME;
115
116 if (opts->raw_samples) {
117 attr->sample_type |= PERF_SAMPLE_TIME;
118 attr->sample_type |= PERF_SAMPLE_RAW;
119 attr->sample_type |= PERF_SAMPLE_CPU;
120 }
121
122 if (opts->no_delay) {
123 attr->watermark = 0;
124 attr->wakeup_events = 1;
125 }
126
127 attr->mmap = track;
128 attr->comm = track;
129
130 if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) {
131 attr->disabled = 1;
132 attr->enable_on_exec = 1;
133 }
134}
135
66int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 136int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
67{ 137{
68 int cpu, thread; 138 int cpu, thread;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b1d15e6f7ae..326b8e4d503 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -61,12 +61,17 @@ struct perf_evsel {
61 off_t id_offset; 61 off_t id_offset;
62 }; 62 };
63 struct cgroup_sel *cgrp; 63 struct cgroup_sel *cgrp;
64 struct {
65 void *func;
66 void *data;
67 } handler;
64 bool supported; 68 bool supported;
65}; 69};
66 70
67struct cpu_map; 71struct cpu_map;
68struct thread_map; 72struct thread_map;
69struct perf_evlist; 73struct perf_evlist;
74struct perf_record_opts;
70 75
71struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 76struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
72void perf_evsel__init(struct perf_evsel *evsel, 77void perf_evsel__init(struct perf_evsel *evsel,
@@ -74,6 +79,9 @@ void perf_evsel__init(struct perf_evsel *evsel,
74void perf_evsel__exit(struct perf_evsel *evsel); 79void perf_evsel__exit(struct perf_evsel *evsel);
75void perf_evsel__delete(struct perf_evsel *evsel); 80void perf_evsel__delete(struct perf_evsel *evsel);
76 81
82void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts);
84
77int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 85int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
78int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 86int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
79int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 87int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 33c17a2b2a8..5b01449152e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2041,6 +2041,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
2041 lseek(fd, tmp, SEEK_SET); 2041 lseek(fd, tmp, SEEK_SET);
2042 } 2042 }
2043 2043
2044 symbol_conf.nr_events = nr_attrs;
2045
2044 if (f_header.event_types.size) { 2046 if (f_header.event_types.size) {
2045 lseek(fd, f_header.event_types.offset, SEEK_SET); 2047 lseek(fd, f_header.event_types.offset, SEEK_SET);
2046 events = malloc(f_header.event_types.size); 2048 events = malloc(f_header.event_types.size);
@@ -2068,9 +2070,9 @@ out_delete_evlist:
2068 return -ENOMEM; 2070 return -ENOMEM;
2069} 2071}
2070 2072
2071int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 2073int perf_event__synthesize_attr(struct perf_tool *tool,
2072 perf_event__handler_t process, 2074 struct perf_event_attr *attr, u16 ids, u64 *id,
2073 struct perf_session *session) 2075 perf_event__handler_t process)
2074{ 2076{
2075 union perf_event *ev; 2077 union perf_event *ev;
2076 size_t size; 2078 size_t size;
@@ -2092,22 +2094,23 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
2092 ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 2094 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
2093 ev->attr.header.size = size; 2095 ev->attr.header.size = size;
2094 2096
2095 err = process(ev, NULL, session); 2097 err = process(tool, ev, NULL, NULL);
2096 2098
2097 free(ev); 2099 free(ev);
2098 2100
2099 return err; 2101 return err;
2100} 2102}
2101 2103
2102int perf_session__synthesize_attrs(struct perf_session *session, 2104int perf_event__synthesize_attrs(struct perf_tool *tool,
2105 struct perf_session *session,
2103 perf_event__handler_t process) 2106 perf_event__handler_t process)
2104{ 2107{
2105 struct perf_evsel *attr; 2108 struct perf_evsel *attr;
2106 int err = 0; 2109 int err = 0;
2107 2110
2108 list_for_each_entry(attr, &session->evlist->entries, node) { 2111 list_for_each_entry(attr, &session->evlist->entries, node) {
2109 err = perf_event__synthesize_attr(&attr->attr, attr->ids, 2112 err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids,
2110 attr->id, process, session); 2113 attr->id, process);
2111 if (err) { 2114 if (err) {
2112 pr_debug("failed to create perf header attribute\n"); 2115 pr_debug("failed to create perf header attribute\n");
2113 return err; 2116 return err;
@@ -2118,23 +2121,23 @@ int perf_session__synthesize_attrs(struct perf_session *session,
2118} 2121}
2119 2122
2120int perf_event__process_attr(union perf_event *event, 2123int perf_event__process_attr(union perf_event *event,
2121 struct perf_session *session) 2124 struct perf_evlist **pevlist)
2122{ 2125{
2123 unsigned int i, ids, n_ids; 2126 unsigned int i, ids, n_ids;
2124 struct perf_evsel *evsel; 2127 struct perf_evsel *evsel;
2128 struct perf_evlist *evlist = *pevlist;
2125 2129
2126 if (session->evlist == NULL) { 2130 if (evlist == NULL) {
2127 session->evlist = perf_evlist__new(NULL, NULL); 2131 *pevlist = evlist = perf_evlist__new(NULL, NULL);
2128 if (session->evlist == NULL) 2132 if (evlist == NULL)
2129 return -ENOMEM; 2133 return -ENOMEM;
2130 } 2134 }
2131 2135
2132 evsel = perf_evsel__new(&event->attr.attr, 2136 evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries);
2133 session->evlist->nr_entries);
2134 if (evsel == NULL) 2137 if (evsel == NULL)
2135 return -ENOMEM; 2138 return -ENOMEM;
2136 2139
2137 perf_evlist__add(session->evlist, evsel); 2140 perf_evlist__add(evlist, evsel);
2138 2141
2139 ids = event->header.size; 2142 ids = event->header.size;
2140 ids -= (void *)&event->attr.id - (void *)event; 2143 ids -= (void *)&event->attr.id - (void *)event;
@@ -2148,18 +2151,16 @@ int perf_event__process_attr(union perf_event *event,
2148 return -ENOMEM; 2151 return -ENOMEM;
2149 2152
2150 for (i = 0; i < n_ids; i++) { 2153 for (i = 0; i < n_ids; i++) {
2151 perf_evlist__id_add(session->evlist, evsel, 0, i, 2154 perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]);
2152 event->attr.id[i]);
2153 } 2155 }
2154 2156
2155 perf_session__update_sample_type(session);
2156
2157 return 0; 2157 return 0;
2158} 2158}
2159 2159
2160int perf_event__synthesize_event_type(u64 event_id, char *name, 2160int perf_event__synthesize_event_type(struct perf_tool *tool,
2161 u64 event_id, char *name,
2161 perf_event__handler_t process, 2162 perf_event__handler_t process,
2162 struct perf_session *session) 2163 struct machine *machine)
2163{ 2164{
2164 union perf_event ev; 2165 union perf_event ev;
2165 size_t size = 0; 2166 size_t size = 0;
@@ -2177,13 +2178,14 @@ int perf_event__synthesize_event_type(u64 event_id, char *name,
2177 ev.event_type.header.size = sizeof(ev.event_type) - 2178 ev.event_type.header.size = sizeof(ev.event_type) -
2178 (sizeof(ev.event_type.event_type.name) - size); 2179 (sizeof(ev.event_type.event_type.name) - size);
2179 2180
2180 err = process(&ev, NULL, session); 2181 err = process(tool, &ev, NULL, machine);
2181 2182
2182 return err; 2183 return err;
2183} 2184}
2184 2185
2185int perf_event__synthesize_event_types(perf_event__handler_t process, 2186int perf_event__synthesize_event_types(struct perf_tool *tool,
2186 struct perf_session *session) 2187 perf_event__handler_t process,
2188 struct machine *machine)
2187{ 2189{
2188 struct perf_trace_event_type *type; 2190 struct perf_trace_event_type *type;
2189 int i, err = 0; 2191 int i, err = 0;
@@ -2191,9 +2193,9 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
2191 for (i = 0; i < event_count; i++) { 2193 for (i = 0; i < event_count; i++) {
2192 type = &events[i]; 2194 type = &events[i];
2193 2195
2194 err = perf_event__synthesize_event_type(type->event_id, 2196 err = perf_event__synthesize_event_type(tool, type->event_id,
2195 type->name, process, 2197 type->name, process,
2196 session); 2198 machine);
2197 if (err) { 2199 if (err) {
2198 pr_debug("failed to create perf header event type\n"); 2200 pr_debug("failed to create perf header event type\n");
2199 return err; 2201 return err;
@@ -2203,8 +2205,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
2203 return err; 2205 return err;
2204} 2206}
2205 2207
2206int perf_event__process_event_type(union perf_event *event, 2208int perf_event__process_event_type(struct perf_tool *tool __unused,
2207 struct perf_session *session __unused) 2209 union perf_event *event)
2208{ 2210{
2209 if (perf_header__push_event(event->event_type.event_type.event_id, 2211 if (perf_header__push_event(event->event_type.event_type.event_id,
2210 event->event_type.event_type.name) < 0) 2212 event->event_type.event_type.name) < 0)
@@ -2213,9 +2215,9 @@ int perf_event__process_event_type(union perf_event *event,
2213 return 0; 2215 return 0;
2214} 2216}
2215 2217
2216int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, 2218int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
2217 perf_event__handler_t process, 2219 struct perf_evlist *evlist,
2218 struct perf_session *session __unused) 2220 perf_event__handler_t process)
2219{ 2221{
2220 union perf_event ev; 2222 union perf_event ev;
2221 struct tracing_data *tdata; 2223 struct tracing_data *tdata;
@@ -2246,7 +2248,7 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
2246 ev.tracing_data.header.size = sizeof(ev.tracing_data); 2248 ev.tracing_data.header.size = sizeof(ev.tracing_data);
2247 ev.tracing_data.size = aligned_size; 2249 ev.tracing_data.size = aligned_size;
2248 2250
2249 process(&ev, NULL, session); 2251 process(tool, &ev, NULL, NULL);
2250 2252
2251 /* 2253 /*
2252 * The put function will copy all the tracing data 2254 * The put function will copy all the tracing data
@@ -2288,10 +2290,10 @@ int perf_event__process_tracing_data(union perf_event *event,
2288 return size_read + padding; 2290 return size_read + padding;
2289} 2291}
2290 2292
2291int perf_event__synthesize_build_id(struct dso *pos, u16 misc, 2293int perf_event__synthesize_build_id(struct perf_tool *tool,
2294 struct dso *pos, u16 misc,
2292 perf_event__handler_t process, 2295 perf_event__handler_t process,
2293 struct machine *machine, 2296 struct machine *machine)
2294 struct perf_session *session)
2295{ 2297{
2296 union perf_event ev; 2298 union perf_event ev;
2297 size_t len; 2299 size_t len;
@@ -2311,12 +2313,13 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
2311 ev.build_id.header.size = sizeof(ev.build_id) + len; 2313 ev.build_id.header.size = sizeof(ev.build_id) + len;
2312 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 2314 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
2313 2315
2314 err = process(&ev, NULL, session); 2316 err = process(tool, &ev, NULL, machine);
2315 2317
2316 return err; 2318 return err;
2317} 2319}
2318 2320
2319int perf_event__process_build_id(union perf_event *event, 2321int perf_event__process_build_id(struct perf_tool *tool __used,
2322 union perf_event *event,
2320 struct perf_session *session) 2323 struct perf_session *session)
2321{ 2324{
2322 __event_process_build_id(&event->build_id, 2325 __event_process_build_id(&event->build_id,
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 3d5a742f4a2..09365b32098 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -68,6 +68,7 @@ struct perf_header {
68}; 68};
69 69
70struct perf_evlist; 70struct perf_evlist;
71struct perf_session;
71 72
72int perf_session__read_header(struct perf_session *session, int fd); 73int perf_session__read_header(struct perf_session *session, int fd);
73int perf_session__write_header(struct perf_session *session, 74int 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,
96 const char *name, bool is_kallsyms); 97 const char *name, bool is_kallsyms);
97int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 98int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
98 99
99int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 100int perf_event__synthesize_attr(struct perf_tool *tool,
100 perf_event__handler_t process, 101 struct perf_event_attr *attr, u16 ids, u64 *id,
101 struct perf_session *session); 102 perf_event__handler_t process);
102int perf_session__synthesize_attrs(struct perf_session *session, 103int perf_event__synthesize_attrs(struct perf_tool *tool,
103 perf_event__handler_t process); 104 struct perf_session *session,
104int perf_event__process_attr(union perf_event *event, struct perf_session *session); 105 perf_event__handler_t process);
106int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
105 107
106int perf_event__synthesize_event_type(u64 event_id, char *name, 108int perf_event__synthesize_event_type(struct perf_tool *tool,
109 u64 event_id, char *name,
107 perf_event__handler_t process, 110 perf_event__handler_t process,
108 struct perf_session *session); 111 struct machine *machine);
109int perf_event__synthesize_event_types(perf_event__handler_t process, 112int perf_event__synthesize_event_types(struct perf_tool *tool,
110 struct perf_session *session); 113 perf_event__handler_t process,
111int perf_event__process_event_type(union perf_event *event, 114 struct machine *machine);
112 struct perf_session *session); 115int perf_event__process_event_type(struct perf_tool *tool,
113 116 union perf_event *event);
114int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, 117
115 perf_event__handler_t process, 118int perf_event__synthesize_tracing_data(struct perf_tool *tool,
116 struct perf_session *session); 119 int fd, struct perf_evlist *evlist,
120 perf_event__handler_t process);
117int perf_event__process_tracing_data(union perf_event *event, 121int perf_event__process_tracing_data(union perf_event *event,
118 struct perf_session *session); 122 struct perf_session *session);
119 123
120int perf_event__synthesize_build_id(struct dso *pos, u16 misc, 124int perf_event__synthesize_build_id(struct perf_tool *tool,
125 struct dso *pos, u16 misc,
121 perf_event__handler_t process, 126 perf_event__handler_t process,
122 struct machine *machine, 127 struct machine *machine);
123 struct perf_session *session); 128int perf_event__process_build_id(struct perf_tool *tool,
124int perf_event__process_build_id(union perf_event *event, 129 union perf_event *event,
125 struct perf_session *session); 130 struct perf_session *session);
126 131
127/* 132/*
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 89289c8e935..ff6f9d56ea4 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -117,7 +117,6 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
117 117
118static inline int hist_entry__tui_annotate(struct hist_entry *self __used, 118static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
119 int evidx __used, 119 int evidx __used,
120 int nr_events __used,
121 void(*timer)(void *arg) __used, 120 void(*timer)(void *arg) __used,
122 void *arg __used, 121 void *arg __used,
123 int delay_secs __used) 122 int delay_secs __used)
@@ -128,7 +127,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
128#define K_RIGHT -2 127#define K_RIGHT -2
129#else 128#else
130#include "ui/keysyms.h" 129#include "ui/keysyms.h"
131int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, 130int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
132 void(*timer)(void *arg), void *arg, int delay_secs); 131 void(*timer)(void *arg), void *arg, int delay_secs);
133 132
134int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 133int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 78284b13e80..316aa0ab712 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -562,6 +562,10 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
562 INIT_LIST_HEAD(&self->user_dsos); 562 INIT_LIST_HEAD(&self->user_dsos);
563 INIT_LIST_HEAD(&self->kernel_dsos); 563 INIT_LIST_HEAD(&self->kernel_dsos);
564 564
565 self->threads = RB_ROOT;
566 INIT_LIST_HEAD(&self->dead_threads);
567 self->last_match = NULL;
568
565 self->kmaps.machine = self; 569 self->kmaps.machine = self;
566 self->pid = pid; 570 self->pid = pid;
567 self->root_dir = strdup(root_dir); 571 self->root_dir = strdup(root_dir);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 890d85545d0..2b8017f8a93 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -18,9 +18,11 @@ enum map_type {
18extern const char *map_type__name[MAP__NR_TYPES]; 18extern const char *map_type__name[MAP__NR_TYPES];
19 19
20struct dso; 20struct dso;
21struct ip_callchain;
21struct ref_reloc_sym; 22struct ref_reloc_sym;
22struct map_groups; 23struct map_groups;
23struct machine; 24struct machine;
25struct perf_evsel;
24 26
25struct map { 27struct map {
26 union { 28 union {
@@ -61,7 +63,11 @@ struct map_groups {
61struct machine { 63struct machine {
62 struct rb_node rb_node; 64 struct rb_node rb_node;
63 pid_t pid; 65 pid_t pid;
66 u16 id_hdr_size;
64 char *root_dir; 67 char *root_dir;
68 struct rb_root threads;
69 struct list_head dead_threads;
70 struct thread *last_match;
65 struct list_head user_dsos; 71 struct list_head user_dsos;
66 struct list_head kernel_dsos; 72 struct list_head kernel_dsos;
67 struct map_groups kmaps; 73 struct map_groups kmaps;
@@ -148,6 +154,13 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid);
148void machine__exit(struct machine *self); 154void machine__exit(struct machine *self);
149void machine__delete(struct machine *self); 155void machine__delete(struct machine *self);
150 156
157int machine__resolve_callchain(struct machine *machine,
158 struct perf_evsel *evsel, struct thread *thread,
159 struct ip_callchain *chain,
160 struct symbol **parent);
161int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
162 u64 addr);
163
151/* 164/*
152 * Default guest kernel is defined by parameter --guestkallsyms 165 * Default guest kernel is defined by parameter --guestkallsyms
153 * and --guestmodules 166 * and --guestmodules
@@ -190,6 +203,12 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
190 struct map **mapp, 203 struct map **mapp,
191 symbol_filter_t filter); 204 symbol_filter_t filter);
192 205
206
207struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
208void machine__remove_thread(struct machine *machine, struct thread *th);
209
210size_t machine__fprintf(struct machine *machine, FILE *fp);
211
193static inline 212static inline
194struct symbol *machine__find_kernel_symbol(struct machine *self, 213struct symbol *machine__find_kernel_symbol(struct machine *self,
195 enum map_type type, u64 addr, 214 enum map_type type, u64 addr,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 928918b796b..586ab3fe60f 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -25,8 +25,6 @@ enum event_result {
25 EVT_HANDLED_ALL 25 EVT_HANDLED_ALL
26}; 26};
27 27
28char debugfs_path[MAXPATHLEN];
29
30#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 28#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
31#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 29#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
32 30
@@ -140,7 +138,7 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
140 char evt_path[MAXPATHLEN]; 138 char evt_path[MAXPATHLEN];
141 int fd; 139 int fd;
142 140
143 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 141 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
144 sys_dir->d_name, evt_dir->d_name); 142 sys_dir->d_name, evt_dir->d_name);
145 fd = open(evt_path, O_RDONLY); 143 fd = open(evt_path, O_RDONLY);
146 if (fd < 0) 144 if (fd < 0)
@@ -171,16 +169,16 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
171 char evt_path[MAXPATHLEN]; 169 char evt_path[MAXPATHLEN];
172 char dir_path[MAXPATHLEN]; 170 char dir_path[MAXPATHLEN];
173 171
174 if (debugfs_valid_mountpoint(debugfs_path)) 172 if (debugfs_valid_mountpoint(tracing_events_path))
175 return NULL; 173 return NULL;
176 174
177 sys_dir = opendir(debugfs_path); 175 sys_dir = opendir(tracing_events_path);
178 if (!sys_dir) 176 if (!sys_dir)
179 return NULL; 177 return NULL;
180 178
181 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 179 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
182 180
183 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 181 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
184 sys_dirent.d_name); 182 sys_dirent.d_name);
185 evt_dir = opendir(dir_path); 183 evt_dir = opendir(dir_path);
186 if (!evt_dir) 184 if (!evt_dir)
@@ -447,7 +445,7 @@ parse_single_tracepoint_event(char *sys_name,
447 u64 id; 445 u64 id;
448 int fd; 446 int fd;
449 447
450 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 448 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
451 sys_name, evt_name); 449 sys_name, evt_name);
452 450
453 fd = open(evt_path, O_RDONLY); 451 fd = open(evt_path, O_RDONLY);
@@ -485,7 +483,7 @@ parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
485 struct dirent *evt_ent; 483 struct dirent *evt_ent;
486 DIR *evt_dir; 484 DIR *evt_dir;
487 485
488 snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); 486 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
489 evt_dir = opendir(evt_path); 487 evt_dir = opendir(evt_path);
490 488
491 if (!evt_dir) { 489 if (!evt_dir) {
@@ -528,7 +526,7 @@ parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
528 char sys_name[MAX_EVENT_LENGTH]; 526 char sys_name[MAX_EVENT_LENGTH];
529 unsigned int sys_length, evt_length; 527 unsigned int sys_length, evt_length;
530 528
531 if (debugfs_valid_mountpoint(debugfs_path)) 529 if (debugfs_valid_mountpoint(tracing_events_path))
532 return 0; 530 return 0;
533 531
534 evt_name = strchr(*strp, ':'); 532 evt_name = strchr(*strp, ':');
@@ -920,10 +918,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
920 char evt_path[MAXPATHLEN]; 918 char evt_path[MAXPATHLEN];
921 char dir_path[MAXPATHLEN]; 919 char dir_path[MAXPATHLEN];
922 920
923 if (debugfs_valid_mountpoint(debugfs_path)) 921 if (debugfs_valid_mountpoint(tracing_events_path))
924 return; 922 return;
925 923
926 sys_dir = opendir(debugfs_path); 924 sys_dir = opendir(tracing_events_path);
927 if (!sys_dir) 925 if (!sys_dir)
928 return; 926 return;
929 927
@@ -932,7 +930,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
932 !strglobmatch(sys_dirent.d_name, subsys_glob)) 930 !strglobmatch(sys_dirent.d_name, subsys_glob))
933 continue; 931 continue;
934 932
935 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 933 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
936 sys_dirent.d_name); 934 sys_dirent.d_name);
937 evt_dir = opendir(dir_path); 935 evt_dir = opendir(dir_path);
938 if (!evt_dir) 936 if (!evt_dir)
@@ -964,16 +962,16 @@ int is_valid_tracepoint(const char *event_string)
964 char evt_path[MAXPATHLEN]; 962 char evt_path[MAXPATHLEN];
965 char dir_path[MAXPATHLEN]; 963 char dir_path[MAXPATHLEN];
966 964
967 if (debugfs_valid_mountpoint(debugfs_path)) 965 if (debugfs_valid_mountpoint(tracing_events_path))
968 return 0; 966 return 0;
969 967
970 sys_dir = opendir(debugfs_path); 968 sys_dir = opendir(tracing_events_path);
971 if (!sys_dir) 969 if (!sys_dir)
972 return 0; 970 return 0;
973 971
974 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 972 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
975 973
976 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 974 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
977 sys_dirent.d_name); 975 sys_dirent.d_name);
978 evt_dir = opendir(dir_path); 976 evt_dir = opendir(dir_path);
979 if (!evt_dir) 977 if (!evt_dir)
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2f8e375e038..7e0cbe75d5f 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -39,7 +39,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
39int print_hwcache_events(const char *event_glob); 39int print_hwcache_events(const char *event_glob);
40extern int is_valid_tracepoint(const char *event_string); 40extern int is_valid_tracepoint(const char *event_string);
41 41
42extern char debugfs_path[];
43extern int valid_debugfs_mount(const char *debugfs); 42extern int valid_debugfs_mount(const char *debugfs);
44 43
45#endif /* __PERF_PARSE_EVENTS_H */ 44#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 1132c8f0ce8..17e94d0c36f 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -5,7 +5,6 @@
5#include "util.h" 5#include "util.h"
6#include "probe-event.h" 6#include "probe-event.h"
7 7
8#define MAX_PATH_LEN 256
9#define MAX_PROBE_BUFFER 1024 8#define MAX_PROBE_BUFFER 1024
10#define MAX_PROBES 128 9#define MAX_PROBES 128
11 10
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 74350ffb57f..a82ce4303ff 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -27,6 +27,8 @@
27 27
28#include "../../perf.h" 28#include "../../perf.h"
29#include "../util.h" 29#include "../util.h"
30#include "../thread.h"
31#include "../event.h"
30#include "../trace-event.h" 32#include "../trace-event.h"
31 33
32#include <EXTERN.h> 34#include <EXTERN.h>
@@ -248,7 +250,7 @@ static inline struct event *find_cache_event(int type)
248static void perl_process_event(union perf_event *pevent __unused, 250static void perl_process_event(union perf_event *pevent __unused,
249 struct perf_sample *sample, 251 struct perf_sample *sample,
250 struct perf_evsel *evsel, 252 struct perf_evsel *evsel,
251 struct perf_session *session __unused, 253 struct machine *machine __unused,
252 struct thread *thread) 254 struct thread *thread)
253{ 255{
254 struct format_field *field; 256 struct format_field *field;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 6ccf70e8d8f..0b2a4878317 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -29,6 +29,8 @@
29 29
30#include "../../perf.h" 30#include "../../perf.h"
31#include "../util.h" 31#include "../util.h"
32#include "../event.h"
33#include "../thread.h"
32#include "../trace-event.h" 34#include "../trace-event.h"
33 35
34PyMODINIT_FUNC initperf_trace_context(void); 36PyMODINIT_FUNC initperf_trace_context(void);
@@ -207,7 +209,7 @@ static inline struct event *find_cache_event(int type)
207static void python_process_event(union perf_event *pevent __unused, 209static void python_process_event(union perf_event *pevent __unused,
208 struct perf_sample *sample, 210 struct perf_sample *sample,
209 struct perf_evsel *evsel __unused, 211 struct perf_evsel *evsel __unused,
210 struct perf_session *session __unused, 212 struct machine *machine __unused,
211 struct thread *thread) 213 struct thread *thread)
212{ 214{
213 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 215 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0f4555ce906..d9318d8a9ba 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -10,6 +10,7 @@
10#include "evlist.h" 10#include "evlist.h"
11#include "evsel.h" 11#include "evsel.h"
12#include "session.h" 12#include "session.h"
13#include "tool.h"
13#include "sort.h" 14#include "sort.h"
14#include "util.h" 15#include "util.h"
15#include "cpumap.h" 16#include "cpumap.h"
@@ -78,39 +79,13 @@ out_close:
78 return -1; 79 return -1;
79} 80}
80 81
81static void perf_session__id_header_size(struct perf_session *session)
82{
83 struct perf_sample *data;
84 u64 sample_type = session->sample_type;
85 u16 size = 0;
86
87 if (!session->sample_id_all)
88 goto out;
89
90 if (sample_type & PERF_SAMPLE_TID)
91 size += sizeof(data->tid) * 2;
92
93 if (sample_type & PERF_SAMPLE_TIME)
94 size += sizeof(data->time);
95
96 if (sample_type & PERF_SAMPLE_ID)
97 size += sizeof(data->id);
98
99 if (sample_type & PERF_SAMPLE_STREAM_ID)
100 size += sizeof(data->stream_id);
101
102 if (sample_type & PERF_SAMPLE_CPU)
103 size += sizeof(data->cpu) * 2;
104out:
105 session->id_hdr_size = size;
106}
107
108void perf_session__update_sample_type(struct perf_session *self) 82void perf_session__update_sample_type(struct perf_session *self)
109{ 83{
110 self->sample_type = perf_evlist__sample_type(self->evlist); 84 self->sample_type = perf_evlist__sample_type(self->evlist);
111 self->sample_size = __perf_evsel__sample_size(self->sample_type); 85 self->sample_size = __perf_evsel__sample_size(self->sample_type);
112 self->sample_id_all = perf_evlist__sample_id_all(self->evlist); 86 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
113 perf_session__id_header_size(self); 87 self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
88 self->host_machine.id_hdr_size = self->id_hdr_size;
114} 89}
115 90
116int perf_session__create_kernel_maps(struct perf_session *self) 91int perf_session__create_kernel_maps(struct perf_session *self)
@@ -130,7 +105,7 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
130 105
131struct perf_session *perf_session__new(const char *filename, int mode, 106struct perf_session *perf_session__new(const char *filename, int mode,
132 bool force, bool repipe, 107 bool force, bool repipe,
133 struct perf_event_ops *ops) 108 struct perf_tool *tool)
134{ 109{
135 size_t len = filename ? strlen(filename) + 1 : 0; 110 size_t len = filename ? strlen(filename) + 1 : 0;
136 struct perf_session *self = zalloc(sizeof(*self) + len); 111 struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -139,9 +114,6 @@ struct perf_session *perf_session__new(const char *filename, int mode,
139 goto out; 114 goto out;
140 115
141 memcpy(self->filename, filename, len); 116 memcpy(self->filename, filename, len);
142 self->threads = RB_ROOT;
143 INIT_LIST_HEAD(&self->dead_threads);
144 self->last_match = NULL;
145 /* 117 /*
146 * On 64bit we can mmap the data file in one go. No need for tiny mmap 118 * On 64bit we can mmap the data file in one go. No need for tiny mmap
147 * slices. On 32bit we use 32MB. 119 * slices. On 32bit we use 32MB.
@@ -171,10 +143,10 @@ struct perf_session *perf_session__new(const char *filename, int mode,
171 goto out_delete; 143 goto out_delete;
172 } 144 }
173 145
174 if (ops && ops->ordering_requires_timestamps && 146 if (tool && tool->ordering_requires_timestamps &&
175 ops->ordered_samples && !self->sample_id_all) { 147 tool->ordered_samples && !self->sample_id_all) {
176 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 148 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
177 ops->ordered_samples = false; 149 tool->ordered_samples = false;
178 } 150 }
179 151
180out: 152out:
@@ -184,17 +156,22 @@ out_delete:
184 return NULL; 156 return NULL;
185} 157}
186 158
187static void perf_session__delete_dead_threads(struct perf_session *self) 159static void machine__delete_dead_threads(struct machine *machine)
188{ 160{
189 struct thread *n, *t; 161 struct thread *n, *t;
190 162
191 list_for_each_entry_safe(t, n, &self->dead_threads, node) { 163 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
192 list_del(&t->node); 164 list_del(&t->node);
193 thread__delete(t); 165 thread__delete(t);
194 } 166 }
195} 167}
196 168
197static void perf_session__delete_threads(struct perf_session *self) 169static void perf_session__delete_dead_threads(struct perf_session *session)
170{
171 machine__delete_dead_threads(&session->host_machine);
172}
173
174static void machine__delete_threads(struct machine *self)
198{ 175{
199 struct rb_node *nd = rb_first(&self->threads); 176 struct rb_node *nd = rb_first(&self->threads);
200 177
@@ -207,6 +184,11 @@ static void perf_session__delete_threads(struct perf_session *self)
207 } 184 }
208} 185}
209 186
187static void perf_session__delete_threads(struct perf_session *session)
188{
189 machine__delete_threads(&session->host_machine);
190}
191
210void perf_session__delete(struct perf_session *self) 192void perf_session__delete(struct perf_session *self)
211{ 193{
212 perf_session__destroy_kernel_maps(self); 194 perf_session__destroy_kernel_maps(self);
@@ -217,7 +199,7 @@ void perf_session__delete(struct perf_session *self)
217 free(self); 199 free(self);
218} 200}
219 201
220void perf_session__remove_thread(struct perf_session *self, struct thread *th) 202void machine__remove_thread(struct machine *self, struct thread *th)
221{ 203{
222 self->last_match = NULL; 204 self->last_match = NULL;
223 rb_erase(&th->rb_node, &self->threads); 205 rb_erase(&th->rb_node, &self->threads);
@@ -236,16 +218,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
236 return 0; 218 return 0;
237} 219}
238 220
239int perf_session__resolve_callchain(struct perf_session *self, 221int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
240 struct thread *thread, 222 struct thread *thread,
241 struct ip_callchain *chain, 223 struct ip_callchain *chain,
242 struct symbol **parent) 224 struct symbol **parent)
243{ 225{
244 u8 cpumode = PERF_RECORD_MISC_USER; 226 u8 cpumode = PERF_RECORD_MISC_USER;
245 unsigned int i; 227 unsigned int i;
246 int err; 228 int err;
247 229
248 callchain_cursor_reset(&self->callchain_cursor); 230 callchain_cursor_reset(&evsel->hists.callchain_cursor);
249 231
250 for (i = 0; i < chain->nr; i++) { 232 for (i = 0; i < chain->nr; i++) {
251 u64 ip; 233 u64 ip;
@@ -272,7 +254,7 @@ int perf_session__resolve_callchain(struct perf_session *self,
272 254
273 al.filtered = false; 255 al.filtered = false;
274 thread__find_addr_location(thread, self, cpumode, 256 thread__find_addr_location(thread, self, cpumode,
275 MAP__FUNCTION, thread->pid, ip, &al, NULL); 257 MAP__FUNCTION, ip, &al, NULL);
276 if (al.sym != NULL) { 258 if (al.sym != NULL) {
277 if (sort__has_parent && !*parent && 259 if (sort__has_parent && !*parent &&
278 symbol__match_parent_regex(al.sym)) 260 symbol__match_parent_regex(al.sym))
@@ -281,7 +263,7 @@ int perf_session__resolve_callchain(struct perf_session *self,
281 break; 263 break;
282 } 264 }
283 265
284 err = callchain_cursor_append(&self->callchain_cursor, 266 err = callchain_cursor_append(&evsel->hists.callchain_cursor,
285 ip, al.map, al.sym); 267 ip, al.map, al.sym);
286 if (err) 268 if (err)
287 return err; 269 return err;
@@ -290,75 +272,91 @@ int perf_session__resolve_callchain(struct perf_session *self,
290 return 0; 272 return 0;
291} 273}
292 274
293static int process_event_synth_stub(union perf_event *event __used, 275static int process_event_synth_tracing_data_stub(union perf_event *event __used,
294 struct perf_session *session __used) 276 struct perf_session *session __used)
277{
278 dump_printf(": unhandled!\n");
279 return 0;
280}
281
282static int process_event_synth_attr_stub(union perf_event *event __used,
283 struct perf_evlist **pevlist __used)
295{ 284{
296 dump_printf(": unhandled!\n"); 285 dump_printf(": unhandled!\n");
297 return 0; 286 return 0;
298} 287}
299 288
300static int process_event_sample_stub(union perf_event *event __used, 289static int process_event_sample_stub(struct perf_tool *tool __used,
290 union perf_event *event __used,
301 struct perf_sample *sample __used, 291 struct perf_sample *sample __used,
302 struct perf_evsel *evsel __used, 292 struct perf_evsel *evsel __used,
303 struct perf_session *session __used) 293 struct machine *machine __used)
304{ 294{
305 dump_printf(": unhandled!\n"); 295 dump_printf(": unhandled!\n");
306 return 0; 296 return 0;
307} 297}
308 298
309static int process_event_stub(union perf_event *event __used, 299static int process_event_stub(struct perf_tool *tool __used,
300 union perf_event *event __used,
310 struct perf_sample *sample __used, 301 struct perf_sample *sample __used,
311 struct perf_session *session __used) 302 struct machine *machine __used)
303{
304 dump_printf(": unhandled!\n");
305 return 0;
306}
307
308static int process_finished_round_stub(struct perf_tool *tool __used,
309 union perf_event *event __used,
310 struct perf_session *perf_session __used)
312{ 311{
313 dump_printf(": unhandled!\n"); 312 dump_printf(": unhandled!\n");
314 return 0; 313 return 0;
315} 314}
316 315
317static int process_finished_round_stub(union perf_event *event __used, 316static int process_event_type_stub(struct perf_tool *tool __used,
318 struct perf_session *session __used, 317 union perf_event *event __used)
319 struct perf_event_ops *ops __used)
320{ 318{
321 dump_printf(": unhandled!\n"); 319 dump_printf(": unhandled!\n");
322 return 0; 320 return 0;
323} 321}
324 322
325static int process_finished_round(union perf_event *event, 323static int process_finished_round(struct perf_tool *tool,
326 struct perf_session *session, 324 union perf_event *event,
327 struct perf_event_ops *ops); 325 struct perf_session *session);
328 326
329static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 327static void perf_tool__fill_defaults(struct perf_tool *tool)
330{ 328{
331 if (handler->sample == NULL) 329 if (tool->sample == NULL)
332 handler->sample = process_event_sample_stub; 330 tool->sample = process_event_sample_stub;
333 if (handler->mmap == NULL) 331 if (tool->mmap == NULL)
334 handler->mmap = process_event_stub; 332 tool->mmap = process_event_stub;
335 if (handler->comm == NULL) 333 if (tool->comm == NULL)
336 handler->comm = process_event_stub; 334 tool->comm = process_event_stub;
337 if (handler->fork == NULL) 335 if (tool->fork == NULL)
338 handler->fork = process_event_stub; 336 tool->fork = process_event_stub;
339 if (handler->exit == NULL) 337 if (tool->exit == NULL)
340 handler->exit = process_event_stub; 338 tool->exit = process_event_stub;
341 if (handler->lost == NULL) 339 if (tool->lost == NULL)
342 handler->lost = perf_event__process_lost; 340 tool->lost = perf_event__process_lost;
343 if (handler->read == NULL) 341 if (tool->read == NULL)
344 handler->read = process_event_stub; 342 tool->read = process_event_sample_stub;
345 if (handler->throttle == NULL) 343 if (tool->throttle == NULL)
346 handler->throttle = process_event_stub; 344 tool->throttle = process_event_stub;
347 if (handler->unthrottle == NULL) 345 if (tool->unthrottle == NULL)
348 handler->unthrottle = process_event_stub; 346 tool->unthrottle = process_event_stub;
349 if (handler->attr == NULL) 347 if (tool->attr == NULL)
350 handler->attr = process_event_synth_stub; 348 tool->attr = process_event_synth_attr_stub;
351 if (handler->event_type == NULL) 349 if (tool->event_type == NULL)
352 handler->event_type = process_event_synth_stub; 350 tool->event_type = process_event_type_stub;
353 if (handler->tracing_data == NULL) 351 if (tool->tracing_data == NULL)
354 handler->tracing_data = process_event_synth_stub; 352 tool->tracing_data = process_event_synth_tracing_data_stub;
355 if (handler->build_id == NULL) 353 if (tool->build_id == NULL)
356 handler->build_id = process_event_synth_stub; 354 tool->build_id = process_finished_round_stub;
357 if (handler->finished_round == NULL) { 355 if (tool->finished_round == NULL) {
358 if (handler->ordered_samples) 356 if (tool->ordered_samples)
359 handler->finished_round = process_finished_round; 357 tool->finished_round = process_finished_round;
360 else 358 else
361 handler->finished_round = process_finished_round_stub; 359 tool->finished_round = process_finished_round_stub;
362 } 360 }
363} 361}
364 362
@@ -490,11 +488,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
490static int perf_session_deliver_event(struct perf_session *session, 488static int perf_session_deliver_event(struct perf_session *session,
491 union perf_event *event, 489 union perf_event *event,
492 struct perf_sample *sample, 490 struct perf_sample *sample,
493 struct perf_event_ops *ops, 491 struct perf_tool *tool,
494 u64 file_offset); 492 u64 file_offset);
495 493
496static void flush_sample_queue(struct perf_session *s, 494static void flush_sample_queue(struct perf_session *s,
497 struct perf_event_ops *ops) 495 struct perf_tool *tool)
498{ 496{
499 struct ordered_samples *os = &s->ordered_samples; 497 struct ordered_samples *os = &s->ordered_samples;
500 struct list_head *head = &os->samples; 498 struct list_head *head = &os->samples;
@@ -505,7 +503,7 @@ static void flush_sample_queue(struct perf_session *s,
505 unsigned idx = 0, progress_next = os->nr_samples / 16; 503 unsigned idx = 0, progress_next = os->nr_samples / 16;
506 int ret; 504 int ret;
507 505
508 if (!ops->ordered_samples || !limit) 506 if (!tool->ordered_samples || !limit)
509 return; 507 return;
510 508
511 list_for_each_entry_safe(iter, tmp, head, list) { 509 list_for_each_entry_safe(iter, tmp, head, list) {
@@ -516,7 +514,7 @@ static void flush_sample_queue(struct perf_session *s,
516 if (ret) 514 if (ret)
517 pr_err("Can't parse sample, err = %d\n", ret); 515 pr_err("Can't parse sample, err = %d\n", ret);
518 else 516 else
519 perf_session_deliver_event(s, iter->event, &sample, ops, 517 perf_session_deliver_event(s, iter->event, &sample, tool,
520 iter->file_offset); 518 iter->file_offset);
521 519
522 os->last_flush = iter->timestamp; 520 os->last_flush = iter->timestamp;
@@ -578,11 +576,11 @@ static void flush_sample_queue(struct perf_session *s,
578 * Flush every events below timestamp 7 576 * Flush every events below timestamp 7
579 * etc... 577 * etc...
580 */ 578 */
581static int process_finished_round(union perf_event *event __used, 579static int process_finished_round(struct perf_tool *tool,
582 struct perf_session *session, 580 union perf_event *event __used,
583 struct perf_event_ops *ops) 581 struct perf_session *session)
584{ 582{
585 flush_sample_queue(session, ops); 583 flush_sample_queue(session, tool);
586 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; 584 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
587 585
588 return 0; 586 return 0;
@@ -737,13 +735,26 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
737 callchain__printf(sample); 735 callchain__printf(sample);
738} 736}
739 737
738static struct machine *
739 perf_session__find_machine_for_cpumode(struct perf_session *session,
740 union perf_event *event)
741{
742 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
743
744 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest)
745 return perf_session__find_machine(session, event->ip.pid);
746
747 return perf_session__find_host_machine(session);
748}
749
740static int perf_session_deliver_event(struct perf_session *session, 750static int perf_session_deliver_event(struct perf_session *session,
741 union perf_event *event, 751 union perf_event *event,
742 struct perf_sample *sample, 752 struct perf_sample *sample,
743 struct perf_event_ops *ops, 753 struct perf_tool *tool,
744 u64 file_offset) 754 u64 file_offset)
745{ 755{
746 struct perf_evsel *evsel; 756 struct perf_evsel *evsel;
757 struct machine *machine;
747 758
748 dump_event(session, event, file_offset, sample); 759 dump_event(session, event, file_offset, sample);
749 760
@@ -765,6 +776,8 @@ static int perf_session_deliver_event(struct perf_session *session,
765 hists__inc_nr_events(&evsel->hists, event->header.type); 776 hists__inc_nr_events(&evsel->hists, event->header.type);
766 } 777 }
767 778
779 machine = perf_session__find_machine_for_cpumode(session, event);
780
768 switch (event->header.type) { 781 switch (event->header.type) {
769 case PERF_RECORD_SAMPLE: 782 case PERF_RECORD_SAMPLE:
770 dump_sample(session, event, sample); 783 dump_sample(session, event, sample);
@@ -772,23 +785,25 @@ static int perf_session_deliver_event(struct perf_session *session,
772 ++session->hists.stats.nr_unknown_id; 785 ++session->hists.stats.nr_unknown_id;
773 return -1; 786 return -1;
774 } 787 }
775 return ops->sample(event, sample, evsel, session); 788 return tool->sample(tool, event, sample, evsel, machine);
776 case PERF_RECORD_MMAP: 789 case PERF_RECORD_MMAP:
777 return ops->mmap(event, sample, session); 790 return tool->mmap(tool, event, sample, machine);
778 case PERF_RECORD_COMM: 791 case PERF_RECORD_COMM:
779 return ops->comm(event, sample, session); 792 return tool->comm(tool, event, sample, machine);
780 case PERF_RECORD_FORK: 793 case PERF_RECORD_FORK:
781 return ops->fork(event, sample, session); 794 return tool->fork(tool, event, sample, machine);
782 case PERF_RECORD_EXIT: 795 case PERF_RECORD_EXIT:
783 return ops->exit(event, sample, session); 796 return tool->exit(tool, event, sample, machine);
784 case PERF_RECORD_LOST: 797 case PERF_RECORD_LOST:
785 return ops->lost(event, sample, session); 798 if (tool->lost == perf_event__process_lost)
799 session->hists.stats.total_lost += event->lost.lost;
800 return tool->lost(tool, event, sample, machine);
786 case PERF_RECORD_READ: 801 case PERF_RECORD_READ:
787 return ops->read(event, sample, session); 802 return tool->read(tool, event, sample, evsel, machine);
788 case PERF_RECORD_THROTTLE: 803 case PERF_RECORD_THROTTLE:
789 return ops->throttle(event, sample, session); 804 return tool->throttle(tool, event, sample, machine);
790 case PERF_RECORD_UNTHROTTLE: 805 case PERF_RECORD_UNTHROTTLE:
791 return ops->unthrottle(event, sample, session); 806 return tool->unthrottle(tool, event, sample, machine);
792 default: 807 default:
793 ++session->hists.stats.nr_unknown_events; 808 ++session->hists.stats.nr_unknown_events;
794 return -1; 809 return -1;
@@ -812,24 +827,29 @@ static int perf_session__preprocess_sample(struct perf_session *session,
812} 827}
813 828
814static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 829static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
815 struct perf_event_ops *ops, u64 file_offset) 830 struct perf_tool *tool, u64 file_offset)
816{ 831{
832 int err;
833
817 dump_event(session, event, file_offset, NULL); 834 dump_event(session, event, file_offset, NULL);
818 835
819 /* These events are processed right away */ 836 /* These events are processed right away */
820 switch (event->header.type) { 837 switch (event->header.type) {
821 case PERF_RECORD_HEADER_ATTR: 838 case PERF_RECORD_HEADER_ATTR:
822 return ops->attr(event, session); 839 err = tool->attr(event, &session->evlist);
840 if (err == 0)
841 perf_session__update_sample_type(session);
842 return err;
823 case PERF_RECORD_HEADER_EVENT_TYPE: 843 case PERF_RECORD_HEADER_EVENT_TYPE:
824 return ops->event_type(event, session); 844 return tool->event_type(tool, event);
825 case PERF_RECORD_HEADER_TRACING_DATA: 845 case PERF_RECORD_HEADER_TRACING_DATA:
826 /* setup for reading amidst mmap */ 846 /* setup for reading amidst mmap */
827 lseek(session->fd, file_offset, SEEK_SET); 847 lseek(session->fd, file_offset, SEEK_SET);
828 return ops->tracing_data(event, session); 848 return tool->tracing_data(event, session);
829 case PERF_RECORD_HEADER_BUILD_ID: 849 case PERF_RECORD_HEADER_BUILD_ID:
830 return ops->build_id(event, session); 850 return tool->build_id(tool, event, session);
831 case PERF_RECORD_FINISHED_ROUND: 851 case PERF_RECORD_FINISHED_ROUND:
832 return ops->finished_round(event, session, ops); 852 return tool->finished_round(tool, event, session);
833 default: 853 default:
834 return -EINVAL; 854 return -EINVAL;
835 } 855 }
@@ -837,7 +857,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
837 857
838static int perf_session__process_event(struct perf_session *session, 858static int perf_session__process_event(struct perf_session *session,
839 union perf_event *event, 859 union perf_event *event,
840 struct perf_event_ops *ops, 860 struct perf_tool *tool,
841 u64 file_offset) 861 u64 file_offset)
842{ 862{
843 struct perf_sample sample; 863 struct perf_sample sample;
@@ -853,7 +873,7 @@ static int perf_session__process_event(struct perf_session *session,
853 hists__inc_nr_events(&session->hists, event->header.type); 873 hists__inc_nr_events(&session->hists, event->header.type);
854 874
855 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 875 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
856 return perf_session__process_user_event(session, event, ops, file_offset); 876 return perf_session__process_user_event(session, event, tool, file_offset);
857 877
858 /* 878 /*
859 * For all kernel events we get the sample data 879 * For all kernel events we get the sample data
@@ -866,14 +886,14 @@ static int perf_session__process_event(struct perf_session *session,
866 if (perf_session__preprocess_sample(session, event, &sample)) 886 if (perf_session__preprocess_sample(session, event, &sample))
867 return 0; 887 return 0;
868 888
869 if (ops->ordered_samples) { 889 if (tool->ordered_samples) {
870 ret = perf_session_queue_event(session, event, &sample, 890 ret = perf_session_queue_event(session, event, &sample,
871 file_offset); 891 file_offset);
872 if (ret != -ETIME) 892 if (ret != -ETIME)
873 return ret; 893 return ret;
874 } 894 }
875 895
876 return perf_session_deliver_event(session, event, &sample, ops, 896 return perf_session_deliver_event(session, event, &sample, tool,
877 file_offset); 897 file_offset);
878} 898}
879 899
@@ -884,6 +904,11 @@ void perf_event_header__bswap(struct perf_event_header *self)
884 self->size = bswap_16(self->size); 904 self->size = bswap_16(self->size);
885} 905}
886 906
907struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
908{
909 return machine__findnew_thread(&session->host_machine, pid);
910}
911
887static struct thread *perf_session__register_idle_thread(struct perf_session *self) 912static struct thread *perf_session__register_idle_thread(struct perf_session *self)
888{ 913{
889 struct thread *thread = perf_session__findnew(self, 0); 914 struct thread *thread = perf_session__findnew(self, 0);
@@ -897,9 +922,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
897} 922}
898 923
899static void perf_session__warn_about_errors(const struct perf_session *session, 924static void perf_session__warn_about_errors(const struct perf_session *session,
900 const struct perf_event_ops *ops) 925 const struct perf_tool *tool)
901{ 926{
902 if (ops->lost == perf_event__process_lost && 927 if (tool->lost == perf_event__process_lost &&
903 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 928 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
904 ui__warning("Processed %d events and lost %d chunks!\n\n" 929 ui__warning("Processed %d events and lost %d chunks!\n\n"
905 "Check IO/CPU overload!\n\n", 930 "Check IO/CPU overload!\n\n",
@@ -934,7 +959,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
934volatile int session_done; 959volatile int session_done;
935 960
936static int __perf_session__process_pipe_events(struct perf_session *self, 961static int __perf_session__process_pipe_events(struct perf_session *self,
937 struct perf_event_ops *ops) 962 struct perf_tool *tool)
938{ 963{
939 union perf_event event; 964 union perf_event event;
940 uint32_t size; 965 uint32_t size;
@@ -943,7 +968,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
943 int err; 968 int err;
944 void *p; 969 void *p;
945 970
946 perf_event_ops__fill_defaults(ops); 971 perf_tool__fill_defaults(tool);
947 972
948 head = 0; 973 head = 0;
949more: 974more:
@@ -980,7 +1005,7 @@ more:
980 } 1005 }
981 1006
982 if (size == 0 || 1007 if (size == 0 ||
983 (skip = perf_session__process_event(self, &event, ops, head)) < 0) { 1008 (skip = perf_session__process_event(self, &event, tool, head)) < 0) {
984 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1009 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
985 head, event.header.size, event.header.type); 1010 head, event.header.size, event.header.type);
986 /* 1011 /*
@@ -1003,7 +1028,7 @@ more:
1003done: 1028done:
1004 err = 0; 1029 err = 0;
1005out_err: 1030out_err:
1006 perf_session__warn_about_errors(self, ops); 1031 perf_session__warn_about_errors(self, tool);
1007 perf_session_free_sample_buffers(self); 1032 perf_session_free_sample_buffers(self);
1008 return err; 1033 return err;
1009} 1034}
@@ -1034,7 +1059,7 @@ fetch_mmaped_event(struct perf_session *session,
1034 1059
1035int __perf_session__process_events(struct perf_session *session, 1060int __perf_session__process_events(struct perf_session *session,
1036 u64 data_offset, u64 data_size, 1061 u64 data_offset, u64 data_size,
1037 u64 file_size, struct perf_event_ops *ops) 1062 u64 file_size, struct perf_tool *tool)
1038{ 1063{
1039 u64 head, page_offset, file_offset, file_pos, progress_next; 1064 u64 head, page_offset, file_offset, file_pos, progress_next;
1040 int err, mmap_prot, mmap_flags, map_idx = 0; 1065 int err, mmap_prot, mmap_flags, map_idx = 0;
@@ -1043,7 +1068,7 @@ int __perf_session__process_events(struct perf_session *session,
1043 union perf_event *event; 1068 union perf_event *event;
1044 uint32_t size; 1069 uint32_t size;
1045 1070
1046 perf_event_ops__fill_defaults(ops); 1071 perf_tool__fill_defaults(tool);
1047 1072
1048 page_size = sysconf(_SC_PAGESIZE); 1073 page_size = sysconf(_SC_PAGESIZE);
1049 1074
@@ -1098,7 +1123,7 @@ more:
1098 size = event->header.size; 1123 size = event->header.size;
1099 1124
1100 if (size == 0 || 1125 if (size == 0 ||
1101 perf_session__process_event(session, event, ops, file_pos) < 0) { 1126 perf_session__process_event(session, event, tool, file_pos) < 0) {
1102 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1127 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
1103 file_offset + head, event->header.size, 1128 file_offset + head, event->header.size,
1104 event->header.type); 1129 event->header.type);
@@ -1127,15 +1152,15 @@ more:
1127 err = 0; 1152 err = 0;
1128 /* do the final flush for ordered samples */ 1153 /* do the final flush for ordered samples */
1129 session->ordered_samples.next_flush = ULLONG_MAX; 1154 session->ordered_samples.next_flush = ULLONG_MAX;
1130 flush_sample_queue(session, ops); 1155 flush_sample_queue(session, tool);
1131out_err: 1156out_err:
1132 perf_session__warn_about_errors(session, ops); 1157 perf_session__warn_about_errors(session, tool);
1133 perf_session_free_sample_buffers(session); 1158 perf_session_free_sample_buffers(session);
1134 return err; 1159 return err;
1135} 1160}
1136 1161
1137int perf_session__process_events(struct perf_session *self, 1162int perf_session__process_events(struct perf_session *self,
1138 struct perf_event_ops *ops) 1163 struct perf_tool *tool)
1139{ 1164{
1140 int err; 1165 int err;
1141 1166
@@ -1146,9 +1171,9 @@ int perf_session__process_events(struct perf_session *self,
1146 err = __perf_session__process_events(self, 1171 err = __perf_session__process_events(self,
1147 self->header.data_offset, 1172 self->header.data_offset,
1148 self->header.data_size, 1173 self->header.data_size,
1149 self->size, ops); 1174 self->size, tool);
1150 else 1175 else
1151 err = __perf_session__process_pipe_events(self, ops); 1176 err = __perf_session__process_pipe_events(self, tool);
1152 1177
1153 return err; 1178 return err;
1154} 1179}
@@ -1163,9 +1188,8 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg)
1163 return true; 1188 return true;
1164} 1189}
1165 1190
1166int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, 1191int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1167 const char *symbol_name, 1192 const char *symbol_name, u64 addr)
1168 u64 addr)
1169{ 1193{
1170 char *bracket; 1194 char *bracket;
1171 enum map_type i; 1195 enum map_type i;
@@ -1224,6 +1248,27 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1224 return ret; 1248 return ret;
1225} 1249}
1226 1250
1251size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1252{
1253 /*
1254 * FIXME: Here we have to actually print all the machines in this
1255 * session, not just the host...
1256 */
1257 return machine__fprintf(&session->host_machine, fp);
1258}
1259
1260void perf_session__remove_thread(struct perf_session *session,
1261 struct thread *th)
1262{
1263 /*
1264 * FIXME: This one makes no sense, we need to remove the thread from
1265 * the machine it belongs to, perf_session can have many machines, so
1266 * doing it always on ->host_machine is wrong. Fix when auditing all
1267 * the 'perf kvm' code.
1268 */
1269 machine__remove_thread(&session->host_machine, th);
1270}
1271
1227struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1272struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1228 unsigned int type) 1273 unsigned int type)
1229{ 1274{
@@ -1236,17 +1281,16 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1236 return NULL; 1281 return NULL;
1237} 1282}
1238 1283
1239void perf_session__print_ip(union perf_event *event, 1284void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1240 struct perf_sample *sample, 1285 struct machine *machine, struct perf_evsel *evsel,
1241 struct perf_session *session, 1286 int print_sym, int print_dso)
1242 int print_sym, int print_dso)
1243{ 1287{
1244 struct addr_location al; 1288 struct addr_location al;
1245 const char *symname, *dsoname; 1289 const char *symname, *dsoname;
1246 struct callchain_cursor *cursor = &session->callchain_cursor; 1290 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
1247 struct callchain_cursor_node *node; 1291 struct callchain_cursor_node *node;
1248 1292
1249 if (perf_event__preprocess_sample(event, session, &al, sample, 1293 if (perf_event__preprocess_sample(event, machine, &al, sample,
1250 NULL) < 0) { 1294 NULL) < 0) {
1251 error("problem processing %d event, skipping it.\n", 1295 error("problem processing %d event, skipping it.\n",
1252 event->header.type); 1296 event->header.type);
@@ -1255,7 +1299,7 @@ void perf_session__print_ip(union perf_event *event,
1255 1299
1256 if (symbol_conf.use_callchain && sample->callchain) { 1300 if (symbol_conf.use_callchain && sample->callchain) {
1257 1301
1258 if (perf_session__resolve_callchain(session, al.thread, 1302 if (machine__resolve_callchain(machine, evsel, al.thread,
1259 sample->callchain, NULL) != 0) { 1303 sample->callchain, NULL) != 0) {
1260 if (verbose) 1304 if (verbose)
1261 error("Failed to resolve callchain. Skipping\n"); 1305 error("Failed to resolve callchain. Skipping\n");
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 6e393c98eb3..30e9c6b6fc3 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -30,9 +30,6 @@ struct perf_session {
30 struct perf_header header; 30 struct perf_header header;
31 unsigned long size; 31 unsigned long size;
32 unsigned long mmap_window; 32 unsigned long mmap_window;
33 struct rb_root threads;
34 struct list_head dead_threads;
35 struct thread *last_match;
36 struct machine host_machine; 33 struct machine host_machine;
37 struct rb_root machines; 34 struct rb_root machines;
38 struct perf_evlist *evlist; 35 struct perf_evlist *evlist;
@@ -53,65 +50,31 @@ struct perf_session {
53 int cwdlen; 50 int cwdlen;
54 char *cwd; 51 char *cwd;
55 struct ordered_samples ordered_samples; 52 struct ordered_samples ordered_samples;
56 struct callchain_cursor callchain_cursor;
57 char filename[0]; 53 char filename[0];
58}; 54};
59 55
60struct perf_evsel; 56struct perf_tool;
61struct perf_event_ops;
62
63typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
64 struct perf_evsel *evsel, struct perf_session *session);
65typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
66 struct perf_session *session);
67typedef int (*event_synth_op)(union perf_event *self,
68 struct perf_session *session);
69typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
70 struct perf_event_ops *ops);
71
72struct perf_event_ops {
73 event_sample sample;
74 event_op mmap,
75 comm,
76 fork,
77 exit,
78 lost,
79 read,
80 throttle,
81 unthrottle;
82 event_synth_op attr,
83 event_type,
84 tracing_data,
85 build_id;
86 event_op2 finished_round;
87 bool ordered_samples;
88 bool ordering_requires_timestamps;
89};
90 57
91struct perf_session *perf_session__new(const char *filename, int mode, 58struct perf_session *perf_session__new(const char *filename, int mode,
92 bool force, bool repipe, 59 bool force, bool repipe,
93 struct perf_event_ops *ops); 60 struct perf_tool *tool);
94void perf_session__delete(struct perf_session *self); 61void perf_session__delete(struct perf_session *self);
95 62
96void perf_event_header__bswap(struct perf_event_header *self); 63void perf_event_header__bswap(struct perf_event_header *self);
97 64
98int __perf_session__process_events(struct perf_session *self, 65int __perf_session__process_events(struct perf_session *self,
99 u64 data_offset, u64 data_size, u64 size, 66 u64 data_offset, u64 data_size, u64 size,
100 struct perf_event_ops *ops); 67 struct perf_tool *tool);
101int perf_session__process_events(struct perf_session *self, 68int perf_session__process_events(struct perf_session *self,
102 struct perf_event_ops *event_ops); 69 struct perf_tool *tool);
103 70
104int perf_session__resolve_callchain(struct perf_session *self, 71int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel,
105 struct thread *thread, 72 struct thread *thread,
106 struct ip_callchain *chain, 73 struct ip_callchain *chain,
107 struct symbol **parent); 74 struct symbol **parent);
108 75
109bool perf_session__has_traces(struct perf_session *self, const char *msg); 76bool perf_session__has_traces(struct perf_session *self, const char *msg);
110 77
111int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
112 const char *symbol_name,
113 u64 addr);
114
115void mem_bswap_64(void *src, int byte_size); 78void mem_bswap_64(void *src, int byte_size);
116void perf_event__attr_swap(struct perf_event_attr *attr); 79void perf_event__attr_swap(struct perf_event_attr *attr);
117 80
@@ -144,12 +107,16 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p
144 107
145static inline 108static inline
146void perf_session__process_machines(struct perf_session *self, 109void perf_session__process_machines(struct perf_session *self,
110 struct perf_tool *tool,
147 machine__process_t process) 111 machine__process_t process)
148{ 112{
149 process(&self->host_machine, self); 113 process(&self->host_machine, tool);
150 return machines__process(&self->machines, process, self); 114 return machines__process(&self->machines, process, tool);
151} 115}
152 116
117struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
118size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
119
153size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 120size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
154 121
155size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 122size_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,
170struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 137struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
171 unsigned int type); 138 unsigned int type);
172 139
173void perf_session__print_ip(union perf_event *event, 140void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
174 struct perf_sample *sample, 141 struct machine *machine, struct perf_evsel *evsel,
175 struct perf_session *session, 142 int print_sym, int print_dso);
176 int print_sym, int print_dso);
177 143
178int perf_session__cpu_bitmap(struct perf_session *session, 144int perf_session__cpu_bitmap(struct perf_session *session,
179 const char *cpu_list, unsigned long *cpu_bitmap); 145 const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 95d37007492..36d4c561957 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -27,7 +27,8 @@ build_tmp = getenv('PYTHON_EXTBUILD_TMP')
27perf = Extension('perf', 27perf = Extension('perf',
28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', 29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], 30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c',
31 'util/debugfs.c'],
31 include_dirs = ['util/include'], 32 include_dirs = ['util/include'],
32 extra_compile_args = cflags, 33 extra_compile_args = cflags,
33 ) 34 )
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 29f8d742e92..123c2e14353 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -68,6 +68,7 @@ struct strlist;
68 68
69struct symbol_conf { 69struct symbol_conf {
70 unsigned short priv_size; 70 unsigned short priv_size;
71 unsigned short nr_events;
71 bool try_vmlinux_path, 72 bool try_vmlinux_path,
72 use_modules, 73 use_modules,
73 sort_by_name, 74 sort_by_name,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index d5d3b22250f..fb4b7ea6752 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -61,7 +61,7 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
61 map_groups__fprintf(&self->mg, verbose, fp); 61 map_groups__fprintf(&self->mg, verbose, fp);
62} 62}
63 63
64struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) 64struct thread *machine__findnew_thread(struct machine *self, pid_t pid)
65{ 65{
66 struct rb_node **p = &self->threads.rb_node; 66 struct rb_node **p = &self->threads.rb_node;
67 struct rb_node *parent = NULL; 67 struct rb_node *parent = NULL;
@@ -125,12 +125,12 @@ int thread__fork(struct thread *self, struct thread *parent)
125 return 0; 125 return 0;
126} 126}
127 127
128size_t perf_session__fprintf(struct perf_session *self, FILE *fp) 128size_t machine__fprintf(struct machine *machine, FILE *fp)
129{ 129{
130 size_t ret = 0; 130 size_t ret = 0;
131 struct rb_node *nd; 131 struct rb_node *nd;
132 132
133 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) { 133 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
134 struct thread *pos = rb_entry(nd, struct thread, rb_node); 134 struct thread *pos = rb_entry(nd, struct thread, rb_node);
135 135
136 ret += thread__fprintf(pos, fp); 136 ret += thread__fprintf(pos, fp);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index e5f2401c1b5..70c2c13ff67 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -18,16 +18,14 @@ struct thread {
18 int comm_len; 18 int comm_len;
19}; 19};
20 20
21struct perf_session; 21struct machine;
22 22
23void thread__delete(struct thread *self); 23void thread__delete(struct thread *self);
24 24
25int thread__set_comm(struct thread *self, const char *comm); 25int thread__set_comm(struct thread *self, const char *comm);
26int thread__comm_len(struct thread *self); 26int thread__comm_len(struct thread *self);
27struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
28void thread__insert_map(struct thread *self, struct map *map); 27void thread__insert_map(struct thread *self, struct map *map);
29int thread__fork(struct thread *self, struct thread *parent); 28int thread__fork(struct thread *self, struct thread *parent);
30size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
31 29
32static inline struct map *thread__find_map(struct thread *self, 30static inline struct map *thread__find_map(struct thread *self,
33 enum map_type type, u64 addr) 31 enum map_type type, u64 addr)
@@ -35,14 +33,12 @@ static inline struct map *thread__find_map(struct thread *self,
35 return self ? map_groups__find(&self->mg, type, addr) : NULL; 33 return self ? map_groups__find(&self->mg, type, addr) : NULL;
36} 34}
37 35
38void thread__find_addr_map(struct thread *self, 36void thread__find_addr_map(struct thread *thread, struct machine *machine,
39 struct perf_session *session, u8 cpumode, 37 u8 cpumode, enum map_type type, u64 addr,
40 enum map_type type, pid_t pid, u64 addr,
41 struct addr_location *al); 38 struct addr_location *al);
42 39
43void thread__find_addr_location(struct thread *self, 40void thread__find_addr_location(struct thread *thread, struct machine *machine,
44 struct perf_session *session, u8 cpumode, 41 u8 cpumode, enum map_type type, u64 addr,
45 enum map_type type, pid_t pid, u64 addr,
46 struct addr_location *al, 42 struct addr_location *al,
47 symbol_filter_t filter); 43 symbol_filter_t filter);
48#endif /* __PERF_THREAD_H */ 44#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
new file mode 100644
index 00000000000..b0e1aadba8d
--- /dev/null
+++ b/tools/perf/util/tool.h
@@ -0,0 +1,50 @@
1#ifndef __PERF_TOOL_H
2#define __PERF_TOOL_H
3
4#include <stdbool.h>
5
6struct perf_session;
7union perf_event;
8struct perf_evlist;
9struct perf_evsel;
10struct perf_sample;
11struct perf_tool;
12struct machine;
13
14typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
15 struct perf_sample *sample,
16 struct perf_evsel *evsel, struct machine *machine);
17
18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
19 struct perf_sample *sample, struct machine *machine);
20
21typedef int (*event_attr_op)(union perf_event *event,
22 struct perf_evlist **pevlist);
23typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
24
25typedef int (*event_synth_op)(union perf_event *event,
26 struct perf_session *session);
27
28typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
29 struct perf_session *session);
30
31struct perf_tool {
32 event_sample sample,
33 read;
34 event_op mmap,
35 comm,
36 fork,
37 exit,
38 lost,
39 throttle,
40 unthrottle;
41 event_attr_op attr;
42 event_synth_op tracing_data;
43 event_simple_op event_type;
44 event_op2 finished_round,
45 build_id;
46 bool ordered_samples;
47 bool ordering_requires_timestamps;
48};
49
50#endif /* __PERF_TOOL_H */
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 39965096795..a248f3c2c60 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -1,15 +1,17 @@
1#ifndef __PERF_TOP_H 1#ifndef __PERF_TOP_H
2#define __PERF_TOP_H 1 2#define __PERF_TOP_H 1
3 3
4#include "tool.h"
4#include "types.h" 5#include "types.h"
5#include "../perf.h"
6#include <stddef.h> 6#include <stddef.h>
7#include <stdbool.h>
7 8
8struct perf_evlist; 9struct perf_evlist;
9struct perf_evsel; 10struct perf_evsel;
10struct perf_session; 11struct perf_session;
11 12
12struct perf_top { 13struct perf_top {
14 struct perf_tool tool;
13 struct perf_evlist *evlist; 15 struct perf_evlist *evlist;
14 /* 16 /*
15 * Symbols will be added here in perf_event__process_sample and will 17 * Symbols will be added here in perf_event__process_sample and will
@@ -23,10 +25,26 @@ struct perf_top {
23 int freq; 25 int freq;
24 pid_t target_pid, target_tid; 26 pid_t target_pid, target_tid;
25 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool system_wide;
29 bool use_tui, use_stdio;
30 bool sort_has_symbols;
31 bool dont_use_callchains;
32 bool kptr_restrict_warned;
33 bool vmlinux_warned;
34 bool inherit;
35 bool group;
36 bool sample_id_all_avail;
37 bool dump_symtab;
26 const char *cpu_list; 38 const char *cpu_list;
27 struct hist_entry *sym_filter_entry; 39 struct hist_entry *sym_filter_entry;
28 struct perf_evsel *sym_evsel; 40 struct perf_evsel *sym_evsel;
29 struct perf_session *session; 41 struct perf_session *session;
42 struct winsize winsize;
43 unsigned int mmap_pages;
44 int default_interval;
45 int realtime_prio;
46 int sym_pcnt_filter;
47 const char *sym_filter;
30}; 48};
31 49
32size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index d2655f08bcc..ac6830d8292 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -18,7 +18,8 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _GNU_SOURCE 21#include <ctype.h>
22#include "util.h"
22#include <dirent.h> 23#include <dirent.h>
23#include <mntent.h> 24#include <mntent.h>
24#include <stdio.h> 25#include <stdio.h>
@@ -31,7 +32,6 @@
31#include <pthread.h> 32#include <pthread.h>
32#include <fcntl.h> 33#include <fcntl.h>
33#include <unistd.h> 34#include <unistd.h>
34#include <ctype.h>
35#include <errno.h> 35#include <errno.h>
36#include <stdbool.h> 36#include <stdbool.h>
37#include <linux/list.h> 37#include <linux/list.h>
@@ -44,10 +44,6 @@
44 44
45#define VERSION "0.5" 45#define VERSION "0.5"
46 46
47#define _STR(x) #x
48#define STR(x) _STR(x)
49#define MAX_PATH 256
50
51#define TRACE_CTRL "tracing_on" 47#define TRACE_CTRL "tracing_on"
52#define TRACE "trace" 48#define TRACE "trace"
53#define AVAILABLE "available_tracers" 49#define AVAILABLE "available_tracers"
@@ -73,26 +69,6 @@ struct events {
73}; 69};
74 70
75 71
76
77static void die(const char *fmt, ...)
78{
79 va_list ap;
80 int ret = errno;
81
82 if (errno)
83 perror("perf");
84 else
85 ret = -1;
86
87 va_start(ap, fmt);
88 fprintf(stderr, " ");
89 vfprintf(stderr, fmt, ap);
90 va_end(ap);
91
92 fprintf(stderr, "\n");
93 exit(ret);
94}
95
96void *malloc_or_die(unsigned int size) 72void *malloc_or_die(unsigned int size)
97{ 73{
98 void *data; 74 void *data;
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index c9dcbec7d80..a3fdf55f317 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -39,7 +39,7 @@ static int stop_script_unsupported(void)
39static void process_event_unsupported(union perf_event *event __unused, 39static void process_event_unsupported(union perf_event *event __unused,
40 struct perf_sample *sample __unused, 40 struct perf_sample *sample __unused,
41 struct perf_evsel *evsel __unused, 41 struct perf_evsel *evsel __unused,
42 struct perf_session *session __unused, 42 struct machine *machine __unused,
43 struct thread *thread __unused) 43 struct thread *thread __unused)
44{ 44{
45} 45}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index a8410081764..58ae14c5baa 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,7 +3,11 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "parse-events.h" 5#include "parse-events.h"
6#include "session.h" 6
7struct machine;
8struct perf_sample;
9union perf_event;
10struct thread;
7 11
8#define __unused __attribute__((unused)) 12#define __unused __attribute__((unused))
9 13
@@ -292,7 +296,7 @@ struct scripting_ops {
292 void (*process_event) (union perf_event *event, 296 void (*process_event) (union perf_event *event,
293 struct perf_sample *sample, 297 struct perf_sample *sample,
294 struct perf_evsel *evsel, 298 struct perf_evsel *evsel,
295 struct perf_session *session, 299 struct machine *machine,
296 struct thread *thread); 300 struct thread *thread);
297 int (*generate_script) (const char *outfile); 301 int (*generate_script) (const char *outfile);
298}; 302};
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 0575905d120..295a9c93f94 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -224,7 +224,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser)
224} 224}
225 225
226static int annotate_browser__run(struct annotate_browser *self, int evidx, 226static int annotate_browser__run(struct annotate_browser *self, int evidx,
227 int nr_events, void(*timer)(void *arg), 227 void(*timer)(void *arg),
228 void *arg, int delay_secs) 228 void *arg, int delay_secs)
229{ 229{
230 struct rb_node *nd = NULL; 230 struct rb_node *nd = NULL;
@@ -328,8 +328,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
328 notes = symbol__annotation(target); 328 notes = symbol__annotation(target);
329 pthread_mutex_lock(&notes->lock); 329 pthread_mutex_lock(&notes->lock);
330 330
331 if (notes->src == NULL && 331 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
332 symbol__alloc_hist(target, nr_events) < 0) {
333 pthread_mutex_unlock(&notes->lock); 332 pthread_mutex_unlock(&notes->lock);
334 ui__warning("Not enough memory for annotating '%s' symbol!\n", 333 ui__warning("Not enough memory for annotating '%s' symbol!\n",
335 target->name); 334 target->name);
@@ -337,7 +336,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
337 } 336 }
338 337
339 pthread_mutex_unlock(&notes->lock); 338 pthread_mutex_unlock(&notes->lock);
340 symbol__tui_annotate(target, ms->map, evidx, nr_events, 339 symbol__tui_annotate(target, ms->map, evidx,
341 timer, arg, delay_secs); 340 timer, arg, delay_secs);
342 } 341 }
343 continue; 342 continue;
@@ -358,15 +357,15 @@ out:
358 return key; 357 return key;
359} 358}
360 359
361int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, 360int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
362 void(*timer)(void *arg), void *arg, int delay_secs) 361 void(*timer)(void *arg), void *arg, int delay_secs)
363{ 362{
364 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events, 363 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
365 timer, arg, delay_secs); 364 timer, arg, delay_secs);
366} 365}
367 366
368int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 367int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
369 int nr_events, void(*timer)(void *arg), void *arg, 368 void(*timer)(void *arg), void *arg,
370 int delay_secs) 369 int delay_secs)
371{ 370{
372 struct objdump_line *pos, *n; 371 struct objdump_line *pos, *n;
@@ -419,8 +418,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
419 browser.b.nr_entries = browser.nr_entries; 418 browser.b.nr_entries = browser.nr_entries;
420 browser.b.entries = &notes->src->source, 419 browser.b.entries = &notes->src->source,
421 browser.b.width += 18; /* Percentage */ 420 browser.b.width += 18; /* Percentage */
422 ret = annotate_browser__run(&browser, evidx, nr_events, 421 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
423 timer, arg, delay_secs);
424 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 422 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
425 list_del(&pos->node); 423 list_del(&pos->node);
426 objdump_line__free(pos); 424 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index d0c94b45968..1212a386a03 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -1020,7 +1020,7 @@ do_annotate:
1020 * Don't let this be freed, say, by hists__decay_entry. 1020 * Don't let this be freed, say, by hists__decay_entry.
1021 */ 1021 */
1022 he->used = true; 1022 he->used = true;
1023 err = hist_entry__tui_annotate(he, evsel->idx, nr_events, 1023 err = hist_entry__tui_annotate(he, evsel->idx,
1024 timer, arg, delay_secs); 1024 timer, arg, delay_secs);
1025 he->used = false; 1025 he->used = false;
1026 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1026 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c
index 295e366b631..13aa64e50e1 100644
--- a/tools/perf/util/ui/progress.c
+++ b/tools/perf/util/ui/progress.c
@@ -14,6 +14,9 @@ void ui_progress__update(u64 curr, u64 total, const char *title)
14 if (use_browser <= 0) 14 if (use_browser <= 0)
15 return; 15 return;
16 16
17 if (total == 0)
18 return;
19
17 ui__refresh_dimensions(true); 20 ui__refresh_dimensions(true);
18 pthread_mutex_lock(&ui__lock); 21 pthread_mutex_lock(&ui__lock);
19 y = SLtt_Screen_Rows / 2 - 2; 22 y = SLtt_Screen_Rows / 2 - 2;