Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1543833 > unrolled thread

[PATCH V4 00/14] Cqm2: Intel Cache Monitoring fixes and enhancements

Started byVikas Shivappa <vikas.shivappa@linux.intel.com>
First post2016-12-17 00:20 +0100
Last post2016-12-17 00:20 +0100
Articles 4 on this page of 24 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH V4 00/14] Cqm2: Intel Cache Monitoring fixes and enhancements Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
    [PATCH 03/14] x86/rdt: Add rdt common/cqm compile option Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
    [PATCH 05/14] x86/cqm,perf/core: Cgroup support prepare Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
    [PATCH 13/14] perf/stat: fix bug in handling events in error state Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
    [PATCH 07/14] x86/rdt,cqm: Scheduling support update Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
    [PATCH 02/14] x86/cqm: Remove cqm recycling/conflict handling Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
    [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
      Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Peter Zijlstra <peterz@infradead.org> - 2016-12-23 13:40 +0100
        Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Shivappa Vikas <vikas.shivappa@intel.com> - 2016-12-23 20:40 +0100
          Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Peter Zijlstra <peterz@infradead.org> - 2016-12-23 22:00 +0100
            Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Shivappa Vikas <vikas.shivappa@intel.com> - 2016-12-23 22:50 +0100
            Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Shivappa Vikas <vikas.shivappa@intel.com> - 2016-12-25 03:00 +0100
              Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation David Carrillo-Cisneros <davidcc@google.com> - 2016-12-27 08:20 +0100
              Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Andi Kleen <andi@firstfloor.org> - 2016-12-27 21:10 +0100
                Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Shivappa Vikas <vikas.shivappa@intel.com> - 2016-12-27 21:30 +0100
                  Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation David Carrillo-Cisneros <davidcc@google.com> - 2016-12-27 22:40 +0100
                Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation David Carrillo-Cisneros <davidcc@google.com> - 2016-12-27 22:40 +0100
                  Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Andi Kleen <andi@firstfloor.org> - 2016-12-28 00:20 +0100
                    Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation David Carrillo-Cisneros <davidcc@google.com> - 2016-12-28 02:30 +0100
                      Re: [PATCH 01/14] x86/cqm: Intel Resource Monitoring Documentation Shivappa Vikas <vikas.shivappa@intel.com> - 2016-12-28 21:10 +0100
    [PATCH 06/14] x86/cqm: Add cgroup hierarchical monitoring support Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
    [PATCH 11/14] x86/cqm: Add failure on open and read Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100
      Re: [PATCH 11/14] x86/cqm: Add failure on open and read David Carrillo-Cisneros <davidcc@google.com> - 2016-12-23 13:00 +0100
    [PATCH 08/14] x86/cqm: Add support for monitoring task and cgroup together Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2016-12-17 00:20 +0100

Page 2 of 2 — ← Prev page 1 [2]


#1543844 — [PATCH 06/14] x86/cqm: Add cgroup hierarchical monitoring support

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2016-12-17 00:20 +0100
Subject[PATCH 06/14] x86/cqm: Add cgroup hierarchical monitoring support
Message-ID<sP9Xd-1Cb-57@gated-at.bofh.it>
In reply to#1543833
From: David Carrillo-Cisneros <davidcc@google.com>

Patch adds support for monitoring cgroup hierarchy. The
arch_info that was introduced in the perf_cgroup is used to maintain the
cgroup related rmid and hierarchy information.

Since cgroup supports hierarchical monitoring, a cgroup is always
monitoring for some ancestor. By default root is always monitored with
RMID 0 and hence when any cgroup is first created it always reports data
to the root.  mfa or 'monitor for ancestor' is used to keep track of
this information.  Basically which ancestor the cgroup is actually
monitoring for or has to report the data to.

By default, all cgroup's mfa points to root.
1.event init: When ever a new cgroup x would start to be monitored,
the mfa of the monitored cgroup's descendants point towards the cgroup
x.
2.switch_to: task finds the cgroup its associated with and if the
cgroup itself is being monitored cgroup uses its own rmid(a) else it uses
the rmid of the mfa(b).
3.read: During the read call, the cgroup x just adds the
counts of its descendants who had cgroup x as mfa and were also
monitored(To count the scenario (a) in switch_to).

Locking: cgroup traversal: rcu_readlock.  cgroup->arch_info: css_alloc,
css_free, event terminate, init hold mutex.

Tests: Cgroup monitoring should work. Monitoring multiple cgroups in the
same hierarchy works. monitoring cgroup and a task within same cgroup
doesnt work yet.

Patch modified/refactored by Vikas Shivappa
<vikas.shivappa@linux.intel.com> to support recycling removal.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/events/intel/cqm.c             | 227 +++++++++++++++++++++++++++-----
 arch/x86/include/asm/intel_rdt_common.h |  64 +++++++++
 2 files changed, 257 insertions(+), 34 deletions(-)

diff --git a/arch/x86/events/intel/cqm.c b/arch/x86/events/intel/cqm.c
index 536c8ad..57edbfc 100644
--- a/arch/x86/events/intel/cqm.c
+++ b/arch/x86/events/intel/cqm.c
@@ -85,6 +85,7 @@ struct sample {
 static cpumask_t cqm_cpumask;
 
 struct pkg_data **cqm_pkgs_data;
+struct cgrp_cqm_info cqm_rootcginfo;
 
 #define RMID_VAL_ERROR		(1ULL << 63)
 #define RMID_VAL_UNAVAIL	(1ULL << 62)
@@ -193,6 +194,11 @@ static void __put_rmid(u32 rmid, int domain)
 	list_add_tail(&entry->list, &cqm_pkgs_data[domain]->cqm_rmid_limbo_lru);
 }
 
+static bool is_task_event(struct perf_event *e)
+{
+	return (e->attach_state & PERF_ATTACH_TASK);
+}
+
 static void cqm_cleanup(void)
 {
 	int i;
@@ -209,7 +215,6 @@ static void cqm_cleanup(void)
 	kfree(cqm_pkgs_data);
 }
 
-
 /*
  * Determine if @a and @b measure the same set of tasks.
  *
@@ -224,20 +229,18 @@ static bool __match_event(struct perf_event *a, struct perf_event *b)
 		return false;
 
 #ifdef CONFIG_CGROUP_PERF
-	if (a->cgrp != b->cgrp)
-		return false;
-#endif
-
-	/* If not task event, we're machine wide */
-	if (!(b->attach_state & PERF_ATTACH_TASK))
+	if ((is_cgroup_event(a) && is_cgroup_event(b)) &&
+		(a->cgrp == b->cgrp))
 		return true;
+#endif
 
 	/*
 	 * Events that target same task are placed into the same cache group.
 	 * Mark it as a multi event group, so that we update ->count
 	 * for every event rather than just the group leader later.
 	 */
-	if (a->hw.target == b->hw.target) {
+	if ((is_task_event(a) && is_task_event(b)) &&
+		(a->hw.target == b->hw.target)) {
 		b->hw.is_group_event = true;
 		return true;
 	}
@@ -365,6 +368,63 @@ static void init_mbm_sample(u32 *rmid, u32 evt_type)
 	on_each_cpu_mask(&cqm_cpumask, __intel_mbm_event_init, &rr, 1);
 }
 
+static inline void cqm_enable_mon(struct cgrp_cqm_info *cqm_info, u32 *rmid)
+{
+	if (rmid != NULL) {
+		cqm_info->mon_enabled = true;
+		cqm_info->rmid = rmid;
+	} else {
+		cqm_info->mon_enabled = false;
+		cqm_info->rmid = NULL;
+	}
+}
+
+static void cqm_assign_hier_rmid(struct cgroup_subsys_state *rcss, u32 *rmid)
+{
+	struct cgrp_cqm_info *ccqm_info, *rcqm_info;
+	struct cgroup_subsys_state *pos_css;
+
+	rcu_read_lock();
+
+	rcqm_info = css_to_cqm_info(rcss);
+
+	/* Enable or disable monitoring based on rmid.*/
+	cqm_enable_mon(rcqm_info, rmid);
+
+	pos_css = css_next_descendant_pre(rcss, rcss);
+	while (pos_css) {
+		ccqm_info = css_to_cqm_info(pos_css);
+
+		/*
+		 * Monitoring is being enabled.
+		 * Update the descendents to monitor for you, unless
+		 * they were already monitoring for a descendent of yours.
+		 */
+		if (rmid && (rcqm_info->level > ccqm_info->mfa->level))
+			ccqm_info->mfa = rcqm_info;
+
+		/*
+		 * Monitoring is being disabled.
+		 * Update the descendents who were monitoring for you
+		 * to monitor for the ancestor you were monitoring.
+		 */
+		if (!rmid && (ccqm_info->mfa == rcqm_info))
+			ccqm_info->mfa = rcqm_info->mfa;
+		pos_css = css_next_descendant_pre(pos_css, rcss);
+	}
+	rcu_read_unlock();
+}
+
+static int cqm_assign_rmid(struct perf_event *event, u32 *rmid)
+{
+#ifdef CONFIG_CGROUP_PERF
+	if (is_cgroup_event(event)) {
+		cqm_assign_hier_rmid(&event->cgrp->css, rmid);
+	}
+#endif
+	return 0;
+}
+
 /*
  * Find a group and setup RMID.
  *
@@ -402,11 +462,14 @@ static int intel_cqm_setup_event(struct perf_event *event,
 	return 0;
 }
 
+static u64 cqm_read_subtree(struct perf_event *event, struct rmid_read *rr);
+
 static void intel_cqm_event_read(struct perf_event *event)
 {
-	unsigned long flags;
-	u32 rmid;
-	u64 val;
+	struct rmid_read rr = {
+		.evt_type = event->attr.config,
+		.value = ATOMIC64_INIT(0),
+	};
 
 	/*
 	 * Task events are handled by intel_cqm_event_count().
@@ -414,26 +477,9 @@ static void intel_cqm_event_read(struct perf_event *event)
 	if (event->cpu == -1)
 		return;
 
-	raw_spin_lock_irqsave(&cache_lock, flags);
-	rmid = event->hw.cqm_rmid[pkg_id];
-
-	if (!__rmid_valid(rmid))
-		goto out;
-
-	if (is_mbm_event(event->attr.config))
-		val = rmid_read_mbm(rmid, event->attr.config);
-	else
-		val = __rmid_read(rmid);
-
-	/*
-	 * Ignore this reading on error states and do not update the value.
-	 */
-	if (val & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL))
-		goto out;
+	rr.rmid = ACCESS_ONCE(event->hw.cqm_rmid);
 
