diff --git a/src/cobalt/bin/system-metrics/BUILD.gn b/src/cobalt/bin/system-metrics/BUILD.gn index 0a80b547c0d31320be66e1eb1df66e54689af380..7e10432d9d56fce1e9eb39a6af91755ddfb0ed46 100644 --- a/src/cobalt/bin/system-metrics/BUILD.gn +++ b/src/cobalt/bin/system-metrics/BUILD.gn @@ -15,6 +15,9 @@ metrics_registry("metrics_registry") { source_set("system_metrics_daemon_lib") { sources = [ + "cpu_stats_fetcher.h", + "cpu_stats_fetcher_impl.cc", + "cpu_stats_fetcher_impl.h", "memory_stats_fetcher.h", "memory_stats_fetcher_impl.cc", "memory_stats_fetcher_impl.h", @@ -27,9 +30,9 @@ source_set("system_metrics_daemon_lib") { "//garnet/public/lib/fsl", "//sdk/lib/sys/cpp", "//src/cobalt/bin/utils:clock", + "//src/lib/cobalt/cpp:cobalt_event_builder", "//zircon/public/fidl/fuchsia-cobalt", "//zircon/public/fidl/fuchsia-sysinfo:fuchsia-sysinfo_c", - "//src/lib/cobalt/cpp:cobalt_event_builder", "//zircon/public/lib/async-loop-cpp", "//zircon/public/lib/trace", "//zircon/public/lib/trace-provider", @@ -69,6 +72,8 @@ executable("cobalt_system_metrics_unittests") { testonly = true sources = [ + "fake_cpu_stats_fetcher.cc", + "fake_cpu_stats_fetcher.h", "fake_memory_stats_fetcher.cc", "fake_memory_stats_fetcher.h", "system_metrics_daemon_test.cc", diff --git a/src/cobalt/bin/system-metrics/cpu_stats_fetcher.h b/src/cobalt/bin/system-metrics/cpu_stats_fetcher.h new file mode 100644 index 0000000000000000000000000000000000000000..fc1452ddb14aee763ca2edc04e833b1eb6b4a23c --- /dev/null +++ b/src/cobalt/bin/system-metrics/cpu_stats_fetcher.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef SRC_COBALT_BIN_SYSTEM_METRICS_CPU_STATS_FETCHER_H_ +#define SRC_COBALT_BIN_SYSTEM_METRICS_CPU_STATS_FETCHER_H_ + +#include <lib/zx/resource.h> + +namespace cobalt { + +// An abstrace interface for cpu stats fetching from various +// resources +class CpuStatsFetcher { + public: + virtual ~CpuStatsFetcher() = default; + + // Get average CPU percentage used over all CPU cores since + // the last time this function is called. + // + // Return true if this is not the first time this function is + // called. Pass the calculated percentage in cpu_percentage. + // Return false if this is the first time this function is called + // and there is not a time range during which we can calculate + // the average CPU used. + virtual bool FetchCpuPercentage(double *cpu_percentage) = 0; +}; + +} // namespace cobalt + +#endif // SRC_COBALT_BIN_SYSTEM_METRICS_CPU_STATS_FETCHER_H_ diff --git a/src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.cc b/src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.cc new file mode 100644 index 0000000000000000000000000000000000000000..b16d37a8940cd8789e53d13f2e84403f5ca237f4 --- /dev/null +++ b/src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.cc @@ -0,0 +1,124 @@ +// 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 "src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.h" + +#include <fcntl.h> +#include <fuchsia/cobalt/cpp/fidl.h> +#include <fuchsia/sysinfo/c/fidl.h> +#include <lib/fdio/fdio.h> +#include <lib/zx/resource.h> +#include <trace/event.h> +#include <zircon/status.h> + +#include "src/lib/fxl/logging.h" + +namespace cobalt { + +CpuStatsFetcherImpl::CpuStatsFetcherImpl() { InitializeRootResourceHandle(); } + +bool CpuStatsFetcherImpl::FetchCpuPercentage(double *cpu_percentage) { + TRACE_DURATION("system_metrics", "CpuStatsFetcherImpl::FetchCpuPercentage"); + if (FetchCpuStats() == false) { + return false; + } + bool success = CalculateCpuPercentage(cpu_percentage); + last_cpu_stats_.swap(cpu_stats_); + + last_cpu_fetch_time_ = cpu_fetch_time_; + return success; +} + +bool CpuStatsFetcherImpl::FetchCpuStats() { + if (root_resource_handle_ == ZX_HANDLE_INVALID) { + FXL_LOG(ERROR) << "CpuStatsFetcherImpl: No root resource " + << "present. Reconnecting..."; + InitializeRootResourceHandle(); + return false; + } + size_t actual, available; + cpu_fetch_time_ = std::chrono::high_resolution_clock::now(); + zx_status_t err = zx_object_get_info( + root_resource_handle_, ZX_INFO_CPU_STATS, &cpu_stats_[0], + cpu_stats_.size() * sizeof(zx_info_cpu_stats_t), &actual, &available); + if (err != ZX_OK) { + FXL_LOG(ERROR) << "CpuStatsFetcherImpl: Fetching " + << "ZX_INFO_CPU_STATS through syscall returns " + << zx_status_get_string(err); + return false; + } + if (actual < available) { + FXL_LOG(WARNING) << "CpuStatsFetcherImpl: actual CPUs reported " << actual + << " is less than available CPUs " << available + << ". Please increase zx_info_cpu_stats_t vector size!" + << sizeof(cpu_stats_); + return false; + } + if (num_cpu_cores_ == 0) { + num_cpu_cores_ = actual; + } + return true; +} + +bool CpuStatsFetcherImpl::CalculateCpuPercentage(double *cpu_percentage) { + if (last_cpu_stats_.empty()) { + return false; + } + auto elapsed_time = std::chrono::duration_cast<std::chrono::nanoseconds>( + cpu_fetch_time_ - last_cpu_fetch_time_) + .count(); + double cpu_percentage_sum = 0; + for (size_t i = 0; i < num_cpu_cores_; i++) { + zx_duration_t delta_idle_time = zx_duration_sub_duration( + cpu_stats_[i].idle_time, last_cpu_stats_[i].idle_time); + zx_duration_t delta_busy_time = + (delta_idle_time > elapsed_time ? 0 : elapsed_time - delta_idle_time); + cpu_percentage_sum += static_cast<double>(delta_busy_time) * 100 / + static_cast<double>(elapsed_time); + } + *cpu_percentage = cpu_percentage_sum / static_cast<double>(num_cpu_cores_); + return true; +} + +// TODO(CF-691) When Component Stats (CS) supports cpu metrics, +// switch to Component Stats / iquery, by creating a new class with the +// interface CpuStatsFetcher. +void CpuStatsFetcherImpl::InitializeRootResourceHandle() { + static const char kSysInfo[] = "/dev/misc/sysinfo"; + int fd = open(kSysInfo, O_RDWR); + if (fd < 0) { + FXL_LOG(ERROR) + << "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. " + << "Cannot open sysinfo: " << strerror(errno); + return; + } + zx::channel channel; + zx_status_t status = + fdio_get_service_handle(fd, channel.reset_and_get_address()); + if (status != ZX_OK) { + FXL_LOG(ERROR) + << "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. " + << "Cannot obtain sysinfo channel: " << zx_status_get_string(status); + return; + } + zx_status_t fidl_status = fuchsia_sysinfo_DeviceGetRootResource( + channel.get(), &status, &root_resource_handle_); + if (fidl_status != ZX_OK) { + FXL_LOG(ERROR) + << "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. " + << zx_status_get_string(fidl_status); + return; + } else if (status != ZX_OK) { + FXL_LOG(ERROR) + << "Cobalt SystemMetricsDaemon: Error getting root_resource_handle_. " + << zx_status_get_string(status); + return; + } else if (root_resource_handle_ == ZX_HANDLE_INVALID) { + FXL_LOG(ERROR) + << "Cobalt SystemMetricsDaemon: Failed to get root_resource_handle_."; + return; + } +} + +} // namespace cobalt diff --git a/src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.h b/src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..ec8660b3ddbf06cd491d38ea02e96ef4801e9442 --- /dev/null +++ b/src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.h @@ -0,0 +1,42 @@ +// 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. + +#ifndef SRC_COBALT_BIN_SYSTEM_METRICS_CPU_STATS_FETCHER_IMPL_H_ +#define SRC_COBALT_BIN_SYSTEM_METRICS_CPU_STATS_FETCHER_IMPL_H_ + +#include <lib/zx/resource.h> + +#include <chrono> +#include <vector> + +#include "src/cobalt/bin/system-metrics/cpu_stats_fetcher.h" + +using cobalt::CpuStatsFetcher; + +namespace cobalt { + +class CpuStatsFetcherImpl : public CpuStatsFetcher { + public: + CpuStatsFetcherImpl(); + bool FetchCpuPercentage(double *cpu_percentage) override; + + private: + bool FetchCpuCoreCount(); + bool FetchCpuStats(); + bool CalculateCpuPercentage(double *cpu_percentage); + void InitializeRootResourceHandle(); + + zx_handle_t root_resource_handle_ = ZX_HANDLE_INVALID; + size_t num_cpu_cores_ = 0; + std::chrono::time_point<std::chrono::high_resolution_clock> cpu_fetch_time_; + std::chrono::time_point<std::chrono::high_resolution_clock> + last_cpu_fetch_time_; + // TODO: Determine the vector size at runtime (32 is arbitrary). + std::vector<zx_info_cpu_stats_t> cpu_stats_{32}; + std::vector<zx_info_cpu_stats_t> last_cpu_stats_{32}; +}; + +} // namespace cobalt + +#endif // SRC_COBALT_BIN_SYSTEM_METRICS_CPU_STATS_FETCHER_IMPL_H_ diff --git a/src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.cc b/src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.cc new file mode 100644 index 0000000000000000000000000000000000000000..6d6b31a60d60b54b157a16fd806392e771e5b217 --- /dev/null +++ b/src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.cc @@ -0,0 +1,18 @@ +// 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 "src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.h" + +#include <lib/zx/resource.h> + +namespace cobalt { + +FakeCpuStatsFetcher::FakeCpuStatsFetcher() {} + +bool FakeCpuStatsFetcher::FetchCpuPercentage(double *cpu_percentage) { + *cpu_percentage = 12.34; + return true; +} + +} // namespace cobalt diff --git a/src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.h b/src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.h new file mode 100644 index 0000000000000000000000000000000000000000..a30f856084c1b8bf2209ea9126723688358221ae --- /dev/null +++ b/src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.h @@ -0,0 +1,22 @@ +// 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. + +#ifndef SRC_COBALT_BIN_SYSTEM_METRICS_FAKE_CPU_STATS_FETCHER_H_ +#define SRC_COBALT_BIN_SYSTEM_METRICS_FAKE_CPU_STATS_FETCHER_H_ + +#include <lib/zx/resource.h> + +#include "src/cobalt/bin/system-metrics/cpu_stats_fetcher.h" + +namespace cobalt { + +class FakeCpuStatsFetcher : public cobalt::CpuStatsFetcher { + public: + FakeCpuStatsFetcher(); + bool FetchCpuPercentage(double *cpu_percentage) override; +}; + +} // namespace cobalt + +#endif // SRC_COBALT_BIN_SYSTEM_METRICS_FAKE_CPU_STATS_FETCHER_H_ diff --git a/src/cobalt/bin/system-metrics/memory_stats_fetcher.h b/src/cobalt/bin/system-metrics/memory_stats_fetcher.h index c579e5826b58551c9ea403e2dadedc0054ca72ad..3db45611cab76b3f6e774059969c8baae7cebdb6 100644 --- a/src/cobalt/bin/system-metrics/memory_stats_fetcher.h +++ b/src/cobalt/bin/system-metrics/memory_stats_fetcher.h @@ -9,7 +9,8 @@ namespace cobalt { -// An abstrace interface to a +// An abstrace interface for memory stats fetching from various +// resources class MemoryStatsFetcher { public: virtual ~MemoryStatsFetcher() = default; diff --git a/src/cobalt/bin/system-metrics/memory_stats_fetcher_impl.cc b/src/cobalt/bin/system-metrics/memory_stats_fetcher_impl.cc index f719ea6cb541a6d0f13e18dcbc17c200cbc3bb41..2466d084aa557955a9163fd9c4cd1f53d607c1b5 100644 --- a/src/cobalt/bin/system-metrics/memory_stats_fetcher_impl.cc +++ b/src/cobalt/bin/system-metrics/memory_stats_fetcher_impl.cc @@ -9,6 +9,7 @@ #include <fuchsia/sysinfo/c/fidl.h> #include <lib/fdio/fdio.h> #include <lib/zx/resource.h> +#include <trace/event.h> #include <zircon/status.h> #include "src/lib/fxl/logging.h" @@ -20,6 +21,7 @@ MemoryStatsFetcherImpl::MemoryStatsFetcherImpl() { } bool MemoryStatsFetcherImpl::FetchMemoryStats(zx_info_kmem_stats_t* mem_stats) { + TRACE_DURATION("system_metrics", "MemoryStatsFetcherImpl::FetchMemoryStats"); if (root_resource_handle_ == ZX_HANDLE_INVALID) { FXL_LOG(ERROR) << "MemoryStatsFetcherImpl: No root resource" << "present. Reconnecting..."; diff --git a/src/cobalt/bin/system-metrics/system_metrics_daemon.cc b/src/cobalt/bin/system-metrics/system_metrics_daemon.cc index 8ea81ed9c93b93402dfdba1ee78c9ff518a44c36..d091803cc5049ffdaeb05a9a3adcb6e19e28f020 100644 --- a/src/cobalt/bin/system-metrics/system_metrics_daemon.cc +++ b/src/cobalt/bin/system-metrics/system_metrics_daemon.cc @@ -19,8 +19,11 @@ #include <chrono> #include <memory> +#include <numeric> #include <thread> +#include <vector> +#include "src/cobalt/bin/system-metrics/cpu_stats_fetcher_impl.h" #include "src/cobalt/bin/system-metrics/memory_stats_fetcher_impl.h" #include "src/cobalt/bin/system-metrics/metrics_registry.cb.h" #include "src/cobalt/bin/utils/clock.h" @@ -48,7 +51,9 @@ SystemMetricsDaemon::SystemMetricsDaemon(async_dispatcher_t* dispatcher, dispatcher, context, nullptr, std::unique_ptr<cobalt::SteadyClock>(new cobalt::RealSteadyClock()), std::unique_ptr<cobalt::MemoryStatsFetcher>( - new cobalt::MemoryStatsFetcherImpl())) { + new cobalt::MemoryStatsFetcherImpl()), + std::unique_ptr<cobalt::CpuStatsFetcher>( + new cobalt::CpuStatsFetcherImpl())) { InitializeLogger(); } @@ -56,18 +61,21 @@ SystemMetricsDaemon::SystemMetricsDaemon( async_dispatcher_t* dispatcher, sys::ComponentContext* context, fuchsia::cobalt::Logger_Sync* logger, std::unique_ptr<cobalt::SteadyClock> clock, - std::unique_ptr<cobalt::MemoryStatsFetcher> memory_stats_fetcher) + std::unique_ptr<cobalt::MemoryStatsFetcher> memory_stats_fetcher, + std::unique_ptr<cobalt::CpuStatsFetcher> cpu_stats_fetcher) : dispatcher_(dispatcher), context_(context), logger_(logger), start_time_(clock->Now()), clock_(std::move(clock)), - memory_stats_fetcher_(std::move(memory_stats_fetcher)) {} + memory_stats_fetcher_(std::move(memory_stats_fetcher)), + cpu_stats_fetcher_(std::move(cpu_stats_fetcher)) {} void SystemMetricsDaemon::StartLogging() { TRACE_DURATION("system_metrics", "SystemMetricsDaemon::StartLogging"); // We keep gathering metrics until this process is terminated. RepeatedlyLogUpTimeAndLifeTimeEvents(); + RepeatedlyLogCpuUsage(); RepeatedlyLogMemoryUsage(); } @@ -79,6 +87,14 @@ void SystemMetricsDaemon::RepeatedlyLogUpTimeAndLifeTimeEvents() { return; } +void SystemMetricsDaemon::RepeatedlyLogCpuUsage() { + std::chrono::seconds seconds_to_sleep = LogCpuUsage(); + async::PostDelayedTask( + dispatcher_, [this]() { RepeatedlyLogCpuUsage(); }, + zx::sec(seconds_to_sleep.count())); + return; +} + void SystemMetricsDaemon::RepeatedlyLogMemoryUsage() { std::chrono::seconds seconds_to_sleep = LogMemoryUsage(); async::PostDelayedTask( @@ -236,6 +252,52 @@ std::chrono::seconds SystemMetricsDaemon::LogFuchsiaLifetimeEvents() { return std::chrono::seconds::max(); } +std::chrono::seconds SystemMetricsDaemon::LogCpuUsage() { + TRACE_DURATION("system_metrics", "SystemMetricsDaemon::LogCpuUsage"); + if (!logger_) { + FXL_LOG(ERROR) << "Cobalt SystemMetricsDaemon: No logger " + "present. Reconnecting..."; + InitializeLogger(); + return std::chrono::minutes(1); + } + + double cpu_percentage; + if (!cpu_stats_fetcher_->FetchCpuPercentage(&cpu_percentage)) { + return std::chrono::minutes(1); + } + cpu_percentages_.push_back(cpu_percentage); + // collect 60 data points before sending to Cobalt + if (cpu_percentages_.size() == 60) { + LogCpuPercentagesToCobalt(); + cpu_percentages_.clear(); + } + return std::chrono::seconds(1); +} + +void SystemMetricsDaemon::LogCpuPercentagesToCobalt() { + TRACE_DURATION("system_metrics", + "SystemMetricsDaemon::LogCpuPercentagesToCobalt"); + std::vector<CobaltEvent> events; + // per sec + auto builder = CobaltEventBuilder( + fuchsia_system_metrics::kFuchsiaCpuPercentageExperimentalMetricId); + for (unsigned i = 0; i < cpu_percentages_.size(); i++) { + // TODO(CB-253) Change to CPU metric type and + // take away "* 100" if the new metric type supports double. + events.push_back( + builder.Clone().as_memory_usage(cpu_percentages_[i] * 100)); + } + // call cobalt FIDL + fuchsia::cobalt::Status status = fuchsia::cobalt::Status::INTERNAL_ERROR; + logger_->LogCobaltEvents(std::move(events), &status); + if (status != fuchsia::cobalt::Status::OK) { + FXL_LOG(ERROR) << "Cobalt SystemMetricsDaemon::LogCpuPercentagesToCobalt " + "returned status=" + << StatusToString(status); + } + return; +} + std::chrono::seconds SystemMetricsDaemon::LogMemoryUsage() { TRACE_DURATION("system_metrics", "SystemMetricsDaemon::LogMemoryUsage"); if (!logger_) { @@ -256,6 +318,8 @@ std::chrono::seconds SystemMetricsDaemon::LogMemoryUsage() { void SystemMetricsDaemon::LogMemoryUsageToCobalt( const zx_info_kmem_stats_t& stats, const std::chrono::seconds& uptime) { + TRACE_DURATION("system_metrics", + "SystemMetricsDaemon::LogMemoryUsageToCobalt"); typedef FuchsiaMemoryExperimental2MetricDimensionMemoryBreakdown Breakdown; auto builder = @@ -333,6 +397,8 @@ SystemMetricsDaemon::GetUpTimeEventCode(const std::chrono::seconds& uptime) { void SystemMetricsDaemon::LogMemoryUsageToCobalt( const zx_info_kmem_stats_t& stats) { + TRACE_DURATION("system_metrics", + "SystemMetricsDaemon::LogMemoryUsageToCobalt2"); typedef FuchsiaMemoryExperimentalMetricDimensionMemoryBreakdown Breakdown; std::vector<CobaltEvent> events; diff --git a/src/cobalt/bin/system-metrics/system_metrics_daemon.h b/src/cobalt/bin/system-metrics/system_metrics_daemon.h index 353342436f35b236ad2c05e6fc5751fac15e4f30..5e9eca90400144ca670081d79f71a8e64f0a2a8e 100644 --- a/src/cobalt/bin/system-metrics/system_metrics_daemon.h +++ b/src/cobalt/bin/system-metrics/system_metrics_daemon.h @@ -15,7 +15,9 @@ #include <chrono> #include <memory> #include <thread> +#include <vector> +#include "src/cobalt/bin/system-metrics/cpu_stats_fetcher.h" #include "src/cobalt/bin/system-metrics/memory_stats_fetcher.h" #include "src/cobalt/bin/system-metrics/metrics_registry.cb.h" #include "src/cobalt/bin/utils/clock.h" @@ -53,7 +55,8 @@ class SystemMetricsDaemon { async_dispatcher_t* dispatcher, sys::ComponentContext* context, fuchsia::cobalt::Logger_Sync* logger, std::unique_ptr<cobalt::SteadyClock> clock, - std::unique_ptr<cobalt::MemoryStatsFetcher> memory_stats_fetcher); + std::unique_ptr<cobalt::MemoryStatsFetcher> memory_stats_fetcher, + std::unique_ptr<cobalt::CpuStatsFetcher> cpu_stats_fetcher); void InitializeLogger(); @@ -69,6 +72,11 @@ class SystemMetricsDaemon { // the next round. void RepeatedlyLogMemoryUsage(); + // Calls LogCpuUsage, + // then uses the |dispatcher| passed to the constructor to schedule + // the next round. + void RepeatedlyLogCpuUsage(); + // Returns the amount of time since SystemMetricsDaemon started. std::chrono::seconds GetUpTime(); @@ -121,6 +129,15 @@ class SystemMetricsDaemon { // information in one zx_info_kmem_stats_t stats data point. void LogMemoryUsageToCobalt(const zx_info_kmem_stats_t& stats); + // Fetches and logs system-wide CPU usage. + // + // Returns the amount of time before this method needs to be invoked again. + std::chrono::seconds LogCpuUsage(); + + // Helper function to call Cobalt logger's LogCobaltEvent to log + // a vector of cpu percentages taken in one minute into Cobalt. + void LogCpuPercentagesToCobalt(); + bool boot_reported_ = false; async_dispatcher_t* const dispatcher_; sys::ComponentContext* context_; @@ -130,6 +147,8 @@ class SystemMetricsDaemon { std::chrono::steady_clock::time_point start_time_; std::unique_ptr<cobalt::SteadyClock> clock_; std::unique_ptr<cobalt::MemoryStatsFetcher> memory_stats_fetcher_; + std::unique_ptr<cobalt::CpuStatsFetcher> cpu_stats_fetcher_; + std::vector<double> cpu_percentages_; }; #endif // SRC_COBALT_BIN_SYSTEM_METRICS_SYSTEM_METRICS_DAEMON_H_ diff --git a/src/cobalt/bin/system-metrics/system_metrics_daemon_test.cc b/src/cobalt/bin/system-metrics/system_metrics_daemon_test.cc index db6316cb274f23a0b3b9d05e3213cba58ec61aff..d4a7ac23f70ad6d879dc156876028bf7c3e49723 100644 --- a/src/cobalt/bin/system-metrics/system_metrics_daemon_test.cc +++ b/src/cobalt/bin/system-metrics/system_metrics_daemon_test.cc @@ -10,12 +10,14 @@ #include <future> #include "gtest/gtest.h" +#include "src/cobalt/bin/system-metrics/fake_cpu_stats_fetcher.h" #include "src/cobalt/bin/system-metrics/fake_memory_stats_fetcher.h" #include "src/cobalt/bin/system-metrics/metrics_registry.cb.h" #include "src/cobalt/bin/testing/fake_clock.h" #include "src/cobalt/bin/testing/fake_logger.h" #include "src/cobalt/bin/utils/clock.h" +using cobalt::FakeCpuStatsFetcher; using cobalt::FakeLogger_Sync; using cobalt::FakeMemoryStatsFetcher; using cobalt::FakeSteadyClock; @@ -36,7 +38,9 @@ class SystemMetricsDaemonTest : public gtest::TestLoopFixture { dispatcher(), nullptr, &fake_logger_, std::unique_ptr<cobalt::SteadyClock>(fake_clock_), std::unique_ptr<cobalt::MemoryStatsFetcher>( - new FakeMemoryStatsFetcher()))) {} + new FakeMemoryStatsFetcher()), + std::unique_ptr<cobalt::CpuStatsFetcher>( + new FakeCpuStatsFetcher()))) {} seconds LogFuchsiaUpPing(seconds uptime) { return daemon_->LogFuchsiaUpPing(uptime); @@ -56,14 +60,23 @@ class SystemMetricsDaemonTest : public gtest::TestLoopFixture { seconds LogMemoryUsage() { return daemon_->LogMemoryUsage(); } + seconds LogCpuUsage() { + for (int i = 0; i < 59; i++) { + daemon_->cpu_percentages_.push_back(static_cast<double>(i)); + } + return daemon_->LogCpuUsage(); + } + void CheckValues(LogMethod expected_log_method_invoked, size_t expected_call_count, uint32_t expected_metric_id, - uint32_t expected_last_event_code) { + uint32_t expected_last_event_code, + size_t expected_event_count = 0) { EXPECT_EQ(expected_log_method_invoked, fake_logger_.last_log_method_invoked()); EXPECT_EQ(expected_call_count, fake_logger_.call_count()); EXPECT_EQ(expected_metric_id, fake_logger_.last_metric_id()); EXPECT_EQ(expected_last_event_code, fake_logger_.last_event_code()); + EXPECT_EQ(expected_event_count, fake_logger_.event_count()); } void DoFuchsiaUpPingTest(seconds now_seconds, seconds expected_sleep_seconds, @@ -407,5 +420,14 @@ TEST_F(SystemMetricsDaemonTest, LogMemoryUsage) { // When LogMemoryUsage() is invoked it should log 10 events // for each of the memory breakdowns and return 1 minute. EXPECT_EQ(seconds(60).count(), LogMemoryUsage().count()); - CheckValues(cobalt::kLogCobaltEvents, 2, -1, -1); + CheckValues(cobalt::kLogCobaltEvents, 2, -1, -1, 10); +} +// Tests the method LogCpuUsage(). Uses a local FakeLogger_Sync and +// does not use FIDL. Does not use the message loop. +TEST_F(SystemMetricsDaemonTest, LogCpuUsage) { + fake_logger_.reset(); + // When LogCpuUsage() is invoked it should log 60 events + // in 1 FIDL call, and return 1 second. + EXPECT_EQ(seconds(1).count(), LogCpuUsage().count()); + CheckValues(cobalt::kLogCobaltEvents, 1, -1, -1, 60); } diff --git a/src/cobalt/bin/testing/fake_logger.cc b/src/cobalt/bin/testing/fake_logger.cc index c049962aa0315f8d853d485aed96649081d7ef2d..9f188e9e9553b12930447179c94f559fbb30fa5f 100644 --- a/src/cobalt/bin/testing/fake_logger.cc +++ b/src/cobalt/bin/testing/fake_logger.cc @@ -4,6 +4,8 @@ #include "src/cobalt/bin/testing/fake_logger.h" +#include <vector> + using fuchsia::cobalt::CobaltEvent; using fuchsia::cobalt::CustomEventValue; using fuchsia::cobalt::HistogramBucket; @@ -117,6 +119,7 @@ zx_status_t FakeLogger_Sync::LogCobaltEvents(::std::vector<CobaltEvent> events, call_count_++; last_log_method_invoked_ = kLogCobaltEvents; *out_status = Status::OK; + event_count_ = events.size(); return ZX_OK; } diff --git a/src/cobalt/bin/testing/fake_logger.h b/src/cobalt/bin/testing/fake_logger.h index eeedee58a19eb7e3d9b735f3b898b9ceecd0333c..3ebe3c3f6a4e36dd7cfdce54dbfbc6d8e63d6cb7 100644 --- a/src/cobalt/bin/testing/fake_logger.h +++ b/src/cobalt/bin/testing/fake_logger.h @@ -77,11 +77,16 @@ class FakeLogger_Sync : public fuchsia::cobalt::Logger_Sync { void reset_call_count() { call_count_ = 0; } + size_t event_count() { return event_count_; } // for LogCobaltEvents only + + void reset_event_count() { event_count_ = 0; } // for LogCobaltEvents only + void reset() { reset_last_metric_id(); reset_last_event_code(); reset_last_log_method_invoked(); reset_call_count(); + reset_event_count(); } private: @@ -89,6 +94,7 @@ class FakeLogger_Sync : public fuchsia::cobalt::Logger_Sync { uint32_t last_event_code_ = -1; LogMethod last_log_method_invoked_ = kOther; size_t call_count_ = 0; + size_t event_count_ = 0; // for LogCobaltEvents only }; } // namespace cobalt