mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 22:25:25 +00:00
virNodeGetCPUStats: Implement linux support
Signed-off-by: Minoru Usui <usui@mxm.nes.nec.co.jp>
This commit is contained in:
parent
7e6cb82d1c
commit
ce76e85350
@ -733,6 +733,7 @@ virNodeDeviceObjUnlock;
|
|||||||
|
|
||||||
# nodeinfo.h
|
# nodeinfo.h
|
||||||
nodeCapsInitNUMA;
|
nodeCapsInitNUMA;
|
||||||
|
nodeGetCPUStats;
|
||||||
nodeGetCellsFreeMemory;
|
nodeGetCellsFreeMemory;
|
||||||
nodeGetFreeMemory;
|
nodeGetFreeMemory;
|
||||||
nodeGetInfo;
|
nodeGetInfo;
|
||||||
|
@ -2885,6 +2885,7 @@ static virDriver lxcDriver = {
|
|||||||
.domainSetSchedulerParameters = lxcSetSchedulerParameters, /* 0.5.0 */
|
.domainSetSchedulerParameters = lxcSetSchedulerParameters, /* 0.5.0 */
|
||||||
.domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
|
.domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
|
||||||
.domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
|
.domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
|
||||||
|
.nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
|
||||||
.nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.6.5 */
|
.nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.6.5 */
|
||||||
.nodeGetFreeMemory = nodeGetFreeMemory, /* 0.6.5 */
|
.nodeGetFreeMemory = nodeGetFreeMemory, /* 0.6.5 */
|
||||||
.domainEventRegister = lxcDomainEventRegister, /* 0.7.0 */
|
.domainEventRegister = lxcDomainEventRegister, /* 0.7.0 */
|
||||||
|
138
src/nodeinfo.c
138
src/nodeinfo.c
@ -57,12 +57,20 @@
|
|||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
# define CPUINFO_PATH "/proc/cpuinfo"
|
# define CPUINFO_PATH "/proc/cpuinfo"
|
||||||
# define CPU_SYS_PATH "/sys/devices/system/cpu"
|
# define CPU_SYS_PATH "/sys/devices/system/cpu"
|
||||||
|
# define PROCSTAT_PATH "/proc/stat"
|
||||||
|
|
||||||
|
# define LINUX_NB_CPU_STATS 4
|
||||||
|
|
||||||
/* NB, this is not static as we need to call it from the testsuite */
|
/* NB, this is not static as we need to call it from the testsuite */
|
||||||
int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
|
int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
|
||||||
virNodeInfoPtr nodeinfo,
|
virNodeInfoPtr nodeinfo,
|
||||||
bool need_hyperthreads);
|
bool need_hyperthreads);
|
||||||
|
|
||||||
|
static int linuxNodeGetCPUStats(FILE *procstat,
|
||||||
|
int cpuNum,
|
||||||
|
virCPUStatsPtr params,
|
||||||
|
int *nparams);
|
||||||
|
|
||||||
/* Return the positive decimal contents of the given
|
/* Return the positive decimal contents of the given
|
||||||
* CPU_SYS_PATH/cpu%u/FILE, or -1 on error. If MISSING_OK and the
|
* CPU_SYS_PATH/cpu%u/FILE, or -1 on error. If MISSING_OK and the
|
||||||
* file could not be found, return 1 instead of an error; this is
|
* file could not be found, return 1 instead of an error; this is
|
||||||
@ -376,6 +384,107 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK))
|
||||||
|
|
||||||
|
int linuxNodeGetCPUStats(FILE *procstat,
|
||||||
|
int cpuNum,
|
||||||
|
virCPUStatsPtr params,
|
||||||
|
int *nparams)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char line[1024];
|
||||||
|
unsigned long long usr, ni, sys, idle, iowait;
|
||||||
|
unsigned long long irq, softirq, steal, guest, guest_nice;
|
||||||
|
char cpu_header[3 + INT_BUFSIZE_BOUND(cpuNum)];
|
||||||
|
|
||||||
|
if ((*nparams) == 0) {
|
||||||
|
/* Current number of cpu stats supported by linux */
|
||||||
|
*nparams = LINUX_NB_CPU_STATS;
|
||||||
|
ret = 0;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*nparams) != LINUX_NB_CPU_STATS) {
|
||||||
|
nodeReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
"%s", _("Invalid parameter count"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpuNum == VIR_CPU_STATS_ALL_CPUS) {
|
||||||
|
strcpy(cpu_header, "cpu");
|
||||||
|
} else {
|
||||||
|
snprintf(cpu_header, sizeof(cpu_header), "cpu%d", cpuNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), procstat) != NULL) {
|
||||||
|
char *buf = line;
|
||||||
|
|
||||||
|
if (STRPREFIX(buf, cpu_header)) { /* aka logical CPU time */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (sscanf(buf,
|
||||||
|
"%*s %llu %llu %llu %llu %llu" // user ~ iowait
|
||||||
|
"%llu %llu %llu %llu %llu", // irq ~ guest_nice
|
||||||
|
&usr, &ni, &sys, &idle, &iowait,
|
||||||
|
&irq, &softirq, &steal, &guest, &guest_nice) < 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < *nparams; i++) {
|
||||||
|
virCPUStatsPtr param = ¶ms[i];
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case 0: /* fill kernel cpu time here */
|
||||||
|
if (virStrcpyStatic(param->field, VIR_CPU_STATS_KERNEL) == NULL) {
|
||||||
|
nodeReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("Field kernel cpu time too long for destination"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
param->value = (sys + irq + softirq) * TICK_TO_NSEC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* fill user cpu time here */
|
||||||
|
if (virStrcpyStatic(param->field, VIR_CPU_STATS_USER) == NULL) {
|
||||||
|
nodeReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("Field kernel cpu time too long for destination"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
param->value = (usr + ni) * TICK_TO_NSEC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* fill idle cpu time here */
|
||||||
|
if (virStrcpyStatic(param->field, VIR_CPU_STATS_IDLE) == NULL) {
|
||||||
|
nodeReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("Field kernel cpu time too long for destination"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
param->value = idle * TICK_TO_NSEC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: /* fill iowait cpu time here */
|
||||||
|
if (virStrcpyStatic(param->field, VIR_CPU_STATS_IOWAIT) == NULL) {
|
||||||
|
nodeReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("Field kernel cpu time too long for destination"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
param->value = iowait * TICK_TO_NSEC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
/* should not hit here */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid cpu number"));
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
|
int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
|
||||||
@ -414,6 +523,35 @@ int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
int cpuNum,
|
||||||
|
virCPUStatsPtr params,
|
||||||
|
int *nparams,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
virCheckFlags(0, -1);
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
FILE *procstat = fopen(PROCSTAT_PATH, "r");
|
||||||
|
if (!procstat) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("cannot open %s"), PROCSTAT_PATH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = linuxNodeGetCPUStats(procstat, cpuNum, params, nparams);
|
||||||
|
VIR_FORCE_FCLOSE(procstat);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
nodeReportError(VIR_ERR_NO_SUPPORT, "%s",
|
||||||
|
_("node CPU stats not implemented on this platform"));
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if HAVE_NUMACTL
|
#if HAVE_NUMACTL
|
||||||
# if LIBNUMA_API_VERSION <= 1
|
# if LIBNUMA_API_VERSION <= 1
|
||||||
# define NUMA_MAX_N_CPUS 4096
|
# define NUMA_MAX_N_CPUS 4096
|
||||||
|
@ -30,7 +30,11 @@
|
|||||||
int nodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo);
|
int nodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo);
|
||||||
int nodeCapsInitNUMA(virCapsPtr caps);
|
int nodeCapsInitNUMA(virCapsPtr caps);
|
||||||
|
|
||||||
|
int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
int cpuNum,
|
||||||
|
virCPUStatsPtr params,
|
||||||
|
int *nparams,
|
||||||
|
unsigned int flags ATTRIBUTE_UNUSED);
|
||||||
int nodeGetCellsFreeMemory(virConnectPtr conn,
|
int nodeGetCellsFreeMemory(virConnectPtr conn,
|
||||||
unsigned long long *freeMems,
|
unsigned long long *freeMems,
|
||||||
int startCell,
|
int startCell,
|
||||||
|
@ -8092,6 +8092,7 @@ static virDriver qemuDriver = {
|
|||||||
.domainBlockPeek = qemudDomainBlockPeek, /* 0.4.4 */
|
.domainBlockPeek = qemudDomainBlockPeek, /* 0.4.4 */
|
||||||
.domainMemoryPeek = qemudDomainMemoryPeek, /* 0.4.4 */
|
.domainMemoryPeek = qemudDomainMemoryPeek, /* 0.4.4 */
|
||||||
.domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
|
.domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
|
||||||
|
.nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
|
||||||
.nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.4.4 */
|
.nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.4.4 */
|
||||||
.nodeGetFreeMemory = nodeGetFreeMemory, /* 0.4.4 */
|
.nodeGetFreeMemory = nodeGetFreeMemory, /* 0.4.4 */
|
||||||
.domainEventRegister = qemuDomainEventRegister, /* 0.5.0 */
|
.domainEventRegister = qemuDomainEventRegister, /* 0.5.0 */
|
||||||
|
@ -2218,6 +2218,7 @@ static virDriver umlDriver = {
|
|||||||
.domainGetAutostart = umlDomainGetAutostart, /* 0.5.0 */
|
.domainGetAutostart = umlDomainGetAutostart, /* 0.5.0 */
|
||||||
.domainSetAutostart = umlDomainSetAutostart, /* 0.5.0 */
|
.domainSetAutostart = umlDomainSetAutostart, /* 0.5.0 */
|
||||||
.domainBlockPeek = umlDomainBlockPeek, /* 0.5.0 */
|
.domainBlockPeek = umlDomainBlockPeek, /* 0.5.0 */
|
||||||
|
.nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
|
||||||
.nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.5.0 */
|
.nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.5.0 */
|
||||||
.nodeGetFreeMemory = nodeGetFreeMemory, /* 0.5.0 */
|
.nodeGetFreeMemory = nodeGetFreeMemory, /* 0.5.0 */
|
||||||
.isEncrypted = umlIsEncrypted, /* 0.7.3 */
|
.isEncrypted = umlIsEncrypted, /* 0.7.3 */
|
||||||
|
Loading…
Reference in New Issue
Block a user