All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matt Fleming <matt@console-pimps.org>
To: Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@kernel.org>, Jiri Olsa <jolsa@redhat.com>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	Andi Kleen <andi@firstfloor.org>
Cc: Thomas Gleixner <tglx@linutronix.de>,
	linux-kernel@vger.kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
	Kanaka Juvva <kanaka.d.juvva@intel.com>,
	Matt Fleming <matt.fleming@intel.com>
Subject: [PATCH 11/11] perf/x86/intel: Enable conflicting event scheduling for CQM
Date: Fri, 14 Nov 2014 21:15:12 +0000	[thread overview]
Message-ID: <1415999712-5850-12-git-send-email-matt@console-pimps.org> (raw)
In-Reply-To: <1415999712-5850-1-git-send-email-matt@console-pimps.org>

From: Matt Fleming <matt.fleming@intel.com>

We can leverage the workqueue that we use for RMID rotation to support
scheduling of conflicting monitoring events. Allowing events that
monitor conflicting things is done at various other places in the perf
subsystem, so there's precedent there.

An example of two conflicting events would be monitoring a cgroup and
simultaneously monitoring a task within that cgroup.

This uses the cache_groups list as a queuing mechanism, where every
event that reaches the front of the list gets the chance to be scheduled
in, possibly descheduling any conflicting events that are running.

Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
 arch/x86/kernel/cpu/perf_event_intel_cqm.c | 132 +++++++++++++++++++----------
 1 file changed, 86 insertions(+), 46 deletions(-)

diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
index df15d28c00e3..4720ba30d503 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
@@ -510,7 +510,6 @@ static unsigned int __rmid_queue_time_ms = RMID_DEFAULT_QUEUE_TIME;
 static bool intel_cqm_rmid_stabilize(bool *available)
 {
 	struct cqm_rmid_entry *entry, *tmp;
-	struct perf_event *event;
 
 	lockdep_assert_held(&cache_mutex);
 
@@ -579,19 +578,9 @@ static bool intel_cqm_rmid_stabilize(bool *available)
 
 		/*
 		 * If we have groups waiting for RMIDs, hand
-		 * them one now.
+		 * them one now provided they don't conflict.
 		 */
-		list_for_each_entry(event, &cache_groups,
-				    hw.cqm_groups_entry) {
-			if (__rmid_valid(event->hw.cqm_rmid))
-				continue;
-
-			intel_cqm_xchg_rmid(event, entry->rmid);
-			entry = NULL;
-			break;
-		}
-
-		if (!entry)
+		if (intel_cqm_sched_in_event(entry->rmid))
 			continue;
 
 		/*
@@ -606,25 +595,75 @@ static bool intel_cqm_rmid_stabilize(bool *available)
 
 /*
  * Pick a victim group and move it to the tail of the group list.
+ * @next: The first group without an RMID
  */
-static struct perf_event *
-__intel_cqm_pick_and_rotate(void)
+static void __intel_cqm_pick_and_rotate(struct perf_event *next)
 {
 	struct perf_event *rotor;
+	unsigned int rmid;
 
 	lockdep_assert_held(&cache_mutex);
-	lockdep_assert_held(&cache_lock);
 
 	rotor = list_first_entry(&cache_groups, struct perf_event,
 				 hw.cqm_groups_entry);
+
+	/*
+	 * The group at the front of the list should always have a valid
+	 * RMID. If it doesn't then no groups have RMIDs assigned and we
+	 * don't need to rotate the list.
+	 */
+	if (next == rotor)
+		return;
+
+	rmid = intel_cqm_xchg_rmid(rotor, INVALID_RMID);
+	__put_rmid(rmid);
+
 	list_rotate_left(&cache_groups);
+}
+
+/*
+ * Deallocate the RMIDs from any events that conflict with @event, and
+ * place them on the back of the group list.
+ */
+static void intel_cqm_sched_out_events(struct perf_event *event)
+{
+	struct perf_event *group, *g;
+	unsigned int rmid;
 
-	return rotor;
+	lockdep_assert_held(&cache_mutex);
+
+	list_for_each_entry_safe(group, g, &cache_groups, hw.cqm_groups_entry) {
+		if (group == event)
+			continue;
+
+		rmid = group->hw.cqm_rmid;
+
+		/*
+		 * Skip events that don't have a valid RMID.
+		 */
+		if (!__rmid_valid(rmid))
+			continue;
+
+		/*
+		 * No conflict? No problem! Leave the event alone.
+		 */
+		if (!__conflict_event(group, event))
+			continue;
+
+		intel_cqm_xchg_rmid(group, INVALID_RMID);
+		__put_rmid(rmid);
+
+		list_move_tail(&group->hw.cqm_groups_entry, &cache_groups);
+	}
 }
 
 /*
  * Attempt to rotate the groups and assign new RMIDs.
  *
+ * We rotate for two reasons,
+ *   1. To handle the scheduling of conflicting events
+ *   2. To recycle RMIDs
+ *
  * Rotating RMIDs is complicated because the hardware doesn't give us
  * any clues.
  *
@@ -644,9 +683,8 @@ __intel_cqm_pick_and_rotate(void)
  */
 static bool __intel_cqm_rmid_rotate(void)
 {
-	struct perf_event *group, *rotor, *start = NULL;
+	struct perf_event *group, *start = NULL;
 	unsigned int nr_needed = 0;
-	unsigned int rmid;
 	bool rotated = false;
 	bool available;
 
@@ -679,7 +717,9 @@ again:
 		goto stabilize;
 
 	/*
-	 * We have more event groups without RMIDs than available RMIDs.
+	 * We have more event groups without RMIDs than available RMIDs,
+	 * or we have event groups that conflict with the ones currently
+	 * scheduled.
 	 *
 	 * We force deallocate the rmid of the group at the head of
 	 * cache_groups. The first event group without an RMID then gets
@@ -689,15 +729,7 @@ again:
 	 * Rotate the cache_groups list so the previous head is now the
 	 * tail.
 	 */
-	rotor = __intel_cqm_pick_and_rotate();
-	rmid = intel_cqm_xchg_rmid(rotor, INVALID_RMID);
-
-	/*
-	 * The group at the front of the list should always have a valid
-	 * RMID. If it doesn't then no groups have RMIDs assigned.
-	 */
-	if (!__rmid_valid(rmid))
-		goto stabilize;
+	__intel_cqm_pick_and_rotate(start);
 
 	/*
 	 * If the rotation is going to succeed, reduce the threshold so
@@ -705,14 +737,14 @@ again:
 	 */
 	if (__rmid_valid(intel_cqm_rotation_rmid)) {
 		intel_cqm_xchg_rmid(start, intel_cqm_rotation_rmid);
-		intel_cqm_rotation_rmid = INVALID_RMID;
+		intel_cqm_rotation_rmid = __get_rmid();
+
+		intel_cqm_sched_out_events(start);
 
 		if (__intel_cqm_threshold)
 			__intel_cqm_threshold--;
 	}
 
-	__put_rmid(rmid);
-
 	rotated = true;
 
 stabilize:
@@ -760,25 +792,37 @@ static void intel_cqm_rmid_rotate(struct work_struct *work)
  *
  * If we're part of a group, we use the group's RMID.
  */
-static int intel_cqm_setup_event(struct perf_event *event,
-				 struct perf_event **group)
+static void intel_cqm_setup_event(struct perf_event *event,
+				  struct perf_event **group)
 {
 	struct perf_event *iter;
+	unsigned int rmid;
+	bool conflict = false;
 
 	list_for_each_entry(iter, &cache_groups, hw.cqm_groups_entry) {
+		rmid = iter->hw.cqm_rmid;
+
 		if (__match_event(iter, event)) {
 			/* All tasks in a group share an RMID */
-			event->hw.cqm_rmid = iter->hw.cqm_rmid;
+			event->hw.cqm_rmid = rmid;
 			*group = iter;
-			return 0;
+			return;
 		}
 
-		if (__conflict_event(iter, event))
-			return -EBUSY;
+		/*
+		 * We only care about conflicts for events that are
+		 * actually scheduled in (and hence have a valid RMID).
+		 */
+		if (__conflict_event(iter, event) && __rmid_valid(rmid))
+			conflict = true;
 	}
 
-	event->hw.cqm_rmid = __get_rmid();
-	return 0;
+	if (conflict)
+		rmid = INVALID_RMID;
+	else
+		rmid = __get_rmid();
+
+	event->hw.cqm_rmid = rmid;
 }
 
 static void intel_cqm_event_read(struct perf_event *event)
@@ -998,7 +1042,6 @@ static int intel_cqm_event_init(struct perf_event *event)
 {
 	struct perf_event *group = NULL;
 	bool rotate = false;
-	int err;
 
 	if (event->attr.type != intel_cqm_pmu.type)
 		return -ENOENT;
@@ -1024,9 +1067,7 @@ static int intel_cqm_event_init(struct perf_event *event)
 	mutex_lock(&cache_mutex);
 
 	/* Will also set rmid */
-	err = intel_cqm_setup_event(event, &group);
-	if (err)
-		goto out;
+	intel_cqm_setup_event(event, &group);
 
 	if (group) {
 		list_add_tail(&event->hw.cqm_group_entry,
@@ -1046,13 +1087,12 @@ static int intel_cqm_event_init(struct perf_event *event)
 			rotate = true;
 	}
 
-out:
 	mutex_unlock(&cache_mutex);
 
 	if (rotate)
 		schedule_delayed_work(&intel_cqm_rmid_work, 0);
 
-	return err;
+	return 0;
 }
 
 EVENT_ATTR_STR(llc_occupancy, intel_cqm_llc, "event=0x01");
-- 
1.9.3


  parent reply	other threads:[~2014-11-14 21:15 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-14 21:15 [PATCH v4 00/11] perf: Intel Cache QoS Monitoring support Matt Fleming
2014-11-14 21:15 ` [PATCH 01/11] perf tools: Parse event per-package info files Matt Fleming
2014-11-14 21:15 ` [PATCH 02/11] perf tools: Implement snapshot event file logic Matt Fleming
2014-11-14 21:15 ` [PATCH 03/11] perf: Make perf_cgroup_from_task() global Matt Fleming
2014-11-14 21:15 ` [PATCH 04/11] perf: Add ->count() function to read per-package counters Matt Fleming
2014-11-14 21:15 ` [PATCH 05/11] perf: Move cgroup init before PMU ->event_init() Matt Fleming
2014-11-14 21:15 ` [PATCH 06/11] x86: Add support for Intel Cache QoS Monitoring (CQM) detection Matt Fleming
2014-11-14 21:15 ` [PATCH 07/11] perf/x86/intel: Add Intel Cache QoS Monitoring support Matt Fleming
2014-11-14 21:15 ` [PATCH 08/11] perf/x86/intel: Implement LRU monitoring ID allocation for CQM Matt Fleming
2014-11-14 21:15 ` [PATCH v4 09/11] perf/x86/intel: Support task events with Intel CQM Matt Fleming
2014-11-14 21:15 ` [PATCH v4 10/11] perf/x86/intel: Perform rotation on Intel CQM RMIDs Matt Fleming
2015-01-06 16:13   ` Peter Zijlstra
2015-01-06 17:17   ` Peter Zijlstra
2015-01-09 12:14     ` Matt Fleming
2015-01-09 13:02       ` Peter Zijlstra
2015-01-09 15:24         ` Matt Fleming
2015-01-09 15:58           ` Peter Zijlstra
2015-01-15 15:31             ` Matt Fleming
2015-01-15 19:37             ` Matt Fleming
2015-01-06 17:36   ` Peter Zijlstra
2015-01-09 12:22     ` Matt Fleming
2015-01-09 12:59       ` Peter Zijlstra
2015-01-07 12:16   ` Peter Zijlstra
2015-01-09 12:55     ` Matt Fleming
2015-01-09 12:58       ` Peter Zijlstra
2015-01-11 10:45         ` Matt Fleming
2014-11-14 21:15 ` Matt Fleming [this message]
2015-01-08 11:49   ` [PATCH 11/11] perf/x86/intel: Enable conflicting event scheduling for CQM Peter Zijlstra
2015-01-09 12:56     ` Matt Fleming
2015-01-08 11:51   ` Peter Zijlstra
2015-01-09 14:27     ` Matt Fleming
2014-11-25 14:55 ` [PATCH v4 00/11] perf: Intel Cache QoS Monitoring support Matt Fleming
2014-12-18  7:59   ` Matt Fleming
  -- strict thread matches above, loose matches on Subject: below --
2014-11-06 12:23 [PATCH v3 " Matt Fleming
2014-11-06 12:23 ` [PATCH 11/11] perf/x86/intel: Enable conflicting event scheduling for CQM Matt Fleming

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1415999712-5850-12-git-send-email-matt@console-pimps.org \
    --to=matt@console-pimps.org \
    --cc=acme@kernel.org \
    --cc=andi@firstfloor.org \
    --cc=hpa@zytor.com \
    --cc=jolsa@redhat.com \
    --cc=kanaka.d.juvva@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=matt.fleming@intel.com \
    --cc=mingo@kernel.org \
    --cc=peterz@infradead.org \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.