[go: nahoru, domu]

metrics: Create Template for Sharing Metrics Data Between Processes

Create a template that contains metrics data and is guarded by a lock
so that the metrics data can be shared between processes.

Bug: 1151343
Change-Id: Ic365f837e385ac984f47d883f3f5104702d2ed35
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2644749
Commit-Queue: weiliangc <weiliangc@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Steve Kobes <skobes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#848183}
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 8c8f34b..9c44e43e 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -192,6 +192,7 @@
     "metrics/latency_ukm_reporter.h",
     "metrics/lcd_text_metrics_reporter.cc",
     "metrics/lcd_text_metrics_reporter.h",
+    "metrics/shared_metrics_buffer.h",
     "metrics/throughput_ukm_reporter.cc",
     "metrics/throughput_ukm_reporter.h",
     "metrics/total_frame_counter.cc",
diff --git a/cc/metrics/OWNERS b/cc/metrics/OWNERS
index 0cb4f83e..39db757 100644
--- a/cc/metrics/OWNERS
+++ b/cc/metrics/OWNERS
@@ -1,2 +1,4 @@
 per-file ukm_smoothness_data.h=set noparent
 per-file ukm_smoothness_data.h=file://ipc/SECURITY_OWNERS
+per-file shared_metrics_buffer.h=set noparent
+per-file shared_metrics_buffer.h=file://ipc/SECURITY_OWNERS
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc
index 818de70..18e2925c 100644
--- a/cc/metrics/dropped_frame_counter.cc
+++ b/cc/metrics/dropped_frame_counter.cc
@@ -163,12 +163,7 @@
         static_cast<double>(total_smoothness_dropped_) * 100 / total_frames;
     smoothness_data.worst_smoothness = sliding_window_max_percent_dropped_;
     smoothness_data.percentile_95 = sliding_window_95pct_percent_dropped;
-
-    ukm_smoothness_data_->seq_lock.WriteBegin();
-    device::OneWriterSeqLock::AtomicWriterMemcpy(&ukm_smoothness_data_->data,
-                                                 &smoothness_data,
-                                                 sizeof(UkmSmoothnessData));
-    ukm_smoothness_data_->seq_lock.WriteEnd();
+    ukm_smoothness_data_->Write(smoothness_data);
   }
 }
 
diff --git a/cc/metrics/dropped_frame_counter.h b/cc/metrics/dropped_frame_counter.h
index 153d0ff..72bc46d 100644
--- a/cc/metrics/dropped_frame_counter.h
+++ b/cc/metrics/dropped_frame_counter.h
@@ -12,10 +12,10 @@
 #include "base/containers/ring_buffer.h"
 #include "cc/cc_export.h"
 #include "cc/metrics/frame_sorter.h"
