[metrics] Add metrics to Runtime, implement ClassVerificationTotalTime

This creates the main metrics struct and makes it readily accessible for
ART components that want to start collecting metrics. It also implements
the ClassVerificationTime metric.

Test: m test-art-host-gtest-art_runtime_tests
Test: m test-art-host-gtest-art_libartbase_tests
Bug: 170149255
Change-Id: I33b5b2dd40127074619750d6730db220e3ed1257
diff --git a/libartbase/base/metrics.h b/libartbase/base/metrics.h
index d403834..f2852b4 100644
--- a/libartbase/base/metrics.h
+++ b/libartbase/base/metrics.h
@@ -33,7 +33,6 @@
 
 // COUNTER(counter_name)
 #define ART_COUNTERS(COUNTER) COUNTER(ClassVerificationTotalTime)
-// TODO: ClassVerificationTime serves as a mock for now. Implementation will come later.
 
 // HISTOGRAM(counter_name, num_buckets, minimum_value, maximum_value)
 //
@@ -248,13 +247,15 @@
     start_time_microseconds_ = MicroTime();
   }
 
-  void Stop() {
+  // Stops a running timer. Returns the time elapsed since starting the timer in microseconds.
+  uint64_t Stop() {
     DCHECK(running_);
     uint64_t stop_time_microseconds = MicroTime();
     running_ = false;
 
-    metric_->Add(
-        static_cast<typename Metric::value_t>(stop_time_microseconds - start_time_microseconds_));
+    uint64_t elapsed_time = stop_time_microseconds - start_time_microseconds_;
+    metric_->Add(static_cast<typename Metric::value_t>(elapsed_time));
+    return elapsed_time;
   }
 
  private:
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 594edaa..9eef7a2 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -21,15 +21,16 @@
 #include <stdio.h>
 
 #include <iosfwd>
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
-#include <memory>
 #include <vector>
 
 #include "base/locks.h"
 #include "base/macros.h"
 #include "base/mem_map.h"
+#include "base/metrics.h"
 #include "base/string_view_cpp20.h"
 #include "deoptimization_kind.h"
 #include "dex/dex_file_types.h"
@@ -979,6 +980,8 @@
   // Return true if we should load oat files as executable or not.
   bool GetOatFilesExecutable() const;
 
+  metrics::ArtMetrics* GetMetrics() { return &metrics_; }
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -1334,6 +1337,8 @@
   bool verifier_missing_kthrow_fatal_;
   bool perfetto_hprof_enabled_;
 
+  metrics::ArtMetrics metrics_;
+
   // Note: See comments on GetFaultMessage.
   friend std::string GetFaultMessageForAbortLogging();
   friend class Dex2oatImageTest;
@@ -1344,6 +1349,8 @@
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
 
+inline metrics::ArtMetrics* GetMetrics() { return Runtime::Current()->GetMetrics(); }
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_RUNTIME_H_
diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc
index 386e490..d725a58 100644
--- a/runtime/verifier/class_verifier.cc
+++ b/runtime/verifier/class_verifier.cc
@@ -242,10 +242,7 @@
 
   ClassAccessor accessor(*dex_file, class_def);
   SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(accessor.GetDescriptor());
-  uint64_t start_ns = 0u;
-  if (VLOG_IS_ON(verifier)) {
-    start_ns = NanoTime();
-  }
+  metrics::AutoTimer timer{GetMetrics()->ClassVerificationTotalTime()};
 
   int64_t previous_method_idx[2] = { -1, -1 };
   MethodVerifier::FailureData failure_data;
@@ -307,7 +304,8 @@
     }
     failure_data.Merge(result);
   }
-  VLOG(verifier) << "VerifyClass took " << PrettyDuration(NanoTime() - start_ns)
+  uint64_t elapsed_time_microseconds = timer.Stop();
+  VLOG(verifier) << "VerifyClass took " << PrettyDuration(elapsed_time_microseconds * 1000)
                  << ", class: " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
 
   if (failure_data.kind == FailureKind::kNoFailure) {
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index e56cde9..d7e193c 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -71,5 +71,14 @@
   VerifyDexFile(*java_lang_dex_file_);
 }
 
+// Make sure verification time metrics are collected.
+TEST_F(MethodVerifierTest, VerificationTimeMetrics) {
+  ScopedObjectAccess soa(Thread::Current());
+  ASSERT_TRUE(java_lang_dex_file_ != nullptr);
+  const uint64_t original_time = GetMetrics()->ClassVerificationTotalTime()->Value();
+  VerifyDexFile(*java_lang_dex_file_);
+  ASSERT_GT(GetMetrics()->ClassVerificationTotalTime()->Value(), original_time);
+}
+
 }  // namespace verifier
 }  // namespace art