diff options
author | Ingo Molnar <mingo@elte.hu> | 2012-01-27 06:07:57 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-01-27 06:08:09 -0500 |
commit | 44a683971119bafb5bc30778f92ee773680ebb6f (patch) | |
tree | 58648459f29d45c447bd2352e81844d4d9aa3a15 | |
parent | 801493c2e249a7314e9e8e54ad60d613d0a86f14 (diff) | |
parent | 08aa0d1f376e9b966568316bd2019b3c1274d885 (diff) |
Merge branch 'perf/fast' into perf/core
Merge reason: Lets ready it for v3.4
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/arm/include/asm/perf_event.h | 4 | ||||
-rw-r--r-- | arch/frv/include/asm/perf_event.h | 2 | ||||
-rw-r--r-- | arch/hexagon/include/asm/perf_event.h | 2 | ||||
-rw-r--r-- | arch/powerpc/include/asm/perf_event_server.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/perf_event.c | 6 | ||||
-rw-r--r-- | arch/s390/include/asm/perf_event.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/perf_event.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 82 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.h | 8 | ||||
-rw-r--r-- | include/linux/perf_event.h | 11 | ||||
-rw-r--r-- | kernel/events/core.c | 53 | ||||
-rw-r--r-- | kernel/events/hw_breakpoint.c | 7 | ||||
-rw-r--r-- | tools/perf/builtin-test.c | 177 |
13 files changed, 328 insertions, 29 deletions
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index 99cfe3607989..7523340afb8a 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h | |||
@@ -12,10 +12,6 @@ | |||
12 | #ifndef __ARM_PERF_EVENT_H__ | 12 | #ifndef __ARM_PERF_EVENT_H__ |
13 | #define __ARM_PERF_EVENT_H__ | 13 | #define __ARM_PERF_EVENT_H__ |
14 | 14 | ||
15 | /* ARM performance counters start from 1 (in the cp15 accesses) so use the | ||
16 | * same indexes here for consistency. */ | ||
17 | #define PERF_EVENT_INDEX_OFFSET 1 | ||
18 | |||
19 | /* ARM perf PMU IDs for use by internal perf clients. */ | 15 | /* ARM perf PMU IDs for use by internal perf clients. */ |
20 | enum arm_perf_pmu_ids { | 16 | enum arm_perf_pmu_ids { |
21 | ARM_PERF_PMU_ID_XSCALE1 = 0, | 17 | ARM_PERF_PMU_ID_XSCALE1 = 0, |
diff --git a/arch/frv/include/asm/perf_event.h b/arch/frv/include/asm/perf_event.h index a69e0155d146..c52ea5546b5b 100644 --- a/arch/frv/include/asm/perf_event.h +++ b/arch/frv/include/asm/perf_event.h | |||
@@ -12,6 +12,4 @@ | |||
12 | #ifndef _ASM_PERF_EVENT_H | 12 | #ifndef _ASM_PERF_EVENT_H |
13 | #define _ASM_PERF_EVENT_H | 13 | #define _ASM_PERF_EVENT_H |
14 | 14 | ||
15 | #define PERF_EVENT_INDEX_OFFSET 0 | ||
16 | |||
17 | #endif /* _ASM_PERF_EVENT_H */ | 15 | #endif /* _ASM_PERF_EVENT_H */ |
diff --git a/arch/hexagon/include/asm/perf_event.h b/arch/hexagon/include/asm/perf_event.h index 6c2910f91180..8b8526b491c7 100644 --- a/arch/hexagon/include/asm/perf_event.h +++ b/arch/hexagon/include/asm/perf_event.h | |||
@@ -19,6 +19,4 @@ | |||
19 | #ifndef _ASM_PERF_EVENT_H | 19 | #ifndef _ASM_PERF_EVENT_H |
20 | #define _ASM_PERF_EVENT_H | 20 | #define _ASM_PERF_EVENT_H |
21 | 21 | ||
22 | #define PERF_EVENT_INDEX_OFFSET 0 | ||
23 | |||
24 | #endif /* _ASM_PERF_EVENT_H */ | 22 | #endif /* _ASM_PERF_EVENT_H */ |
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index 8f1df1208d23..1a8093fa8f71 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h | |||
@@ -61,8 +61,6 @@ struct pt_regs; | |||
61 | extern unsigned long perf_misc_flags(struct pt_regs *regs); | 61 | extern unsigned long perf_misc_flags(struct pt_regs *regs); |
62 | extern unsigned long perf_instruction_pointer(struct pt_regs *regs); | 62 | extern unsigned long perf_instruction_pointer(struct pt_regs *regs); |
63 | 63 | ||
64 | #define PERF_EVENT_INDEX_OFFSET 1 | ||
65 | |||
66 | /* | 64 | /* |
67 | * Only override the default definitions in include/linux/perf_event.h | 65 | * Only override the default definitions in include/linux/perf_event.h |
68 | * if we have hardware PMU support. | 66 | * if we have hardware PMU support. |
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c index 10a140f82cb8..d614ab57ccca 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/kernel/perf_event.c | |||
@@ -1187,6 +1187,11 @@ static int power_pmu_event_init(struct perf_event *event) | |||
1187 | return err; | 1187 | return err; |
1188 | } | 1188 | } |
1189 | 1189 | ||
1190 | static int power_pmu_event_idx(struct perf_event *event) | ||
1191 | { | ||
1192 | return event->hw.idx; | ||
1193 | } | ||
1194 | |||
1190 | struct pmu power_pmu = { | 1195 | struct pmu power_pmu = { |
1191 | .pmu_enable = power_pmu_enable, | 1196 | .pmu_enable = power_pmu_enable, |
1192 | .pmu_disable = power_pmu_disable, | 1197 | .pmu_disable = power_pmu_disable, |
@@ -1199,6 +1204,7 @@ struct pmu power_pmu = { | |||
1199 | .start_txn = power_pmu_start_txn, | 1204 | .start_txn = power_pmu_start_txn, |
1200 | .cancel_txn = power_pmu_cancel_txn, | 1205 | .cancel_txn = power_pmu_cancel_txn, |
1201 | .commit_txn = power_pmu_commit_txn, | 1206 | .commit_txn = power_pmu_commit_txn, |
1207 | .event_idx = power_pmu_event_idx, | ||
1202 | }; | 1208 | }; |
1203 | 1209 | ||
1204 | /* | 1210 | /* |
diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h index a75f168d2718..4eb444edbe49 100644 --- a/arch/s390/include/asm/perf_event.h +++ b/arch/s390/include/asm/perf_event.h | |||
@@ -6,4 +6,3 @@ | |||
6 | 6 | ||
7 | /* Empty, just to avoid compiling error */ | 7 | /* Empty, just to avoid compiling error */ |
8 | 8 | ||
9 | #define PERF_EVENT_INDEX_OFFSET 0 | ||
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 096c975e099f..9b922c136254 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h | |||
@@ -188,8 +188,6 @@ extern u32 get_ibs_caps(void); | |||
188 | #ifdef CONFIG_PERF_EVENTS | 188 | #ifdef CONFIG_PERF_EVENTS |
189 | extern void perf_events_lapic_init(void); | 189 | extern void perf_events_lapic_init(void); |
190 | 190 | ||
191 | #define PERF_EVENT_INDEX_OFFSET 0 | ||
192 | |||
193 | /* | 191 | /* |
194 | * Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups. | 192 | * Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups. |
195 | * This flag is otherwise unused and ABI specified to be 0, so nobody should | 193 | * This flag is otherwise unused and ABI specified to be 0, so nobody should |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 5adce1040b11..f8bddb5b0600 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/cpu.h> | 25 | #include <linux/cpu.h> |
26 | #include <linux/bitops.h> | 26 | #include <linux/bitops.h> |
27 | #include <linux/device.h> | ||
27 | 28 | ||
28 | #include <asm/apic.h> | 29 | #include <asm/apic.h> |
29 | #include <asm/stacktrace.h> | 30 | #include <asm/stacktrace.h> |
@@ -31,6 +32,7 @@ | |||
31 | #include <asm/compat.h> | 32 | #include <asm/compat.h> |
32 | #include <asm/smp.h> | 33 | #include <asm/smp.h> |
33 | #include <asm/alternative.h> | 34 | #include <asm/alternative.h> |
35 | #include <asm/timer.h> | ||
34 | 36 | ||
35 | #include "perf_event.h" | 37 | #include "perf_event.h" |
36 | 38 | ||
@@ -1210,6 +1212,8 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) | |||
1210 | break; | 1212 | break; |
1211 | 1213 | ||
1212 | case CPU_STARTING: | 1214 | case CPU_STARTING: |
1215 | if (x86_pmu.attr_rdpmc) | ||
1216 | set_in_cr4(X86_CR4_PCE); | ||
1213 | if (x86_pmu.cpu_starting) | 1217 | if (x86_pmu.cpu_starting) |
1214 | x86_pmu.cpu_starting(cpu); | 1218 | x86_pmu.cpu_starting(cpu); |
1215 | break; | 1219 | break; |
@@ -1319,6 +1323,8 @@ static int __init init_hw_perf_events(void) | |||
1319 | } | 1323 | } |
1320 | } | 1324 | } |
1321 | 1325 | ||
1326 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ | ||
1327 | |||
1322 | pr_info("... version: %d\n", x86_pmu.version); | 1328 | pr_info("... version: %d\n", x86_pmu.version); |
1323 | pr_info("... bit width: %d\n", x86_pmu.cntval_bits); | 1329 | pr_info("... bit width: %d\n", x86_pmu.cntval_bits); |
1324 | pr_info("... generic registers: %d\n", x86_pmu.num_counters); | 1330 | pr_info("... generic registers: %d\n", x86_pmu.num_counters); |
@@ -1542,10 +1548,71 @@ static int x86_pmu_event_init(struct perf_event *event) | |||
1542 | return err; | 1548 | return err; |
1543 | } | 1549 | } |
1544 | 1550 | ||
1551 | static int x86_pmu_event_idx(struct perf_event *event) | ||
1552 | { | ||
1553 | int idx = event->hw.idx; | ||
1554 | |||
1555 | if (x86_pmu.num_counters_fixed && idx >= X86_PMC_IDX_FIXED) { | ||
1556 | idx -= X86_PMC_IDX_FIXED; | ||
1557 | idx |= 1 << 30; | ||
1558 | } | ||
1559 | |||
1560 | return idx + 1; | ||
1561 | } | ||
1562 | |||
1563 | static ssize_t get_attr_rdpmc(struct device *cdev, | ||
1564 | struct device_attribute *attr, | ||
1565 | char *buf) | ||
1566 | { | ||
1567 | return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc); | ||
1568 | } | ||
1569 | |||
1570 | static void change_rdpmc(void *info) | ||
1571 | { | ||
1572 | bool enable = !!(unsigned long)info; | ||
1573 | |||
1574 | if (enable) | ||
1575 | set_in_cr4(X86_CR4_PCE); | ||
1576 | else | ||
1577 | clear_in_cr4(X86_CR4_PCE); | ||
1578 | } | ||
1579 | |||
1580 | static ssize_t set_attr_rdpmc(struct device *cdev, | ||
1581 | struct device_attribute *attr, | ||
1582 | const char *buf, size_t count) | ||
1583 | { | ||
1584 | unsigned long val = simple_strtoul(buf, NULL, 0); | ||
1585 | |||
1586 | if (!!val != !!x86_pmu.attr_rdpmc) { | ||
1587 | x86_pmu.attr_rdpmc = !!val; | ||
1588 | smp_call_function(change_rdpmc, (void *)val, 1); | ||
1589 | } | ||
1590 | |||
1591 | return count; | ||
1592 | } | ||
1593 | |||
1594 | static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc); | ||
1595 | |||
1596 | static struct attribute *x86_pmu_attrs[] = { | ||
1597 | &dev_attr_rdpmc.attr, | ||
1598 | NULL, | ||
1599 | }; | ||
1600 | |||
1601 | static struct attribute_group x86_pmu_attr_group = { | ||
1602 | .attrs = x86_pmu_attrs, | ||
1603 | }; | ||
1604 | |||
1605 | static const struct attribute_group *x86_pmu_attr_groups[] = { | ||
1606 | &x86_pmu_attr_group, | ||
1607 | NULL, | ||
1608 | }; | ||
1609 | |||
1545 | static struct pmu pmu = { | 1610 | static struct pmu pmu = { |
1546 | .pmu_enable = x86_pmu_enable, | 1611 | .pmu_enable = x86_pmu_enable, |
1547 | .pmu_disable = x86_pmu_disable, | 1612 | .pmu_disable = x86_pmu_disable, |
1548 | 1613 | ||
1614 | .attr_groups = x86_pmu_attr_groups, | ||
1615 | |||
1549 | .event_init = x86_pmu_event_init, | 1616 | .event_init = x86_pmu_event_init, |
1550 | 1617 | ||
1551 | .add = x86_pmu_add, | 1618 | .add = x86_pmu_add, |
@@ -1557,8 +1624,23 @@ static struct pmu pmu = { | |||
1557 | .start_txn = x86_pmu_start_txn, | 1624 | .start_txn = x86_pmu_start_txn, |
1558 | .cancel_txn = x86_pmu_cancel_txn, | 1625 | .cancel_txn = x86_pmu_cancel_txn, |
1559 | .commit_txn = x86_pmu_commit_txn, | 1626 | .commit_txn = x86_pmu_commit_txn, |
1627 | |||
1628 | .event_idx = x86_pmu_event_idx, | ||
1560 | }; | 1629 | }; |
1561 | 1630 | ||
1631 | void perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now) | ||
1632 | { | ||
1633 | if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) | ||
1634 | return; | ||
1635 | |||
1636 | if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) | ||
1637 | return; | ||
1638 | |||
1639 | userpg->time_mult = this_cpu_read(cyc2ns); | ||
1640 | userpg->time_shift = CYC2NS_SCALE_FACTOR; | ||
1641 | userpg->time_offset = this_cpu_read(cyc2ns_offset) - now; | ||
1642 | } | ||
1643 | |||
1562 | /* | 1644 | /* |
1563 | * callchain support | 1645 | * callchain support |
1564 | */ | 1646 | */ |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 8944062f46e2..513d617b93c4 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -307,6 +307,14 @@ struct x86_pmu { | |||
307 | struct x86_pmu_quirk *quirks; | 307 | struct x86_pmu_quirk *quirks; |
308 | int perfctr_second_write; | 308 | int perfctr_second_write; |
309 | 309 | ||
310 | /* | ||
311 | * sysfs attrs | ||
312 | */ | ||
313 | int attr_rdpmc; | ||
314 | |||
315 | /* | ||
316 | * CPU Hotplug hooks | ||
317 | */ | ||
310 | int (*cpu_prepare)(int cpu); | 318 | int (*cpu_prepare)(int cpu); |
311 | void (*cpu_starting)(int cpu); | 319 | void (*cpu_starting)(int cpu); |
312 | void (*cpu_dying)(int cpu); | 320 | void (*cpu_dying)(int cpu); |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 08855613ceb3..0b91db2522cc 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -291,12 +291,14 @@ struct perf_event_mmap_page { | |||
291 | __s64 offset; /* add to hardware event value */ | 291 | __s64 offset; /* add to hardware event value */ |
292 | __u64 time_enabled; /* time event active */ | 292 | __u64 time_enabled; /* time event active */ |
293 | __u64 time_running; /* time event on cpu */ | 293 | __u64 time_running; /* time event on cpu */ |
294 | __u32 time_mult, time_shift; | ||
295 | __u64 time_offset; | ||
294 | 296 | ||
295 | /* | 297 | /* |
296 | * Hole for extension of the self monitor capabilities | 298 | * Hole for extension of the self monitor capabilities |
297 | */ | 299 | */ |
298 | 300 | ||
299 | __u64 __reserved[123]; /* align to 1k */ | 301 | __u64 __reserved[121]; /* align to 1k */ |
300 | 302 | ||
301 | /* | 303 | /* |
302 | * Control data for the mmap() data buffer. | 304 | * Control data for the mmap() data buffer. |
@@ -615,6 +617,7 @@ struct pmu { | |||
615 | struct list_head entry; | 617 | struct list_head entry; |
616 | 618 | ||
617 | struct device *dev; | 619 | struct device *dev; |
620 | const struct attribute_group **attr_groups; | ||
618 | char *name; | 621 | char *name; |
619 | int type; | 622 | int type; |
620 | 623 | ||
@@ -680,6 +683,12 @@ struct pmu { | |||
680 | * for each successful ->add() during the transaction. | 683 | * for each successful ->add() during the transaction. |
681 | */ | 684 | */ |
682 | void (*cancel_txn) (struct pmu *pmu); /* optional */ | 685 | void (*cancel_txn) (struct pmu *pmu); /* optional */ |
686 | |||
687 | /* | ||
688 | * Will return the value for perf_event_mmap_page::index for this event, | ||
689 | * if no implementation is provided it will default to: event->hw.idx + 1. | ||
690 | */ | ||
691 | int (*event_idx) (struct perf_event *event); /*optional */ | ||
683 | }; | 692 | }; |
684 | 693 | ||
685 | /** | 694 | /** |
diff --git a/kernel/events/core.c b/kernel/events/core.c index 32b48c889711..de859fb4038f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -3208,10 +3208,6 @@ int perf_event_task_disable(void) | |||
3208 | return 0; | 3208 | return 0; |
3209 | } | 3209 | } |
3210 | 3210 | ||
3211 | #ifndef PERF_EVENT_INDEX_OFFSET | ||
3212 | # define PERF_EVENT_INDEX_OFFSET 0 | ||
3213 | #endif | ||
3214 | |||
3215 | static int perf_event_index(struct perf_event *event) | 3211 | static int perf_event_index(struct perf_event *event) |
3216 | { | 3212 | { |
3217 | if (event->hw.state & PERF_HES_STOPPED) | 3213 | if (event->hw.state & PERF_HES_STOPPED) |
@@ -3220,21 +3216,26 @@ static int perf_event_index(struct perf_event *event) | |||
3220 | if (event->state != PERF_EVENT_STATE_ACTIVE) | 3216 | if (event->state != PERF_EVENT_STATE_ACTIVE) |
3221 | return 0; | 3217 | return 0; |
3222 | 3218 | ||
3223 | return event->hw.idx + 1 - PERF_EVENT_INDEX_OFFSET; | 3219 | return event->pmu->event_idx(event); |
3224 | } | 3220 | } |
3225 | 3221 | ||
3226 | static void calc_timer_values(struct perf_event *event, | 3222 | static void calc_timer_values(struct perf_event *event, |
3223 | u64 *now, | ||
3227 | u64 *enabled, | 3224 | u64 *enabled, |
3228 | u64 *running) | 3225 | u64 *running) |
3229 | { | 3226 | { |
3230 | u64 now, ctx_time; | 3227 | u64 ctx_time; |
3231 | 3228 | ||
3232 | now = perf_clock(); | 3229 | *now = perf_clock(); |
3233 | ctx_time = event->shadow_ctx_time + now; | 3230 | ctx_time = event->shadow_ctx_time + *now; |
3234 | *enabled = ctx_time - event->tstamp_enabled; | 3231 | *enabled = ctx_time - event->tstamp_enabled; |
3235 | *running = ctx_time - event->tstamp_running; | 3232 | *running = ctx_time - event->tstamp_running; |
3236 | } | 3233 | } |
3237 | 3234 | ||
3235 | void __weak perf_update_user_clock(struct perf_event_mmap_page *userpg, u64 now) | ||
3236 | { | ||
3237 | } | ||
3238 | |||
3238 | /* | 3239 | /* |
3239 | * Callers need to ensure there can be no nesting of this function, otherwise | 3240 | * Callers need to ensure there can be no nesting of this function, otherwise |
3240 | * the seqlock logic goes bad. We can not serialize this because the arch | 3241 | * the seqlock logic goes bad. We can not serialize this because the arch |
@@ -3244,7 +3245,7 @@ void perf_event_update_userpage(struct perf_event *event) | |||
3244 | { | 3245 | { |
3245 | struct perf_event_mmap_page *userpg; | 3246 | struct perf_event_mmap_page *userpg; |
3246 | struct ring_buffer *rb; | 3247 | struct ring_buffer *rb; |
3247 | u64 enabled, running; | 3248 | u64 enabled, running, now; |
3248 | 3249 | ||
3249 | rcu_read_lock(); | 3250 | rcu_read_lock(); |
3250 | /* | 3251 | /* |
@@ -3256,7 +3257,7 @@ void perf_event_update_userpage(struct perf_event *event) | |||
3256 | * because of locking issue as we can be called in | 3257 | * because of locking issue as we can be called in |
3257 | * NMI context | 3258 | * NMI context |
3258 | */ | 3259 | */ |
3259 | calc_timer_values(event, &enabled, &running); | 3260 | calc_timer_values(event, &now, &enabled, &running); |
3260 | rb = rcu_dereference(event->rb); | 3261 | rb = rcu_dereference(event->rb); |
3261 | if (!rb) | 3262 | if (!rb) |
3262 | goto unlock; | 3263 | goto unlock; |
@@ -3272,7 +3273,7 @@ void perf_event_update_userpage(struct perf_event *event) | |||
3272 | barrier(); | 3273 | barrier(); |
3273 | userpg->index = perf_event_index(event); | 3274 | userpg->index = perf_event_index(event); |
3274 | userpg->offset = perf_event_count(event); | 3275 | userpg->offset = perf_event_count(event); |
3275 | if (event->state == PERF_EVENT_STATE_ACTIVE) | 3276 | if (userpg->index) |
3276 | userpg->offset -= local64_read(&event->hw.prev_count); | 3277 | userpg->offset -= local64_read(&event->hw.prev_count); |
3277 | 3278 | ||
3278 | userpg->time_enabled = enabled + | 3279 | userpg->time_enabled = enabled + |
@@ -3281,6 +3282,8 @@ void perf_event_update_userpage(struct perf_event *event) | |||
3281 | userpg->time_running = running + | 3282 | userpg->time_running = running + |
3282 | atomic64_read(&event->child_total_time_running); | 3283 | atomic64_read(&event->child_total_time_running); |
3283 | 3284 | ||
3285 | perf_update_user_clock(userpg, now); | ||
3286 | |||
3284 | barrier(); | 3287 | barrier(); |
3285 | ++userpg->lock; | 3288 | ++userpg->lock; |
3286 | preempt_enable(); | 3289 | preempt_enable(); |
@@ -3538,6 +3541,8 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) | |||
3538 | event->mmap_user = get_current_user(); | 3541 | event->mmap_user = get_current_user(); |
3539 | vma->vm_mm->pinned_vm += event->mmap_locked; | 3542 | vma->vm_mm->pinned_vm += event->mmap_locked; |
3540 | 3543 | ||
3544 | perf_event_update_userpage(event); | ||
3545 | |||
3541 | unlock: | 3546 | unlock: |
3542 | if (!ret) | 3547 | if (!ret) |
3543 | atomic_inc(&event->mmap_count); | 3548 | atomic_inc(&event->mmap_count); |
@@ -3769,7 +3774,7 @@ static void perf_output_read_group(struct perf_output_handle *handle, | |||
3769 | static void perf_output_read(struct perf_output_handle *handle, | 3774 | static void perf_output_read(struct perf_output_handle *handle, |
3770 | struct perf_event *event) | 3775 | struct perf_event *event) |
3771 | { | 3776 | { |
3772 | u64 enabled = 0, running = 0; | 3777 | u64 enabled = 0, running = 0, now; |
3773 | u64 read_format = event->attr.read_format; | 3778 | u64 read_format = event->attr.read_format; |
3774 | 3779 | ||
3775 | /* | 3780 | /* |
@@ -3782,7 +3787,7 @@ static void perf_output_read(struct perf_output_handle *handle, | |||
3782 | * NMI context | 3787 | * NMI context |
3783 | */ | 3788 | */ |
3784 | if (read_format & PERF_FORMAT_TOTAL_TIMES) | 3789 | if (read_format & PERF_FORMAT_TOTAL_TIMES) |
3785 | calc_timer_values(event, &enabled, &running); | 3790 | calc_timer_values(event, &now, &enabled, &running); |
3786 | 3791 | ||
3787 | if (event->attr.read_format & PERF_FORMAT_GROUP) | 3792 | if (event->attr.read_format & PERF_FORMAT_GROUP) |
3788 | perf_output_read_group(handle, event, enabled, running); | 3793 | perf_output_read_group(handle, event, enabled, running); |
@@ -4994,6 +4999,11 @@ static int perf_swevent_init(struct perf_event *event) | |||
4994 | return 0; | 4999 | return 0; |
4995 | } | 5000 | } |
4996 | 5001 | ||
5002 | static int perf_swevent_event_idx(struct perf_event *event) | ||
5003 | { | ||
5004 | return 0; | ||
5005 | } | ||
5006 | |||
4997 | static struct pmu perf_swevent = { | 5007 | static struct pmu perf_swevent = { |
4998 | .task_ctx_nr = perf_sw_context, | 5008 | .task_ctx_nr = perf_sw_context, |
4999 | 5009 | ||
@@ -5003,6 +5013,8 @@ static struct pmu perf_swevent = { | |||
5003 | .start = perf_swevent_start, | 5013 | .start = perf_swevent_start, |
5004 | .stop = perf_swevent_stop, | 5014 | .stop = perf_swevent_stop, |
5005 | .read = perf_swevent_read, | 5015 | .read = perf_swevent_read, |
5016 | |||
5017 | .event_idx = perf_swevent_event_idx, | ||
5006 | }; | 5018 | }; |
5007 | 5019 | ||
5008 | #ifdef CONFIG_EVENT_TRACING | 5020 | #ifdef CONFIG_EVENT_TRACING |
@@ -5089,6 +5101,8 @@ static struct pmu perf_tracepoint = { | |||
5089 | .start = perf_swevent_start, | 5101 | .start = perf_swevent_start, |
5090 | .stop = perf_swevent_stop, | 5102 | .stop = perf_swevent_stop, |
5091 | .read = perf_swevent_read, | 5103 | .read = perf_swevent_read, |
5104 | |||
5105 | .event_idx = perf_swevent_event_idx, | ||
5092 | }; | 5106 | }; |
5093 | 5107 | ||
5094 | static inline void perf_tp_register(void) | 5108 | static inline void perf_tp_register(void) |
@@ -5308,6 +5322,8 @@ static struct pmu perf_cpu_clock = { | |||
5308 | .start = cpu_clock_event_start, | 5322 | .start = cpu_clock_event_start, |
5309 | .stop = cpu_clock_event_stop, | 5323 | .stop = cpu_clock_event_stop, |
5310 | .read = cpu_clock_event_read, | 5324 | .read = cpu_clock_event_read, |
5325 | |||
5326 | .event_idx = perf_swevent_event_idx, | ||
5311 | }; | 5327 | }; |
5312 | 5328 | ||
5313 | /* | 5329 | /* |
@@ -5380,6 +5396,8 @@ static struct pmu perf_task_clock = { | |||
5380 | .start = task_clock_event_start, | 5396 | .start = task_clock_event_start, |
5381 | .stop = task_clock_event_stop, | 5397 | .stop = task_clock_event_stop, |
5382 | .read = task_clock_event_read, | 5398 | .read = task_clock_event_read, |
5399 | |||
5400 | .event_idx = perf_swevent_event_idx, | ||
5383 | }; | 5401 | }; |
5384 | 5402 | ||
5385 | static void perf_pmu_nop_void(struct pmu *pmu) | 5403 | static void perf_pmu_nop_void(struct pmu *pmu) |
@@ -5407,6 +5425,11 @@ static void perf_pmu_cancel_txn(struct pmu *pmu) | |||
5407 | perf_pmu_enable(pmu); | 5425 | perf_pmu_enable(pmu); |
5408 | } | 5426 | } |
5409 | 5427 | ||
5428 | static int perf_event_idx_default(struct perf_event *event) | ||
5429 | { | ||
5430 | return event->hw.idx + 1; | ||
5431 | } | ||
5432 | |||
5410 | /* | 5433 | /* |
5411 | * Ensures all contexts with the same task_ctx_nr have the same | 5434 | * Ensures all contexts with the same task_ctx_nr have the same |
5412 | * pmu_cpu_context too. | 5435 | * pmu_cpu_context too. |
@@ -5493,6 +5516,7 @@ static int pmu_dev_alloc(struct pmu *pmu) | |||
5493 | if (!pmu->dev) | 5516 | if (!pmu->dev) |
5494 | goto out; | 5517 | goto out; |
5495 | 5518 | ||
5519 | pmu->dev->groups = pmu->attr_groups; | ||
5496 | device_initialize(pmu->dev); | 5520 | device_initialize(pmu->dev); |
5497 | ret = dev_set_name(pmu->dev, "%s", pmu->name); | 5521 | ret = dev_set_name(pmu->dev, "%s", pmu->name); |
5498 | if (ret) | 5522 | if (ret) |
@@ -5596,6 +5620,9 @@ got_cpu_context: | |||
5596 | pmu->pmu_disable = perf_pmu_nop_void; | 5620 | pmu->pmu_disable = perf_pmu_nop_void; |
5597 | } | 5621 | } |
5598 | 5622 | ||
5623 | if (!pmu->event_idx) | ||
5624 | pmu->event_idx = perf_event_idx_default; | ||
5625 | |||
5599 | list_add_rcu(&pmu->entry, &pmus); | 5626 | list_add_rcu(&pmu->entry, &pmus); |
5600 | ret = 0; | 5627 | ret = 0; |
5601 | unlock: | 5628 | unlock: |
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index b7971d6f38bf..b0309f76d777 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c | |||
@@ -613,6 +613,11 @@ static void hw_breakpoint_stop(struct perf_event *bp, int flags) | |||
613 | bp->hw.state = PERF_HES_STOPPED; | 613 | bp->hw.state = PERF_HES_STOPPED; |
614 | } | 614 | } |
615 | 615 | ||
616 | static int hw_breakpoint_event_idx(struct perf_event *bp) | ||
617 | { | ||
618 | return 0; | ||
619 | } | ||
620 | |||
616 | static struct pmu perf_breakpoint = { | 621 | static struct pmu perf_breakpoint = { |
617 | .task_ctx_nr = perf_sw_context, /* could eventually get its own */ | 622 | .task_ctx_nr = perf_sw_context, /* could eventually get its own */ |
618 | 623 | ||
@@ -622,6 +627,8 @@ static struct pmu perf_breakpoint = { | |||
622 | .start = hw_breakpoint_start, | 627 | .start = hw_breakpoint_start, |
623 | .stop = hw_breakpoint_stop, | 628 | .stop = hw_breakpoint_stop, |
624 | .read = hw_breakpoint_pmu_read, | 629 | .read = hw_breakpoint_pmu_read, |
630 | |||
631 | .event_idx = hw_breakpoint_event_idx, | ||
625 | }; | 632 | }; |
626 | 633 | ||
627 | int __init init_hw_breakpoint(void) | 634 | int __init init_hw_breakpoint(void) |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 3ce709e97462..70c4eb2bdf72 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -15,6 +15,8 @@ | |||
15 | #include "util/thread_map.h" | 15 | #include "util/thread_map.h" |
16 | #include "../../include/linux/hw_breakpoint.h" | 16 | #include "../../include/linux/hw_breakpoint.h" |
17 | 17 | ||
18 | #include <sys/mman.h> | ||
19 | |||
18 | static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) | 20 | static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) |
19 | { | 21 | { |
20 | bool *visited = symbol__priv(sym); | 22 | bool *visited = symbol__priv(sym); |
@@ -1296,6 +1298,173 @@ out: | |||
1296 | return (err < 0 || errs > 0) ? -1 : 0; | 1298 | return (err < 0 || errs > 0) ? -1 : 0; |
1297 | } | 1299 | } |
1298 | 1300 | ||
1301 | |||
1302 | #if defined(__x86_64__) || defined(__i386__) | ||
1303 | |||
1304 | #define barrier() asm volatile("" ::: "memory") | ||
1305 | |||
1306 | static u64 rdpmc(unsigned int counter) | ||
1307 | { | ||
1308 | unsigned int low, high; | ||
1309 | |||
1310 | asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter)); | ||
1311 | |||
1312 | return low | ((u64)high) << 32; | ||
1313 | } | ||
1314 | |||
1315 | static u64 rdtsc(void) | ||
1316 | { | ||
1317 | unsigned int low, high; | ||
1318 | |||
1319 | asm volatile("rdtsc" : "=a" (low), "=d" (high)); | ||
1320 | |||
1321 | return low | ((u64)high) << 32; | ||
1322 | } | ||
1323 | |||
1324 | static u64 mmap_read_self(void *addr) | ||
1325 | { | ||
1326 | struct perf_event_mmap_page *pc = addr; | ||
1327 | u32 seq, idx, time_mult = 0, time_shift = 0; | ||
1328 | u64 count, cyc = 0, time_offset = 0, enabled, running, delta; | ||
1329 | |||
1330 | do { | ||
1331 | seq = pc->lock; | ||
1332 | barrier(); | ||
1333 | |||
1334 | enabled = pc->time_enabled; | ||
1335 | running = pc->time_running; | ||
1336 | |||
1337 | if (enabled != running) { | ||
1338 | cyc = rdtsc(); | ||
1339 | time_mult = pc->time_mult; | ||
1340 | time_shift = pc->time_shift; | ||
1341 | time_offset = pc->time_offset; | ||
1342 | } | ||
1343 | |||
1344 | idx = pc->index; | ||
1345 | count = pc->offset; | ||
1346 | if (idx) | ||
1347 | count += rdpmc(idx - 1); | ||
1348 | |||
1349 | barrier(); | ||
1350 | } while (pc->lock != seq); | ||
1351 | |||
1352 | if (enabled != running) { | ||
1353 | u64 quot, rem; | ||
1354 | |||
1355 | quot = (cyc >> time_shift); | ||
1356 | rem = cyc & ((1 << time_shift) - 1); | ||
1357 | delta = time_offset + quot * time_mult + | ||
1358 | ((rem * time_mult) >> time_shift); | ||
1359 | |||
1360 | enabled += delta; | ||
1361 | if (idx) | ||
1362 | running += delta; | ||
1363 | |||
1364 | quot = count / running; | ||
1365 | rem = count % running; | ||
1366 | count = quot * enabled + (rem * enabled) / running; | ||
1367 | } | ||
1368 | |||
1369 | return count; | ||
1370 | } | ||
1371 | |||
1372 | /* | ||
1373 | * If the RDPMC instruction faults then signal this back to the test parent task: | ||
1374 | */ | ||
1375 | static void segfault_handler(int sig __used, siginfo_t *info __used, void *uc __used) | ||
1376 | { | ||
1377 | exit(-1); | ||
1378 | } | ||
1379 | |||
1380 | static int __test__rdpmc(void) | ||
1381 | { | ||
1382 | long page_size = sysconf(_SC_PAGE_SIZE); | ||
1383 | volatile int tmp = 0; | ||
1384 | u64 i, loops = 1000; | ||
1385 | int n; | ||
1386 | int fd; | ||
1387 | void *addr; | ||
1388 | struct perf_event_attr attr = { | ||
1389 | .type = PERF_TYPE_HARDWARE, | ||
1390 | .config = PERF_COUNT_HW_INSTRUCTIONS, | ||
1391 | .exclude_kernel = 1, | ||
1392 | }; | ||
1393 | u64 delta_sum = 0; | ||
1394 | struct sigaction sa; | ||
1395 | |||
1396 | sigfillset(&sa.sa_mask); | ||
1397 | sa.sa_sigaction = segfault_handler; | ||
1398 | sigaction(SIGSEGV, &sa, NULL); | ||
1399 | |||
1400 | fprintf(stderr, "\n\n"); | ||
1401 | |||
1402 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | ||
1403 | if (fd < 0) { | ||
1404 | die("Error: sys_perf_event_open() syscall returned " | ||
1405 | "with %d (%s)\n", fd, strerror(errno)); | ||
1406 | } | ||
1407 | |||
1408 | addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); | ||
1409 | if (addr == (void *)(-1)) { | ||
1410 | die("Error: mmap() syscall returned " | ||
1411 | "with (%s)\n", strerror(errno)); | ||
1412 | } | ||
1413 | |||
1414 | for (n = 0; n < 6; n++) { | ||
1415 | u64 stamp, now, delta; | ||
1416 | |||
1417 | stamp = mmap_read_self(addr); | ||
1418 | |||
1419 | for (i = 0; i < loops; i++) | ||
1420 | tmp++; | ||
1421 | |||
1422 | now = mmap_read_self(addr); | ||
1423 | loops *= 10; | ||
1424 | |||
1425 | delta = now - stamp; | ||
1426 | fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta); | ||
1427 | |||
1428 | delta_sum += delta; | ||
1429 | } | ||
1430 | |||
1431 | munmap(addr, page_size); | ||
1432 | close(fd); | ||
1433 | |||
1434 | fprintf(stderr, " "); | ||
1435 | |||
1436 | if (!delta_sum) | ||
1437 | return -1; | ||
1438 | |||
1439 | return 0; | ||
1440 | } | ||
1441 | |||
1442 | static int test__rdpmc(void) | ||
1443 | { | ||
1444 | int status = 0; | ||
1445 | int wret = 0; | ||
1446 | int ret; | ||
1447 | int pid; | ||
1448 | |||
1449 | pid = fork(); | ||
1450 | if (pid < 0) | ||
1451 | return -1; | ||
1452 | |||
1453 | if (!pid) { | ||
1454 | ret = __test__rdpmc(); | ||
1455 | |||
1456 | exit(ret); | ||
1457 | } | ||
1458 | |||
1459 | wret = waitpid(pid, &status, 0); | ||
1460 | if (wret < 0 || status) | ||
1461 | return -1; | ||
1462 | |||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | #endif | ||
1467 | |||
1299 | static struct test { | 1468 | static struct test { |
1300 | const char *desc; | 1469 | const char *desc; |
1301 | int (*func)(void); | 1470 | int (*func)(void); |
@@ -1320,6 +1489,12 @@ static struct test { | |||
1320 | .desc = "parse events tests", | 1489 | .desc = "parse events tests", |
1321 | .func = test__parse_events, | 1490 | .func = test__parse_events, |
1322 | }, | 1491 | }, |
1492 | #if defined(__x86_64__) || defined(__i386__) | ||
1493 | { | ||
1494 | .desc = "x86 rdpmc test", | ||
1495 | .func = test__rdpmc, | ||
1496 | }, | ||
1497 | #endif | ||
1323 | { | 1498 | { |
1324 | .desc = "Validate PERF_RECORD_* events & perf_sample fields", | 1499 | .desc = "Validate PERF_RECORD_* events & perf_sample fields", |
1325 | .func = test__PERF_RECORD, | 1500 | .func = test__PERF_RECORD, |
@@ -1412,7 +1587,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used) | |||
1412 | if (symbol__init() < 0) | 1587 | if (symbol__init() < 0) |
1413 | return -1; | 1588 | return -1; |
1414 | 1589 | ||
1415 | setup_pager(); | ||
1416 | |||
1417 | return __cmd_test(argc, argv); | 1590 | return __cmd_test(argc, argv); |
1418 | } | 1591 | } |