+#include "cc/metrics/ukm_smoothness_data.h"
 
 namespace cc {
 class TotalFrameCounter;
-struct UkmSmoothnessDataShared;
 
 // This class maintains a counter for produced/dropped frames, and can be used
 // to estimate the recent throughput.
diff --git a/cc/metrics/shared_metrics_buffer.h b/cc/metrics/shared_metrics_buffer.h
new file mode 100644
index 0000000..5167a77
--- /dev/null
+++ b/cc/metrics/shared_metrics_buffer.h
@@ -0,0 +1,46 @@
+// Copyright 2021 The Chromium 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 CC_METRICS_SHARED_METRICS_BUFFER_H_
+#define CC_METRICS_SHARED_METRICS_BUFFER_H_
+
+#include "device/base/synchronization/one_writer_seqlock.h"
+
+namespace cc {
+// The struct written in shared memory to transport metrics across
+// processes. |data| is protected by the sequence-lock |seq_lock|.
+// Note: This template copies data between processes. Any class that uses this
+// template would need security review.
+template <class T>
+struct SharedMetricsBuffer {
+  device::OneWriterSeqLock seq_lock;
+  T data;
+  static_assert(std::is_trivially_copyable<T>::value,
+                "Metrics shared across processes need to be trivially "
+                "copyable, otherwise it is dangerous to copy it.");
+
+  bool Read(T& out) const {
+    const uint32_t kMaxRetries = 5;
+    uint32_t retries = 0;
+    base::subtle::Atomic32 version;
+    do {
+      const uint32_t kMaxReadAttempts = 32;
+      version = seq_lock.ReadBegin(kMaxReadAttempts);
+      device::OneWriterSeqLock::AtomicReaderMemcpy(&out, &data, sizeof(T));
+    } while (seq_lock.ReadRetry(version) && ++retries < kMaxRetries);
+
+    // Consider the number of retries less than kMaxRetries as success.
+    return retries < kMaxRetries;
+  }
+
+  void Write(const T& in) {
+    seq_lock.WriteBegin();
+    device::OneWriterSeqLock::AtomicWriterMemcpy(&data, &in, sizeof(T));
+    seq_lock.WriteEnd();
+  }
+};
+
+}  // namespace cc
+
+#endif  // CC_METRICS_SHARED_METRICS_BUFFER_H_
diff --git a/cc/metrics/ukm_smoothness_data.h b/cc/metrics/ukm_smoothness_data.h
index 2bb5118..d4b95533 100644
--- a/cc/metrics/ukm_smoothness_data.h
+++ b/cc/metrics/ukm_smoothness_data.h
@@ -5,7 +5,7 @@
 #ifndef CC_METRICS_UKM_SMOOTHNESS_DATA_H_
 #define CC_METRICS_UKM_SMOOTHNESS_DATA_H_
 
-#include "device/base/synchronization/one_writer_seqlock.h"
+#include "cc/metrics/shared_metrics_buffer.h"
 
 namespace cc {
 
@@ -19,12 +19,7 @@
   double percentile_95 = 0.0;
 };
 
-// The struct written in shared memory to transport UkmSmoothnessData across
-// processes. |data| is protected by the sequence-lock |seq_lock|.
-struct UkmSmoothnessDataShared {
-  device::OneWriterSeqLock seq_lock;
-  struct UkmSmoothnessData data;
-};
+using UkmSmoothnessDataShared = SharedMetricsBuffer<UkmSmoothnessData>;
 
 }  // namespace cc
 
diff --git a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
index 5bfe9d3..8741738 100644
--- a/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core/ukm_page_load_metrics_observer.cc
@@ -1026,27 +1026,19 @@
   }
 
   base::ElapsedTimer timer;
-  const uint32_t kMaxRetries = 5;
-  uint32_t retries = 0;
   cc::UkmSmoothnessData smoothness_data;
-  base::subtle::Atomic32 version;
-  do {
-    const uint32_t kMaxReadAttempts = 32;
-    version = smoothness->seq_lock.ReadBegin(kMaxReadAttempts);
-    device::OneWriterSeqLock::AtomicReaderMemcpy(
-        &smoothness_data, &smoothness->data, sizeof(cc::UkmSmoothnessData));
-  } while (smoothness->seq_lock.ReadRetry(version) && ++retries < kMaxRetries);
+  bool success = smoothness->Read(smoothness_data);
 
   UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
       "Graphics.Smoothness.Diagnostic.ReadSharedMemoryDuration",
       timer.Elapsed(), base::TimeDelta::FromMicroseconds(1),
       base::TimeDelta::FromMilliseconds(5), 100);
   UMA_HISTOGRAM_BOOLEAN(
-      "Graphics.Smoothness.Diagnostic.ReadSharedMemoryUKMSuccess",
-      retries < kMaxRetries);
+      "Graphics.Smoothness.Diagnostic.ReadSharedMemoryUKMSuccess", success);
 
-  if (retries >= kMaxRetries)
+  if (!success)
     return;
+
   ukm::builders::Graphics_Smoothness_NormalizedPercentDroppedFrames(
       GetDelegate().GetPageUkmSourceId())
       .SetAverage(smoothness_data.avg_smoothness)