summaryrefslogtreecommitdiff
path: root/cgswap.go
blob: 3491f176bcc499e5ab1aaaa06b8f1693d8ba5b20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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