libct/cg/dev: optimize and test findDeviceGroup

1. Use strings.TrimPrefix instead of fmt.Sscanf and simplify the code.

2. Add a test case and a benchmark.

The benchmark shows some improvement, compared to the old
implementation:

name               old time/op    new time/op    delta
FindDeviceGroup-4    39.7µs ± 2%    26.8µs ± 2%  -32.63%  (p=0.008 n=5+5)

name               old alloc/op   new alloc/op   delta
FindDeviceGroup-4    6.08kB ± 0%    4.23kB ± 0%  -30.39%  (p=0.008 n=5+5)

name               old allocs/op  new allocs/op  delta
FindDeviceGroup-4       117 ± 0%         6 ± 0%  -94.87%  (p=0.008 n=5+5)

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2022-01-27 19:23:18 -08:00
parent 39fe1c39fc
commit defb1cc718
2 changed files with 32 additions and 15 deletions
+5 -15
View File
@@ -2,9 +2,9 @@ package devices
import (
"bufio"
"errors"
"fmt"
"os"
"strconv"
"strings"
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
@@ -181,6 +181,7 @@ func findDeviceGroup(ruleType devices.Type, ruleMajor int64) (string, error) {
if err != nil {
return "", err
}
ruleMajorStr := strconv.FormatInt(ruleMajor, 10) + " "
scanner := bufio.NewScanner(fh)
var currentType devices.Type
@@ -205,20 +206,9 @@ func findDeviceGroup(ruleType devices.Type, ruleMajor int64) (string, error) {
continue
}
// Parse out the (major, name).
var (
currMajor int64
currName string
)
if n, err := fmt.Sscanf(line, "%d %s", &currMajor, &currName); err != nil || n != 2 {
if err == nil {
err = errors.New("wrong number of fields")
}
return "", fmt.Errorf("scan /proc/devices line %q: %w", line, err)
}
if currMajor == ruleMajor {
return prefix + currName, nil
group := strings.TrimPrefix(line, ruleMajorStr)
if len(group) < len(line) { // got it
return prefix + group, nil
}
}
if err := scanner.Err(); err != nil {
@@ -2,6 +2,7 @@ package devices
import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
@@ -240,6 +241,32 @@ func TestSkipDevicesFalse(t *testing.T) {
})
}
func testFindDeviceGroup() error {
const (
major = 136
group = "char-pts"
)
res, err := findDeviceGroup(devices.CharDevice, major)
if res != group || err != nil {
return fmt.Errorf("expected %v, nil, got %v, %w", group, res, err)
}
return nil
}
func TestFindDeviceGroup(t *testing.T) {
if err := testFindDeviceGroup(); err != nil {
t.Fatal(err)
}
}
func BenchmarkFindDeviceGroup(b *testing.B) {
for i := 0; i < b.N; i++ {
if err := testFindDeviceGroup(); err != nil {
b.Fatal(err)
}
}
}
func newManager(t *testing.T, config *configs.Cgroup) (m cgroups.Manager) {
t.Helper()
var err error