[libvirt] [PATCH 1/3] util: add Intel x86 RDT/CMT support

Wang Huaqiang huaqiang.wang at intel.com
Fri Jun 8 09:02:17 UTC 2018


Add RDT/CMT feature (Intel x86) by interacting with kernel resctrl file system. Integrate code into util/resctrl.
---
 src/libvirt_private.syms |   9 ++
 src/util/virresctrl.c    | 316 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/util/virresctrl.h    |  44 +++++++
 3 files changed, 367 insertions(+), 2 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b4ab1f3..e16c3e0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2634,6 +2634,15 @@ virResctrlAllocSetSize;
 virResctrlGetInfo;
 virResctrlInfoGetCache;
 virResctrlInfoNew;
+virResctrlMonNew;
+virResctrlMonSetID;
+virResctrlMonGetID;
+virResctrlMonDeterminePath;
+virResctrlMonAddPID;
+virResctrlMonCreate;
+virResctrlMonRemove;
+virResctrlMonIsRunning;
+virResctrlMonGetCacheOccupancy;
 
 
 # util/virrotatingfile.h
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
index fc11635..e5f5caf 100644
--- a/src/util/virresctrl.c
+++ b/src/util/virresctrl.c
@@ -224,6 +224,22 @@ struct _virResctrlAlloc {
 
 static virClassPtr virResctrlAllocClass;
 
+struct _virResctrlMon {
+    virObject parent;
+
+    /* pairedalloc: pointer to a resctrl allocaion it paried with.
+     * NULL for a resctrl monitoring group not associated with
+     * any allocation. */
+    virResctrlAllocPtr pairedalloc;
+    /* The identifier (any unique string for now) */
+    char *id;
+    /* libvirt-generated path, may be identical to alloction path
+     * may not if allocation is ready */
+    char *path;
+};
+
+static virClassPtr virResctrlMonClass;
+
 static void
 virResctrlAllocDispose(void *obj)
 {
@@ -275,7 +291,28 @@ virResctrlAllocOnceInit(void)
 }
 
 
+static void
+virResctrlMonDispose(void *obj)
+{
+    virResctrlMonPtr resctrlMon = obj;
+
+    VIR_FREE(resctrlMon->id);
+    VIR_FREE(resctrlMon->path);
+}
+
+
+static int
+virResctrlMonOnceInit(void)
+{
+    if (!VIR_CLASS_NEW(virResctrlMon, virClassForObject()))
+        return -1;
+
+    return 0;
+}
+
+
 VIR_ONCE_GLOBAL_INIT(virResctrlAlloc)
+VIR_ONCE_GLOBAL_INIT(virResctrlMon)
 
 
 virResctrlAllocPtr
@@ -288,6 +325,16 @@ virResctrlAllocNew(void)
 }
 
 
+virResctrlMonPtr
+virResctrlMonNew(void)
+{
+    if (virResctrlMonInitialize() < 0)
+        return NULL;
+
+    return virObjectNew(virResctrlMonClass);
+}
+
+
 /* Common functions */
 #ifdef __linux__
 static int
@@ -329,8 +376,6 @@ virResctrlLockWrite(void)
 #endif
 
 
-
-
 static int
 virResctrlUnlock(int fd)
 {
@@ -1646,3 +1691,270 @@ virResctrlAllocRemove(virResctrlAllocPtr alloc)
 
     return ret;
 }
