Upgrade to Pro — share decks privately, control downloads, hide ads and more …

code generation from C in gopsutil

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
Tweet

More Decks by shirou

Other Decks in Technology

Transcript

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

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

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

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