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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list