[PATCH v3 09/46] perf/x86/intel/cmt: add basic monr hierarchy
From: David Carrillo-Cisneros
Date: Sat Oct 29 2016 - 20:48:37 EST
Add root for monr hierarchy and auxiliary functions for locking.
Also, add support for attaching CPU and tasks events to monr hierarchy.
As of this patch, both types of events always use the root monr (this
will change when cgroups are introduced later in this series).
More details in code's comments.
Signed-off-by: David Carrillo-Cisneros <davidcc@xxxxxxxxxx>
---
arch/x86/events/intel/cmt.c | 77 +++++++++++++++++++++++++++++++++++++++++++--
arch/x86/events/intel/cmt.h | 26 +++++++++++++++
2 files changed, 101 insertions(+), 2 deletions(-)
diff --git a/arch/x86/events/intel/cmt.c b/arch/x86/events/intel/cmt.c
index 23606a7..39f4bfa 100644
--- a/arch/x86/events/intel/cmt.c
+++ b/arch/x86/events/intel/cmt.c
@@ -26,6 +26,9 @@ static unsigned int cmt_l3_scale; /* cmt hw units to bytes. */
static unsigned int __min_max_rmid; /* minimum max_rmid across all pkgs. */
+/* Root for system-wide hierarchy of MONitored Resources (monr). */
+static struct monr *monr_hrchy_root;
+
/* Array of packages (array of pkgds). It's protected by RCU or cmt_mutex. */
static struct pkg_data **cmt_pkgs_data;
@@ -82,6 +85,24 @@ static void monr_hrchy_assert_held_mutexes(void)
lockdep_assert_held(&pkgd->mutex);
}
+static void monr_hrchy_acquire_locks(unsigned long *flags)
+{
+ struct pkg_data *pkgd = NULL;
+
+ raw_local_irq_save(*flags);
+ while ((pkgd = cmt_pkgs_data_next_rcu(pkgd)))
+ raw_spin_lock(&pkgd->lock);
+}
+
+static void monr_hrchy_release_locks(unsigned long *flags)
+{
+ struct pkg_data *pkgd = NULL;
+
+ while ((pkgd = cmt_pkgs_data_next_rcu(pkgd)))
+ raw_spin_unlock(&pkgd->lock);
+ raw_local_irq_restore(*flags);
+}
+
static void monr_dealloc(struct monr *monr)
{
kfree(monr);
@@ -97,6 +118,10 @@ static struct monr *monr_alloc(void)
if (!monr)
return ERR_PTR(-ENOMEM);
+ INIT_LIST_HEAD(&monr->entry);
+ INIT_LIST_HEAD(&monr->children);
+ INIT_LIST_HEAD(&monr->parent_entry);
+
return monr;
}
@@ -145,6 +170,26 @@ static int monr_append_event(struct monr *monr, struct perf_event *event)
return 0;
}
+static void monr_hrchy_insert_leaf(struct monr *monr, struct monr *parent)
+{
+ unsigned long flags;
+
+ monr_hrchy_acquire_locks(&flags);
+ list_add_tail(&monr->parent_entry, &parent->children);
+ monr->parent = parent;
+ monr_hrchy_release_locks(&flags);
+}
+
+static void monr_hrchy_remove_leaf(struct monr *monr)
+{
+ unsigned long flags;
+
+ monr_hrchy_acquire_locks(&flags);
+ list_del_init(&monr->parent_entry);
+ monr->parent = NULL;
+ monr_hrchy_release_locks(&flags);
+}
+
static bool is_cgroup_event(struct perf_event *event)
{
return false;
@@ -155,20 +200,32 @@ static int monr_hrchy_attach_cgroup_event(struct perf_event *event)
return -EPERM;
}
+/*
+ * This non cgroup version creates a two-levels hierarchy: Root and first level
+ * and all event monr underneath it.
+ */
+static struct monr *monr_hrchy_get_monr_parent(struct perf_event *event)
+{
+ return monr_hrchy_root;
+}
+
static int monr_hrchy_attach_cpu_event(struct perf_event *event)
{
- return -EPERM;
+ return monr_append_event(monr_hrchy_root, event);
}
static int monr_hrchy_attach_task_event(struct perf_event *event)
{
- struct monr *monr;
+ struct monr *monr_parent, *monr;
int err;
+ monr_parent = monr_hrchy_get_monr_parent(event);
monr = monr_alloc();
if (IS_ERR(monr))
return -ENOMEM;
+ monr_hrchy_insert_leaf(monr, monr_parent);
+
err = monr_append_event(monr, event);
if (err)
monr_dealloc(monr);
@@ -199,6 +256,12 @@ static int monr_hrchy_attach_event(struct perf_event *event)
return err;
}
+static void monr_destroy(struct monr *monr)
+{
+ monr_hrchy_remove_leaf(monr);
+ monr_dealloc(monr);
+}
+
/**
* __match_event() - Determine if @a and @b should share a rmid.
*/
@@ -281,6 +344,7 @@ static void intel_cmt_event_destroy(struct perf_event *event)
/* monr is dettached from event. */
monr = monr_remove_event(event);
+ monr_destroy(monr);
monr_hrchy_release_mutexes();
mutex_unlock(&cmt_mutex);
@@ -516,6 +580,9 @@ static const struct x86_cpu_id intel_cmt_match[] = {
static void cmt_dealloc(void)
{
+ kfree(monr_hrchy_root);
+ monr_hrchy_root = NULL;
+
kfree(cmt_pkgs_data);
cmt_pkgs_data = NULL;
}
@@ -537,6 +604,12 @@ static int __init cmt_alloc(void)
if (!cmt_pkgs_data)
return -ENOMEM;
+ mutex_lock(&cmt_mutex);
+ monr_hrchy_root = monr_alloc();
+ mutex_unlock(&cmt_mutex);
+ if (IS_ERR(monr_hrchy_root))
+ return PTR_ERR(monr_hrchy_root);
+
return 0;
}
diff --git a/arch/x86/events/intel/cmt.h b/arch/x86/events/intel/cmt.h
index 0ce5d4d..46e8335 100644
--- a/arch/x86/events/intel/cmt.h
+++ b/arch/x86/events/intel/cmt.h
@@ -7,6 +7,25 @@
* In order to monitor a cgroups and/or thread, it must be associated to
* a monr. A monr is active in a CPU when a thread that is associated to
* it (either directly or through a cgroup) is scheduled in it.
+ * The monrs are organized in a tree hierarchy named "monr hierarchy". It
+ * captures the dependencies between the monitored entities, e.g.:
+ *
+ * cgroup hierarchy monr hierarchy
+ *------------------------------------------------------------------------
+ * root cgroup root monr
+ * (always monitored) / \
+ * / \ monr A monr B1
+ * cgroup A cgroupB |
+ * (monitored) (no monitored) monr A1
+ * | / \
+ * task A1 task B1 task B2
+ * (monitored) (monitored) (no monitored)
+ *
+ *
+ * This driver mantains the monr hierarchy as separate from the cgroup
+ * hierarchy in order to reduce the need for synchronization between the two
+ * and to make possible to capture dependencies between threads in the same
+ * cgroup or process.
*
*
* Locking
@@ -46,6 +65,9 @@ struct pkg_data {
* struct monr - MONitored Resource.
* @mon_events: The head of event's group that use this monr, if any.
* @entry: List entry into cmt_event_monrs.
+ * @parent: Parent in monr hierarchy.
+ * @children: List of children in monr hierarchy.
+ * @parent_entry: Entry in parent's children list.
*
* An monr is assigned to every CMT event and/or monitored cgroups when
* monitoring is activated and that instance's address do not change during
@@ -54,4 +76,8 @@ struct pkg_data {
struct monr {
struct perf_event *mon_events;
struct list_head entry;
+
+ struct monr *parent;
+ struct list_head children;
+ struct list_head parent_entry;
};
--
2.8.0.rc3.226.g39d4020