From b63b4d6f366e06b15986ee31cd8c3c329ecdf4c1 Mon Sep 17 00:00:00 2001 From: Chen Hui Date: Wed, 14 Sep 2022 10:21:28 +0800 Subject: [PATCH] benchmarks: add hackbench benchmark for scheduler performance Signed-off-by: Chen Hui --- images/benchmarks/hackbench/Dockerfile | 6 ++ test/benchmarks/base/BUILD | 11 ++++ test/benchmarks/base/hackbench_test.go | 89 ++++++++++++++++++++++++++ test/benchmarks/tools/BUILD | 1 + test/benchmarks/tools/hackbench.go | 68 ++++++++++++++++++++ 5 files changed, 175 insertions(+) create mode 100644 images/benchmarks/hackbench/Dockerfile create mode 100644 test/benchmarks/base/hackbench_test.go create mode 100644 test/benchmarks/tools/hackbench.go diff --git a/images/benchmarks/hackbench/Dockerfile b/images/benchmarks/hackbench/Dockerfile new file mode 100644 index 000000000..d1a2d1659 --- /dev/null +++ b/images/benchmarks/hackbench/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:18.04 + +RUN set -x \ + && apt-get update \ + && apt-get install -y rt-tests \ + && rm -rf /var/lib/apt/lists/* diff --git a/test/benchmarks/base/BUILD b/test/benchmarks/base/BUILD index 16d25bd5f..2572fefcb 100644 --- a/test/benchmarks/base/BUILD +++ b/test/benchmarks/base/BUILD @@ -59,3 +59,14 @@ benchmark_test( "//test/benchmarks/tools", ], ) + +benchmark_test( + name = "hackbench_test", + srcs = ["hackbench_test.go"], + visibility = ["//:sandbox"], + deps = [ + "//pkg/test/dockerutil", + "//test/benchmarks/harness", + "//test/benchmarks/tools", + ], +) diff --git a/test/benchmarks/base/hackbench_test.go b/test/benchmarks/base/hackbench_test.go new file mode 100644 index 000000000..1c88e6dea --- /dev/null +++ b/test/benchmarks/base/hackbench_test.go @@ -0,0 +1,89 @@ +// Copyright 2022 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 hackbench_test + +import ( + "context" + "os" + "testing" + + "gvisor.dev/gvisor/pkg/test/dockerutil" + "gvisor.dev/gvisor/test/benchmarks/harness" + "gvisor.dev/gvisor/test/benchmarks/tools" +) + +// BenchmarHackbench runs hackbench on the runtime. +func BenchmarkHackbench(b *testing.B) { + testCases := []tools.Hackbench{ + { + IpcMode: "pipe", + ProcessMode: "thread", + }, + { + IpcMode: "socket", + ProcessMode: "process", + }, + } + + machine, err := harness.GetMachine() + if err != nil { + b.Fatalf("failed to get machine: %v", err) + } + defer machine.CleanUp() + + for _, tc := range testCases { + ipcMode := tools.Parameter{ + Name: "ipcMode", + Value: tc.IpcMode, + } + processMode := tools.Parameter{ + Name: "processMode", + Value: tc.ProcessMode, + } + name, err := tools.ParametersToName(ipcMode, processMode) + if err != nil { + b.Fatalf("Failed to parse params: %v", err) + } + b.Run(name, func(b *testing.B) { + ctx := context.Background() + container := machine.GetContainer(ctx, b) + defer container.CleanUp(ctx) + + if err := container.Spawn( + ctx, dockerutil.RunOpts{ + Image: "benchmarks/hackbench", + }, + "sleep", "24h", + ); err != nil { + b.Fatalf("run failed with: %v", err) + } + + cmd := tc.MakeCmd(b) + b.ResetTimer() + out, err := container.Exec(ctx, dockerutil.ExecOpts{}, cmd...) + if err != nil { + b.Fatalf("failed to run hackbench: %v, logs:%s", err, out) + } + tc.Report(b, out) + }) + } +} + +// TestMain is the main method for this package. +func TestMain(m *testing.M) { + harness.Init() + harness.SetFixedBenchmarks() + os.Exit(m.Run()) +} diff --git a/test/benchmarks/tools/BUILD b/test/benchmarks/tools/BUILD index 9290830d7..3e31f507f 100644 --- a/test/benchmarks/tools/BUILD +++ b/test/benchmarks/tools/BUILD @@ -14,6 +14,7 @@ go_library( "parser_util.go", "redis.go", "sysbench.go", + "hackbench.go", "tools.go", ], visibility = ["//:sandbox"], diff --git a/test/benchmarks/tools/hackbench.go b/test/benchmarks/tools/hackbench.go new file mode 100644 index 000000000..9be3ebc46 --- /dev/null +++ b/test/benchmarks/tools/hackbench.go @@ -0,0 +1,68 @@ +// Copyright 2022 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" + "testing" +) + +// Hackbench makes 'hackbench' commands and parses their output. +type Hackbench struct { + IpcMode string // ipc mode: pipe, socket(default) + ProcessMode string // process mode: thread, process(default) +} + +// MakeCmd makes commands for Hackbench. +func (s *Hackbench) MakeCmd(b *testing.B) []string { + cmd := []string{"hackbench"} + // ipc mode + if s.IpcMode == "pipe" { + cmd = append(cmd, "--pipe") + } + // group num + cmd = append(cmd, "--groups=10") + // process mode + if s.ProcessMode == "thread" { + cmd = append(cmd, "--threads") + } else { + cmd = append(cmd, "--process") + } + // loops + cmd = append(cmd, "--loops=1000") + return cmd +} + +// Report reports the relevant metrics for Hackbench. +func (s *Hackbench) Report(b *testing.B, output string) { + b.Helper() + result, err := s.parseResult(output) + if err != nil { + b.Fatalf("parsing result from %s failed: %v", output, err) + } + ReportCustomMetric(b, result, "execution_time" /*metric name*/, "s" /*unit*/) +} + +var hackbenchRegexp = regexp.MustCompile(`Time:\s*(\d*.?\d*)\n`) + +func (s *Hackbench) parseResult(data string) (float64, error) { + match := hackbenchRegexp.FindStringSubmatch(data) + if len(match) < 2 { + return 0.0, fmt.Errorf("could not find Time: %s", data) + } + return strconv.ParseFloat(match[1], 64) +}