From 494f900e917abfea0906644285f37aa55316c686 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Fri, 19 Feb 2021 02:10:51 -0800 Subject: [PATCH] libct/cg/fscommon: rename/facelift GetCgroupParamKeyValue 1. This is the only function in the package with Get prefix that does not read a file (but parses a string). Rename accordingly, and convert the callers. GetCgroupParamKeyValue -> ParseKeyValue 2. Use strings.Split rather than strings.Fields. Split by a space is 2x faster, plus we can limit the splitting. The downside is we have to strip a newline in one of the callers. 3. Improve the doc and the code flow. 4. Fix a test case with invalid data (spaces at BOL). Signed-off-by: Kir Kolyshkin --- libcontainer/cgroups/fs/cpu.go | 2 +- libcontainer/cgroups/fs/cpu_test.go | 2 +- libcontainer/cgroups/fs/memory.go | 2 +- libcontainer/cgroups/fs2/cpu.go | 2 +- libcontainer/cgroups/fs2/hugetlb.go | 3 ++- libcontainer/cgroups/fs2/memory.go | 2 +- libcontainer/cgroups/fscommon/utils.go | 30 +++++++++++++------------- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/libcontainer/cgroups/fs/cpu.go b/libcontainer/cgroups/fs/cpu.go index 1d5f455d6..194f3a542 100644 --- a/libcontainer/cgroups/fs/cpu.go +++ b/libcontainer/cgroups/fs/cpu.go @@ -97,7 +97,7 @@ func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error { sc := bufio.NewScanner(f) for sc.Scan() { - t, v, err := fscommon.GetCgroupParamKeyValue(sc.Text()) + t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { return err } diff --git a/libcontainer/cgroups/fs/cpu_test.go b/libcontainer/cgroups/fs/cpu_test.go index 4a8ecf995..9adc9b31c 100644 --- a/libcontainer/cgroups/fs/cpu_test.go +++ b/libcontainer/cgroups/fs/cpu_test.go @@ -112,7 +112,7 @@ func TestCpuStats(t *testing.T) { throttledTime = uint64(18446744073709551615) ) - cpuStatContent := fmt.Sprintf("nr_periods %d\n nr_throttled %d\n throttled_time %d\n", + cpuStatContent := fmt.Sprintf("nr_periods %d\nnr_throttled %d\nthrottled_time %d\n", nrPeriods, nrThrottled, throttledTime) helper.writeFileContents(map[string]string{ "cpu.stat": cpuStatContent, diff --git a/libcontainer/cgroups/fs/memory.go b/libcontainer/cgroups/fs/memory.go index 9b521fe26..5d52d3257 100644 --- a/libcontainer/cgroups/fs/memory.go +++ b/libcontainer/cgroups/fs/memory.go @@ -188,7 +188,7 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { sc := bufio.NewScanner(statsFile) for sc.Scan() { - t, v, err := fscommon.GetCgroupParamKeyValue(sc.Text()) + t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err) } diff --git a/libcontainer/cgroups/fs2/cpu.go b/libcontainer/cgroups/fs2/cpu.go index 0dffe6648..b7331338f 100644 --- a/libcontainer/cgroups/fs2/cpu.go +++ b/libcontainer/cgroups/fs2/cpu.go @@ -57,7 +57,7 @@ func statCpu(dirPath string, stats *cgroups.Stats) error { sc := bufio.NewScanner(f) for sc.Scan() { - t, v, err := fscommon.GetCgroupParamKeyValue(sc.Text()) + t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { return err } diff --git a/libcontainer/cgroups/fs2/hugetlb.go b/libcontainer/cgroups/fs2/hugetlb.go index 18cd411ce..deeee34c5 100644 --- a/libcontainer/cgroups/fs2/hugetlb.go +++ b/libcontainer/cgroups/fs2/hugetlb.go @@ -4,6 +4,7 @@ package fs2 import ( "strconv" + "strings" "github.com/pkg/errors" @@ -48,7 +49,7 @@ func statHugeTlb(dirPath string, stats *cgroups.Stats) error { if err != nil { return errors.Wrap(err, "failed to read stats") } - _, value, err = fscommon.GetCgroupParamKeyValue(contents) + _, value, err = fscommon.ParseKeyValue(strings.TrimSuffix(contents, "\n")) if err != nil { return errors.Wrap(err, "failed to parse "+fileName) } diff --git a/libcontainer/cgroups/fs2/memory.go b/libcontainer/cgroups/fs2/memory.go index 81b28df75..cc8eaeb2e 100644 --- a/libcontainer/cgroups/fs2/memory.go +++ b/libcontainer/cgroups/fs2/memory.go @@ -82,7 +82,7 @@ func statMemory(dirPath string, stats *cgroups.Stats) error { sc := bufio.NewScanner(statsFile) for sc.Scan() { - t, v, err := fscommon.GetCgroupParamKeyValue(sc.Text()) + t, v, err := fscommon.ParseKeyValue(sc.Text()) if err != nil { return errors.Wrapf(err, "failed to parse memory.stat (%q)", sc.Text()) } diff --git a/libcontainer/cgroups/fscommon/utils.go b/libcontainer/cgroups/fscommon/utils.go index 2e4e837f2..235c98859 100644 --- a/libcontainer/cgroups/fscommon/utils.go +++ b/libcontainer/cgroups/fscommon/utils.go @@ -35,22 +35,22 @@ func ParseUint(s string, base, bitSize int) (uint64, error) { return value, nil } -// GetCgroupParamKeyValue parses a space-separated "name value" kind of cgroup -// parameter and returns its components. For example, "io_service_bytes 1234" -// will return as "io_service_bytes", 1234. -func GetCgroupParamKeyValue(t string) (string, uint64, error) { - parts := strings.Fields(t) - switch len(parts) { - case 2: - value, err := ParseUint(parts[1], 10, 64) - if err != nil { - return "", 0, fmt.Errorf("unable to convert to uint64: %v", err) - } - - return parts[0], value, nil - default: - return "", 0, ErrNotValidFormat +// ParseKeyValue parses a space-separated "name value" kind of cgroup +// parameter and returns its key as a string, and its value as uint64 +// (ParseUint is used to convert the value). For example, +// "io_service_bytes 1234" will be returned as "io_service_bytes", 1234. +func ParseKeyValue(t string) (string, uint64, error) { + parts := strings.SplitN(t, " ", 3) + if len(parts) != 2 { + return "", 0, fmt.Errorf("line %q is not in key value format", t) } + + value, err := ParseUint(parts[1], 10, 64) + if err != nil { + return "", 0, fmt.Errorf("unable to convert to uint64: %v", err) + } + + return parts[0], value, nil } // GetCgroupParamUint reads a single uint64 value from the specified cgroup file.