-	local64_set(&event->count, val);
-out:
-	raw_spin_unlock_irqrestore(&cache_lock, flags);
+	cqm_read_subtree(event, &rr);
 }
 
 static void __intel_cqm_event_count(void *info)
@@ -545,6 +591,55 @@ static void mbm_hrtimer_init(void)
 	}
 }
 
+static void cqm_mask_call_local(struct rmid_read *rr)
+{
+	if (is_mbm_event(rr->evt_type))
+		__intel_mbm_event_count(rr);
+	else
+		__intel_cqm_event_count(rr);
+}
+
+static inline void
+	delta_local(struct perf_event *event, struct rmid_read *rr, u32 *rmid)
+{
+	atomic64_set(&rr->value, 0);
+	rr->rmid = ACCESS_ONCE(rmid);
+
+	cqm_mask_call_local(rr);
+	local64_add(atomic64_read(&rr->value), &event->count);
+}
+
+/*
+ * Since cgroup follows hierarchy, add the count of
+ *  the descendents who were being monitored as well.
+ */
+static u64 cqm_read_subtree(struct perf_event *event, struct rmid_read *rr)
+{
+#ifdef CONFIG_CGROUP_PERF
+
+	struct cgroup_subsys_state *rcss, *pos_css;
+	struct cgrp_cqm_info *ccqm_info;
+
+	cqm_mask_call_local(rr);
+	local64_set(&event->count, atomic64_read(&(rr->value)));
+
+	if (is_task_event(event))
+		return __perf_event_count(event);
+
+	rcu_read_lock();
+	rcss = &event->cgrp->css;
+	css_for_each_descendant_pre(pos_css, rcss) {
+		ccqm_info = (css_to_cqm_info(pos_css));
+
+		/* Add the descendent 'monitored cgroup' counts */
+		if (pos_css != rcss && ccqm_info->mon_enabled)
+			delta_local(event, rr, ccqm_info->rmid);
+	}
+	rcu_read_unlock();
+#endif
+	return __perf_event_count(event);
+}
+
 static u64 intel_cqm_event_count(struct perf_event *event)
 {
 	struct rmid_read rr = {
@@ -603,7 +698,7 @@ void alloc_needed_pkg_rmid(u32 *cqm_rmid)
 	if (WARN_ON(!cqm_rmid))
 		return;
 
-	if (cqm_rmid[pkg_id])
+	if (cqm_rmid == cqm_rootcginfo.rmid || cqm_rmid[pkg_id])
 		return;
 
 	raw_spin_lock_irqsave(&cache_lock, flags);
@@ -661,9 +756,11 @@ static int intel_cqm_event_add(struct perf_event *event, int mode)
 			__put_rmid(rmid[d], d);
 	}
 	kfree(event->hw.cqm_rmid);
+	cqm_assign_rmid(event, NULL);
 	list_del(&event->hw.cqm_groups_entry);
 }
