| // 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(); |
| } |