概要
sysfsの無いFreeBSD環境の現在のCPU時間をGo言語から取得したい...けど、syscall.Sysctl()ではすんなりとできない。
なんとかしたいから、文字列→Byte列→数値の変換でなんとか読みだしてみた。
解説
sysctl()システムコールをGo言語から使用する場合、標準ライブラリのsyscall.Sysctl()かsyscall.SysctlUint32()を使用します。
ただし、取得できるデータ形式が文字列と符号なし32bit整数のみで“kern.cp_time"等、配列を返すmibにはすんなりと対応できません。
syscall.Sysctl()の結果を以下のように変換して結果を取り出します。
sysctl_go.go
package main
import (
"bytes"
"encoding/binary"
"fmt"
"syscall"
)
func main() {
val, err := syscall.Sysctl("kern.cp_time")
if err != nil {
return
}
buf := bytes.NewBufferString(val)
buf.Write([]byte{0})
fmt.Println("buf len=", buf.Len())
b := buf.Bytes()
fmt.Println("result:", len(b), b)
var i1 uint64
var i2 uint64
var i3 uint64
var i4 uint64
var i5 uint64
binary.Read(buf, binary.LittleEndian, &i1)
binary.Read(buf, binary.LittleEndian, &i2)
binary.Read(buf, binary.LittleEndian, &i3)
binary.Read(buf, binary.LittleEndian, &i4)
binary.Read(buf, binary.LittleEndian, &i5)
println(i1, i2, i3, i4, i5)
}
実行結果は
% ./sysctl_go && echo && sysctl kern.cp_time
buf len= 40
result: 40 [35 147 0 0 0 0 0 0 234 0 0 0 0 0 0 0 30 42 2 0 0 0 0 0 221 11 2 0 0 0 0 0 165 170 242 9 0 0 0 0]
37667 234 141854 134109 166898341
kern.cp_time: 37667 234 141855 134109 166898341
sysctlコマンドの結果と一致しているようです。
課題
とりあえず、それっぽい結果にするために数値のサイズを64bitと決め打ち&バッファに1Byte足して8Byte境界になるようにしてしまっています。
AMD64アーキテクチャなのでそれっぽいですが、sysctlの仕様としてあっているのか要確認です。
4時間ほどsyscallパッケージのソースコードとにらめっこしてこの結果に。
まじめな自前実装もやってみようと思いましたが却下。
アーキテクチャの差をせっかくsyscallパッケージで吸収してくれているのが無駄になってしまう。
タイムアップ...ということで続きは次回(あるのかな?)