mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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) <peterz@infradead.org> [ Made the patch compile and things. ] Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@kernel.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Link: http://lkml.kernel.org/r/1441336073-22750-7-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									0492d4c5b8
								
							
						
					
					
						commit
						fa8c269353
					
				
					 1 changed files with 58 additions and 33 deletions
				
			
		| 
						 | 
					@ -3862,50 +3862,75 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(perf_event_read_value);
 | 
					EXPORT_SYMBOL_GPL(perf_event_read_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int perf_read_group(struct perf_event *event,
 | 
					static void __perf_read_group_add(struct perf_event *leader,
 | 
				
			||||||
				   u64 read_format, char __user *buf)
 | 
										u64 read_format, u64 *values)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct perf_event *leader = event->group_leader, *sub;
 | 
						struct perf_event *sub;
 | 
				
			||||||
	struct perf_event_context *ctx = leader->ctx;
 | 
						int n = 1; /* skip @nr */
 | 
				
			||||||
	int n = 0, size = 0, ret;
 | 
					 | 
				
			||||||
	u64 count, enabled, running;
 | 
					 | 
				
			||||||
	u64 values[5];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lockdep_assert_held(&ctx->mutex);
 | 
						perf_event_read(leader, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	count = perf_event_read_value(leader, &enabled, &running);
 | 
						/*
 | 
				
			||||||
 | 
						 * Since we co-schedule groups, {enabled,running} times of siblings
 | 
				
			||||||
 | 
						 * will be identical to those of the leader, so we only publish one
 | 
				
			||||||
 | 
						 * set.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
 | 
				
			||||||
 | 
							values[n++] += leader->total_time_enabled +
 | 
				
			||||||
 | 
								atomic64_read(&leader->child_total_time_enabled);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	values[n++] = 1 + leader->nr_siblings;
 | 
						if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
 | 
				
			||||||
	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
 | 
							values[n++] += leader->total_time_running +
 | 
				
			||||||
		values[n++] = enabled;
 | 
								atomic64_read(&leader->child_total_time_running);
 | 
				
			||||||
	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
 | 
						}
 | 
				
			||||||
		values[n++] = running;
 | 
					
 | 
				
			||||||
	values[n++] = count;
 | 
						/*
 | 
				
			||||||
 | 
						 * Write {count,id} tuples for every sibling.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						values[n++] += perf_event_count(leader);
 | 
				
			||||||
	if (read_format & PERF_FORMAT_ID)
 | 
						if (read_format & PERF_FORMAT_ID)
 | 
				
			||||||
		values[n++] = primary_event_id(leader);
 | 
							values[n++] = primary_event_id(leader);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size = n * sizeof(u64);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (copy_to_user(buf, values, size))
 | 
					 | 
				
			||||||
		return -EFAULT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	list_for_each_entry(sub, &leader->sibling_list, group_entry) {
 | 
						list_for_each_entry(sub, &leader->sibling_list, group_entry) {
 | 
				
			||||||
		n = 0;
 | 
							values[n++] += perf_event_count(sub);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		values[n++] = perf_event_read_value(sub, &enabled, &running);
 | 
					 | 
				
			||||||
		if (read_format & PERF_FORMAT_ID)
 | 
							if (read_format & PERF_FORMAT_ID)
 | 
				
			||||||
			values[n++] = primary_event_id(sub);
 | 
								values[n++] = primary_event_id(sub);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		size = n * sizeof(u64);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (copy_to_user(buf + ret, values, size)) {
 | 
					 | 
				
			||||||
			return -EFAULT;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret += size;
 | 
					static int perf_read_group(struct perf_event *event,
 | 
				
			||||||
	}
 | 
									   u64 read_format, char __user *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct perf_event *leader = event->group_leader, *child;
 | 
				
			||||||
 | 
						struct perf_event_context *ctx = leader->ctx;
 | 
				
			||||||
 | 
						int ret = event->read_size;
 | 
				
			||||||
 | 
						u64 *values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lockdep_assert_held(&ctx->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						values = kzalloc(event->read_size, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!values)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						values[0] = 1 + leader->nr_siblings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * By locking the child_mutex of the leader we effectively
 | 
				
			||||||
 | 
						 * lock the child list of all siblings.. XXX explain how.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						mutex_lock(&leader->child_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__perf_read_group_add(leader, read_format, values);
 | 
				
			||||||
 | 
						list_for_each_entry(child, &leader->child_list, child_list)
 | 
				
			||||||
 | 
							__perf_read_group_add(child, read_format, values);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&leader->child_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (copy_to_user(buf, values, event->read_size))
 | 
				
			||||||
 | 
							ret = -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(values);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue