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

Bringing number of syscalls down in fs.getDistStatsMap() #3348

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 85 additions & 48 deletions fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
package fs

import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"os/exec"
"path"
Expand Down Expand Up @@ -58,6 +59,9 @@ const (
// A pool for restricting the number of consecutive `du` and `find` tasks running.
var pool = make(chan struct{}, maxConcurrentOps)

// bufSize control size of read buffer in getDiskStatsMap()
var bufSize = 5000

func init() {
for i := 0; i < maxConcurrentOps; i++ {
releaseToken()
Expand Down Expand Up @@ -504,67 +508,100 @@ func getDiskStatsMap(diskStatsFile string) (map[string]DiskStats, error) {
}

defer file.Close()
scanner := bufio.NewScanner(file)

for scanner.Scan() {
line := scanner.Text()
words := strings.Fields(line)
if !partitionRegex.MatchString(words[2]) {
continue
leftover := []byte{}
const newline = 10
for {
buf := make([]byte, bufSize)
count, err := file.Read(buf)
buf = append(leftover, bytes.Trim(buf, "\x00")...)
klog.V(10).Infof("read %d bytes in getDiskStatsMap()", count)
if err == io.EOF {
break
}
lines := bytes.Split(buf, []byte{newline})
var skipLastLine bool
if buf[len(buf)-1] != newline {
skipLastLine = true
}
// 8 50 sdd2 40 0 280 223 7 0 22 108 0 330 330
deviceName := path.Join("/dev", words[2])

var err error
devInfo := make([]uint64, 2)
for i := 0; i < len(devInfo); i++ {
devInfo[i], err = strconv.ParseUint(words[i], 10, 64)
for i, bLine := range lines {
if len(bLine) == 0 {
klog.V(10).Infof("skipping empty line in getDiskStatsMap() iteration %d", i)
continue
}
if skipLastLine && i == len(lines)-1 {
klog.V(10).Infof("skipping leftover line in getDiskStatsMap() iteration %d", i)
continue
}
line := string(bLine)
words := strings.Fields(line)

if !partitionRegex.MatchString(words[2]) {
continue
}
// 8 50 sdd2 40 0 280 223 7 0 22 108 0 330 330
deviceName := path.Join("/dev", words[2])

var err error
devInfo := make([]uint64, 2)
for i := 0; i < len(devInfo); i++ {
devInfo[i], err = strconv.ParseUint(words[i], 10, 64)
if err != nil {
return nil, err
}
}

wordLength := len(words)
offset := 3
var stats = make([]uint64, wordLength-offset)
if len(stats) < 11 {
return nil, fmt.Errorf("could not parse all 11 columns of /proc/diskstats")
}
for i := offset; i < wordLength; i++ {
stats[i-offset], err = strconv.ParseUint(words[i], 10, 64)
if err != nil {
return nil, err
}
}

major64, err := strconv.ParseUint(words[0], 10, 64)
if err != nil {
return nil, err
}
}

wordLength := len(words)
offset := 3
var stats = make([]uint64, wordLength-offset)
if len(stats) < 11 {
return nil, fmt.Errorf("could not parse all 11 columns of /proc/diskstats")
}
for i := offset; i < wordLength; i++ {
stats[i-offset], err = strconv.ParseUint(words[i], 10, 64)
minor64, err := strconv.ParseUint(words[1], 10, 64)
if err != nil {
return nil, err
}

diskStats := DiskStats{
MajorNum: devInfo[0],
MinorNum: devInfo[1],
ReadsCompleted: stats[0],
ReadsMerged: stats[1],
SectorsRead: stats[2],
ReadTime: stats[3],
WritesCompleted: stats[4],
WritesMerged: stats[5],
SectorsWritten: stats[6],
WriteTime: stats[7],
IoInProgress: stats[8],
IoTime: stats[9],
WeightedIoTime: stats[10],
Major: major64,
Minor: minor64,
}
diskStatsMap[deviceName] = diskStats
}

major64, err := strconv.ParseUint(words[0], 10, 64)
if err != nil {
return nil, err
if buf[len(buf)-1] != newline {
leftover = lines[len(lines)-1]
klog.V(10).Info("saving leftover line %q", leftover)
} else {
leftover = []byte{}
}

minor64, err := strconv.ParseUint(words[1], 10, 64)
if err != nil {
return nil, err
}

diskStats := DiskStats{
MajorNum: devInfo[0],
MinorNum: devInfo[1],
ReadsCompleted: stats[0],
ReadsMerged: stats[1],
SectorsRead: stats[2],
ReadTime: stats[3],
WritesCompleted: stats[4],
WritesMerged: stats[5],
SectorsWritten: stats[6],
WriteTime: stats[7],
IoInProgress: stats[8],
IoTime: stats[9],
WeightedIoTime: stats[10],
Major: major64,
Minor: minor64,
}
diskStatsMap[deviceName] = diskStats
}
return diskStatsMap, nil
}
Expand Down
9 changes: 9 additions & 0 deletions fs/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func TestMountInfoFromDir(t *testing.T) {
}

func TestGetDiskStatsMap(t *testing.T) {
origBufSize := bufSize
bufSize = 100
defer func() { bufSize = origBufSize }()
diskStatsMap, err := getDiskStatsMap("test_resources/diskstats")
if err != nil {
t.Errorf("Error calling getDiskStatsMap %s", err)
Expand Down Expand Up @@ -92,6 +95,9 @@ func TestGetDiskStatsMap(t *testing.T) {
}

func TestGetDiskStatsMapMajorMinorNum(t *testing.T) {
origBufSize := bufSize
bufSize = 100
defer func() { bufSize = origBufSize }()
diskStatsMap, err := getDiskStatsMap("test_resources/diskstats")
if err != nil {
t.Errorf("Error calling getDiskStatsMap %s", err)
Expand All @@ -108,6 +114,9 @@ func TestGetDiskStatsMapMajorMinorNum(t *testing.T) {
}

func TestFileNotExist(t *testing.T) {
origBufSize := bufSize
bufSize = 100
defer func() { bufSize = origBufSize }()
_, err := getDiskStatsMap("/file_does_not_exist")
if err != nil {
t.Fatalf("getDiskStatsMap must not error for absent file: %s", err)
Expand Down
Loading