Signed-off-by: Martin Kletzander <mkletzan@xxxxxxxxxx> --- src/conf/capabilities.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++ src/conf/capabilities.h | 29 +++++++++ src/libvirt_private.syms | 1 + 3 files changed, 186 insertions(+) diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index be95c50cfb67..c07c64e7d73c 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -31,6 +31,7 @@ #include <unistd.h> #include "capabilities.h" +#include "c-ctype.h" #include "count-one-bits.h" #include "cpu_conf.h" #include "domain_conf.h" @@ -238,6 +239,10 @@ virCapabilitiesDispose(void *object) virCapabilitiesClearSecModel(&caps->host.secModels[i]); VIR_FREE(caps->host.secModels); + for (i = 0; i < caps->host.ncaches; i++) + virCapsHostCacheBankFree(caps->host.caches[i]); + VIR_FREE(caps->host.caches); + VIR_FREE(caps->host.netprefix); VIR_FREE(caps->host.pagesSize); virCPUDefFree(caps->host.cpu); @@ -861,6 +866,49 @@ virCapabilitiesFormatNUMATopology(virBufferPtr buf, return 0; } +static int +virCapabilitiesFormatCaches(virBufferPtr buf, + size_t ncaches, + virCapsHostCacheBankPtr *caches) +{ + size_t i = 0; + + if (!ncaches) + return 0; + + virBufferAddLit(buf, "<cache>\n"); + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < ncaches; i++) { + virCapsHostCacheBankPtr bank = caches[i]; + char *cpus_str = virBitmapFormat(bank->cpus); + bool kilos = !(bank->size % 1024); + + if (!cpus_str) + return -1; + + /* + * Let's just *hope* the size is aligned to KiBs so that it does not + * bite is back in the future + */ + virBufferAsprintf(buf, + "<bank id='%u' level='%u' type='%s' " + "size='%llu' unit='%s' cpus='%s'/>\n", + bank->id, bank->level, + virCacheTypeToString(bank->type), + bank->size >> (kilos * 10), + kilos ? "KiB" : "B", + cpus_str); + + VIR_FREE(cpus_str); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</cache>\n"); + + return 0; +} + /** * virCapabilitiesFormatXML: * @caps: capabilities to format @@ -957,6 +1005,10 @@ virCapabilitiesFormatXML(virCapsPtr caps) caps->host.numaCell) < 0) goto error; + if (virCapabilitiesFormatCaches(&buf, caps->host.ncaches, + caps->host.caches) < 0) + goto error; + for (i = 0; i < caps->host.nsecModels; i++) { virBufferAddLit(&buf, "<secmodel>\n"); virBufferAdjustIndent(&buf, 2); @@ -1439,3 +1491,107 @@ virCapabilitiesInitPages(virCapsPtr caps) VIR_FREE(pages_size); return ret; } + + +VIR_ENUM_IMPL(virCache, VIR_CACHE_TYPE_LAST, + "unified", + "instruction", + "data") + +bool +virCapsHostCacheBankEquals(virCapsHostCacheBankPtr a, + virCapsHostCacheBankPtr b) +{ + return (a->id == b->id && + a->level == b->level && + a->type == b->type && + a->size == b->size && + virBitmapEqual(a->cpus, b->cpus)); +} + +void +virCapsHostCacheBankFree(virCapsHostCacheBankPtr ptr) +{ + if (!ptr) + return; + + virBitmapFree(ptr->cpus); + VIR_FREE(ptr); +} + +int +virCapabilitiesInitCaches(virCapsPtr caps) +{ + size_t i = 0; + virBitmapPtr cpus = NULL; + ssize_t pos = -1; + DIR *dirp = NULL; + int ret = -1; + char *type = NULL; + struct dirent *ent = NULL; + virCapsHostCacheBankPtr bank = NULL; + + /* offline CPUs don't provide cache info */ + if (virSysfsGetValueBitmap("cpu/online", &cpus) < 0) + return -1; + + while ((pos = virBitmapNextSetBit(cpus, pos)) >= 0) { + int rv = virSysfsCpuDirOpen(pos, "cache/", &dirp); + + if (rv == -2) + continue; + + while ((rv = virDirRead(dirp, &ent, "cache/")) > 0) { + int tmp_i; + char *tmp_c; + + if (!STRPREFIX(ent->d_name, "index")) + continue; + + if (VIR_ALLOC(bank) < 0) + goto cleanup; + + if (virSysfsGetCpuCacheValueUint(pos, ent->d_name, "id", &bank->id) < 0 || + virSysfsGetCpuCacheValueUint(pos, ent->d_name, "level", &bank->level) < 0 || + virSysfsGetCpuCacheValueString(pos, ent->d_name, "type", &type) < 0 || + virSysfsGetCpuCacheValueScaledInt(pos, ent->d_name, "size", &bank->size) < 0 || + virSysfsGetCpuCacheValueBitmap(pos, ent->d_name, "shared_cpu_list", &bank->cpus) < 0) + goto cleanup; + + for (tmp_c = type; tmp_c != '\0'; tmp_c++) + *tmp_c = c_tolower(*tmp_c); + + tmp_i = virCacheTypeFromString(type); + if (tmp_i < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown cache type '%s'"), type); + VIR_FREE(type); + goto cleanup; + } + bank->type = tmp_i; + + for (i = 0; i < caps->host.ncaches; i++) { + if (virCapsHostCacheBankEquals(bank, caps->host.caches[i])) + break; + } + if (i == caps->host.ncaches) { + if (VIR_APPEND_ELEMENT(caps->host.caches, + caps->host.ncaches, + bank) < 0) { + goto cleanup; + } + bank = NULL; + continue; + } + + } + if (rv < 0) + goto cleanup; + } + + ret = 0; + cleanup: + virDirClose(&dirp); + virCapsHostCacheBankFree(bank); + return ret; +} diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index d10eef3afdea..e099cccf6d39 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -138,6 +138,26 @@ struct _virCapsHostSecModel { virCapsHostSecModelLabelPtr labels; }; +typedef enum { + VIR_CACHE_TYPE_DATA, + VIR_CACHE_TYPE_INSTRUCTION, + VIR_CACHE_TYPE_UNIFIED, + + VIR_CACHE_TYPE_LAST +} virCacheType; + +VIR_ENUM_DECL(virCache); + +typedef struct _virCapsHostCacheBank virCapsHostCacheBank; +typedef virCapsHostCacheBank *virCapsHostCacheBankPtr; +struct _virCapsHostCacheBank { + unsigned int id; + unsigned int level; /* 1=L1, 2=L2, 3=L3, etc. */ + unsigned long long size; /* B */ + virCacheType type; /* Data, Instruction or Unified */ + virBitmapPtr cpus; /* All CPUs that share this bank */ +}; + typedef struct _virCapsHost virCapsHost; typedef virCapsHost *virCapsHostPtr; struct _virCapsHost { @@ -157,6 +177,9 @@ struct _virCapsHost { size_t nnumaCell_max; virCapsHostNUMACellPtr *numaCell; + size_t ncaches; + virCapsHostCacheBankPtr *caches; + size_t nsecModels; virCapsHostSecModelPtr secModels; @@ -303,4 +326,10 @@ int virCapabilitiesInitPages(virCapsPtr caps); int virCapabilitiesInitNUMA(virCapsPtr caps); +bool virCapsHostCacheBankEquals(virCapsHostCacheBankPtr a, + virCapsHostCacheBankPtr b); +void virCapsHostCacheBankFree(virCapsHostCacheBankPtr ptr); + +int virCapabilitiesInitCaches(virCapsPtr caps); + #endif /* __VIR_CAPABILITIES_H */ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0b3b41516fe6..5eb8c1ae962b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -59,6 +59,7 @@ virCapabilitiesFreeNUMAInfo; virCapabilitiesGetCpusForNodemask; virCapabilitiesGetNodeInfo; virCapabilitiesHostSecModelAddBaseLabel; +virCapabilitiesInitCaches; virCapabilitiesInitNUMA; virCapabilitiesInitPages; virCapabilitiesNew; -- 2.12.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list