Skip to content

Commit fa8c269

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
perf/core: Invert perf_read_group() loops
In order to enable the use of perf_event_read(.group = true), we need to invert the sibling-child loop nesting of perf_read_group(). Currently we iterate the child list for each sibling, this precludes using group reads. Flip things around so we iterate each group for each child. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> [ Made the patch compile and things. ] Signed-off-by: Sukadev Bhattiprolu <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vince Weaver <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 0492d4c commit fa8c269

File tree

1 file changed

+55
-30
lines changed

1 file changed

+55
-30
lines changed

kernel/events/core.c

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3862,50 +3862,75 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
38623862
}
38633863
EXPORT_SYMBOL_GPL(perf_event_read_value);
38643864

3865-
static int perf_read_group(struct perf_event *event,
3866-
u64 read_format, char __user *buf)
3865+
static void __perf_read_group_add(struct perf_event *leader,
3866+
u64 read_format, u64 *values)
38673867
{
3868-
struct perf_event *leader = event->group_leader, *sub;
3869-
struct perf_event_context *ctx = leader->ctx;
3870-
int n = 0, size = 0, ret;
3871-
u64 count, enabled, running;
3872-
u64 values[5];
3868+
struct perf_event *sub;
3869+
int n = 1; /* skip @nr */
38733870

3874-
lockdep_assert_held(&ctx->mutex);
3871+
perf_event_read(leader, true);
3872+
3873+
/*
3874+
* Since we co-schedule groups, {enabled,running} times of siblings
3875+
* will be identical to those of the leader, so we only publish one
3876+
* set.
3877+
*/
3878+
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
3879+
values[n++] += leader->total_time_enabled +
3880+
atomic64_read(&leader->child_total_time_enabled);
3881+
}
38753882

3876-
count = perf_event_read_value(leader, &enabled, &running);
3883+
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
3884+
values[n++] += leader->total_time_running +
3885+
atomic64_read(&leader->child_total_time_running);
3886+
}
38773887

3878-
values[n++] = 1 + leader->nr_siblings;
3879-
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
3880-
values[n++] = enabled;
3881-
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
3882-
values[n++] = running;
3883-
values[n++] = count;
3888+
/*
3889+
* Write {count,id} tuples for every sibling.
3890+
*/
3891+
values[n++] += perf_event_count(leader);
38843892
if (read_format & PERF_FORMAT_ID)
38853893
values[n++] = primary_event_id(leader);
38863894

3887-
size = n * sizeof(u64);
3895+
list_for_each_entry(sub, &leader->sibling_list, group_entry) {
3896+
values[n++] += perf_event_count(sub);
3897+
if (read_format & PERF_FORMAT_ID)
3898+
values[n++] = primary_event_id(sub);
3899+
}
3900+
}
38883901

3889-
if (copy_to_user(buf, values, size))
3890-
return -EFAULT;
3902+
static int perf_read_group(struct perf_event *event,
3903+
u64 read_format, char __user *buf)
3904+
{
3905+
struct perf_event *leader = event->group_leader, *child;
3906+
struct perf_event_context *ctx = leader->ctx;
3907+
int ret = event->read_size;
3908+
u64 *values;
38913909

3892-
ret = size;
3910+
lockdep_assert_held(&ctx->mutex);
38933911

3894-
list_for_each_entry(sub, &leader->sibling_list, group_entry) {
3895-
n = 0;
3912+
values = kzalloc(event->read_size, GFP_KERNEL);
3913+
if (!values)
3914+
return -ENOMEM;
38963915

3897-
values[n++] = perf_event_read_value(sub, &enabled, &running);
3898-
if (read_format & PERF_FORMAT_ID)
3899-
values[n++] = primary_event_id(sub);
3916+
values[0] = 1 + leader->nr_siblings;
3917+
3918+
/*
3919+
* By locking the child_mutex of the leader we effectively
3920+
* lock the child list of all siblings.. XXX explain how.
3921+
*/
3922+
mutex_lock(&leader->child_mutex);
39003923

3901-
size = n * sizeof(u64);
3924+
__perf_read_group_add(leader, read_format, values);
3925+
list_for_each_entry(child, &leader->child_list, child_list)
3926+
__perf_read_group_add(child, read_format, values);
39023927

3903-
if (copy_to_user(buf + ret, values, size)) {
3904-
return -EFAULT;
3905-
}
3928+
mutex_unlock(&leader->child_mutex);
39063929

3907-
ret += size;
3908-
}
3930+
if (copy_to_user(buf, values, event->read_size))
3931+
ret = -EFAULT;
3932+
3933+
kfree(values);
39093934

39103935
return ret;
39113936
}

0 commit comments

Comments
 (0)