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