[metrics] Make metrics atomic am: c4adf54117

Original change: https://android-review.googlesource.com/c/platform/art/+/1446999

Change-Id: I1b5f488f54f83ee92ad131d86774733259f5c8c9
diff --git a/libartbase/base/metrics.h b/libartbase/base/metrics.h
index d4d00b9..51ea66f 100644
--- a/libartbase/base/metrics.h
+++ b/libartbase/base/metrics.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 #include <array>
+#include <atomic>
 #include <ostream>
 #include <string_view>
 #include <vector>
@@ -135,13 +136,14 @@
     static_assert(sizeof(*this) == sizeof(uint64_t));
   }
 
-  void AddOne() { value_++; }
-  void Add(uint64_t value) { value_ += value; }
+  void AddOne() { Add(1u); }
+  void Add(uint64_t value) { value_.fetch_add(value, std::memory_order::memory_order_relaxed); }
 
-  uint64_t Value() const { return value_; }
+  uint64_t Value() const { return value_.load(std::memory_order::memory_order_relaxed); }
 
  private:
-  uint64_t value_;
+  std::atomic<uint64_t> value_;
+  static_assert(std::atomic<uint64_t>::is_always_lock_free);
 };
 
 template <size_t num_buckets_, int64_t minimum_value_, int64_t maximum_value_>
@@ -157,11 +159,14 @@
 
   void Add(int64_t value) {
     const size_t i = FindBucketId(value);
-    buckets_[i]++;
+    buckets_[i].fetch_add(1u, std::memory_order::memory_order_relaxed);
   }
 
  protected:
   std::vector<uint32_t> GetBuckets() const {
+    // The loads from buckets_ will all be memory_order_seq_cst, which means they will be acquire
+    // loads. This is a stricter memory order than is needed, but this should not be a
+    // performance-critical section of code.
     return std::vector<uint32_t>{buckets_.begin(), buckets_.end()};
   }
 
@@ -180,9 +185,10 @@
     return static_cast<size_t>(value - minimum_value_) * num_buckets_ / bucket_width;
   }
 
-  std::array<uint32_t, num_buckets_> buckets_;
+  std::array<std::atomic<uint32_t>, num_buckets_> buckets_;
 
   friend class ArtMetrics;
+  static_assert(std::atomic<uint32_t>::is_always_lock_free);
 };
 
 /**