diff --git a/test/benchmarks/fs/rubydev_test.go b/test/benchmarks/fs/rubydev_test.go index fe1ec9988..ab53f3c2b 100644 --- a/test/benchmarks/fs/rubydev_test.go +++ b/test/benchmarks/fs/rubydev_test.go @@ -19,8 +19,6 @@ import ( "context" "fmt" "os" - "regexp" - "strconv" "strings" "testing" @@ -55,14 +53,6 @@ func BenchmarkRubyNoOpTest(b *testing.B) { }, nil) } -func extractLoadTime(output string) (float64, error) { - submatches := regexp.MustCompile(`files took (\d[\d,]*[\.]?[\d]*) seconds to load`).FindStringSubmatch(output) - if len(submatches) != 2 { - return 0, fmt.Errorf("count not find load time in output = %q", output) - } - return strconv.ParseFloat(submatches[1], 64) -} - // BenchmarkRubySpecTest runs a complex test suite from the Fastlane project: // https://github.com/fastlane/fastlane func BenchmarkRubySpecTest(b *testing.B) { @@ -72,12 +62,12 @@ func BenchmarkRubySpecTest(b *testing.B) { RunCmd: []string{"bash", "/files/run_fastlane_tests.sh"}, WantOutput: "3613 examples, 0 failures", Callback: func(b *testing.B, output string) { - loadTime, err := extractLoadTime(output) + loadTime, err := tools.ExtractRubyLoadTime(output) if err != nil { - b.Errorf("failed to extract load time from fastlane test suite output: %v", err) + b.Errorf("ExtractRubyLoadTime failed: %v", err) return } - tools.ReportCustomMetric(b, loadTime, "load", "sec") + tools.ReportCustomMetric(b, float64(loadTime.Nanoseconds()), "load", "ns") }, }, []string{ // Fastlane tests pollute the filesystem a lot. diff --git a/test/benchmarks/tools/BUILD b/test/benchmarks/tools/BUILD index da6c6889d..0c3314a8d 100644 --- a/test/benchmarks/tools/BUILD +++ b/test/benchmarks/tools/BUILD @@ -17,6 +17,7 @@ go_library( "meminfo.go", "parser_util.go", "redis.go", + "rubydev.go", "sysbench.go", "tools.go", ], diff --git a/test/benchmarks/tools/rubydev.go b/test/benchmarks/tools/rubydev.go new file mode 100644 index 000000000..b54c31bac --- /dev/null +++ b/test/benchmarks/tools/rubydev.go @@ -0,0 +1,67 @@ +// Copyright 2020 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tools + +import ( + "fmt" + "regexp" + "strconv" + "time" +) + +// ExtractRubyTestTime extracts the test time from fastlane ruby test output. +func ExtractRubyTestTime(output string) (time.Duration, error) { + testTime, err := extractRubyTime("Finished in ", ` \(files took`, output) + if err != nil { + return 0, fmt.Errorf("failed to extract test time: %v, output=\n%s", err, output) + } + return testTime, nil +} + +// ExtractRubyLoadTime extracts the load time from fastlane ruby test output. +func ExtractRubyLoadTime(output string) (time.Duration, error) { + loadTime, err := extractRubyTime(`\(files took `, ` to load\)`, output) + if err != nil { + return 0, fmt.Errorf("failed to extract load time: %v, output=\n%s", err, output) + } + return loadTime, nil +} + +// extractRubyTime extracts the time from s in the format ([x] minutes [y] seconds) +// where minutes may be optional. It returns the time in seconds. No commas are +// expected in the numbers. +func extractRubyTime(prefix, suffix, s string) (time.Duration, error) { + submatches := regexp.MustCompile(prefix + `(\d+) minute[s]? (\d+[\.]?[\d]*) second[s]?` + suffix).FindStringSubmatch(s) + if len(submatches) == 3 { + mins, err := strconv.ParseInt(submatches[1], 10, 64) + if err != nil { + return 0, fmt.Errorf("failed to parse minutes: %v, prefix = %q, suffix = %q", err, prefix, suffix) + } + secs, err := strconv.ParseFloat(submatches[2], 64) + if err != nil { + return 0, fmt.Errorf("failed to parse seconds: %v, prefix = %q, suffix = %q", err, prefix, suffix) + } + return (time.Minute * time.Duration(mins)) + time.Duration(float64(time.Second)*secs), nil + } + submatches = regexp.MustCompile(prefix + `(\d+[\.]?[\d]*) second[s]?` + suffix).FindStringSubmatch(s) + if len(submatches) == 2 { + secs, err := strconv.ParseFloat(submatches[1], 64) + if err != nil { + return 0, fmt.Errorf("failed to parse seconds: %v, prefix = %q, suffix = %q", err, prefix, suffix) + } + return time.Duration(float64(time.Second) * secs), nil + } + return 0, fmt.Errorf("count not find prefix = %q and suffix = %q", prefix, suffix) +}