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


Groups > linux.kernel > #1675020 > unrolled thread

[PATCH V1 00/21] x86/cqm3: Resctrl based cqm

Started byVikas Shivappa <vikas.shivappa@linux.intel.com>
First post2017-06-26 21:00 +0200
Last post2017-07-03 12:00 +0200
Articles 20 on this page of 21 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH V1 00/21] x86/cqm3: Resctrl based cqm Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
    [PATCH 16/21] x86/intel_rdt/cqm: Add mount,umount support Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 16/21] x86/intel_rdt/cqm: Add mount,umount support Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 15:30 +0200
    [PATCH 20/21] x86/intel_rdt/mbm: Add mbm counter initialization Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
    [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 13:20 +0200
      Re: [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 14:40 +0200
    [PATCH 15/21] x86/intel_rdt/cqm: Add rmdir support Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 15/21] x86/intel_rdt/cqm: Add rmdir support Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 15:20 +0200
    [PATCH 03/21] x86/intel_rdt/cqm: Documentation for resctrl based RDT Monitoring Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
    [PATCH 21/21] x86/intel_rdt/mbm: Handle counter overflow Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 21/21] x86/intel_rdt/mbm: Handle counter overflow Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 16:00 +0200
    [PATCH 14/21] x86/intel_rdt/cqm: Add mon_data Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 14/21] x86/intel_rdt/cqm: Add mon_data Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 14:50 +0200
    [PATCH 17/21] x86/intel_rdt/cqm: Add sched_in support Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 17/21] x86/intel_rdt/cqm: Add sched_in support Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 15:40 +0200
    [PATCH 12/21] x86/intel_rdt/cqm: Add tasks file support Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 12/21] x86/intel_rdt/cqm: Add tasks file support Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 13:10 +0200
    [PATCH 08/21] x86/intel_rdt/cqm: Add RMID(Resource monitoring ID) management Vikas Shivappa <vikas.shivappa@linux.intel.com> - 2017-06-26 21:00 +0200
      Re: [PATCH 08/21] x86/intel_rdt/cqm: Add RMID(Resource monitoring  ID) management Thomas Gleixner <tglx@linutronix.de> - 2017-07-02 12:10 +0200
        Re: [PATCH 08/21] x86/intel_rdt/cqm: Add RMID(Resource monitoring  ID) management Thomas Gleixner <tglx@linutronix.de> - 2017-07-03 12:00 +0200

Page 1 of 2  [1] 2  Next page →


#1675020 — [PATCH V1 00/21] x86/cqm3: Resctrl based cqm

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH V1 00/21] x86/cqm3: Resctrl based cqm
Message-ID<tWHoR-5Yd-3@gated-at.bofh.it>
Sending a version of resctrl based cqm and mbm patches as per the
requirements discussed here:
https://marc.info/?l=linux-kernel&m=148891934720489

Several attempts were made to fix the existing upstream perf based cqm
but were NACKed by the community which led to the above discussions.

Patches are based on 4.12-rc4.

	Acknowledgements:
- Thanks to Thomas for all the feedback on the requirements and design.
- Thanks to Stephane Eranian <eranian@google.com> and David
Carrillo-Cisneros <davidcc@google.com> for going through all the
churning during requirements and design phase and code reviews.
- Thanks to "Chatre, Reinette" <reinette.chatre@intel.com> for bringing up
issues in code organization and other issues in declaring globals which
were not static.

	Summary of the changes -

01/21 - Remove the existing perf based cqm
02/21 - A fix to existing RDT memory leak issue
03/21 - Documentation for resctrl based cqm
04 - 06/21 - Cleanup/Preparatory patches for resctrl based cqm
07 - 18/21 - Add CQM support
19 - 21/21 - Add MBM support

Tony Luck (2):
  x86/intel_rdt: Simplify info and base file lists
  x86/intel_rdt/mbm: Basic counting of MBM events (total and local)

Vikas Shivappa (19):
  x86/perf/cqm: Wipe out perf based cqm
  x86/intel_rdt: Fix memory leak during mount
  x86/intel_rdt/cqm: Documentation for resctrl based RDT Monitoring
  x86/intel_rdt: Introduce a common compile option for RDT
  x86/intel_rdt: Change file names to accommodate RDT monitor code
  x86/intel_rdt: Cleanup namespace to support RDT monitoring
  x86/intel_rdt/cqm: Add RDT monitoring initialization
  x86/intel_rdt/cqm: Add RMID(Resource monitoring ID) management
  x86/intel_rdt/cqm: Add info files for RDT monitoring
  x86/intel_rdt/cqm: Add mkdir support for RDT monitoring
  x86/intel_rdt/cqm: Add tasks file support
  x86/intel_rdt/cqm: Add cpus file support
  x86/intel_rdt/cqm: Add mon_data
  x86/intel_rdt/cqm: Add rmdir support
  x86/intel_rdt/cqm: Add mount,umount support
  x86/intel_rdt/cqm: Add sched_in support
  x86/intel_rdt/cqm: Add hotcpu support
  x86/intel_rdt/mbm: Add mbm counter initialization
  x86/intel_rdt/mbm: Handle counter overflow

 Documentation/x86/intel_rdt_ui.txt          |  316 ++++-
 MAINTAINERS                                 |    2 +-
 arch/x86/Kconfig                            |   12 +-
 arch/x86/events/intel/Makefile              |    2 +-
 arch/x86/events/intel/cqm.c                 | 1766 ---------------------------
 arch/x86/include/asm/intel_rdt.h            |  286 -----
 arch/x86/include/asm/intel_rdt_common.h     |   27 -
 arch/x86/include/asm/intel_rdt_sched.h      |   93 ++
 arch/x86/kernel/cpu/Makefile                |    2 +-
 arch/x86/kernel/cpu/intel_rdt.c             |  186 ++-
 arch/x86/kernel/cpu/intel_rdt.h             |  413 +++++++
 arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c |  340 ++++++
 arch/x86/kernel/cpu/intel_rdt_monitor.c     |  421 +++++++
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c    | 1099 ++++++++++++++---
 arch/x86/kernel/cpu/intel_rdt_schemata.c    |  286 -----
 arch/x86/kernel/process_32.c                |    2 +-
 arch/x86/kernel/process_64.c                |    2 +-
 include/linux/perf_event.h                  |   18 -
 include/linux/sched.h                       |    3 +-
 kernel/events/core.c                        |   11 +-
 kernel/trace/bpf_trace.c                    |    2 +-
 21 files changed, 2617 insertions(+), 2672 deletions(-)
 delete mode 100644 arch/x86/events/intel/cqm.c
 delete mode 100644 arch/x86/include/asm/intel_rdt.h
 delete mode 100644 arch/x86/include/asm/intel_rdt_common.h
 create mode 100644 arch/x86/include/asm/intel_rdt_sched.h
 create mode 100644 arch/x86/kernel/cpu/intel_rdt.h
 create mode 100644 arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
 create mode 100644 arch/x86/kernel/cpu/intel_rdt_monitor.c
 delete mode 100644 arch/x86/kernel/cpu/intel_rdt_schemata.c

-- 
1.9.1

[toc] | [next] | [standalone]


#1675021 — [PATCH 16/21] x86/intel_rdt/cqm: Add mount,umount support

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 16/21] x86/intel_rdt/cqm: Add mount,umount support
Message-ID<tWHoS-5Yd-31@gated-at.bofh.it>
In reply to#1675020
Add monitoring support during mount and unmount. Since root directory is
a "ctrl_mon" directory which can control and monitor resources create
the "mon_groups" directory which can hold monitor groups and a
"mon_data" directory which would hold all monitoring data like the rest
of resource groups.

The mount succeeds if either of monitoring or control/allocation is
enabled. If only monitoring is enabled user can still create monitor
groups under the "/sys/fs/resctrl/mon_groups/" and any mkdir under root
would fail. If only control/allocation is enabled all of the monitoring
related directories/files would not exist and resctrl would work in
legacy mode.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/intel_rdt.h          |  5 +++
 arch/x86/kernel/cpu/intel_rdt_monitor.c  |  3 ++
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 67 +++++++++++++++++++++++++++++---
 3 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index 631d58e..ea7a86f 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -22,6 +22,9 @@
 
 #define RMID_VAL_ERROR		(1ULL << 63)
 #define RMID_VAL_UNAVAIL	(1ULL << 62)
+
+DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
+
 /**
  * struct mon_evt - Entry in the event list of a resource
  * @evtid:		event id
@@ -59,6 +62,8 @@ struct rmid_read {
 extern int rdt_mon_features;
 
 DECLARE_PER_CPU_READ_MOSTLY(int, cpu_rmid);
+DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
+
 
 enum rdt_group_type {
 	RDTCTRL_GROUP = 0,
diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c
index cc252eb..a7247ca 100644
--- a/arch/x86/kernel/cpu/intel_rdt_monitor.c
+++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c
@@ -76,6 +76,9 @@ struct rmid_entry {
 unsigned int intel_cqm_threshold;
 
 DEFINE_PER_CPU_READ_MOSTLY(int, cpu_rmid);
+
+DEFINE_STATIC_KEY_FALSE(rdt_mon_enable_key);
+
 static inline struct rmid_entry *__rmid_entry(u32 rmid)
 {
 	struct rmid_entry *entry;
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index 6131508..2384c07 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -35,6 +35,7 @@
 #include <asm/intel_rdt_sched.h>
 #include "intel_rdt.h"
 
+DEFINE_STATIC_KEY_FALSE(rdt_enable_key);
 DEFINE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
 struct kernfs_root *rdt_root;
 struct rdtgroup rdtgroup_default;
@@ -43,6 +44,12 @@
 /* Kernel fs node for "info" directory under root */
 static struct kernfs_node *kn_info;
 
+/* Kernel fs node for "mon_groups" directory under root */
+static struct kernfs_node *kn_mongrp;
+
+/* Kernel fs node for "mon_data" directory under root */
+static struct kernfs_node *kn_mondata;
+
 /*
  * Trivial allocator for CLOSIDs. Since h/w only supports a small number,
  * we can keep a bitmap of free CLOSIDs in a single integer.
@@ -1078,6 +1085,9 @@ void rdtgroup_kn_unlock(struct kernfs_node *kn)
 	}
 }
 
+static int mkdir_mondata_all(struct kernfs_node *parent_kn, struct rdtgroup *pr,
+			     struct kernfs_node **mon_data_kn);
+
 static struct dentry *rdt_mount(struct file_system_type *fs_type,
 				int flags, const char *unused_dev_name,
 				void *data)
@@ -1089,7 +1099,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
 	/*
 	 * resctrl file system can only be mounted once.
 	 */
-	if (static_branch_unlikely(&rdt_alloc_enable_key)) {
+	if (static_branch_unlikely(&rdt_enable_key)) {
 		dentry = ERR_PTR(-EBUSY);
 		goto out;
 	}
@@ -1108,15 +1118,47 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
 		goto out_cdp;
 	}
 
+	if (rdt_mon_features) {
+		ret = mongroup_create_dir(rdtgroup_default.kn,
+					  NULL, "mon_groups",
+					  &kn_mongrp);
+		if (ret) {
+			dentry = ERR_PTR(ret);
+			goto out_info;
+		}
+		kernfs_get(kn_mongrp);
+
+		ret = mkdir_mondata_all(rdtgroup_default.kn,
+					&rdtgroup_default, &kn_mondata);
+		if (ret) {
+			dentry = ERR_PTR(ret);
+			goto out_mongrp;
+		}
+		kernfs_get(kn_mondata);
+		rdtgroup_default.mon_data_kn = kn_mondata;
+	}
+
 	dentry = kernfs_mount(fs_type, flags, rdt_root,
 			      RDTGROUP_SUPER_MAGIC, NULL);
 	if (IS_ERR(dentry))
-		goto out_destroy;
+		goto out_mondata;
 
-	static_branch_enable(&rdt_alloc_enable_key);
+	if (rdt_alloc_enabled)
+		static_branch_enable(&rdt_alloc_enable_key);
+	if (rdt_mon_features)
+		static_branch_enable(&rdt_mon_enable_key);
+
+	if (rdt_alloc_enabled || rdt_mon_features)
+		static_branch_enable(&rdt_enable_key);
 	goto out;
 
-out_destroy:
+out_mondata:
+	if (rdt_mon_features)
+		kernfs_remove(kn_mondata);
+out_mongrp:
+	if (rdt_mon_features)
+		kernfs_remove(kn_mongrp);
+out_info:
 	kernfs_remove(kn_info);
 out_cdp:
 	cdp_disable();
@@ -1219,12 +1261,21 @@ static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
  */
 static void rmdir_all_sub(void)
 {
-	struct rdtgroup *rdtgrp, *tmp;
+	struct rdtgroup *rdtgrp, *tmp, *sentry, *stmp;
+	struct list_head *llist;
 
 	/* Move all tasks to the default resource group */
 	rdt_move_group_tasks(NULL, &rdtgroup_default, NULL);
 
 	list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
+		/* Free any child rmids */
+		llist = &rdtgrp->crdtgrp_list;
+		list_for_each_entry_safe(sentry, stmp, llist, crdtgrp_list) {
+			free_rmid(sentry->rmid);
+			list_del(&sentry->crdtgrp_list);
+			kfree(sentry);
+		}
+
 		/* Remove each rdtgroup other than root */
 		if (rdtgrp == &rdtgroup_default)
 			continue;
@@ -1237,6 +1288,8 @@ static void rmdir_all_sub(void)
 		cpumask_or(&rdtgroup_default.cpu_mask,
 			   &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
 
+		free_rmid(rdtgrp->rmid);
+
 		kernfs_remove(rdtgrp->kn);
 		list_del(&rdtgrp->rdtgroup_list);
 		kfree(rdtgrp);
@@ -1247,6 +1300,8 @@ static void rmdir_all_sub(void)
 	put_online_cpus();
 
 	kernfs_remove(kn_info);
+	kernfs_remove(kn_mongrp);
+	kernfs_remove(kn_mondata);
 }
 
 static void rdt_kill_sb(struct super_block *sb)
@@ -1261,6 +1316,8 @@ static void rdt_kill_sb(struct super_block *sb)
 	cdp_disable();
 	rmdir_all_sub();
 	static_branch_disable(&rdt_alloc_enable_key);
+	static_branch_disable(&rdt_mon_enable_key);
+	static_branch_disable(&rdt_enable_key);
 	kernfs_kill_sb(sb);
 	mutex_unlock(&rdtgroup_mutex);
 }
-- 
1.9.1

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


#1679466 — Re: [PATCH 16/21] x86/intel_rdt/cqm: Add mount,umount support

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 15:30 +0200
SubjectRe: [PATCH 16/21] x86/intel_rdt/cqm: Add mount,umount support
Message-ID<tYN6N-2qM-5@gated-at.bofh.it>
In reply to#1675021
On Mon, 26 Jun 2017, Vikas Shivappa wrote:
>  
>  	list_for_each_entry_safe(rdtgrp, tmp, &rdt_all_groups, rdtgroup_list) {
> +		/* Free any child rmids */
> +		llist = &rdtgrp->crdtgrp_list;
> +		list_for_each_entry_safe(sentry, stmp, llist, crdtgrp_list) {
> +			free_rmid(sentry->rmid);
> +			list_del(&sentry->crdtgrp_list);
> +			kfree(sentry);
> +		}

I'm pretty sure, that I've seen exactly this code sequence already. Please
create a helper instead of copying stuff over and over.

Thanks,

	tglx

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


#1675022 — [PATCH 20/21] x86/intel_rdt/mbm: Add mbm counter initialization

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 20/21] x86/intel_rdt/mbm: Add mbm counter initialization
Message-ID<tWHoS-5Yd-39@gated-at.bofh.it>
In reply to#1675020
MBM counters are monotonically increasing counts representing the total
memory bytes at a particular time. In order to calculate total_bytes for
an rdtgroup, we store the value of the counter when we create an
rdtgroup or when a new domain comes online.

When the total_bytes(all memory controller bytes) or local_bytes(local
memory controller bytes) file in "mon_data" is read it shows the total
bytes for that rdtgroup since its creation. User can snapshot this at
different time intervals to obtain bytes/second.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/intel_rdt.c             |  2 +-
 arch/x86/kernel/cpu/intel_rdt.h             | 11 +++++++++-
 arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c | 25 +++++++++++++--------
 arch/x86/kernel/cpu/intel_rdt_monitor.c     |  7 ++++++
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c    | 34 ++++++++++++++++++-----------
 5 files changed, 55 insertions(+), 24 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index a17f323..7762e32 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -469,7 +469,7 @@ static void domain_add_cpu(int cpu, struct rdt_resource *r)
 	 * per domain monitor data directories.
 	 */
 	if (static_branch_unlikely(&rdt_mon_enable_key))
