github.com/elastic/gosigar@v0.14.3/sigar_openbsd.go (about) 1 // Copyright (c) 2016 Jasper Lievisse Adriaanse <j@jasper.la>. 2 3 // +build openbsd 4 5 package gosigar 6 7 /* 8 #include <sys/param.h> 9 #include <sys/types.h> 10 #include <sys/sysctl.h> 11 #include <sys/mount.h> 12 #include <sys/sched.h> 13 #include <sys/swap.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 */ 17 import "C" 18 19 //import "github.com/davecgh/go-spew/spew" 20 21 import ( 22 "runtime" 23 "syscall" 24 "time" 25 "unsafe" 26 ) 27 28 type Uvmexp struct { 29 pagesize uint32 30 pagemask uint32 31 pageshift uint32 32 npages uint32 33 free uint32 34 active uint32 35 inactive uint32 36 paging uint32 37 wired uint32 38 zeropages uint32 39 reserve_pagedaemon uint32 40 reserve_kernel uint32 41 anonpages uint32 42 vnodepages uint32 43 vtextpages uint32 44 freemin uint32 45 freetarg uint32 46 inactarg uint32 47 wiredmax uint32 48 anonmin uint32 49 vtextmin uint32 50 vnodemin uint32 51 anonminpct uint32 52 vtextmi uint32 53 npct uint32 54 vnodeminpct uint32 55 nswapdev uint32 56 swpages uint32 57 swpginuse uint32 58 swpgonly uint32 59 nswget uint32 60 nanon uint32 61 nanonneeded uint32 62 nfreeanon uint32 63 faults uint32 64 traps uint32 65 intrs uint32 66 swtch uint32 67 softs uint32 68 syscalls uint32 69 pageins uint32 70 obsolete_swapins uint32 71 obsolete_swapouts uint32 72 pgswapin uint32 73 pgswapout uint32 74 forks uint32 75 forks_ppwait uint32 76 forks_sharevm uint32 77 pga_zerohit uint32 78 pga_zeromiss uint32 79 zeroaborts uint32 80 fltnoram uint32 81 fltnoanon uint32 82 fltpgwait uint32 83 fltpgrele uint32 84 fltrelck uint32 85 fltrelckok uint32 86 fltanget uint32 87 fltanretry uint32 88 fltamcopy uint32 89 fltnamap uint32 90 fltnomap uint32 91 fltlget uint32 92 fltget uint32 93 flt_anon uint32 94 flt_acow uint32 95 flt_obj uint32 96 flt_prcopy uint32 97 flt_przero uint32 98 pdwoke uint32 99 pdrevs uint32 100 pdswout uint32 101 pdfreed uint32 102 pdscans uint32 103 pdanscan uint32 104 pdobscan uint32 105 pdreact uint32 106 pdbusy uint32 107 pdpageouts uint32 108 pdpending uint32 109 pddeact uint32 110 pdreanon uint32 111 pdrevnode uint32 112 pdrevtext uint32 113 fpswtch uint32 114 kmapent uint32 115 } 116 117 type Bcachestats struct { 118 numbufs uint64 119 numbufpages uint64 120 numdirtypages uint64 121 numcleanpages uint64 122 pendingwrites uint64 123 pendingreads uint64 124 numwrites uint64 125 numreads uint64 126 cachehits uint64 127 busymapped uint64 128 dmapages uint64 129 highpages uint64 130 delwribufs uint64 131 kvaslots uint64 132 kvaslots_avail uint64 133 } 134 135 type Swapent struct { 136 se_dev C.dev_t 137 se_flags int32 138 se_nblks int32 139 se_inuse int32 140 se_priority int32 141 sw_path []byte 142 } 143 144 func (self *FileSystemList) Get() error { 145 num, err := syscall.Getfsstat(nil, C.MNT_NOWAIT) 146 if err != nil { 147 return err 148 } 149 150 buf := make([]syscall.Statfs_t, num) 151 152 _, err = syscall.Getfsstat(buf, C.MNT_NOWAIT) 153 if err != nil { 154 return err 155 } 156 157 fslist := make([]FileSystem, 0, num) 158 159 for i := 0; i < num; i++ { 160 fs := FileSystem{} 161 162 fs.DirName = byteListToString(buf[i].F_mntonname[:]) 163 fs.DevName = byteListToString(buf[i].F_mntfromname[:]) 164 fs.SysTypeName = byteListToString(buf[i].F_fstypename[:]) 165 166 fslist = append(fslist, fs) 167 } 168 169 self.List = fslist 170 171 return err 172 } 173 174 func (self *FileSystemUsage) Get(path string) error { 175 stat := syscall.Statfs_t{} 176 err := syscall.Statfs(path, &stat) 177 if err != nil { 178 return err 179 } 180 181 self.Total = uint64(stat.F_blocks) * uint64(stat.F_bsize) 182 self.Free = uint64(stat.F_bfree) * uint64(stat.F_bsize) 183 self.Avail = uint64(stat.F_bavail) * uint64(stat.F_bsize) 184 self.Used = self.Total - self.Free 185 self.Files = stat.F_files 186 self.FreeFiles = stat.F_ffree 187 188 return nil 189 } 190 191 func (self *FDUsage) Get() error { 192 return ErrNotImplemented{runtime.GOOS} 193 } 194 195 func (self *LoadAverage) Get() error { 196 avg := []C.double{0, 0, 0} 197 198 C.getloadavg(&avg[0], C.int(len(avg))) 199 200 self.One = float64(avg[0]) 201 self.Five = float64(avg[1]) 202 self.Fifteen = float64(avg[2]) 203 204 return nil 205 } 206 207 func (self *Uptime) Get() error { 208 tv := syscall.Timeval{} 209 mib := [2]int32{C.CTL_KERN, C.KERN_BOOTTIME} 210 211 n := uintptr(0) 212 // First we determine how much memory we'll need to pass later on (via `n`) 213 _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 214 215 if errno != 0 || n == 0 { 216 return nil 217 } 218 219 // Now perform the actual sysctl(3) call, storing the result in tv 220 _, _, errno = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, uintptr(unsafe.Pointer(&tv)), uintptr(unsafe.Pointer(&n)), 0, 0) 221 222 if errno != 0 || n == 0 { 223 return nil 224 } 225 226 self.Length = time.Since(time.Unix(int64(tv.Sec), int64(tv.Usec)*1000)).Seconds() 227 228 return nil 229 } 230 231 func (self *Mem) Get() error { 232 n := uintptr(0) 233 234 var uvmexp Uvmexp 235 mib := [2]int32{C.CTL_VM, C.VM_UVMEXP} 236 n = uintptr(0) 237 // First we determine how much memory we'll need to pass later on (via `n`) 238 _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 239 if errno != 0 || n == 0 { 240 return nil 241 } 242 243 _, _, errno = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, uintptr(unsafe.Pointer(&uvmexp)), uintptr(unsafe.Pointer(&n)), 0, 0) 244 if errno != 0 || n == 0 { 245 return nil 246 } 247 248 var bcachestats Bcachestats 249 mib3 := [3]int32{C.CTL_VFS, C.VFS_GENERIC, C.VFS_BCACHESTAT} 250 n = uintptr(0) 251 _, _, errno = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib3[0])), 3, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 252 if errno != 0 || n == 0 { 253 return nil 254 } 255 _, _, errno = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib3[0])), 3, uintptr(unsafe.Pointer(&bcachestats)), uintptr(unsafe.Pointer(&n)), 0, 0) 256 if errno != 0 || n == 0 { 257 return nil 258 } 259 260 self.Total = uint64(uvmexp.npages) << uvmexp.pageshift 261 self.Used = uint64(uvmexp.npages-uvmexp.free) << uvmexp.pageshift 262 self.Free = uint64(uvmexp.free) << uvmexp.pageshift 263 264 self.ActualFree = self.Free + (uint64(bcachestats.numbufpages) << uvmexp.pageshift) 265 self.ActualUsed = self.Used - (uint64(bcachestats.numbufpages) << uvmexp.pageshift) 266 267 return nil 268 } 269 270 func (self *Swap) Get() error { 271 nswap := C.swapctl(C.SWAP_NSWAP, unsafe.Pointer(uintptr(0)), 0) 272 273 // If there are no swap devices, nothing to do here. 274 if nswap == 0 { 275 return nil 276 } 277 278 swdev := make([]Swapent, nswap) 279 280 rnswap := C.swapctl(C.SWAP_STATS, unsafe.Pointer(&swdev[0]), nswap) 281 if rnswap == 0 { 282 return nil 283 } 284 285 for i := 0; i < int(nswap); i++ { 286 if swdev[i].se_flags&C.SWF_ENABLE == 2 { 287 self.Used = self.Used + uint64(swdev[i].se_inuse/(1024/C.DEV_BSIZE)) 288 self.Total = self.Total + uint64(swdev[i].se_nblks/(1024/C.DEV_BSIZE)) 289 } 290 } 291 292 self.Free = self.Total - self.Used 293 294 return nil 295 } 296 297 func (self *HugeTLBPages) Get() error { 298 return ErrNotImplemented{runtime.GOOS} 299 } 300 301 func (self *Cpu) Get() error { 302 load := [C.CPUSTATES]C.long{C.CP_USER, C.CP_NICE, C.CP_SYS, C.CP_INTR, C.CP_IDLE} 303 304 mib := [2]int32{C.CTL_KERN, C.KERN_CPTIME} 305 n := uintptr(0) 306 // First we determine how much memory we'll need to pass later on (via `n`) 307 _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 308 if errno != 0 || n == 0 { 309 return nil 310 } 311 312 _, _, errno = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, uintptr(unsafe.Pointer(&load)), uintptr(unsafe.Pointer(&n)), 0, 0) 313 if errno != 0 || n == 0 { 314 return nil 315 } 316 317 self.User = uint64(load[0]) 318 self.Nice = uint64(load[1]) 319 self.Sys = uint64(load[2]) 320 self.Irq = uint64(load[3]) 321 self.Idle = uint64(load[4]) 322 323 return nil 324 } 325 326 func (self *CpuList) Get() error { 327 mib := [2]int32{C.CTL_HW, C.HW_NCPU} 328 var ncpu int 329 330 n := uintptr(0) 331 // First we determine how much memory we'll need to pass later on (via `n`) 332 _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 333 334 if errno != 0 || n == 0 { 335 return nil 336 } 337 338 // Now perform the actual sysctl(3) call, storing the result in ncpu 339 _, _, errno = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 2, uintptr(unsafe.Pointer(&ncpu)), uintptr(unsafe.Pointer(&n)), 0, 0) 340 341 if errno != 0 || n == 0 { 342 return nil 343 } 344 345 load := [C.CPUSTATES]C.long{C.CP_USER, C.CP_NICE, C.CP_SYS, C.CP_INTR, C.CP_IDLE} 346 347 self.List = make([]Cpu, ncpu) 348 for curcpu := range self.List { 349 sysctlCptime(ncpu, curcpu, &load) 350 fillCpu(&self.List[curcpu], load) 351 } 352 353 return nil 354 } 355 356 func (self *ProcList) Get() error { 357 return nil 358 } 359 360 func (self *ProcArgs) Get(pid int) error { 361 return nil 362 } 363 364 func (self *ProcEnv) Get(pid int) error { 365 return ErrNotImplemented{runtime.GOOS} 366 } 367 368 func (self *ProcState) Get(pid int) error { 369 return nil 370 } 371 372 func (self *ProcMem) Get(pid int) error { 373 return nil 374 } 375 376 func (self *ProcTime) Get(pid int) error { 377 return ErrNotImplemented{runtime.GOOS} 378 } 379 380 func (self *ProcExe) Get(pid int) error { 381 return nil 382 } 383 384 func (self *ProcFDUsage) Get(pid int) error { 385 return ErrNotImplemented{runtime.GOOS} 386 } 387 388 func (self *Rusage) Get(pid int) error { 389 return ErrNotImplemented{runtime.GOOS} 390 } 391 392 func fillCpu(cpu *Cpu, load [C.CPUSTATES]C.long) { 393 cpu.User = uint64(load[0]) 394 cpu.Nice = uint64(load[1]) 395 cpu.Sys = uint64(load[2]) 396 cpu.Irq = uint64(load[3]) 397 cpu.Idle = uint64(load[4]) 398 } 399 400 func sysctlCptime(ncpu int, curcpu int, load *[C.CPUSTATES]C.long) error { 401 var mib []int32 402 403 // Use the correct mib based on the number of CPUs and fill out the 404 // current CPU number in case of SMP. (0 indexed cf. self.List) 405 if ncpu == 0 { 406 mib = []int32{C.CTL_KERN, C.KERN_CPTIME} 407 } else { 408 mib = []int32{C.CTL_KERN, C.KERN_CPTIME2, int32(curcpu)} 409 } 410 411 len := len(mib) 412 413 n := uintptr(0) 414 // First we determine how much memory we'll need to pass later on (via `n`) 415 _, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), uintptr(len), 0, uintptr(unsafe.Pointer(&n)), 0, 0) 416 if errno != 0 || n == 0 { 417 return nil 418 } 419 420 _, _, errno = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), uintptr(len), uintptr(unsafe.Pointer(load)), uintptr(unsafe.Pointer(&n)), 0, 0) 421 if errno != 0 || n == 0 { 422 return nil 423 } 424 425 return nil 426 }