From f7e0594f87a0cb4d8cebbf03d54a61dd3cc08d63 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 7 Aug 2006 14:35:20 +0000 Subject: [PATCH] Added vcpuinfo vcpupin commands to virsh. Fixed off by one bug in virDomainVcpuPin method --- ChangeLog | 8 ++ include/libvirt/libvirt.h | 24 +++++ src/libvirt.c | 2 +- src/virsh.c | 188 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 952c9d6f3f..1efed88a54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Fri Aug 4 20:19:23 EDT 2006 Daniel Berrange + + * src/libvirt.c: Fix off-by-one in validated VCPU number (it is + zero based, not one based). + * include/libvirt/libvirt.h: Add some convenience macros for + calculating neccessary CPU map lengths & total host CPUs + * src/virsh.c: Add 'vcpuinfo' and 'vcpumap' commands + Fri Aug 4 14:45:25 CEST 2006 Daniel Veillard * python/generator.py: fix the generator when handling long integers diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h index 2db8beba03..f846fe0351 100644 --- a/include/libvirt/libvirt.h +++ b/include/libvirt/libvirt.h @@ -167,6 +167,18 @@ struct _virNodeInfo { unsigned int threads;/* number of threads per core */ }; + +/** + * VIR_NODEINFO_MAXCPUS: + * @nodeinfo: virNodeInfo instance + * + * This macro is to calculate the total number of CPUs supported + * but not neccessarily active in the host. + */ + + +#define VIR_NODEINFO_MAXCPUS(nodeinfo) ((nodeinfo).nodes*(nodeinfo).sockets*(nodeinfo).cores*(nodeinfo).threads) + /** * virNodeInfoPtr: * @@ -339,6 +351,18 @@ int virDomainPinVcpu (virDomainPtr domain, #define VIR_UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8))) +/** + * VIR_CPU_MAPLEN + * @cpu: number of physical CPUs + * + * This macro is to be used in conjonction with virDomainPinVcpu() API. + * It returns the length (in bytes) required to store the complete + * CPU map between a single virtual & all physical CPUs of a domain. + */ + +#define VIR_CPU_MAPLEN(cpu) (((cpu)+7)/8) + + int virDomainGetVcpus (virDomainPtr domain, virVcpuInfoPtr info, int maxinfo, diff --git a/src/libvirt.c b/src/libvirt.c index 70fcf0a7bc..14294894cd 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -1720,7 +1720,7 @@ virDomainPinVcpu(virDomainPtr domain, unsigned int vcpu, } if (domain->conn->flags & VIR_CONNECT_RO) return (-1); - if ((vcpu < 1) || (cpumap == NULL) || (maplen < 1)) { + if ((vcpu < 0) || (cpumap == NULL) || (maplen < 1)) { virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); return (-1); } diff --git a/src/virsh.c b/src/virsh.c index 84a05554e3..a5f72ac0a0 100644 --- a/src/virsh.c +++ b/src/virsh.c @@ -207,6 +207,7 @@ static void vshDebug(vshControl * ctl, int level, const char *format, ...); #define vshPrint(_ctl, ...) fprintf(stdout, __VA_ARGS__) static const char *vshDomainStateToString(int state); +static const char *vshDomainVcpuStateToString(int state); static int vshConnectionUsability(vshControl * ctl, virConnectPtr conn, int showerror); @@ -793,6 +794,175 @@ cmdDominfo(vshControl * ctl, vshCmd * cmd) return ret; } +/* + * "vcpuinfo" command + */ +static vshCmdInfo info_vcpuinfo[] = { + {"syntax", "vcpuinfo "}, + {"help", "domain vcpu information"}, + {"desc", "Returns basic information about the domain virtual CPUs."}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vcpuinfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVcpuinfo(vshControl * ctl, vshCmd * cmd) +{ + virDomainInfo info; + virDomainPtr dom; + virNodeInfo nodeinfo; + virVcpuInfoPtr cpuinfo; + unsigned char *cpumap; + int ncpus; + size_t cpumaplen; + int ret = TRUE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL))) + return FALSE; + + if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) { + virDomainFree(dom); + return FALSE; + } + + if (virDomainGetInfo(dom, &info) != 0) { + virDomainFree(dom); + return FALSE; + } + + cpuinfo = malloc(sizeof(virVcpuInfo)*info.nrVirtCpu); + cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); + cpumap = malloc(info.nrVirtCpu * cpumaplen); + + if ((ncpus = virDomainGetVcpus(dom, + cpuinfo, info.nrVirtCpu, + cpumap, cpumaplen)) >= 0) { + int n; + for (n = 0 ; n < ncpus ; n++) { + unsigned int m; + vshPrint(ctl, "%-15s %d\n", "VCPU:", n); + vshPrint(ctl, "%-15s %d\n", "CPU:", cpuinfo[n].cpu); + vshPrint(ctl, "%-15s %s\n", "State:", + vshDomainVcpuStateToString(cpuinfo[n].state)); + if (cpuinfo[n].cpuTime != 0) { + double cpuUsed = cpuinfo[n].cpuTime; + + cpuUsed /= 1000000000.0; + + vshPrint(ctl, "%-15s %.1lfs\n", "CPU time:", cpuUsed); + } + vshPrint(ctl, "%-15s ", "CPU Affinity:"); + for (m = 0 ; m < VIR_NODEINFO_MAXCPUS(nodeinfo) ; m++) { + vshPrint(ctl, "%c", VIR_CPU_USABLE(cpumap, cpumaplen, n, m) ? 'y' : '-'); + } + vshPrint(ctl, "\n"); + if (n < (ncpus - 1)) { + vshPrint(ctl, "\n"); + } + } + } else { + ret = FALSE; + } + + free(cpumap); + free(cpuinfo); + virDomainFree(dom); + return ret; +} + +/* + * "vcpupin" command + */ +static vshCmdInfo info_vcpupin[] = { + {"syntax", "vcpupin "}, + {"help", "control domain vcpu affinity"}, + {"desc", "Pin domain VCPUs to host physical CPUs"}, + {NULL, NULL} +}; + +static vshCmdOptDef opts_vcpupin[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, "domain name, id or uuid"}, + {"vcpu", VSH_OT_DATA, VSH_OFLAG_REQ, "vcpu number"}, + {"cpulist", VSH_OT_DATA, VSH_OFLAG_REQ, "host cpu number(s) (comma separated)"}, + {NULL, 0, 0, NULL} +}; + +static int +cmdVcpupin(vshControl * ctl, vshCmd * cmd) +{ + virDomainInfo info; + virDomainPtr dom; + virNodeInfo nodeinfo; + int vcpu; + char *cpulist; + int ret = TRUE; + int vcpufound = 0; + unsigned char *cpumap; + int cpumaplen; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", NULL))) + return FALSE; + + vcpu = vshCommandOptInt(cmd, "vcpu", &vcpufound); + if (!vcpufound) { + virDomainFree(dom); + return FALSE; + } + + if (!(cpulist = vshCommandOptString(cmd, "cpulist", NULL))) { + virDomainFree(dom); + return FALSE; + } + + if (virNodeGetInfo(ctl->conn, &nodeinfo) != 0) { + virDomainFree(dom); + return FALSE; + } + + if (virDomainGetInfo(dom, &info) != 0) { + virDomainFree(dom); + return FALSE; + } + + if (vcpu >= info.nrVirtCpu) { + virDomainFree(dom); + return FALSE; + } + + cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); + cpumap = malloc(cpumaplen); + memset(cpumap, 0, cpumaplen); + + do { + unsigned int cpu = atoi(cpulist); + + if (cpu < VIR_NODEINFO_MAXCPUS(nodeinfo)) { + VIR_USE_CPU(cpumap, cpu); + } + cpulist = index(cpulist, ','); + if (cpulist) + cpulist++; + } while (cpulist); + + if (virDomainPinVcpu(dom, vcpu, cpumap, cpumaplen) != 0) { + ret = FALSE; + } + + free(cpumap); + virDomainFree(dom); + return ret; +} + /* * "nodeinfo" command */ @@ -1081,6 +1251,8 @@ static vshCmdDef commands[] = { {"save", cmdSave, opts_save, info_save}, {"shutdown", cmdShutdown, opts_shutdown, info_shutdown}, {"suspend", cmdSuspend, opts_suspend, info_suspend}, + {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo}, + {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin}, {"version", cmdVersion, NULL, info_version}, {NULL, NULL, NULL, NULL} }; @@ -1643,6 +1815,22 @@ vshDomainStateToString(int state) return NULL; } +static const char * +vshDomainVcpuStateToString(int state) +{ + switch (state) { + case VIR_VCPU_OFFLINE: + return "offline"; + case VIR_VCPU_BLOCKED: + return "blocked"; + case VIR_VCPU_RUNNING: + return "running"; + default: + return "no state"; + } + return NULL; +} + static int vshConnectionUsability(vshControl * ctl, virConnectPtr conn, int showerror) {