-		mkdir_mondata_subdir_allrdtgrp(r, d->id);
+		mkdir_mondata_subdir_allrdtgrp(r, d);
 }
 
 static void domain_remove_cpu(int cpu, struct rdt_resource *r)
diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index ab010fb..f0896ac 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -57,6 +57,7 @@ struct rmid_read {
 	struct rdtgroup		*rgrp;
 	struct rdt_domain	*d;
 	int			evtid;
+	bool			first;
 	u64			val;
 };
 
@@ -253,6 +254,12 @@ static inline bool is_mbm_enabled(void)
 	return (is_mbm_total_enabled() || is_mbm_local_enabled());
 }
 
+static inline bool is_mbm_event(int e)
+{
+	return (e >= QOS_L3_MBM_TOTAL_EVENT_ID &&
+		e <= QOS_L3_MBM_LOCAL_EVENT_ID);
+}
+
 /**
  * struct rdt_resource - attributes of an RDT resource
  * @alloc_enabled:	Is allocation enabled on this machine
@@ -390,6 +397,8 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of,
 void rmdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
 				    unsigned int dom_id);
 void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
-				    unsigned int dom_id);
+				    struct rdt_domain *d);
+void mon_event_read(struct rmid_read *rr, struct rdt_domain *d,
+		    struct rdtgroup *rdtgrp, int evtid, int first);
 
 #endif /* _ASM_X86_INTEL_RDT_H */
diff --git a/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c b/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
index 926d889..e9391e3 100644
--- a/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
+++ b/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
@@ -285,6 +285,21 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of,
 	return ret;
 }
 
+void mon_event_read(struct rmid_read *rr, struct rdt_domain *d,
+		    struct rdtgroup *rdtgrp, int evtid, int first)
+{
+	/*
+	 * setup the parameters to send to the IPI to read the data.
+	 */
+	rr->rgrp = rdtgrp;
+	rr->evtid = evtid;
+	rr->d = d;
+	rr->val = 0;
+	rr->first = first;
+
+	smp_call_function_any(&d->cpu_mask, mon_event_count, rr, 1);
+}
+
 int rdtgroup_mondata_show(struct seq_file *m, void *arg)
 {
 	struct kernfs_open_file *of = m->private;
@@ -310,15 +325,7 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)
 		goto out;
 	}
 
-	/*
-	 * setup the parameters to send to the IPI to read the data.
-	 */
-	rr.rgrp = rdtgrp;
-	rr.evtid = evtid;
-	rr.d = d;
-	rr.val = 0;
-
-	smp_call_function_any(&d->cpu_mask, mon_event_count, &rr, 1);
+	mon_event_read(&rr, d, rdtgrp, evtid, false);
 
 	if (rr.val & RMID_VAL_ERROR)
 		seq_puts(m, "Error\n");
diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c
index 2c5768c..a196f4d 100644
--- a/arch/x86/kernel/cpu/intel_rdt_monitor.c
+++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c
@@ -230,6 +230,13 @@ static bool __mon_event_count(u32 rmid, struct rmid_read *rr)
 	default:
 		return false;
 	}
+
+	if (rr->first) {
+		m->prev_msr = tval;
+		m->chunks = 0;
+		return true;
+	}
+
 	shift = 64 - MBM_CNTR_WIDTH;
 	chunks = (tval << shift) - (m->prev_msr << shift);
 	chunks >>= shift;
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index 8e1581a..1b84485 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -1379,12 +1379,14 @@ static int get_rdt_resourceid(struct rdt_resource *r)
 	return ((r - rdt_resources_all) / sizeof(struct rdt_resource));
 }
 
-static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, int domid,
+static int mkdir_mondata_subdir(struct kernfs_node *parent_kn,
+				struct rdt_domain *d,
 				struct rdt_resource *r, struct rdtgroup *pr)
 {
 	union mon_data_bits priv;
 	struct kernfs_node *kn;
 	struct mon_evt *mevt;
+	struct rmid_read rr;
 	char name[32];
 	int ret, rid;
 
@@ -1392,7 +1394,7 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, int domid,
 	if (rid < 0)
 		return -EINVAL;
 
-	sprintf(name, "mon_%s_%02d", r->name, domid);
+	sprintf(name, "mon_%s_%02d", r->name, d->id);
 	/* create the directory */
 	kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, pr);
 	if (IS_ERR(kn))
@@ -1413,12 +1415,15 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, int domid,
 	}
 
 	priv.u.rid = rid;
-	priv.u.domid = domid;
+	priv.u.domid = d->id;
 	list_for_each_entry(mevt, &r->evt_list, list) {
 		priv.u.evtid = mevt->evtid;
 		ret = mon_addfile(kn, mevt->name, priv.priv);
 		if (ret)
 			goto out_destroy;
+
+		if (is_mbm_event(mevt->evtid))
+			mon_event_read(&rr, d, pr, mevt->evtid, true);
 	}
 	kernfs_activate(kn);
 	return 0;
@@ -1432,7 +1437,8 @@ static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, int domid,
  * Add all subdirectories of mon_data for "ctrl_mon" groups
  * and "monitor" groups with given domain id.
  */
-void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, unsigned int domid)
+void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
+				    struct rdt_domain *d)
 {
 	struct kernfs_node *parent_kn;
 	struct rdtgroup *pr, *cr;
@@ -1442,11 +1448,11 @@ void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r, unsigned int domid)
 
 	list_for_each_entry(pr, &rdt_all_groups, rdtgroup_list) {
 		parent_kn = pr->mon_data_kn;
-		mkdir_mondata_subdir(parent_kn, domid, r, pr);
+		mkdir_mondata_subdir(parent_kn, d, r, pr);
 
 		list_for_each_entry(cr, &pr->crdtgrp_list, crdtgrp_list) {
 			parent_kn = cr->mon_data_kn;
-			mkdir_mondata_subdir(parent_kn, domid, r, cr);
+			mkdir_mondata_subdir(parent_kn, d, r, cr);
 		}
 	}
 }
@@ -1459,7 +1465,7 @@ static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
 	int ret;
 
 	list_for_each_entry(dom, &r->domains, list) {
-		ret = mkdir_mondata_subdir(parent_kn, dom->id, r, pr);
+		ret = mkdir_mondata_subdir(parent_kn, dom, r, pr);
 		if (ret)
 			return ret;
 	}
@@ -1575,20 +1581,22 @@ static int mkdir_rdt_common(struct kernfs_node *pkn, struct kernfs_node *prkn,
 		goto out_destroy;
 
 	if (rdt_mon_features) {
-		ret = mkdir_mondata_all(kn, rdtgrp, &rdtgrp->mon_data_kn);
-		if (ret)
-			goto out_destroy;
-
 		ret = alloc_rmid();
 		if (ret < 0)
-			return ret;
-
+			goto out_destroy;
 		rdtgrp->rmid = ret;
+
+		ret = mkdir_mondata_all(kn, rdtgrp, &rdtgrp->mon_data_kn);
+		if (ret)
+			goto out_idfree;
 	}
 	kernfs_activate(kn);
 
 	return 0;
 
+out_idfree:
+	if (rdtgrp->rmid)
+		free_rmid(rdtgrp->rmid);
 out_destroy:
 	kernfs_remove(rdtgrp->kn);
 out_cancel_ref:
-- 
1.9.1

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


#1675023 — [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support
Message-ID<tWHoS-5Yd-45@gated-at.bofh.it>
In reply to#1675020
The cpus file is extended to support resource monitoring. This is used
to over-ride the RMID of the default group when running on specific
CPUs. It works similar to the resource control. The "cpus" and
"cpus_list" file is present in default group, ctrl_mon groups and
monitor groups.

Each "cpus" file or cpu_list file reads a cpumask or list showing which
CPUs belong to the resource group. By default all online cpus belong to
the default root group. A CPU can be present in one "ctrl_mon" and one
"monitor" group simultaneously. They can be added to a resource group by
writing the CPU to the file. When a CPU is added to a ctrl_mon group it
is automatically removed from the previous ctrl_mon group. A CPU can be
added to a monitor group only if it is present in the parent ctrl_mon
group and when a CPU is added to a monitor group, it is automatically
removed from the previous monitor group. When CPUs go offline, they are
automatically removed from the ctrl_mon and monitor groups.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/intel_rdt.c          |  15 ++-
 arch/x86/kernel/cpu/intel_rdt.h          |   2 +
 arch/x86/kernel/cpu/intel_rdt_monitor.c  |   1 +
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 183 +++++++++++++++++++++++++------
 4 files changed, 169 insertions(+), 32 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index e96b3f0..b0f8c35 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -483,6 +483,17 @@ static int intel_rdt_online_cpu(unsigned int cpu)
 	return 0;
 }
 
+static void clear_childcpus(struct rdtgroup *r, unsigned int cpu)
+{
+	struct rdtgroup *cr;
+
+	list_for_each_entry(cr, &r->crdtgrp_list, crdtgrp_list) {
+		if (cpumask_test_and_clear_cpu(cpu, &cr->cpu_mask)) {
+			break;
+		}
+	}
+}
+
 static int intel_rdt_offline_cpu(unsigned int cpu)
 {
 	struct rdtgroup *rdtgrp;
@@ -492,8 +503,10 @@ static int intel_rdt_offline_cpu(unsigned int cpu)
 	for_each_alloc_capable_rdt_resource(r)
 		domain_remove_cpu(cpu, r);
 	list_for_each_entry(rdtgrp, &rdt_all_groups, rdtgroup_list) {
-		if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask))
+		if (cpumask_test_and_clear_cpu(cpu, &rdtgrp->cpu_mask)) {
+			clear_childcpus(rdtgrp, cpu);
 			break;
+		}
 	}
 	clear_closid(cpu);
 	mutex_unlock(&rdtgroup_mutex);
diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index fdf3654..fec8ba9 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -37,6 +37,8 @@ struct mon_evt {
 extern bool rdt_alloc_enabled;
 extern int rdt_mon_features;
 
+DECLARE_PER_CPU_READ_MOSTLY(int, cpu_rmid);
+
 enum rdt_group_type {
 	RDTCTRL_GROUP = 0,
 	RDTMON_GROUP,
diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c
index 4f4221a..624a0aa 100644
--- a/arch/x86/kernel/cpu/intel_rdt_monitor.c
+++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c
@@ -75,6 +75,7 @@ struct rmid_entry {
  */
 unsigned int intel_cqm_threshold;
 
+DEFINE_PER_CPU_READ_MOSTLY(int, cpu_rmid);
 static inline struct rmid_entry *__rmid_entry(u32 rmid)
 {
 	struct rmid_entry *entry;
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index 8fd0757..d32b781 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -181,13 +181,18 @@ static int rdtgroup_cpus_show(struct kernfs_open_file *of,
 /*
  * This is safe against intel_rdt_sched_in() called from __switch_to()
  * because __switch_to() is executed with interrupts disabled. A local call
- * from rdt_update_closid() is proteced against __switch_to() because
+ * from rdt_update_closidrmid() is proteced against __switch_to() because
  * preemption is disabled.
  */
-static void rdt_update_cpu_closid(void *closid)
+static void update_cpu_closid_rmid(void *info)
 {
-	if (closid)
-		this_cpu_write(cpu_closid, *(int *)closid);
+	struct rdtgroup *r = info;
+
+	if (r) {
+		this_cpu_write(cpu_closid, r->closid);
+		this_cpu_write(cpu_rmid, r->rmid);
+	}
+
 	/*
 	 * We cannot unconditionally write the MSR because the current
 	 * executing task might have its own closid selected. Just reuse
@@ -199,33 +204,30 @@ static void rdt_update_cpu_closid(void *closid)
 /*
  * Update the PGR_ASSOC MSR on all cpus in @cpu_mask,
  *
- * Per task closids must have been set up before calling this function.
+ * Per task closids/rmids must have been set up before calling this function.
  *
- * The per cpu closids are updated with the smp function call, when @closid
- * is not NULL. If @closid is NULL then all affected percpu closids must
- * have been set up before calling this function.
+ * The per cpu closids and rmids are updated with the smp function call
  */
 static void
-rdt_update_closid(const struct cpumask *cpu_mask, int *closid)
+update_closid_rmid(const struct cpumask *cpu_mask, struct rdtgroup *r)
 {
 	int cpu = get_cpu();
 
 	if (cpumask_test_cpu(cpu, cpu_mask))
-		rdt_update_cpu_closid(closid);
-	smp_call_function_many(cpu_mask, rdt_update_cpu_closid, closid, 1);
+		update_cpu_closid_rmid(r);
+	smp_call_function_many(cpu_mask, update_cpu_closid_rmid, r, 1);
 	put_cpu();
 }
 
-static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
-				   char *buf, size_t nbytes, loff_t off)
+static ssize_t cpus_mon_write(struct kernfs_open_file *of,
+			      char *buf, size_t nbytes,
+			      struct rdtgroup *rdtgrp)
 {
+	struct rdtgroup *pr = rdtgrp->parent, *cr;
 	cpumask_var_t tmpmask, newmask;
-	struct rdtgroup *rdtgrp, *r;
+	struct list_head *llist;
 	int ret;
 
-	if (!buf)
-		return -EINVAL;
-
 	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
 		return -ENOMEM;
 	if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) {
@@ -233,10 +235,89 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
 		return -ENOMEM;
 	}
 
-	rdtgrp = rdtgroup_kn_lock_live(of->kn);
-	if (!rdtgrp) {
-		ret = -ENOENT;
-		goto unlock;
+	if (is_cpu_list(of))
+		ret = cpulist_parse(buf, newmask);
+	else
+		ret = cpumask_parse(buf, newmask);
+
+	if (ret)
+		goto out;
+
+	/* check that user didn't specify any offline cpus */
+	cpumask_andnot(tmpmask, newmask, cpu_online_mask);
+	if (cpumask_weight(tmpmask)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Check whether cpus belong to parent ctrl group */
+	cpumask_andnot(tmpmask, newmask, &pr->cpu_mask);
+	if (cpumask_weight(tmpmask)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Check whether cpus are dropped from this group */
+	cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
+	if (cpumask_weight(tmpmask)) {
+		/* Give any dropped cpus to parent rdtgroup */
+		cpumask_or(&pr->cpu_mask, &pr->cpu_mask, tmpmask);
+		update_closid_rmid(tmpmask, pr);
+	}
+
+	/*
+	 * If we added cpus, remove them from previous group that owned them
+	 * and update per-cpu rmid
+	 */
+	cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
+	if (cpumask_weight(tmpmask)) {
+		llist = &pr->crdtgrp_list;
+		list_for_each_entry(cr, llist, crdtgrp_list) {
+			if (cr == rdtgrp)
+				continue;
+			cpumask_andnot(&cr->cpu_mask, &cr->cpu_mask, tmpmask);
+		}
+		update_closid_rmid(tmpmask, rdtgrp);
+	}
+
+	/* Done pushing/pulling - update this group with new mask */
+	cpumask_copy(&rdtgrp->cpu_mask, newmask);
+
+out:
+	free_cpumask_var(tmpmask);
+	free_cpumask_var(newmask);
+
+	return ret ?: nbytes;
+}
+
+static void cpumask_rdtgrp_clear(struct rdtgroup *r, struct cpumask *m)
+{
+	struct rdtgroup *cr;
+
+	cpumask_andnot(&r->cpu_mask, &r->cpu_mask, m);
+	/* update the child mon group masks as well*/
+	list_for_each_entry(cr, &r->crdtgrp_list, crdtgrp_list)
+		cpumask_and(&cr->cpu_mask, &r->cpu_mask, &cr->cpu_mask);
+}
+
+static ssize_t cpus_ctrl_write(struct kernfs_open_file *of,
+			       char *buf, size_t nbytes,
+			       struct rdtgroup *rdtgrp)
+{
+	cpumask_var_t tmpmask, newmask, tmpmask1;
+	struct rdtgroup *r, *cr;
+	int ret;
+
+	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
+		return -ENOMEM;
+	if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) {
+		free_cpumask_var(tmpmask);
+		return -ENOMEM;
+	}
+	if (!zalloc_cpumask_var(&tmpmask1, GFP_KERNEL)) {
+		free_cpumask_var(tmpmask);
+		free_cpumask_var(newmask);
+		return -ENOMEM;
 	}
 
 	if (is_cpu_list(of))
@@ -245,13 +326,13 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
 		ret = cpumask_parse(buf, newmask);
 
 	if (ret)
-		goto unlock;
+		goto out;
 
 	/* check that user didn't specify any offline cpus */
 	cpumask_andnot(tmpmask, newmask, cpu_online_mask);
 	if (cpumask_weight(tmpmask)) {
 		ret = -EINVAL;
-		goto unlock;
+		goto out;
 	}
 
 	/* Check whether cpus are dropped from this group */
@@ -260,12 +341,13 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
 		/* Can't drop from default group */
 		if (rdtgrp == &rdtgroup_default) {
 			ret = -EINVAL;
-			goto unlock;
+			goto out;
 		}
+
 		/* Give any dropped cpus to rdtgroup_default */
 		cpumask_or(&rdtgroup_default.cpu_mask,
 			   &rdtgroup_default.cpu_mask, tmpmask);
-		rdt_update_closid(tmpmask, &rdtgroup_default.closid);
+		update_closid_rmid(tmpmask, &rdtgroup_default);
 	}
 
 	/*
@@ -277,22 +359,61 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
 		list_for_each_entry(r, &rdt_all_groups, rdtgroup_list) {
 			if (r == rdtgrp)
 				continue;
-			cpumask_andnot(&r->cpu_mask, &r->cpu_mask, tmpmask);
+			cpumask_and(tmpmask1, &r->cpu_mask, tmpmask);
+			if (cpumask_weight(tmpmask1))
+				cpumask_rdtgrp_clear(r, tmpmask1);
 		}
-		rdt_update_closid(tmpmask, &rdtgrp->closid);
+		update_closid_rmid(tmpmask, rdtgrp);
 	}
 
 	/* Done pushing/pulling - update this group with new mask */
 	cpumask_copy(&rdtgrp->cpu_mask, newmask);
 
-unlock:
-	rdtgroup_kn_unlock(of->kn);
+	/*
+	 * Update the child mon group masks as well. The child groups
+	 * would always have the subset of parent, but any new cpus
+	 * to the parent need to be removed from the children.
+	 */
+	list_for_each_entry(cr, &rdtgrp->crdtgrp_list, crdtgrp_list) {
+		cpumask_and(tmpmask, &rdtgrp->cpu_mask, &cr->cpu_mask);
+		cpumask_andnot(&cr->cpu_mask, tmpmask, newmask);
+	}
+out:
+	free_cpumask_var(tmpmask1);
 	free_cpumask_var(tmpmask);
 	free_cpumask_var(newmask);
 
 	return ret ?: nbytes;
 }
 
+static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
+				   char *buf, size_t nbytes, loff_t off)
+{
+	struct rdtgroup *rdtgrp;
+	int ret;
+
+	if (!buf)
+		return -EINVAL;
+
+	rdtgrp = rdtgroup_kn_lock_live(of->kn);
+	if (!rdtgrp) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+
+	if (rdtgrp->type == RDTCTRL_GROUP)
+		ret = cpus_ctrl_write(of, buf, nbytes, rdtgrp);
+	else if (rdtgrp->type == RDTMON_GROUP)
+		ret = cpus_mon_write(of, buf, nbytes, rdtgrp);
+	else
+		ret = -EINVAL;
+
+unlock:
+	rdtgroup_kn_unlock(of->kn);
+
+	return ret ?: nbytes;
+}
+
 struct task_move_callback {
 	struct callback_head	work;
 	struct rdtgroup		*rdtgrp;
@@ -1102,7 +1223,7 @@ static void rmdir_all_sub(void)
 	}
 	/* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */
 	get_online_cpus();
-	rdt_update_closid(cpu_online_mask, &rdtgroup_default.closid);
+	update_closid_rmid(cpu_online_mask, &rdtgroup_default);
 	put_online_cpus();
 
 	kernfs_remove(kn_info);
@@ -1342,7 +1463,7 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
 	 * task running on them.
 	 */
 	cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
-	rdt_update_closid(tmpmask, NULL);
+	update_closid_rmid(tmpmask, NULL);
 
 	rdtgrp->flags = RDT_DELETED;
 	closid_free(rdtgrp->closid);
-- 
1.9.1

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


#1679448 — Re: [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 13:20 +0200
SubjectRe: [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support
Message-ID<tYL4Z-15R-3@gated-at.bofh.it>
In reply to#1675023
On Mon, 26 Jun 2017, Vikas Shivappa wrote:
> diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
> index fdf3654..fec8ba9 100644
> --- a/arch/x86/kernel/cpu/intel_rdt.h
> +++ b/arch/x86/kernel/cpu/intel_rdt.h
> @@ -37,6 +37,8 @@ struct mon_evt {
>  extern bool rdt_alloc_enabled;
>  extern int rdt_mon_features;
>  
> +DECLARE_PER_CPU_READ_MOSTLY(int, cpu_rmid);

u32

>  
> +DEFINE_PER_CPU_READ_MOSTLY(int, cpu_rmid);
>  static inline struct rmid_entry *__rmid_entry(u32 rmid)

Bah. Please add a new line between the DEFINE... and the function.

But that whole thing is wrong. The per cpu default closid and rmid want to
be in a single place, not in two distinct per cpu variables.

struct rdt_cpu_default {
       u32	rmid;
       u32	closid;
};

DEFINE_PER_CPU_READ_MOSTLY(struct rdt_cpu_default, rdt_cpu_default);

or something like this. That way it's guaranteed that the context switch
code touches a single cache line for the per cpu defaults.

Thanks,

	tglx

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


#1679459 — Re: [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 14:40 +0200
SubjectRe: [PATCH 13/21] x86/intel_rdt/cqm: Add cpus file support
Message-ID<tYMkq-1Qk-21@gated-at.bofh.it>
In reply to#1675023
On Mon, 26 Jun 2017, Vikas Shivappa wrote:
> -static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
> -				   char *buf, size_t nbytes, loff_t off)
> +static ssize_t cpus_mon_write(struct kernfs_open_file *of,
> +			      char *buf, size_t nbytes,
> +			      struct rdtgroup *rdtgrp)

Again. Please make the split of rdtgroup_cpus_write() as a seperate
preparatory change first and just move the guts of the existing write
function out into cpus_ctrl_write() and then add the mon_write stuff as an
extra patch.

>  {
> +	struct rdtgroup *pr = rdtgrp->parent, *cr;

 *pr and *cr really suck. 

>  	cpumask_var_t tmpmask, newmask;
> -	struct rdtgroup *rdtgrp, *r;
> +	struct list_head *llist;
>  	int ret;
>  
> -	if (!buf)
> -		return -EINVAL;
> -
>  	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
>  		return -ENOMEM;
>  	if (!zalloc_cpumask_var(&newmask, GFP_KERNEL)) {
> @@ -233,10 +235,89 @@ static ssize_t rdtgroup_cpus_write(struct kernfs_open_file *of,
>  		return -ENOMEM;
>  	}
>  
> -	rdtgrp = rdtgroup_kn_lock_live(of->kn);
> -	if (!rdtgrp) {
> -		ret = -ENOENT;
> -		goto unlock;
> +	if (is_cpu_list(of))
> +		ret = cpulist_parse(buf, newmask);
> +	else
> +		ret = cpumask_parse(buf, newmask);

The cpuask allocation and parsing of the user buffer can be done in the
common code. No point in duplicating that.

> +
> +	if (ret)
> +		goto out;
> +
> +	/* check that user didn't specify any offline cpus */
> +	cpumask_andnot(tmpmask, newmask, cpu_online_mask);
> +	if (cpumask_weight(tmpmask)) {
> +		ret = -EINVAL;
> +		goto out;
> +	}

Common code.

> +	/* Check whether cpus belong to parent ctrl group */
> +	cpumask_andnot(tmpmask, newmask, &pr->cpu_mask);
> +	if (cpumask_weight(tmpmask)) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	/* Check whether cpus are dropped from this group */
> +	cpumask_andnot(tmpmask, &rdtgrp->cpu_mask, newmask);
> +	if (cpumask_weight(tmpmask)) {
> +		/* Give any dropped cpus to parent rdtgroup */
> +		cpumask_or(&pr->cpu_mask, &pr->cpu_mask, tmpmask);

This does not make any sense. The check above verifies that all cpus in
newmask belong to the parent->cpu_mask. If they don't then you return
-EINVAL, but here you give them back to parent->cpu_mask. How is that
supposed to work? You never get into this code path!

So you need a seperate mask in the parent rdtgroup to store the CPUs which
are valid in any monitoring group which belongs to it. So the logic
becomes:

	/*
	 * Check whether the CPU mask is a subset of the CPUs
	 * which belong to the parent group.
	 */
	cpumask_andnot(tmpmask, newmask, parent->cpus_valid_mask);
	if (cpumask_weight(tmpmask))
		return -EINVAL;

When CAT is not available, then parent->cpus_valid_mask is a pointer to
cpu_online_mask. When CAT is enabled, then parent->cpus_valid_mask is a
pointer to the CAT group cpu mask.

> +		update_closid_rmid(tmpmask, pr);
> +	}
> +
> +	/*
> +	 * If we added cpus, remove them from previous group that owned them
> +	 * and update per-cpu rmid
> +	 */
> +	cpumask_andnot(tmpmask, newmask, &rdtgrp->cpu_mask);
> +	if (cpumask_weight(tmpmask)) {
> +		llist = &pr->crdtgrp_list;

llist is a bad name. We have a facility llist, i.e. lockless list. head ?

> +		list_for_each_entry(cr, llist, crdtgrp_list) {
> +			if (cr == rdtgrp)
> +				continue;
> +			cpumask_andnot(&cr->cpu_mask, &cr->cpu_mask, tmpmask);
> +		}
> +		update_closid_rmid(tmpmask, rdtgrp);
> +	}

> +static void cpumask_rdtgrp_clear(struct rdtgroup *r, struct cpumask *m)
> +{
> +	struct rdtgroup *cr;
> +
> +	cpumask_andnot(&r->cpu_mask, &r->cpu_mask, m);
> +	/* update the child mon group masks as well*/
> +	list_for_each_entry(cr, &r->crdtgrp_list, crdtgrp_list)
> +		cpumask_and(&cr->cpu_mask, &r->cpu_mask, &cr->cpu_mask);

That's equally wrong. See above.

Thanks,

	tglx

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


#1675024 — [PATCH 15/21] x86/intel_rdt/cqm: Add rmdir support

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 15/21] x86/intel_rdt/cqm: Add rmdir support
Message-ID<tWHoS-5Yd-37@gated-at.bofh.it>
In reply to#1675020
Resource groups (ctrl_mon and monitor groups) are represented by
directories in resctrl fs. Add support to remove the directories.

When a ctrl_mon directory is removed all the cpus and tasks are assigned
back to the root rdtgroup. When a monitor group is removed the cpus and
tasks are returned to the parent control group.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 110 +++++++++++++++++++++++++++----
 1 file changed, 99 insertions(+), 11 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index 9377bcd..6131508 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -1164,6 +1164,18 @@ static int reset_all_ctrls(struct rdt_resource *r)
 	return 0;
 }
 
+static bool is_closid_match(struct task_struct *t, struct rdtgroup *r)
+{
+	return (rdt_alloc_enabled &&
+		(r->type == RDTCTRL_GROUP) && (t->closid == r->closid));
+}
+
+static bool is_rmid_match(struct task_struct *t, struct rdtgroup *r)
+{
+	return (rdt_mon_features &&
+		(r->type == RDTMON_GROUP) && (t->rmid == r->rmid));
+}
+
 /*
  * Move tasks from one to the other group. If @from is NULL, then all tasks
  * in the systems are moved unconditionally (used for teardown).
@@ -1179,8 +1191,11 @@ static void rdt_move_group_tasks(struct rdtgroup *from, struct rdtgroup *to,
 
 	read_lock(&tasklist_lock);
 	for_each_process_thread(p, t) {
-		if (!from || t->closid == from->closid) {
+		if (!from || is_closid_match(t, from) ||
+		    is_rmid_match(t, from)) {
 			t->closid = to->closid;
+			t->rmid = to->rmid;
+
 #ifdef CONFIG_SMP
 			/*
 			 * This is safe on x86 w/o barriers as the ordering
@@ -1402,6 +1417,7 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn, struct rdtgroup *pr,
 	kernfs_remove(kn);
 	return ret;
 }
+
 /*
  * Common code for ctrl_mon and monitor group mkdir.
  * The caller needs to unlock the global mutex upon success.
@@ -1588,20 +1604,57 @@ static int rdtgroup_mkdir(struct kernfs_node *pkn, const char *name,
 		return -EPERM;
 }
 
-static int rdtgroup_rmdir(struct kernfs_node *kn)
+static int rdtgroup_rmdir_mon(struct kernfs_node *kn, struct rdtgroup *rdtgrp)
 {
-	int ret, cpu, closid = rdtgroup_default.closid;
-	struct rdtgroup *rdtgrp;
+	struct rdtgroup *prdtgrp = rdtgrp->parent;
 	cpumask_var_t tmpmask;
+	int cpu;
 
 	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
 		return -ENOMEM;
 
-	rdtgrp = rdtgroup_kn_lock_live(kn);
-	if (!rdtgrp) {
-		ret = -EPERM;
-		goto out;
-	}
+	/* Give any tasks back to the parent group */
+	rdt_move_group_tasks(rdtgrp, prdtgrp, tmpmask);
+
+	/* Update per cpu rmid of the moved CPUs first */
+	for_each_cpu(cpu, &rdtgrp->cpu_mask)
+		per_cpu(cpu_rmid, cpu) = prdtgrp->rmid;
+	/*
+	 * Update the MSR on moved CPUs and CPUs which have moved
+	 * task running on them.
+	 */
+	cpumask_or(tmpmask, tmpmask, &rdtgrp->cpu_mask);
+	update_closid_rmid(tmpmask, NULL);
+
+	rdtgrp->flags = RDT_DELETED;
+	free_rmid(rdtgrp->rmid);
+
+	/*
+	 * Remove your rmid from the parent ctrl groups list
+	 */
+	WARN_ON(list_empty(&prdtgrp->crdtgrp_list));
+	list_del(&rdtgrp->crdtgrp_list);
+
+	/*
+	 * one extra hold on this, will drop when we kfree(rdtgrp)
+	 * in rdtgroup_kn_unlock()
+	 */
+	kernfs_get(kn);
+	kernfs_remove(rdtgrp->kn);
+	free_cpumask_var(tmpmask);
+
+	return 0;
+}
+
+static int rdtgroup_rmdir_ctrl(struct kernfs_node *kn, struct rdtgroup *rdtgrp)
+{
+	int cpu, closid = rdtgroup_default.closid;
+	struct rdtgroup *entry, *tmp;
+	struct list_head *llist;
+	cpumask_var_t tmpmask;
+
+	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
+		return -ENOMEM;
 
 	/* Give any tasks back to the default group */
 	rdt_move_group_tasks(rdtgrp, &rdtgroup_default, tmpmask);
@@ -1622,6 +1675,18 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
 
 	rdtgrp->flags = RDT_DELETED;
 	closid_free(rdtgrp->closid);
+	free_rmid(rdtgrp->rmid);
+
+	/*
+	 * Free all the child monitor group rmids.
+	 */
+	llist = &rdtgrp->crdtgrp_list;
+	list_for_each_entry_safe(entry, tmp, llist, crdtgrp_list) {
+		free_rmid(entry->rmid);
+		list_del(&entry->crdtgrp_list);
+		kfree(entry);
+	}
+
 	list_del(&rdtgrp->rdtgroup_list);
 
 	/*
@@ -1630,10 +1695,33 @@ static int rdtgroup_rmdir(struct kernfs_node *kn)
 	 */
 	kernfs_get(kn);
 	kernfs_remove(rdtgrp->kn);
-	ret = 0;
+	free_cpumask_var(tmpmask);
+
+	return 0;
+}
+
+static int rdtgroup_rmdir(struct kernfs_node *kn)
+{
+	struct kernfs_node *parent_kn = kn->parent;
+	struct rdtgroup *rdtgrp;
+	int ret = 0;
+
+	rdtgrp = rdtgroup_kn_lock_live(kn);
+	if (!rdtgrp) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn)
+		ret = rdtgroup_rmdir_ctrl(kn, rdtgrp);
+	else if (rdtgrp->type == RDTMON_GROUP &&
+		 !strcmp(parent_kn->name, "mon_groups"))
+		ret = rdtgroup_rmdir_mon(kn, rdtgrp);
+	else
+		ret = -EPERM;
+
 out:
 	rdtgroup_kn_unlock(kn);
-	free_cpumask_var(tmpmask);
 	return ret;
 }
 
-- 
1.9.1

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


#1679465 — Re: [PATCH 15/21] x86/intel_rdt/cqm: Add rmdir support

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 15:20 +0200
SubjectRe: [PATCH 15/21] x86/intel_rdt/cqm: Add rmdir support
Message-ID<tYMX7-2nc-1@gated-at.bofh.it>
In reply to#1675024
On Mon, 26 Jun 2017, Vikas Shivappa wrote:

> Resource groups (ctrl_mon and monitor groups) are represented by
> directories in resctrl fs. Add support to remove the directories.

Again. Please split that patch into two parts; seperate ctrl stuff from rmdir and
then add monitoring support.

> +	rdtgrp->flags = RDT_DELETED;
> +	free_rmid(rdtgrp->rmid);
> +
> +	/*
> +	 * Remove your rmid from the parent ctrl groups list

You are not removing a rmid. You remove the group from the parents group
list. Please be more accurate with your comments. Wrong comments are worse
than no comments.

> +	WARN_ON(list_empty(&prdtgrp->crdtgrp_list));
> +	list_del(&rdtgrp->crdtgrp_list);

> +static int rdtgroup_rmdir_ctrl(struct kernfs_node *kn, struct rdtgroup *rdtgrp)
> +{
> +	int cpu, closid = rdtgroup_default.closid;
> +	struct rdtgroup *entry, *tmp;
> +	struct list_head *llist;

*head please.

> +	cpumask_var_t tmpmask;
> +
> +	if (!zalloc_cpumask_var(&tmpmask, GFP_KERNEL))
> +		return -ENOMEM;

Allocation/free can be done at the call site for both functions.

> +static int rdtgroup_rmdir(struct kernfs_node *kn)
> +{
> +	struct kernfs_node *parent_kn = kn->parent;
> +	struct rdtgroup *rdtgrp;
> +	int ret = 0;
> +
> +	rdtgrp = rdtgroup_kn_lock_live(kn);
> +	if (!rdtgrp) {
> +		ret = -EPERM;
> +		goto out;
> +	}
> +
> +	if (rdtgrp->type == RDTCTRL_GROUP && parent_kn == rdtgroup_default.kn)
> +		ret = rdtgroup_rmdir_ctrl(kn, rdtgrp);
> +	else if (rdtgrp->type == RDTMON_GROUP &&
> +		 !strcmp(parent_kn->name, "mon_groups"))
> +		ret = rdtgroup_rmdir_mon(kn, rdtgrp);
> +	else
> +		ret = -EPERM;

Like in the other patch, please makes this parseable.

Thanks,

	tglx

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


#1675025 — [PATCH 03/21] x86/intel_rdt/cqm: Documentation for resctrl based RDT Monitoring

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 03/21] x86/intel_rdt/cqm: Documentation for resctrl based RDT Monitoring
Message-ID<tWHoS-5Yd-43@gated-at.bofh.it>
In reply to#1675020
Add a description of resctrl based RDT(resource director technology)
monitoring extension and its usage.

[Tony: Added descriptions for how monitoring and allocation are measured
and some cleanups]

Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 Documentation/x86/intel_rdt_ui.txt | 316 ++++++++++++++++++++++++++++++++-----
 1 file changed, 278 insertions(+), 38 deletions(-)

diff --git a/Documentation/x86/intel_rdt_ui.txt b/Documentation/x86/intel_rdt_ui.txt
index c491a1b..76f21e2 100644
--- a/Documentation/x86/intel_rdt_ui.txt
+++ b/Documentation/x86/intel_rdt_ui.txt
@@ -6,8 +6,8 @@ Fenghua Yu <fenghua.yu@intel.com>
 Tony Luck <tony.luck@intel.com>
 Vikas Shivappa <vikas.shivappa@intel.com>
 
-This feature is enabled by the CONFIG_INTEL_RDT_A Kconfig and the
-X86 /proc/cpuinfo flag bits "rdt", "cat_l3" and "cdp_l3".
+This feature is enabled by the CONFIG_INTEL_RDT Kconfig and the
+X86 /proc/cpuinfo flag bits "rdt", "cqm", "cat_l3" and "cdp_l3".
 
 To use the feature mount the file system:
 
@@ -17,6 +17,13 @@ mount options are:
 
 "cdp": Enable code/data prioritization in L3 cache allocations.
 
+RDT features are orthogonal. A particular system may support only
+monitoring, only control, or both monitoring and control.
+
+The mount succeeds if either of allocation or monitoring is present, but
+only those files and directories supported by the system will be created.
+For more details on the behavior of the interface during monitoring
+and allocation, see the "Resource alloc and monitor groups" section.
 
 Info directory
 --------------
@@ -24,7 +31,12 @@ Info directory
 The 'info' directory contains information about the enabled
 resources. Each resource has its own subdirectory. The subdirectory
 names reflect the resource names.
-Cache resource(L3/L2)  subdirectory contains the following files:
+
+Each subdirectory contains the following files with respect to
+allocation:
+
+Cache resource(L3/L2)  subdirectory contains the following files
+related to allocation:
 
 "num_closids":  	The number of CLOSIDs which are valid for this
 			resource. The kernel uses the smallest number of
@@ -36,7 +48,8 @@ Cache resource(L3/L2)  subdirectory contains the following files:
 "min_cbm_bits": 	The minimum number of consecutive bits which
 			must be set when writing a mask.
 
-Memory bandwitdh(MB) subdirectory contains the following files:
+Memory bandwitdh(MB) subdirectory contains the following files
+with respect to allocation:
 
 "min_bandwidth":	The minimum memory bandwidth percentage which
 			user can request.
@@ -52,48 +65,152 @@ Memory bandwitdh(MB) subdirectory contains the following files:
 			non-linear. This field is purely informational
 			only.
 
-Resource groups
----------------
+If RDT monitoring is available there will be an "L3_MON" directory
+with the following files:
+
+"num_rmids":		The number of RMIDs available. This is the
+			upper bound for how many "CTRL_MON" + "MON"
+			groups can be created.
+
+"mon_features":	Lists the monitoring events if
+			monitoring is enabled for the resource.
+
+"max_threshold_occupancy":
+			Read/write file provides the largest value (in
+			bytes) at which a previously used LLC_occupancy
+			counter can be considered for re-use.
+
+
+Resource alloc and monitor groups
+---------------------------------
+
 Resource groups are represented as directories in the resctrl file
-system. The default group is the root directory. Other groups may be
-created as desired by the system administrator using the "mkdir(1)"
-command, and removed using "rmdir(1)".
+system.  The default group is the root directory which, immediately
+after mounting, owns all the tasks and cpus in the system and can make
+full use of all resources.
+
+On a system with RDT control features additional directories can be
+created in the root directory that specify different amounts of each
+resource (see "schemata" below). The root and these additional top level
+directories are referred to as "CTRL_MON" groups below.
+
+On a system with RDT monitoring the root directory and other top level
+directories contain a directory named "mon_groups" in which additional
+directories can be created to monitor subsets of tasks in the CTRL_MON
+group that is their ancestor. These are called "MON" groups in the rest
+of this document.
+
+Removing a directory will move all tasks and cpus owned by the group it
+represents to the parent. Removing one of the created CTRL_MON groups
+will automatically remove all MON groups below it.
+
+All groups contain the following files:
+
+"tasks":
+	Reading this file shows the list of all tasks that belong to
+	this group. Writing a task id to the file will add a task to the
+	group. If the group is a CTRL_MON group the task is removed from
+	whichever previous CTRL_MON group owned the task and also from
+	any MON group that owned the task. If the group is a MON group,
+	then the task must already belong to the CTRL_MON parent of this
+	group. The task is removed from any previous MON group.
+
+
+"cpus":
+	Reading this file shows a bitmask of the logical CPUs owned by
+	this group. Writing a mask to this file will add and remove
+	CPUs to/from this group. As with the tasks file a hierarchy is
+	maintained where MON groups may only include CPUs owned by the
+	parent CTRL_MON group.
+
+
+"cpus_list":
+	Just like "cpus", only using ranges of CPUs instead of bitmasks.
 
-There are three files associated with each group:
 
-"tasks": A list of tasks that belongs to this group. Tasks can be
-	added to a group by writing the task ID to the "tasks" file
-	(which will automatically remove them from the previous
-	group to which they belonged). New tasks created by fork(2)
-	and clone(2) are added to the same group as their parent.
-	If a pid is not in any sub partition, it is in root partition
-	(i.e. default partition).
+When control is enabled all CTRL_MON groups will also contain:
 
-"cpus": A bitmask of logical CPUs assigned to this group. Writing
-	a new mask can add/remove CPUs from this group. Added CPUs
-	are removed from their previous group. Removed ones are
-	given to the default (root) group. You cannot remove CPUs
-	from the default group.
+"schemata":
+	A list of all the resources available to this group.
+	Each resource has its own line and format - see below for details.
 
-"cpus_list": One or more CPU ranges of logical CPUs assigned to this
-	     group. Same rules apply like for the "cpus" file.
+When monitoring is enabled all MON groups will also contain:
 
-"schemata": A list of all the resources available to this group.
-	Each resource has its own line and format - see below for
-	details.
+"mon_data":
+	This contains a set of files organized by L3 domain and by
+	RDT event. E.g. on a system with two L3 domains there will
+	be subdirectories "mon_L3_00" and "mon_L3_01".	Each of these
+	directories have one file per event (e.g. "llc_occupancy",
+	"mbm_total_bytes", and "mbm_local_bytes"). In a MON group these
+	files provide a read out of the current value of the event for
+	all tasks in the group. In CTRL_MON groups these files provide
+	the sum for all tasks in the CTRL_MON group and all tasks in
+	MON groups. Please see example section for more details on usage.
 
-When a task is running the following rules define which resources
-are available to it:
+Resource allocation rules
+-------------------------
+When a task is running the following rules define which resources are
+available to it:
 
 1) If the task is a member of a non-default group, then the schemata
-for that group is used.
+   for that group is used.
 
 2) Else if the task belongs to the default group, but is running on a
-CPU that is assigned to some specific group, then the schemata for
-the CPU's group is used.
+   CPU that is assigned to some specific group, then the schemata for the
+   CPU's group is used.
 
 3) Otherwise the schemata for the default group is used.
 
+Resource monitoring rules
+-------------------------
+1) If a task is a member of a MON group, or non-default CTRL_MON group
+   then RDT events for the task will be reported in that group.
+
+2) If a task is a member of the default CTRL_MON group, but is running
+   on a CPU that is assigned to some specific group, then the RDT events
+   for the task will be reported in that group.
+
+3) Otherwise RDT events for the task will be reported in the root level
+   "mon_data" group.
+
+
+Notes on cache occupancy monitoring and control
+-----------------------------------------------
+When moving a task from one group to another you should remember that
+this only affects *new* cache allocations by the task. E.g. you may have
+a task in a monitor group showing 3 MB of cache occupancy. If you move
+to a new group and immediately check the occupancy of the old and new
+groups you will likely see that the old group is still showing 3 MB and
+the new group zero. When the task accesses locations still in cache from
+before the move, the h/w does not update any counters. On a busy system
+you will likely see the occupancy in the old group go down as cache lines
+are evicted and re-used while the occupancy in the new group rises as
+the task accesses memory and loads into the cache are counted based on
+membership in the new group.
+
+The same applies to cache allocation control. Moving a task to a group
+with a smaller cache partition will not evict any cache lines. The
+process may continue to use them from the old partition.
+
+Hardware uses CLOSid(Class of service ID) and an RMID(Resource monitoring ID)
+to identify a control group and a monitoring group respectively. Each of
+the resource groups are mapped to these IDs based on the kind of group. The
+number of CLOSid and RMID are limited by the hardware and hence the creation of
+a "CTRL_MON" directory may fail if we run out of either CLOSID or RMID
+and creation of "MON" group may fail if we run out of RMIDs.
+
+max_threshold_occupancy - generic concepts
+------------------------------------------
+
+Note that an RMID once freed may not be immediately available for use as
+the RMID is still tagged the cache lines of the previous user of RMID.
+Hence such RMIDs are placed on limbo list and checked back if the cache
+occupancy has gone down. If there is a time when system has a lot of
+limbo RMIDs but which are not ready to be used, user may see an -EBUSY
+during mkdir.
+
+max_threshold_occupancy is a user configurable value to determine the
+occupancy at which an RMID can be freed.
 
 Schemata files - general concepts
 ---------------------------------
@@ -143,22 +260,22 @@ SKUs. Using a high bandwidth and a low bandwidth setting on two threads
 sharing a core will result in both threads being throttled to use the
 low bandwidth.
 
-L3 details (code and data prioritization disabled)
---------------------------------------------------
+L3 schemata file details (code and data prioritization disabled)
+----------------------------------------------------------------
 With CDP disabled the L3 schemata format is:
 
 	L3:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
 
-L3 details (CDP enabled via mount option to resctrl)
-----------------------------------------------------
+L3 schemata file details (CDP enabled via mount option to resctrl)
+------------------------------------------------------------------
 When CDP is enabled L3 control is split into two separate resources
 so you can specify independent masks for code and data like this:
 
 	L3data:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
 	L3code:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
 
-L2 details
-----------
+L2 schemata file details
+------------------------
 L2 cache does not support code and data prioritization, so the
 schemata format is always:
 
@@ -185,6 +302,8 @@ L3CODE:0=fffff;1=fffff;2=fffff;3=fffff
 L3DATA:0=fffff;1=fffff;2=3c0;3=fffff
 L3CODE:0=fffff;1=fffff;2=fffff;3=fffff
 
+Examples for RDT allocation usage:
+
 Example 1
 ---------
 On a two socket machine (one L3 cache per socket) with just four bits
@@ -410,3 +529,124 @@ void main(void)
 	/* code to read and write directory contents */
 	resctrl_release_lock(fd);
 }
+
+Examples for RDT Monitoring along with allocation usage:
+
+Reading monitored data
+----------------------
+Reading an event file (for ex: mon_data/mon_L3_00/llc_occupancy) would
+show the current snapshot of LLC occupancy of the corresponding MON
+group or CTRL_MON group.
+
+
+Example 1 (Monitor CTRL_MON group and subset of tasks in CTRL_MON group)
+---------
+On a two socket machine (one L3 cache per socket) with just four bits
+for cache bit masks
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+# mkdir p0 p1
+# echo "L3:0=3;1=c" > /sys/fs/resctrl/p0/schemata
+# echo "L3:0=3;1=3" > /sys/fs/resctrl/p1/schemata
+# echo 5678 > p1/tasks
+# echo 5679 > p1/tasks
+
+The default resource group is unmodified, so we have access to all parts
+of all caches (its schemata file reads "L3:0=f;1=f").
+
+Tasks that are under the control of group "p0" may only allocate from the
+"lower" 50% on cache ID 0, and the "upper" 50% of cache ID 1.
+Tasks in group "p1" use the "lower" 50% of cache on both sockets.
+
+Create monitor groups and assign a subset of tasks to each monitor group.
+
+# cd /sys/fs/resctrl/p1/mon_groups
+# mkdir m11 m12
+# echo 5678 > m11/tasks
+# echo 5679 > m12/tasks
+
+fetch data (data shown in bytes)
+
+# cat m11/mon_data/mon_L3_00/llc_occupancy
+16234000
+# cat m11/mon_data/mon_L3_01/llc_occupancy
+14789000
+# cat m12/mon_data/mon_L3_00/llc_occupancy
+16789000
+
+The parent ctrl_mon group shows the aggregated data.
+
+# cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
+31234000
+
+Example 2 (Monitor a task from its creation)
+---------
+On a two socket machine (one L3 cache per socket)
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+# mkdir p0 p1
+
+An RMID is allocated to the group once its created and hence the <cmd>
+below is monitored from its creation.
+
+# echo $$ > /sys/fs/resctrl/p1/tasks
+# <cmd>
+
+Fetch the data
+
+# cat /sys/fs/resctrl/p1/mon_data/mon_l3_00/llc_occupancy
+31789000
+
+Example 3 (Monitor without CAT support or before creating CAT groups)
+---------
+
+Assume a system like HSW has only CQM and no CAT support. In this case
+the resctrl will still mount but cannot create CTRL_MON directories.
+But user can create different MON groups within the root group thereby
+able to monitor all tasks including kernel threads.
+
+This can also be used to profile jobs cache size footprint before being
+able to allocate them to different allocation groups.
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+# mkdir mon_groups/m01
+# mkdir mon_groups/m02
+
+# echo 3478 > /sys/fs/resctrl/mon_groups/m01/tasks
+# echo 2467 > /sys/fs/resctrl/mon_groups/m02/tasks
+
+Monitor the groups separately and also get per domain data. From the
+below its apparent that the tasks are mostly doing work on
+domain(socket) 0.
+
+# cat /sys/fs/resctrl/mon_groups/m01/mon_L3_00/llc_occupancy
+31234000
+# cat /sys/fs/resctrl/mon_groups/m01/mon_L3_01/llc_occupancy
+34555
+# cat /sys/fs/resctrl/mon_groups/m02/mon_L3_00/llc_occupancy
+31234000
+# cat /sys/fs/resctrl/mon_groups/m02/mon_L3_01/llc_occupancy
+32789
+
+
+Example 4 (Monitor real time tasks)
+-----------------------------------
+
+A single socket system which has real time tasks running on cores 4-7
+and non real time tasks on other cpus. We want to monitor the cache
+occupancy of the real time threads on these cores.
+
+# mount -t resctrl resctrl /sys/fs/resctrl
+# cd /sys/fs/resctrl
+# mkdir p1
+
+Move the cpus 4-7 over to p1
+# echo f0 > p0/cpus
+
+View the llc occupancy snapshot
+
+# cat /sys/fs/resctrl/p1/mon_data/mon_L3_00/llc_occupancy
+11234000
-- 
1.9.1

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


#1675026 — [PATCH 21/21] x86/intel_rdt/mbm: Handle counter overflow

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 21/21] x86/intel_rdt/mbm: Handle counter overflow
Message-ID<tWHoS-5Yd-47@gated-at.bofh.it>
In reply to#1675020
Set up a delayed work queue for each domain that will read all
the MBM counters of active RMIDs once per second to make sure
that they don't wrap around between reads from users.

[Tony: Added the initializations for the work structure and completed
the patch]

Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/intel_rdt.c          | 34 +++++++++++++++----
 arch/x86/kernel/cpu/intel_rdt.h          |  9 +++++
 arch/x86/kernel/cpu/intel_rdt_monitor.c  | 57 ++++++++++++++++++++++++++++++++
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c |  9 +++++
 4 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index 7762e32..fe5c22a 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -318,6 +318,19 @@ static u32 delay_bw_map(unsigned long bw, struct rdt_resource *r)
 		wrmsrl(r->msr_base + cbm_idx(r, i), d->ctrl_val[i]);
 }
 
+struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r)
+{
+	struct rdt_domain *d;
+
+	list_for_each_entry(d, &r->domains, list) {
+		/* Find the domain that contains this CPU */
+		if (cpumask_test_cpu(cpu, &d->cpu_mask))
+			return d;
+	}
+
+	return NULL;
+}
+
 void rdt_ctrl_update(void *arg)
 {
 	struct msr_param *m = arg;
@@ -325,12 +338,10 @@ void rdt_ctrl_update(void *arg)
 	int cpu = smp_processor_id();
 	struct rdt_domain *d;
 
-	list_for_each_entry(d, &r->domains, list) {
-		/* Find the domain that contains this CPU */
-		if (cpumask_test_cpu(cpu, &d->cpu_mask)) {
-			r->msr_update(d, m, r);
-			return;
-		}
+	d = get_domain_from_cpu(cpu, r);
+	if (d) {
+		r->msr_update(d, m, r);
+		return;
 	}
 	pr_warn_once("cpu %d not found in any domain for resource %s\n",
 		     cpu, r->name);
@@ -413,6 +424,12 @@ static bool domain_setup_mbm_state(struct rdt_resource *r, struct rdt_domain *d)
 			return false;
 		}
 	}
+
+	if (is_mbm_enabled()) {
+		INIT_DELAYED_WORK(&d->mbm_over, mbm_handle_overflow);
+		mbm_setup_overflow_handler(d);
+	}
+
 	return true;
 }
 
