Files
kopia/tests/perf_benchmark/process_results.go
Eng Zer Jun c3f4c41591 refactor: move from ioutil.ReadDir to os.ReadDir (#1361)
* refactor: move from ioutil.ReadDir to os.ReadDir

This commit is an addition to PR #1360. According to
`ioutil.ReadDir` documentation (https://pkg.go.dev/io/ioutil#ReadDir),
`os.ReadDir` should be preferred as it is a more efficient and correct
implementation.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>

* perf: optimize localfs scan performance

Reference: https://github.com/kopia/kopia/pull/1361#issuecomment-937345195
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2021-11-04 16:57:24 -07:00

171 lines
3.4 KiB
Go

package main
import (
"bufio"
"fmt"
"log"
"os"
"regexp"
"strconv"
"strings"
"github.com/pkg/errors"
)
var (
psrecordRegex = regexp.MustCompile(`psrecord-(.*)-(initial|second)-(.*).log`)
reposizeRegex = regexp.MustCompile(`repo-size-(.*?)-(.*).log`)
)
type processStats struct {
duration float64
avgCPU float64
avgRAM float64
maxCPU float64
maxRAM float64
}
var (
processStatsByScenarioAndVersion = map[string]map[string]processStats{}
repoSizeByScenarioArndVersion = map[string]map[string]int64{}
)
// getProcessStats parses psrecord log file and computes statistics.
func getProcessStats(fname string) (processStats, error) {
f, err := os.Open(fname) //nolint:gosec
if err != nil {
return processStats{}, err
}
defer f.Close() //nolint:errcheck,gosec
s := bufio.NewScanner(f)
s.Scan() // skip first line
var (
ps processStats
totalCPUUsage float64
totalRAMUsage float64
maxCPUUsage float64
maxRAMUsage float64
sampleCount float64
)
for s.Scan() {
fields := strings.Fields(s.Text())
ts, err := strconv.ParseFloat(fields[0], 64)
if err != nil {
return ps, errors.Wrap(err, "error parsing time")
}
cpuUsage, err := strconv.ParseFloat(fields[1], 64)
if err != nil {
return ps, errors.Wrap(err, "error parsing cpu")
}
totalCPUUsage += cpuUsage
if cpuUsage > maxCPUUsage {
maxCPUUsage = cpuUsage
}
ramUsage, err := strconv.ParseFloat(fields[2], 64)
if err != nil {
return ps, errors.Wrap(err, "error parsing ram")
}
totalRAMUsage += ramUsage
if ramUsage > maxRAMUsage {
maxRAMUsage = ramUsage
}
sampleCount++
ps.duration = ts
}
if sampleCount > 0 {
ps.maxCPU = maxCPUUsage
ps.maxRAM = maxRAMUsage
ps.avgCPU = totalCPUUsage / sampleCount
ps.avgRAM = totalRAMUsage / sampleCount
}
return ps, nil
}
func parseRepoSize(fname string) (int64, error) {
f, err := os.Open(fname) //nolint:gosec
if err != nil {
return 0, err
}
defer f.Close() //nolint:errcheck,gosec
s := bufio.NewScanner(f)
s.Scan()
fields := strings.Fields(s.Text())
if len(fields) != 2 {
return 0, errors.Errorf("unvalid repo size format")
}
return strconv.ParseInt(fields[0], 10, 64)
}
func main() {
files, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, f := range files {
if m := psrecordRegex.FindStringSubmatch(f.Name()); m != nil {
version := m[1]
phase := m[2]
scenario := m[3]
ps, err := getProcessStats(f.Name())
if err != nil {
log.Fatalf("err: %v", err)
}
if phase == "initial" {
ss := processStatsByScenarioAndVersion[scenario]
if ss == nil {
ss = map[string]processStats{}
processStatsByScenarioAndVersion[scenario] = ss
}
ss[version] = ps
}
}
if m := reposizeRegex.FindStringSubmatch(f.Name()); m != nil {
version := m[1]
scenario := m[2]
rs, err := parseRepoSize(f.Name())
if err != nil {
log.Fatalf("unable to parse repo size: %v", err)
}
ss := repoSizeByScenarioArndVersion[scenario]
if ss == nil {
ss = map[string]int64{}
repoSizeByScenarioArndVersion[scenario] = ss
}
ss[version] = rs
}
}
for scenario, results := range processStatsByScenarioAndVersion {
for ver, ps := range results {
rs := repoSizeByScenarioArndVersion[scenario][ver]
fmt.Printf("%v,%v,%v,%v,%v,%v,%v,%v\n", scenario, ver, ps.duration, ps.avgCPU, ps.maxCPU, ps.avgRAM, ps.maxRAM, rs)
}
}
}