Skip to content

Commit 119a784

Browse files
namhyungPeter Zijlstra
authored andcommitted
perf/core: Add a new read format to get a number of lost samples
Sometimes we want to know an accurate number of samples even if it's lost. Currenlty PERF_RECORD_LOST is generated for a ring-buffer which might be shared with other events. So it's hard to know per-event lost count. Add event->lost_samples field and PERF_FORMAT_LOST to retrieve it from userspace. Original-patch-by: Jiri Olsa <[email protected]> Signed-off-by: Namhyung Kim <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent f0fe9f3 commit 119a784

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
lines changed

include/linux/perf_event.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,8 @@ struct perf_event {
759759
struct pid_namespace *ns;
760760
u64 id;
761761

762+
atomic64_t lost_samples;
763+
762764
u64 (*clock)(void);
763765
perf_overflow_handler_t overflow_handler;
764766
void *overflow_handler_context;

include/uapi/linux/perf_event.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,13 +301,15 @@ enum {
301301
* { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
302302
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
303303
* { u64 id; } && PERF_FORMAT_ID
304+
* { u64 lost; } && PERF_FORMAT_LOST
304305
* } && !PERF_FORMAT_GROUP
305306
*
306307
* { u64 nr;
307308
* { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
308309
* { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
309310
* { u64 value;
310311
* { u64 id; } && PERF_FORMAT_ID
312+
* { u64 lost; } && PERF_FORMAT_LOST
311313
* } cntr[nr];
312314
* } && PERF_FORMAT_GROUP
313315
* };
@@ -317,8 +319,9 @@ enum perf_event_read_format {
317319
PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
318320
PERF_FORMAT_ID = 1U << 2,
319321
PERF_FORMAT_GROUP = 1U << 3,
322+
PERF_FORMAT_LOST = 1U << 4,
320323

321-
PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
324+
PERF_FORMAT_MAX = 1U << 5, /* non-ABI */
322325
};
323326

324327
#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */

kernel/events/core.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,6 +1819,9 @@ static void __perf_event_read_size(struct perf_event *event, int nr_siblings)
18191819
if (event->attr.read_format & PERF_FORMAT_ID)
18201820
entry += sizeof(u64);
18211821

1822+
if (event->attr.read_format & PERF_FORMAT_LOST)
1823+
entry += sizeof(u64);
1824+
18221825
if (event->attr.read_format & PERF_FORMAT_GROUP) {
18231826
nr += nr_siblings;
18241827
size += sizeof(u64);
@@ -5260,11 +5263,15 @@ static int __perf_read_group_add(struct perf_event *leader,
52605263
values[n++] += perf_event_count(leader);
52615264
if (read_format & PERF_FORMAT_ID)
52625265
values[n++] = primary_event_id(leader);
5266+
if (read_format & PERF_FORMAT_LOST)
5267+
values[n++] = atomic64_read(&leader->lost_samples);
52635268

52645269
for_each_sibling_event(sub, leader) {
52655270
values[n++] += perf_event_count(sub);
52665271
if (read_format & PERF_FORMAT_ID)
52675272
values[n++] = primary_event_id(sub);
5273+
if (read_format & PERF_FORMAT_LOST)
5274+
values[n++] = atomic64_read(&sub->lost_samples);
52685275
}
52695276

52705277
raw_spin_unlock_irqrestore(&ctx->lock, flags);
@@ -5321,7 +5328,7 @@ static int perf_read_one(struct perf_event *event,
53215328
u64 read_format, char __user *buf)
53225329
{
53235330
u64 enabled, running;
5324-
u64 values[4];
5331+
u64 values[5];
53255332
int n = 0;
53265333

53275334
values[n++] = __perf_event_read_value(event, &enabled, &running);
@@ -5331,6 +5338,8 @@ static int perf_read_one(struct perf_event *event,
53315338
values[n++] = running;
53325339
if (read_format & PERF_FORMAT_ID)
53335340
values[n++] = primary_event_id(event);
5341+
if (read_format & PERF_FORMAT_LOST)
5342+
values[n++] = atomic64_read(&event->lost_samples);
53345343

53355344
if (copy_to_user(buf, values, n * sizeof(u64)))
53365345
return -EFAULT;
@@ -6858,7 +6867,7 @@ static void perf_output_read_one(struct perf_output_handle *handle,
68586867
u64 enabled, u64 running)
68596868
{
68606869
u64 read_format = event->attr.read_format;
6861-
u64 values[4];
6870+
u64 values[5];
68626871
int n = 0;
68636872

68646873
values[n++] = perf_event_count(event);
@@ -6872,6 +6881,8 @@ static void perf_output_read_one(struct perf_output_handle *handle,
68726881
}
68736882
if (read_format & PERF_FORMAT_ID)
68746883
values[n++] = primary_event_id(event);
6884+
if (read_format & PERF_FORMAT_LOST)
6885+
values[n++] = atomic64_read(&event->lost_samples);
68756886

68766887
__output_copy(handle, values, n * sizeof(u64));
68776888
}
@@ -6882,7 +6893,7 @@ static void perf_output_read_group(struct perf_output_handle *handle,
68826893
{
68836894
struct perf_event *leader = event->group_leader, *sub;
68846895
u64 read_format = event->attr.read_format;
6885-
u64 values[5];
6896+
u64 values[6];
68866897
int n = 0;
68876898

68886899
values[n++] = 1 + leader->nr_siblings;
@@ -6900,6 +6911,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
69006911
values[n++] = perf_event_count(leader);
69016912
if (read_format & PERF_FORMAT_ID)
69026913
values[n++] = primary_event_id(leader);
6914+
if (read_format & PERF_FORMAT_LOST)
6915+
values[n++] = atomic64_read(&leader->lost_samples);
69036916

69046917
__output_copy(handle, values, n * sizeof(u64));
69056918

@@ -6913,6 +6926,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
69136926
values[n++] = perf_event_count(sub);
69146927
if (read_format & PERF_FORMAT_ID)
69156928
values[n++] = primary_event_id(sub);
6929+
if (read_format & PERF_FORMAT_LOST)
6930+
values[n++] = atomic64_read(&sub->lost_samples);
69166931

69176932
__output_copy(handle, values, n * sizeof(u64));
69186933
}

kernel/events/ring_buffer.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,10 @@ __perf_output_begin(struct perf_output_handle *handle,
172172
goto out;
173173

174174
if (unlikely(rb->paused)) {
175-
if (rb->nr_pages)
175+
if (rb->nr_pages) {
176176
local_inc(&rb->lost);
177+
atomic64_inc(&event->lost_samples);
178+
}
177179
goto out;
178180
}
179181

@@ -254,6 +256,7 @@ __perf_output_begin(struct perf_output_handle *handle,
254256

255257
fail:
256258
local_inc(&rb->lost);
259+
atomic64_inc(&event->lost_samples);
257260
perf_output_put_handle(handle);
258261
out:
259262
rcu_read_unlock();

0 commit comments

Comments
 (0)