-static void intel_cqm_event_destroy(struct perf_event *event)
+
+static void intel_cqm_event_terminate(struct perf_event *event)
 {
 	struct perf_event *group_other = NULL;
 	unsigned long flags;
@@ -917,6 +1014,7 @@ static int intel_cqm_event_init(struct perf_event *event)
 	.attr_groups	     = intel_cqm_attr_groups,
 	.task_ctx_nr	     = perf_sw_context,
 	.event_init	     = intel_cqm_event_init,
+	.event_terminate     = intel_cqm_event_terminate,
 	.add		     = intel_cqm_event_add,
 	.del		     = intel_cqm_event_stop,
 	.start		     = intel_cqm_event_start,
@@ -924,12 +1022,67 @@ static int intel_cqm_event_init(struct perf_event *event)
 	.read		     = intel_cqm_event_read,
 	.count		     = intel_cqm_event_count,
 };
+
 #ifdef CONFIG_CGROUP_PERF
 int perf_cgroup_arch_css_alloc(struct cgroup_subsys_state *parent_css,
 				      struct cgroup_subsys_state *new_css)
-{}
+{
+	struct cgrp_cqm_info *cqm_info, *pcqm_info;
+	struct perf_cgroup *new_cgrp;
+
+	if (!parent_css) {
+		cqm_rootcginfo.level = 0;
+
+		cqm_rootcginfo.mon_enabled = true;
+		cqm_rootcginfo.cont_mon = true;
+		cqm_rootcginfo.mfa = NULL;
+		INIT_LIST_HEAD(&cqm_rootcginfo.tskmon_rlist);
+
+		if (new_css) {
+			new_cgrp = css_to_perf_cgroup(new_css);
+			new_cgrp->arch_info = &cqm_rootcginfo;
+		}
+		return 0;
+	}
+
+	mutex_lock(&cache_mutex);
+
+	new_cgrp = css_to_perf_cgroup(new_css);
+
+	cqm_info = kzalloc(sizeof(struct cgrp_cqm_info), GFP_KERNEL);
+	if (!cqm_info) {
+		mutex_unlock(&cache_mutex);
+		return -ENOMEM;
+	}
+
+	pcqm_info = (css_to_cqm_info(parent_css));
+	cqm_info->level = pcqm_info->level + 1;
+	cqm_info->rmid = pcqm_info->rmid;
+
+	cqm_info->cont_mon = false;
+	cqm_info->mon_enabled = false;
+	INIT_LIST_HEAD(&cqm_info->tskmon_rlist);
+	if (!pcqm_info->mfa)
+		cqm_info->mfa = pcqm_info;
+	else
+		cqm_info->mfa = pcqm_info->mfa;
+
+	new_cgrp->arch_info = cqm_info;
+	mutex_unlock(&cache_mutex);
+
+	return 0;
+}
+
 void perf_cgroup_arch_css_free(struct cgroup_subsys_state *css)
-{}
+{
+	struct perf_cgroup *cgrp = css_to_perf_cgroup(css);
+
+	mutex_lock(&cache_mutex);
+	kfree(cgrp_to_cqm_info(cgrp));
+	cgrp->arch_info = NULL;
+	mutex_unlock(&cache_mutex);
+}
+
 void perf_cgroup_arch_attach(struct cgroup_taskset *tset)
 {}
 int perf_cgroup_arch_can_attach(struct cgroup_taskset *tset)
@@ -1053,6 +1206,12 @@ static int pkg_data_init_cpu(int cpu)
 	entry = __rmid_entry(0, curr_pkgid);
 	list_del(&entry->list);
 
+	cqm_rootcginfo.rmid = kzalloc(sizeof(u32) * cqm_socket_max, GFP_KERNEL);
+	if (!cqm_rootcginfo.rmid) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	return 0;
 fail:
 	kfree(ccqm_rmid_ptrs);
