From nobody Wed Dec 17 00:01:02 2025 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.zohomail.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 1510563079213667.5749619183719; Mon, 13 Nov 2017 00:51:19 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EB168550CC; Mon, 13 Nov 2017 08:51:17 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C6FBA703A7; Mon, 13 Nov 2017 08:51:17 +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 9439E3D381; Mon, 13 Nov 2017 08:51:17 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id vAD8onLX016351 for ; Mon, 13 Nov 2017 03:50:49 -0500 Received: by smtp.corp.redhat.com (Postfix) id 3B4D15E7BF; Mon, 13 Nov 2017 08:50:49 +0000 (UTC) Received: from caroline.localdomain (unknown [10.43.2.67]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B33615E27D for ; Mon, 13 Nov 2017 08:50:46 +0000 (UTC) Received: from caroline.brq.redhat.com (caroline.brq.redhat.com [127.0.0.1]) by caroline.localdomain (Postfix) with ESMTP id A58E2123A81 for ; Mon, 13 Nov 2017 09:50:41 +0100 (CET) From: Martin Kletzander To: libvir-list@redhat.com Date: Mon, 13 Nov 2017 09:50:27 +0100 Message-Id: In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH 12/21] resctrl: Instantiate all resctrl information at once 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.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Mon, 13 Nov 2017 08:51:18 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" This allows for looking up the cache control information more sensibly from conf/capabilities.c and also provides more data to the virresctrl module th= at will get more usable later on. Signed-off-by: Martin Kletzander Reviewed-by: John Ferlan --- po/POTFILES.in | 1 + src/conf/capabilities.c | 48 +++---- src/conf/capabilities.h | 4 +- src/libvirt_private.syms | 4 +- src/util/virresctrl.c | 335 +++++++++++++++++++++++++++++++++----------= ---- src/util/virresctrl.h | 24 ++-- 6 files changed, 274 insertions(+), 142 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index c1fa23427eff..8382ee633621 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -252,6 +252,7 @@ src/util/virportallocator.c src/util/virprocess.c src/util/virqemu.c src/util/virrandom.c +src/util/virresctrl.c src/util/virrotatingfile.c src/util/virscsi.c src/util/virscsihost.c diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 5bf8ac2019f9..74d8e7459e6d 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -245,6 +245,7 @@ virCapabilitiesDispose(void *object) VIR_FREE(caps->host.netprefix); VIR_FREE(caps->host.pagesSize); virCPUDefFree(caps->host.cpu); + virObjectUnref(caps->host.resctrl); } =20 /** @@ -1588,6 +1589,15 @@ virCapsHostCacheBankSorter(const void *a, const void= *b) return ca->id - cb->id; } =20 +static int +virCapabilitiesInitResctrl(virCapsPtr caps) +{ + if (!caps->host.resctrl) + return virResctrlGetInfo(&caps->host.resctrl); + + return 0; +} + int virCapabilitiesInitCaches(virCapsPtr caps) { @@ -1596,7 +1606,6 @@ virCapabilitiesInitCaches(virCapsPtr caps) ssize_t pos =3D -1; DIR *dirp =3D NULL; int ret =3D -1; - int typeret; char *path =3D NULL; char *type =3D NULL; struct dirent *ent =3D NULL; @@ -1607,6 +1616,9 @@ virCapabilitiesInitCaches(virCapsPtr caps) * lose information. */ const int cache_min_level =3D 3; =20 + if (virCapabilitiesInitResctrl(caps) < 0) + return -1; + /* offline CPUs don't provide cache info */ if (virFileReadValueBitmap(&cpus, "%s/cpu/online", SYSFS_SYSTEM_PATH) = < 0) return -1; @@ -1672,32 +1684,6 @@ virCapabilitiesInitCaches(virCapsPtr caps) SYSFS_SYSTEM_PATH, pos, ent->d_name= ) < 0) goto cleanup; =20 - typeret =3D virResctrlGetCacheControlType(bank->level); - if (typeret < 0) - goto cleanup; - - if (typeret =3D=3D 1) { - if (virResctrlGetCacheInfo(bank->level, - bank->size, - VIR_CACHE_TYPE_BOTH, - &bank->controls, - &bank->ncontrols) < 0) - goto cleanup; - } else if (typeret =3D=3D 2) { - if (virResctrlGetCacheInfo(bank->level, - bank->size, - VIR_CACHE_TYPE_CODE, - &bank->controls, - &bank->ncontrols) < 0) - goto cleanup; - if (virResctrlGetCacheInfo(bank->level, - bank->size, - VIR_CACHE_TYPE_DATA, - &bank->controls, - &bank->ncontrols) < 0) - goto cleanup; - } - kernel_type =3D virCacheKernelTypeFromString(type); if (kernel_type < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -1713,6 +1699,14 @@ virCapabilitiesInitCaches(virCapsPtr caps) break; } if (i =3D=3D caps->host.ncaches) { + /* If it is a new cache, then update its resctrl informati= on. */ + if (virResctrlInfoGetCache(caps->host.resctrl, + bank->level, + bank->size, + &bank->ncontrols, + &bank->controls) < 0) + goto cleanup; + if (VIR_APPEND_ELEMENT(caps->host.caches, caps->host.ncaches, bank) < 0) { diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 5048fa819d95..694a3590bf83 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -148,7 +148,7 @@ struct _virCapsHostCacheBank { virCacheType type; /* Data, Instruction or Unified */ virBitmapPtr cpus; /* All CPUs that share this bank */ size_t ncontrols; - virResctrlInfoPtr *controls; + virResctrlInfoPerCachePtr *controls; }; =20 typedef struct _virCapsHost virCapsHost; @@ -170,6 +170,8 @@ struct _virCapsHost { size_t nnumaCell_max; virCapsHostNUMACellPtr *numaCell; =20 + virResctrlInfoPtr resctrl; + size_t ncaches; virCapsHostCacheBankPtr *caches; =20 diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3986cc523e39..b24728ce4a1d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2532,8 +2532,8 @@ virRandomInt; # util/virresctrl.h virCacheTypeFromString; virCacheTypeToString; -virResctrlGetCacheControlType; -virResctrlGetCacheInfo; +virResctrlGetInfo; +virResctrlInfoGetCache; =20 =20 # util/virrotatingfile.h diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c index 2a11825a52dc..6c6692e78f42 100644 --- a/src/util/virresctrl.c +++ b/src/util/virresctrl.c @@ -18,6 +18,11 @@ =20 #include =20 +#include +#include +#include +#include + #include "virresctrl.h" =20 #include "c-ctype.h" @@ -25,12 +30,16 @@ #include "viralloc.h" #include "virfile.h" #include "virlog.h" +#include "virobject.h" #include "virstring.h" =20 + #define VIR_FROM_THIS VIR_FROM_RESCTRL =20 VIR_LOG_INIT("util.virresctrl") =20 + +/* Common definitions */ #define SYSFS_RESCTRL_PATH "/sys/fs/resctrl" =20 /* Resctrl is short for Resource Control. It might be implemented for var= ious @@ -55,133 +64,257 @@ VIR_ENUM_IMPL(virResctrl, VIR_CACHE_TYPE_LAST, "CODE", "DATA") =20 -int -virResctrlGetCacheInfo(unsigned int level, - unsigned long long size, - virCacheType scope, - virResctrlInfoPtr **controls, - size_t *ncontrols) -{ - int ret =3D -1; - char *tmp =3D NULL; - char *path =3D NULL; - char *cbm_mask =3D NULL; - char *type_upper =3D NULL; - unsigned int bits =3D 0; - unsigned int min_cbm_bits =3D 0; - virResctrlInfoPtr control; - - if (VIR_ALLOC(control) < 0) - goto cleanup; =20 - if (scope !=3D VIR_CACHE_TYPE_BOTH && - virStringToUpper(&type_upper, virCacheTypeToString(scope)) < 0) - goto cleanup; +/* Info-related definitions and InfoClass-related functions */ +typedef struct _virResctrlInfoPerType virResctrlInfoPerType; +typedef virResctrlInfoPerType *virResctrlInfoPerTypePtr; +struct _virResctrlInfoPerType { + /* Kernel-provided information */ + char *cbm_mask; + unsigned int min_cbm_bits; =20 - if (virFileReadValueUint(&control->max_allocation, - SYSFS_RESCTRL_PATH "/info/L%u%s/num_closids", - level, - type_upper ? type_upper : "") < 0) - goto cleanup; + /* Our computed information from the above */ + unsigned int bits; + unsigned int max_cache_id; =20 - if (virFileReadValueString(&cbm_mask, - SYSFS_RESCTRL_PATH - "/info/L%u%s/cbm_mask", - level, - type_upper ? type_upper: "") < 0) - goto cleanup; + /* In order to be self-sufficient we need size information per cache. + * Funnily enough, one of the outcomes of the resctrlfs design is that= it + * does not account for different sizes per cache on the same level. = So + * for the sake of easiness, let's copy that, for now. */ + unsigned long long size; =20 - if (virFileReadValueUint(&min_cbm_bits, - SYSFS_RESCTRL_PATH "/info/L%u%s/min_cbm_bits", - level, - type_upper ? type_upper : "") < 0) - goto cleanup; + /* Information that we will return upon request (this is public struct= ) as + * until now all the above is internal to this module */ + virResctrlInfoPerCache control; +}; =20 - virStringTrimOptionalNewline(cbm_mask); +typedef struct _virResctrlInfoPerLevel virResctrlInfoPerLevel; +typedef virResctrlInfoPerLevel *virResctrlInfoPerLevelPtr; +struct _virResctrlInfoPerLevel { + virResctrlInfoPerTypePtr *types; +}; =20 - for (tmp =3D cbm_mask; *tmp !=3D '\0'; tmp++) { - if (c_isxdigit(*tmp)) - bits +=3D count_one_bits(virHexToBin(*tmp)); - } +struct _virResctrlInfo { + virObject parent; =20 - control->granularity =3D size / bits; - if (min_cbm_bits !=3D 1) - control->min =3D min_cbm_bits * control->granularity; + virResctrlInfoPerLevelPtr *levels; + size_t nlevels; +}; =20 - control->scope =3D scope; +static virClassPtr virResctrlInfoClass; =20 - if (VIR_APPEND_ELEMENT(*controls, *ncontrols, control) < 0) - goto cleanup; +static void +virResctrlInfoDispose(void *obj) +{ + size_t i =3D 0; + size_t j =3D 0; =20 - ret =3D 0; + virResctrlInfoPtr resctrl =3D obj; =20 - cleanup: - VIR_FREE(path); - VIR_FREE(cbm_mask); - VIR_FREE(type_upper); - VIR_FREE(control); - return ret; -} + for (i =3D 0; i < resctrl->nlevels; i++) { + virResctrlInfoPerLevelPtr level =3D resctrl->levels[--resctrl->nle= vels]; + + if (!level) + continue; =20 + if (level->types) { + for (j =3D 0; j < VIR_CACHE_TYPE_LAST; j++) + VIR_FREE(level->types[j]); + } + VIR_FREE(level->types); + VIR_FREE(level); + } + + VIR_FREE(resctrl->levels); +} =20 -static inline int -virResctrlGetCacheDir(char **path, - const char *prefix, - unsigned int level, - virCacheType type) +static int virResctrlInfoOnceInit(void) { - return virAsprintf(path, - SYSFS_RESCTRL_PATH "%s/L%u%s", - prefix ? prefix : "", - level, - virResctrlTypeToString(type)); + if (!(virResctrlInfoClass =3D virClassNew(virClassForObject(), + "virResctrlInfo", + sizeof(virResctrlInfo), + virResctrlInfoDispose))) + return -1; + + return 0; } =20 +VIR_ONCE_GLOBAL_INIT(virResctrlInfo) =20 -/* - * This function tests whether TYPE of cache control is supported or not. - * - * Returns 0 if not, 1 if yes and negative value on error. - */ -static int -virResctrlGetCacheSupport(unsigned int level, virCacheType type) +static virResctrlInfoPtr +virResctrlInfoNew(void) { - int ret =3D -1; - char *path =3D NULL; - - if (virResctrlGetCacheDir(&path, "/info", level, type) < 0) - return -1; + if (virResctrlInfoInitialize() < 0) + return NULL; =20 - ret =3D virFileExists(path); - VIR_FREE(path); - return ret; + return virObjectNew(virResctrlInfoClass); } =20 =20 -/* - * This function tests which TYPE of cache control is supported - * Return values are: - * -1: error - * 0: none - * 1: CAT - * 2: CDP - */ +/* Info-related functions */ int -virResctrlGetCacheControlType(unsigned int level) +virResctrlGetInfo(virResctrlInfoPtr *resctrl) { + DIR *dirp =3D NULL; + char *info_path =3D NULL; + char *endptr =3D NULL; + char *tmp_str =3D NULL; + int ret =3D 0; int rv =3D -1; - - rv =3D virResctrlGetCacheSupport(level, VIR_CACHE_TYPE_BOTH); - if (rv < 0) + int type =3D 0; + struct dirent *ent =3D NULL; + unsigned int level =3D 0; + virResctrlInfoPerLevelPtr i_level =3D NULL; + virResctrlInfoPerTypePtr i_type =3D NULL; + virResctrlInfoPtr tmp_info =3D virResctrlInfoNew(); + + if (!tmp_info) return -1; - if (rv) - return 1; =20 - rv =3D virResctrlGetCacheSupport(level, VIR_CACHE_TYPE_CODE); - if (rv < 0) - return -1; - if (rv) - return 2; + rv =3D virDirOpenIfExists(&dirp, SYSFS_RESCTRL_PATH "/info"); + if (rv <=3D 0) { + ret =3D rv; + goto cleanup; + } =20 - return 0; + while ((rv =3D virDirRead(dirp, &ent, SYSFS_RESCTRL_PATH "/info")) > 0= ) { + if (ent->d_type !=3D DT_DIR) + continue; + + if (ent->d_name[0] !=3D 'L') + continue; + + if (virStrToLong_uip(ent->d_name + 1, &endptr, 10, &level) < 0) + goto cleanup; + + type =3D virResctrlTypeFromString(endptr); + if (type < 0) + goto cleanup; + + if (VIR_ALLOC(i_type) < 0) + goto cleanup; + + i_type->control.scope =3D type; + + if (virFileReadValueUint(&i_type->control.max_allocation, + SYSFS_RESCTRL_PATH "/info/%s/num_closids", + ent->d_name) < 0) + goto cleanup; + + if (virFileReadValueString(&i_type->cbm_mask, + SYSFS_RESCTRL_PATH + "/info/%s/cbm_mask", + ent->d_name) < 0) + goto cleanup; + + if (virFileReadValueUint(&i_type->min_cbm_bits, + SYSFS_RESCTRL_PATH "/info/%s/min_cbm_bits= ", + ent->d_name) < 0) + goto cleanup; + + virStringTrimOptionalNewline(i_type->cbm_mask); + + if (tmp_info->nlevels <=3D level && + VIR_EXPAND_N(tmp_info->levels, tmp_info->nlevels, + level - tmp_info->nlevels + 1) < 0) + goto cleanup; + + if (!tmp_info->levels[level] && + (VIR_ALLOC(tmp_info->levels[level]) < 0 || + VIR_ALLOC_N(tmp_info->levels[level]->types, VIR_CACHE_TYPE_LA= ST) < 0)) + goto cleanup; + i_level =3D tmp_info->levels[level]; + + if (i_level->types[type]) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Duplicate cache type in resctrlfs for level = %u"), + level); + goto cleanup; + } + + if (VIR_ALLOC(i_level->types[type]) < 0) + goto cleanup; + + for (tmp_str =3D i_type->cbm_mask; *tmp_str !=3D '\0'; tmp_str++) { + if (!c_isxdigit(*tmp_str)) + goto cleanup; + + i_type->bits +=3D count_one_bits(virHexToBin(*tmp_str)); + } + + i_level->types[type] =3D i_type; + i_type =3D NULL; + } + + *resctrl =3D tmp_info; + tmp_info =3D NULL; + cleanup: + VIR_DIR_CLOSE(dirp); + VIR_FREE(info_path); + virObjectUnref(tmp_info); + VIR_FREE(i_type); + return ret; +} + +int +virResctrlInfoGetCache(virResctrlInfoPtr resctrl, + unsigned int level, + unsigned long long size, + size_t *ncontrols, + virResctrlInfoPerCachePtr **controls) +{ + virResctrlInfoPerLevelPtr i_level =3D NULL; + virResctrlInfoPerTypePtr i_type =3D NULL; + size_t i =3D 0; + int ret =3D -1; + + if (!resctrl) + return 0; + + if (level >=3D resctrl->nlevels) + return 0; + + i_level =3D resctrl->levels[level]; + if (!i_level) + return 0; + + for (i =3D 0; i < VIR_CACHE_TYPE_LAST; i++) { + i_type =3D i_level->types[i]; + if (!i_type) + continue; + + /* Let's take the opportunity to update our internal information a= bout + * the cache size */ + if (!i_type->size) { + i_type->size =3D size; + i_type->control.granularity =3D size / i_type->bits; + if (i_type->min_cbm_bits !=3D 1) + i_type->control.min =3D i_type->min_cbm_bits * i_type->con= trol.granularity; + } else { + if (i_type->size !=3D size) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Forbidden inconsistency for resctrlfs, " + "level %u caches have different sizes"), + level); + goto error; + } + i_type->max_cache_id++; + } + + if (VIR_EXPAND_N(*controls, *ncontrols, 1) < 0) + goto error; + if (VIR_ALLOC((*controls)[*ncontrols - 1]) < 0) + goto error; + + memcpy((*controls)[*ncontrols - 1], &i_type->control, sizeof(i_typ= e->control)); + } + + ret =3D 0; + cleanup: + return ret; + error: + while (*ncontrols) + VIR_FREE((*controls)[--*ncontrols]); + VIR_FREE(*controls); + goto cleanup; } diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h index 848b13e98aa3..c4df88f23c3a 100644 --- a/src/util/virresctrl.h +++ b/src/util/virresctrl.h @@ -36,28 +36,30 @@ typedef enum { VIR_ENUM_DECL(virCache); =20 =20 -typedef struct _virResctrlInfo virResctrlInfo; -typedef virResctrlInfo *virResctrlInfoPtr; -struct _virResctrlInfo { +typedef struct _virResctrlInfoPerCache virResctrlInfoPerCache; +typedef virResctrlInfoPerCache *virResctrlInfoPerCachePtr; +struct _virResctrlInfoPerCache { /* Smallest possible increase of the allocation size in bytes */ unsigned long long granularity; /* Minimal allocatable size in bytes (if different from granularity) */ unsigned long long min; - /* Type of the allocation */ - virCacheType scope; /* Maximum number of simultaneous allocations */ unsigned int max_allocation; + /* Type of the allocation */ + virCacheType scope; }; =20 +typedef struct _virResctrlInfo virResctrlInfo; +typedef virResctrlInfo *virResctrlInfoPtr; =20 int -virResctrlGetCacheInfo(unsigned int level, - unsigned long long size, - virCacheType scope, - virResctrlInfoPtr **controls, - size_t *ncontrols); +virResctrlGetInfo(virResctrlInfoPtr *resctrl); =20 int -virResctrlGetCacheControlType(unsigned int level); +virResctrlInfoGetCache(virResctrlInfoPtr resctrl, + unsigned int level, + unsigned long long size, + size_t *ncontrols, + virResctrlInfoPerCachePtr **controls); =20 #endif /* __VIR_RESCTRL_H__ */ --=20 2.15.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list