Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isolated cpu parsing #427

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions fixtures.ttar
Expand Up @@ -6462,6 +6462,11 @@ Mode: 644
Directory: fixtures/sys/devices/system/cpu/cpufreq/policy1
Mode: 755
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Path: fixtures/sys/devices/system/cpu/isolated
Lines: 1
1,2-7,9
Mode: 664
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Directory: fixtures/sys/devices/system/node
Mode: 775
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down
49 changes: 49 additions & 0 deletions sysfs/system_cpu.go
Expand Up @@ -16,8 +16,11 @@
package sysfs

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

"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -237,3 +240,49 @@ func parseCpufreqCpuinfo(cpuPath string) (*SystemCPUCpufreqStats, error) {
SetSpeed: stringOut[4],
}, nil
}

func (fs FS) IsolatedCPUs() ([]uint16, error) {
isolcpus, err := ioutil.ReadFile(fs.sys.Path("devices/system/cpu/isolated"))
if err != nil {
return nil, fmt.Errorf("failed to read isolcpus from sysfs: %w", err)
}

return parseIsolCPUs(isolcpus)
}

func parseIsolCPUs(data []byte) ([]uint16, error) {
DavidVentura marked this conversation as resolved.
Show resolved Hide resolved

var isolcpusInt = []uint16{}

for _, cpu := range strings.Split(strings.TrimRight(string(data), "\n"), ",") {
if cpu == "" {
continue
}
if strings.Contains(cpu, "-") {
ranges := strings.Split(cpu, "-")
DavidVentura marked this conversation as resolved.
Show resolved Hide resolved
if len(ranges) != 2 {
return nil, fmt.Errorf("invalid cpu range: %s", cpu)
}
startRange, err := strconv.Atoi(ranges[0])
if err != nil {
return nil, fmt.Errorf("invalid cpu start range: %w", err)
}
endRange, err := strconv.Atoi(ranges[1])
if err != nil {
return nil, fmt.Errorf("invalid cpu end range: %w", err)
}

for i := startRange; i <= endRange; i++ {
isolcpusInt = append(isolcpusInt, uint16(i))
}
continue
}

cpuN, err := strconv.Atoi(cpu)
if err != nil {
return nil, err
}
isolcpusInt = append(isolcpusInt, uint16(cpuN))
}
return isolcpusInt, nil
}
49 changes: 49 additions & 0 deletions sysfs/system_cpu_test.go
Expand Up @@ -16,6 +16,7 @@
package sysfs

import (
"errors"
"reflect"
"testing"
)
Expand Down Expand Up @@ -140,3 +141,51 @@ func TestSystemCpufreq(t *testing.T) {
t.Errorf("Result not correct: want %v, have %v", systemCpufreq, c)
}
}

func TestIsolatedParsingCPU(t *testing.T) {
var testParams = []struct {
in []byte
res []uint16
err error
}{
{[]byte(""), []uint16{}, nil},
{[]byte("1\n"), []uint16{1}, nil},
{[]byte("1"), []uint16{1}, nil},
{[]byte("1,2"), []uint16{1, 2}, nil},
{[]byte("1-2"), []uint16{1, 2}, nil},
{[]byte("1-3"), []uint16{1, 2, 3}, nil},
{[]byte("1,2-4"), []uint16{1, 2, 3, 4}, nil},
{[]byte("1,3-4"), []uint16{1, 3, 4}, nil},
{[]byte("1,3-4,7,20-21"), []uint16{1, 3, 4, 7, 20, 21}, nil},
DavidVentura marked this conversation as resolved.
Show resolved Hide resolved

{[]byte("1,"), []uint16{1}, nil},
{[]byte("1,2-"), nil, errors.New(`invalid cpu end range: strconv.Atoi: parsing "": invalid syntax`)},
{[]byte("1,-3"), nil, errors.New(`invalid cpu start range: strconv.Atoi: parsing "": invalid syntax`)},
}
for _, params := range testParams {
t.Run("blabla", func(t *testing.T) {
res, err := parseIsolCPUs(params.in)
if !reflect.DeepEqual(res, params.res) {
t.Fatalf("should have %v result: got %v", params.res, res)
}
if err != nil && params.err != nil && err.Error() != params.err.Error() {
t.Fatalf("should have '%v' error: got '%v'", params.err, err)
}
if (err == nil || params.err == nil) && err != params.err {
t.Fatalf("should have %v error: got %v", params.err, err)
}

})
}
}
func TestIsolatedCPUs(t *testing.T) {
fs, err := NewFS(sysTestFixtures)
if err != nil {
t.Fatal(err)
}
isolated, err := fs.IsolatedCPUs()
expected := []uint16{1, 2, 3, 4, 5, 6, 7, 9}
if !reflect.DeepEqual(isolated, expected) {
t.Errorf("Result not correct: want %v, have %v", expected, isolated)
}
}