diff --git a/arch/x86/include/asm/intel_rdt_common.h b/arch/x86/include/asm/intel_rdt_common.h
index b31081b..e11ed5e 100644
--- a/arch/x86/include/asm/intel_rdt_common.h
+++ b/arch/x86/include/asm/intel_rdt_common.h
@@ -24,4 +24,68 @@ struct intel_pqr_state {
 
 DECLARE_PER_CPU(struct intel_pqr_state, pqr_state);
 
+/**
+ * struct cgrp_cqm_info - perf_event cgroup metadata for cqm
+ * @cont_mon     Continuous monitoring flag
+ * @mon_enabled  Whether monitoring is enabled
+ * @level        Level in the cgroup tree. Root is level 0.
+ * @rmid        The rmids of the cgroup.
+ * @mfa          'Monitoring for ancestor' points to the cqm_info
+ *  of the ancestor the cgroup is monitoring for. 'Monitoring for ancestor'
+ *  means you will use an ancestors RMID at sched_in if you are
+ *  not monitoring yourself.
+ *
+ *  Due to the hierarchical nature of cgroups, every cgroup just
+ *  monitors for the 'nearest monitored ancestor' at all times.
+ *  Since root cgroup is always monitored, all descendents
+ *  at boot time monitor for root and hence all mfa points to root except
+ *  for root->mfa which is NULL.
+ *  1. RMID setup: When cgroup x start monitoring:
+ *    for each descendent y, if y's mfa->level < x->level, then
+ *    y->mfa = x. (Where level of root node = 0...)
+ *  2. sched_in: During sched_in for x
+ *    if (x->mon_enabled) choose x->rmid
+ *    else choose x->mfa->rmid.
+ *  3. read: for each descendent of cgroup x
+ *     if (x->monitored) count += rmid_read(x->rmid).
+ *  4. evt_destroy: for each descendent y of x, if (y->mfa == x) then
+ *     y->mfa = x->mfa. Meaning if any descendent was monitoring for x,
+ *     set that descendent to monitor for the cgroup which x was monitoring for.
+ *
+ * @tskmon_rlist List of tasks being monitored in the cgroup
+ *  When a task which belongs to a cgroup x is being monitored, it always uses
+ *  its own task->rmid even if cgroup x is monitored during sched_in.
+ *  To account for the counts of such tasks, cgroup keeps this list
+ *  and parses it during read.
+ *
+ *  Perf handles hierarchy for other events, but because RMIDs are per pkg
+ *  this is handled here.
+*/
+struct cgrp_cqm_info {
+	bool cont_mon;
+	bool mon_enabled;
+	int level;
+	u32 *rmid;
+	struct cgrp_cqm_info *mfa;
+	struct list_head tskmon_rlist;
+};
+
+struct tsk_rmid_entry {
+	u32 *rmid;
+	struct list_head list;
+};
+
+#ifdef CONFIG_CGROUP_PERF
+
+# define css_to_perf_cgroup(css_) container_of(css_, struct perf_cgroup, css)
+# define cgrp_to_cqm_info(cgrp_) ((struct cgrp_cqm_info *)cgrp_->arch_info)
+# define css_to_cqm_info(css_) cgrp_to_cqm_info(css_to_perf_cgroup(css_))
+
+#else
+
+# define css_to_perf_cgroup(css_) NULL
+# define cgrp_to_cqm_info(cgrp_) NULL
+# define css_to_cqm_info(css_) NULL
+
+#endif
 #endif /* _ASM_X86_INTEL_RDT_COMMON_H */
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1543845 — [PATCH 11/14] x86/cqm: Add failure on open and read

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2016-12-17 00:20 +0100
Subject[PATCH 11/14] x86/cqm: Add failure on open and read
Message-ID<sP9Xc-1Cb-39@gated-at.bofh.it>
In reply to#1543833
To provide reliable output to the user, cqm throws error when it does
not have enough RMIDs to monitor depending upon the mode user choses.
This also takes care to not overuse RMIDs. Default is LAZY mode.

NOLAZY mode: This patch adds a file mon_mask in the perf_cgroup which
indicates the packages which the user wants guaranteed monitoring. For
such cgroup events RMIDs are assigned at event create and we fail if
enough RMIDs are not present. This is basically a NOLAZY allocation of
RMIDs. This mode can be used in real time scenarios where user is sure
that tasks that are monitored are scheduled.

LAZY mode: If user did not enable the NOLAZY mode, RMIDs are allocated
only when tasks are actually scheduled. Upon failure to obtain RMIDs it
indicates a failure in read. Typical use case for this mode could be to
start monitoring cgroups which still donot have any tasks in them and
such cgroups are part of large number of cgroups which are monitored -
that way we donot overuse RMIDs.

Patch is based on David Carrillo-Cisneros <davidcc@google.com> patches
in cqm2 series.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/events/intel/cqm.c             | 145 +++++++++++++++++++++++++++++---
 arch/x86/events/intel/cqm.h             |   1 +
 arch/x86/include/asm/intel_rdt_common.h |   7 +-
 3 files changed, 141 insertions(+), 12 deletions(-)

diff --git a/arch/x86/events/intel/cqm.c b/arch/x86/events/intel/cqm.c
index 85162aa..e0d4017 100644
--- a/arch/x86/events/intel/cqm.c
+++ b/arch/x86/events/intel/cqm.c
@@ -78,6 +78,11 @@ struct sample {
  */
 static cpumask_t cqm_cpumask;
 
+/*
+ * Mask of online sockets.
+ */
+static cpumask_t cqm_pkgmask;
+
 struct pkg_data **cqm_pkgs_data;
 struct cgrp_cqm_info cqm_rootcginfo;
 
@@ -110,6 +115,14 @@ bool __rmid_valid(u32 rmid)
 	return true;
 }
 
+static inline bool __rmid_valid_raw(u32 rmid)
+{
+	if (rmid > cqm_max_rmid)
+		return false;
+
+	return true;
+}
+
 static u64 __rmid_read(u32 rmid)
 {
 	u64 val;
@@ -159,16 +172,19 @@ u32 __get_rmid(int domain)
 {
 	struct list_head *cqm_flist;
 	struct cqm_rmid_entry *entry;
+	struct pkg_data *pdata;
 
 	lockdep_assert_held(&cache_lock);
 
-	cqm_flist = &cqm_pkgs_data[domain]->cqm_rmid_free_lru;
+	pdata = cqm_pkgs_data[domain];
+	cqm_flist = &pdata->cqm_rmid_free_lru;
 
 	if (list_empty(cqm_flist))
 		return INVALID_RMID;
 
 	entry = list_first_entry(cqm_flist, struct cqm_rmid_entry, list);
 	list_del(&entry->list);
+	pdata->rmid_used_count++;
 
 	return entry->rmid;
 }
@@ -344,6 +360,7 @@ static void __intel_cqm_rmid_reuse(void)
 		 */
 		list_del(&entry->list);
 		list_add_tail(&entry->list, flist);
+		pdata->rmid_used_count--;
 	}
 
 end:
@@ -607,6 +624,33 @@ static int cqm_assign_rmid(struct perf_event *event, u32 *rmid)
 	return 0;
 }
 
