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

code generation from C in gopsutil

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.


June 21, 2015

More Decks by shirou

Other Decks in Technology


  1. go code generation

    from C
    r_rudi / एࢁ ࢙࿠

    View full-size slide

  2. Who are you?
    • @r_rudi / WAKAYAMA Shirou
    • CTO of Tsukinowa inc.
    • ansible / MQTT / Sphinx
    • No.6 of Go GitHub developers in Japan

    View full-size slide

  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

    View full-size slide

  4. gopsutil
    • go port of the psutil
    • github.com/shirou/gopsutil
    • Linux/Windows/OSX/FreeBSD
    • 32bit/64bit
    • “Pure Golang"

    View full-size slide

  5. How to get system information
    • Linux has proc filesystem
    • read under “/proc”
    • /proc/stat
    • /proc/mem
    • /proc/10/stat
    Thanks it’s Text

    View full-size slide

  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

    View full-size slide

  7. Use syscall.Syscall
    • call syscall of low-level operating system
    primitives directory

    http://golang.org/pkg shows only Linux. 

    you must read src directory to read other platform

    View full-size slide

  8. How to use syscall
    // freebsd MIB

    mib := []int32{CTLKern, KernDevstat, KernDevstatAll}

    // invoke syscall

    _, _, err = syscall.Syscall6(

    // parse bytes to Devstat

    var ds Devstat
    br := bytes.NewReader(buf)
    Read(br, binary.LittleEndian, &ds)

    View full-size slide

  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!

    View full-size slide

  10. Use “cgo -godefs"
    // +build ignore
    package disk
    import "C"
    type Devstat C.struct_devstat
    % go tool cgo -godefs types_freebsd.go > disk_freebsd_amd64.go
    Once you created definition, can use on other hosts.

    View full-size slide

  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

    View full-size slide

  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…

    View full-size slide

  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(



    View full-size slide

  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

    View full-size slide