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

Commit b04243ef authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

perf: Complete software pmu grouping



Aside from allowing software events into a !software group,
allow adding !software events to pure software groups.

Once we've moved the software group and attached the first
!software event, the group will no longer be a pure software
group and hence no longer be eligible for movement, at which
point the straight ctx comparison is correct again.

Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Robert Richter <robert.richter@amd.com>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <20100917093009.410784731@chello.nl>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d14b12d7
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -804,12 +804,18 @@ struct perf_event {
#endif /* CONFIG_PERF_EVENTS */
#endif /* CONFIG_PERF_EVENTS */
};
};


enum perf_event_context_type {
	task_context,
	cpu_context,
};

/**
/**
 * struct perf_event_context - event context structure
 * struct perf_event_context - event context structure
 *
 *
 * Used as a container for task events and CPU events as well:
 * Used as a container for task events and CPU events as well:
 */
 */
struct perf_event_context {
struct perf_event_context {
	enum perf_event_context_type	type;
	struct pmu			*pmu;
	struct pmu			*pmu;
	/*
	/*
	 * Protect the states of the events in the list,
	 * Protect the states of the events in the list,
+60 −5
Original line number Original line Diff line number Diff line
@@ -5184,6 +5184,7 @@ int perf_pmu_register(struct pmu *pmu)


		cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
		cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
		__perf_event_init_context(&cpuctx->ctx);
		__perf_event_init_context(&cpuctx->ctx);
		cpuctx->ctx.type = cpu_context;
		cpuctx->ctx.pmu = pmu;
		cpuctx->ctx.pmu = pmu;
		cpuctx->timer_interval = TICK_NSEC;
		cpuctx->timer_interval = TICK_NSEC;
		hrtimer_init(&cpuctx->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
		hrtimer_init(&cpuctx->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
@@ -5517,7 +5518,8 @@ SYSCALL_DEFINE5(perf_event_open,
		struct perf_event_attr __user *, attr_uptr,
		struct perf_event_attr __user *, attr_uptr,
		pid_t, pid, int, cpu, int, group_fd, unsigned long, flags)
		pid_t, pid, int, cpu, int, group_fd, unsigned long, flags)
{
{
	struct perf_event *event, *group_leader = NULL, *output_event = NULL;
	struct perf_event *group_leader = NULL, *output_event = NULL;
	struct perf_event *event, *sibling;
	struct perf_event_attr attr;
	struct perf_event_attr attr;
	struct perf_event_context *ctx;
	struct perf_event_context *ctx;
	struct file *event_file = NULL;
	struct file *event_file = NULL;
@@ -5525,6 +5527,7 @@ SYSCALL_DEFINE5(perf_event_open,
	struct task_struct *task = NULL;
	struct task_struct *task = NULL;
	struct pmu *pmu;
	struct pmu *pmu;
	int event_fd;
	int event_fd;
	int move_group = 0;
	int fput_needed = 0;
	int fput_needed = 0;
	int err;
	int err;


@@ -5574,8 +5577,29 @@ SYSCALL_DEFINE5(perf_event_open,
	 * any hardware group.
	 * any hardware group.
	 */
	 */
	pmu = event->pmu;
	pmu = event->pmu;
	if ((pmu->task_ctx_nr == perf_sw_context) && group_leader)

	if (group_leader &&
	    (is_software_event(event) != is_software_event(group_leader))) {
		if (is_software_event(event)) {
			/*
			 * If event and group_leader are not both a software
			 * event, and event is, then group leader is not.
			 *
			 * Allow the addition of software events to !software
			 * groups, this is safe because software events never
			 * fail to schedule.
			 */
			pmu = group_leader->pmu;
			pmu = group_leader->pmu;
		} else if (is_software_event(group_leader) &&
			   (group_leader->group_flags & PERF_GROUP_SOFTWARE)) {
			/*
			 * In case the group is a pure software group, and we
			 * try to add a hardware event, move the whole group to
			 * the hardware context.
			 */
			move_group = 1;
		}
	}


	if (pid != -1)
	if (pid != -1)
		task = find_lively_task_by_vpid(pid);
		task = find_lively_task_by_vpid(pid);
@@ -5605,8 +5629,14 @@ SYSCALL_DEFINE5(perf_event_open,
		 * Do not allow to attach to a group in a different
		 * Do not allow to attach to a group in a different
		 * task or CPU context:
		 * task or CPU context:
		 */
		 */
		if (move_group) {
			if (group_leader->ctx->type != ctx->type)
				goto err_context;
		} else {
			if (group_leader->ctx != ctx)
			if (group_leader->ctx != ctx)
				goto err_context;
				goto err_context;
		}

		/*
		/*
		 * Only a group leader can be exclusive or pinned
		 * Only a group leader can be exclusive or pinned
		 */
		 */
@@ -5626,9 +5656,34 @@ SYSCALL_DEFINE5(perf_event_open,
		goto err_context;
		goto err_context;
	}
	}


	if (move_group) {
		struct perf_event_context *gctx = group_leader->ctx;

		mutex_lock(&gctx->mutex);
		perf_event_remove_from_context(group_leader);
		list_for_each_entry(sibling, &group_leader->sibling_list,
				    group_entry) {
			perf_event_remove_from_context(sibling);
			put_ctx(gctx);
		}
		mutex_unlock(&gctx->mutex);
		put_ctx(gctx);
	}

	event->filp = event_file;
	event->filp = event_file;
	WARN_ON_ONCE(ctx->parent_ctx);
	WARN_ON_ONCE(ctx->parent_ctx);
	mutex_lock(&ctx->mutex);
	mutex_lock(&ctx->mutex);

	if (move_group) {
		perf_install_in_context(ctx, group_leader, cpu);
		get_ctx(ctx);
		list_for_each_entry(sibling, &group_leader->sibling_list,
				    group_entry) {
			perf_install_in_context(ctx, sibling, cpu);
			get_ctx(ctx);
		}
	}

	perf_install_in_context(ctx, event, cpu);
	perf_install_in_context(ctx, event, cpu);
	++ctx->generation;
	++ctx->generation;
	mutex_unlock(&ctx->mutex);
	mutex_unlock(&ctx->mutex);