working with ctypes and complex data structures
Michael Felt
michael at felt.demon.nl
Mon Oct 3 17:27:34 EDT 2016
On 02-Oct-16 19:50, Michael Felt wrote:
> class perfstat_cpu_total_t(Structure):
> """
> typedef struct { /* global cpu information */
> int ncpus; /* number of active logical
> processors */
> int ncpus_cfg; /* number of configured processors */
> char description[IDENTIFIER_LENGTH]; /* processor description
> (type/official name) */
> u_longlong_t buffer1[15]; /* several variables being
> skipped for now */
> time_t lbolt; /* number of ticks since last
> reboot */
> u_longlong_t loadavg[3]; /* (1<<SBITS) times the average
> number of runnables processes during the last
> 1, 5 and 15 minutes. */
> u_longlong_t buffer2[29]; /* several variables being
> skipped for now */
> int ncpus_high; /* index of highest processor online */
> u_longlong_t puser; /* raw number of physical processor
> tics in user mode */
> u_longlong_t psys; /* raw number of physical processor
> tics in system mode */
> u_longlong_t pidle; /* raw number of physical processor
> tics idle */
> u_longlong_t pwait; /* raw number of physical processor
> tics waiting for I/O */
> u_longlong_t buffer2[29]; /* several variables being
> skipped for now */
> } perfstat_cpu_total_t;
> """
> _fields_ = [
> ("ncpus", c_int),
> ("ncpus_cfg", c_int),
> ("description", c_char * IDENTIFIER_LENGTH),
> ("buffer1", c_ulonglong * 15),
> ("lbolt", time_t),
> ("loadavg", c_ulonglong * 3),
> ("buffer2", c_ulonglong * 29),
> ("ncpus_high", c_int),
> ("puser", c_ulonglong),
> ("psys", c_ulonglong),
> ("pidle", c_ulonglong),
> ("pwait", c_ulonglong),
> ("buffer3", c_ulonglong * 12)
> ]
Perhaps I should explain what I want to accomplish.
a) use ctypes.CDLL to open libperfstat.a(shr_64.o)
b) call a number for functions, among them
The prototype template (in C) is:
The common signature used by all of the global interfaces is as follows:
int perfstat_subsystem_total(
perfstat_id_t *name,
perfstat_subsystem_total_t *userbuff,
int sizeof_struct,
int desired_number);
The usage of the parameters for all of the interfaces is as follows:
perfstat_id_t *name Reserved for future use, should be NULL
perfstat_subsystem_total_t *userbuff A pointer to a memory area with
enough space for the returned structure
int sizeof_struct Should be set to sizeof(perfstat_subsystem_t)
int desired_number Reserved for future use, must be set to 0 or 1
The return value will be -1 in case of errors. Otherwise, the number of
structures copied is returned. This
is always 1.
So, in C the call looks something like this - for cpu_total
perfstat_cpu_total(NULL, (struct perfstat_cpu_total_t *) &xxx, sizeof(perfstat_cpu_total_t), 1)
I am struggling with the declarations needed to make the call
I have several iterations - the most simple case (no CFUNCTYPE declaration) gives
+79 class cpu_total:
+80 def __init__(self):
+81 __perfstat__ = CDLL("libperfstat.a(shr_64.o)")
+82 xxx = perfstat_cpu_total_t
+83 cpu_total = __perfstat__.perfstat_cpu_total
+84 ret = cpu_total(None, xxx, sizeof(xxx), 1)
+85 print xxx.ncpus
+86 print xxx.lbolt.v
+87
+88 a = cpu_total()
!cat test_1.py | python
Traceback (most recent call last):
File "<stdin>", line 88, in <module>
File "<stdin>", line 84, in __init__
ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: Don't know how to convert parameter 2
I have tried some experiments with CFUNCTYPE - basically
prototype = CFUNCTYPE(c_int, c_void_p, c_int, c_int, c_int)
but I do not understand how (I think some of the details are missing from the example) how the following works:
I have also tried:
+80 def __init__(self):
+81 __perfstat__ = CDLL("libperfstat.a(shr_64.o)")
+82 xxx = perfstat_cpu_total_t
+83 xptr = POINTER(xxx)
+84 x2 = cast(xptr,POINTER(c_void_p))
+85 cpu_total = __perfstat__.perfstat_cpu_total
+86 ret = cpu_total(None, x2, sizeof(xxx), 1)
+87 print xxx.ncpus
+88 print xxx.lbolt.v
+89
+90 a = cpu_total()
+91 print sizeof(a)
!cat test_1.py | python
Traceback (most recent call last):
File "<stdin>", line 90, in <module>
File "<stdin>", line 84, in __init__
File "/opt/lib/python2.7/ctypes/__init__.py", line 509, in cast
return _cast(obj, obj, typ)
ctypes.ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong type
+79 class cpu_total:
+80 def __init__(self):
+81 __perfstat__ = CDLL("libperfstat.a(shr_64.o)")
+82 xxx = perfstat_cpu_total_t
+83 xptr = POINTER(xxx)
+84 cpu_total = __perfstat__.perfstat_cpu_total
+85 ret = cpu_total(None, xptr, sizeof(xxx), 1)
+86 print xxx.ncpus
+87 print xxx.lbolt.v
+88
+89 a = cpu_total()
+90 print sizeof(a)
+91
!cat test_1.py | python
Traceback (most recent call last):
File "<stdin>", line 89, in <module>
File "<stdin>", line 85, in __init__
ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: Don't know how to convert parameter 2
and
+79 class cpu_total:
+80 def __init__(self):
+81 __perfstat__ = CDLL("libperfstat.a(shr_64.o)")
+82 xxx = perfstat_cpu_total_t
+83 xptr = c_void_p(xxx)
+84 cpu_total = __perfstat__.perfstat_cpu_total
+85 ret = cpu_total(None, xptr, sizeof(xxx), 1)
+86 print xxx.ncpus
+87 print xxx.lbolt.v
+88
+89 a = cpu_total()
+90 print sizeof(a)
+91
!cat test_1.py | python
Traceback (most recent call last):
File "<stdin>", line 89, in <module>
File "<stdin>", line 83, in __init__
TypeError: cannot be converted to pointer
I know they are "stabs in the dark" as I really do not grasp the documentation. Maybe it is clear to someone well versed in python, or just smarter than I.
Your expert assistance is appreciated!
More information about the Python-list
mailing list