mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
resctrl: Use cache IDs instead of max_id/max_cache_id
It is not guaranteed for the cache IDs to be continuous, especially for L3 caches. Hence do not assume so and instead record the individual IDs in a virBitmap. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
f3fd0664cf
commit
bfad111c43
@ -2128,7 +2128,9 @@ virCapabilitiesInitResctrlMemory(virCaps *caps)
|
|||||||
node = g_new0(virCapsHostMemBWNode, 1);
|
node = g_new0(virCapsHostMemBWNode, 1);
|
||||||
|
|
||||||
if (virResctrlInfoGetMemoryBandwidth(caps->host.resctrl,
|
if (virResctrlInfoGetMemoryBandwidth(caps->host.resctrl,
|
||||||
bank->level, &node->control) > 0) {
|
bank->level,
|
||||||
|
bank->id,
|
||||||
|
&node->control) > 0) {
|
||||||
node->id = bank->id;
|
node->id = bank->id;
|
||||||
node->cpus = virBitmapNewCopy(bank->cpus);
|
node->cpus = virBitmapNewCopy(bank->cpus);
|
||||||
|
|
||||||
@ -2269,6 +2271,7 @@ virCapabilitiesInitCaches(virCaps *caps)
|
|||||||
if (i == caps->host.cache.nbanks) {
|
if (i == caps->host.cache.nbanks) {
|
||||||
/* If it is a new cache, then update its resctrl information. */
|
/* If it is a new cache, then update its resctrl information. */
|
||||||
if (virResctrlInfoGetCache(caps->host.resctrl,
|
if (virResctrlInfoGetCache(caps->host.resctrl,
|
||||||
|
bank->id,
|
||||||
bank->level,
|
bank->level,
|
||||||
bank->size,
|
bank->size,
|
||||||
&bank->ncontrols,
|
&bank->ncontrols,
|
||||||
|
@ -121,6 +121,8 @@ struct _virResctrlInfoPerType {
|
|||||||
unsigned int bits;
|
unsigned int bits;
|
||||||
unsigned int max_cache_id;
|
unsigned int max_cache_id;
|
||||||
|
|
||||||
|
virBitmap *cache_ids;
|
||||||
|
|
||||||
/* In order to be self-sufficient we need size information per cache.
|
/* In order to be self-sufficient we need size information per cache.
|
||||||
* Funnily enough, one of the outcomes of the resctrl design is that it
|
* Funnily enough, one of the outcomes of the resctrl design is that it
|
||||||
* does not account for different sizes per cache on the same level. So
|
* does not account for different sizes per cache on the same level. So
|
||||||
@ -146,11 +148,8 @@ struct _virResctrlInfoMemBW {
|
|||||||
unsigned int max_allocation;
|
unsigned int max_allocation;
|
||||||
/* level number of last level cache */
|
/* level number of last level cache */
|
||||||
unsigned int last_level_cache;
|
unsigned int last_level_cache;
|
||||||
/* max id of last level cache, this is used to track
|
|
||||||
* how many last level cache available in host system,
|
virBitmap *cache_ids;
|
||||||
* the number of memory bandwidth allocation controller
|
|
||||||
* is identical with last level cache. */
|
|
||||||
unsigned int max_id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _virResctrlInfoMongrp {
|
struct _virResctrlInfoMongrp {
|
||||||
@ -192,6 +191,7 @@ virResctrlInfoMemBWFree(virResctrlInfoMemBW *ptr)
|
|||||||
if (!ptr)
|
if (!ptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
virBitmapFree(ptr->cache_ids);
|
||||||
g_free(ptr);
|
g_free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,6 +203,7 @@ virResctrlInfoPerTypeFree(virResctrlInfoPerType *ptr)
|
|||||||
if (!ptr)
|
if (!ptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
virBitmapFree(ptr->cache_ids);
|
||||||
g_free(ptr);
|
g_free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,6 +849,7 @@ virResctrlInfoIsEmpty(virResctrlInfo *resctrl)
|
|||||||
int
|
int
|
||||||
virResctrlInfoGetMemoryBandwidth(virResctrlInfo *resctrl,
|
virResctrlInfoGetMemoryBandwidth(virResctrlInfo *resctrl,
|
||||||
unsigned int level,
|
unsigned int level,
|
||||||
|
unsigned int id,
|
||||||
virResctrlInfoMemBWPerNode *control)
|
virResctrlInfoMemBWPerNode *control)
|
||||||
{
|
{
|
||||||
virResctrlInfoMemBW *membw_info = resctrl->membw_info;
|
virResctrlInfoMemBW *membw_info = resctrl->membw_info;
|
||||||
@ -858,6 +860,13 @@ virResctrlInfoGetMemoryBandwidth(virResctrlInfo *resctrl,
|
|||||||
if (membw_info->last_level_cache != level)
|
if (membw_info->last_level_cache != level)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* This "should not happen", but resctrl code is constantly full of
|
||||||
|
* surprises. Warning might make us aware in the future. */
|
||||||
|
if (!virBitmapIsBitSet(membw_info->cache_ids, id)) {
|
||||||
|
VIR_WARN("Memory bandwidth for cache id %u is not recorded in list of cache IDs",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
control->granularity = membw_info->bandwidth_granularity;
|
control->granularity = membw_info->bandwidth_granularity;
|
||||||
control->min = membw_info->min_bandwidth;
|
control->min = membw_info->min_bandwidth;
|
||||||
control->max_allocation = membw_info->max_allocation;
|
control->max_allocation = membw_info->max_allocation;
|
||||||
@ -867,6 +876,7 @@ virResctrlInfoGetMemoryBandwidth(virResctrlInfo *resctrl,
|
|||||||
|
|
||||||
int
|
int
|
||||||
virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
||||||
|
unsigned int id,
|
||||||
unsigned int level,
|
unsigned int level,
|
||||||
unsigned long long size,
|
unsigned long long size,
|
||||||
size_t *ncontrols,
|
size_t *ncontrols,
|
||||||
@ -885,12 +895,15 @@ virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
|||||||
if (resctrl->membw_info) {
|
if (resctrl->membw_info) {
|
||||||
virResctrlInfoMemBW *membw_info = resctrl->membw_info;
|
virResctrlInfoMemBW *membw_info = resctrl->membw_info;
|
||||||
|
|
||||||
|
if (!membw_info->cache_ids)
|
||||||
|
membw_info->cache_ids = virBitmapNew(0);
|
||||||
|
|
||||||
if (level > membw_info->last_level_cache) {
|
if (level > membw_info->last_level_cache) {
|
||||||
membw_info->last_level_cache = level;
|
membw_info->last_level_cache = level;
|
||||||
membw_info->max_id = 0;
|
virBitmapShrink(membw_info->cache_ids, 0);
|
||||||
} else if (membw_info->last_level_cache == level) {
|
|
||||||
membw_info->max_id++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virBitmapSetBitExpand(membw_info->cache_ids, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level >= resctrl->nlevels)
|
if (level >= resctrl->nlevels)
|
||||||
@ -905,6 +918,11 @@ virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
|||||||
if (!i_type)
|
if (!i_type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!i_type->cache_ids)
|
||||||
|
i_type->cache_ids = virBitmapNew(id);
|
||||||
|
|
||||||
|
virBitmapSetBitExpand(i_type->cache_ids, id);
|
||||||
|
|
||||||
/* Let's take the opportunity to update our internal information about
|
/* Let's take the opportunity to update our internal information about
|
||||||
* the cache size */
|
* the cache size */
|
||||||
if (!i_type->size) {
|
if (!i_type->size) {
|
||||||
@ -919,7 +937,6 @@ virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
|||||||
level, i_type->size, size);
|
level, i_type->size, size);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
i_type->max_cache_id++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_EXPAND_N(*controls, *ncontrols, 1);
|
VIR_EXPAND_N(*controls, *ncontrols, 1);
|
||||||
@ -1418,8 +1435,7 @@ virResctrlAllocMemoryBandwidthFormat(virResctrlAlloc *alloc,
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
virResctrlAllocParseProcessMemoryBandwidth(virResctrlInfo *resctrl,
|
virResctrlAllocParseProcessMemoryBandwidth(virResctrlAlloc *alloc,
|
||||||
virResctrlAlloc *alloc,
|
|
||||||
char *mem_bw)
|
char *mem_bw)
|
||||||
{
|
{
|
||||||
unsigned int bandwidth;
|
unsigned int bandwidth;
|
||||||
@ -1442,12 +1458,6 @@ virResctrlAllocParseProcessMemoryBandwidth(virResctrlInfo *resctrl,
|
|||||||
_("Invalid bandwidth %1$u"), bandwidth);
|
_("Invalid bandwidth %1$u"), bandwidth);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (id > resctrl->membw_info->max_id) {
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
||||||
_("Missing or inconsistent resctrl info for memory bandwidth node '%1$u'"),
|
|
||||||
id);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (alloc->mem_bw->nbandwidths <= id) {
|
if (alloc->mem_bw->nbandwidths <= id) {
|
||||||
VIR_EXPAND_N(alloc->mem_bw->bandwidths, alloc->mem_bw->nbandwidths,
|
VIR_EXPAND_N(alloc->mem_bw->bandwidths, alloc->mem_bw->nbandwidths,
|
||||||
id - alloc->mem_bw->nbandwidths + 1);
|
id - alloc->mem_bw->nbandwidths + 1);
|
||||||
@ -1495,7 +1505,7 @@ virResctrlAllocParseMemoryBandwidthLine(virResctrlInfo *resctrl,
|
|||||||
|
|
||||||
mbs = g_strsplit(tmp, ";", 0);
|
mbs = g_strsplit(tmp, ";", 0);
|
||||||
for (next = mbs; *next; next++) {
|
for (next = mbs; *next; next++) {
|
||||||
if (virResctrlAllocParseProcessMemoryBandwidth(resctrl, alloc, *next) < 0)
|
if (virResctrlAllocParseProcessMemoryBandwidth(alloc, *next) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1597,7 +1607,8 @@ virResctrlAllocParseProcessCache(virResctrlInfo *resctrl,
|
|||||||
if (!resctrl ||
|
if (!resctrl ||
|
||||||
level >= resctrl->nlevels ||
|
level >= resctrl->nlevels ||
|
||||||
!resctrl->levels[level] ||
|
!resctrl->levels[level] ||
|
||||||
!resctrl->levels[level]->types[type]) {
|
!resctrl->levels[level]->types[type] ||
|
||||||
|
!virBitmapIsBitSet(resctrl->levels[level]->types[type]->cache_ids, cache_id)) {
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
_("Missing or inconsistent resctrl info for level '%1$u' type '%2$s'"),
|
_("Missing or inconsistent resctrl info for level '%1$u' type '%2$s'"),
|
||||||
level, virCacheTypeToString(type));
|
level, virCacheTypeToString(type));
|
||||||
@ -1790,7 +1801,7 @@ virResctrlAllocNewFromInfo(virResctrlInfo *info)
|
|||||||
for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
|
for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
|
||||||
virResctrlInfoPerType *i_type = i_level->types[j];
|
virResctrlInfoPerType *i_type = i_level->types[j];
|
||||||
g_autoptr(virBitmap) mask = NULL;
|
g_autoptr(virBitmap) mask = NULL;
|
||||||
size_t k = 0;
|
ssize_t bit = -1;
|
||||||
|
|
||||||
if (!i_type)
|
if (!i_type)
|
||||||
continue;
|
continue;
|
||||||
@ -1798,8 +1809,8 @@ virResctrlAllocNewFromInfo(virResctrlInfo *info)
|
|||||||
mask = virBitmapNew(i_type->bits);
|
mask = virBitmapNew(i_type->bits);
|
||||||
virBitmapSetAll(mask);
|
virBitmapSetAll(mask);
|
||||||
|
|
||||||
for (k = 0; k <= i_type->max_cache_id; k++) {
|
while ((bit = virBitmapNextSetBit(i_type->cache_ids, bit)) >= 0) {
|
||||||
if (virResctrlAllocUpdateMask(ret, i, j, k, mask) < 0)
|
if (virResctrlAllocUpdateMask(ret, i, j, bit, mask) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1830,10 +1841,21 @@ virResctrlAllocCopyMemBW(virResctrlAlloc *dst,
|
|||||||
src_bw->nbandwidths - dst_bw->nbandwidths);
|
src_bw->nbandwidths - dst_bw->nbandwidths);
|
||||||
|
|
||||||
for (i = 0; i < src_bw->nbandwidths; i++) {
|
for (i = 0; i < src_bw->nbandwidths; i++) {
|
||||||
if (dst_bw->bandwidths[i])
|
if (!src_bw->bandwidths[i]) {
|
||||||
|
if (!dst_bw->bandwidths[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
|
_("bandwidth controller id %1$zd does not exist"),
|
||||||
|
i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dst_bw->bandwidths[i]) {
|
||||||
|
dst_bw->bandwidths[i] = g_new0(unsigned int, 1);
|
||||||
|
*dst_bw->bandwidths[i] = *src_bw->bandwidths[i];
|
||||||
continue;
|
continue;
|
||||||
dst_bw->bandwidths[i] = g_new0(unsigned int, 1);
|
}
|
||||||
*dst_bw->bandwidths[i] = *src_bw->bandwidths[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2065,12 +2087,6 @@ virResctrlAllocMemoryBandwidth(virResctrlInfo *resctrl,
|
|||||||
mem_bw_info->min_bandwidth);
|
mem_bw_info->min_bandwidth);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (i > mem_bw_info->max_id) {
|
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
||||||
_("bandwidth controller id %1$zd does not exist, max controller id %2$u"),
|
|
||||||
i, mem_bw_info->max_id);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ VIR_ENUM_DECL(virResctrlMonitorPrefix);
|
|||||||
|
|
||||||
typedef struct _virResctrlInfoPerCache virResctrlInfoPerCache;
|
typedef struct _virResctrlInfoPerCache virResctrlInfoPerCache;
|
||||||
struct _virResctrlInfoPerCache {
|
struct _virResctrlInfoPerCache {
|
||||||
|
unsigned int id;
|
||||||
/* Smallest possible increase of the allocation size in bytes */
|
/* Smallest possible increase of the allocation size in bytes */
|
||||||
unsigned long long granularity;
|
unsigned long long granularity;
|
||||||
/* Minimal allocatable size in bytes (if different from granularity) */
|
/* Minimal allocatable size in bytes (if different from granularity) */
|
||||||
@ -96,6 +97,7 @@ virResctrlInfoNew(void);
|
|||||||
|
|
||||||
int
|
int
|
||||||
virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
||||||
|
unsigned int id,
|
||||||
unsigned int level,
|
unsigned int level,
|
||||||
unsigned long long size,
|
unsigned long long size,
|
||||||
size_t *ncontrols,
|
size_t *ncontrols,
|
||||||
@ -104,6 +106,7 @@ virResctrlInfoGetCache(virResctrlInfo *resctrl,
|
|||||||
int
|
int
|
||||||
virResctrlInfoGetMemoryBandwidth(virResctrlInfo *resctrl,
|
virResctrlInfoGetMemoryBandwidth(virResctrlInfo *resctrl,
|
||||||
unsigned int level,
|
unsigned int level,
|
||||||
|
unsigned int id,
|
||||||
virResctrlInfoMemBWPerNode *control);
|
virResctrlInfoMemBWPerNode *control);
|
||||||
/* Alloc-related things */
|
/* Alloc-related things */
|
||||||
typedef struct _virResctrlAlloc virResctrlAlloc;
|
typedef struct _virResctrlAlloc virResctrlAlloc;
|
||||||
|
Loading…
Reference in New Issue
Block a user