+static inline int check_min_rmids(struct cgrp_cqm_info *cqm_info)
+{
+	int pkg = cpumask_first_and(&cqm_info->mon_mask, &cqm_pkgmask);
+
+	for (; pkg < nr_cpu_ids;
+	     pkg = cpumask_next_and(pkg, &cqm_info->mon_mask, &cqm_pkgmask)) {
+		if (cqm_pkgs_data[pkg]->rmid_used_count >= cqm_max_rmid)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline void alloc_min_rmids(struct cgrp_cqm_info *cqm_info)
+{
+	int pkg = cpumask_first_and(&cqm_info->mon_mask, &cqm_pkgmask);
+	u32 rmid;
+
+	for ( ; pkg < nr_cpu_ids;
+	     pkg = cpumask_next_and(pkg, &cqm_info->mon_mask, &cqm_pkgmask)) {
+
+		rmid = __get_rmid(pkg);
+		if (__rmid_valid(rmid))
+			cqm_info->rmid[pkg] = rmid;
+	}
+}
+
 /*
  * Find a group and setup RMID.
  *
@@ -642,6 +686,14 @@ static int intel_cqm_setup_event(struct perf_event *event,
 			event->hw.cqm_rmid = cqm_info->rmid;
 			return 0;
 		}
+
+		/*
+		 * For cgroups which must have RMIDs check if enough
+		 * RMIDs are available.
+		 */
+		if (cpumask_weight(&cqm_info->mon_mask) &&
+		    check_min_rmids(cqm_info))
+			return -EINVAL;
 	}
 #endif
 
@@ -656,6 +708,11 @@ static int intel_cqm_setup_event(struct perf_event *event,
 
 	cqm_assign_rmid(event, event->hw.cqm_rmid);
 
+#ifdef CONFIG_CGROUP_PERF
+	if (event->cgrp && cpumask_weight(&cqm_info->mon_mask))
+		alloc_min_rmids(cqm_info);
+#endif
+
 	return 0;
 }
 
@@ -896,16 +953,16 @@ static u64 intel_cqm_event_count(struct perf_event *event)
 	return __perf_event_count(event);
 }
 
-void alloc_needed_pkg_rmid(u32 *cqm_rmid)
+u32 alloc_needed_pkg_rmid(u32 *cqm_rmid)
 {
 	unsigned long flags;
 	u32 rmid;
 
 	if (WARN_ON(!cqm_rmid))
-		return;
+		return -EINVAL;
 
 	if (cqm_rmid == cqm_rootcginfo.rmid || cqm_rmid[pkg_id])
-		return;
+		return 0;
 
 	raw_spin_lock_irqsave(&cache_lock, flags);
 
@@ -914,6 +971,8 @@ void alloc_needed_pkg_rmid(u32 *cqm_rmid)
 		cqm_rmid[pkg_id] = rmid;
 
 	raw_spin_unlock_irqrestore(&cache_lock, flags);
+
+	return rmid;
 }
 
 static void intel_cqm_event_start(struct perf_event *event, int mode)
@@ -925,10 +984,8 @@ static void intel_cqm_event_start(struct perf_event *event, int mode)
 
 	event->hw.cqm_state &= ~PERF_HES_STOPPED;
 
-	if (is_task_event(event)) {
-		alloc_needed_pkg_rmid(event->hw.cqm_rmid);
+	if (is_task_event(event))
 		state->next_task_rmid = event->hw.cqm_rmid[pkg_id];
-	}
 }
 
 static void intel_cqm_event_stop(struct perf_event *event, int mode)
@@ -944,11 +1001,19 @@ static void intel_cqm_event_stop(struct perf_event *event, int mode)
 
 static int intel_cqm_event_add(struct perf_event *event, int mode)
 {
+	u32 rmid;
+
 	event->hw.cqm_state = PERF_HES_STOPPED;
 
-	if ((mode & PERF_EF_START))
+	/*
+	 * If Lazy RMID alloc fails indicate the error to the user.
+	 */
+	if ((mode & PERF_EF_START)) {
+		rmid = alloc_needed_pkg_rmid(event->hw.cqm_rmid);
+		if (!__rmid_valid_raw(rmid))
+			return -EINVAL;
 		intel_cqm_event_start(event, mode);
-
+	}
 	return 0;
 }
 
@@ -1426,12 +1491,67 @@ static int cqm_cont_monitoring_write_u64(struct cgroup_subsys_state *css,
 	return ret;
 }
 
