diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | cgswap.go | 97 |
3 files changed, 99 insertions, 0 deletions
@@ -1,5 +1,6 @@ *~ batterymon +cgswap chardiff chardiff_pre chardiff_post @@ -10,6 +10,7 @@ GOBUILD = go build BINFILES = \ batterymon \ + cgswap \ chardiff \ chardiff_pre \ chardiff_post \ diff --git a/cgswap.go b/cgswap.go new file mode 100644 index 0000000..3491f17 --- /dev/null +++ b/cgswap.go @@ -0,0 +1,97 @@ +package main + +import ( + "sync" + "fmt" + "os" + "bufio" + "strings" + "strconv" +) + +func handleErr(err error) { + if err != nil { + panic(err) + } +} + +type pidinfo struct { + VmSwap int + Cgroup string +} + +func in_array(needle string, haystack []string) bool { + for _, straw := range haystack { + if needle == straw { + return true + } + } + return false +} + +func main() { + dir, err := os.Open("/proc") + handleErr(err) + fileinfos, err := dir.Readdir(-1) + handleErr(err) + + ch := make(chan pidinfo) + dat := make(map[string]int) + var consumers sync.WaitGroup + consumers.Add(1) + go func() { + for info := range ch { + cur, _ := dat[info.Cgroup] + dat[info.Cgroup] = cur + info.VmSwap + } + consumers.Done() + }() + + var producers sync.WaitGroup + for _, fileinfo := range fileinfos { + if pid, err := strconv.Atoi(fileinfo.Name()); fileinfo.IsDir() && err == nil { + producers.Add(1) + go func(pid int) { + defer producers.Done() + statusFile, err := os.Open(fmt.Sprintf("/proc/%d/status", pid)) + if err != nil { + return + } + cgroupFile, err := os.Open(fmt.Sprintf("/proc/%d/cgroup", pid)) + + buf := bufio.NewScanner(statusFile) + for buf.Scan() { + line := buf.Text() + if strings.HasPrefix(line, "VmSwap:") { + swap, err := strconv.Atoi(strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(line, "VmSwap:"), "kB"))) + if err != nil || swap == 0 { + return + } + buf := bufio.NewScanner(cgroupFile) + for buf.Scan() { + parts := strings.SplitN(buf.Text(), ":", 3) + if len(parts) != 3 { + continue + } + heir := parts[0] + controllers := strings.Split(parts[1], ",") + cgroup := parts[2] + if heir == "0" || in_array("name=systemd", controllers) { + ch <- pidinfo{VmSwap: swap, Cgroup: cgroup} + return + } + } + return + } + } + }(pid) + } + } + producers.Wait() + close(ch) + consumers.Wait() + for cgroup, vmswap := range dat { + fmt.Println(vmswap, "kB", cgroup) + } +} +// grep VmSwap /proc/*/status|sed -rn 's|^/proc/([0-9]+)/status:VmSwap:\s*(\S+ \S+)$|\2 \1|p'|while read -r kb _ pid; do echo "$kb $(systemctl status "$pid"|head -n1|awk '{print $2}')"; done |