[libvirt] [PATCHv2 01/10] util: add Intel x86 RDT/CMT support

Wang Huaqiang huaqiang.wang at intel.com
Mon Jul 9 07:00:49 UTC 2018


Add RDT/CMT feature (Intel x86) by interacting with kernel
resctrl file system. Integrate code into util/resctrl.
---
 src/libvirt_private.syms |  10 ++
 src/util/virresctrl.c    | 338 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virresctrl.h    |  40 ++++++
 3 files changed, 388 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3e30490..b10a3a5 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2655,6 +2655,16 @@ virResctrlAllocSetID;
 virResctrlAllocSetSize;
 virResctrlInfoGetCache;
 virResctrlInfoNew;
+virResctrlMonAddPID;
+virResctrlMonCreate;
+virResctrlMonDeterminePath;
+virResctrlMonGetAlloc;
+virResctrlMonGetCacheOccupancy;
+virResctrlMonGetID;
+virResctrlMonIsRunning;
+virResctrlMonNew;
+virResctrlMonRemove;
+virResctrlMonSetID;
 
 
 # util/virrotatingfile.h
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
index e492a63..3dca937 100644
--- a/src/util/virresctrl.c
+++ b/src/util/virresctrl.c
@@ -90,6 +90,7 @@ typedef virResctrlAllocPerLevel *virResctrlAllocPerLevelPtr;
 /* Class definitions and initializations */
 static virClassPtr virResctrlInfoClass;
 static virClassPtr virResctrlAllocClass;
+static virClassPtr virResctrlMonClass;
 
 
 /* virResctrlInfo */
@@ -257,6 +258,33 @@ virResctrlAllocDispose(void *obj)
 }
 
 
+
+/* virResctrlMon*/
+struct _virResctrlMon {
+    virObject parent;
+
+    /* alloc: keeps the pointer to a allocation group if sharing same
+     * resctrlfs subdirectory with a allocation group.
+     * NULL for a standalone monitoring group.*/
+    virResctrlAllocPtr alloc;
+    /* The identifier (any unique string for now) */
+    char *id;
+    /* libvirt-generated path, be identical to path of 'alloc' if sharing
+     * same resctrlfs subdirectory with allocation group */
+    char *path;
+};
+
+
+static void
+virResctrlMonDispose(void *obj)
+{
+    virResctrlMonPtr resctrlMon = obj;
+
+    VIR_FREE(resctrlMon->id);
+    VIR_FREE(resctrlMon->path);
+}
+
+
 /* Global initialization for classes */
 static int
 virResctrlOnceInit(void)
@@ -267,6 +295,9 @@ virResctrlOnceInit(void)
     if (!VIR_CLASS_NEW(virResctrlAlloc, virClassForObject()))
         return -1;
 
+    if (!VIR_CLASS_NEW(virResctrlMon, virClassForObject()))
+        return -1;
+
     return 0;
 }
 
@@ -1612,3 +1643,310 @@ virResctrlAllocRemove(virResctrlAllocPtr alloc)
 
     return ret;
 }
