blob: c24eec56bb21e593b3e23fbd2d960bf8d57ad5c2 [file] [log] [blame]
// 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 <sys/stat.h>
#include <unistd.h>
#ifdef __unix__
#include <spawn.h>
#include <sys/wait.h>
#endif
#ifdef __Fuchsia__
#include <launchpad/launchpad.h>
#include <magenta/syscalls.h>
#include <magenta/syscalls/object.h>
#endif
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(), 0700), 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);
std::string binary = run_dir_name + "/" + benchmark_name;
CHECK_EQ(CopyFile(binary, benchmark_name), 0)
<< "Error copying binary, Error: " << strerror(errno);
CHECK_EQ(chmod(binary.c_str(), 0700), 0)
<< "Error changing file permission for binary: " << 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) {
int page_size = getpagesize();
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;
}
#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
#ifdef __unix__
int SpecFixture::LaunchProcess(char** args, int args_length) {
run_dir_name = tmpDir + "/" + benchmark_name + "/";
std::string command = run_dir_name + args[0];
char** argv = new char*[args_length + 1];
ScopedGuard guard([&]() { delete[] argv; });
for (int i = 0; i < args_length; i++) {
argv[i] = args[i];
}
argv[args_length] = NULL;
pid_t pid;
int status = posix_spawn(&pid, command.c_str(), NULL, NULL, argv, environ);
if (status == 0) {
if (waitpid(pid, &status, 0) != -1) {
return status;
} else {
LOG(ERROR) << "waitpid error: " << strerror(errno);
}
} else {
LOG(ERROR) << "posix_spawn error: " << strerror(status);
}
return -1;
}
#endif