[Libvir] PATCH: Add missing APIs to python binding

Daniel P. Berrange berrange at redhat.com
Sun Jan 20 17:23:46 UTC 2008


The python binding is missing all the APIs relating to CPU pinning and
schedular parameters because they are too hard for the generator to manage.
This patch implements them manually. Now a few words about the impls since
they are non-trivial

 * virDomainGetSchedulerType

   The C binding has a return value, and an out parameter. I translated
   this into a tuple in python  (schedular-type, n-parms)

   eg  

     print dom.schedulerType()
     ('credit', 2)

   Arguably we could drop the nparams field - its less use in python
   since you don't have to pre-allocate a virSchedParam list. 

 * virDomainGetSchedulerParameters
 
   This has an out parameter which is a list of virSchedParam structs, and
   a param specifying the length of the passed in virSchedParam list. The
   latter is irrelevant; The former I translated into a hash table return
   value

   eg  

      print dom.schedulerParameters()
      {'cap': 0, 'weight': 100}

 * virDomainSetSchedulerParameters

   This has two in parameters, a list of virSchedParma structs, and a param
   specifying length of the list. I just convert this into a hash. I also
   make all the fields optional - it'll copy existing values for any params
   which are omimtted.

    eg

       dom.setSchedulerParameters({'weight': 100})

 * virDomainGetVcpus

   This has two out parameters, a list of virVcpuInfo structs, and a bitmap
   both pre-allocated, and their size passed in. This needs to be turned into
   a 2 element tuple return value. First element returning vcpu info, and the
   second element returning mapping. The vcpu info will be returned as a list
   of lists, and the cpumap will be another list of lists - a True indicating
   affinity.

     eg

       (cpuinfo, cpumap) = dom.vcpus()
       print cpuinfo
       print cpumap
       [(0, 2, 7753916026L, 1), (1, 2, 5698028782L, 0), (2, 2, 4916522979L, 0), (3, 2, 3773416711L, 1)]
       [(False, True), (True, True), (True, False), (True, True)]

 * virDomainPinVcpu

   This takes a vcpu number and a bitmap of affinity. I turn the bitmap
   into a list of True/False values

      eg

        dom.pinVcpu(1, (True, True))


