Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57e7986e authored by Paul Mackerras's avatar Paul Mackerras Committed by Ingo Molnar
Browse files

perf_counter: Provide a way to enable counters on exec



This provides a way to mark a counter to be enabled on the next
exec. This is useful for measuring the total activity of a
program without including overhead from the process that
launches it.

This also changes the perf stat command to use this new
facility.

Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <19017.43927.838745.689203@cargo.ozlabs.ibm.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 051ae7f7
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -179,8 +179,9 @@ struct perf_counter_attr {
				comm	       :  1, /* include comm data     */
				freq           :  1, /* use freq, not period  */
				inherit_stat   :  1, /* per task counts       */
				enable_on_exec :  1, /* next exec enables     */

				__reserved_1   : 52;
				__reserved_1   : 51;

	__u32			wakeup_events;	/* wakeup every n events */
	__u32			__reserved_2;
+50 −0
Original line number Diff line number Diff line
@@ -1428,6 +1428,53 @@ void perf_counter_task_tick(struct task_struct *curr, int cpu)
		perf_counter_task_sched_in(curr, cpu);
}

/*
 * Enable all of a task's counters that have been marked enable-on-exec.
 * This expects task == current.
 */
static void perf_counter_enable_on_exec(struct task_struct *task)
{
	struct perf_counter_context *ctx;
	struct perf_counter *counter;
	unsigned long flags;
	int enabled = 0;

	local_irq_save(flags);
	ctx = task->perf_counter_ctxp;
	if (!ctx || !ctx->nr_counters)
		goto out;

	__perf_counter_task_sched_out(ctx);

	spin_lock(&ctx->lock);

	list_for_each_entry(counter, &ctx->counter_list, list_entry) {
		if (!counter->attr.enable_on_exec)
			continue;
		counter->attr.enable_on_exec = 0;
		if (counter->state >= PERF_COUNTER_STATE_INACTIVE)
			continue;
		counter->state = PERF_COUNTER_STATE_INACTIVE;
		counter->tstamp_enabled =
			ctx->time - counter->total_time_enabled;
		enabled = 1;
	}

	/*
	 * Unclone this context if we enabled any counter.
	 */
	if (enabled && ctx->parent_ctx) {
		put_ctx(ctx->parent_ctx);
		ctx->parent_ctx = NULL;
	}

	spin_unlock(&ctx->lock);

	perf_counter_task_sched_in(task, smp_processor_id());
 out:
	local_irq_restore(flags);
}

/*
 * Cross CPU call to read the hardware counter
 */
@@ -2949,6 +2996,9 @@ void perf_counter_comm(struct task_struct *task)
{
	struct perf_comm_event comm_event;

	if (task->perf_counter_ctxp)
		perf_counter_enable_on_exec(task);

	if (!atomic_read(&nr_comm_counters))
		return;

+3 −3
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ static void create_perf_stat_counter(int counter, int pid)
	} else {
		attr->inherit	     = inherit;
		attr->disabled	     = 1;
		attr->enable_on_exec = 1;

		fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0);
		if (fd[0][counter] < 0 && verbose)
@@ -262,7 +263,6 @@ static int run_perf_stat(int argc, const char **argv)
	 * Enable counters and exec the command:
	 */
	t0 = rdclock();
	prctl(PR_TASK_PERF_COUNTERS_ENABLE);

	close(go_pipe[1]);
	wait(&status);