blob: 98065211876623eac3d8c0e9c871c7775adf3cae [file] [log] [blame]
// Copyright 2019 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 <fuchsia/hardware/cpu/insntrace/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/job.h>
#include <lib/zx/process.h>
#include <unistd.h>
#include <zircon/syscalls.h>
#include <gtest/gtest.h>
#include "src/developer/tracing/lib/test_utils/run_program.h"
#include "src/lib/fxl/command_line.h"
#include "src/lib/fxl/test/test_settings.h"
namespace {
using ControllerSyncPtr = ::fuchsia::hardware::cpu::insntrace::ControllerSyncPtr;
const char kInsntraceDevicePath[] = "/dev/sys/cpu-trace/insntrace";
#ifdef __x86_64__
const char kInsntracePath[] = "/bin/insntrace";
// These files should be created when running insntrace.
const char* const kResultFileList[] = {
"/tmp/ptout.cpuid",
"/tmp/ptout.ktrace",
"/tmp/ptout.ptlist",
};
TEST(Insntrace, Control) {
zx::job job{}; // -> default job
// A note on file sizes:
// The default size of the output file is 256K. With 4 cpus that's 1MB
// which is fine. There is also the ktrace buffer which is 32MB by default.
std::vector<std::string> start_argv{kInsntracePath, "--control", "init", "start"};
ASSERT_TRUE(tracing::test::RunProgramAndWait(job, start_argv, 0, nullptr));
// Give tracing something to trace.
std::vector<std::string> help_argv{kInsntracePath, "--help"};
ASSERT_TRUE(tracing::test::RunProgramAndWait(job, help_argv, 0, nullptr));
std::vector<std::string> stop_argv{kInsntracePath, "--control", "stop", "dump", "reset"};
ASSERT_TRUE(tracing::test::RunProgramAndWait(job, stop_argv, 0, nullptr));
// There's not much more we can do at this point, beyond verifying the
// expected files exist. Examining them requires the reader-library which
// is a host-side tool.
for (const auto& path : kResultFileList) {
EXPECT_EQ(access(path, R_OK), 0) << "Missing: " << path;
unlink(path);
}
unsigned num_cpus = zx_system_get_num_cpus();
static const char kCpuOutputPathPattern[] = "/tmp/ptout.cpu%u.pt";
char cpu_output_path[sizeof(kCpuOutputPathPattern) + 10];
for (unsigned cpu = 0; cpu < num_cpus; ++cpu) {
snprintf(cpu_output_path, sizeof(cpu_output_path), kCpuOutputPathPattern, cpu);
EXPECT_EQ(access(cpu_output_path, R_OK), 0) << "Missing: " << cpu_output_path;
unlink(cpu_output_path);
}
}
#endif // __x86_64__
ControllerSyncPtr OpenDevice() {
ControllerSyncPtr controller_ptr;
zx_status_t status = fdio_service_connect(kInsntraceDevicePath,
controller_ptr.NewRequest().TakeChannel().release());
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Error connecting to " << kInsntraceDevicePath << ": " << status;
return ControllerSyncPtr();
}
return controller_ptr;
}
bool IsSupported() {
ControllerSyncPtr ipt{OpenDevice()};
if (!ipt) {
return false;
}
// TODO(dje): Need fidl interface to query device properties.
::fuchsia::hardware::cpu::insntrace::Controller_Terminate_Result result;
zx_status_t status = ipt->Terminate(&result);
if (status != ZX_OK) {
FX_VLOGS(1) << "Is-supported proxy(terminate) failed: " << status;
return false;
}
FX_DCHECK(result.is_err());
if (result.is_err()) {
FX_VLOGS(1) << "Is-supported proxy(terminate) received: " << result.err();
return result.err() == ZX_ERR_BAD_STATE;
}
FX_VLOGS(1) << "Is-supported proxy(terminate) failed";
return false;
}
} // namespace
// Provide our own main so that we can do an early-exit if instruction
// tracing is not supported.
int main(int argc, char** argv) {
auto cl = fxl::CommandLineFromArgcArgv(argc, argv);
if (!fxl::SetTestSettings(cl))
return EXIT_FAILURE;
// Early exit if there is no insntrace device.
if (!IsSupported()) {
FX_LOGS(INFO) << "Insntrace device not supported";
return EXIT_SUCCESS;
}
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}