The generator fails on the C code part of the bindings completely, so that
is hand-written. It also fails on the python part of the bindings, but
the way the generator is structured doesn't enable us to hand-write the 
python part for methods within objects :-( So I have basically just editted
the generator to blacklist all the out-parameters, and blacklist the in
parameters which specify list lengths.

Here is the code I used to test the functions:

#!/usr/bin/python                                                                                                                                   

import libvirt

con = libvirt.open("xen:///")
dom = con.lookupByName("rhel5pv")

dominfo = dom.info()
nodeinfo = con.getInfo()
pcpus = nodeinfo[4] * nodeinfo[5] * nodeinfo[6] * nodeinfo[7]

(cpuinfo, cpumap) = dom.vcpus()
print cpuinfo
print cpumap

for i in range(dominfo[3]):
    print "vcpu: %d" % i
    if cpuinfo[i][1] == 0:
        print "state: offline"
    elif cpuinfo[i][1] == 2:
        print "state: blocked"
    else:
        print "state: running"
    print "cputime: %d" % cpuinfo[i][2]
    print "pcpu: %d" % cpuinfo[i][3]
    affinity = ""
    for p in range(pcpus):
        if cpumap[i][p] == True:
            affinity = affinity + "y"
        else:
            affinity = affinity + "-"
    print "affinity: %s" % affinity
    print

dom.pinVcpu(1, (True, True))

print dom.schedulerType()
print dom.schedulerParameters()

dom.setSchedulerParameters({"weight": 100})

And here is the diffstat:


 generator.py |   26 ++++
 libvir.c     |  318 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 344 insertions(+)

Dan.


diff -r 8468c0d428c9 python/generator.py
--- a/python/generator.py	Sun Jan 20 12:06:47 2008 -0500
+++ b/python/generator.py	Sun Jan 20 12:07:59 2008 -0500
@@ -229,6 +229,7 @@ py_types = {
     'double':  ('d', None, "double", "double"),
     'unsigned int':  ('i', None, "int", "int"),
     'unsigned long':  ('l', None, "long", "long"),
+    'unsigned long long':  ('l', None, "longlong", "long long"),
     'unsigned char *':  ('z', None, "charPtr", "char *"),
     'char *':  ('z', None, "charPtr", "char *"),
     'const char *':  ('z', None, "charPtrConst", "const char *"),
@@ -279,6 +280,11 @@ skip_impl = (
     'virDomainBlockStats',
     'virDomainInterfaceStats',
     'virNodeGetCellsFreeMemory',
+    'virDomainGetSchedulerType',
+    'virDomainGetSchedulerParameters',
+    'virDomainSetSchedulerParameters',
+    'virDomainGetVcpus',
+    'virDomainPinVcpu',
 )
 
 def skip_function(name):
@@ -918,6 +924,16 @@ def buildWrappers():
 		txt.write("    %s()\n" % func);
 		n = 0
 		for arg in args:
+                    if name == "virDomainPinVcpu" and arg[0] == "maplen":
+                        continue
+                    if name == "virDomainGetSchedulerType" and arg[0] == "nparams":
+                        continue
+                    if name == "virDomainSetSchedulerParameters" and arg[0] == "nparams":
+                        continue
+                    if name == "virDomainGetSchedulerParameters" and arg[0] != "domain":
+                        continue
+                    if name == "virDomainGetVcpus" and arg[0] != "domain":
+                        continue
 		    if n != index:
 			classes.write(", %s" % arg[0])
 		    n = n + 1
@@ -939,6 +955,16 @@ def buildWrappers():
 		classes.write("libvirtmod.%s(" % name)
 		n = 0
 		for arg in args:
+                    if name == "virDomainPinVcpu" and arg[0] == "maplen":
+                        continue
+                    if name == "virDomainGetSchedulerType" and arg[0] == "nparams":
+                        continue
+                    if name == "virDomainSetSchedulerParameters" and arg[0] == "nparams":
+                        continue
+                    if name == "virDomainGetSchedulerParameters" and arg[0] != "domain":
+                        continue
+                    if name == "virDomainGetVcpus" and arg[0] != "domain":
+                        continue
 		    if n != 0:
 			classes.write(", ");
 		    if n != index:
diff -r 8468c0d428c9 python/libvir.c
--- a/python/libvir.c	Sun Jan 20 12:06:47 2008 -0500
+++ b/python/libvir.c	Sun Jan 20 12:07:59 2008 -0500
@@ -102,6 +102,319 @@ libvirt_virDomainInterfaceStats(PyObject
     PyTuple_SetItem(info, 7, PyLong_FromLongLong(stats.tx_drop));
     return(info);
 }
+
+
+static PyObject *
+libvirt_virDomainGetSchedulerType(PyObject *self ATTRIBUTE_UNUSED,
+                                  PyObject *args) {
+    virDomainPtr domain;
+    PyObject *pyobj_domain, *info;
+    char *c_retval;
+    int nparams;
+
+    if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetScedulerType",
+                          &pyobj_domain))
+        return(NULL);
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    c_retval = virDomainGetSchedulerType(domain, &nparams);
+    if (c_retval == NULL)
+        return VIR_PY_NONE;
+
+    /* convert to a Python tupple of long objects */
+    if ((info = PyTuple_New(2)) == NULL) {
+        free(c_retval);
+        return VIR_PY_NONE;
+    }
+
+    PyTuple_SetItem(info, 0, libvirt_constcharPtrWrap(c_retval));
+    PyTuple_SetItem(info, 1, PyInt_FromLong((long)nparams));
+    free(c_retval);
+    return(info);
+}
+
+static PyObject *
+libvirt_virDomainGetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
+                                        PyObject *args) {
+    virDomainPtr domain;
+    PyObject *pyobj_domain, *info;
+    char *c_retval;
+    int nparams, i;
+    virSchedParameterPtr params;
+
+    if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetScedulerParameters",
+                          &pyobj_domain))
+        return(NULL);
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    c_retval = virDomainGetSchedulerType(domain, &nparams);
+    if (c_retval == NULL)
+        return VIR_PY_NONE;
+    free(c_retval);
+
+    if ((params = malloc(sizeof(*params)*nparams)) == NULL)
+        return VIR_PY_NONE;
+
+    if (virDomainGetSchedulerParameters(domain, params, &nparams) < 0) {
+        free(params);
+        return VIR_PY_NONE;
+    }
+
+    /* convert to a Python tupple of long objects */
+    if ((info = PyDict_New()) == NULL) {
+        free(params);
+        return VIR_PY_NONE;
+    }
+    for (i = 0 ; i < nparams ; i++) {
+        PyObject *key, *val;
+
+        switch (params[i].type) {
+        case VIR_DOMAIN_SCHED_FIELD_INT:
+            val = PyInt_FromLong((long)params[i].value.i);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_UINT:
+            val = PyInt_FromLong((long)params[i].value.ui);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_LLONG:
+            val = PyLong_FromLongLong((long long)params[i].value.l);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_ULLONG:
+            val = PyLong_FromLongLong((long long)params[i].value.ul);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
+            val = PyFloat_FromDouble((double)params[i].value.d);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
+            val = PyBool_FromLong((long)params[i].value.b);
+            break;
+
+        default:
+            free(params);
+            Py_DECREF(info);
+            return VIR_PY_NONE;
+        }
+
+        key = libvirt_constcharPtrWrap(params[i].field);
+        PyDict_SetItem(info, key, val);
+    }
+    free(params);
+    return(info);
+}
+
+static PyObject *
+libvirt_virDomainSetSchedulerParameters(PyObject *self ATTRIBUTE_UNUSED,
+                                        PyObject *args) {
+    virDomainPtr domain;
+    PyObject *pyobj_domain, *info;
+    char *c_retval;
+    int nparams, i;
+    virSchedParameterPtr params;
+
+    if (!PyArg_ParseTuple(args, (char *)"OO:virDomainSetScedulerParameters",
+                          &pyobj_domain, &info))
+        return(NULL);
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    c_retval = virDomainGetSchedulerType(domain, &nparams);
+    if (c_retval == NULL)
+        return VIR_PY_NONE;
+    free(c_retval);
+
+    if ((params = malloc(sizeof(*params)*nparams)) == NULL)
+        return VIR_PY_NONE;
+
+    if (virDomainGetSchedulerParameters(domain, params, &nparams) < 0) {
+        free(params);
+        return VIR_PY_NONE;
+    }
+
+    /* convert to a Python tupple of long objects */
+    for (i = 0 ; i < nparams ; i++) {
+        PyObject *key, *val;
+        key = libvirt_constcharPtrWrap(params[i].field);
+        val = PyDict_GetItem(info, key);
+        Py_DECREF(key);
+
+        if (val == NULL)
+            continue;
+
+        switch (params[i].type) {
+        case VIR_DOMAIN_SCHED_FIELD_INT:
+            params[i].value.i = (int)PyInt_AS_LONG(val);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_UINT:
+            params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_LLONG:
+            params[i].value.l = (long long)PyLong_AsLongLong(val);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_ULLONG:
+            params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
+            params[i].value.d = (double)PyFloat_AsDouble(val);
+            break;
+
+        case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
+            {
+                /* Hack - Python's definition of Py_True breaks strict
+                 * aliasing rules, so can't directly compare :-(
+                 */
+                PyObject *hacktrue = PyBool_FromLong(1);
+                params[i].value.b = hacktrue == val ? 1 : 0;
+                Py_DECREF(hacktrue);
+            }
+            break;
+
+        default:
+            free(params);
+            return VIR_PY_NONE;
+        }
+    }
+
+    if (virDomainSetSchedulerParameters(domain, params, nparams) < 0) {
+        free(params);
+        return VIR_PY_NONE;
+    }
+
+    free(params);
+    return VIR_PY_NONE;
+}
+
+static PyObject *
+libvirt_virDomainGetVcpus(PyObject *self ATTRIBUTE_UNUSED,
+                          PyObject *args) {
+    virDomainPtr domain;
+    PyObject *pyobj_domain, *pyretval = NULL, *pycpuinfo = NULL, *pycpumap = NULL;
+    virNodeInfo nodeinfo;
+    virDomainInfo dominfo;
+    virVcpuInfoPtr cpuinfo = NULL;
+    unsigned char *cpumap = NULL;
+    int cpumaplen, i;
+
+    if (!PyArg_ParseTuple(args, (char *)"O:virDomainGetVcpus",
+                          &pyobj_domain))
+        return(NULL);
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    if (virNodeGetInfo(virDomainGetConnect(domain), &nodeinfo) != 0)
+        return VIR_PY_NONE;
+
+    if (virDomainGetInfo(domain, &dominfo) != 0)
+        return VIR_PY_NONE;
+
+    if ((cpuinfo = malloc(sizeof(*cpuinfo)*dominfo.nrVirtCpu)) == NULL)
+        return VIR_PY_NONE;
+
+    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
+    if ((cpumap = malloc(dominfo.nrVirtCpu * cpumaplen)) == NULL)
+        goto cleanup;
+
+    if (virDomainGetVcpus(domain,
+                          cpuinfo, dominfo.nrVirtCpu,
+                          cpumap, cpumaplen) < 0)
+        goto cleanup;
+
+    /* convert to a Python tupple of long objects */
+    if ((pyretval = PyTuple_New(2)) == NULL)
+        goto cleanup;
+    if ((pycpuinfo = PyList_New(dominfo.nrVirtCpu)) == NULL)
+        goto cleanup;
+    if ((pycpumap = PyList_New(dominfo.nrVirtCpu)) == NULL)
+        goto cleanup;
+
+    for (i = 0 ; i < dominfo.nrVirtCpu ; i++) {
+        PyObject *info = PyTuple_New(4);
+        if (info == NULL)
+            goto cleanup;
+        PyTuple_SetItem(info, 0, PyInt_FromLong((long)cpuinfo[i].number));
+        PyTuple_SetItem(info, 1, PyInt_FromLong((long)cpuinfo[i].state));
+        PyTuple_SetItem(info, 2, PyLong_FromLongLong((long long)cpuinfo[i].cpuTime));
+        PyTuple_SetItem(info, 3, PyInt_FromLong((long)cpuinfo[i].cpu));
+        PyList_SetItem(pycpuinfo, i, info);
+    }
+    for (i = 0 ; i < dominfo.nrVirtCpu ; i++) {
+        PyObject *info = PyTuple_New(VIR_NODEINFO_MAXCPUS(nodeinfo));
+        int j;
+        if (info == NULL)
+            goto cleanup;
+        for (j = 0 ; j < VIR_NODEINFO_MAXCPUS(nodeinfo) ; j++) {
+            PyTuple_SetItem(info, j, PyBool_FromLong(VIR_CPU_USABLE(cpumap, cpumaplen, i, j)));
+        }
+        PyList_SetItem(pycpumap, i, info);
+    }
+    PyTuple_SetItem(pyretval, 0, pycpuinfo);
+    PyTuple_SetItem(pyretval, 1, pycpumap);
+
+    free(cpuinfo);
+    free(cpumap);
+
+    return(pyretval);
+
+ cleanup:
+    free(cpuinfo);
+    free(cpumap);
+    /* NB, Py_DECREF is a badly defined macro, so we require
+     * braces here to avoid 'ambiguous else' warnings from
+     * the compiler.
+     * NB. this comment is true at of time of writing wrt to
+     * at least python2.5.
+     */
+    if (pyretval) { Py_DECREF(pyretval); }
+    if (pycpuinfo) { Py_DECREF(pycpuinfo); }
+    if (pycpumap) { Py_DECREF(pycpumap); }
+    return VIR_PY_NONE;
+}
+
+
+static PyObject *
+libvirt_virDomainPinVcpu(PyObject *self ATTRIBUTE_UNUSED,
+                         PyObject *args) {
+    virDomainPtr domain;
+    PyObject *pyobj_domain, *pycpumap, *truth;
+    virNodeInfo nodeinfo;
+    unsigned char *cpumap;
+    int cpumaplen, i, vcpu;
+
+    if (!PyArg_ParseTuple(args, (char *)"OiO:virDomainPinVcpu",
+                          &pyobj_domain, &vcpu, &pycpumap))
+        return(NULL);
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    if (virNodeGetInfo(virDomainGetConnect(domain), &nodeinfo) != 0)
+        return VIR_PY_NONE;
+
+    cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo));
+    if ((cpumap = malloc(cpumaplen)) == NULL)
+        return VIR_PY_NONE;
+    memset(cpumap, 0, cpumaplen);
+
+    truth = PyBool_FromLong(1);
+    for (i = 0 ; i < VIR_NODEINFO_MAXCPUS(nodeinfo) ; i++) {
+        PyObject *flag = PyTuple_GetItem(pycpumap, i);
+        if (flag == truth)
+            VIR_USE_CPU(cpumap, i);
+        else
+            VIR_UNUSE_CPU(cpumap, i);
+    }
+
+    virDomainPinVcpu(domain, vcpu, cpumap, cpumaplen);
+    Py_DECREF(truth);
+    free(cpumap);
+
+    return VIR_PY_NONE;
+}
+
+
 /************************************************************************
  *									*
  *		Global error handler at the Python level		*
@@ -876,6 +1189,11 @@ static PyMethodDef libvirtMethods[] = {
     {(char *) "virDomainBlockStats", libvirt_virDomainBlockStats, METH_VARARGS, NULL},
     {(char *) "virDomainInterfaceStats", libvirt_virDomainInterfaceStats, METH_VARARGS, NULL},
     {(char *) "virNodeGetCellsFreeMemory", libvirt_virNodeGetCellsFreeMemory, METH_VARARGS, NULL},
+    {(char *) "virDomainGetSchedulerType", libvirt_virDomainGetSchedulerType, METH_VARARGS, NULL},
+    {(char *) "virDomainGetSchedulerParameters", libvirt_virDomainGetSchedulerParameters, METH_VARARGS, NULL},
+    {(char *) "virDomainSetSchedulerParameters", libvirt_virDomainSetSchedulerParameters, METH_VARARGS, NULL},
+    {(char *) "virDomainGetVcpus", libvirt_virDomainGetVcpus, METH_VARARGS, NULL},
+    {(char *) "virDomainPinVcpu", libvirt_virDomainPinVcpu, METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}
 };
 


-- 
|=- 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  -=| 




More information about the libvir-list mailing list