summaryrefslogtreecommitdiffhomepage
path: root/test/perf
diff options
context:
space:
mode:
Diffstat (limited to 'test/perf')
-rw-r--r--test/perf/BUILD114
-rw-r--r--test/perf/linux/BUILD356
-rw-r--r--test/perf/linux/clock_getres_benchmark.cc39
-rw-r--r--test/perf/linux/clock_gettime_benchmark.cc60
-rw-r--r--test/perf/linux/death_benchmark.cc36
-rw-r--r--test/perf/linux/epoll_benchmark.cc99
-rw-r--r--test/perf/linux/fork_benchmark.cc350
-rw-r--r--test/perf/linux/futex_benchmark.cc248
-rw-r--r--test/perf/linux/getdents_benchmark.cc149
-rw-r--r--test/perf/linux/getpid_benchmark.cc37
-rw-r--r--test/perf/linux/gettid_benchmark.cc38
-rw-r--r--test/perf/linux/mapping_benchmark.cc163
-rw-r--r--test/perf/linux/open_benchmark.cc56
-rw-r--r--test/perf/linux/pipe_benchmark.cc66
-rw-r--r--test/perf/linux/randread_benchmark.cc100
-rw-r--r--test/perf/linux/read_benchmark.cc53
-rw-r--r--test/perf/linux/sched_yield_benchmark.cc37
-rw-r--r--test/perf/linux/send_recv_benchmark.cc372
-rw-r--r--test/perf/linux/seqwrite_benchmark.cc66
-rw-r--r--test/perf/linux/signal_benchmark.cc59
-rw-r--r--test/perf/linux/sleep_benchmark.cc60
-rw-r--r--test/perf/linux/stat_benchmark.cc62
-rw-r--r--test/perf/linux/unlink_benchmark.cc66
-rw-r--r--test/perf/linux/write_benchmark.cc52
24 files changed, 0 insertions, 2738 deletions
diff --git a/test/perf/BUILD b/test/perf/BUILD
deleted file mode 100644
index 7a2bf10ed..000000000
--- a/test/perf/BUILD
+++ /dev/null
@@ -1,114 +0,0 @@
-load("//test/runner:defs.bzl", "syscall_test")
-
-package(licenses = ["notice"])
-
-syscall_test(
- test = "//test/perf/linux:clock_getres_benchmark",
-)
-
-syscall_test(
- test = "//test/perf/linux:clock_gettime_benchmark",
-)
-
-syscall_test(
- test = "//test/perf/linux:death_benchmark",
-)
-
-syscall_test(
- test = "//test/perf/linux:epoll_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:fork_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:futex_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:getdents_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:getpid_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:gettid_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:mapping_benchmark",
-)
-
-syscall_test(
- size = "large",
- add_overlay = True,
- test = "//test/perf/linux:open_benchmark",
-)
-
-syscall_test(
- test = "//test/perf/linux:pipe_benchmark",
-)
-
-syscall_test(
- size = "large",
- add_overlay = True,
- test = "//test/perf/linux:randread_benchmark",
-)
-
-syscall_test(
- size = "large",
- add_overlay = True,
- test = "//test/perf/linux:read_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:sched_yield_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:send_recv_benchmark",
-)
-
-syscall_test(
- size = "large",
- add_overlay = True,
- test = "//test/perf/linux:seqwrite_benchmark",
-)
-
-syscall_test(
- size = "large",
- test = "//test/perf/linux:signal_benchmark",
-)
-
-syscall_test(
- test = "//test/perf/linux:sleep_benchmark",
-)
-
-syscall_test(
- size = "large",
- add_overlay = True,
- test = "//test/perf/linux:stat_benchmark",
-)
-
-syscall_test(
- size = "large",
- add_overlay = True,
- test = "//test/perf/linux:unlink_benchmark",
-)
-
-syscall_test(
- size = "large",
- add_overlay = True,
- test = "//test/perf/linux:write_benchmark",
-)
diff --git a/test/perf/linux/BUILD b/test/perf/linux/BUILD
deleted file mode 100644
index b4e907826..000000000
--- a/test/perf/linux/BUILD
+++ /dev/null
@@ -1,356 +0,0 @@
-load("//tools:defs.bzl", "cc_binary", "gbenchmark", "gtest")
-
-package(
- default_visibility = ["//:sandbox"],
- licenses = ["notice"],
-)
-
-cc_binary(
- name = "getpid_benchmark",
- testonly = 1,
- srcs = [
- "getpid_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:test_main",
- ],
-)
-
-cc_binary(
- name = "send_recv_benchmark",
- testonly = 1,
- srcs = [
- "send_recv_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/syscalls/linux:socket_test_util",
- "//test/util:file_descriptor",
- "//test/util:logging",
- "//test/util:posix_error",
- "//test/util:test_main",
- "//test/util:test_util",
- "//test/util:thread_util",
- "@com_google_absl//absl/synchronization",
- ],
-)
-
-cc_binary(
- name = "gettid_benchmark",
- testonly = 1,
- srcs = [
- "gettid_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:test_main",
- ],
-)
-
-cc_binary(
- name = "sched_yield_benchmark",
- testonly = 1,
- srcs = [
- "sched_yield_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "clock_getres_benchmark",
- testonly = 1,
- srcs = [
- "clock_getres_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:test_main",
- ],
-)
-
-cc_binary(
- name = "clock_gettime_benchmark",
- testonly = 1,
- srcs = [
- "clock_gettime_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:test_main",
- "@com_google_absl//absl/time",
- ],
-)
-
-cc_binary(
- name = "open_benchmark",
- testonly = 1,
- srcs = [
- "open_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:fs_util",
- "//test/util:logging",
- "//test/util:temp_path",
- "//test/util:test_main",
- ],
-)
-
-cc_binary(
- name = "read_benchmark",
- testonly = 1,
- srcs = [
- "read_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:fs_util",
- "//test/util:logging",
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "randread_benchmark",
- testonly = 1,
- srcs = [
- "randread_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:file_descriptor",
- "//test/util:logging",
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- "@com_google_absl//absl/random",
- ],
-)
-
-cc_binary(
- name = "write_benchmark",
- testonly = 1,
- srcs = [
- "write_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "seqwrite_benchmark",
- testonly = 1,
- srcs = [
- "seqwrite_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- "@com_google_absl//absl/random",
- ],
-)
-
-cc_binary(
- name = "pipe_benchmark",
- testonly = 1,
- srcs = [
- "pipe_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:test_main",
- "//test/util:test_util",
- "//test/util:thread_util",
- ],
-)
-
-cc_binary(
- name = "fork_benchmark",
- testonly = 1,
- srcs = [
- "fork_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:cleanup",
- "//test/util:file_descriptor",
- "//test/util:logging",
- "//test/util:test_main",
- "//test/util:test_util",
- "//test/util:thread_util",
- "@com_google_absl//absl/synchronization",
- ],
-)
-
-cc_binary(
- name = "futex_benchmark",
- testonly = 1,
- srcs = [
- "futex_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:test_main",
- "//test/util:thread_util",
- "@com_google_absl//absl/time",
- ],
-)
-
-cc_binary(
- name = "epoll_benchmark",
- testonly = 1,
- srcs = [
- "epoll_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:epoll_util",
- "//test/util:file_descriptor",
- "//test/util:test_main",
- "//test/util:test_util",
- "//test/util:thread_util",
- "@com_google_absl//absl/time",
- ],
-)
-
-cc_binary(
- name = "death_benchmark",
- testonly = 1,
- srcs = [
- "death_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:test_main",
- ],
-)
-
-cc_binary(
- name = "mapping_benchmark",
- testonly = 1,
- srcs = [
- "mapping_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:memory_util",
- "//test/util:posix_error",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "signal_benchmark",
- testonly = 1,
- srcs = [
- "signal_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "getdents_benchmark",
- testonly = 1,
- srcs = [
- "getdents_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:file_descriptor",
- "//test/util:fs_util",
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
-
-cc_binary(
- name = "sleep_benchmark",
- testonly = 1,
- srcs = [
- "sleep_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:logging",
- "//test/util:test_main",
- ],
-)
-
-cc_binary(
- name = "stat_benchmark",
- testonly = 1,
- srcs = [
- "stat_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:fs_util",
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- "@com_google_absl//absl/strings",
- ],
-)
-
-cc_binary(
- name = "unlink_benchmark",
- testonly = 1,
- srcs = [
- "unlink_benchmark.cc",
- ],
- deps = [
- gbenchmark,
- gtest,
- "//test/util:fs_util",
- "//test/util:temp_path",
- "//test/util:test_main",
- "//test/util:test_util",
- ],
-)
diff --git a/test/perf/linux/clock_getres_benchmark.cc b/test/perf/linux/clock_getres_benchmark.cc
deleted file mode 100644
index b051293ad..000000000
--- a/test/perf/linux/clock_getres_benchmark.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#include <time.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// clock_getres(1) is very nearly a no-op syscall, but it does require copying
-// out to a userspace struct. It thus provides a nice small copy-out benchmark.
-void BM_ClockGetRes(benchmark::State& state) {
- struct timespec ts;
- for (auto _ : state) {
- clock_getres(CLOCK_MONOTONIC, &ts);
- }
-}
-
-BENCHMARK(BM_ClockGetRes);
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/clock_gettime_benchmark.cc b/test/perf/linux/clock_gettime_benchmark.cc
deleted file mode 100644
index 6691bebd9..000000000
--- a/test/perf/linux/clock_gettime_benchmark.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-#include <pthread.h>
-#include <time.h>
-
-#include "gtest/gtest.h"
-#include "absl/time/clock.h"
-#include "absl/time/time.h"
-#include "benchmark/benchmark.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_ClockGettimeThreadCPUTime(benchmark::State& state) {
- clockid_t clockid;
- ASSERT_EQ(0, pthread_getcpuclockid(pthread_self(), &clockid));
- struct timespec tp;
-
- for (auto _ : state) {
- clock_gettime(clockid, &tp);
- }
-}
-
-BENCHMARK(BM_ClockGettimeThreadCPUTime);
-
-void BM_VDSOClockGettime(benchmark::State& state) {
- const clockid_t clock = state.range(0);
- struct timespec tp;
- absl::Time start = absl::Now();
-
- // Don't benchmark the calibration phase.
- while (absl::Now() < start + absl::Milliseconds(2100)) {
- clock_gettime(clock, &tp);
- }
-
- for (auto _ : state) {
- clock_gettime(clock, &tp);
- }
-}
-
-BENCHMARK(BM_VDSOClockGettime)->Arg(CLOCK_MONOTONIC)->Arg(CLOCK_REALTIME);
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/death_benchmark.cc b/test/perf/linux/death_benchmark.cc
deleted file mode 100644
index cb2b6fd07..000000000
--- a/test/perf/linux/death_benchmark.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.
-
-#include <signal.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// DeathTest is not so much a microbenchmark as a macrobenchmark. It is testing
-// the ability of gVisor (on whatever platform) to execute all the related
-// stack-dumping routines associated with EXPECT_EXIT / EXPECT_DEATH.
-TEST(DeathTest, ZeroEqualsOne) {
- EXPECT_EXIT({ TEST_CHECK(0 == 1); }, ::testing::KilledBySignal(SIGABRT), "");
-}
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/epoll_benchmark.cc b/test/perf/linux/epoll_benchmark.cc
deleted file mode 100644
index 0b121338a..000000000
--- a/test/perf/linux/epoll_benchmark.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// 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.
-
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-
-#include <atomic>
-#include <cerrno>
-#include <cstdint>
-#include <cstdlib>
-#include <ctime>
-#include <memory>
-
-#include "gtest/gtest.h"
-#include "absl/time/time.h"
-#include "benchmark/benchmark.h"
-#include "test/util/epoll_util.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/test_util.h"
-#include "test/util/thread_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// Returns a new eventfd.
-PosixErrorOr<FileDescriptor> NewEventFD() {
- int fd = eventfd(0, /* flags = */ 0);
- MaybeSave();
- if (fd < 0) {
- return PosixError(errno, "eventfd");
- }
- return FileDescriptor(fd);
-}
-
-// Also stolen from epoll.cc unit tests.
-void BM_EpollTimeout(benchmark::State& state) {
- constexpr int kFDsPerEpoll = 3;
- auto epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
-
- std::vector<FileDescriptor> eventfds;
- for (int i = 0; i < kFDsPerEpoll; i++) {
- eventfds.push_back(ASSERT_NO_ERRNO_AND_VALUE(NewEventFD()));
- ASSERT_NO_ERRNO(
- RegisterEpollFD(epollfd.get(), eventfds[i].get(), EPOLLIN, 0));
- }
-
- struct epoll_event result[kFDsPerEpoll];
- int timeout_ms = state.range(0);
-
- for (auto _ : state) {
- EXPECT_EQ(0, epoll_wait(epollfd.get(), result, kFDsPerEpoll, timeout_ms));
- }
-}
-
-BENCHMARK(BM_EpollTimeout)->Range(0, 8);
-
-// Also stolen from epoll.cc unit tests.
-void BM_EpollAllEvents(benchmark::State& state) {
- auto epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD());
- const int fds_per_epoll = state.range(0);
- constexpr uint64_t kEventVal = 5;
-
- std::vector<FileDescriptor> eventfds;
- for (int i = 0; i < fds_per_epoll; i++) {
- eventfds.push_back(ASSERT_NO_ERRNO_AND_VALUE(NewEventFD()));
- ASSERT_NO_ERRNO(
- RegisterEpollFD(epollfd.get(), eventfds[i].get(), EPOLLIN, 0));
-
- ASSERT_THAT(WriteFd(eventfds[i].get(), &kEventVal, sizeof(kEventVal)),
- SyscallSucceedsWithValue(sizeof(kEventVal)));
- }
-
- std::vector<struct epoll_event> result(fds_per_epoll);
-
- for (auto _ : state) {
- EXPECT_EQ(fds_per_epoll,
- epoll_wait(epollfd.get(), result.data(), fds_per_epoll, 0));
- }
-}
-
-BENCHMARK(BM_EpollAllEvents)->Range(2, 1024);
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/fork_benchmark.cc b/test/perf/linux/fork_benchmark.cc
deleted file mode 100644
index 84fdbc8a0..000000000
--- a/test/perf/linux/fork_benchmark.cc
+++ /dev/null
@@ -1,350 +0,0 @@
-// 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.
-
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "absl/synchronization/barrier.h"
-#include "benchmark/benchmark.h"
-#include "test/util/cleanup.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/logging.h"
-#include "test/util/test_util.h"
-#include "test/util/thread_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-constexpr int kBusyMax = 250;
-
-// Do some CPU-bound busy-work.
-int busy(int max) {
- // Prevent the compiler from optimizing this work away,
- volatile int count = 0;
-
- for (int i = 1; i < max; i++) {
- for (int j = 2; j < i / 2; j++) {
- if (i % j == 0) {
- count++;
- }
- }
- }
-
- return count;
-}
-
-void BM_CPUBoundUniprocess(benchmark::State& state) {
- for (auto _ : state) {
- busy(kBusyMax);
- }
-}
-
-BENCHMARK(BM_CPUBoundUniprocess);
-
-void BM_CPUBoundAsymmetric(benchmark::State& state) {
- const size_t max = state.max_iterations;
- pid_t child = fork();
- if (child == 0) {
- for (int i = 0; i < max; i++) {
- busy(kBusyMax);
- }
- _exit(0);
- }
- ASSERT_THAT(child, SyscallSucceeds());
- ASSERT_TRUE(state.KeepRunningBatch(max));
-
- int status;
- EXPECT_THAT(RetryEINTR(waitpid)(child, &status, 0), SyscallSucceeds());
- EXPECT_TRUE(WIFEXITED(status));
- EXPECT_EQ(0, WEXITSTATUS(status));
- ASSERT_FALSE(state.KeepRunning());
-}
-
-BENCHMARK(BM_CPUBoundAsymmetric)->UseRealTime();
-
-void BM_CPUBoundSymmetric(benchmark::State& state) {
- std::vector<pid_t> children;
- auto child_cleanup = Cleanup([&] {
- for (const pid_t child : children) {
- int status;
- EXPECT_THAT(RetryEINTR(waitpid)(child, &status, 0), SyscallSucceeds());
- EXPECT_TRUE(WIFEXITED(status));
- EXPECT_EQ(0, WEXITSTATUS(status));
- }
- ASSERT_FALSE(state.KeepRunning());
- });
-
- const int processes = state.range(0);
- for (int i = 0; i < processes; i++) {
- size_t cur = (state.max_iterations + (processes - 1)) / processes;
- if ((state.iterations() + cur) >= state.max_iterations) {
- cur = state.max_iterations - state.iterations();
- }
- pid_t child = fork();
- if (child == 0) {
- for (int i = 0; i < cur; i++) {
- busy(kBusyMax);
- }
- _exit(0);
- }
- ASSERT_THAT(child, SyscallSucceeds());
- if (cur > 0) {
- // We can have a zero cur here, depending.
- ASSERT_TRUE(state.KeepRunningBatch(cur));
- }
- children.push_back(child);
- }
-}
-
-BENCHMARK(BM_CPUBoundSymmetric)->Range(2, 16)->UseRealTime();
-
-// Child routine for ProcessSwitch/ThreadSwitch.
-// Reads from readfd and writes the result to writefd.
-void SwitchChild(int readfd, int writefd) {
- while (1) {
- char buf;
- int ret = ReadFd(readfd, &buf, 1);
- if (ret == 0) {
- break;
- }
- TEST_CHECK_MSG(ret == 1, "read failed");
-
- ret = WriteFd(writefd, &buf, 1);
- if (ret == -1) {
- TEST_CHECK_MSG(errno == EPIPE, "unexpected write failure");
- break;
- }
- TEST_CHECK_MSG(ret == 1, "write failed");
- }
-}
-
-// Send bytes in a loop through a series of pipes, each passing through a
-// different process.
-//
-// Proc 0 Proc 1
-// * ----------> *
-// ^ Pipe 1 |
-// | |
-// | Pipe 0 | Pipe 2
-// | |
-// | |
-// | Pipe 3 v
-// * <---------- *
-// Proc 3 Proc 2
-//
-// This exercises context switching through multiple processes.
-void BM_ProcessSwitch(benchmark::State& state) {
- // Code below assumes there are at least two processes.
- const int num_processes = state.range(0);
- ASSERT_GE(num_processes, 2);
-
- std::vector<pid_t> children;
- auto child_cleanup = Cleanup([&] {
- for (const pid_t child : children) {
- int status;
- EXPECT_THAT(RetryEINTR(waitpid)(child, &status, 0), SyscallSucceeds());
- EXPECT_TRUE(WIFEXITED(status));
- EXPECT_EQ(0, WEXITSTATUS(status));
- }
- });
-
- // Must come after children, as the FDs must be closed before the children
- // will exit.
- std::vector<FileDescriptor> read_fds;
- std::vector<FileDescriptor> write_fds;
-
- for (int i = 0; i < num_processes; i++) {
- int fds[2];
- ASSERT_THAT(pipe(fds), SyscallSucceeds());
- read_fds.emplace_back(fds[0]);
- write_fds.emplace_back(fds[1]);
- }
-
- // This process is one of the processes in the loop. It will be considered
- // index 0.
- for (int i = 1; i < num_processes; i++) {
- // Read from current pipe index, write to next.
- const int read_index = i;
- const int read_fd = read_fds[read_index].get();
-
- const int write_index = (i + 1) % num_processes;
- const int write_fd = write_fds[write_index].get();
-
- // std::vector isn't safe to use from the fork child.
- FileDescriptor* read_array = read_fds.data();
- FileDescriptor* write_array = write_fds.data();
-
- pid_t child = fork();
- if (!child) {
- // Close all other FDs.
- for (int j = 0; j < num_processes; j++) {
- if (j != read_index) {
- read_array[j].reset();
- }
- if (j != write_index) {
- write_array[j].reset();
- }
- }
-
- SwitchChild(read_fd, write_fd);
- _exit(0);
- }
- ASSERT_THAT(child, SyscallSucceeds());
- children.push_back(child);
- }
-
- // Read from current pipe index (0), write to next (1).
- const int read_index = 0;
- const int read_fd = read_fds[read_index].get();
-
- const int write_index = 1;
- const int write_fd = write_fds[write_index].get();
-
- // Kick start the loop.
- char buf = 'a';
- ASSERT_THAT(WriteFd(write_fd, &buf, 1), SyscallSucceedsWithValue(1));
-
- for (auto _ : state) {
- ASSERT_THAT(ReadFd(read_fd, &buf, 1), SyscallSucceedsWithValue(1));
- ASSERT_THAT(WriteFd(write_fd, &buf, 1), SyscallSucceedsWithValue(1));
- }
-}
-
-BENCHMARK(BM_ProcessSwitch)->Range(2, 16)->UseRealTime();
-
-// Equivalent to BM_ThreadSwitch using threads instead of processes.
-void BM_ThreadSwitch(benchmark::State& state) {
- // Code below assumes there are at least two threads.
- const int num_threads = state.range(0);
- ASSERT_GE(num_threads, 2);
-
- // Must come after threads, as the FDs must be closed before the children
- // will exit.
- std::vector<std::unique_ptr<ScopedThread>> threads;
- std::vector<FileDescriptor> read_fds;
- std::vector<FileDescriptor> write_fds;
-
- for (int i = 0; i < num_threads; i++) {
- int fds[2];
- ASSERT_THAT(pipe(fds), SyscallSucceeds());
- read_fds.emplace_back(fds[0]);
- write_fds.emplace_back(fds[1]);
- }
-
- // This thread is one of the threads in the loop. It will be considered
- // index 0.
- for (int i = 1; i < num_threads; i++) {
- // Read from current pipe index, write to next.
- //
- // Transfer ownership of the FDs to the thread.
- const int read_index = i;
- const int read_fd = read_fds[read_index].release();
-
- const int write_index = (i + 1) % num_threads;
- const int write_fd = write_fds[write_index].release();
-
- threads.emplace_back(std::make_unique<ScopedThread>([read_fd, write_fd] {
- FileDescriptor read(read_fd);
- FileDescriptor write(write_fd);
- SwitchChild(read.get(), write.get());
- }));
- }
-
- // Read from current pipe index (0), write to next (1).
- const int read_index = 0;
- const int read_fd = read_fds[read_index].get();
-
- const int write_index = 1;
- const int write_fd = write_fds[write_index].get();
-
- // Kick start the loop.
- char buf = 'a';
- ASSERT_THAT(WriteFd(write_fd, &buf, 1), SyscallSucceedsWithValue(1));
-
- for (auto _ : state) {
- ASSERT_THAT(ReadFd(read_fd, &buf, 1), SyscallSucceedsWithValue(1));
- ASSERT_THAT(WriteFd(write_fd, &buf, 1), SyscallSucceedsWithValue(1));
- }
-
- // The two FDs still owned by this thread are closed, causing the next thread
- // to exit its loop and close its FDs, and so on until all threads exit.
-}
-
-BENCHMARK(BM_ThreadSwitch)->Range(2, 16)->UseRealTime();
-
-void BM_ThreadStart(benchmark::State& state) {
- const int num_threads = state.range(0);
-
- for (auto _ : state) {
- state.PauseTiming();
-
- auto barrier = new absl::Barrier(num_threads + 1);
- std::vector<std::unique_ptr<ScopedThread>> threads;
-
- state.ResumeTiming();
-
- for (size_t i = 0; i < num_threads; ++i) {
- threads.emplace_back(std::make_unique<ScopedThread>([barrier] {
- if (barrier->Block()) {
- delete barrier;
- }
- }));
- }
-
- if (barrier->Block()) {
- delete barrier;
- }
-
- state.PauseTiming();
-
- for (const auto& thread : threads) {
- thread->Join();
- }
-
- state.ResumeTiming();
- }
-}
-
-BENCHMARK(BM_ThreadStart)->Range(1, 2048)->UseRealTime();
-
-// Benchmark the complete fork + exit + wait.
-void BM_ProcessLifecycle(benchmark::State& state) {
- const int num_procs = state.range(0);
-
- std::vector<pid_t> pids(num_procs);
- for (auto _ : state) {
- for (size_t i = 0; i < num_procs; ++i) {
- int pid = fork();
- if (pid == 0) {
- _exit(0);
- }
- ASSERT_THAT(pid, SyscallSucceeds());
- pids[i] = pid;
- }
-
- for (const int pid : pids) {
- ASSERT_THAT(RetryEINTR(waitpid)(pid, nullptr, 0),
- SyscallSucceedsWithValue(pid));
- }
- }
-}
-
-BENCHMARK(BM_ProcessLifecycle)->Range(1, 512)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/futex_benchmark.cc b/test/perf/linux/futex_benchmark.cc
deleted file mode 100644
index b349d50bf..000000000
--- a/test/perf/linux/futex_benchmark.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-// 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.
-
-#include <linux/futex.h>
-
-#include <atomic>
-#include <cerrno>
-#include <cstdint>
-#include <cstdlib>
-#include <ctime>
-
-#include "gtest/gtest.h"
-#include "absl/time/clock.h"
-#include "absl/time/time.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-#include "test/util/thread_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-inline int FutexWait(std::atomic<int32_t>* v, int32_t val) {
- return syscall(SYS_futex, v, FUTEX_BITSET_MATCH_ANY, nullptr);
-}
-
-inline int FutexWaitRelativeTimeout(std::atomic<int32_t>* v, int32_t val,
- const struct timespec* reltime) {
- return syscall(SYS_futex, v, FUTEX_WAIT_PRIVATE, reltime);
-}
-
-inline int FutexWaitAbsoluteTimeout(std::atomic<int32_t>* v, int32_t val,
- const struct timespec* abstime) {
- return syscall(SYS_futex, v, FUTEX_BITSET_MATCH_ANY, abstime);
-}
-
-inline int FutexWaitBitsetAbsoluteTimeout(std::atomic<int32_t>* v, int32_t val,
- int32_t bits,
- const struct timespec* abstime) {
- return syscall(SYS_futex, v, FUTEX_WAIT_BITSET_PRIVATE | FUTEX_CLOCK_REALTIME,
- val, abstime, nullptr, bits);
-}
-
-inline int FutexWake(std::atomic<int32_t>* v, int32_t count) {
- return syscall(SYS_futex, v, FUTEX_WAKE_PRIVATE, count);
-}
-
-// This just uses FUTEX_WAKE on an address with nothing waiting, very simple.
-void BM_FutexWakeNop(benchmark::State& state) {
- std::atomic<int32_t> v(0);
-
- for (auto _ : state) {
- EXPECT_EQ(0, FutexWake(&v, 1));
- }
-}
-
-BENCHMARK(BM_FutexWakeNop);
-
-// This just uses FUTEX_WAIT on an address whose value has changed, i.e., the
-// syscall won't wait.
-void BM_FutexWaitNop(benchmark::State& state) {
- std::atomic<int32_t> v(0);
-
- for (auto _ : state) {
- EXPECT_EQ(-EAGAIN, FutexWait(&v, 1));
- }
-}
-
-BENCHMARK(BM_FutexWaitNop);
-
-// This uses FUTEX_WAIT with a timeout on an address whose value never
-// changes, such that it always times out. Timeout overhead can be estimated by
-// timer overruns for short timeouts.
-void BM_FutexWaitTimeout(benchmark::State& state) {
- const int timeout_ns = state.range(0);
- std::atomic<int32_t> v(0);
- auto ts = absl::ToTimespec(absl::Nanoseconds(timeout_ns));
-
- for (auto _ : state) {
- EXPECT_EQ(-ETIMEDOUT, FutexWaitRelativeTimeout(&v, 0, &ts));
- }
-}
-
-BENCHMARK(BM_FutexWaitTimeout)
- ->Arg(1)
- ->Arg(10)
- ->Arg(100)
- ->Arg(1000)
- ->Arg(10000);
-
-// This calls FUTEX_WAIT_BITSET with CLOCK_REALTIME.
-void BM_FutexWaitBitset(benchmark::State& state) {
- std::atomic<int32_t> v(0);
- int timeout_ns = state.range(0);
- auto ts = absl::ToTimespec(absl::Nanoseconds(timeout_ns));
- for (auto _ : state) {
- EXPECT_EQ(-ETIMEDOUT, FutexWaitBitsetAbsoluteTimeout(&v, 0, 1, &ts));
- }
-}
-
-BENCHMARK(BM_FutexWaitBitset)->Range(0, 100000);
-
-int64_t GetCurrentMonotonicTimeNanos() {
- struct timespec ts;
- TEST_CHECK(clock_gettime(CLOCK_MONOTONIC, &ts) != -1);
- return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
-}
-
-void SpinNanos(int64_t delay_ns) {
- if (delay_ns <= 0) {
- return;
- }
- const int64_t end = GetCurrentMonotonicTimeNanos() + delay_ns;
- while (GetCurrentMonotonicTimeNanos() < end) {
- // spin
- }
-}
-
-// Each iteration of FutexRoundtripDelayed involves a thread sending a futex
-// wakeup to another thread, which spins for delay_us and then sends a futex
-// wakeup back. The time per iteration is 2* (delay_us + kBeforeWakeDelayNs +
-// futex/scheduling overhead).
-void BM_FutexRoundtripDelayed(benchmark::State& state) {
- const int delay_us = state.range(0);
-
- const int64_t delay_ns = delay_us * 1000;
- // Spin for an extra kBeforeWakeDelayNs before invoking FUTEX_WAKE to reduce
- // the probability that the wakeup comes before the wait, preventing the wait
- // from ever taking effect and causing the benchmark to underestimate the
- // actual wakeup time.
- constexpr int64_t kBeforeWakeDelayNs = 500;
- std::atomic<int32_t> v(0);
- ScopedThread t([&] {
- for (int i = 0; i < state.max_iterations; i++) {
- SpinNanos(delay_ns);
- while (v.load(std::memory_order_acquire) == 0) {
- FutexWait(&v, 0);
- }
- SpinNanos(kBeforeWakeDelayNs + delay_ns);
- v.store(0, std::memory_order_release);
- FutexWake(&v, 1);
- }
- });
- for (auto _ : state) {
- SpinNanos(kBeforeWakeDelayNs + delay_ns);
- v.store(1, std::memory_order_release);
- FutexWake(&v, 1);
- SpinNanos(delay_ns);
- while (v.load(std::memory_order_acquire) == 1) {
- FutexWait(&v, 1);
- }
- }
-}
-
-BENCHMARK(BM_FutexRoundtripDelayed)
- ->Arg(0)
- ->Arg(10)
- ->Arg(20)
- ->Arg(50)
- ->Arg(100);
-
-// FutexLock is a simple, dumb futex based lock implementation.
-// It will try to acquire the lock by atomically incrementing the
-// lock word. If it did not increment the lock from 0 to 1, someone
-// else has the lock, so it will FUTEX_WAIT until it is woken in
-// the unlock path.
-class FutexLock {
- public:
- FutexLock() : lock_word_(0) {}
-
- void lock(struct timespec* deadline) {
- int32_t val;
- while ((val = lock_word_.fetch_add(1, std::memory_order_acquire) + 1) !=
- 1) {
- // If we didn't get the lock by incrementing from 0 to 1,
- // do a FUTEX_WAIT with the desired current value set to
- // val. If val is no longer what the atomic increment returned,
- // someone might have set it to 0 so we can try to acquire
- // again.
- int ret = FutexWaitAbsoluteTimeout(&lock_word_, val, deadline);
- if (ret == 0 || ret == -EWOULDBLOCK || ret == -EINTR) {
- continue;
- } else {
- FAIL() << "unexpected FUTEX_WAIT return: " << ret;
- }
- }
- }
-
- void unlock() {
- // Store 0 into the lock word and wake one waiter. We intentionally
- // ignore the return value of the FUTEX_WAKE here, since there may be
- // no waiters to wake anyway.
- lock_word_.store(0, std::memory_order_release);
- (void)FutexWake(&lock_word_, 1);
- }
-
- private:
- std::atomic<int32_t> lock_word_;
-};
-
-FutexLock* test_lock; // Used below.
-
-void FutexContend(benchmark::State& state, int thread_index,
- struct timespec* deadline) {
- int counter = 0;
- if (thread_index == 0) {
- test_lock = new FutexLock();
- }
- for (auto _ : state) {
- test_lock->lock(deadline);
- counter++;
- test_lock->unlock();
- }
- if (thread_index == 0) {
- delete test_lock;
- }
- state.SetItemsProcessed(state.iterations());
-}
-
-void BM_FutexContend(benchmark::State& state) {
- FutexContend(state, state.thread_index, nullptr);
-}
-
-BENCHMARK(BM_FutexContend)->ThreadRange(1, 1024)->UseRealTime();
-
-void BM_FutexDeadlineContend(benchmark::State& state) {
- auto deadline = absl::ToTimespec(absl::Now() + absl::Minutes(10));
- FutexContend(state, state.thread_index, &deadline);
-}
-
-BENCHMARK(BM_FutexDeadlineContend)->ThreadRange(1, 1024)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/getdents_benchmark.cc b/test/perf/linux/getdents_benchmark.cc
deleted file mode 100644
index 0e03975b4..000000000
--- a/test/perf/linux/getdents_benchmark.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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.
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/fs_util.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-#ifndef SYS_getdents64
-#if defined(__x86_64__)
-#define SYS_getdents64 217
-#elif defined(__aarch64__)
-#define SYS_getdents64 217
-#else
-#error "Unknown architecture"
-#endif
-#endif // SYS_getdents64
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-constexpr int kBufferSize = 16384;
-
-PosixErrorOr<TempPath> CreateDirectory(int count,
- std::vector<std::string>* files) {
- ASSIGN_OR_RETURN_ERRNO(TempPath dir, TempPath::CreateDir());
-
- ASSIGN_OR_RETURN_ERRNO(FileDescriptor dfd,
- Open(dir.path(), O_RDONLY | O_DIRECTORY));
-
- for (int i = 0; i < count; i++) {
- auto file = NewTempRelPath();
- auto res = MknodAt(dfd, file, S_IFREG | 0644, 0);
- RETURN_IF_ERRNO(res);
- files->push_back(file);
- }
-
- return std::move(dir);
-}
-
-PosixError CleanupDirectory(const TempPath& dir,
- std::vector<std::string>* files) {
- ASSIGN_OR_RETURN_ERRNO(FileDescriptor dfd,
- Open(dir.path(), O_RDONLY | O_DIRECTORY));
-
- for (auto it = files->begin(); it != files->end(); ++it) {
- auto res = UnlinkAt(dfd, *it, 0);
- RETURN_IF_ERRNO(res);
- }
- return NoError();
-}
-
-// Creates a directory containing `files` files, and reads all the directory
-// entries from the directory using a single FD.
-void BM_GetdentsSameFD(benchmark::State& state) {
- // Create directory with given files.
- const int count = state.range(0);
-
- // Keep a vector of all of the file TempPaths that is destroyed before dir.
- //
- // Normally, we'd simply allow dir to recursively clean up the contained
- // files, but that recursive cleanup uses getdents, which may be very slow in
- // extreme benchmarks.
- TempPath dir;
- std::vector<std::string> files;
- dir = ASSERT_NO_ERRNO_AND_VALUE(CreateDirectory(count, &files));
-
- FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY | O_DIRECTORY));
- char buffer[kBufferSize];
-
- // We read all directory entries on each iteration, but report this as a
- // "batch" iteration so that reported times are per file.
- while (state.KeepRunningBatch(count)) {
- ASSERT_THAT(lseek(fd.get(), 0, SEEK_SET), SyscallSucceeds());
-
- int ret;
- do {
- ASSERT_THAT(ret = syscall(SYS_getdents64, fd.get(), buffer, kBufferSize),
- SyscallSucceeds());
- } while (ret > 0);
- }
-
- ASSERT_NO_ERRNO(CleanupDirectory(dir, &files));
-
- state.SetItemsProcessed(state.iterations());
-}
-
-BENCHMARK(BM_GetdentsSameFD)->Range(1, 1 << 16)->UseRealTime();
-
-// Creates a directory containing `files` files, and reads all the directory
-// entries from the directory using a new FD each time.
-void BM_GetdentsNewFD(benchmark::State& state) {
- // Create directory with given files.
- const int count = state.range(0);
-
- // Keep a vector of all of the file TempPaths that is destroyed before dir.
- //
- // Normally, we'd simply allow dir to recursively clean up the contained
- // files, but that recursive cleanup uses getdents, which may be very slow in
- // extreme benchmarks.
- TempPath dir;
- std::vector<std::string> files;
- dir = ASSERT_NO_ERRNO_AND_VALUE(CreateDirectory(count, &files));
- char buffer[kBufferSize];
-
- // We read all directory entries on each iteration, but report this as a
- // "batch" iteration so that reported times are per file.
- while (state.KeepRunningBatch(count)) {
- FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY | O_DIRECTORY));
-
- int ret;
- do {
- ASSERT_THAT(ret = syscall(SYS_getdents64, fd.get(), buffer, kBufferSize),
- SyscallSucceeds());
- } while (ret > 0);
- }
-
- ASSERT_NO_ERRNO(CleanupDirectory(dir, &files));
-
- state.SetItemsProcessed(state.iterations());
-}
-
-BENCHMARK(BM_GetdentsNewFD)->Range(1, 1 << 16)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/getpid_benchmark.cc b/test/perf/linux/getpid_benchmark.cc
deleted file mode 100644
index db74cb264..000000000
--- a/test/perf/linux/getpid_benchmark.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_Getpid(benchmark::State& state) {
- for (auto _ : state) {
- syscall(SYS_getpid);
- }
-}
-
-BENCHMARK(BM_Getpid);
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/gettid_benchmark.cc b/test/perf/linux/gettid_benchmark.cc
deleted file mode 100644
index 8f4961f5e..000000000
--- a/test/perf/linux/gettid_benchmark.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_Gettid(benchmark::State& state) {
- for (auto _ : state) {
- syscall(SYS_gettid);
- }
-}
-
-BENCHMARK(BM_Gettid)->ThreadRange(1, 4000)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/mapping_benchmark.cc b/test/perf/linux/mapping_benchmark.cc
deleted file mode 100644
index 39c30fe69..000000000
--- a/test/perf/linux/mapping_benchmark.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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.
-
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-#include "test/util/memory_util.h"
-#include "test/util/posix_error.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// Conservative value for /proc/sys/vm/max_map_count, which limits the number of
-// VMAs, minus a safety margin for VMAs that already exist for the test binary.
-// The default value for max_map_count is
-// include/linux/mm.h:DEFAULT_MAX_MAP_COUNT = 65530.
-constexpr size_t kMaxVMAs = 64001;
-
-// Map then unmap pages without touching them.
-void BM_MapUnmap(benchmark::State& state) {
- // Number of pages to map.
- const int pages = state.range(0);
-
- while (state.KeepRunning()) {
- void* addr = mmap(0, pages * kPageSize, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- TEST_CHECK_MSG(addr != MAP_FAILED, "mmap failed");
-
- int ret = munmap(addr, pages * kPageSize);
- TEST_CHECK_MSG(ret == 0, "munmap failed");
- }
-}
-
-BENCHMARK(BM_MapUnmap)->Range(1, 1 << 17)->UseRealTime();
-
-// Map, touch, then unmap pages.
-void BM_MapTouchUnmap(benchmark::State& state) {
- // Number of pages to map.
- const int pages = state.range(0);
-
- while (state.KeepRunning()) {
- void* addr = mmap(0, pages * kPageSize, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- TEST_CHECK_MSG(addr != MAP_FAILED, "mmap failed");
-
- char* c = reinterpret_cast<char*>(addr);
- char* end = c + pages * kPageSize;
- while (c < end) {
- *c = 42;
- c += kPageSize;
- }
-
- int ret = munmap(addr, pages * kPageSize);
- TEST_CHECK_MSG(ret == 0, "munmap failed");
- }
-}
-
-BENCHMARK(BM_MapTouchUnmap)->Range(1, 1 << 17)->UseRealTime();
-
-// Map and touch many pages, unmapping all at once.
-//
-// NOTE(b/111429208): This is a regression test to ensure performant mapping and
-// allocation even with tons of mappings.
-void BM_MapTouchMany(benchmark::State& state) {
- // Number of pages to map.
- const int page_count = state.range(0);
-
- while (state.KeepRunning()) {
- std::vector<void*> pages;
-
- for (int i = 0; i < page_count; i++) {
- void* addr = mmap(nullptr, kPageSize, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- TEST_CHECK_MSG(addr != MAP_FAILED, "mmap failed");
-
- char* c = reinterpret_cast<char*>(addr);
- *c = 42;
-
- pages.push_back(addr);
- }
-
- for (void* addr : pages) {
- int ret = munmap(addr, kPageSize);
- TEST_CHECK_MSG(ret == 0, "munmap failed");
- }
- }
-
- state.SetBytesProcessed(kPageSize * page_count * state.iterations());
-}
-
-BENCHMARK(BM_MapTouchMany)->Range(1, 1 << 12)->UseRealTime();
-
-void BM_PageFault(benchmark::State& state) {
- // Map the region in which we will take page faults. To ensure that each page
- // fault maps only a single page, each page we touch must correspond to a
- // distinct VMA. Thus we need a 1-page gap between each 1-page VMA. However,
- // each gap consists of a PROT_NONE VMA, instead of an unmapped hole, so that
- // if there are background threads running, they can't inadvertently creating
- // mappings in our gaps that are unmapped when the test ends.
- size_t test_pages = kMaxVMAs;
- // Ensure that test_pages is odd, since we want the test region to both
- // begin and end with a mapped page.
- if (test_pages % 2 == 0) {
- test_pages--;
- }
- const size_t test_region_bytes = test_pages * kPageSize;
- // Use MAP_SHARED here because madvise(MADV_DONTNEED) on private mappings on
- // gVisor won't force future sentry page faults (by design). Use MAP_POPULATE
- // so that Linux pre-allocates the shmem file used to back the mapping.
- Mapping m = ASSERT_NO_ERRNO_AND_VALUE(
- MmapAnon(test_region_bytes, PROT_READ, MAP_SHARED | MAP_POPULATE));
- for (size_t i = 0; i < test_pages / 2; i++) {
- ASSERT_THAT(
- mprotect(reinterpret_cast<void*>(m.addr() + ((2 * i + 1) * kPageSize)),
- kPageSize, PROT_NONE),
- SyscallSucceeds());
- }
-
- const size_t mapped_pages = test_pages / 2 + 1;
- // "Start" at the end of the mapped region to force the mapped region to be
- // reset, since we mapped it with MAP_POPULATE.
- size_t cur_page = mapped_pages;
- for (auto _ : state) {
- if (cur_page >= mapped_pages) {
- // We've reached the end of our mapped region and have to reset it to
- // incur page faults again.
- state.PauseTiming();
- ASSERT_THAT(madvise(m.ptr(), test_region_bytes, MADV_DONTNEED),
- SyscallSucceeds());
- cur_page = 0;
- state.ResumeTiming();
- }
- const uintptr_t addr = m.addr() + (2 * cur_page * kPageSize);
- const char c = *reinterpret_cast<volatile char*>(addr);
- benchmark::DoNotOptimize(c);
- cur_page++;
- }
-}
-
-BENCHMARK(BM_PageFault)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/open_benchmark.cc b/test/perf/linux/open_benchmark.cc
deleted file mode 100644
index 68008f6d5..000000000
--- a/test/perf/linux/open_benchmark.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/fs_util.h"
-#include "test/util/logging.h"
-#include "test/util/temp_path.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_Open(benchmark::State& state) {
- const int size = state.range(0);
- std::vector<TempPath> cache;
- for (int i = 0; i < size; i++) {
- auto path = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
- cache.emplace_back(std::move(path));
- }
-
- unsigned int seed = 1;
- for (auto _ : state) {
- const int chosen = rand_r(&seed) % size;
- int fd = open(cache[chosen].path().c_str(), O_RDONLY);
- TEST_CHECK(fd != -1);
- close(fd);
- }
-}
-
-BENCHMARK(BM_Open)->Range(1, 128)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/pipe_benchmark.cc b/test/perf/linux/pipe_benchmark.cc
deleted file mode 100644
index 8f5f6a2a3..000000000
--- a/test/perf/linux/pipe_benchmark.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <cerrno>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-#include "test/util/test_util.h"
-#include "test/util/thread_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_Pipe(benchmark::State& state) {
- int fds[2];
- TEST_CHECK(pipe(fds) == 0);
-
- const int size = state.range(0);
- std::vector<char> wbuf(size);
- std::vector<char> rbuf(size);
- RandomizeBuffer(wbuf.data(), size);
-
- ScopedThread t([&] {
- auto const fd = fds[1];
- for (int i = 0; i < state.max_iterations; i++) {
- TEST_CHECK(WriteFd(fd, wbuf.data(), wbuf.size()) == size);
- }
- });
-
- for (auto _ : state) {
- TEST_CHECK(ReadFd(fds[0], rbuf.data(), rbuf.size()) == size);
- }
-
- t.Join();
-
- close(fds[0]);
- close(fds[1]);
-
- state.SetBytesProcessed(static_cast<int64_t>(size) *
- static_cast<int64_t>(state.iterations()));
-}
-
-BENCHMARK(BM_Pipe)->Range(1, 1 << 20)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/randread_benchmark.cc b/test/perf/linux/randread_benchmark.cc
deleted file mode 100644
index b0eb8c24e..000000000
--- a/test/perf/linux/randread_benchmark.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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.
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/logging.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// Create a 1GB file that will be read from at random positions. This should
-// invalid any performance gains from caching.
-const uint64_t kFileSize = 1ULL << 30;
-
-// How many bytes to write at once to initialize the file used to read from.
-const uint32_t kWriteSize = 65536;
-
-// Largest benchmarked read unit.
-const uint32_t kMaxRead = 1UL << 26;
-
-TempPath CreateFile(uint64_t file_size) {
- auto path = TempPath::CreateFile().ValueOrDie();
- FileDescriptor fd = Open(path.path(), O_WRONLY).ValueOrDie();
-
- // Try to minimize syscalls by using maximum size writev() requests.
- std::vector<char> buffer(kWriteSize);
- RandomizeBuffer(buffer.data(), buffer.size());
- const std::vector<std::vector<struct iovec>> iovecs_list =
- GenerateIovecs(file_size, buffer.data(), buffer.size());
- for (const auto& iovecs : iovecs_list) {
- TEST_CHECK(writev(fd.get(), iovecs.data(), iovecs.size()) >= 0);
- }
-
- return path;
-}
-
-// Global test state, initialized once per process lifetime.
-struct GlobalState {
- const TempPath tmpfile;
- explicit GlobalState(TempPath tfile) : tmpfile(std::move(tfile)) {}
-};
-
-GlobalState& GetGlobalState() {
- // This gets created only once throughout the lifetime of the process.
- // Use a dynamically allocated object (that is never deleted) to avoid order
- // of destruction of static storage variables issues.
- static GlobalState* const state =
- // The actual file size is the maximum random seek range (kFileSize) + the
- // maximum read size so we can read that number of bytes at the end of the
- // file.
- new GlobalState(CreateFile(kFileSize + kMaxRead));
- return *state;
-}
-
-void BM_RandRead(benchmark::State& state) {
- const int size = state.range(0);
-
- GlobalState& global_state = GetGlobalState();
- FileDescriptor fd =
- ASSERT_NO_ERRNO_AND_VALUE(Open(global_state.tmpfile.path(), O_RDONLY));
- std::vector<char> buf(size);
-
- unsigned int seed = 1;
- for (auto _ : state) {
- TEST_CHECK(PreadFd(fd.get(), buf.data(), buf.size(),
- rand_r(&seed) % kFileSize) == size);
- }
-
- state.SetBytesProcessed(static_cast<int64_t>(size) *
- static_cast<int64_t>(state.iterations()));
-}
-
-BENCHMARK(BM_RandRead)->Range(1, kMaxRead)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/read_benchmark.cc b/test/perf/linux/read_benchmark.cc
deleted file mode 100644
index 62445867d..000000000
--- a/test/perf/linux/read_benchmark.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/fs_util.h"
-#include "test/util/logging.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_Read(benchmark::State& state) {
- const int size = state.range(0);
- const std::string contents(size, 0);
- auto path = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
- GetAbsoluteTestTmpdir(), contents, TempPath::kDefaultFileMode));
- FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path.path(), O_RDONLY));
-
- std::vector<char> buf(size);
- for (auto _ : state) {
- TEST_CHECK(PreadFd(fd.get(), buf.data(), buf.size(), 0) == size);
- }
-
- state.SetBytesProcessed(static_cast<int64_t>(size) *
- static_cast<int64_t>(state.iterations()));
-}
-
-BENCHMARK(BM_Read)->Range(1, 1 << 26)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/sched_yield_benchmark.cc b/test/perf/linux/sched_yield_benchmark.cc
deleted file mode 100644
index 6756b5575..000000000
--- a/test/perf/linux/sched_yield_benchmark.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#include <sched.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_Sched_yield(benchmark::State& state) {
- for (auto ignored : state) {
- TEST_CHECK(sched_yield() == 0);
- }
-}
-
-BENCHMARK(BM_Sched_yield)->ThreadRange(1, 2000)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/send_recv_benchmark.cc b/test/perf/linux/send_recv_benchmark.cc
deleted file mode 100644
index d73e49523..000000000
--- a/test/perf/linux/send_recv_benchmark.cc
+++ /dev/null
@@ -1,372 +0,0 @@
-// 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.
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <poll.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <cstring>
-
-#include "gtest/gtest.h"
-#include "absl/synchronization/notification.h"
-#include "benchmark/benchmark.h"
-#include "test/syscalls/linux/socket_test_util.h"
-#include "test/util/file_descriptor.h"
-#include "test/util/logging.h"
-#include "test/util/posix_error.h"
-#include "test/util/test_util.h"
-#include "test/util/thread_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-constexpr ssize_t kMessageSize = 1024;
-
-class Message {
- public:
- explicit Message(int byte = 0) : Message(byte, kMessageSize, 0) {}
-
- explicit Message(int byte, int sz) : Message(byte, sz, 0) {}
-
- explicit Message(int byte, int sz, int cmsg_sz)
- : buffer_(sz, byte), cmsg_buffer_(cmsg_sz, 0) {
- iov_.iov_base = buffer_.data();
- iov_.iov_len = sz;
- hdr_.msg_iov = &iov_;
- hdr_.msg_iovlen = 1;
- hdr_.msg_control = cmsg_buffer_.data();
- hdr_.msg_controllen = cmsg_sz;
- }
-
- struct msghdr* header() {
- return &hdr_;
- }
-
- private:
- std::vector<char> buffer_;
- std::vector<char> cmsg_buffer_;
- struct iovec iov_ = {};
- struct msghdr hdr_ = {};
-};
-
-void BM_Recvmsg(benchmark::State& state) {
- int sockets[2];
- TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
- FileDescriptor send_socket(sockets[0]), recv_socket(sockets[1]);
- absl::Notification notification;
- Message send_msg('a'), recv_msg;
-
- ScopedThread t([&send_msg, &send_socket, &notification] {
- while (!notification.HasBeenNotified()) {
- sendmsg(send_socket.get(), send_msg.header(), 0);
- }
- });
-
- int64_t bytes_received = 0;
- for (auto ignored : state) {
- int n = recvmsg(recv_socket.get(), recv_msg.header(), 0);
- TEST_CHECK(n > 0);
- bytes_received += n;
- }
-
- notification.Notify();
- recv_socket.reset();
-
- state.SetBytesProcessed(bytes_received);
-}
-
-BENCHMARK(BM_Recvmsg)->UseRealTime();
-
-void BM_Sendmsg(benchmark::State& state) {
- int sockets[2];
- TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
- FileDescriptor send_socket(sockets[0]), recv_socket(sockets[1]);
- absl::Notification notification;
- Message send_msg('a'), recv_msg;
-
- ScopedThread t([&recv_msg, &recv_socket, &notification] {
- while (!notification.HasBeenNotified()) {
- recvmsg(recv_socket.get(), recv_msg.header(), 0);
- }
- });
-
- int64_t bytes_sent = 0;
- for (auto ignored : state) {
- int n = sendmsg(send_socket.get(), send_msg.header(), 0);
- TEST_CHECK(n > 0);
- bytes_sent += n;
- }
-
- notification.Notify();
- send_socket.reset();
-
- state.SetBytesProcessed(bytes_sent);
-}
-
-BENCHMARK(BM_Sendmsg)->UseRealTime();
-
-void BM_Recvfrom(benchmark::State& state) {
- int sockets[2];
- TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
- FileDescriptor send_socket(sockets[0]), recv_socket(sockets[1]);
- absl::Notification notification;
- char send_buffer[kMessageSize], recv_buffer[kMessageSize];
-
- ScopedThread t([&send_socket, &send_buffer, &notification] {
- while (!notification.HasBeenNotified()) {
- sendto(send_socket.get(), send_buffer, kMessageSize, 0, nullptr, 0);
- }
- });
-
- int bytes_received = 0;
- for (auto ignored : state) {
- int n = recvfrom(recv_socket.get(), recv_buffer, kMessageSize, 0, nullptr,
- nullptr);
- TEST_CHECK(n > 0);
- bytes_received += n;
- }
-
- notification.Notify();
- recv_socket.reset();
-
- state.SetBytesProcessed(bytes_received);
-}
-
-BENCHMARK(BM_Recvfrom)->UseRealTime();
-
-void BM_Sendto(benchmark::State& state) {
- int sockets[2];
- TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == 0);
- FileDescriptor send_socket(sockets[0]), recv_socket(sockets[1]);
- absl::Notification notification;
- char send_buffer[kMessageSize], recv_buffer[kMessageSize];
-
- ScopedThread t([&recv_socket, &recv_buffer, &notification] {
- while (!notification.HasBeenNotified()) {
- recvfrom(recv_socket.get(), recv_buffer, kMessageSize, 0, nullptr,
- nullptr);
- }
- });
-
- int64_t bytes_sent = 0;
- for (auto ignored : state) {
- int n = sendto(send_socket.get(), send_buffer, kMessageSize, 0, nullptr, 0);
- TEST_CHECK(n > 0);
- bytes_sent += n;
- }
-
- notification.Notify();
- send_socket.reset();
-
- state.SetBytesProcessed(bytes_sent);
-}
-
-BENCHMARK(BM_Sendto)->UseRealTime();
-
-PosixErrorOr<sockaddr_storage> InetLoopbackAddr(int family) {
- struct sockaddr_storage addr;
- memset(&addr, 0, sizeof(addr));
- addr.ss_family = family;
- switch (family) {
- case AF_INET:
- reinterpret_cast<struct sockaddr_in*>(&addr)->sin_addr.s_addr =
- htonl(INADDR_LOOPBACK);
- break;
- case AF_INET6:
- reinterpret_cast<struct sockaddr_in6*>(&addr)->sin6_addr =
- in6addr_loopback;
- break;
- default:
- return PosixError(EINVAL,
- absl::StrCat("unknown socket family: ", family));
- }
- return addr;
-}
-
-// BM_RecvmsgWithControlBuf measures the performance of recvmsg when we allocate
-// space for control messages. Note that we do not expect to receive any.
-void BM_RecvmsgWithControlBuf(benchmark::State& state) {
- auto listen_socket =
- ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP));
-
- // Initialize address to the loopback one.
- sockaddr_storage addr = ASSERT_NO_ERRNO_AND_VALUE(InetLoopbackAddr(AF_INET6));
- socklen_t addrlen = sizeof(addr);
-
- // Bind to some port then start listening.
- ASSERT_THAT(bind(listen_socket.get(),
- reinterpret_cast<struct sockaddr*>(&addr), addrlen),
- SyscallSucceeds());
-
- ASSERT_THAT(listen(listen_socket.get(), SOMAXCONN), SyscallSucceeds());
-
- // Get the address we're listening on, then connect to it. We need to do this
- // because we're allowing the stack to pick a port for us.
- ASSERT_THAT(getsockname(listen_socket.get(),
- reinterpret_cast<struct sockaddr*>(&addr), &addrlen),
- SyscallSucceeds());
-
- auto send_socket =
- ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP));
-
- ASSERT_THAT(
- RetryEINTR(connect)(send_socket.get(),
- reinterpret_cast<struct sockaddr*>(&addr), addrlen),
- SyscallSucceeds());
-
- // Accept the connection.
- auto recv_socket =
- ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_socket.get(), nullptr, nullptr));
-
- absl::Notification notification;
- Message send_msg('a');
- // Create a msghdr with a buffer allocated for control messages.
- Message recv_msg(0, kMessageSize, /*cmsg_sz=*/24);
-
- ScopedThread t([&send_msg, &send_socket, &notification] {
- while (!notification.HasBeenNotified()) {
- sendmsg(send_socket.get(), send_msg.header(), 0);
- }
- });
-
- int64_t bytes_received = 0;
- for (auto ignored : state) {
- int n = recvmsg(recv_socket.get(), recv_msg.header(), 0);
- TEST_CHECK(n > 0);
- bytes_received += n;
- }
-
- notification.Notify();
- recv_socket.reset();
-
- state.SetBytesProcessed(bytes_received);
-}
-
-BENCHMARK(BM_RecvmsgWithControlBuf)->UseRealTime();
-
-// BM_SendmsgTCP measures the sendmsg throughput with varying payload sizes.
-//
-// state.Args[0] indicates whether the underlying socket should be blocking or
-// non-blocking w/ 0 indicating non-blocking and 1 to indicate blocking.
-// state.Args[1] is the size of the payload to be used per sendmsg call.
-void BM_SendmsgTCP(benchmark::State& state) {
- auto listen_socket =
- ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
-
- // Initialize address to the loopback one.
- sockaddr_storage addr = ASSERT_NO_ERRNO_AND_VALUE(InetLoopbackAddr(AF_INET));
- socklen_t addrlen = sizeof(addr);
-
- // Bind to some port then start listening.
- ASSERT_THAT(bind(listen_socket.get(),
- reinterpret_cast<struct sockaddr*>(&addr), addrlen),
- SyscallSucceeds());
-
- ASSERT_THAT(listen(listen_socket.get(), SOMAXCONN), SyscallSucceeds());
-
- // Get the address we're listening on, then connect to it. We need to do this
- // because we're allowing the stack to pick a port for us.
- ASSERT_THAT(getsockname(listen_socket.get(),
- reinterpret_cast<struct sockaddr*>(&addr), &addrlen),
- SyscallSucceeds());
-
- auto send_socket =
- ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
-
- ASSERT_THAT(
- RetryEINTR(connect)(send_socket.get(),
- reinterpret_cast<struct sockaddr*>(&addr), addrlen),
- SyscallSucceeds());
-
- // Accept the connection.
- auto recv_socket =
- ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_socket.get(), nullptr, nullptr));
-
- // Check if we want to run the test w/ a blocking send socket
- // or non-blocking.
- const int blocking = state.range(0);
- if (!blocking) {
- // Set the send FD to O_NONBLOCK.
- int opts;
- ASSERT_THAT(opts = fcntl(send_socket.get(), F_GETFL), SyscallSucceeds());
- opts |= O_NONBLOCK;
- ASSERT_THAT(fcntl(send_socket.get(), F_SETFL, opts), SyscallSucceeds());
- }
-
- absl::Notification notification;
-
- // Get the buffer size we should use for this iteration of the test.
- const int buf_size = state.range(1);
- Message send_msg('a', buf_size), recv_msg(0, buf_size);
-
- ScopedThread t([&recv_msg, &recv_socket, &notification] {
- while (!notification.HasBeenNotified()) {
- TEST_CHECK(recvmsg(recv_socket.get(), recv_msg.header(), 0) >= 0);
- }
- });
-
- int64_t bytes_sent = 0;
- int ncalls = 0;
- for (auto ignored : state) {
- int sent = 0;
- while (true) {
- struct msghdr hdr = {};
- struct iovec iov = {};
- struct msghdr* snd_header = send_msg.header();
- iov.iov_base = static_cast<char*>(snd_header->msg_iov->iov_base) + sent;
- iov.iov_len = snd_header->msg_iov->iov_len - sent;
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
- int n = RetryEINTR(sendmsg)(send_socket.get(), &hdr, 0);
- ncalls++;
- if (n > 0) {
- sent += n;
- if (sent == buf_size) {
- break;
- }
- // n can be > 0 but less than requested size. In which case we don't
- // poll.
- continue;
- }
- // Poll the fd for it to become writable.
- struct pollfd poll_fd = {send_socket.get(), POLL_OUT, 0};
- EXPECT_THAT(RetryEINTR(poll)(&poll_fd, 1, 10),
- SyscallSucceedsWithValue(0));
- }
- bytes_sent += static_cast<int64_t>(sent);
- }
-
- notification.Notify();
- send_socket.reset();
- state.SetBytesProcessed(bytes_sent);
-}
-
-void Args(benchmark::internal::Benchmark* benchmark) {
- for (int blocking = 0; blocking < 2; blocking++) {
- for (int buf_size = 1024; buf_size <= 256 << 20; buf_size *= 2) {
- benchmark->Args({blocking, buf_size});
- }
- }
-}
-
-BENCHMARK(BM_SendmsgTCP)->Apply(&Args)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/seqwrite_benchmark.cc b/test/perf/linux/seqwrite_benchmark.cc
deleted file mode 100644
index af49e4477..000000000
--- a/test/perf/linux/seqwrite_benchmark.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// The maximum file size of the test file, when writes get beyond this point
-// they wrap around. This should be large enough to blow away caches.
-const uint64_t kMaxFile = 1 << 30;
-
-// Perform writes of various sizes sequentially to one file. Wraps around if it
-// goes above a certain maximum file size.
-void BM_SeqWrite(benchmark::State& state) {
- auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
- FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_WRONLY));
-
- const int size = state.range(0);
- std::vector<char> buf(size);
- RandomizeBuffer(buf.data(), buf.size());
-
- // Start writes at offset 0.
- uint64_t offset = 0;
- for (auto _ : state) {
- TEST_CHECK(PwriteFd(fd.get(), buf.data(), buf.size(), offset) ==
- buf.size());
- offset += buf.size();
- // Wrap around if going above the maximum file size.
- if (offset >= kMaxFile) {
- offset = 0;
- }
- }
-
- state.SetBytesProcessed(static_cast<int64_t>(size) *
- static_cast<int64_t>(state.iterations()));
-}
-
-BENCHMARK(BM_SeqWrite)->Range(1, 1 << 26)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/signal_benchmark.cc b/test/perf/linux/signal_benchmark.cc
deleted file mode 100644
index a6928df58..000000000
--- a/test/perf/linux/signal_benchmark.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-#include <signal.h>
-#include <string.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void FixupHandler(int sig, siginfo_t* si, void* void_ctx) {
- static unsigned int dataval = 0;
-
- // Skip the offending instruction.
- ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_ctx);
- ctx->uc_mcontext.gregs[REG_RAX] = reinterpret_cast<greg_t>(&dataval);
-}
-
-void BM_FaultSignalFixup(benchmark::State& state) {
- // Set up the signal handler.
- struct sigaction sa = {};
- sigemptyset(&sa.sa_mask);
- sa.sa_sigaction = FixupHandler;
- sa.sa_flags = SA_SIGINFO;
- TEST_CHECK(sigaction(SIGSEGV, &sa, nullptr) == 0);
-
- // Fault, fault, fault.
- for (auto _ : state) {
- register volatile unsigned int* ptr asm("rax");
-
- // Trigger the segfault.
- ptr = nullptr;
- *ptr = 0;
- }
-}
-
-BENCHMARK(BM_FaultSignalFixup)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/sleep_benchmark.cc b/test/perf/linux/sleep_benchmark.cc
deleted file mode 100644
index 99ef05117..000000000
--- a/test/perf/linux/sleep_benchmark.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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.
-
-#include <errno.h>
-#include <sys/syscall.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// Sleep for 'param' nanoseconds.
-void BM_Sleep(benchmark::State& state) {
- const int nanoseconds = state.range(0);
-
- for (auto _ : state) {
- struct timespec ts;
- ts.tv_sec = 0;
- ts.tv_nsec = nanoseconds;
-
- int ret;
- do {
- ret = syscall(SYS_nanosleep, &ts, &ts);
- if (ret < 0) {
- TEST_CHECK(errno == EINTR);
- }
- } while (ret < 0);
- }
-}
-
-BENCHMARK(BM_Sleep)
- ->Arg(0)
- ->Arg(1)
- ->Arg(1000) // 1us
- ->Arg(1000 * 1000) // 1ms
- ->Arg(10 * 1000 * 1000) // 10ms
- ->Arg(50 * 1000 * 1000) // 50ms
- ->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/stat_benchmark.cc b/test/perf/linux/stat_benchmark.cc
deleted file mode 100644
index f15424482..000000000
--- a/test/perf/linux/stat_benchmark.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "absl/strings/str_cat.h"
-#include "benchmark/benchmark.h"
-#include "test/util/fs_util.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// Creates a file in a nested directory hierarchy at least `depth` directories
-// deep, and stats that file multiple times.
-void BM_Stat(benchmark::State& state) {
- // Create nested directories with given depth.
- int depth = state.range(0);
- const TempPath top_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
- std::string dir_path = top_dir.path();
-
- while (depth-- > 0) {
- // Don't use TempPath because it will make paths too long to use.
- //
- // The top_dir destructor will clean up this whole tree.
- dir_path = JoinPath(dir_path, absl::StrCat(depth));
- ASSERT_NO_ERRNO(Mkdir(dir_path, 0755));
- }
-
- // Create the file that will be stat'd.
- const TempPath file =
- ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir_path));
-
- struct stat st;
- for (auto _ : state) {
- ASSERT_THAT(stat(file.path().c_str(), &st), SyscallSucceeds());
- }
-}
-
-BENCHMARK(BM_Stat)->Range(1, 100)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/unlink_benchmark.cc b/test/perf/linux/unlink_benchmark.cc
deleted file mode 100644
index 92243a042..000000000
--- a/test/perf/linux/unlink_benchmark.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// 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.
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/fs_util.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-// Creates a directory containing `files` files, and unlinks all the files.
-void BM_Unlink(benchmark::State& state) {
- // Create directory with given files.
- const int file_count = state.range(0);
-
- // We unlink all files on each iteration, but report this as a "batch"
- // iteration so that reported times are per file.
- TempPath dir;
- while (state.KeepRunningBatch(file_count)) {
- state.PauseTiming();
- // N.B. dir is declared outside the loop so that destruction of the previous
- // iteration's directory occurs here, inside of PauseTiming.
- dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
-
- std::vector<TempPath> files;
- for (int i = 0; i < file_count; i++) {
- TempPath file =
- ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir.path()));
- files.push_back(std::move(file));
- }
- state.ResumeTiming();
-
- while (!files.empty()) {
- // Destructor unlinks.
- files.pop_back();
- }
- }
-
- state.SetItemsProcessed(state.iterations());
-}
-
-BENCHMARK(BM_Unlink)->Range(1, 100 * 1000)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor
diff --git a/test/perf/linux/write_benchmark.cc b/test/perf/linux/write_benchmark.cc
deleted file mode 100644
index 7b060c70e..000000000
--- a/test/perf/linux/write_benchmark.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "gtest/gtest.h"
-#include "benchmark/benchmark.h"
-#include "test/util/logging.h"
-#include "test/util/temp_path.h"
-#include "test/util/test_util.h"
-
-namespace gvisor {
-namespace testing {
-
-namespace {
-
-void BM_Write(benchmark::State& state) {
- auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
- FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_WRONLY));
-
- const int size = state.range(0);
- std::vector<char> buf(size);
- RandomizeBuffer(buf.data(), size);
-
- for (auto _ : state) {
- TEST_CHECK(PwriteFd(fd.get(), buf.data(), size, 0) == size);
- }
-
- state.SetBytesProcessed(static_cast<int64_t>(size) *
- static_cast<int64_t>(state.iterations()));
-}
-
-BENCHMARK(BM_Write)->Range(1, 1 << 26)->UseRealTime();
-
-} // namespace
-
-} // namespace testing
-} // namespace gvisor