blkio.go 3.46 KB
Newer Older
“李磊”'s avatar
“李磊” committed
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package fs

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"linkfog.com/public/lib/cgroup/types"
	"linkfog.com/public/lib/l"
)

func IOSubSystemName() string {
	return "blkio"
}

func SetIORWLimit(cgroupDir string, devinfos []types.DevInfo, rlimit, wlimit uint64) (map[string]*types.DevLimit, error) {
	ioRdLimitPath := path.Join(cgroupDir, "blkio.throttle.read_bps_device")
	ioWrLimitPath := path.Join(cgroupDir, "blkio.throttle.write_bps_device")
	l.Infof("io read limit path: %s, limit size: %d", ioRdLimitPath, rlimit)
	l.Infof("io write limit path: %s, limit size: %d", ioWrLimitPath, wlimit)
	fr, err := os.OpenFile(ioRdLimitPath, os.O_WRONLY|os.O_CREATE, 0)
	if err != nil {
		return nil, err
	}
	defer fr.Close()
	fw, err := os.OpenFile(ioWrLimitPath, os.O_WRONLY|os.O_CREATE, 0)
	if err != nil {
		return nil, err
	}
	defer fw.Close()

	devLmts := make(map[string]*types.DevLimit, 0)
	ioRdLimitSuccCnt := 0
	ioWrLimitSuccCnt := 0
	for _, devinfo := range devinfos {
		devKey := fmt.Sprintf("%s:%s", devinfo.Major, devinfo.Minor)
		devLmts[devKey] = &types.DevLimit{
			DevName: devinfo.Name,
			RdLimit: false,
			WrLimit: false,
		}

		rlimitStr := fmt.Sprintf("%s:%s %d", devinfo.Major, devinfo.Minor, rlimit)
		wlimitStr := fmt.Sprintf("%s:%s %d", devinfo.Major, devinfo.Minor, wlimit)

		// set io read limit
		_, err := fr.WriteString(rlimitStr)
		if err != nil {
			l.Debugf("set %s io read limit error %v, config:%s", devinfo.Name, err, rlimitStr)
		} else {
			devLmts[devKey].RdLimit = true
			ioRdLimitSuccCnt++
			l.Debugf("set %s io read limit success, config:%s", devinfo.Name, rlimitStr)
		}

		// set io write limit
		_, err = fw.WriteString(wlimitStr)
		if err != nil {
			l.Debugf("set %s io write limit error %v, config:%s", devinfo.Name, err, wlimitStr)
		} else {
			devLmts[devKey].WrLimit = true
			ioWrLimitSuccCnt++
			l.Debugf("set %s io write limit success, config:%s", devinfo.Name, wlimitStr)
		}
	}
	if ioRdLimitSuccCnt == 0 || ioWrLimitSuccCnt == 0 {
		return nil, fmt.Errorf("set io limit error, read_limit:%d, write_limit:%d",
			ioRdLimitSuccCnt, ioWrLimitSuccCnt)
	}

	return devLmts, nil
}

// #cat blkio.throttle.io_service_bytes
// 8:0 Read 5829550080
// 8:0 Write 4474982400
// 8:0 Sync 4415606784
// 8:0 Async 5888925696
// 8:0 Total 10304532480
// Total 10304532480
func GetAllDevIOStat(cgroupDir string) (map[string]*types.IOStat, error) {
	data, err := os.ReadFile(filepath.Join(cgroupDir, "blkio.throttle.io_service_bytes"))
	if err != nil {
		return nil, err
	}

	ioStats := make(map[string]*types.IOStat, 0)
	ioStats["total"] = &types.IOStat{}
	for _, line := range strings.Split(string(data), "\n") {
		line = strings.TrimSpace(line)
		// line content: 8:0 Read 8433958912
		fields := strings.Split(line, " ")
		if len(fields) != 3 {
			continue
		}
		device := fields[0]
		event := fields[1]
		size := fields[2]

		if event == "Read" || event == "Write" {
			sizeUint64, err := strconv.ParseUint(size, 10, 64)
			if err != nil {
				return ioStats, fmt.Errorf("unable to convert size to uint64: %s", err)
			}

			if _, ok := ioStats[device]; !ok {
				ioStats[device] = &types.IOStat{}
			}
			if event == "Read" {
				ioStats[device].Read = sizeUint64
				ioStats["total"].Read += sizeUint64
			}
			if event == "Write" {
				ioStats[device].Write = sizeUint64
				ioStats["total"].Write += sizeUint64
			}
		}
	}
	return ioStats, nil
}