| 29 | } |
| 30 | |
| 31 | func vm_stat() (bytesFree, bytesInactive uint64, err error) { |
| 32 | type memStat struct { |
| 33 | regex *regexp.Regexp |
| 34 | value uint64 |
| 35 | valid bool |
| 36 | } |
| 37 | |
| 38 | stats := map[string]*memStat{ |
| 39 | "pageSize": {regex: regexp.MustCompile("page size of (\\d+) bytes")}, |
| 40 | "pagesFree": {regex: regexp.MustCompile("Pages free: *(\\d+).")}, |
| 41 | "pagesInactive": {regex: regexp.MustCompile("Pages inactive: *(\\d+).")}, |
| 42 | } |
| 43 | |
| 44 | cmd := exec.Command("vm_stat") |
| 45 | out, err := cmd.Output() |
| 46 | if err != nil { |
| 47 | return 0, 0, err |
| 48 | } |
| 49 | |
| 50 | // Parse lines in vm_stat output |
| 51 | lines := bytes.Split(out, []byte("\n")) |
| 52 | for _, line := range lines { |
| 53 | for _, stat := range stats { |
| 54 | match := stat.regex.FindSubmatch(line) |
| 55 | if match == nil { |
| 56 | continue |
| 57 | } |
| 58 | |
| 59 | stat.value, err = strconv.ParseUint(string(match[1]), 10, 64) |
| 60 | if err != nil { |
| 61 | return 0, 0, err |
| 62 | } |
| 63 | stat.valid = true |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | // Check every stat is found in output |
| 68 | for _, stat := range stats { |
| 69 | if !stat.valid { |
| 70 | return 0, 0, errors.New("cannot parse vm_stat output") |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | pageSize := stats["pageSize"].value |
| 75 | return pageSize * stats["pagesFree"].value, pageSize * stats["pagesInactive"].value, nil |
| 76 | } |
| 77 | |
| 78 | // generic Sysctl buffer unmarshalling |
| 79 | func sysctlbyname(name string, data interface{}) (err error) { |