[Libvir] Here the patch for virtual CPU functions.

Daniel P. Berrange berrange at redhat.com
Sat Aug 5 00:27:43 UTC 2006


On Fri, Aug 04, 2006 at 06:55:17PM +0100, Daniel P. Berrange wrote:
> On Fri, Aug 04, 2006 at 05:45:41AM -0400, Daniel Veillard wrote:
> > On Thu, Aug 03, 2006 at 03:32:46PM +0200, Philippe Berthault wrote:
> > I had a few things to change:
> >    - discard // based comments to stick just to /*
> >    - apply the header patch to libvirt.h.in not to the generated header
> >    - shorten some comments to fit in 80 characters wide
> >    - renamed the macros adding the VIR_ prefix to avoid potential name
> >      collision with other headers

I added 3 more convenience macros:

 VIR_NODEINFO_MAXCPUS(nodeinfo)
 VIR_CPU_MAPLEN(cpu)
 VIR_CPU_FULL_MAPLEN(vcpu, cpu)  

To hide the maths from developers.

I also bug-fixed the pin cpu method which mistakenly checked for vcpu < 1
instead of vcpu < 0 when validating args.

See atached patch for these changes

> One more:
> 
>  - expose the new APIs via virsh. Michael originally suggsted pretty much
>    following the style of 'xm vcpu-pin' and 'vcpu-list'. Seems like a fairly
>    reasonable pattern to follow.

See the attached patch which adds these commands. eg:

# ~berrange/usr/bin/virsh vcpuinfo Demo03
VCPU:           0
CPU:            1
State:          blocked
CPU time:       13.4s
CPU Affinity:   y-

VCPU:           1
CPU:            0
State:          blocked
CPU time:       5.0s
CPU Affinity:   -y

# ~berrange/usr/bin/virsh vcpupin Demo03 1 0,1

# ~berrange/usr/bin/virsh vcpuinfo Demo03
VCPU:           0
CPU:            1
State:          blocked
CPU time:       13.4s
CPU Affinity:   -y

VCPU:           1
CPU:            1
State:          blocked
CPU time:       5.0s
CPU Affinity:   yy

Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
-------------- next part --------------
diff -c -r1.200 ChangeLog
*** ChangeLog	4 Aug 2006 13:36:07 -0000	1.200
--- ChangeLog	5 Aug 2006 01:17:22 -0000
***************
*** 1,3 ****
--- 1,11 ----
+ Fri Aug  4 20:19:23 EDT 2006 Daniel Berrange <berrange at redhat.com>
+ 
+ 	* 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 <veillard at redhat.com>
  
  	* python/generator.py: fix the generator when handling long integers
diff -c -r1.20 libvirt.h
*** include/libvirt/libvirt.h	4 Aug 2006 10:41:05 -0000	1.20
--- include/libvirt/libvirt.h	5 Aug 2006 01:17:22 -0000
***************
*** 167,172 ****
--- 167,184 ----
      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,344 ****
--- 351,380 ----
  
  #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)
+ 
+ /**
+  * VIR_CPU_FULL_MAPLEN
+  * @vcpu: number of virtual CPUs
+  * @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 all virtual & physical CPUs of a domain.
+  */
+ 
+ #define VIR_CPU_FULL_MAPLEN(vcpu, cpu)      (((cpu)+7)/8*(vcpu))
+ 
+ 
  int			virDomainGetVcpus	(virDomainPtr domain,
  						 virVcpuInfoPtr info,
  						 int maxinfo,
diff -c -r1.38 libvirt.c
*** src/libvirt.c	4 Aug 2006 10:41:05 -0000	1.38
--- src/libvirt.c	5 Aug 2006 01:17:22 -0000
***************
*** 1720,1726 ****
      }
      if (domain->conn->flags & VIR_CONNECT_RO)
          return (-1);
!     if ((vcpu < 1) || (cpumap == NULL) || (maplen < 1)) {
          virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
          return (-1);
      }
--- 1720,1726 ----
      }
      if (domain->conn->flags & VIR_CONNECT_RO)
          return (-1);
!     if ((vcpu < 0) || (cpumap == NULL) || (maplen < 1)) {
          virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
          return (-1);
      }
diff -c -r1.32 virsh.c
*** src/virsh.c	19 Jul 2006 22:24:37 -0000	1.32
--- src/virsh.c	5 Aug 2006 01:17:23 -0000
***************
*** 207,212 ****
--- 207,213 ----
  #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);
  
***************
*** 794,799 ****
--- 795,969 ----
  }
  
  /*
+  * "vcpuinfo" command
+  */
+ static vshCmdInfo info_vcpuinfo[] = {
+     {"syntax", "vcpuinfo <domain>"},
+     {"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_FULL_MAPLEN(info.nrVirtCpu, VIR_NODEINFO_MAXCPUS(nodeinfo));
+     cpumap = malloc(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 <domain>"},
+     {"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
   */
  static vshCmdInfo info_nodeinfo[] = {
***************
*** 1081,1086 ****
--- 1251,1258 ----
      {"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,1648 ****
--- 1815,1836 ----
      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)
  {


More information about the libvir-list mailing list