+static int cqm_mon_mask_seq_show(struct seq_file *sf, void *v)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&cache_lock, flags);
+	seq_printf(sf, "%*pbl\n",
+		    cpumask_pr_args(&css_to_cqm_info(seq_css(sf))->mon_mask));
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+
+	return 0;
+}
+
+static ssize_t cqm_mon_mask_write(struct kernfs_open_file *of,
+				    char *buf, size_t nbytes, loff_t off)
+{
+	cpumask_var_t tmp_cpus, tmp_cpus1;
+	struct cgrp_cqm_info *cqm_info;
+	unsigned long flags;
+	int ret = 0;
+
+	buf = strstrip(buf);
+
+	if (!zalloc_cpumask_var(&tmp_cpus, GFP_KERNEL) ||
+		!zalloc_cpumask_var(&tmp_cpus1, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = cpulist_parse(buf, tmp_cpus);
+	if (ret)
+		goto out;
+
+	if (cpumask_andnot(tmp_cpus1, tmp_cpus, &cqm_pkgmask)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	raw_spin_lock_irqsave(&cache_lock, flags);
+	cqm_info = css_to_cqm_info(of_css(of));
+	cpumask_copy(&cqm_info->mon_mask, tmp_cpus);
+	raw_spin_unlock_irqrestore(&cache_lock, flags);
+
+out:
+	free_cpumask_var(tmp_cpus);
+	free_cpumask_var(tmp_cpus1);
+
+	return ret ?: nbytes;
+}
+
 struct cftype perf_event_cgrp_arch_subsys_cftypes[] = {
 	{
 		.name = "cqm_cont_monitoring",
 		.read_u64 = cqm_cont_monitoring_read_u64,
 		.write_u64 = cqm_cont_monitoring_write_u64,
 	},
+	{
+		.name = "cqm_mon_mask",
+		.seq_show = cqm_mon_mask_seq_show,
+		.write = cqm_mon_mask_write,
+		.max_write_len = (100U + 6 * NR_CPUS),
+	},
 
 	{}	/* terminate */
 };
@@ -1449,8 +1569,10 @@ static inline void cqm_pick_event_reader(int cpu)
 
 	/* First online cpu in package becomes the reader */
 	reader = cpumask_any_and(&cqm_cpumask, topology_core_cpumask(cpu));
-	if (reader >= nr_cpu_ids)
+	if (reader >= nr_cpu_ids) {
 		cpumask_set_cpu(cpu, &cqm_cpumask);
+		cpumask_set_cpu(pkg_id, &cqm_pkgmask);
+	}
 }
 
 static int intel_cqm_cpu_starting(unsigned int cpu)
@@ -1482,6 +1604,8 @@ static int intel_cqm_cpu_exit(unsigned int cpu)
 
 	if (target < nr_cpu_ids)
 		cpumask_set_cpu(target, &cqm_cpumask);
+	else
+		cpumask_clear_cpu(pkg_id, &cqm_pkgmask);
 
 	return 0;
 }
@@ -1562,6 +1686,7 @@ static int pkg_data_init_cpu(int cpu)
 	 */
 	entry = __rmid_entry(0, curr_pkgid);
 	list_del(&entry->list);
+	pkg_data->rmid_used_count++;
 
 	cqm_rootcginfo.rmid = kzalloc(sizeof(u32) * cqm_socket_max, GFP_KERNEL);
 	if (!cqm_rootcginfo.rmid) {
diff --git a/arch/x86/events/intel/cqm.h b/arch/x86/events/intel/cqm.h
index 4415497..063956d 100644
--- a/arch/x86/events/intel/cqm.h
+++ b/arch/x86/events/intel/cqm.h
@@ -32,6 +32,7 @@ struct pkg_data {
 	atomic_t		reuse_scheduled;
 
 	int			rmid_work_cpu;
+	int			rmid_used_count;
 };
 #endif
 #endif
diff --git a/arch/x86/include/asm/intel_rdt_common.h b/arch/x86/include/asm/intel_rdt_common.h
index 6424322..39fa4fb 100644
--- a/arch/x86/include/asm/intel_rdt_common.h
+++ b/arch/x86/include/asm/intel_rdt_common.h
@@ -29,7 +29,7 @@ struct intel_pqr_state {
 
 u32 __get_rmid(int domain);
 bool __rmid_valid(u32 rmid);
-void alloc_needed_pkg_rmid(u32 *cqm_rmid);
+u32 alloc_needed_pkg_rmid(u32 *cqm_rmid);
 struct cgrp_cqm_info *cqminfo_from_tsk(struct task_struct *tsk);
 
 extern struct cgrp_cqm_info cqm_rootcginfo;
@@ -42,7 +42,9 @@ struct intel_pqr_state {
  * @cont_mon     Continuous monitoring flag
  * @mon_enabled  Whether monitoring is enabled
  * @level        Level in the cgroup tree. Root is level 0.
- * @rmid        The rmids of the cgroup.
+ * @rmid         The rmids of the cgroup.
+ * @mon_mask     Package Mask to indicate packages which must
+ *  must have RMIDs(guaranteed cqm monitoring).
  * @mfa          'Monitoring for ancestor' points to the cqm_info
  *  of the ancestor the cgroup is monitoring for. 'Monitoring for ancestor'
  *  means you will use an ancestors RMID at sched_in if you are
@@ -79,6 +81,7 @@ struct cgrp_cqm_info {
 	bool mon_enabled;
 	int level;
 	u32 *rmid;
+	struct cpumask mon_mask;
 	struct cgrp_cqm_info *mfa;
 	struct list_head tskmon_rlist;
 };
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1546842 — Re: [PATCH 11/14] x86/cqm: Add failure on open and read

FromDavid Carrillo-Cisneros <davidcc@google.com>
Date2016-12-23 13:00 +0100
SubjectRe: [PATCH 11/14] x86/cqm: Add failure on open and read
Message-ID<sRwFX-6pi-13@gated-at.bofh.it>
In reply to#1543845
On Fri, Dec 16, 2016 at 3:13 PM, Vikas Shivappa
<vikas.shivappa@linux.intel.com> wrote:
> To provide reliable output to the user, cqm throws error when it does
> not have enough RMIDs to monitor depending upon the mode user choses.
> This also takes care to not overuse RMIDs. Default is LAZY mode.
>
> NOLAZY mode: This patch adds a file mon_mask in the perf_cgroup which
> indicates the packages which the user wants guaranteed monitoring. For
> such cgroup events RMIDs are assigned at event create and we fail if
> enough RMIDs are not present. This is basically a NOLAZY allocation of
> RMIDs. This mode can be used in real time scenarios where user is sure
> that tasks that are monitored are scheduled.
>
> LAZY mode: If user did not enable the NOLAZY mode, RMIDs are allocated
> only when tasks are actually scheduled. Upon failure to obtain RMIDs it
> indicates a failure in read. Typical use case for this mode could be to
> start monitoring cgroups which still donot have any tasks in them and
> such cgroups are part of large number of cgroups which are monitored -
> that way we donot overuse RMIDs.
>

The proposed interface is:
  - a global boolean cqm_cont_monitoring.
  - a per-package boolean in the bitfield cqm_mon_mask.

So, for each package there will be four states, yet one of them is
not meaningful:

cont_monitoring, cqm_mon_mask[p]: meaning
------------------------------------------
0, 0 : off
0, 1 : off but reserve a RMID that is not going to be used?
1, 0 : on with NOLAZY
1, 1 : on with LAZY

the case 0,1 is problematic.

How can new cases be added in the future? another file? What's wrong
with having a
pkg0_flags;pkg1_flags;...;pkgn_flags
cont_monitoring file, that is more akin to the RDT Allocation format.
(There is a parser function and implementation for that format in v3
of my CMT series).



Below is a full discussion about how many per-package configuration states are
useful now and if/when RMID rotation is added.


There are two types of error sources introduced by not having a RMID
when one is needed:
  - E_read : Introduced into the measurement when stealing a
    RMID with non-zero occupancy.
  - E_sched: Introduced when a thread runs but no RMID is available for it.

A user may have two tolerance levels to errors that determine if an
event can be read
or read should fail:
  - NoTol  : No tolerance to error at all. If there has been any type
of E_read or
    E_sched in the past, read must give an error.
  - SomeTol: Tolerate _some_ error. It can be defined in terms of
time, magnitude or both.
    As an example, in v3 of my CMT patches, I assumed a user would
tolerate an error that
    occurred more that an arbitrarily chosen time in the past. The
minimum criterion is that
    there should at least be a RMID at the time of read.

The driver can follow two types of RMID allocation policies:
  - NoLazy: reserve RMID as soon as user starts monitoring (when event
is created or
    cont_monitoring is set). This policy introduces no error.
  - Lazy: reserve RMID first time a task is sched in. May introduce E_sched
    if no RMID available on sched in.

and three RMID deallocation policies:
  - Fixed: RMID can never be stolen. This policy introduces no error
into the measurement.
  - Reuse: RMID can be stolen when not scheduled thread is using it
and it has non-zero
    occupancy. This policy may introduce E_sched when no RMID available on
    sched_in after an incidence of reuse.
  - Steal: RMID can be stolen any time. This policy introduces both E_sched and
    E_read errors into the measurement (this is the so-called RMID rotation).

Therefore there are three possible risks levels:
  - No Risk: possible with NoLazy & Fixed
  - Risk of E_sched: possible with either NoLazy & Reuse or Lazy &
Fixed  or Lazy & Reuse
  - Risk of E_sched and E_read: possible with NoLazy & Steal or Lazy & Steal
Notes:
  a) E_read only is impossible.
  b) In "No Risk" a RMID must be allocated in advance and never
released, even if unused
      (e.g. a task may run only in one package but we allocade RMID in
all of them).
  c) For the E_sched risk, Lazy & Reuse give the highest RMID flexibility.
  d) For the E_read and E_sched risk, NoLazy & Steal give the highest
