aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKan Liang <kan.liang@intel.com>2015-05-10 15:13:14 -0400
committerIngo Molnar <mingo@kernel.org>2015-06-07 10:09:02 -0400
commitf38b0dbb491a6987e198aa6b428db8692a6480f8 (patch)
treea3ba22b7226e96b085d3e08174d73a3883cfe44a
parent156174999dd1d0fe8732f5a05f4e9cef921ad487 (diff)
perf/x86/intel: Introduce PERF_RECORD_LOST_SAMPLES
After enlarging the PEBS interrupt threshold, there may be some mixed up PEBS samples which are discarded by the kernel. This patch makes the kernel emit a PERF_RECORD_LOST_SAMPLES record with the number of possible discarded records when it is impossible to demux the samples. It makes sure the user is not left in the dark about such discards. Signed-off-by: Kan Liang <kan.liang@intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: acme@infradead.org Cc: eranian@google.com Link: http://lkml.kernel.org/r/1431285195-14269-8-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c20
-rw-r--r--include/linux/perf_event.h3
-rw-r--r--include/uapi/linux/perf_event.h12
-rw-r--r--kernel/events/core.c33
4 files changed, 65 insertions, 3 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 266079a3a646..34d0c4816141 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -1126,6 +1126,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
1126 void *base, *at, *top; 1126 void *base, *at, *top;
1127 int bit; 1127 int bit;
1128 short counts[MAX_PEBS_EVENTS] = {}; 1128 short counts[MAX_PEBS_EVENTS] = {};
1129 short error[MAX_PEBS_EVENTS] = {};
1129 1130
1130 if (!x86_pmu.pebs_active) 1131 if (!x86_pmu.pebs_active)
1131 return; 1132 return;
@@ -1169,20 +1170,33 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
1169 /* slow path */ 1170 /* slow path */
1170 pebs_status = p->status & cpuc->pebs_enabled; 1171 pebs_status = p->status & cpuc->pebs_enabled;
1171 pebs_status &= (1ULL << MAX_PEBS_EVENTS) - 1; 1172 pebs_status &= (1ULL << MAX_PEBS_EVENTS) - 1;
1172 if (pebs_status != (1 << bit)) 1173 if (pebs_status != (1 << bit)) {
1174 u8 i;
1175
1176 for_each_set_bit(i, (unsigned long *)&pebs_status,
1177 MAX_PEBS_EVENTS)
1178 error[i]++;
1173 continue; 1179 continue;
1180 }
1174 } 1181 }
1175 counts[bit]++; 1182 counts[bit]++;
1176 } 1183 }
1177 1184
1178 for (bit = 0; bit < x86_pmu.max_pebs_events; bit++) { 1185 for (bit = 0; bit < x86_pmu.max_pebs_events; bit++) {
1179 if (counts[bit] == 0) 1186 if ((counts[bit] == 0) && (error[bit] == 0))
1180 continue; 1187 continue;
1181 event = cpuc->events[bit]; 1188 event = cpuc->events[bit];
1182 WARN_ON_ONCE(!event); 1189 WARN_ON_ONCE(!event);
1183 WARN_ON_ONCE(!event->attr.precise_ip); 1190 WARN_ON_ONCE(!event->attr.precise_ip);
1184 1191
1185 __intel_pmu_pebs_event(event, iregs, base, top, bit, counts[bit]); 1192 /* log dropped samples number */
1193 if (error[bit])
1194 perf_log_lost_samples(event, error[bit]);
1195
1196 if (counts[bit]) {
1197 __intel_pmu_pebs_event(event, iregs, base,
1198 top, bit, counts[bit]);
1199 }
1186 } 1200 }
1187} 1201}
1188 1202
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 5f192e1bc98e..a204d5266f5f 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -743,6 +743,9 @@ perf_event__output_id_sample(struct perf_event *event,
743 struct perf_output_handle *handle, 743 struct perf_output_handle *handle,
744 struct perf_sample_data *sample); 744 struct perf_sample_data *sample);
745 745
746extern void
747perf_log_lost_samples(struct perf_event *event, u64 lost);
748
746static inline bool is_sampling_event(struct perf_event *event) 749static inline bool is_sampling_event(struct perf_event *event)
747{ 750{
748 return event->attr.sample_period != 0; 751 return event->attr.sample_period != 0;
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index c4622f1ce046..613ed9ad588f 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -802,6 +802,18 @@ enum perf_event_type {
802 */ 802 */
803 PERF_RECORD_ITRACE_START = 12, 803 PERF_RECORD_ITRACE_START = 12,
804 804
805 /*
806 * Records the dropped/lost sample number.
807 *
808 * struct {
809 * struct perf_event_header header;
810 *
811 * u64 lost;
812 * struct sample_id sample_id;
813 * };
814 */
815 PERF_RECORD_LOST_SAMPLES = 13,
816
805 PERF_RECORD_MAX, /* non-ABI */ 817 PERF_RECORD_MAX, /* non-ABI */
806}; 818};
807 819
diff --git a/kernel/events/core.c b/kernel/events/core.c
index e499b4e43aff..9e0773d5d110 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5975,6 +5975,39 @@ void perf_event_aux_event(struct perf_event *event, unsigned long head,
5975} 5975}
5976 5976
5977/* 5977/*
5978 * Lost/dropped samples logging
5979 */
5980void perf_log_lost_samples(struct perf_event *event, u64 lost)
5981{
5982 struct perf_output_handle handle;
5983 struct perf_sample_data sample;
5984 int ret;
5985
5986 struct {
5987 struct perf_event_header header;
5988 u64 lost;
5989 } lost_samples_event = {
5990 .header = {
5991 .type = PERF_RECORD_LOST_SAMPLES,
5992 .misc = 0,
5993 .size = sizeof(lost_samples_event),
5994 },
5995 .lost = lost,
5996 };
5997
5998 perf_event_header__init_id(&lost_samples_event.header, &sample, event);
5999
6000 ret = perf_output_begin(&handle, event,
6001 lost_samples_event.header.size);
6002 if (ret)
6003 return;
6004
6005 perf_output_put(&handle, lost_samples_event);
6006 perf_event__output_id_sample(event, &handle, &sample);
6007 perf_output_end(&handle);
6008}
6009
6010/*
5978 * IRQ throttle logging 6011 * IRQ throttle logging
5979 */ 6012 */
5980 6013