[metrics] Reset metrics at zygote fork

This is needed to prevent metrics in the zygote from being counted
towards child processes. This is especially important as the zygote
can be a very long running process.

Test: libartbase_gtests
Bug: 170149255
Change-Id: I5c34d44c55381dd976b83e81517145f7e23d061f
diff --git a/libartbase/base/metrics/metrics.h b/libartbase/base/metrics/metrics.h
index e9b40ed..e61e982 100644
--- a/libartbase/base/metrics/metrics.h
+++ b/libartbase/base/metrics/metrics.h
@@ -204,11 +204,18 @@
 
   void Report(MetricsBackend* backend) const { backend->ReportCounter(counter_type, Value()); }
 
+ protected:
+  void Reset() {
+    value_ = 0;
+  }
+
  private:
   value_t Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
 
   std::atomic<value_t> value_;
   static_assert(std::atomic<value_t>::is_always_lock_free);
+
+  friend class ArtMetrics;
 };
 
 template <DatumId histogram_type_,
@@ -239,6 +246,13 @@
     backend->ReportHistogram(histogram_type_, minimum_value_, maximum_value_, GetBuckets());
   }
 
+ protected:
+  void Reset() {
+    for (auto& bucket : buckets_) {
+      bucket = 0;
+    }
+  }
+
  private:
   inline constexpr size_t FindBucketId(int64_t value) const {
     // Values below the minimum are clamped into the first bucket.
@@ -263,6 +277,8 @@
 
   std::array<std::atomic<value_t>, num_buckets_> buckets_;
   static_assert(std::atomic<value_t>::is_always_lock_free);
+
+  friend class ArtMetrics;
 };
 
 // A backend that writes metrics in a human-readable format to a string.
@@ -398,6 +414,10 @@
   void ReportAllMetrics(MetricsBackend* backend) const;
   void DumpForSigQuit(std::ostream& os) const;
 
+  // Resets all metrics to their initial value. This is intended to be used after forking from the
+  // zygote so we don't attribute parent values to the child process.
+  void Reset();
+
 #define METRIC_ACCESSORS(name, Kind, ...)                                        \
   Kind<DatumId::k##name, ##__VA_ARGS__>* name() { return &name##_; } \
   const Kind<DatumId::k##name, ##__VA_ARGS__>* name() const { return &name##_; }
diff --git a/libartbase/base/metrics/metrics_common.cc b/libartbase/base/metrics/metrics_common.cc
index 0c2ec09..89d003a 100644
--- a/libartbase/base/metrics/metrics_common.cc
+++ b/libartbase/base/metrics/metrics_common.cc
@@ -70,7 +70,7 @@
 
 #define ART_METRIC(name, Kind, ...) name()->Report(backend);
   ART_METRICS(ART_METRIC)
-#undef ART_METRICS
+#undef ART_METRIC
 
   backend->EndReport();
 }
@@ -81,6 +81,13 @@
   os << backend.GetAndResetBuffer();
 }
 
+void ArtMetrics::Reset() {
+  beginning_timestamp_ = MilliTime();
+#define ART_METRIC(name, kind, ...) name##_.Reset();
+  ART_METRICS(ART_METRIC);
+#undef ART_METRIC
+}
+
 StringBackend::StringBackend() {}
 
 std::string StringBackend::GetAndResetBuffer() {
diff --git a/libartbase/base/metrics/metrics_test.cc b/libartbase/base/metrics/metrics_test.cc
index 93701e6..7b26e43 100644
--- a/libartbase/base/metrics/metrics_test.cc
+++ b/libartbase/base/metrics/metrics_test.cc
@@ -220,6 +220,51 @@
 #undef METRIC
 }
 
+TEST_F(MetricsTest, ResetMetrics) {
+  ArtMetrics metrics;
+
+  // Add something to each of the metrics.
+#define METRIC(name, type, ...) metrics.name()->Add(42);
+  ART_METRICS(METRIC)
+#undef METRIC
+
+  class NonZeroBackend : public TestBackendBase {
+   public:
+    void ReportCounter(DatumId, uint64_t value) override {
+      EXPECT_NE(value, 0u);
+    }
+
+    void ReportHistogram(DatumId, int64_t, int64_t, const std::vector<uint32_t>& buckets) override {
+      bool nonzero = false;
+      for (const auto value : buckets) {
+        nonzero |= (value != 0u);
+      }
+      EXPECT_TRUE(nonzero);
+    }
+  } non_zero_backend;
+
+  // Make sure the metrics all have a nonzero value.
+  metrics.ReportAllMetrics(&non_zero_backend);
+
+  // Reset the metrics and make sure they are all zero again
+  metrics.Reset();
+
+  class ZeroBackend : public TestBackendBase {
+   public:
+    void ReportCounter(DatumId, uint64_t value) override {
+      EXPECT_EQ(value, 0u);
+    }
+
+    void ReportHistogram(DatumId, int64_t, int64_t, const std::vector<uint32_t>& buckets) override {
+      for (const auto value : buckets) {
+        EXPECT_EQ(value, 0u);
+      }
+    }
+  } zero_backend;
+
+  metrics.ReportAllMetrics(&zero_backend);
+}
+
 }  // namespace metrics
 }  // namespace art
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1f856b4..a4e98f2 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1068,9 +1068,10 @@
     thread_pool_->StartWorkers(Thread::Current());
   }
 
-  // Reset the gc performance data at zygote fork so that the GCs
+  // Reset the gc performance data and metrics at zygote fork so that the events from
   // before fork aren't attributed to an app.
   heap_->ResetGcPerformanceInfo();
+  GetMetrics()->Reset();
 
   if (metrics_reporter_ != nullptr) {
     if (IsSystemServer() && !metrics_reporter_->IsPeriodicReportingEnabled()) {