diff --git a/garnet/bin/cpuperf_provider/BUILD.gn b/garnet/bin/cpuperf_provider/BUILD.gn index eec859db08ca1455460df2f96dbebe1ef74e463e..0102a95d4ab720fb8040a983ba7eb6a651232002 100644 --- a/garnet/bin/cpuperf_provider/BUILD.gn +++ b/garnet/bin/cpuperf_provider/BUILD.gn @@ -103,10 +103,26 @@ executable("cpuperf_provider_tests_bin") { ] } +executable("cpuperf_provider_integration_tests") { + testonly = true + output_name = "cpuperf_provider_integration_tests" + + sources = [ + "cpuperf_provider_integration_tests.cc" + ] + + deps = [ + "//garnet/lib/perfmon", + "//src/developer/tracing/lib/test_utils", + "//third_party/googletest:gtest", + "//zircon/public/lib/trace-reader", + "//zircon/public/lib/zx", + ] +} + test_package("cpuperf_provider_tests") { deps = [ ":cpuperf_provider_tests_bin", - "//src/lib/fxl", ] tests = [ @@ -115,4 +131,17 @@ test_package("cpuperf_provider_tests") { environments = basic_envs }, ] + + if (current_cpu == "x64") { + deps += [ + ":cpuperf_provider_integration_tests", + ] + + tests += [ + { + name = "cpuperf_provider_integration_tests" + environments = basic_envs + }, + ] + } } diff --git a/garnet/bin/cpuperf_provider/app.cc b/garnet/bin/cpuperf_provider/app.cc index 99beeb0a51d8a17f6258f216e2b1bdf39749abde..7df2177e184dc95687db42f6d9e9e35d84b1e8a2 100644 --- a/garnet/bin/cpuperf_provider/app.cc +++ b/garnet/bin/cpuperf_provider/app.cc @@ -103,13 +103,11 @@ void App::PrintHelp() { void App::UpdateState() { if (trace_state() == TRACE_STARTED) { + FXL_DCHECK(!IsTracing()); auto new_config = TraceConfig::Create(model_event_manager_.get(), trace_is_category_enabled); - if (new_config && trace_config_->Changed(*new_config)) { - StopTracing(); - if (new_config->is_enabled()) { - StartTracing(std::move(new_config)); - } + if (new_config != nullptr && new_config->is_enabled()) { + StartTracing(std::move(new_config)); } } else { StopTracing(); @@ -157,8 +155,8 @@ Fail: } void App::StopTracing() { - if (!context_) { - return; // not currently tracing + if (!IsTracing()) { + return; } FXL_DCHECK(trace_config_->is_enabled()); diff --git a/garnet/bin/cpuperf_provider/app.h b/garnet/bin/cpuperf_provider/app.h index cd77d983f04b24bfaf25ba9a16d49b0be01cfab6..1a70dfe51aa0ddb3dde2fe7c9cdb7da2f75e1a6f 100644 --- a/garnet/bin/cpuperf_provider/app.h +++ b/garnet/bin/cpuperf_provider/app.h @@ -28,6 +28,7 @@ class App { void StartTracing(std::unique_ptr<TraceConfig> trace_config); void StopTracing(); + bool IsTracing() const { return context_ != nullptr; } void PrintHelp(); diff --git a/garnet/bin/cpuperf_provider/cpuperf_provider_integration_tests.cc b/garnet/bin/cpuperf_provider/cpuperf_provider_integration_tests.cc new file mode 100644 index 0000000000000000000000000000000000000000..16f88c344bbd89f1959ee0ed416db5a523ff910e --- /dev/null +++ b/garnet/bin/cpuperf_provider/cpuperf_provider_integration_tests.cc @@ -0,0 +1,93 @@ +// 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 <gtest/gtest.h> +#include <lib/zx/job.h> +#include <lib/zx/process.h> +#include <src/developer/tracing/lib/test_utils/spawn_and_wait.h> +#include <src/lib/fxl/command_line.h> +#include <src/lib/fxl/log_settings_command_line.h> +#include <src/lib/fxl/logging.h> +#include <trace-reader/file_reader.h> + +#include "garnet/lib/perfmon/controller.h" + +const char kTracePath[] = "/bin/trace"; + +const char kDurationArg[] = "--duration=1"; + +// Note: /data is no longer large enough in qemu sessions +const char kOutputFile[] = "/tmp/test-trace.fxt"; + +#if defined(__x86_64__) +const char kCategoriesArg[] = + "--categories=cpu:fixed:instructions_retired,cpu:tally"; +const char kCategoryName[] = "cpu:perf"; +const char kTestEventName[] = "instructions_retired"; +#else +#error "unsupported architecture" +#endif + +TEST(CpuperfProvider, IntegrationTest) { + zx::job job; + ASSERT_EQ(zx::job::create(*zx::job::default_job(), 0, &job), ZX_OK); + + zx::process child; + std::vector<std::string> argv{ + kTracePath, "record", "--binary", kDurationArg, kCategoriesArg, + std::string("--output-file=") + kOutputFile}; + ASSERT_EQ(SpawnProgram(job, argv, ZX_HANDLE_INVALID, &child), ZX_OK); + + int return_code; + ASSERT_EQ(WaitAndGetExitCode(argv[0], child, &return_code), ZX_OK); + EXPECT_EQ(return_code, 0); + + size_t record_count = 0; + size_t instructions_retired_count = 0; + auto record_consumer = [&record_count, &instructions_retired_count](trace::Record record) { + ++record_count; + if (record.type() == trace::RecordType::kEvent) { + const trace::Record::Event& event = record.GetEvent(); + if (event.type() == trace::EventType::kCounter && + event.category == kCategoryName && + event.name == kTestEventName) { + ++instructions_retired_count; + } + } + }; + + bool got_error = false; + auto error_handler = [&got_error](fbl::String error) { + FXL_LOG(ERROR) << "While reading records got error: " << error.c_str(); + got_error = true; + }; + + std::unique_ptr<trace::FileReader> reader; + ASSERT_TRUE(trace::FileReader::Create(kOutputFile, + std::move(record_consumer), + std::move(error_handler), &reader)); + reader->ReadFile(); + ASSERT_FALSE(got_error); + + FXL_LOG(INFO) << "Got " << record_count << " records, " + << instructions_retired_count << " instructions"; + + ASSERT_GT(instructions_retired_count, 0u); +} + +// Provide our own main so that --verbose,etc. are recognized. +int main(int argc, char** argv) { + fxl::CommandLine cl = fxl::CommandLineFromArgcArgv(argc, argv); + if (!fxl::SetLogSettingsFromCommandLine(cl)) + return EXIT_FAILURE; + + if (!perfmon::Controller::IsSupported()) { + FXL_LOG(INFO) << "Exiting, perfmon device not supported"; + return 0; + } + + testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} diff --git a/garnet/bin/cpuperf_provider/main.cc b/garnet/bin/cpuperf_provider/main.cc index 2943db21bca1134bb88e90e6b07c029b42191339..c5652d8be241e26067e10bf2bc9de075f323a5c4 100644 --- a/garnet/bin/cpuperf_provider/main.cc +++ b/garnet/bin/cpuperf_provider/main.cc @@ -9,12 +9,18 @@ #include <trace-provider/provider.h> #include "garnet/bin/cpuperf_provider/app.h" +#include "garnet/lib/perfmon/controller.h" int main(int argc, const char** argv) { auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); if (!fxl::SetLogSettingsFromCommandLine(command_line)) return 1; + if (!perfmon::Controller::IsSupported()) { + FXL_LOG(INFO) << "Exiting, perfmon device not supported"; + return 0; + } + FXL_VLOG(2) << argv[0] << ": starting"; async::Loop loop(&kAsyncLoopConfigAttachToThread); diff --git a/garnet/bin/cpuperf_provider/meta/cpuperf_provider_integration_tests.cmx b/garnet/bin/cpuperf_provider/meta/cpuperf_provider_integration_tests.cmx new file mode 100644 index 0000000000000000000000000000000000000000..d1e37b533075b9cb2fae4764384d48cf43154b45 --- /dev/null +++ b/garnet/bin/cpuperf_provider/meta/cpuperf_provider_integration_tests.cmx @@ -0,0 +1,33 @@ +{ + "facets": { + "fuchsia.test": { + "injected-services": { + "fuchsia.tracelink.Registry": [ + "fuchsia-pkg://fuchsia.com/trace_manager#meta/trace_manager.cmx", + "--verbose=4" + ], + "fuchsia.tracing.controller.Controller": [ + "fuchsia-pkg://fuchsia.com/trace_manager#meta/trace_manager.cmx", + "--verbose=4" + ] + } + } + }, + "program": { + "binary": "test/cpuperf_provider_integration_tests" + }, + "sandbox": { + "dev": [ "sys/cpu-trace" ], + "features": [ + "shell", + "system-temp" + ], + "services": [ + "fuchsia.sys.Launcher", + "fuchsia.process.Launcher", + "fuchsia.process.Resolver", + "fuchsia.tracelink.Registry", + "fuchsia.tracing.controller.Controller" + ] + } +} diff --git a/garnet/packages/tests/BUILD.gn b/garnet/packages/tests/BUILD.gn index a86339c8e9bbc31cc3bc79775b7e0486b04352d5..8bf2fe2ddd6d025768765f967b31046a951ed641 100644 --- a/garnet/packages/tests/BUILD.gn +++ b/garnet/packages/tests/BUILD.gn @@ -59,6 +59,7 @@ group("libinet") { group("tracing") { testonly = true public_deps = [ + "//garnet/bin/cpuperf_provider:cpuperf_provider_tests", "//garnet/bin/trace/tests:trace_tests", "//garnet/bin/trace2json:trace2json_tests($host_toolchain)", "//garnet/bin/trace_stress",