* [RFC PATCH 0/3] x86: Add Cache QoS Monitoring (CQM) support
@ 2013-12-26 21:34 Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 1/3] x86: Add support for Cache QoS Monitoring (CQM) detection Peter P Waskiewicz Jr
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Peter P Waskiewicz Jr @ 2013-12-26 21:34 UTC (permalink / raw)
To: cgroups, x86, tj; +Cc: linux-kernel, peter.p.waskiewicz.jr
RFC: This is a work-in-progress patchset. Looking for general
feedback on the approach and design of this changeset, especially
since this is adding a new cgroup subsystem to present the data
from this CPU feature.
This patchset adds support for the new Cache QoS Monitoring (CQM)
feature found in future Intel Xeon processors.
CQM allows a process, or set of processes, to be tracked by the CPU
to determine the cache usage of that task group. Using this data
from the CPU, software can be written to extract this data and
report cache usage and occupancy for a particular process, or
group of processes.
More information about Cache QoS Monitoring can be found in the
Intel (R) x86 Architecture Software Developer Manual, section 17.14.
This series is also laying the framework for additional Platform
QoS features in future Intel Xeon processors.
The CPU features themselves are relatively straight-forward, but
the presentation of the data is less straight-forward. Since this
tracks cache usage and occupancy per process (by swapping Resource
Monitor IDs, or RMIDs, when processes are rescheduled), perf would
not be a good fit for this data, which does not report on a
per-process level. Therefore, a new cgroup subsystem, cacheqos, has
been added. This operates very similarly to the cpu and cpuacct
cgroup subsystems, where tasks can be grouped into sub-leaves of the
root-level cgroup.
Peter P Waskiewicz Jr (3):
x86: Add support for Cache QoS Monitoring (CQM) detection
x86: Add Cache QoS Monitoring support to x86 perf uncore
cgroup: Add new cacheqos cgroup subsys to support Cache QoS Monitoring
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC PATCH 1/3] x86: Add support for Cache QoS Monitoring (CQM) detection
2013-12-26 21:34 [RFC PATCH 0/3] x86: Add Cache QoS Monitoring (CQM) support Peter P Waskiewicz Jr
@ 2013-12-26 21:34 ` Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 2/3] x86: Add Cache QoS Monitoring support to x86 perf uncore Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 3/3] cgroup: Add new cacheqos cgroup subsys to support Cache QoS Monitoring Peter P Waskiewicz Jr
2 siblings, 0 replies; 4+ messages in thread
From: Peter P Waskiewicz Jr @ 2013-12-26 21:34 UTC (permalink / raw)
To: cgroups, x86, tj; +Cc: linux-kernel, peter.p.waskiewicz.jr
This patch adds support for the new Cache QoS Monitoring (CQM)
feature found in future Intel Xeon processors. It includes the
new values to track CQM resources to the cpuinfo_x86 structure,
plus the CPUID detection routines for CQM.
CQM allows a process, or set of processes, to be tracked by the CPU
to determine the cache usage of that task group. Using this data
from the CPU, software can be written to extract this data and
report cache usage and occupancy for a particular process, or
group of processes.
More information about Cache QoS Monitoring can be found in the
Intel (R) x86 Architecture Software Developer Manual, section 17.14.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
arch/x86/configs/x86_64_defconfig | 1 +
arch/x86/include/asm/cpufeature.h | 9 ++++++++-
arch/x86/include/asm/processor.h | 3 +++
arch/x86/kernel/cpu/common.c | 39 +++++++++++++++++++++++++++++++++++++++
4 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index c1119d4..8e98ed4 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -14,6 +14,7 @@ CONFIG_LOG_BUF_SHIFT=18
CONFIG_CGROUPS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CPUSETS=y
+CONFIG_CGROUP_CACHEQOS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_SCHED=y
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 89270b4..5dd59a2 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -8,7 +8,7 @@
#include <asm/required-features.h>
#endif
-#define NCAPINTS 10 /* N 32-bit words worth of info */
+#define NCAPINTS 12 /* N 32-bit words worth of info */
#define NBUGINTS 1 /* N 32-bit bug flags */
/*
@@ -216,10 +216,17 @@
#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */
#define X86_FEATURE_INVPCID (9*32+10) /* Invalidate Processor Context ID */
#define X86_FEATURE_RTM (9*32+11) /* Restricted Transactional Memory */
+#define X86_FEATURE_CQM (9*32+12) /* Cache QoS Monitoring */
#define X86_FEATURE_RDSEED (9*32+18) /* The RDSEED instruction */
#define X86_FEATURE_ADX (9*32+19) /* The ADCX and ADOX instructions */
#define X86_FEATURE_SMAP (9*32+20) /* Supervisor Mode Access Prevention */
+/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (edx), word 10 */
+#define X86_FEATURE_CQM_LLC (10*32+ 1) /* LLC QoS if 1 */
+
+/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (edx), word 11 */
+#define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 0) /* LLC occupancy monitoring if 1 */
+
/*
* BUG word(s)
*/
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 7b034a4..3892281 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -110,6 +110,9 @@ struct cpuinfo_x86 {
/* in KB - valid for CPUS which support this call: */
int x86_cache_size;
int x86_cache_alignment; /* In bytes */
+ /* Cache QoS architectural values: */
+ int x86_cache_max_rmid; /* max index */
+ int x86_cache_occ_scale; /* scale to bytes */
int x86_power;
unsigned long loops_per_jiffy;
/* cpuid returned max cores value: */
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 6abc172..f18bc43 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -626,6 +626,30 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[9] = ebx;
}
+ /* Additional Intel-defined flags: level 0x0000000F */
+ if (c->cpuid_level >= 0x0000000F) {
+ u32 eax, ebx, ecx, edx;
+
+ /* QoS sub-leaf, EAX=0Fh, ECX=0 */
+ cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx);
+ c->x86_capability[10] = edx;
+ if (cpu_has(c, X86_FEATURE_CQM_LLC)) {
+ /* will be overridden if occupancy monitoring exists */
+ c->x86_cache_max_rmid = ebx;
+
+ /* QoS sub-leaf, EAX=0Fh, ECX=1 */
+ cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx);
+ c->x86_capability[11] = edx;
+ if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC)) {
+ c->x86_cache_max_rmid = ecx;
+ c->x86_cache_occ_scale = ebx;
+ }
+ } else {
+ c->x86_cache_max_rmid = -1;
+ c->x86_cache_occ_scale = -1;
+ }
+ }
+
/* AMD-defined flags: level 0x80000001 */
xlvl = cpuid_eax(0x80000000);
c->extended_cpuid_level = xlvl;
@@ -814,6 +838,20 @@ static void generic_identify(struct cpuinfo_x86 *c)
detect_nopl(c);
}
+static void x86_init_cache_qos(struct cpuinfo_x86 *c)
+{
+ /*
+ * The heavy lifting of max_rmid and cache_occ_scale are handled
+ * in get_cpu_cap(). Here we just set the max_rmid for the boot_cpu
+ * in case CQM bits really aren't there in this CPU.
+ */
+ if (c != &boot_cpu_data) {
+ boot_cpu_data.x86_cache_max_rmid =
+ min(boot_cpu_data.x86_cache_max_rmid,
+ c->x86_cache_max_rmid);
+ }
+}
+
/*
* This does the hard work of actually picking apart the CPU stuff...
*/
@@ -903,6 +941,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
init_hypervisor(c);
x86_init_rdrand(c);
+ x86_init_cache_qos(c);
/*
* Clear/Set all flags overriden by options, need do it
--
1.8.3.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC PATCH 2/3] x86: Add Cache QoS Monitoring support to x86 perf uncore
2013-12-26 21:34 [RFC PATCH 0/3] x86: Add Cache QoS Monitoring (CQM) support Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 1/3] x86: Add support for Cache QoS Monitoring (CQM) detection Peter P Waskiewicz Jr
@ 2013-12-26 21:34 ` Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 3/3] cgroup: Add new cacheqos cgroup subsys to support Cache QoS Monitoring Peter P Waskiewicz Jr
2 siblings, 0 replies; 4+ messages in thread
From: Peter P Waskiewicz Jr @ 2013-12-26 21:34 UTC (permalink / raw)
To: cgroups, x86, tj; +Cc: linux-kernel, peter.p.waskiewicz.jr
This patch adds the MSRs and masks for CQM to the x86 uncore.
The actual scheduling functions using the MSRs will be included
in the next patch when the new cgroup subsystem is added, as there
are dependencies on structs from the cgroup.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index a80ab71..f788145 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -412,6 +412,19 @@
#define NHMEX_W_PMON_GLOBAL_FIXED_EN (1ULL << 31)
+#ifdef CONFIG_CGROUP_CACHEQOS
+/* Intel Cache QoS Monitoring uncore support */
+#define IA32_QM_EVTSEL 0xc8d
+#define IA32_QM_CTR 0xc8e
+#define IA32_PQR_ASSOC 0xc8f
+
+#define IA32_QM_EVTSEL_EVTID_READ_OCC 0x01
+#define IA32_QM_CTR_ERR (0x03llu << 62)
+#define IA32_RMID_PQR_MASK 0x3ff
+#define IA32_QM_EVTSEL_RMID_POSITION 32
+
+#endif /* CONFIG_CGROUP_CACHEQOS */
+
struct intel_uncore_ops;
struct intel_uncore_pmu;
struct intel_uncore_box;
--
1.8.3.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC PATCH 3/3] cgroup: Add new cacheqos cgroup subsys to support Cache QoS Monitoring
2013-12-26 21:34 [RFC PATCH 0/3] x86: Add Cache QoS Monitoring (CQM) support Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 1/3] x86: Add support for Cache QoS Monitoring (CQM) detection Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 2/3] x86: Add Cache QoS Monitoring support to x86 perf uncore Peter P Waskiewicz Jr
@ 2013-12-26 21:34 ` Peter P Waskiewicz Jr
2 siblings, 0 replies; 4+ messages in thread
From: Peter P Waskiewicz Jr @ 2013-12-26 21:34 UTC (permalink / raw)
To: cgroups, x86, tj; +Cc: linux-kernel, peter.p.waskiewicz.jr
This patch adds a new cgroup subsystem, named cacheqos. This cgroup
controller is intended to manage task groups to track cache occupancy
and usage of a CPU.
This patch also adds the scheduler functions to the Intel uncore events
to implement Cache QoS Monitoring. This needs to be added along with
the cgroup subsystem since events from the cgroup trigger when a task
needs to be tracked on the underlying CPU.
The patch also adds the Kconfig option for enabling/disabling the
CGROUP_CACHEQOS subsystem.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 52 ++++
include/linux/cgroup_subsys.h | 4 +
include/linux/perf_event.h | 15 +
init/Kconfig | 6 +
kernel/sched/core.c | 432 ++++++++++++++++++++++++++
kernel/sched/sched.h | 55 ++++
6 files changed, 564 insertions(+)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 29c2487..6f06d68 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -1633,6 +1633,58 @@ static struct intel_uncore_type *snb_msr_uncores[] = {
};
/* end of Sandy Bridge uncore support */
+#ifdef CONFIG_CGROUP_CACHEQOS
+
+/* needed for the cacheqos cgroup structs */
+#include "../../../kernel/sched/sched.h"
+
+void cacheqos_map_schedule_out(void)
+{
+ /*
+ * cacheqos_map_schedule_in() will set the MSR correctly, but
+ * clearing the MSR here will prevent occupancy counts against this
+ * task during the context switch. In other words, this gives a
+ * "better" representation of what's happening in the cache.
+ */
+ wrmsrl(IA32_PQR_ASSOC, 0);
+}
+
+void cacheqos_map_schedule_in(struct cacheqos *cq)
+{
+ u64 map;
+
+ map = cq->rmid & IA32_RMID_PQR_MASK;
+ wrmsrl(IA32_PQR_ASSOC, map);
+}
+
+void cacheqos_read(void *arg)
+{
+ struct cacheqos *cq = arg;
+ u64 config;
+ u64 result = 0;
+ int cpu, node;
+
+ cpu = smp_processor_id();
+ node = cpu_to_node(cpu);
+
+ config = cq->rmid;
+ config = ((config & IA32_RMID_PQR_MASK) <<
+ IA32_QM_EVTSEL_RMID_POSITION) |
+ IA32_QM_EVTSEL_EVTID_READ_OCC;
+ wrmsrl(IA32_QM_EVTSEL, config);
+ rdmsrl(IA32_QM_CTR, result);
+
+ /* place results in sys_wide_info area for recovery */
+ if (result & IA32_QM_CTR_ERR)
+ result = -1;
+ else
+ result &= ~IA32_QM_CTR_ERR;
+
+ cq->subsys_wide_info->node_results[node] =
+ result * cq->subsys_wide_info->cache_occ_scale;
+}
+#endif /* CONFIG_CGROUP_CACHEQOS */
+
/* Nehalem uncore support */
static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
{
diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h
index b613ffd..14b97e4 100644
--- a/include/linux/cgroup_subsys.h
+++ b/include/linux/cgroup_subsys.h
@@ -50,6 +50,10 @@ SUBSYS(net_prio)
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_HUGETLB)
SUBSYS(hugetlb)
#endif
+
+#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_CACHEQOS)
+SUBSYS(cacheqos)
+#endif
/*
* DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS.
*/
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2e069d1..18a9c43 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -670,12 +670,22 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr)
}
extern struct static_key_deferred perf_sched_events;
+#ifdef CONFIG_CGROUP_CACHEQOS
+extern int cacheqos_cgroup_is_active;
+inline void cacheqos_sched_out(void);
+inline void cacheqos_sched_in(struct task_struct *task);
+#endif /* CONFIG_CGROUP_CACHEQOS */
static inline void perf_event_task_sched_in(struct task_struct *prev,
struct task_struct *task)
{
if (static_key_false(&perf_sched_events.key))
__perf_event_task_sched_in(prev, task);
+
+#ifdef CONFIG_CGROUP_CACHEQOS
+ if (cacheqos_cgroup_is_active)
+ cacheqos_sched_in(task);
+#endif /* CONFIG_CGROUP_CACHEQOS */
}
static inline void perf_event_task_sched_out(struct task_struct *prev,
@@ -685,6 +695,11 @@ static inline void perf_event_task_sched_out(struct task_struct *prev,
if (static_key_false(&perf_sched_events.key))
__perf_event_task_sched_out(prev, next);
+
+#ifdef CONFIG_CGROUP_CACHEQOS
+ if (cacheqos_cgroup_is_active)
+ cacheqos_sched_out();
+#endif /* CONFIG_CGROUP_CACHEQOS */
}
extern void perf_event_mmap(struct vm_area_struct *vma);
diff --git a/init/Kconfig b/init/Kconfig
index 4e5d96a..5dc35f9 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -905,6 +905,12 @@ config PROC_PID_CPUSET
depends on CPUSETS
default y
+config CGROUP_CACHEQOS
+ bool "Simple Cache QoS Monitoring cgroup subsystem"
+ help
+ Provides a simple Resource Controller for monitoring the
+ total cache occupancy by the tasks in a cgroup.
+
config CGROUP_CPUACCT
bool "Simple CPU accounting cgroup subsystem"
help
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a88f4a4..da49c42 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7354,6 +7354,438 @@ struct cgroup_subsys cpu_cgroup_subsys = {
#endif /* CONFIG_CGROUP_SCHED */
+#ifdef CONFIG_CGROUP_CACHEQOS
+
+/* Cache QoS code for task cgroups. */
+static struct cftype cacheqos_files[];
+struct cacheqos_subsys_wide_info cacheqos_wide_info = {{0},};
+struct cacheqos root_cacheqos_group;
+int cacheqos_cgroup_is_active = 0;
+
+/*
+ * This mutex guards the subsys_wide_info unused and inuse lists as well as
+ * the node results array.
+ */
+static DEFINE_MUTEX(cacheqos_mutex);
+
+extern void cacheqos_map_schedule_out(void);
+extern void cacheqos_map_schedule_in(struct cacheqos *);
+extern void cacheqos_read(void *);
+
+/* return cacheqos feature flags and assign constants */
+static __init int cacheqos_late_init(void)
+{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+ struct rmid_list_element *elem;
+ int i;
+
+ mutex_lock(&cacheqos_mutex);
+
+ cacheqos_wide_info.cache_max_rmid = c->x86_cache_max_rmid;
+ cacheqos_wide_info.cache_occ_scale = c->x86_cache_occ_scale;
+ cacheqos_wide_info.cache_size = c->x86_cache_size;
+
+ /* Populate the unused rmid list with all rmids. */
+ INIT_LIST_HEAD(&cacheqos_wide_info.rmid_unused_fifo);
+ INIT_LIST_HEAD(&cacheqos_wide_info.rmid_inuse_list);
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ elem->rmid = 0;
+ list_add_tail(&elem->list, &cacheqos_wide_info.rmid_inuse_list);
+ for (i = 1; i < cacheqos_wide_info.cache_max_rmid; i++) {
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ elem->rmid = i;
+ INIT_LIST_HEAD(&elem->list);
+ list_add_tail(&elem->list,
+ &cacheqos_wide_info.rmid_unused_fifo);
+ }
+
+ mutex_unlock(&cacheqos_mutex);
+ return 0;
+}
+late_initcall(cacheqos_late_init);
+
+inline void cacheqos_sched_out(void)
+{
+ /*
+ * Assumption is that this thread is running on the logical processor
+ * from which the task is being scheduled out.
+ *
+ * As the task is scheduled out mapping goes back to default map.
+ */
+ cacheqos_map_schedule_out();
+}
+
+inline void cacheqos_sched_in(struct task_struct *task)
+{
+ struct cacheqos *cq;
+ /*
+ * Assumption is that this thread is running on the logical processor
+ * of which this task is being scheduled onto.
+ *
+ * As the task is scheduled in, the cgroup's rmid is loaded
+ */
+ cq = task_cacheqos(task);
+ cacheqos_map_schedule_in(cq);
+}
+
+static void cacheqos_adjust_children_rmid(struct cacheqos *cq)
+{
+ struct cgroup_subsys_state *css, *pos;
+ struct cacheqos *p_cq, *pos_cq;
+
+ css = &cq->css;
+ rcu_read_lock();
+
+ css_for_each_descendant_pre(pos, css) {
+ pos_cq = css_cacheqos(pos);
+ if (pos_cq->monitor_cache == 0) {
+ /* monitoring is disabled, so use the parent's RMID */
+ p_cq = parent_cacheqos(pos_cq);
+ spin_lock_irq(&pos_cq->lock);
+ pos_cq->rmid = p_cq->rmid;
+ spin_unlock_irq(&pos_cq->lock);
+ }
+ }
+ rcu_read_unlock();
+}
+
+static int cacheqos_move_rmid_to_unused_list(struct cacheqos *cq)
+{
+ struct rmid_list_element *elem;
+
+ /*
+ * Assumes only called when cq->rmid is valid (ie, it is on the
+ * inuse list) and cacheqos_mutex is held.
+ */
+ lockdep_assert_held(&cacheqos_mutex);
+ list_for_each_entry(elem, &cq->subsys_wide_info->rmid_inuse_list,
+ list) {
+ if (cq->rmid == elem->rmid) {
+ /* Move rmid from inuse to unused list */
+ list_del_init(&elem->list);
+ list_add_tail(&elem->list,
+ &cq->subsys_wide_info->rmid_unused_fifo);
+ goto quick_exit;
+ }
+ }
+ return -ELIBBAD;
+
+quick_exit:
+ return 0;
+}
+
+static int cacheqos_deallocate_rmid(struct cacheqos *cq)
+{
+ struct cacheqos *cq_parent = parent_cacheqos(cq);
+ int err;
+
+ mutex_lock(&cacheqos_mutex);
+ err = cacheqos_move_rmid_to_unused_list(cq);
+ if (err)
+ return err;
+ /* assign parent's rmid to cgroup */
+ cq->monitor_cache = 0;
+ cq->rmid = cq_parent->rmid;
+
+ /* Check for children using this cgroup's rmid, iterate */
+ cacheqos_adjust_children_rmid(cq);
+
+ mutex_unlock(&cacheqos_mutex);
+ return 0;
+}
+
+static int cacheqos_allocate_rmid(struct cacheqos *cq)
+{
+ struct rmid_list_element *elem;
+ struct list_head *item;
+
+ mutex_lock(&cacheqos_mutex);
+
+ if (list_empty(&cq->subsys_wide_info->rmid_unused_fifo)) {
+ mutex_unlock(&cacheqos_mutex);
+ return -EAGAIN;
+ }
+
+ /* Move rmid from unused to inuse list */
+ item = cq->subsys_wide_info->rmid_unused_fifo.next;
+ list_del_init(item);
+ list_add_tail(item, &cq->subsys_wide_info->rmid_inuse_list);
+
+ /* assign rmid to cgroup */
+ elem = list_entry(item, struct rmid_list_element, list);
+ cq->rmid = elem->rmid;
+ cq->monitor_cache = 1;
+
+ /* Check for children using this cgroup's rmid, iterate */
+ cacheqos_adjust_children_rmid(cq);
+
+ mutex_unlock(&cacheqos_mutex);
+
+ return 0;
+}
+
+/* create a new cacheqos cgroup */
+static struct cgroup_subsys_state *
+cacheqos_css_alloc(struct cgroup_subsys_state *parent_css)
+{
+ struct cacheqos *parent = css_cacheqos(parent_css);
+ struct cacheqos *cq;
+
+ if (!parent) {
+ /* enable monitoring for root w/ rmid = 0 */
+ root_cacheqos_group.monitor_cache = 1;
+ root_cacheqos_group.rmid = 0;
+ root_cacheqos_group.subsys_wide_info = &cacheqos_wide_info;
+ return &root_cacheqos_group.css;
+ }
+
+ cq = kzalloc(sizeof(struct cacheqos), GFP_KERNEL);
+ if (!cq)
+ goto out;
+
+ cq->subsys_wide_info = NULL;
+
+ cq->cgrp = parent_css->cgroup;
+ cq->monitor_cache = 0; /* disabled i.e., use parent's RMID */
+ cq->rmid = parent->rmid; /* Start by using parent's RMID*/
+ cq->subsys_wide_info = &cacheqos_wide_info;
+ return &cq->css;
+
+out:
+ return ERR_PTR(-ENOMEM);
+}
+
+/* destroy an existing cacheqos task group */
+static void cacheqos_css_free(struct cgroup_subsys_state *css)
+{
+ struct cacheqos *cq = css_cacheqos(css);
+
+ if (cq->monitor_cache) {
+ mutex_lock(&cacheqos_mutex);
+ cacheqos_move_rmid_to_unused_list(cq);
+ mutex_unlock(&cacheqos_mutex);
+ }
+ kfree(cq);
+}
+
+/* return task group's monitoring state */
+static u64 cacheqos_monitor_read(struct cgroup_subsys_state *css,
+ struct cftype *cft)
+{
+ struct cacheqos *cq = css_cacheqos(css);
+
+ return cq->monitor_cache;
+}
+
+/* set the task group's monitoring state */
+static int cacheqos_monitor_write(struct cgroup_subsys_state *css,
+ struct cftype *cftype, u64 enable)
+{
+ struct cacheqos *cq = css_cacheqos(css);
+ int err = 0;
+
+ if (enable != 0 && enable != 1) {
+ err = -EINVAL;
+ goto monitor_out;
+ }
+
+ if (enable == cq->monitor_cache)
+ goto monitor_out;
+
+ if (cq->monitor_cache)
+ err = cacheqos_deallocate_rmid(cq);
+ else
+ err = cacheqos_allocate_rmid(cq);
+
+monitor_out:
+ return err;
+}
+
+static int cacheqos_get_occupancy_data(struct cacheqos *cq)
+{
+ unsigned int cpu;
+ unsigned int node;
+ const struct cpumask *node_cpus;
+ int err = 0;
+
+ /* Assumes cacheqos_mutex is held */
+ lockdep_assert_held(&cacheqos_mutex);
+ for_each_node_with_cpus(node) {
+ node_cpus = cpumask_of_node(node);
+ cpu = any_online_cpu(*node_cpus);
+ err = smp_call_function_single(cpu, cacheqos_read, cq, 1);
+
+ if (err) {
+ break;
+ } else if (cq->subsys_wide_info->node_results[node] == -1) {
+ err = -EPROTO;
+ break;
+ }
+ }
+ return err;
+}
+
+/* return total system LLC occupancy in bytes of a task group */
+static int cacheqos_occupancy_read(struct cgroup_subsys_state *css,
+ struct cftype *cft, struct seq_file *m)
+{
+ struct cacheqos *cq = css_cacheqos(css);
+ u64 total_occupancy = 0;
+ int err, node;
+
+ mutex_lock(&cacheqos_mutex);
+ err = cacheqos_get_occupancy_data(cq);
+ if (err) {
+ mutex_unlock(&cacheqos_mutex);
+ return err;
+ }
+
+ for_each_node_with_cpus(node)
+ total_occupancy += cq->subsys_wide_info->node_results[node];
+
+ mutex_unlock(&cacheqos_mutex);
+
+ seq_printf(m, "%llu\n", total_occupancy);
+ return 0;
+}
+
+/* return display each LLC's occupancy in bytes of a task group */
+static int
+cacheqos_occupancy_persocket_seq_read(struct cgroup_subsys_state *css,
+ struct cftype *cft, struct seq_file *m)
+{
+ struct cacheqos *cq = css_cacheqos(css);
+ int err, node;
+
+ mutex_lock(&cacheqos_mutex);
+ err = cacheqos_get_occupancy_data(cq);
+ if (err) {
+ mutex_unlock(&cacheqos_mutex);
+ return err;
+ }
+
+ for_each_node_with_cpus(node) {
+ seq_printf(m, "%llu\n",
+ cq->subsys_wide_info->node_results[node]);
+ }
+
+ mutex_unlock(&cacheqos_mutex);
+
+ return 0;
+}
+
+/* return total system LLC occupancy as a %of system LLC for the task group */
+static int cacheqos_occupancy_percent_read(struct cgroup_subsys_state *css,
+ struct cftype *cft,
+ struct seq_file *m)
+{
+ struct cacheqos *cq = css_cacheqos(css);
+ u64 total_occupancy = 0;
+ int err, node;
+ int node_cnt = 0;
+ int parts_of_100, parts_of_10000;
+ int cache_size;
+
+ mutex_lock(&cacheqos_mutex);
+ err = cacheqos_get_occupancy_data(cq);
+ if (err) {
+ mutex_unlock(&cacheqos_mutex);
+ return err;
+ }
+
+ for_each_node_with_cpus(node) {
+ ++node_cnt;
+ total_occupancy += cq->subsys_wide_info->node_results[node];
+ }
+
+ mutex_unlock(&cacheqos_mutex);
+
+ cache_size = cq->subsys_wide_info->cache_size * node_cnt;
+ parts_of_100 = (total_occupancy * 100) / (cache_size * 1024);
+ parts_of_10000 = (total_occupancy * 10000) / (cache_size * 1024) -
+ parts_of_100 * 100;
+ seq_printf(m, "%d.%02d\n", parts_of_100, parts_of_10000);
+
+ return 0;
+}
+
+/* return display each LLC's % occupancy of the socket's LLC for task group */
+static int
+cacheqos_occupancy_percent_persocket_seq_read(struct cgroup_subsys_state *css,
+ struct cftype *cft,
+ struct seq_file *m)
+{
+ struct cacheqos *cq = css_cacheqos(css);
+ u64 total_occupancy;
+ int err, node;
+ int cache_size;
+ int parts_of_100, parts_of_10000;
+
+ mutex_lock(&cacheqos_mutex);
+ err = cacheqos_get_occupancy_data(cq);
+ if (err) {
+ mutex_unlock(&cacheqos_mutex);
+ return err;
+ }
+
+ cache_size = cq->subsys_wide_info->cache_size;
+ for_each_node_with_cpus(node) {
+ total_occupancy = cq->subsys_wide_info->node_results[node];
+ parts_of_100 = (total_occupancy * 100) / (cache_size * 1024);
+ parts_of_10000 = (total_occupancy * 10000) /
+ (cache_size * 1024) - parts_of_100 * 100;
+
+ seq_printf(m, "%d.%02d\n", parts_of_100, parts_of_10000);
+ }
+
+ mutex_unlock(&cacheqos_mutex);
+
+ return 0;
+}
+
+static struct cftype cacheqos_files[] = {
+ {
+ .name = "monitor_cache",
+ .read_u64 = cacheqos_monitor_read,
+ .write_u64 = cacheqos_monitor_write,
+ .mode = 0666,
+ .flags = CFTYPE_NOT_ON_ROOT,
+ },
+ {
+ .name = "occupancy_persocket",
+ .read_seq_string = cacheqos_occupancy_persocket_seq_read,
+ },
+ {
+ .name = "occupancy",
+ .read_seq_string = cacheqos_occupancy_read,
+ },
+ {
+ .name = "occupancy_percent_persocket",
+ .read_seq_string = cacheqos_occupancy_percent_persocket_seq_read,
+ },
+ {
+ .name = "occupancy_percent",
+ .read_seq_string = cacheqos_occupancy_percent_read,
+ },
+ { } /* terminate */
+};
+
+struct cgroup_subsys cacheqos_subsys = {
+ .name = "cacheqos",
+ .css_alloc = cacheqos_css_alloc,
+ .css_free = cacheqos_css_free,
+ .subsys_id = cacheqos_subsys_id,
+ .base_cftypes = cacheqos_files,
+};
+
+#endif /* CONFIG_CGROUP_CACHEQOS */
+
void dump_cpu_task(int cpu)
{
pr_info("Task dump for CPU %d:\n", cpu);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 88c85b2..f6f463f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -246,6 +246,61 @@ struct cfs_bandwidth { };
#endif /* CONFIG_CGROUP_SCHED */
+#ifdef CONFIG_CGROUP_CACHEQOS
+
+#include <linux/cgroup.h>
+
+struct rmid_list_element {
+ int rmid;
+ struct list_head list;
+};
+
+struct cacheqos_subsys_wide_info {
+ struct list_head rmid_unused_fifo;
+ struct list_head rmid_inuse_list;
+ int cache_max_rmid;
+ int cache_occ_scale;
+ int cache_size;
+ u64 node_results[MAX_NUMNODES];
+};
+
+struct cacheqos {
+ struct cgroup_subsys_state css;
+ struct cacheqos_subsys_wide_info *subsys_wide_info;
+ struct cgroup *cgrp;
+ u64 monitor_cache; /* 0/1 (disable (parent RMID)/enable (fresh RMID))*/
+ /*
+ * This lock is use for walking this cgroups children cgroups
+ * and updating their rmid values based on changes to this cgroup's
+ * monitor_cache value. If monitor_cache is 1 then this cgroup has its
+ * own rmid value but if 0 it will use its parent's rmid value.
+ */
+ spinlock_t lock;
+ u32 rmid;
+};
+
+extern struct cgroup_subsys cacheqos_subsys;
+extern struct cacheqos root_cacheqos;
+
+/* return cacheqos group corresponding to this container */
+static inline struct cacheqos *css_cacheqos(struct cgroup_subsys_state *css)
+{
+ return css ? container_of(css, struct cacheqos, css) : NULL;
+}
+
+/* return cacheqos group to which this task belongs */
+static inline struct cacheqos *task_cacheqos(struct task_struct *task)
+{
+ return css_cacheqos(task_css(task, cacheqos_subsys_id));
+}
+
+static inline struct cacheqos *parent_cacheqos(struct cacheqos *cacheqos)
+{
+ return css_cacheqos(css_parent(&cacheqos->css));
+}
+
+#endif /* CONFIG_CGROUP_CACHEQOS */
+
/* CFS-related fields in a runqueue */
struct cfs_rq {
struct load_weight load;
--
1.8.3.1
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-12-26 21:35 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-26 21:34 [RFC PATCH 0/3] x86: Add Cache QoS Monitoring (CQM) support Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 1/3] x86: Add support for Cache QoS Monitoring (CQM) detection Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 2/3] x86: Add Cache QoS Monitoring support to x86 perf uncore Peter P Waskiewicz Jr
2013-12-26 21:34 ` [RFC PATCH 3/3] cgroup: Add new cacheqos cgroup subsys to support Cache QoS Monitoring Peter P Waskiewicz Jr
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®