[metrics] Improve metrics definition API

This CL combines the ART_COUNTERS and ART_HISTOGRAMS lists into a
single ART_METRICS list. Additionally, this will make it possible to
add additional metrics types with less boilerplate.

Bug: 170149255
Test: gtests
Change-Id: I09e161de1ae574dfcc9ab95e8827b071f0a53892
diff --git a/libartbase/base/metrics/metrics.h b/libartbase/base/metrics/metrics.h
index ab535ea..9e3e95a 100644
--- a/libartbase/base/metrics/metrics.h
+++ b/libartbase/base/metrics/metrics.h
@@ -35,35 +35,20 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic error "-Wconversion"
 
-// COUNTER(counter_name)
-#define ART_COUNTERS(COUNTER)    \
-  COUNTER(ClassLoadingTotalTime) \
-  COUNTER(ClassVerificationTotalTime) \
-  COUNTER(MutatorPauseTimeDuringGC) \
-  COUNTER(YoungGcCount) \
-  COUNTER(FullGcCount) \
-  COUNTER(TotalBytesAllocated) \
-  COUNTER(TotalGcMetaDataSize)
-
-// HISTOGRAM(counter_name, num_buckets, minimum_value, maximum_value)
-//
-// The num_buckets parameter affects memory usage for the histogram and data usage for exported
-// metrics. It is recommended to keep this below 16.
-//
-// The minimum_value and maximum_value parameters are needed because we need to know what range the
-// fixed number of buckets cover. We could keep track of the observed ranges and try to rescale the
-// buckets or allocate new buckets, but this would make incrementing them more expensive than just
-// some index arithmetic and an add.
-//
-// Values outside the range get clamped to the nearest bucket (basically, the two buckets on either
-// side are infinitely long). If we see those buckets being way taller than the others, it means we
-// should consider expanding the range.
-#define ART_HISTOGRAMS(HISTOGRAM) \
-  HISTOGRAM(JitMethodCompileTime, 15, 0, 1'000'000) \
-  HISTOGRAM(YoungGcCollectionTime, 15, 0, 60'000) \
-  HISTOGRAM(FullGcCollectionTime, 15, 0, 60'000) \
-  HISTOGRAM(YoungGcThroughput, 15, 0, 1'000) \
-  HISTOGRAM(FullGcThroughput, 15, 0, 1'000)
+// See README.md in this directory for how to define metrics.
+#define ART_METRICS(METRIC)                                        \
+  METRIC(ClassLoadingTotalTime, MetricsCounter)                    \
+  METRIC(ClassVerificationTotalTime, MetricsCounter)               \
+  METRIC(MutatorPauseTimeDuringGC, MetricsCounter)                 \
+  METRIC(YoungGcCount, MetricsCounter)                             \
+  METRIC(FullGcCount, MetricsCounter)                              \
+  METRIC(TotalBytesAllocated, MetricsCounter)                      \
+  METRIC(TotalGcMetaDataSize, MetricsCounter)                      \
+  METRIC(JitMethodCompileTime, MetricsHistogram, 15, 0, 1'000'000) \
+  METRIC(YoungGcCollectionTime, MetricsHistogram, 15, 0, 60'000)   \
+  METRIC(FullGcCollectionTime, MetricsHistogram, 15, 0, 60'000)    \
+  METRIC(YoungGcThroughput, MetricsHistogram, 15, 0, 1'000)        \
+  METRIC(FullGcThroughput, MetricsHistogram, 15, 0, 1'000)
 
 // A lot of the metrics implementation code is generated by passing one-off macros into ART_COUNTERS
 // and ART_HISTOGRAMS. This means metrics.h and metrics.cc are very #define-heavy, which can be
@@ -84,13 +69,9 @@
  * An enumeration of all ART counters and histograms.
  */
 enum class DatumId {
-#define ART_COUNTER(name) k##name,
-  ART_COUNTERS(ART_COUNTER)
-#undef ART_COUNTER
-
-#define ART_HISTOGRAM(name, num_buckets, low_value, high_value) k##name,
-  ART_HISTOGRAMS(ART_HISTOGRAM)
-#undef ART_HISTOGRAM
+#define METRIC(name, type, ...) k##name,
+  ART_METRICS(METRIC)
+#undef METRIC
 };
 
 // We log compilation reasons as part of the metadata we report. Since elsewhere compilation reasons
@@ -416,33 +397,18 @@
   void ReportAllMetrics(MetricsBackend* backend) const;
   void DumpForSigQuit(std::ostream& os) const;
 
-#define ART_COUNTER(name)                                       \
-  MetricsCounter<DatumId::k##name>* name() { return &name##_; } \
-  const MetricsCounter<DatumId::k##name>* name() const { return &name##_; }
-  ART_COUNTERS(ART_COUNTER)
-#undef ART_COUNTER
-
-#define ART_HISTOGRAM(name, num_buckets, low_value, high_value)                                \
-  MetricsHistogram<DatumId::k##name, num_buckets, low_value, high_value>* name() {             \
-    return &name##_;                                                                           \
-  }                                                                                            \
-  const MetricsHistogram<DatumId::k##name, num_buckets, low_value, high_value>* name() const { \
-    return &name##_;                                                                           \
-  }
-  ART_HISTOGRAMS(ART_HISTOGRAM)
-#undef ART_HISTOGRAM
+#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##_; }
+  ART_METRICS(METRIC_ACCESSORS)
+#undef METRIC_ACCESSORS
 
  private:
   uint64_t beginning_timestamp_;
 
-#define ART_COUNTER(name) MetricsCounter<DatumId::k##name> name##_;
-  ART_COUNTERS(ART_COUNTER)
-#undef ART_COUNTER
-
-#define ART_HISTOGRAM(name, num_buckets, low_value, high_value) \
-  MetricsHistogram<DatumId::k##name, num_buckets, low_value, high_value> name##_;
-  ART_HISTOGRAMS(ART_HISTOGRAM)
-#undef ART_HISTOGRAM
+#define METRIC(name, Kind, ...) Kind<DatumId::k##name, ##__VA_ARGS__> name##_;
+  ART_METRICS(METRIC)
+#undef METRIC
 };
 
 // Returns a human readable name for the given DatumId.