RMID flexibility.


Combining all three criteria, the possible configuration modes that
make sense are:
  1) No monitoring.
  2) NoLazy & Fixed & NoTol. RMID is allocated when event is created
(or cont_monitoring is set).
      No possible error. May waste RMIDs.
  3) Lazy & Reusable & NoTol. RMID are allocated as needed, taken away
when unused.
      May fail to find RMID if there is RMID contention, once it fail,
the event/cgroup must be in error state.
  4) Lazy & Reusable & SomeTol. Similar to (3) but event/cgroup
recovers from error state if a
      recovered RMID stays valid for long enough.
  5 and 6) Lazy allocation & Stealable with and without Tol . RMID can
be stolen even if non-empty
     or in use.

Q. Which modes are useful?

Stephane and I see a clear use for (2). Users of cont_monitoring look
to avoid error and may tolerate
wasted RMIDs. It has the advantage that allows to fail on event
creation (or when cont_monitoring is set).
This is the same mode introduced with NOLAZY in cqm_mon_mask in this patch.

Mode (3) can be viewed as an optimistic approach to RMID allocation
that allows more concurrent users
than 2 when cache occupancy drops quickly and/or task/cgroups manifest
strong package locality.
It still guarantees exact measurements (within hw constraints) when
read succeeds.

Mode (4) is more useful than 3 _if_ it can be assumed that the system
will replace enough cache lines
before the tolerance time expires (otherwise it reads just garbage).
Yet, it's not clear to me how often this assumption is valid.

Modes (5) and (6) require RMID rotation, so they wouldn't be part of
this patch series.