@@ -495,7 +512,12 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r)
 		kfree(d->mbm_total);
 		kfree(d->mbm_local);
 		list_del(&d->list);
+		cancel_delayed_work(&d->mbm_over);
 		kfree(d);
+	} else if (r == &rdt_resources_all[RDT_RESOURCE_L3] &&
+		   cpu == d->mbm_work_cpu) {
+		cancel_delayed_work(&d->mbm_over);
+		mbm_setup_overflow_handler(d);
 	}
 }
 
diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index f0896ac..652efdbe 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -21,6 +21,7 @@
 #define QOS_L3_MBM_LOCAL_EVENT_ID	0x03
 
 #define MBM_CNTR_WIDTH         24
+#define MBM_OVERFLOW_INTERVAL	1000
 
 #define RMID_VAL_ERROR		(1ULL << 63)
 #define RMID_VAL_UNAVAIL	(1ULL << 62)
@@ -179,6 +180,9 @@ struct mbm_state {
  * @cpu_mask:	which cpus share this resource
  * @mbm_total:	saved state for MBM total bandwidth
  * @mbm_local:	saved state for MBM local bandwidth
+ * @mbm_over:	worker to periodically read MBM h/w counters
+ * @mbm_work_cpu:
+ *		worker cpu for MBM h/w counters
  * @ctrl_val:	array of cache or mem ctrl values (indexed by CLOSID)
  * @new_ctrl:	new ctrl value to be loaded
  * @have_new_ctrl: did user provide new_ctrl for this domain
@@ -189,6 +193,8 @@ struct rdt_domain {
 	struct cpumask		cpu_mask;
 	struct mbm_state	*mbm_total;
 	struct mbm_state	*mbm_local;
+	struct delayed_work	mbm_over;
+	int			mbm_work_cpu;
 	u32			*ctrl_val;
 	u32			new_ctrl;
 	bool			have_new_ctrl;
@@ -389,6 +395,7 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
 				char *buf, size_t nbytes, loff_t off);
 int rdtgroup_schemata_show(struct kernfs_open_file *of,
 			   struct seq_file *s, void *v);
+struct rdt_domain *get_domain_from_cpu(int cpu, struct rdt_resource *r);
 int alloc_rmid(void);
 void free_rmid(u32 rmid);
 void rdt_get_mon_l3_config(struct rdt_resource *r);
@@ -400,5 +407,7 @@ void mkdir_mondata_subdir_allrdtgrp(struct rdt_resource *r,
 				    struct rdt_domain *d);
 void mon_event_read(struct rmid_read *rr, struct rdt_domain *d,
 		    struct rdtgroup *rdtgrp, int evtid, int first);
+void mbm_setup_overflow_handler(struct rdt_domain *dom);
+void mbm_handle_overflow(struct work_struct *work);
 
 #endif /* _ASM_X86_INTEL_RDT_H */
diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c
index a196f4d..d78a635 100644
--- a/arch/x86/kernel/cpu/intel_rdt_monitor.c
+++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c
@@ -271,6 +271,63 @@ void mon_event_count(void *info)
 	}
 }
 
