Add spec runner C++ script
177.mesa and 164.gzip are currently using this framework to run the
benchmarks
Also adding clang format config file
Change-Id: I85c90cb59d05d11f5334067de6614770bee30f6b
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..b17a52a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: Chromium
+Standard: Cpp11
diff --git a/BUILD.gn b/BUILD.gn
index a0c45f6..aa1418e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -6,6 +6,7 @@
testonly = true
deps = [
+ "benchmarks:speccpu2000_benchmark",
"164.gzip",
"175.vpr",
"176.gcc",
diff --git a/benchmarks/BUILD.gn b/benchmarks/BUILD.gn
new file mode 100644
index 0000000..e6ec77e
--- /dev/null
+++ b/benchmarks/BUILD.gn
@@ -0,0 +1,42 @@
+# Copyright 2016 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config("util_config") {
+ visibility = [ ":*" ]
+ include_dirs = [ "." ]
+}
+
+executable("speccpu2000_benchmark") {
+ testonly = true
+
+ sources = [
+ "main.cc",
+ ]
+
+ deps = [
+ ":spec_utils",
+ "//third_party/benchmark",
+ "//third_party/glog",
+ ]
+}
+
+source_set("spec_utils") {
+ testonly = true
+
+ sources = [
+ "spec_fixture.cc",
+ "spec_utils.cc",
+ ]
+
+ deps = [
+ "//third_party/benchmark",
+ "//third_party/glog",
+ ]
+
+ libs = [
+ "launchpad",
+ "magenta",
+ ]
+ public_configs = [ ":util_config" ]
+}
diff --git a/benchmarks/main.cc b/benchmarks/main.cc
new file mode 100644
index 0000000..38712c1
--- /dev/null
+++ b/benchmarks/main.cc
@@ -0,0 +1,81 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <benchmark/benchmark.h>
+#include <fstream>
+#include <libgen.h>
+#include <spec_fixture.h>
+#include <spec_utils.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glog/logging.h>
+
+namespace {
+
+class MesaFixture : public SpecFixture {
+ protected:
+ MesaFixture() : SpecFixture("177.mesa") {}
+};
+
+class GzipFixture : public SpecFixture {
+ protected:
+ GzipFixture() : SpecFixture("164.gzip"){};
+};
+
+} // namespace
+
+std::string executableDir;
+
+// Where we will run benchmarks
+std::string tmpDir;
+
+BENCHMARK_F(MesaFixture, 177_Mesa)(benchmark::State& st) {
+ while (st.KeepRunning()) {
+ if (RunSpec(NULL, 0) != 0) {
+ st.SkipWithError(
+ (std::string("Error while running benchmark: ") + strerror(errno))
+ .c_str());
+ }
+ }
+}
+
+BENCHMARK_F(GzipFixture, 164_Gzip)(benchmark::State& st) {
+ while (st.KeepRunning()) {
+ std::vector<std::string> inputs = {"input.source", "input.log",
+ "input.graphic", "input.random",
+ "input.program"};
+
+ for (auto& it : inputs) {
+ const char* args[] = {it.c_str(), "60"};
+ if (RunSpec(args, 2) != 0) {
+ st.SkipWithError(
+ (std::string("Error while running benchmark: ") + strerror(errno))
+ .c_str());
+ }
+ }
+ }
+}
+
+int main(int argc, char* argv[]) {
+ ::benchmark::Initialize(&argc, argv);
+ google::InitGoogleLogging(argv[0]);
+ char* cwd;
+ CHECK_NOTNULL((cwd = get_current_dir_name()));
+ executableDir = std::string(cwd) + "/" + dirname(argv[0]);
+
+ char* c = tempnam(NULL, "speccpu2000");
+ CHECK_NOTNULL(c);
+ tmpDir = c;
+
+ CHECK_EQ(mkdir(tmpDir.c_str(), 0600), 0)
+ << "Error while creating tmp dir: " << tmpDir.c_str()
+ << ", error:" << strerror(errno);
+
+ ::benchmark::RunSpecifiedBenchmarks();
+
+ // try deleting temp directory
+ CHECK_EQ(DeleteDir(tmpDir), 0) << "Error while deleting tmp dir: " << tmpDir
+ << ", error:" << strerror(errno);
+ return 0;
+}
diff --git a/benchmarks/spec_fixture.cc b/benchmarks/spec_fixture.cc
new file mode 100644
index 0000000..befc417
--- /dev/null
+++ b/benchmarks/spec_fixture.cc
@@ -0,0 +1,147 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "spec_fixture.h"
+#include "spec_utils.h"
+
+#include <benchmark/benchmark.h>
+#include <fcntl.h>
+#include <fstream>
+#include <glog/logging.h>
+#include <launchpad/launchpad.h>
+#include <magenta/syscalls.h>
+#include <magenta/syscalls/object.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+extern std::string executableDir;
+extern std::string tmpDir;
+extern std::ofstream result;
+
+namespace {
+class ScopedGuard {
+ public:
+ explicit ScopedGuard(std::function<void()> f) : f_(f) {}
+ ~ScopedGuard() noexcept { f_(); }
+ ScopedGuard(const ScopedGuard&) = delete;
+ ScopedGuard(ScopedGuard&&) = delete;
+ ScopedGuard& operator=(const ScopedGuard&) = delete;
+ ScopedGuard& operator=(ScopedGuard&&) = delete;
+
+ private:
+ std::function<void()> f_;
+};
+} // namespace
+
+void SpecFixture::SetUp(benchmark::State& st) {
+ DLOG(INFO) << "Preparing benchmark: " << benchmark_name;
+ run_dir_name = tmpDir + "/" + benchmark_name;
+
+ DLOG(INFO) << "Changing dir to: " << executableDir.c_str();
+ CHECK_EQ(chdir(executableDir.c_str()), 0) << "Not able to change dir to "
+ << executableDir;
+
+ CHECK_EQ(mkdir(run_dir_name.c_str(), 0600), 0)
+ << "Not able to create dir: " << run_dir_name
+ << ", Error: " << strerror(errno);
+
+ CHECK_EQ(CopyDir(run_dir_name, "data/" + benchmark_name), 0)
+ << "Error copying dir: " << run_dir_name
+ << ", Error: " << strerror(errno);
+
+ CHECK_EQ(CopyFile(run_dir_name + "/" + benchmark_name, benchmark_name), 0)
+ << "Error copying binary, Error: " << strerror(errno);
+}
+
+void SpecFixture::TearDown(benchmark::State& st) {
+ CHECK_EQ(DeleteDir(run_dir_name), 0) << "Error Deleting directory "
+ << run_dir_name
+ << ", Error: " << strerror(errno);
+}
+
+int SpecFixture::RunSpec(const char* args[], int args_length) {
+ char** argv = new char*[args_length + 1];
+ argv[0] = (char*)(benchmark_name.c_str());
+ if (args_length > 0) {
+ memcpy(argv + 1, args, args_length * sizeof(char*));
+ }
+
+ if (chdir(run_dir_name.c_str()) != 0) {
+ LOG(ERROR) << "Not able to change dir to " << run_dir_name
+ << ", Error: " << strerror(errno);
+ return errno;
+ }
+
+ DLOG(INFO) << "Running benchmark";
+
+ // Capture output
+ char buffer[PAGE_SIZE];
+ int out_p[2];
+ int old_stdout = dup(STDOUT_FILENO);
+ if (pipe2(out_p, O_NONBLOCK) != 0) {
+ LOG(ERROR) << "Not able create pipe, Error: " << strerror(errno);
+ return errno;
+ }
+ ScopedGuard guard([&]() { close(out_p[0]); });
+ dup2(out_p[1], STDOUT_FILENO);
+ close(out_p[1]);
+
+ int status = LaunchProcess(argv, args_length + 1);
+
+ fflush(stdout);
+ dup2(old_stdout, STDOUT_FILENO);
+ if (chdir(executableDir.c_str()) != 0) {
+ LOG(ERROR) << "Not able to change dir to " << executableDir
+ << ", Error: " << strerror(errno);
+ return errno;
+ }
+ delete[] argv;
+ if (status != 0) {
+ // Dump output
+ LOG(ERROR) << "Error while running benchmark";
+ ssize_t len;
+ do {
+ len = read(out_p[0], buffer, PAGE_SIZE);
+ if (len == -1) {
+ LOG(ERROR) << "Error reading from pipe, Error: " << strerror(errno);
+ return errno;
+ }
+ fwrite(buffer, sizeof(char), len, stderr);
+ } while (len == PAGE_SIZE);
+ fprintf(stderr, "\n");
+ return 1;
+ }
+ return 0;
+}
+
+// TODO: This is for fuchsia, need to write linux specific
+#ifdef __Fuchsia__
+int SpecFixture::LaunchProcess(char** args, int args_length) {
+ mx_handle_t handle = launchpad_launch_mxio(args[0], args_length, args);
+ if (handle < 0) {
+ LOG(ERROR) << "Failed to launch " << args[0] << ":" << handle;
+ return handle;
+ }
+ mx_status_t status =
+ mx_handle_wait_one(handle, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, NULL);
+
+ if (status != NO_ERROR) {
+ LOG(ERROR) << "Failed to wait for process exiting " << args[0] << ":"
+ << status;
+ return status;
+ }
+
+ mx_info_process_t proc_info;
+ ssize_t info_status = mx_object_get_info(handle, MX_INFO_PROCESS, &proc_info,
+ sizeof(proc_info), NULL, NULL);
+ mx_handle_close(handle);
+
+ if (info_status < 0) {
+ LOG(ERROR) << "Failed to get process return code " << args[0] << ":"
+ << info_status;
+ return 1;
+ }
+ return proc_info.return_code;
+}
+#endif
diff --git a/benchmarks/spec_fixture.h b/benchmarks/spec_fixture.h
new file mode 100644
index 0000000..cdeacde
--- /dev/null
+++ b/benchmarks/spec_fixture.h
@@ -0,0 +1,28 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <benchmark/benchmark.h>
+#include <string.h>
+
+class SpecFixture : public benchmark::Fixture {
+ private:
+ std::string run_dir_name;
+
+ // Launch process defined by arg. It returns 1 if execution failure else
+ // returns 0.
+ int LaunchProcess(char** args, int args_length);
+
+ protected:
+ std::string benchmark_name;
+
+ SpecFixture(std::string name) : benchmark_name(name){};
+
+ void SetUp(benchmark::State& st) override;
+
+ void TearDown(benchmark::State& st) override;
+
+ int RunSpec(const char* args[], int args_length);
+};
diff --git a/benchmarks/spec_utils.cc b/benchmarks/spec_utils.cc
new file mode 100644
index 0000000..945761a
--- /dev/null
+++ b/benchmarks/spec_utils.cc
@@ -0,0 +1,122 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "spec_utils.h"
+#include <dirent.h>
+#include <errno.h>
+#include <glog/logging.h>
+#include <launchpad/launchpad.h>
+#include <limits.h>
+#include <magenta/syscalls.h>
+#include <string>
+#include <sys/stat.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+int DeleteDir(std::string dirname) {
+ DLOG(INFO) << "Deleting: " << dirname;
+ DIR* dir = opendir(dirname.c_str());
+ if (dir == NULL) {
+ return errno;
+ }
+
+ struct dirent* de;
+ struct stat stat_buf;
+ while ((de = readdir(dir)) != NULL) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ continue;
+ }
+
+ std::string name = dirname + "/" + de->d_name;
+ if (stat(name.c_str(), &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) {
+ if (DeleteDir(name) != 0) {
+ return errno;
+ }
+ } else {
+ if (unlink(name.c_str()) != 0) {
+ return errno;
+ }
+ }
+ }
+
+ if (closedir(dir) != 0) {
+ return errno;
+ }
+ if (rmdir(dirname.c_str()) != 0) {
+ return errno;
+ }
+ return 0;
+}
+
+int CopyDir(std::string dest_dirname, std::string src_dirname) {
+ DIR* dir = opendir(src_dirname.c_str());
+ if (dir == NULL) {
+ return errno;
+ }
+
+ DLOG(INFO) << "Copy " << src_dirname << " to " << dest_dirname;
+ struct dirent* de;
+ struct stat stat_buf;
+ while ((de = readdir(dir)) != NULL) {
+ std::string name = src_dirname + "/" + de->d_name;
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ continue;
+ }
+
+ if (stat(name.c_str(), &stat_buf) != 0) {
+ return errno;
+ }
+ if (S_ISDIR(stat_buf.st_mode)) {
+ std::string sub_dir = dest_dirname + "/" + de->d_name;
+ if (mkdir(sub_dir.c_str(), 0600) != 0) {
+ return errno;
+ }
+ if (CopyDir(sub_dir, name) != 0) {
+ return errno;
+ }
+ } else if (S_ISREG(stat_buf.st_mode)) {
+ if (CopyFile(dest_dirname + "/" + de->d_name, name) != 0) {
+ return errno;
+ }
+ }
+ }
+ if (closedir(dir) != 0) {
+ return errno;
+ }
+ return 0;
+}
+
+int CopyFile(std::string dest, std::string src) {
+ char buf[PAGE_SIZE];
+ size_t size;
+ DLOG(INFO) << "Copy " << src << " to " << dest;
+ FILE* srcfile = fopen(src.c_str(), "rb");
+ if (srcfile == NULL) {
+ return errno;
+ }
+ FILE* destfile = fopen(dest.c_str(), "wb");
+ if (destfile == NULL) {
+ return errno;
+ }
+
+ while ((size = fread(buf, 1, PAGE_SIZE, srcfile))) {
+ if (fwrite(buf, 1, size, destfile) != size) {
+ return errno;
+ }
+ }
+
+ if (fclose(srcfile) != 0) {
+ return errno;
+ }
+ if (fflush(destfile) != 0) {
+ return errno;
+ }
+ if (fclose(destfile) != 0) {
+ return errno;
+ }
+ return 0;
+}
diff --git a/benchmarks/spec_utils.h b/benchmarks/spec_utils.h
new file mode 100644
index 0000000..0141607
--- /dev/null
+++ b/benchmarks/spec_utils.h
@@ -0,0 +1,18 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <string>
+#include <sys/time.h>
+
+// Deletes Directory recursively.
+// Retunrs errno if error in deleting
+int DeleteDir(std::string dirname);
+
+// Copies directory recursively.
+int CopyDir(std::string dest_dirname, std::string src_dirname);
+
+// Copies content of the file.
+int CopyFile(std::string dest, std::string src);