From nobody Sat Feb 7 09:30:07 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1493118702001916.5768863906059; Tue, 25 Apr 2017 04:11:42 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D29EDC05AD70; Tue, 25 Apr 2017 11:11:39 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9521379C59; Tue, 25 Apr 2017 11:11:39 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 400E35EC69; Tue, 25 Apr 2017 11:11:39 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v3PBAgjN031920 for ; Tue, 25 Apr 2017 07:10:42 -0400 Received: by smtp.corp.redhat.com (Postfix) id AD8F590DD1; Tue, 25 Apr 2017 11:10:42 +0000 (UTC) Received: from caroline.brq.redhat.com (dhcp129-198.brq.redhat.com [10.34.129.198]) by smtp.corp.redhat.com (Postfix) with ESMTP id E8F0D17BA3; Tue, 25 Apr 2017 11:10:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D29EDC05AD70 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com D29EDC05AD70 From: Martin Kletzander To: libvir-list@redhat.com Date: Tue, 25 Apr 2017 13:10:29 +0200 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-loop: libvir-list@redhat.com Cc: =?UTF-8?q?Erik=20=C5=A0kult=C3=A9ty?= Subject: [libvirt] [PATCH v3 5/8] Add host cache information in capabilities X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 25 Apr 2017 11:11:40 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" We're only adding only info about L3 caches, we can add more later (just by changing one line), but for now that's more than enough without overwhelming anyone. XML snippet of how this should look like (also seen as part of the commit): Signed-off-by: Martin Kletzander --- docs/schemas/capability.rng | 34 ++++ src/conf/capabilities.c | 204 ++++++++++++++++++++= ++++ src/conf/capabilities.h | 29 ++++ src/libvirt_private.syms | 1 + tests/vircaps2xmldata/vircaps-x86_64-caches.xml | 3 + tests/vircaps2xmltest.c | 3 +- 6 files changed, 273 insertions(+), 1 deletion(-) diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng index 88e08d299ac9..26f0aa22bd3f 100644 --- a/docs/schemas/capability.rng +++ b/docs/schemas/capability.rng @@ -45,6 +45,9 @@ + + + @@ -248,6 +251,37 @@ + + + + + + + + + + + + + both + code + data + + + + + + + + + + + + + + + + diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 7ed76e65b1a1..c36ca4088976 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -50,6 +50,8 @@ #define VIR_FROM_THIS VIR_FROM_CAPABILITIES +#define SYSFS_SYSTEM_PATH "/sys/devices/system" + VIR_LOG_INIT("conf.capabilities") VIR_ENUM_DECL(virCapsHostPMTarget) @@ -237,6 +239,10 @@ virCapabilitiesDispose(void *object) virCapabilitiesClearSecModel(&caps->host.secModels[i]); VIR_FREE(caps->host.secModels); + for (i =3D 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); @@ -860,6 +866,49 @@ virCapabilitiesFormatNUMATopology(virBufferPtr buf, return 0; } +static int +virCapabilitiesFormatCaches(virBufferPtr buf, + size_t ncaches, + virCapsHostCacheBankPtr *caches) +{ + size_t i =3D 0; + + if (!ncaches) + return 0; + + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + + for (i =3D 0; i < ncaches; i++) { + virCapsHostCacheBankPtr bank =3D caches[i]; + char *cpus_str =3D virBitmapFormat(bank->cpus); + bool kilos =3D !(bank->size % 1024); + + if (!cpus_str) + return -1; + + /* + * Let's just *hope* the size is aligned to KiBs so that it does n= ot + * bite is back in the future + */ + virBufferAsprintf(buf, + "\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, "\n"); + + return 0; +} + /** * virCapabilitiesFormatXML: * @caps: capabilities to format @@ -956,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 =3D 0; i < caps->host.nsecModels; i++) { virBufferAddLit(&buf, "\n"); virBufferAdjustIndent(&buf, 2); @@ -1438,3 +1491,154 @@ virCapabilitiesInitPages(virCapsPtr caps) VIR_FREE(pages_size); return ret; } + +/* Cache name mapping for Linux kernel naming */ +VIR_ENUM_DECL(virCacheKernel); +VIR_ENUM_IMPL(virCacheKernel, VIR_CACHE_TYPE_LAST, + "Unified", + "Instruction", + "Data") + +/* Our naming for cache types and scopes */ +VIR_ENUM_IMPL(virCache, VIR_CACHE_TYPE_LAST, + "both", + "code", + "data") + +bool +virCapsHostCacheBankEquals(virCapsHostCacheBankPtr a, + virCapsHostCacheBankPtr b) +{ + return (a->id =3D=3D b->id && + a->level =3D=3D b->level && + a->type =3D=3D b->type && + a->size =3D=3D 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 =3D 0; + virBitmapPtr cpus =3D NULL; + ssize_t pos =3D -1; + DIR *dirp =3D NULL; + int ret =3D -1; + char *path =3D NULL; + char *type =3D NULL; + struct dirent *ent =3D NULL; + virCapsHostCacheBankPtr bank =3D NULL; + + /* Minimum level to expose in capabilities. Can be lowered or removed= (with + * the appropriate code below), but should not be increased, because w= e'd + * lose information. */ + const int cache_min_level =3D 3; + + /* offline CPUs don't provide cache info */ + if (virFileReadValueBitmap(&cpus, "%s/cpu/online", SYSFS_SYSTEM_PATH) = < 0) + return -1; + + while ((pos =3D virBitmapNextSetBit(cpus, pos)) >=3D 0) { + int rv =3D -1; + + VIR_FREE(path); + if (virAsprintf(&path, "%s/cpu/cpu%zd/cache/", SYSFS_SYSTEM_PATH, = pos) < 0) + goto cleanup; + + rv =3D virDirOpenIfExists(&dirp, path); + if (rv < 0) + goto cleanup; + + if (!dirp) + continue; + + while ((rv =3D virDirRead(dirp, &ent, path)) > 0) { + int kernel_type; + unsigned int level; + + if (!STRPREFIX(ent->d_name, "index")) + continue; + + if (virFileReadValueUint(&level, + "%s/cpu/cpu%zd/cache/%s/level", + SYSFS_SYSTEM_PATH, pos, ent->d_name) = < 0) + goto cleanup; + + if (level < cache_min_level) + continue; + + if (VIR_ALLOC(bank) < 0) + goto cleanup; + + bank->level =3D level; + + if (virFileReadValueUint(&bank->id, + "%s/cpu/cpu%zd/cache/%s/id", + SYSFS_SYSTEM_PATH, pos, ent->d_name) = < 0) + goto cleanup; + + if (virFileReadValueUint(&bank->level, + "%s/cpu/cpu%zd/cache/%s/level", + SYSFS_SYSTEM_PATH, pos, ent->d_name) = < 0) + goto cleanup; + + if (virFileReadValueString(&type, + "%s/cpu/cpu%zd/cache/%s/type", + SYSFS_SYSTEM_PATH, pos, ent->d_name= ) < 0) + goto cleanup; + + if (virFileReadValueScaledInt(&bank->size, + "%s/cpu/cpu%zd/cache/%s/size", + SYSFS_SYSTEM_PATH, pos, ent->d_n= ame) < 0) + goto cleanup; + + if (virFileReadValueBitmap(&bank->cpus, + "%s/cpu/cpu%zd/cache/%s/shared_cpu_= list", + SYSFS_SYSTEM_PATH, pos, ent->d_name= ) < 0) + goto cleanup; + + kernel_type =3D virCacheKernelTypeFromString(type); + if (kernel_type < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown cache type '%s'"), type); + VIR_FREE(type); + goto cleanup; + } + bank->type =3D kernel_type; + + for (i =3D 0; i < caps->host.ncaches; i++) { + if (virCapsHostCacheBankEquals(bank, caps->host.caches[i])) + break; + } + if (i =3D=3D caps->host.ncaches) { + if (VIR_APPEND_ELEMENT(caps->host.caches, + caps->host.ncaches, + bank) < 0) { + goto cleanup; + } + } + + virCapsHostCacheBankFree(bank); + bank =3D NULL; + } + if (rv < 0) + goto cleanup; + } + + ret =3D 0; + cleanup: + VIR_FREE(path); + virDirClose(&dirp); + virCapsHostCacheBankFree(bank); + return ret; +} diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index d10eef3afdea..a8cccf7184a5 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -138,6 +138,26 @@ struct _virCapsHostSecModel { virCapsHostSecModelLabelPtr labels; }; +typedef enum { + VIR_CACHE_TYPE_BOTH, + VIR_CACHE_TYPE_CODE, + VIR_CACHE_TYPE_DATA, + + 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=3DL1, 2=3DL2, 3=3DL3, 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 5f98c5d52d9f..6b117b7a0c33 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -59,6 +59,7 @@ virCapabilitiesFreeNUMAInfo; virCapabilitiesGetCpusForNodemask; virCapabilitiesGetNodeInfo; virCapabilitiesHostSecModelAddBaseLabel; +virCapabilitiesInitCaches; virCapabilitiesInitNUMA; virCapabilitiesInitPages; virCapabilitiesNew; diff --git a/tests/vircaps2xmldata/vircaps-x86_64-caches.xml b/tests/vircap= s2xmldata/vircaps-x86_64-caches.xml index 88f2ec62277e..fe0be6d08fa7 100644 --- a/tests/vircaps2xmldata/vircaps-x86_64-caches.xml +++ b/tests/vircaps2xmldata/vircaps-x86_64-caches.xml @@ -28,6 +28,9 @@ + + + diff --git a/tests/vircaps2xmltest.c b/tests/vircaps2xmltest.c index 6bf55aae5ba7..c957120aae44 100644 --- a/tests/vircaps2xmltest.c +++ b/tests/vircaps2xmltest.c @@ -58,7 +58,8 @@ test_virCapabilities(const void *opaque) if (!caps) goto cleanup; - if (virCapabilitiesInitNUMA(caps) < 0) + if (virCapabilitiesInitNUMA(caps) < 0 || + virCapabilitiesInitCaches(caps) < 0) goto cleanup; virFileWrapperClearPrefixes(); --=20 2.12.2 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list