code generation from C in gopsutil

28da29f13a2f4e6f602b7bfa032a94cc?s=47 shirou
June 21, 2015

code generation from C in gopsutil

Generate go code from C struct use godefs. This technique is used in the gopsutil, goport of psutil.

28da29f13a2f4e6f602b7bfa032a94cc?s=128

shirou

June 21, 2015
Tweet

Transcript

  1. go code generation
 from C r_rudi / एࢁ ࢙࿠

  2. Who are you? • @r_rudi / WAKAYAMA Shirou • CTO

    of Tsukinowa inc. • ansible / MQTT / Sphinx ! • No.6 of Go GitHub developers in Japan
  3. 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
  4. gopsutil • go port of the psutil • github.com/shirou/gopsutil •

    Linux/Windows/OSX/FreeBSD • 32bit/64bit • “Pure Golang"
  5. How to get system information • Linux has proc filesystem

    • read under “/proc” • /proc/stat • /proc/mem • /proc/10/stat Thanks it’s Text
  6. 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
  7. 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
  8. 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)
  9. 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!
  10. 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.
  11. 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 }
  12. 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…
  13. 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)))
  14. 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