+static void mbm_update(struct rdt_domain *d, int rmid)
+{
+	struct rmid_read rr;
+
+	rr.first = false;
+	rr.d = d;
+
+	if (is_mbm_total_enabled()) {
+		rr.evtid = QOS_L3_MBM_TOTAL_EVENT_ID;
+		__mon_event_count(rmid, &rr);
+	}
+	if (is_mbm_local_enabled()) {
+		rr.evtid = QOS_L3_MBM_LOCAL_EVENT_ID;
+		__mon_event_count(rmid, &rr);
+	}
+}
+
+void mbm_handle_overflow(struct work_struct *work)
+{
+	unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL);
+	int cpu = smp_processor_id();
+	struct rdtgroup *pr, *cr;
+	struct rdt_domain *d;
+
+	mutex_lock(&rdtgroup_mutex);
+
+	if (!static_branch_likely(&rdt_enable_key))
+		goto out_unlock;
+
+	d = get_domain_from_cpu(cpu, &rdt_resources_all[RDT_RESOURCE_L3]);
+	if (!d)
+		goto out_unlock;
+
+	list_for_each_entry(pr, &rdt_all_groups, rdtgroup_list) {
+		mbm_update(d, pr->rmid);
+
+		list_for_each_entry(cr, &pr->crdtgrp_list, crdtgrp_list)
+			mbm_update(d, cr->rmid);
+	}
+
+	schedule_delayed_work_on(cpu, &d->mbm_over, delay);
+out_unlock:
+	mutex_unlock(&rdtgroup_mutex);
+}
+
+void mbm_setup_overflow_handler(struct rdt_domain *dom)
+{
+	unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL);
+	int cpu;
+
+	if (!static_branch_likely(&rdt_enable_key))
+		return;
+	cpu = cpumask_any(&dom->cpu_mask);
+	dom->mbm_work_cpu = cpu;
+	schedule_delayed_work_on(cpu, &dom->mbm_over, delay);
+}
+
 static int dom_data_init(struct rdt_resource *r)
 {
 	struct rmid_entry *entry = NULL;
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index 1b84485..a78f7f7 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -1092,6 +1092,8 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
 				int flags, const char *unused_dev_name,
 				void *data)
 {
+	struct rdt_domain *dom;
+	struct rdt_resource *r;
 	struct dentry *dentry;
 	int ret;
 
@@ -1150,6 +1152,13 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
 
 	if (rdt_alloc_enabled || rdt_mon_features)
 		static_branch_enable(&rdt_enable_key);
+
+	if (is_mbm_enabled()) {
+		r = &rdt_resources_all[RDT_RESOURCE_L3];
+		list_for_each_entry(dom, &r->domains, list)
+			mbm_setup_overflow_handler(dom);
+	}
+
 	goto out;
 
 out_mondata:
-- 
1.9.1

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


#1679471 — Re: [PATCH 21/21] x86/intel_rdt/mbm: Handle counter overflow

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 16:00 +0200
SubjectRe: [PATCH 21/21] x86/intel_rdt/mbm: Handle counter overflow
Message-ID<tYNzP-2La-1@gated-at.bofh.it>
In reply to#1675026
On Mon, 26 Jun 2017, Vikas Shivappa wrote:
> +static void mbm_update(struct rdt_domain *d, int rmid)
> +{
> +	struct rmid_read rr;
> +
> +	rr.first = false;
> +	rr.d = d;
> +
> +	if (is_mbm_total_enabled()) {
> +		rr.evtid = QOS_L3_MBM_TOTAL_EVENT_ID;
> +		__mon_event_count(rmid, &rr);

This is broken as it is not protected against a concurrent read from user
space which comes in via a smp function call.

This means both the internal state and __rmid_read() are unprotected.

I'm not sure whether it's enough to disable interrupts around
__mon_event_count(), but that's the minimal protection required. It's
definitely good enough for __rmid_read(), but it might not be sufficient
for protecting domain->mbm_[local|total]. I leave the exercise of figuring
that out to you.

Thanks,

	tglx

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


#1675027 — [PATCH 14/21] x86/intel_rdt/cqm: Add mon_data

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 14/21] x86/intel_rdt/cqm: Add mon_data
Message-ID<tWHoT-5Yd-49@gated-at.bofh.it>
In reply to#1675020
Add a mon_data directory for the root rdtgroup and all other rdtgroups.
The directory holds all of the monitored data for all domains and events
of all resources being monitored.

The mon_data itself has a list of directories in the format
mon_<domain_name>_<domain_id>. Each of these subdirectories contain one
file per event in the mode "0444". Reading the file displays a snapshot
of the monitored data for the event the file represents.

For ex, on a 2 socket Broadwell with llc_occupancy being
monitored the mon_data contents look as below:

$ ls /sys/fs/resctrl/p1/mon_data/
mon_L3_00
mon_L3_01

Each domain directory has one file per event:
$ ls /sys/fs/resctrl/p1/mon_data/mon_L3_00/
llc_occupancy

To read current llc_occupancy of ctrl_mon group p1
$ cat /sys/fs/resctrl/p1/mon_data/mon_L3_00/llc_occupancy
33789096

[This patch idea is based on Tony's sample patches to organise data in a
per domain directory and have one file per event (and use the fp->priv to
store mon data bits)]

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/Makefile                |   2 +-
 arch/x86/kernel/cpu/intel_rdt.c             |   4 +-
 arch/x86/kernel/cpu/intel_rdt.h             |  27 +++
 arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c | 332 ++++++++++++++++++++++++++++
 arch/x86/kernel/cpu/intel_rdt_monitor.c     |  42 ++++
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c    | 155 +++++++++++++
 arch/x86/kernel/cpu/intel_rdt_schemata.c    | 286 ------------------------
 7 files changed, 559 insertions(+), 289 deletions(-)
 create mode 100644 arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
 delete mode 100644 arch/x86/kernel/cpu/intel_rdt_schemata.c

diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 81b0060..1245f98 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -32,7 +32,7 @@ obj-$(CONFIG_CPU_SUP_CENTAUR)		+= centaur.o
 obj-$(CONFIG_CPU_SUP_TRANSMETA_32)	+= transmeta.o
 obj-$(CONFIG_CPU_SUP_UMC_32)		+= umc.o
 
-obj-$(CONFIG_INTEL_RDT)	+= intel_rdt.o intel_rdt_rdtgroup.o intel_rdt_schemata.o intel_rdt_monitor.o
+obj-$(CONFIG_INTEL_RDT)	+= intel_rdt.o intel_rdt_rdtgroup.o intel_rdt_monitor.o intel_rdt_ctrlmondata.o
 
 obj-$(CONFIG_X86_MCE)			+= mcheck/
 obj-$(CONFIG_MTRR)			+= mtrr/
diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c
index b0f8c35..63bfb47c 100644
--- a/arch/x86/kernel/cpu/intel_rdt.c
+++ b/arch/x86/kernel/cpu/intel_rdt.c
@@ -344,8 +344,8 @@ void rdt_ctrl_update(void *arg)
  * caller, return the first domain whose id is bigger than the input id.
  * The domain list is sorted by id in ascending order.
  */
-static struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id,
-					  struct list_head **pos)
+struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id,
+				   struct list_head **pos)
 {
 	struct rdt_domain *d;
 	struct list_head *l;
diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index fec8ba9..631d58e 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -33,6 +33,27 @@ struct mon_evt {
 	struct list_head	list;
 };
 
+/**
+ * struct mon_data_bits - Monitoring details for each event file
+ * @rid:               Resource id associated with the event file.
+ * @evtid:             Event id associated with the event file
+ * @domid:             The domain to which the event file belongs
+ */
+union mon_data_bits {
+	void *priv;
+	struct {
+		unsigned int rid	: 10;
+		unsigned int evtid	: 8;
+		unsigned int domid	: 14;
+	} u;
+};
+
+struct rmid_read {
+	struct rdtgroup		*rgrp;
+	int			evtid;
+	u64			val;
+};
+
 extern unsigned int intel_cqm_threshold;
 extern bool rdt_alloc_enabled;
 extern int rdt_mon_features;
@@ -48,6 +69,7 @@ enum rdt_group_type {
 /**
  * struct rdtgroup - store rdtgroup's data in resctrl file system.
  * @kn:				kernfs node
+ * @mon_data_kn		kernlfs node for the mon_data directory
  * @rdtgroup_list:		linked list for all rdtgroups
  * @parent:			parent rdtgrp
  * @crdtgrp_list:		child rdtgroup node list
@@ -62,6 +84,7 @@ enum rdt_group_type {
  */
 struct rdtgroup {
 	struct kernfs_node	*kn;
+	struct kernfs_node	*mon_data_kn;
 	struct list_head	rdtgroup_list;
 	struct rdtgroup		*parent;
 	struct list_head	crdtgrp_list;
@@ -311,6 +334,8 @@ enum {
 void rdt_ctrl_update(void *arg);
 struct rdtgroup *rdtgroup_kn_lock_live(struct kernfs_node *kn);
 void rdtgroup_kn_unlock(struct kernfs_node *kn);
+struct rdt_domain *rdt_find_domain(struct rdt_resource *r, int id,
+				   struct list_head **pos);
 ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
 				char *buf, size_t nbytes, loff_t off);
 int rdtgroup_schemata_show(struct kernfs_open_file *of,
@@ -318,5 +343,7 @@ int rdtgroup_schemata_show(struct kernfs_open_file *of,
 int alloc_rmid(void);
 void free_rmid(u32 rmid);
 void rdt_get_mon_l3_config(struct rdt_resource *r);
+void mon_event_count(void *info);
+int rdtgroup_mondata_show(struct seq_file *m, void *arg);
 
 #endif /* _ASM_X86_INTEL_RDT_H */
diff --git a/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c b/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
new file mode 100644
index 0000000..0c8bca0
--- /dev/null
+++ b/arch/x86/kernel/cpu/intel_rdt_ctrlmondata.c
@@ -0,0 +1,332 @@
+/*
+ * Resource Director Technology(RDT)
+ * - Cache Allocation code.
+ *
+ * Copyright (C) 2016 Intel Corporation
+ *
+ * Authors:
+ *    Fenghua Yu <fenghua.yu@intel.com>
+ *    Tony Luck <tony.luck@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * More information about RDT be found in the Intel (R) x86 Architecture
+ * Software Developer Manual June 2016, volume 3, section 17.17.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernfs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include "intel_rdt.h"
+
+/*
+ * Check whether MBA bandwidth percentage value is correct. The value is
+ * checked against the minimum and max bandwidth values specified by the
+ * hardware. The allocated bandwidth percentage is rounded to the next
+ * control step available on the hardware.
+ */
+static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
+{
+	unsigned long bw;
+	int ret;
+
+	/*
+	 * Only linear delay values is supported for current Intel SKUs.
+	 */
+	if (!r->membw.delay_linear)
+		return false;
+
+	ret = kstrtoul(buf, 10, &bw);
+	if (ret)
+		return false;
+
+	if (bw < r->membw.min_bw || bw > r->default_ctrl)
+		return false;
+
+	*data = roundup(bw, (unsigned long)r->membw.bw_gran);
+	return true;
+}
+
+int parse_bw(char *buf, struct rdt_resource *r, struct rdt_domain *d)
+{
+	unsigned long data;
+
+	if (d->have_new_ctrl)
+		return -EINVAL;
+
+	if (!bw_validate(buf, &data, r))
+		return -EINVAL;
+	d->new_ctrl = data;
+	d->have_new_ctrl = true;
+
+	return 0;
+}
+
+/*
+ * Check whether a cache bit mask is valid. The SDM says:
+ *	Please note that all (and only) contiguous '1' combinations
+ *	are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
+ * Additionally Haswell requires at least two bits set.
+ */
+static bool cbm_validate(char *buf, unsigned long *data, struct rdt_resource *r)
+{
+	unsigned long first_bit, zero_bit, val;
+	unsigned int cbm_len = r->cache.cbm_len;
+	int ret;
+
+	ret = kstrtoul(buf, 16, &val);
+	if (ret)
+		return false;
+
+	if (val == 0 || val > r->default_ctrl)
+		return false;
+
+	first_bit = find_first_bit(&val, cbm_len);
+	zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
+
+	if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len)
+		return false;
+
+	if ((zero_bit - first_bit) < r->cache.min_cbm_bits)
+		return false;
+
+	*data = val;
+	return true;
+}
+
+/*
+ * Read one cache bit mask (hex). Check that it is valid for the current
+ * resource type.
+ */
+int parse_cbm(char *buf, struct rdt_resource *r, struct rdt_domain *d)
+{
+	unsigned long data;
+
+	if (d->have_new_ctrl)
+		return -EINVAL;
+
+	if (!cbm_validate(buf, &data, r))
+		return -EINVAL;
+	d->new_ctrl = data;
+	d->have_new_ctrl = true;
+
+	return 0;
+}
+
+/*
+ * For each domain in this resource we expect to find a series of:
+ *	id=mask
+ * separated by ";". The "id" is in decimal, and must match one of
+ * the "id"s for this resource.
+ */
+static int parse_line(char *line, struct rdt_resource *r)
+{
+	char *dom = NULL, *id;
+	struct rdt_domain *d;
+	unsigned long dom_id;
+
+next:
+	if (!line || line[0] == '\0')
+		return 0;
+	dom = strsep(&line, ";");
+	id = strsep(&dom, "=");
+	if (!dom || kstrtoul(id, 10, &dom_id))
+		return -EINVAL;
+	dom = strim(dom);
+	list_for_each_entry(d, &r->domains, list) {
+		if (d->id == dom_id) {
+			if (r->parse_ctrlval(dom, r, d))
+				return -EINVAL;
+			goto next;
+		}
+	}
+	return -EINVAL;
+}
+
+static int update_domains(struct rdt_resource *r, int closid)
+{
+	struct msr_param msr_param;
+	cpumask_var_t cpu_mask;
+	struct rdt_domain *d;
+	int cpu;
+
+	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+		return -ENOMEM;
+
+	msr_param.low = closid;
+	msr_param.high = msr_param.low + 1;
+	msr_param.res = r;
+
+	list_for_each_entry(d, &r->domains, list) {
+		if (d->have_new_ctrl && d->new_ctrl != d->ctrl_val[closid]) {
+			cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+			d->ctrl_val[closid] = d->new_ctrl;
+		}
+	}
+	if (cpumask_empty(cpu_mask))
+		goto done;
+	cpu = get_cpu();
+	/* Update CBM on this cpu if it's in cpu_mask. */
+	if (cpumask_test_cpu(cpu, cpu_mask))
+		rdt_ctrl_update(&msr_param);
+	/* Update CBM on other cpus. */
+	smp_call_function_many(cpu_mask, rdt_ctrl_update, &msr_param, 1);
+	put_cpu();
+
+done:
+	free_cpumask_var(cpu_mask);
+
+	return 0;
+}
+
+static int rdtgroup_parse_resource(char *resname, char *tok, int closid)
+{
+	struct rdt_resource *r;
+
+	for_each_alloc_enabled_rdt_resource(r) {
+		if (!strcmp(resname, r->name) && closid < r->num_closid)
+			return parse_line(tok, r);
+	}
+	return -EINVAL;
+}
+
+ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
+				char *buf, size_t nbytes, loff_t off)
+{
+	struct rdtgroup *rdtgrp;
+	struct rdt_domain *dom;
+	struct rdt_resource *r;
+	char *tok, *resname;
+	int closid, ret = 0;
+
+	/* Valid input requires a trailing newline */
+	if (nbytes == 0 || buf[nbytes - 1] != '\n')
+		return -EINVAL;
+	buf[nbytes - 1] = '\0';
+
+	rdtgrp = rdtgroup_kn_lock_live(of->kn);
+	if (!rdtgrp) {
+		rdtgroup_kn_unlock(of->kn);
+		return -ENOENT;
+	}
+
+	closid = rdtgrp->closid;
+
+	for_each_alloc_enabled_rdt_resource(r) {
+		list_for_each_entry(dom, &r->domains, list)
+			dom->have_new_ctrl = false;
+	}
+
+	while ((tok = strsep(&buf, "\n")) != NULL) {
+		resname = strim(strsep(&tok, ":"));
+		if (!tok) {
+			ret = -EINVAL;
+			goto out;
+		}
+		ret = rdtgroup_parse_resource(resname, tok, closid);
+		if (ret)
+			goto out;
+	}
+
+	for_each_alloc_enabled_rdt_resource(r) {
+		ret = update_domains(r, closid);
+		if (ret)
+			goto out;
+	}
+
+out:
+	rdtgroup_kn_unlock(of->kn);
+	return ret ?: nbytes;
+}
+
+static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
+{
+	struct rdt_domain *dom;
+	bool sep = false;
+
+	seq_printf(s, "%*s:", max_name_width, r->name);
+	list_for_each_entry(dom, &r->domains, list) {
+		if (sep)
+			seq_puts(s, ";");
+		seq_printf(s, r->format_str, dom->id, max_data_width,
+			   dom->ctrl_val[closid]);
+		sep = true;
+	}
+	seq_puts(s, "\n");
+}
+
+int rdtgroup_schemata_show(struct kernfs_open_file *of,
+			   struct seq_file *s, void *v)
+{
+	struct rdtgroup *rdtgrp;
+	struct rdt_resource *r;
+	int closid, ret = 0;
+
+	rdtgrp = rdtgroup_kn_lock_live(of->kn);
+	if (rdtgrp) {
+		closid = rdtgrp->closid;
+		for_each_alloc_enabled_rdt_resource(r) {
+			if (closid < r->num_closid)
+				show_doms(s, r, closid);
+		}
+	} else {
+		ret = -ENOENT;
+	}
+	rdtgroup_kn_unlock(of->kn);
+	return ret;
+}
+
+int rdtgroup_mondata_show(struct seq_file *m, void *arg)
+{
+	struct kernfs_open_file *of = m->private;
+	u32 resid, evtid, domid;
+	struct rdtgroup *rdtgrp;
+	struct rdt_resource *r;
+	union mon_data_bits md;
+	struct rdt_domain *d;
+	struct rmid_read rr;
+	int ret = 0;
+
+	rdtgrp = rdtgroup_kn_lock_live(of->kn);
+
+	md.priv = of->kn->priv;
+	resid = md.u.rid;
+	domid = md.u.domid;
+	evtid = md.u.evtid;
+
+	r = &rdt_resources_all[resid];
+	d = rdt_find_domain(r, domid, NULL);
+	if (!d) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	/*
+	 * setup the parameters to send to the IPI to read the data.
+	 */
+	rr.rgrp = rdtgrp;
+	rr.evtid = evtid;
+	rr.val = 0;
+
+	smp_call_function_any(&d->cpu_mask, mon_event_count, &rr, 1);
+
+	if (rr.val & RMID_VAL_ERROR)
+		seq_puts(m, "Error\n");
+	else if (rr.val & RMID_VAL_UNAVAIL)
+		seq_puts(m, "Unavailable\n");
+	else
+		seq_printf(m, "%llu\n", rr.val * r->mon_scale);
+
+out:
+	rdtgroup_kn_unlock(of->kn);
+	return ret;
+}
diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c
index 624a0aa..cc252eb 100644
--- a/arch/x86/kernel/cpu/intel_rdt_monitor.c
+++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c
@@ -204,6 +204,48 @@ void free_rmid(u32 rmid)
 		list_add_tail(&entry->list, &rmid_free_lru);
 }
 
+static bool __mon_event_count(u32 rmid, struct rmid_read *rr)
+{
+	u64 tval;
+
+	tval = __rmid_read(rmid, rr->evtid);
+	if (tval & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL)) {
+		rr->val = tval;
+		return false;
+	}
+	switch (rr->evtid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		rr->val += tval;
+		return true;
+	default:
+		return false;
+	}
+}
+
+void mon_event_count(void *info)
+{
+	struct rdtgroup *rdtgrp, *entry;
+	struct rmid_read *rr = info;
+	struct list_head *llist;
+
+	rdtgrp = rr->rgrp;
+
+	if (!__mon_event_count(rdtgrp->rmid, rr))
+		return;
+
+	/*
+	 * For Ctrl groups read data from child monitor groups.
+	 */
+	llist = &rdtgrp->crdtgrp_list;
+
+	if (rdtgrp->type == RDTCTRL_GROUP) {
+		list_for_each_entry(entry, llist, crdtgrp_list) {
+			if (!__mon_event_count(entry->rmid, rr))
+				return;
+		}
+	}
+}
+
 static int dom_data_init(struct rdt_resource *r)
 {
 	struct rmid_entry *entry = NULL;
diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index d32b781..9377bcd 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -152,6 +152,11 @@ static ssize_t rdtgroup_file_write(struct kernfs_open_file *of, char *buf,
 	.seq_show		= rdtgroup_seqfile_show,
 };
 
+static struct kernfs_ops kf_mondata_ops = {
+	.atomic_write_len	= PAGE_SIZE,
+	.seq_show		= rdtgroup_mondata_show,
+};
+
 static bool is_cpu_list(struct kernfs_open_file *of)
 {
 	struct rftype *rft = of->kn->priv;
@@ -1251,6 +1256,152 @@ static void rdt_kill_sb(struct super_block *sb)
 	.kill_sb = rdt_kill_sb,
 };
 
+static int mon_addfile(struct kernfs_node *parent_kn, const char *name,
+		       void *priv)
+{
+	struct kernfs_node *kn;
+	int ret = 0;
+
+	kn = __kernfs_create_file(parent_kn, name, 0444, 0,
+				  &kf_mondata_ops, priv, NULL, NULL);
+	if (IS_ERR(kn))
+		return PTR_ERR(kn);
+
+	ret = rdtgroup_kn_set_ugid(kn);
+	if (ret) {
+		kernfs_remove(kn);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int get_rdt_resourceid(struct rdt_resource *r)
+{
+	if (r > (rdt_resources_all + RDT_NUM_RESOURCES - 1) ||
+	    r < rdt_resources_all ||
+	    ((r - rdt_resources_all) % sizeof(struct rdt_resource)))
+		return -EINVAL;
+
+	return ((r - rdt_resources_all) / sizeof(struct rdt_resource));
+}
+
+static int mkdir_mondata_subdir(struct kernfs_node *parent_kn, int domid,
+				struct rdt_resource *r, struct rdtgroup *pr)
+{
+	union mon_data_bits priv;
+	struct kernfs_node *kn;
+	struct mon_evt *mevt;
+	char name[32];
+	int ret, rid;
+
+	rid = get_rdt_resourceid(r);
+	if (rid < 0)
+		return -EINVAL;
+
+	sprintf(name, "mon_%s_%02d", r->name, domid);
+	/* create the directory */
+	kn = kernfs_create_dir(parent_kn, name, parent_kn->mode, pr);
+	if (IS_ERR(kn))
+		return PTR_ERR(kn);
+
+	/*
+	 * This extra ref will be put in kernfs_remove() and guarantees
+	 * that @rdtgrp->kn is always accessible.
+	 */
+	kernfs_get(kn);
+	ret = rdtgroup_kn_set_ugid(kn);
+	if (ret)
+		goto out_destroy;
+
+	if (WARN_ON(list_empty(&r->evt_list))) {
+		ret = -EPERM;
+		goto out_destroy;
+	}
+
+	priv.u.rid = rid;
+	priv.u.domid = domid;
+	list_for_each_entry(mevt, &r->evt_list, list) {
+		priv.u.evtid = mevt->evtid;
+		ret = mon_addfile(kn, mevt->name, priv.priv);
+		if (ret)
+			goto out_destroy;
+	}
+	kernfs_activate(kn);
+	return 0;
+
+out_destroy:
+	kernfs_remove(kn);
+	return ret;
+}
+
+static int mkdir_mondata_subdir_alldom(struct kernfs_node *parent_kn,
+				       struct rdt_resource *r,
+				       struct rdtgroup *pr)
+{
+	struct rdt_domain *dom;
+	int ret;
+
+	list_for_each_entry(dom, &r->domains, list) {
+		ret = mkdir_mondata_subdir(parent_kn, dom->id, r, pr);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * This creates a directory mon_data which holds one subdirectory
+ * per domain which contains the monitored data.
+ *
+ * mon_data has one directory for each domain whic are named
+ * mon_<domain_name>_<domain_id>. For ex: A mon_data with
+ * with L3 domain looks as below:
+ * ./mon_data:
+ * mon_L3_00
+ * mon_L3_01
+ * mon_L3_02
+ * ...
+ *
+ * Each domain directory has one file per event:
+ * ./mon_L3_00/:
+ * llc_occupancy
+ *
+ */
+static int mkdir_mondata_all(struct kernfs_node *parent_kn, struct rdtgroup *pr,
+			     struct kernfs_node **dest_kn)
+{
+	struct rdt_resource *r;
+	struct kernfs_node *kn;
+	int ret;
+
+	/*
+	 * Create the mon_data directory first.
+	 */
+	ret = mongroup_create_dir(parent_kn, NULL, "mon_data", &kn);
+	if (ret)
+		return ret;
+
+	if (dest_kn)
+		*dest_kn = kn;
+
+	/*
+	 * Create the subdirectories for each domain. Note that all events
+	 * in a domain like L3 are grouped into a resource whose domain is L3
+	 */
+	for_each_mon_enabled_rdt_resource(r) {
+		ret = mkdir_mondata_subdir_alldom(kn, r, pr);
+		if (ret)
+			goto out_destroy;
+	}
+
+	return 0;
+
+out_destroy:
+	kernfs_remove(kn);
+	return ret;
+}
 /*
  * Common code for ctrl_mon and monitor group mkdir.
  * The caller needs to unlock the global mutex upon success.
@@ -1307,6 +1458,10 @@ static int mkdir_rdt_common(struct kernfs_node *pkn, struct kernfs_node *prkn,
 		goto out_destroy;
 
 	if (rdt_mon_features) {
+		ret = mkdir_mondata_all(kn, rdtgrp, &rdtgrp->mon_data_kn);
+		if (ret)
+			goto out_destroy;
+
 		ret = alloc_rmid();
 		if (ret < 0)
 			return ret;
diff --git a/arch/x86/kernel/cpu/intel_rdt_schemata.c b/arch/x86/kernel/cpu/intel_rdt_schemata.c
deleted file mode 100644
index 952156c..0000000
--- a/arch/x86/kernel/cpu/intel_rdt_schemata.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Resource Director Technology(RDT)
- * - Cache Allocation code.
- *
- * Copyright (C) 2016 Intel Corporation
- *
- * Authors:
- *    Fenghua Yu <fenghua.yu@intel.com>
- *    Tony Luck <tony.luck@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * More information about RDT be found in the Intel (R) x86 Architecture
- * Software Developer Manual June 2016, volume 3, section 17.17.
- */
-
-#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
-
-#include <linux/kernfs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include "intel_rdt.h"
-
-/*
- * Check whether MBA bandwidth percentage value is correct. The value is
- * checked against the minimum and max bandwidth values specified by the
- * hardware. The allocated bandwidth percentage is rounded to the next
- * control step available on the hardware.
- */
-static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r)
-{
-	unsigned long bw;
-	int ret;
-
-	/*
-	 * Only linear delay values is supported for current Intel SKUs.
-	 */
-	if (!r->membw.delay_linear)
-		return false;
-
-	ret = kstrtoul(buf, 10, &bw);
-	if (ret)
-		return false;
-
-	if (bw < r->membw.min_bw || bw > r->default_ctrl)
-		return false;
-
-	*data = roundup(bw, (unsigned long)r->membw.bw_gran);
-	return true;
-}
-
-int parse_bw(char *buf, struct rdt_resource *r, struct rdt_domain *d)
-{
-	unsigned long data;
-
-	if (d->have_new_ctrl)
-		return -EINVAL;
-
-	if (!bw_validate(buf, &data, r))
-		return -EINVAL;
-	d->new_ctrl = data;
-	d->have_new_ctrl = true;
-
-	return 0;
-}
-
-/*
- * Check whether a cache bit mask is valid. The SDM says:
- *	Please note that all (and only) contiguous '1' combinations
- *	are allowed (e.g. FFFFH, 0FF0H, 003CH, etc.).
- * Additionally Haswell requires at least two bits set.
- */
-static bool cbm_validate(char *buf, unsigned long *data, struct rdt_resource *r)
-{
-	unsigned long first_bit, zero_bit, val;
-	unsigned int cbm_len = r->cache.cbm_len;
-	int ret;
-
-	ret = kstrtoul(buf, 16, &val);
-	if (ret)
-		return false;
-
-	if (val == 0 || val > r->default_ctrl)
-		return false;
-
-	first_bit = find_first_bit(&val, cbm_len);
-	zero_bit = find_next_zero_bit(&val, cbm_len, first_bit);
-
-	if (find_next_bit(&val, cbm_len, zero_bit) < cbm_len)
-		return false;
-
-	if ((zero_bit - first_bit) < r->cache.min_cbm_bits)
-		return false;
-
-	*data = val;
-	return true;
-}
-
-/*
- * Read one cache bit mask (hex). Check that it is valid for the current
- * resource type.
- */
-int parse_cbm(char *buf, struct rdt_resource *r, struct rdt_domain *d)
-{
-	unsigned long data;
-
-	if (d->have_new_ctrl)
-		return -EINVAL;
-
-	if(!cbm_validate(buf, &data, r))
-		return -EINVAL;
-	d->new_ctrl = data;
-	d->have_new_ctrl = true;
-
-	return 0;
-}
-
-/*
- * For each domain in this resource we expect to find a series of:
- *	id=mask
- * separated by ";". The "id" is in decimal, and must match one of
- * the "id"s for this resource.
- */
-static int parse_line(char *line, struct rdt_resource *r)
-{
-	char *dom = NULL, *id;
-	struct rdt_domain *d;
-	unsigned long dom_id;
-
-next:
-	if (!line || line[0] == '\0')
-		return 0;
-	dom = strsep(&line, ";");
-	id = strsep(&dom, "=");
-	if (!dom || kstrtoul(id, 10, &dom_id))
-		return -EINVAL;
-	dom = strim(dom);
-	list_for_each_entry(d, &r->domains, list) {
-		if (d->id == dom_id) {
-			if (r->parse_ctrlval(dom, r, d))
-				return -EINVAL;
-			goto next;
-		}
-	}
-	return -EINVAL;
-}
-
-static int update_domains(struct rdt_resource *r, int closid)
-{
-	struct msr_param msr_param;
-	cpumask_var_t cpu_mask;
-	struct rdt_domain *d;
-	int cpu;
-
-	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
-		return -ENOMEM;
-
-	msr_param.low = closid;
-	msr_param.high = msr_param.low + 1;
-	msr_param.res = r;
-
-	list_for_each_entry(d, &r->domains, list) {
-		if (d->have_new_ctrl && d->new_ctrl != d->ctrl_val[closid]) {
-			cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
-			d->ctrl_val[closid] = d->new_ctrl;
-		}
-	}
-	if (cpumask_empty(cpu_mask))
-		goto done;
-	cpu = get_cpu();
-	/* Update CBM on this cpu if it's in cpu_mask. */
-	if (cpumask_test_cpu(cpu, cpu_mask))
-		rdt_ctrl_update(&msr_param);
-	/* Update CBM on other cpus. */
-	smp_call_function_many(cpu_mask, rdt_ctrl_update, &msr_param, 1);
-	put_cpu();
-
-done:
-	free_cpumask_var(cpu_mask);
-
-	return 0;
-}
-
-static int rdtgroup_parse_resource(char *resname, char *tok, int closid)
-{
-	struct rdt_resource *r;
-
-	for_each_alloc_enabled_rdt_resource(r) {
-		if (!strcmp(resname, r->name) && closid < r->num_closid)
-			return parse_line(tok, r);
-	}
-	return -EINVAL;
-}
-
-ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
-				char *buf, size_t nbytes, loff_t off)
-{
-	struct rdtgroup *rdtgrp;
-	struct rdt_domain *dom;
-	struct rdt_resource *r;
-	char *tok, *resname;
-	int closid, ret = 0;
-
-	/* Valid input requires a trailing newline */
-	if (nbytes == 0 || buf[nbytes - 1] != '\n')
-		return -EINVAL;
-	buf[nbytes - 1] = '\0';
-
-	rdtgrp = rdtgroup_kn_lock_live(of->kn);
-	if (!rdtgrp) {
-		rdtgroup_kn_unlock(of->kn);
-		return -ENOENT;
-	}
-
-	closid = rdtgrp->closid;
-
-	for_each_alloc_enabled_rdt_resource(r) {
-		list_for_each_entry(dom, &r->domains, list)
-			dom->have_new_ctrl = false;
-	}
-
-	while ((tok = strsep(&buf, "\n")) != NULL) {
-		resname = strim(strsep(&tok, ":"));
-		if (!tok) {
-			ret = -EINVAL;
-			goto out;
-		}
-		ret = rdtgroup_parse_resource(resname, tok, closid);
-		if (ret)
-			goto out;
-	}
-
-	for_each_alloc_enabled_rdt_resource(r) {
-		ret = update_domains(r, closid);
-		if (ret)
-			goto out;
-	}
-
-out:
-	rdtgroup_kn_unlock(of->kn);
-	return ret ?: nbytes;
-}
-
-static void show_doms(struct seq_file *s, struct rdt_resource *r, int closid)
-{
-	struct rdt_domain *dom;
-	bool sep = false;
-
-	seq_printf(s, "%*s:", max_name_width, r->name);
-	list_for_each_entry(dom, &r->domains, list) {
-		if (sep)
-			seq_puts(s, ";");
-		seq_printf(s, r->format_str, dom->id, max_data_width,
-			   dom->ctrl_val[closid]);
-		sep = true;
-	}
-	seq_puts(s, "\n");
-}
-
-int rdtgroup_schemata_show(struct kernfs_open_file *of,
-			   struct seq_file *s, void *v)
-{
-	struct rdtgroup *rdtgrp;
-	struct rdt_resource *r;
-	int closid, ret = 0;
-
-	rdtgrp = rdtgroup_kn_lock_live(of->kn);
-	if (rdtgrp) {
-		closid = rdtgrp->closid;
-		for_each_alloc_enabled_rdt_resource(r) {
-			if (closid < r->num_closid)
-				show_doms(s, r, closid);
-		}
-	} else {
-		ret = -ENOENT;
-	}
-	rdtgroup_kn_unlock(of->kn);
-	return ret;
-}
-- 
1.9.1

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


#1679463 — Re: [PATCH 14/21] x86/intel_rdt/cqm: Add mon_data

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 14:50 +0200
SubjectRe: [PATCH 14/21] x86/intel_rdt/cqm: Add mon_data
Message-ID<tYMu5-1Un-3@gated-at.bofh.it>
In reply to#1675027
On Mon, 26 Jun 2017, Vikas Shivappa wrote:

> Add a mon_data directory for the root rdtgroup and all other rdtgroups.
> The directory holds all of the monitored data for all domains and events
> of all resources being monitored.

Again. This does two things at once. Move the existing code to a new file
and add the monitoring stuff. Please split it apart.

> +static bool __mon_event_count(u32 rmid, struct rmid_read *rr)
> +{
> +	u64 tval;
> +
> +	tval = __rmid_read(rmid, rr->evtid);
> +	if (tval & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL)) {
> +		rr->val = tval;
> +		return false;
> +	}
> +	switch (rr->evtid) {
> +	case QOS_L3_OCCUP_EVENT_ID:
> +		rr->val += tval;
> +		return true;
> +	default:
> +		return false;

I have no idea what that return code means. 

> +	}
> +}
> +
> +void mon_event_count(void *info)

Some explanation why this is a void pointer and how that function is called
(I assume it's via IPI) would be appreciated.

> +{
> +	struct rdtgroup *rdtgrp, *entry;
> +	struct rmid_read *rr = info;
> +	struct list_head *llist;

  *head;

> +
> +	rdtgrp = rr->rgrp;
> +
> +	if (!__mon_event_count(rdtgrp->rmid, rr))
> +		return;
> +
> +	/*
> +	 * For Ctrl groups read data from child monitor groups.
> +	 */
> +	llist = &rdtgrp->crdtgrp_list;
> +
> +	if (rdtgrp->type == RDTCTRL_GROUP) {
> +		list_for_each_entry(entry, llist, crdtgrp_list) {
> +			if (!__mon_event_count(entry->rmid, rr))
> +				return;
> +		}
> +	}
> +}

> +static int get_rdt_resourceid(struct rdt_resource *r)
> +{
> +	if (r > (rdt_resources_all + RDT_NUM_RESOURCES - 1) ||
> +	    r < rdt_resources_all ||
> +	    ((r - rdt_resources_all) % sizeof(struct rdt_resource)))
> +		return -EINVAL;

If that ever happens, then you have other problems than a wrong pointer.

> +
> +	return ((r - rdt_resources_all) / sizeof(struct rdt_resource));

Moo. Can't you simply put an index field into struct rdt_resource,
intialize it with the resource ID and use that?

Thanks,

	tglx

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


#1675028 — [PATCH 17/21] x86/intel_rdt/cqm: Add sched_in support

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 17/21] x86/intel_rdt/cqm: Add sched_in support
Message-ID<tWHoT-5Yd-53@gated-at.bofh.it>
In reply to#1675020
OS associates an RMID/CLOSid to a task by writing the per CPU
IA32_PQR_ASSOC MSR when a task is scheduled in.

The sched_in code will stay as no-op unless we are running on Intel SKU
which supports either resource control or monitoring and we also enable
them by mounting the resctrl fs.  The per cpu CLOSid/RMID values are
cached and the write is performed only when a task with a different
CLOSid/RMID is scheduled in.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/include/asm/intel_rdt_sched.h | 47 ++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 13 deletions(-)

diff --git a/arch/x86/include/asm/intel_rdt_sched.h b/arch/x86/include/asm/intel_rdt_sched.h
index 4dee77b..7c823c4 100644
--- a/arch/x86/include/asm/intel_rdt_sched.h
+++ b/arch/x86/include/asm/intel_rdt_sched.h
@@ -27,27 +27,31 @@ struct intel_pqr_state {
 
 DECLARE_PER_CPU(struct intel_pqr_state, pqr_state);
 DECLARE_PER_CPU_READ_MOSTLY(int, cpu_closid);
+DECLARE_PER_CPU_READ_MOSTLY(int, cpu_rmid);
 DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
+DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
+DECLARE_STATIC_KEY_FALSE(rdt_enable_key);
 
 /*
- * intel_rdt_sched_in() - Writes the task's CLOSid to IA32_PQR_MSR
+ * __intel_rdt_sched_in() - Writes the task's CLOSid/RMID to IA32_PQR_MSR
  *
  * Following considerations are made so that this has minimal impact
  * on scheduler hot path:
  * - This will stay as no-op unless we are running on an Intel SKU
- *   which supports resource control and we enable by mounting the
- *   resctrl file system.
- * - Caches the per cpu CLOSid values and does the MSR write only
- *   when a task with a different CLOSid is scheduled in.
+ *   which supports resource control or monitoring and we enable by
+ *   mounting the resctrl file system.
+ * - Caches the per cpu CLOSid/RMID values and does the MSR write only
+ *   when a task with a different CLOSid/RMID is scheduled in.
  *
  * Must be called with preemption disabled.
  */
-static inline void intel_rdt_sched_in(void)
+static void __intel_rdt_sched_in(void)
 {
-	if (static_branch_likely(&rdt_alloc_enable_key)) {
-		struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
-		int closid;
+	struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
+	u32 closid = 0;
+	u32 rmid = 0;
 
+	if (static_branch_likely(&rdt_alloc_enable_key)) {
 		/*
 		 * If this task has a closid assigned, use it.
 		 * Else use the closid assigned to this cpu.
@@ -55,14 +59,31 @@ static inline void intel_rdt_sched_in(void)
 		closid = current->closid;
 		if (closid == 0)
 			closid = this_cpu_read(cpu_closid);
+	}
+
+	if (static_branch_likely(&rdt_mon_enable_key)) {
+		/*
+		 * If this task has a rmid assigned, use it.
+		 * Else use the rmid assigned to this cpu.
+		 */
+		rmid = current->rmid;
+		if (rmid == 0)
+			rmid = this_cpu_read(cpu_rmid);
+	}
 
-		if (closid != state->closid) {
-			state->closid = closid;
-			wrmsr(IA32_PQR_ASSOC, state->rmid, closid);
-		}
+	if (closid != state->closid || rmid != state->rmid) {
+		state->closid = closid;
+		state->rmid = rmid;
+		wrmsr(IA32_PQR_ASSOC, rmid, closid);
 	}
 }
 
+static inline void intel_rdt_sched_in(void)
+{
+	if (static_branch_likely(&rdt_enable_key))
+		__intel_rdt_sched_in();
+}
+
 #else
 
 static inline void intel_rdt_sched_in(void) {}
-- 
1.9.1

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


#1679468 — Re: [PATCH 17/21] x86/intel_rdt/cqm: Add sched_in support

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 15:40 +0200
SubjectRe: [PATCH 17/21] x86/intel_rdt/cqm: Add sched_in support
Message-ID<tYNgu-2wM-21@gated-at.bofh.it>
In reply to#1675028
On Mon, 26 Jun 2017, Vikas Shivappa wrote:
>  DECLARE_PER_CPU(struct intel_pqr_state, pqr_state);
>  DECLARE_PER_CPU_READ_MOSTLY(int, cpu_closid);
> +DECLARE_PER_CPU_READ_MOSTLY(int, cpu_rmid);
>  DECLARE_STATIC_KEY_FALSE(rdt_alloc_enable_key);
> +DECLARE_STATIC_KEY_FALSE(rdt_mon_enable_key);
> +DECLARE_STATIC_KEY_FALSE(rdt_enable_key);

Please make this a two stage change. Add rdt_enable_key first and then the
monitoring stuff. Ideally you introduce rdt_enable_key here and in the
control code in one go.

> +static void __intel_rdt_sched_in(void)
>  {
> -	if (static_branch_likely(&rdt_alloc_enable_key)) {
> -		struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
> -		int closid;
> +	struct intel_pqr_state *state = this_cpu_ptr(&pqr_state);
> +	u32 closid = 0;
> +	u32 rmid = 0;
>  
> +	if (static_branch_likely(&rdt_alloc_enable_key)) {
>  		/*
>  		 * If this task has a closid assigned, use it.
>  		 * Else use the closid assigned to this cpu.
> @@ -55,14 +59,31 @@ static inline void intel_rdt_sched_in(void)
>  		closid = current->closid;
>  		if (closid == 0)
>  			closid = this_cpu_read(cpu_closid);
> +	}
> +
> +	if (static_branch_likely(&rdt_mon_enable_key)) {
> +		/*
> +		 * If this task has a rmid assigned, use it.
> +		 * Else use the rmid assigned to this cpu.
> +		 */
> +		rmid = current->rmid;
> +		if (rmid == 0)
> +			rmid = this_cpu_read(cpu_rmid);
> +	}
>  
> -		if (closid != state->closid) {
> -			state->closid = closid;
> -			wrmsr(IA32_PQR_ASSOC, state->rmid, closid);
> -		}
> +	if (closid != state->closid || rmid != state->rmid) {
> +		state->closid = closid;
> +		state->rmid = rmid;
> +		wrmsr(IA32_PQR_ASSOC, rmid, closid);

This can be written smarter.

	struct intel_pqr_state newstate = this_cpu_read(rdt_cpu_default);
	struct intel_pqr_state *curstate = this_cpu_ptr(&pqr_state);

	if (static_branch_likely(&rdt_alloc_enable_key)) {
		if (current->closid)
			newstate.closid = current->closid;
	}

	if (static_branch_likely(&rdt_mon_enable_key)) {
		if (current->rmid)
			newstate.rmid = current->rmid;
	}

	if (newstate != *curstate) {
		*curstate = newstate;
		wrmsr(IA32_PQR_ASSOC, newstate.rmid, newstate.closid);
	}

The unconditional read of rdt_cpu_default is the right thing to do because
the default behaviour is exactly this.

Thanks,

	tglx

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


#1675029 — [PATCH 12/21] x86/intel_rdt/cqm: Add tasks file support

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 12/21] x86/intel_rdt/cqm: Add tasks file support
Message-ID<tWHoT-5Yd-51@gated-at.bofh.it>
In reply to#1675020
The root directory, ctrl_mon and monitor groups are populated
with a read/write file named "tasks". When read, it shows all the task
IDs assigned to the resource group.

Tasks can be added to groups by writing the PID to the file. A task can
be present in one "ctrl_mon" group "and" one "monitor" group. IOW a
PID_x can be seen in a ctrl_mon group and a monitor group at the same
time. When a task is added to a ctrl_mon group, it is automatically
removed from the previous ctrl_mon group where it belonged. Similarly if
a task is moved to a monitor group it is removed from the previous
monitor group . Also since the monitor groups can only have subset of
tasks of parent ctrl_mon group, a task can be moved to a monitor group
only if its already present in the parent ctrl_mon group.

Task membership is indicated by a new field in the task_struct "u32
rmid" which holds the RMID for the task. RMID=0 is reserved for the
default root group where the tasks belong to at mount.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 18 ++++++++++++++++--
 include/linux/sched.h                    |  1 +
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
index 36078c7..8fd0757 100644
--- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
+++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
@@ -352,7 +352,20 @@ static int __rdtgroup_move_task(struct task_struct *tsk,
 		atomic_dec(&rdtgrp->waitcount);
 		kfree(callback);
 	} else {
-		tsk->closid = rdtgrp->closid;
+		/*
+		 * For ctrl_mon groups move both closid and rmid.
+		 * For monitor groups, can move the tasks only from
+		 * their parent CTRL group.
+		 */
+		if (rdtgrp->type == RDTCTRL_GROUP) {
+			tsk->closid = rdtgrp->closid;
+			tsk->rmid = rdtgrp->rmid;
+		} else if (rdtgrp->type == RDTMON_GROUP) {
+			if (rdtgrp->parent->closid == tsk->closid)
+				tsk->rmid = rdtgrp->rmid;
+			else
+				ret = -EINVAL;
+		}
 	}
 	return ret;
 }
@@ -432,7 +445,8 @@ static void show_rdt_tasks(struct rdtgroup *r, struct seq_file *s)
 
 	rcu_read_lock();
 	for_each_process_thread(p, t) {
-		if (t->closid == r->closid)
+		if ((r->type == RDTCTRL_GROUP && t->closid == r->closid) ||
+		    (r->type == RDTMON_GROUP && t->rmid == r->rmid))
 			seq_printf(s, "%d\n", t->pid);
 	}
 	rcu_read_unlock();
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9e31b3d..6643692 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -866,6 +866,7 @@ struct task_struct {
 #endif
 #ifdef CONFIG_INTEL_RDT
 	int				closid;
+	u32				rmid;
 #endif
 #ifdef CONFIG_FUTEX
 	struct robust_list_head __user	*robust_list;
-- 
1.9.1

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


#1679447 — Re: [PATCH 12/21] x86/intel_rdt/cqm: Add tasks file support

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 13:10 +0200
SubjectRe: [PATCH 12/21] x86/intel_rdt/cqm: Add tasks file support
Message-ID<tYKVk-129-9@gated-at.bofh.it>
In reply to#1675029
On Mon, 26 Jun 2017, Vikas Shivappa wrote:
> @@ -866,6 +866,7 @@ struct task_struct {
>  #endif
>  #ifdef CONFIG_INTEL_RDT
>  	int				closid;
> +	u32				rmid;

Can you please make a preparatory change which makes closid an u32 as well?
We should have done that in the first place, but in hindsight we are always
smarter...

Thanks,

	tglx

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


#1675030 — [PATCH 08/21] x86/intel_rdt/cqm: Add RMID(Resource monitoring ID) management

FromVikas Shivappa <vikas.shivappa@linux.intel.com>
Date2017-06-26 21:00 +0200
Subject[PATCH 08/21] x86/intel_rdt/cqm: Add RMID(Resource monitoring ID) management
Message-ID<tWHoT-5Yd-55@gated-at.bofh.it>
In reply to#1675020
Hardware uses RMID(Resource monitoring ID) to keep track of each of the
RDT events associated with tasks. The number of RMIDs is dependent on
the SKU and is enumerated via CPUID. We add support to manage the RMIDs
which include managing the RMID allocation and reading LLC occupancy
for an RMID.

RMID allocation is managed by keeping a free list which is initialized
to all available RMIDs except for RMID 0 which is always reserved for
root group. RMIDs goto a limbo list once they are
freed since the RMIDs are still tagged to cache lines of the tasks which
were using them - thereby still having some occupancy. They continue to
be in limbo list until the occupancy < threshold_occupancy. The
threshold_occupancy is a user configurable value.
OS uses IA32_QM_CTR MSR to read the occupancy associated with an RMID
after programming the IA32_EVENTSEL MSR with the RMID.

Signed-off-by: Vikas Shivappa <vikas.shivappa@linux.intel.com>
---
 arch/x86/kernel/cpu/intel_rdt.h         |   2 +
 arch/x86/kernel/cpu/intel_rdt_monitor.c | 121 ++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+)

diff --git a/arch/x86/kernel/cpu/intel_rdt.h b/arch/x86/kernel/cpu/intel_rdt.h
index 285f106..cf25b6c 100644
--- a/arch/x86/kernel/cpu/intel_rdt.h
+++ b/arch/x86/kernel/cpu/intel_rdt.h
@@ -20,6 +20,8 @@
 #define QOS_L3_MBM_TOTAL_EVENT_ID	0x02
 #define QOS_L3_MBM_LOCAL_EVENT_ID	0x03
 
+#define RMID_VAL_ERROR		(1ULL << 63)
+#define RMID_VAL_UNAVAIL	(1ULL << 62)
 /**
  * struct mon_evt - Entry in the event list of a resource
  * @evtid:		event id
diff --git a/arch/x86/kernel/cpu/intel_rdt_monitor.c b/arch/x86/kernel/cpu/intel_rdt_monitor.c
index a418854..4f4221a 100644
--- a/arch/x86/kernel/cpu/intel_rdt_monitor.c
+++ b/arch/x86/kernel/cpu/intel_rdt_monitor.c
@@ -28,6 +28,9 @@
 #include <asm/cpu_device_id.h>
 #include "intel_rdt.h"
 
+#define MSR_IA32_QM_CTR		0x0c8e
+#define MSR_IA32_QM_EVTSEL		0x0c8d
+
 enum rmid_recycle_state {
 	RMID_CHECK = 0,
 	RMID_DIRTY,
@@ -82,6 +85,124 @@ static inline struct rmid_entry *__rmid_entry(u32 rmid)
 	return entry;
 }
 
+static u64 __rmid_read(u32 rmid, u32 eventid)
+{
+	u64 val;
+
+	wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
+	rdmsrl(MSR_IA32_QM_CTR, val);
+
+	/*
+	 * Aside from the ERROR and UNAVAIL bits, the return value is the
+	 * count for this @eventid tagged with @rmid.
+	 */
+	return val;
+}
+
+/*
+ * Test whether an RMID is dirty(occupancy > threshold_occupancy)
+ */
+static void intel_cqm_stable(void *arg)
+{
+	struct rmid_entry *entry;
+	u64 val;
+
+	/*
+	 * Since we are in the IPI already lets mark all the RMIDs
+	 * that are dirty
+	 */
+	list_for_each_entry(entry, &rmid_limbo_lru, list) {
+		val = __rmid_read(entry->rmid, QOS_L3_OCCUP_EVENT_ID);
+		if (val > intel_cqm_threshold)
+			entry->state = RMID_DIRTY;
+	}
+}
+
+/*
+ * Scan the limbo list and move all entries that are below the
+ * intel_cqm_threshold to the free list.
+ * Return "true" if the limbo list is empty, "false" if there are
+ * still some RMIDs there.
+ */
+static bool try_freeing_limbo_rmid(void)
+{
+	struct rmid_entry *entry, *tmp;
+	struct rdt_resource *r;
+	cpumask_var_t cpu_mask;
+	struct rdt_domain *d;
+	bool ret = true;
+
+	if (list_empty(&rmid_limbo_lru))
+		return ret;
+
+	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
+		return false;
+
+	r = &rdt_resources_all[RDT_RESOURCE_L3];
+
+	list_for_each_entry(d, &r->domains, list)
+		cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
+
+	/*
+	 * Test whether an RMID is free for each package.
+	 */
+	on_each_cpu_mask(cpu_mask, intel_cqm_stable, NULL, true);
+
+	list_for_each_entry_safe(entry, tmp, &rmid_limbo_lru, list) {
+		/*
+		 * Ignore the RMIDs that are marked dirty and reset the
+		 * state to check for being dirty again later.
+		 */
+		if (entry->state == RMID_DIRTY) {
+			entry->state = RMID_CHECK;
+			ret = false;
+			continue;
+		}
+		list_del(&entry->list);
+		list_add_tail(&entry->list, &rmid_free_lru);
+	}
+
+	free_cpumask_var(cpu_mask);
+	return ret;
+}
+
+int alloc_rmid(void)
+{
+	struct rmid_entry *entry;
+	bool ret;
+
+	lockdep_assert_held(&rdtgroup_mutex);
+
+	if (list_empty(&rmid_free_lru)) {
+		ret = try_freeing_limbo_rmid();
+		if (list_empty(&rmid_free_lru))
+			return ret ? -ENOSPC : -EBUSY;
+	}
+
+	entry = list_first_entry(&rmid_free_lru,
+				 struct rmid_entry, list);
+	list_del(&entry->list);
+
+	return entry->rmid;
+}
+
+void free_rmid(u32 rmid)
+{
+	struct rmid_entry *entry;
+
+	lockdep_assert_held(&rdtgroup_mutex);
+
+	WARN_ON(!rmid);
+	entry = __rmid_entry(rmid);
+
+	entry->state = RMID_CHECK;
+
+	if (rdt_mon_features & (1 << QOS_L3_OCCUP_EVENT_ID))
+		list_add_tail(&entry->list, &rmid_limbo_lru);
+	else
+		list_add_tail(&entry->list, &rmid_free_lru);
+}
+
 static int dom_data_init(struct rdt_resource *r)
 {
 	struct rmid_entry *entry = NULL;
-- 
1.9.1

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


#1679442 — Re: [PATCH 08/21] x86/intel_rdt/cqm: Add RMID(Resource monitoring ID) management

FromThomas Gleixner <tglx@linutronix.de>
Date2017-07-02 12:10 +0200
SubjectRe: [PATCH 08/21] x86/intel_rdt/cqm: Add RMID(Resource monitoring ID) management
Message-ID<tYJZf-65-1@gated-at.bofh.it>
In reply to#1675030
On Mon, 26 Jun 2017, Vikas Shivappa wrote:
> +static u64 __rmid_read(u32 rmid, u32 eventid)
> +{
> +	u64 val;
> +
> +	wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
> +	rdmsrl(MSR_IA32_QM_CTR, val);

The calling convention of this function needs to be documented. It's
obvious that it needs to be serialized ....

> +
> +	/*
> +	 * Aside from the ERROR and UNAVAIL bits, the return value is the
> +	 * count for this @eventid tagged with @rmid.
> +	 */
> +	return val;
> +}
> +
> +/*
> + * Test whether an RMID is dirty(occupancy > threshold_occupancy)
> + */
> +static void intel_cqm_stable(void *arg)
> +{
> +	struct rmid_entry *entry;
> +	u64 val;
> +
> +	/*
> +	 * Since we are in the IPI already lets mark all the RMIDs
> +	 * that are dirty

This comment is crap. It suggests: Let's do it while we are here anyway.

But that's not true. The IPI is issued solely to figure out which RMIDs are
dirty.

> +	 */
> +	list_for_each_entry(entry, &rmid_limbo_lru, list) {

Since this is executed on multiple CPUs, that needs an explanation why that
list is safe to iterate w/o explicit protection here.

> +		val = __rmid_read(entry->rmid, QOS_L3_OCCUP_EVENT_ID);
> +		if (val > intel_cqm_threshold)
> +			entry->state = RMID_DIRTY;
> +	}
> +}
> +
> +/*
> + * Scan the limbo list and move all entries that are below the
> + * intel_cqm_threshold to the free list.
> + * Return "true" if the limbo list is empty, "false" if there are
> + * still some RMIDs there.
> + */
> +static bool try_freeing_limbo_rmid(void)
> +{
> +	struct rmid_entry *entry, *tmp;
> +	struct rdt_resource *r;
> +	cpumask_var_t cpu_mask;
> +	struct rdt_domain *d;
> +	bool ret = true;
> +
> +	if (list_empty(&rmid_limbo_lru))
> +		return ret;
> +
> +	if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
> +		return false;
> +
> +	r = &rdt_resources_all[RDT_RESOURCE_L3];
> +
> +	list_for_each_entry(d, &r->domains, list)
> +		cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
> +
> +	/*
> +	 * Test whether an RMID is free for each package.

That wants a bit of explanation at some place why RMIDs have global
scope. That's a pure implementation decision because from a hardware POV
RMIDs have package scope. We could use the same RMID on different packages
for different purposes.

> +	 */
> +	on_each_cpu_mask(cpu_mask, intel_cqm_stable, NULL, true);
> +
> +	list_for_each_entry_safe(entry, tmp, &rmid_limbo_lru, list) {
> +		/*
> +		 * Ignore the RMIDs that are marked dirty and reset the
> +		 * state to check for being dirty again later.

Ignore? -EMAKESNOSENSE

> +		 */
> +		if (entry->state == RMID_DIRTY) {
> +			entry->state = RMID_CHECK;
> +			ret = false;
> +			continue;
> +		}
> +		list_del(&entry->list);
> +		list_add_tail(&entry->list, &rmid_free_lru);
> +	}
> +
> +	free_cpumask_var(cpu_mask);

...

> +void free_rmid(u32 rmid)
> +{
> +	struct rmid_entry *entry;
> +
> +	lockdep_assert_held(&rdtgroup_mutex);
> +
> +	WARN_ON(!rmid);
> +	entry = __rmid_entry(rmid);
> +
> +	entry->state = RMID_CHECK;
> +
> +	if (rdt_mon_features & (1 << QOS_L3_OCCUP_EVENT_ID))
> +		list_add_tail(&entry->list, &rmid_limbo_lru);
> +	else
> +		list_add_tail(&entry->list, &rmid_free_lru);

Thinking a bit more about that limbo mechanics.

In case that a RMID was never used on a particular package, the state check
forces an IPI on all packages unconditionally. That's suboptimal at least.

We know on which package a given RMID was used, so we could restrict the
checks to exactly these packages, but I'm not sure it's worth the
trouble. We might at least document that and explain why this is
implemented in that way.

Thanks,

	tglx

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


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web