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 -=| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list