2017-03-20 05:13:22 +08:00
|
|
|
// +build darwin
|
|
|
|
// +build cgo
|
|
|
|
|
|
|
|
package disk
|
|
|
|
|
|
|
|
/*
|
2017-07-28 06:16:27 +08:00
|
|
|
#cgo LDFLAGS: -lobjc -framework Foundation -framework IOKit
|
2017-03-20 05:13:22 +08:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
// ### enough?
|
|
|
|
const int MAX_DISK_NAME = 100;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
char DiskName[MAX_DISK_NAME];
|
|
|
|
int64_t Reads;
|
|
|
|
int64_t Writes;
|
|
|
|
int64_t ReadBytes;
|
|
|
|
int64_t WriteBytes;
|
|
|
|
int64_t ReadTime;
|
|
|
|
int64_t WriteTime;
|
|
|
|
} DiskInfo;
|
|
|
|
|
|
|
|
#include "disk_darwin.h"
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"strings"
|
|
|
|
"unsafe"
|
2017-04-08 02:40:49 +08:00
|
|
|
|
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
2017-03-20 05:13:22 +08:00
|
|
|
)
|
|
|
|
|
2017-04-14 09:53:09 +08:00
|
|
|
func IOCounters(names ...string) (map[string]IOCountersStat, error) {
|
2017-03-20 05:13:22 +08:00
|
|
|
if C.StartIOCounterFetch() == 0 {
|
|
|
|
return nil, errors.New("Unable to fetch disk list")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clean up when we are done.
|
|
|
|
defer C.EndIOCounterFetch()
|
|
|
|
ret := make(map[string]IOCountersStat, 0)
|
|
|
|
|
|
|
|
for {
|
|
|
|
res := C.FetchNextDisk()
|
|
|
|
if res == -1 {
|
|
|
|
return nil, errors.New("Unable to fetch disk information")
|
|
|
|
} else if res == 0 {
|
|
|
|
break // done
|
|
|
|
}
|
|
|
|
|
|
|
|
di := C.DiskInfo{}
|
|
|
|
if C.ReadDiskInfo((*C.DiskInfo)(unsafe.Pointer(&di))) == -1 {
|
|
|
|
return nil, errors.New("Unable to fetch disk properties")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used to only get the necessary part of the C string.
|
|
|
|
isRuneNull := func(r rune) bool {
|
|
|
|
return r == '\u0000'
|
|
|
|
}
|
|
|
|
|
|
|
|
// Map from the darwin-specific C struct to the Go type
|
|
|
|
//
|
|
|
|
// ### missing: IopsInProgress, WeightedIO, MergedReadCount,
|
|
|
|
// MergedWriteCount, SerialNumber
|
|
|
|
// IOKit can give us at least the serial number I think...
|
|
|
|
d := IOCountersStat{
|
|
|
|
// Note: The Go type wants unsigned values, but CFNumberGetValue
|
|
|
|
// doesn't appear to be able to give us unsigned values. So, we
|
|
|
|
// cast, and hope for the best.
|
|
|
|
ReadBytes: uint64(di.ReadBytes),
|
|
|
|
WriteBytes: uint64(di.WriteBytes),
|
|
|
|
ReadCount: uint64(di.Reads),
|
|
|
|
WriteCount: uint64(di.Writes),
|
|
|
|
ReadTime: uint64(di.ReadTime),
|
|
|
|
WriteTime: uint64(di.WriteTime),
|
|
|
|
IoTime: uint64(di.ReadTime + di.WriteTime),
|
|
|
|
Name: strings.TrimFunc(C.GoStringN(&di.DiskName[0], C.MAX_DISK_NAME), isRuneNull),
|
|
|
|
}
|
|
|
|
|
2017-04-08 02:40:49 +08:00
|
|
|
if len(names) > 0 && !common.StringsHas(names, d.Name) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2017-03-20 05:13:22 +08:00
|
|
|
ret[d.Name] = d
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
|
|
|
}
|