Share
Embed
code generation from C in gopsutil
Generate go code from C struct use godefs. This technique is used in the gopsutil, goport of psutil.
shirou
June 21, 2015
Transcript
14 slides
-
Who are you? • @r_rudi / WAKAYAMA Shirou • CTO
of Tsukinowa inc. • ansible / MQTT / Sphinx ! • No.6 of Go GitHub developers in Japan -
psutil • A cross-platform process and system utilities module for
Python • Linux/Windows/OSX/FreeBSD/Solaris • 32bit/64bit • CPU, Mem, Disk, Network, Process and so on -
gopsutil • go port of the psutil • github.com/shirou/gopsutil •
Linux/Windows/OSX/FreeBSD • 32bit/64bit • “Pure Golang" -
How to get system information • Linux has proc filesystem
• read under “/proc” • /proc/stat • /proc/mem • /proc/10/stat Thanks it’s Text -
FreeBSD/OSX • Some of values can get from sysctl as
Text ! • Some is Not Text • kern.devstat.all retunes “C struct devinfo_dev” • can not use cgo to stay “Pure golang” • (Linux /var/run/utmp is also not text) % sysctl vm.stats.vm.v_page_count vm.stats.vm.v_page_count: 1012332 -
Use syscall.Syscall • call syscall of low-level operating system primitives
directory Notice: http://golang.org/pkg shows only Linux. you must read src directory to read other platform -
How to use syscall // freebsd MIB mib := []int32{CTLKern,
KernDevstat, KernDevstatAll} // invoke syscall _, _, err = syscall.Syscall6( syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), uintptr(miblen), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&length)), 0, 0) // parse bytes to Devstat var ds Devstat br := bytes.NewReader(buf) Read(br, binary.LittleEndian, &ds) -
struct Devstat from C to Go type Devstat struct {
Sequence0 uint32 Allocated int32 Start_count uint32 End_count uint32 Busy_from Bintime Dev_links _Ctype_struct___0 Device_number uint32 Device_name [16]int8 Unit_number int32 Bytes [4]uint64 Operations [4]uint64 Duration [4]Bintime Busy_time Bintime Creation_time Bintime Block_size uint32 Pad_cgo_0 [4]byte Tag_types [3]uint64 Flags uint32 Device_type uint32 Priority uint32 Pad_cgo_1 [4]byte Id *byte Sequence1 uint32 Pad_cgo_2 [4]byte } struct devstat { /* Internal house-keeping fields */ u_int sequence0; /* Update sequence# */ int allocated; /* Allocated entry */ u_int start_count; /* started ops */ u_int end_count; /* completed ops */ struct bintime busy_from; /* */ STAILQ_ENTRY(devstat) dev_links; u_int32_t device_number; /* * Devstat device * number. */ char device_name[DEVSTAT_NAME_LEN]; int unit_number; u_int64_t bytes[DEVSTAT_N_TRANS_FLAGS]; u_int64_t operations[DEVSTAT_N_TRANS_FLAGS]; struct bintime duration[DEVSTAT_N_TRANS_FLAGS]; struct bintime busy_time; struct bintime creation_time; /* * Time the device was * created. */ u_int32_t block_size; /* Block size, bytes */ u_int64_t tag_types[3]; /* * The number of * simple, ordered, * and head of queue * tags sent. write by your self? Oh no no no! -
Use “cgo -godefs" // +build ignore package disk ! /*
#include <sys/types.h> #include <sys/mount.h> #include <devstat.h> */ import "C" ! type Devstat C.struct_devstat % go tool cgo -godefs types_freebsd.go > disk_freebsd_amd64.go types_freebsd.go Once you created definition, can use on other hosts. -
godefs • godef refer other struct if defined type Devstat
C.struct_devstat type Bintime C.struct_bintime struct devstat { struct bintime busy_time; }; struct bintime { time_t sec; uint64_t frac; }; + type Devstat struct { Busy_time Bintime } type Bintime struct { Sec int64 Frac uint64 } -
limitation • union • C's union types are represented as
a Go byte array with the same length • output perfect may not perfect • some hand editing should be required… -
Ok, how about Windows? • No need to use C
struct ! ! ! ! ! • easy, huh? Modkernel32 = syscall.NewLazyDLL("kernel32.dll") procGetDiskFreeSpaceExW = Modkernel32.NewProc("GetDiskFreeSpaceExW") lpFreeBytesAvailable := int64(0) lpTotalNumberOfBytes := int64(0) lpTotalNumberOfFreeBytes := int64(0) ret, _, err := procGetDiskFreeSpaceExW.Call( uintptr(unsafe.Pointer( syscall.StringToUTF16Ptr(path))), uintptr(unsafe.Pointer(&lpFreeBytesAvailable)), uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)), uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes))) -
Conclusion • gopsutil can get system information • Linux/Windows/OSX/FreeBSD •
use syscall.Syscall to do low-level • use “cgo -godefs” to generate Go from C