mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
Implements domainMemStats in the qemu driver
Support for memory statistics reporting is accepted for qemu inclusion. Statistics are reported via the monitor command 'info balloon' as a comma seprated list: (qemu) info balloon balloon: actual=1024,mem_swapped_in=0,mem_swapped_out=0,major_page_faults=88,minor_page_faults=105535,free_mem=1017065472,total_mem=1045229568 Libvirt, qemu, and the guest operating system may support a subset of the statistics defined by the virtio spec. Thus, only statistics recognized by components will be reported. * src/qemu/qemu_driver.c src/qemu/qemu_monitor_text.[ch]: implement the new entry point by using info balloon monitor command
This commit is contained in:
parent
4fe975fe4e
commit
c7523b410a
@ -6235,6 +6235,43 @@ qemudDomainInterfaceStats (virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemudDomainMemoryStats (virDomainPtr dom,
|
||||||
|
struct _virDomainMemoryStat *stats,
|
||||||
|
unsigned int nr_stats)
|
||||||
|
{
|
||||||
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
|
virDomainObjPtr vm;
|
||||||
|
unsigned int ret = -1;
|
||||||
|
|
||||||
|
qemuDriverLock(driver);
|
||||||
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
||||||
|
qemuDriverUnlock(driver);
|
||||||
|
|
||||||
|
if (!vm) {
|
||||||
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||||
|
virUUIDFormat(dom->uuid, uuidstr);
|
||||||
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
|
||||||
|
_("no domain with matching uuid '%s'"), uuidstr);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virDomainObjIsActive(vm)) {
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
qemuDomainObjEnterMonitor(vm);
|
||||||
|
ret = qemuMonitorTextGetMemoryStats(priv->mon, stats, nr_stats);
|
||||||
|
qemuDomainObjExitMonitor(vm);
|
||||||
|
} else {
|
||||||
|
qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
|
||||||
|
"%s", _("domain is not running"));
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (vm)
|
||||||
|
virDomainObjUnlock(vm);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemudDomainBlockPeek (virDomainPtr dom,
|
qemudDomainBlockPeek (virDomainPtr dom,
|
||||||
const char *path,
|
const char *path,
|
||||||
@ -7930,7 +7967,7 @@ static virDriver qemuDriver = {
|
|||||||
NULL, /* domainMigrateFinish */
|
NULL, /* domainMigrateFinish */
|
||||||
qemudDomainBlockStats, /* domainBlockStats */
|
qemudDomainBlockStats, /* domainBlockStats */
|
||||||
qemudDomainInterfaceStats, /* domainInterfaceStats */
|
qemudDomainInterfaceStats, /* domainInterfaceStats */
|
||||||
NULL, /* domainMemoryStats */
|
qemudDomainMemoryStats, /* domainMemoryStats */
|
||||||
qemudDomainBlockPeek, /* domainBlockPeek */
|
qemudDomainBlockPeek, /* domainBlockPeek */
|
||||||
qemudDomainMemoryPeek, /* domainMemoryPeek */
|
qemudDomainMemoryPeek, /* domainMemoryPeek */
|
||||||
nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
|
nodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
|
||||||
|
@ -454,6 +454,65 @@ error:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parseMemoryStat(char **text, unsigned int tag,
|
||||||
|
const char *search, virDomainMemoryStatPtr stat)
|
||||||
|
{
|
||||||
|
char *dummy;
|
||||||
|
unsigned long long value;
|
||||||
|
|
||||||
|
if (STRPREFIX (*text, search)) {
|
||||||
|
*text += strlen(search);
|
||||||
|
if (virStrToLong_ull (*text, &dummy, 10, &value)) {
|
||||||
|
DEBUG ("error reading %s: %s", search, *text);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert bytes to kilobytes for libvirt */
|
||||||
|
switch (tag) {
|
||||||
|
case VIR_DOMAIN_MEMORY_STAT_SWAP_IN:
|
||||||
|
case VIR_DOMAIN_MEMORY_STAT_SWAP_OUT:
|
||||||
|
case VIR_DOMAIN_MEMORY_STAT_UNUSED:
|
||||||
|
case VIR_DOMAIN_MEMORY_STAT_AVAILABLE:
|
||||||
|
value = value >> 10;
|
||||||
|
}
|
||||||
|
stat->tag = tag;
|
||||||
|
stat->val = value;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The reply from the 'info balloon' command may contain additional memory
|
||||||
|
* statistics in the form: '[,<tag>=<val>]*'
|
||||||
|
*/
|
||||||
|
static int qemuMonitorParseExtraBalloonInfo(char *text,
|
||||||
|
virDomainMemoryStatPtr stats,
|
||||||
|
unsigned int nr_stats)
|
||||||
|
{
|
||||||
|
char *p = text;
|
||||||
|
unsigned int nr_stats_found = 0;
|
||||||
|
|
||||||
|
while (*p && nr_stats_found < nr_stats) {
|
||||||
|
if (parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_SWAP_IN,
|
||||||
|
",mem_swapped_in=", &stats[nr_stats_found]) ||
|
||||||
|
parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_SWAP_OUT,
|
||||||
|
",mem_swapped_out=", &stats[nr_stats_found]) ||
|
||||||
|
parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT,
|
||||||
|
",major_page_faults=", &stats[nr_stats_found]) ||
|
||||||
|
parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT,
|
||||||
|
",minor_page_faults=", &stats[nr_stats_found]) ||
|
||||||
|
parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_UNUSED,
|
||||||
|
",free_mem=", &stats[nr_stats_found]) ||
|
||||||
|
parseMemoryStat(&p, VIR_DOMAIN_MEMORY_STAT_AVAILABLE,
|
||||||
|
",total_mem=", &stats[nr_stats_found]))
|
||||||
|
nr_stats_found++;
|
||||||
|
|
||||||
|
/* Skip to the next label */
|
||||||
|
p = strchr (p, ',');
|
||||||
|
if (!p) break;
|
||||||
|
}
|
||||||
|
return nr_stats_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The reply from QEMU contains 'ballon: actual=421' where value is in MB */
|
/* The reply from QEMU contains 'ballon: actual=421' where value is in MB */
|
||||||
@ -499,6 +558,30 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
|
||||||
|
virDomainMemoryStatPtr stats,
|
||||||
|
unsigned int nr_stats)
|
||||||
|
{
|
||||||
|
char *reply = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
char *offset;
|
||||||
|
|
||||||
|
if (qemuMonitorCommand(mon, "info balloon", &reply) < 0) {
|
||||||
|
qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
||||||
|
"%s", _("could not query memory balloon statistics"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset = strstr(reply, BALLOON_PREFIX)) != NULL) {
|
||||||
|
if ((offset = strchr(reply, ',')) != NULL) {
|
||||||
|
ret = qemuMonitorParseExtraBalloonInfo(offset, stats, nr_stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_FREE(reply);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
|
int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
|
||||||
const char *devname,
|
const char *devname,
|
||||||
|
@ -45,6 +45,9 @@ int qemuMonitorTextGetCPUInfo(qemuMonitorPtr mon,
|
|||||||
int **pids);
|
int **pids);
|
||||||
int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
|
int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
|
||||||
unsigned long *currmem);
|
unsigned long *currmem);
|
||||||
|
int qemuMonitorTextGetMemoryStats(qemuMonitorPtr mon,
|
||||||
|
virDomainMemoryStatPtr stats,
|
||||||
|
unsigned int nr_stats);
|
||||||
int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
|
int qemuMonitorTextGetBlockStatsInfo(qemuMonitorPtr mon,
|
||||||
const char *devname,
|
const char *devname,
|
||||||
long long *rd_req,
|
long long *rd_req,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user