+
+
+virResctrlMonPtr
+virResctrlMonNew(void)
+{
+    if (virResctrlInitialize() < 0)
+        return NULL;
+
+    return virObjectNew(virResctrlMonClass);
+}
+
+
+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)
+{
+    char *grouppath = NULL;
+    int ret = -1;
+
+    if (!mon->id) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                _("Resctrl mon group id must be set before creation"));
+        goto cleanup;
+    }
+
+    if (!mon->path) {
+        if (virAsprintf(&grouppath, "%s/mon_groups/%s-%s",
+                        SYSFS_RESCTRL_PATH, machinename, mon->id) < 0) {
+
+            goto cleanup;
+        }
+        VIR_STEAL_PTR(mon->path, grouppath);
+
+    } else {
+        /* if path exists, validate it */
+        if (virAsprintf(&grouppath, "%s/%s-%s",
+                        SYSFS_RESCTRL_PATH, machinename, mon->id) < 0) {
+            goto cleanup;
+        }
+
+        if (STRNEQ(mon->path, grouppath))
+            goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(grouppath);
+    return ret;
+}
+
+
+int
+virResctrlMonAddPID(virResctrlMonPtr mon,
+                      pid_t pid)
+{
+    char *tasks = NULL;
+    char *pidstr = NULL;
+    int ret = 0;
+
+    /* PID only writes to standalone mon group */
+    if (mon->alloc)
+        return 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 alloc,
+                      virResctrlMonPtr mon,
+                      const char *machinename)
+{
+    int ret = -1;
+    int lockfd = -1;
+
+    if (!mon)
+        return -1;
+
+    if (alloc) {
+        if (!virFileExists(alloc->path)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                    _("resctrl mon group: allocation group exists but not "
+                      "valid"));
+            return -1;
+        }
+        mon->alloc = alloc;
+
+        if (virResctrlMonDeterminePath(mon, machinename) < 0)
+            return -1;
+    } else {
+        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) {
+                virReportSystemError(errno,
+                                     _("Unable to remove resctrl directory '%s'"),
+                                     mon->path);
+                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;
+    int  rv = -1;
+    char *tasks = NULL;
+
+    if (mon && virFileExists(mon->path)) {
+        rv = virFileReadValueString(&tasks, "%s/tasks", mon->path);
+        if (rv < 0)
+            goto cleanup;
+
+        if (!tasks || !tasks[0])
+            goto cleanup;
+
+        ret = true;
+    }
+
+ cleanup:
+    VIR_FREE(tasks);
+    return ret;
+}
+
+
+static int
+virResctrlMonGetStatistic(virResctrlMonPtr mon,
+                          const char *resfile,
+                          unsigned int *value)
+{
+    DIR *dirp = NULL;
+    int ret = -1;
+    int rv = -1;
+    struct dirent *ent = NULL;
+    unsigned int val = 0;
+    unsigned int valtotal = 0;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *mondatapath = NULL;
+
+    if (!mon->path)
+        goto cleanup;
+
+    if (!resfile)
+        goto cleanup;
+
+    *value = 0;
+
+    rv = virDirOpenIfExists(&dirp, mon->path);
+    if (rv <= 0)
+        goto cleanup;
+
+    virBufferAsprintf(&buf, "%s/mon_data",
+            mon->path);
+    mondatapath = virBufferContentAndReset(&buf);
+    if (!mondatapath)
+        goto cleanup;
+
+    VIR_DEBUG("Seek llc_occupancy file from root: %s ",
+              mondatapath);
+
+    if (virDirOpen(&dirp, mondatapath) < 0)
+        goto cleanup;
+
+    while ((rv = virDirRead(dirp, &ent, mondatapath)) > 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(&val,
+                                  "%s/%s/%s",
+                                  mondatapath, ent->d_name, resfile);
+
+        if (rv == -2) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("file %s/%s/%s does not exist"),
+                           mondatapath, ent->d_name, resfile);
+            goto cleanup;
+        } else {
+            if (rv < 0)
+                goto cleanup;
+        }
+
+        valtotal += val;
+    }
+
+    *value = valtotal;
+    ret = 0;
+ cleanup:
+    VIR_FREE(mondatapath);
+    VIR_DIR_CLOSE(dirp);
+    return ret;
+}
+
+int
+virResctrlMonGetCacheOccupancy(virResctrlMonPtr mon,
+                               unsigned int * cacheoccu)
+{
+    const char *cacheoccufile = "llc_occupancy";
+    unsigned int value = 0;
+    int ret = - 1;
+
+    *cacheoccu = 0;
+
+    ret = virResctrlMonGetStatistic(mon,
+                                    cacheoccufile,
+                                    &value);
+    if (ret >= 0)
+        *cacheoccu = value;
+
+    return ret;
+}
+
+
+virResctrlAllocPtr
+virResctrlMonGetAlloc(virResctrlMonPtr mon)
+{
+    return mon->alloc;
+}
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
index 9052a2b..6865ab6 100644
--- a/src/util/virresctrl.h
+++ b/src/util/virresctrl.h
@@ -116,4 +116,44 @@ 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);
+
+virResctrlAllocPtr
+virResctrlMonGetAlloc(virResctrlMonPtr mon);
 #endif /*  __VIR_RESCTRL_H__ */
-- 
2.7.4




More information about the libvir-list mailing list