> +static ssize_t cqm_mon_mask_write(struct kernfs_open_file *of,
> +                                   char *buf, size_t nbytes, loff_t off)
> +{
> +       cpumask_var_t tmp_cpus, tmp_cpus1;
> +       struct cgrp_cqm_info *cqm_info;
> +       unsigned long flags;
> +       int ret = 0;
> +
> +       buf = strstrip(buf);
> +
> +       if (!zalloc_cpumask_var(&tmp_cpus, GFP_KERNEL) ||
> +               !zalloc_cpumask_var(&tmp_cpus1, GFP_KERNEL)) {
> +               ret = -ENOMEM;
> +               goto out;
> +       }
> +
> +       ret = cpulist_parse(buf, tmp_cpus);
> +       if (ret)
> +               goto out;
> +
> +       if (cpumask_andnot(tmp_cpus1, tmp_cpus, &cqm_pkgmask)) {
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       raw_spin_lock_irqsave(&cache_lock, flags);
> +       cqm_info = css_to_cqm_info(of_css(of));
> +       cpumask_copy(&cqm_info->mon_mask, tmp_cpus);
> +       raw_spin_unlock_irqrestore(&cache_lock, flags);

So this only copies the mask so that it can be used for the next
cgroup event in intel_cqm_setup_event?
That defeats the purpose of a NON_LAZY cont_monitoring.

There is no need to create a new cgroup file only to provide a non-lazy event;
such flag could be passed in perf_event_attr::pinned or a config field.

[toc] | [prev] | [next] | [standalone]


#1543847 — [PATCH 08/14] x86/cqm: Add support for monitoring task and cgroup together

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2016-12-17 00:20 +0100
Subject[PATCH 08/14] x86/cqm: Add support for monitoring task and cgroup together
Message-ID<sP9Xc-1Cb-41@gated-at.bofh.it>
In reply to#1543833
From: David Carrillo-Cisneros <davidcc@google.com>

This patch adds support to monitor a cgroup x and a task p1
when p1 is part of cgroup x. Since we cannot write two RMIDs during
sched in the driver handles this.

This patch introduces a u32 *rmid in the task_struck which keeps track
of the RMIDs associated with the task.  There is also a list in the
arch_info of perf_cgroup called taskmon_list which keeps track of tasks
in the cgroup that are monitored.

The taskmon_list is modified in 2 scenarios.
- at event_init of task p1 which is part of a cgroup, add the p1 to the
cgroup->tskmon_list. At event_destroy delete the task from the list.
- at the time of task move from cgrp x to a cgp y, if task was monitored
remove the task from the cgrp x tskmon_list and add it the cgrp y
tskmon_list.

sched in: When the task p1 is scheduled in, we write the task RMID in
the PQR_ASSOC MSR

read(for task p1): As any other cqm task event

read(for the cgroup x): When counting for cgroup, the taskmon list is
traversed and the corresponding RMID counts are added.

Tests: Monitoring a cgroup x and a task with in the cgroup x should
work.

Patch modified/refactored by Vikas Shivappa
<vikas.shivappa@linux.intel.com> to support recycling removal,
changes in the arch_info.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/events/intel/cqm.c | 137 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/sched.h       |   3 +
 2 files changed, 137 insertions(+), 3 deletions(-)

diff --git a/arch/x86/events/intel/cqm.c b/arch/x86/events/intel/cqm.c
index 506e187..8017886 100644
--- a/arch/x86/events/intel/cqm.c
+++ b/arch/x86/events/intel/cqm.c
@@ -362,6 +362,36 @@ static void init_mbm_sample(u32 *rmid, u32 evt_type)
 	on_each_cpu_mask(&cqm_cpumask, __intel_mbm_event_init, &rr, 1);
 }
 
+static inline int add_cgrp_tskmon_entry(u32 *rmid, struct list_head *l)
+{
+	struct tsk_rmid_entry *entry;
+
+	entry = kzalloc(sizeof(struct tsk_rmid_entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&entry->list);
+	entry->rmid = rmid;
+
+	list_add_tail(&entry->list, l);
+
+	return 0;
+}
+
+static inline void del_cgrp_tskmon_entry(u32 *rmid, struct list_head *l)
+{
+	struct tsk_rmid_entry *entry = NULL, *tmp1;
+
+	list_for_each_entry_safe(entry, tmp1, l, list) {
+		if (entry->rmid == rmid) {
+
+			list_del(&entry->list);
+			kfree(entry);
+			break;
+		}
+	}
+}
+
 #ifdef CONFIG_CGROUP_PERF
 struct cgrp_cqm_info *cqminfo_from_tsk(struct task_struct *tsk)
 {
@@ -379,6 +409,49 @@ struct cgrp_cqm_info *cqminfo_from_tsk(struct task_struct *tsk)
 }
 #endif
 
+static inline void
+	cgrp_tskmon_update(struct task_struct *tsk, u32 *rmid, bool ena)
+{
+	struct cgrp_cqm_info *ccinfo = NULL;
+
+#ifdef CONFIG_CGROUP_PERF
+	ccinfo = cqminfo_from_tsk(tsk);
+#endif
+	if (!ccinfo)
+		return;
+
+	if (ena)
+		add_cgrp_tskmon_entry(rmid, &ccinfo->tskmon_rlist);
+	else
+		del_cgrp_tskmon_entry(rmid, &ccinfo->tskmon_rlist);
+}
+
+static int cqm_assign_task_rmid(struct perf_event *event, u32 *rmid)
+{
+	struct task_struct *tsk;
+	int ret = 0;
+
+	rcu_read_lock();
+	tsk = event->hw.target;
+	if (pid_alive(tsk)) {
+		get_task_struct(tsk);
+
+		if (rmid != NULL)
+			cgrp_tskmon_update(tsk, rmid, true);
+		else
+			cgrp_tskmon_update(tsk, tsk->rmid, false);
+
+		tsk->rmid = rmid;
+
+		put_task_struct(tsk);
+	} else {
+		ret = -EINVAL;
+	}
+	rcu_read_unlock();
+
+	return ret;
+}
+
 static inline void cqm_enable_mon(struct cgrp_cqm_info *cqm_info, u32 *rmid)
 {
 	if (rmid != NULL) {
@@ -428,8 +501,12 @@ static void cqm_assign_hier_rmid(struct cgroup_subsys_state *rcss, u32 *rmid)
 
 static int cqm_assign_rmid(struct perf_event *event, u32 *rmid)
 {
+	if (is_task_event(event)) {
+		if (cqm_assign_task_rmid(event, rmid))
+			return -EINVAL;
+	}
 #ifdef CONFIG_CGROUP_PERF
-	if (is_cgroup_event(event)) {
+	else if (is_cgroup_event(event)) {
 		cqm_assign_hier_rmid(&event->cgrp->css, rmid);
 	}
 #endif
@@ -630,6 +707,8 @@ static u64 cqm_read_subtree(struct perf_event *event, struct rmid_read *rr)
 
 	struct cgroup_subsys_state *rcss, *pos_css;
 	struct cgrp_cqm_info *ccqm_info;
+	struct tsk_rmid_entry *entry;
+	struct list_head *l;
 
 	cqm_mask_call_local(rr);
 	local64_set(&event->count, atomic64_read(&(rr->value)));
@@ -645,6 +724,13 @@ static u64 cqm_read_subtree(struct perf_event *event, struct rmid_read *rr)
 		/* Add the descendent 'monitored cgroup' counts */
 		if (pos_css != rcss && ccqm_info->mon_enabled)
 			delta_local(event, rr, ccqm_info->rmid);
+
+		/* Add your and descendent 'monitored task' counts */
+		if (!list_empty(&ccqm_info->tskmon_rlist)) {
+			l = &ccqm_info->tskmon_rlist;
+			list_for_each_entry(entry, l, list)
+				delta_local(event, rr, entry->rmid);
+		}
 	}
 	rcu_read_unlock();
 #endif
@@ -1095,10 +1181,55 @@ void perf_cgroup_arch_css_free(struct cgroup_subsys_state *css)
 	mutex_unlock(&cache_mutex);
 }
 
+/*
+ * Called while attaching/detaching task to a cgroup.
+ */
+static bool is_task_monitored(struct task_struct *tsk)
+{
+	return (tsk->rmid != NULL);
+}
+
 void perf_cgroup_arch_attach(struct cgroup_taskset *tset)
-{}
+{
+	struct cgroup_subsys_state *new_css;
+	struct cgrp_cqm_info *cqm_info;
+	struct task_struct *task;
+
+	mutex_lock(&cache_mutex);
+
+	cgroup_taskset_for_each(task, new_css, tset) {
+		if (!is_task_monitored(task))
+			continue;
+
+		cqm_info = cqminfo_from_tsk(task);
+		if (cqm_info)
+			add_cgrp_tskmon_entry(task->rmid,
+					     &cqm_info->tskmon_rlist);
+	}
+	mutex_unlock(&cache_mutex);
+}
+
 int perf_cgroup_arch_can_attach(struct cgroup_taskset *tset)
-{}
+{
+	struct cgroup_subsys_state *new_css;
+	struct cgrp_cqm_info *cqm_info;
+	struct task_struct *task;
+
+	mutex_lock(&cache_mutex);
+	cgroup_taskset_for_each(task, new_css, tset) {
+		if (!is_task_monitored(task))
+			continue;
+		cqm_info = cqminfo_from_tsk(task);
+
+		if (cqm_info)
+			del_cgrp_tskmon_entry(task->rmid,
+					     &cqm_info->tskmon_rlist);
+
+	}
+	mutex_unlock(&cache_mutex);
+
+	return 0;
+}
 #endif
 
 static inline void cqm_pick_event_reader(int cpu)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c8f4152..a6f8060b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1794,6 +1794,9 @@ struct task_struct {
 #ifdef CONFIG_INTEL_RDT_A
 	int closid;
 #endif
+#ifdef CONFIG_INTEL_RDT_M
+	u32 *rmid;
+#endif
 #ifdef CONFIG_FUTEX
 	struct robust_list_head __user *robust_list;
 #ifdef CONFIG_COMPAT
-- 
1.9.1

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | linux.kernel


csiph-web