+
+
+int
+virResctrlMonSetID(virResctrlMonPtr mon,
+                     const char *id)
+{
+    if (!id) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                _("Resctrl mon group 'id' cannot be NULL"));
+        return -1;
+    }
+
+    return VIR_STRDUP(mon->id, id);
+}
+
+
+const char *
+virResctrlMonGetID(virResctrlMonPtr mon)
+{
+    return mon->id;
+}
+
+
+int
+virResctrlMonDeterminePath(virResctrlMonPtr mon,
+                             const char *machinename)
+{
+
+    VIR_DEBUG("mon group,  mon->path=%s\n", mon->path);
+    if (!mon->id) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                _("Resctrl mon group id must be set before creation"));
+        return -1;
+    }
+
+    if (mon->path)
+        return -1;
+
+    if(mon->pairedalloc)
+    {
+        if (virAsprintf(&mon->path, "%s/%s-%s",
+                    SYSFS_RESCTRL_PATH, machinename, mon->id) < 0)
+            return -1;
+    }
+    else
+    {
+        if (virAsprintf(&mon->path, "%s/mon_groups/%s-%s",
+                    SYSFS_RESCTRL_PATH, machinename, mon->id) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
+int
+virResctrlMonAddPID(virResctrlMonPtr mon,
+                      pid_t pid)
+{
+    char *tasks = NULL;
+    char *pidstr = NULL;
+    int ret = 0;
+
+    if (!mon->path) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                _("Cannot add pid to non-existing resctrl mon group"));
+        return -1;
+    }
+
+    VIR_DEBUG("Add PID %d to domain %s\n",
+            pid, mon->path);
+
+    if (virAsprintf(&tasks, "%s/tasks", mon->path) < 0)
+        return -1;
+
+    if (virAsprintf(&pidstr, "%lld", (long long int) pid) < 0)
+        goto cleanup;
+
+    if (virFileWriteStr(tasks, pidstr, 0) < 0) {
+        virReportSystemError(errno,
+                _("Cannot write pid in tasks file '%s'"),
+                tasks);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    VIR_FREE(tasks);
+    VIR_FREE(pidstr);
+    return ret;
+}
+
+
+int
+virResctrlMonCreate(virResctrlAllocPtr pairedalloc,
+                      virResctrlMonPtr mon,
+                      const char *machinename)
+{
+    int ret = -1;
+    int lockfd = -1;
+
+    if (!mon)
+        return 0;
+
+
+    if (pairedalloc)
+    {
+        if (!virFileExists(pairedalloc->path)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                    _("For paired mon group, the resctrl allocation "
+                        "must be created first"));
+            goto cleanup;
+        }
+        mon->pairedalloc = pairedalloc;
+
+        if (virResctrlMonDeterminePath(mon, machinename) < 0)
+            return -1;
+    }
+    else
+    {
+        mon->pairedalloc = NULL;
+
+        /* resctrl mon group object may use for multiple purpose,
+         * free mon group path information*/
+        VIR_FREE(mon->path);
+
+        if (virResctrlMonDeterminePath(mon, machinename) < 0)
+            return -1;
+
+        lockfd = virResctrlLockWrite();
+        if (lockfd < 0)
+            goto cleanup;
+
+        if (virFileExists(mon->path))
+        {
+            VIR_DEBUG("Removing resctrl mon group %s", mon->path);
+            if (rmdir(mon->path) != 0 && errno != ENOENT) {
+                ret = -errno;
+                VIR_ERROR(_("Unable to remove %s (%d)"), mon->path, errno);
+                goto cleanup;
+            }
+        }
+
+        if (virFileMakePath(mon->path) < 0) {
+            virReportSystemError(errno,
+                    _("Cannot create resctrl directory '%s'"),
+                    mon->path);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+cleanup:
+    virResctrlUnlock(lockfd);
+    return ret;
+}
+
+
+int
+virResctrlMonRemove(virResctrlMonPtr mon)
+{
+    int ret = 0;
+
+    if (!mon->path)
+        return 0;
+
+    VIR_DEBUG("Removing resctrl mon group %s", mon->path);
+    if (rmdir(mon->path) != 0 && errno != ENOENT) {
+        ret = -errno;
+        VIR_ERROR(_("Unable to remove %s (%d)"), mon->path, errno);
+    }
+
+    return ret;
+}
+
+
+bool
+virResctrlMonIsRunning(virResctrlMonPtr mon)
+{
+    bool ret = false;
+    char *tasks = NULL;
+
+    if (mon && virFileExists(mon->path)) {
+        ret = virFileReadValueString(&tasks, "%s/tasks", mon->path);
+        if (ret < 0)
+            goto cleanup;
+
+        if (!tasks || !tasks[0])
+            goto cleanup;
+
+        ret = true;
+    }
+
+cleanup:
+    VIR_FREE(tasks);
+
+    return ret;
+}
+
+
+int
+virResctrlMonGetCacheOccupancy(virResctrlMonPtr mon,
+        unsigned int * cacheoccu)
+{
+    DIR *dirp = NULL;
+    int ret = -1;
+    int rv = -1;
+    struct dirent *ent = NULL;
+    unsigned int cachetotal = 0;
+    unsigned int cacheoccyperblock = 0;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *pathmondata = NULL;
+
+    if (!mon->path)
+        goto cleanup;
+
+    rv = virDirOpenIfExists(&dirp,mon->path);
+    if (rv <= 0) {
+        goto cleanup;
+    }
+
+    virBufferAsprintf(&buf, "%s/mon_data",
+            mon->path);
+    pathmondata = virBufferContentAndReset(&buf);
+    if (!pathmondata)
+        goto cleanup;
+
+    VIR_DEBUG("Seek llc_occupancy file from root: %s ",
+            pathmondata);
+
+    if (virDirOpen(&dirp, pathmondata) < 0)
+        goto cleanup;
+
+    while ((rv = virDirRead(dirp, &ent, pathmondata)) > 0) {
+        VIR_DEBUG("Parsing file '%s'", ent->d_name);
+        if (ent->d_type != DT_DIR)
+            continue;
+
+        if (STRNEQLEN(ent->d_name, "mon_L", 5))
+            continue;
+
+        rv = virFileReadValueUint(&cacheoccyperblock,
+                "%s/%s/llc_occupancy",
+                pathmondata, ent->d_name);
+        if (rv == -2) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                    "file %s/%s/llc_occupancy does not exist",
+                    pathmondata, ent->d_name);
+            goto cleanup;
+        } else if (rv < 0) {
+            goto cleanup;
+        }
+
+        VIR_DEBUG("%s/%s/llc_occupancy:  occupancy %d bytes",
+                pathmondata, ent->d_name, cacheoccyperblock);
+
+        cachetotal += cacheoccyperblock;
+    }
+
+    *cacheoccu = cachetotal;
+
+    ret = 0;
+cleanup:
+    VIR_FREE(pathmondata);
+    VIR_DIR_CLOSE(dirp);
+    return ret;
+}
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
index 5368ba2..a23c425 100644
--- a/src/util/virresctrl.h
+++ b/src/util/virresctrl.h
@@ -35,6 +35,12 @@ typedef enum {
 
 VIR_ENUM_DECL(virCache);
 
+typedef enum {
+    VIR_RESCTRL_MONACT_NONE,
+    VIR_RESCTRL_MONACT_ENABLE,
+    VIR_RESCTRL_MONACT_DISABLE
+} virResctrlMonAct;
+
 
 typedef struct _virResctrlInfoPerCache virResctrlInfoPerCache;
 typedef virResctrlInfoPerCache *virResctrlInfoPerCachePtr;
@@ -118,4 +124,42 @@ virResctrlAllocAddPID(virResctrlAllocPtr alloc,
 int
 virResctrlAllocRemove(virResctrlAllocPtr alloc);
 
+
+/* Monitoring-related things */
+typedef struct _virResctrlMon virResctrlMon;
+typedef virResctrlMon *virResctrlMonPtr;
+
+virResctrlMonPtr
+virResctrlMonNew(void);
+
+int
+virResctrlMonSetID(virResctrlMonPtr mon,
+        const char *id);
+
+const char *
+virResctrlMonGetID(virResctrlMonPtr mon);
+
+int
+virResctrlMonDeterminePath(virResctrlMonPtr mon,
+        const char *machinename);
+
+int
+virResctrlMonAddPID(virResctrlMonPtr alloc,
+        pid_t pid);
+
+int
+virResctrlMonCreate(virResctrlAllocPtr pairedalloc,
+        virResctrlMonPtr mon,
+        const char *machinename);
+
+int
+virResctrlMonRemove(virResctrlMonPtr mon);
+
+bool
+virResctrlMonIsRunning(virResctrlMonPtr mon);
+
+int
+virResctrlMonGetCacheOccupancy(virResctrlMonPtr mon,
+        unsigned int * cacheoccu);
+
 #endif /*  __VIR_RESCTRL_H__ */
-- 
2.7.4




More information about the libvir-list mailing list