Move PersistentHistograms to components
In order to enable persistent histograms on iOS, the code needs to be moved to
components. The only dependancy on //chrome was the path to store the metrics
which was moved to a function parameter.
Bug: 963504
Change-Id: Id2240a1ae1c1bfb4124d783b210a59caa1fcc0a2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1614294
Reviewed-by: Robert Kaplow <rkaplow@chromium.org>
Commit-Queue: Mike Dougherty <michaeldo@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#660894}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: c585702a543fae3f042ac9cff586fc414c905cd9
diff --git a/BUILD.gn b/BUILD.gn
index 8832d0c..2936b89 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -81,11 +81,8 @@
"metrics_switches.h",
"metrics_upload_scheduler.cc",
"metrics_upload_scheduler.h",
- "unsent_log_store.cc",
- "unsent_log_store.h",
- "unsent_log_store_metrics.h",
- "unsent_log_store_metrics_impl.cc",
- "unsent_log_store_metrics_impl.h",
+ "persistent_histograms.cc",
+ "persistent_histograms.h",
"persistent_system_profile.cc",
"persistent_system_profile.h",
"reporting_service.cc",
@@ -99,6 +96,11 @@
"system_memory_stats_recorder_win.cc",
"system_session_analyzer_win.cc",
"system_session_analyzer_win.h",
+ "unsent_log_store.cc",
+ "unsent_log_store.h",
+ "unsent_log_store_metrics.h",
+ "unsent_log_store_metrics_impl.cc",
+ "unsent_log_store_metrics_impl.h",
"url_constants.cc",
"url_constants.h",
"version_utils.cc",
@@ -380,7 +382,6 @@
"metrics_state_manager_unittest.cc",
"net/net_metrics_log_uploader_unittest.cc",
"net/network_metrics_provider_unittest.cc",
- "unsent_log_store_unittest.cc",
"persistent_system_profile_unittest.cc",
"reporting_service_unittest.cc",
"single_sample_metrics_factory_impl_unittest.cc",
@@ -388,6 +389,7 @@
"stability_metrics_provider_unittest.cc",
"system_session_analyzer_win_unittest.cc",
"ui/screen_info_metrics_provider_unittest.cc",
+ "unsent_log_store_unittest.cc",
]
deps = [
diff --git a/persistent_histograms.cc b/persistent_histograms.cc
new file mode 100644
index 0000000..4be700d
--- /dev/null
+++ b/persistent_histograms.cc
@@ -0,0 +1,165 @@
+// Copyright 2018 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.
+
+#include "components/metrics/persistent_histograms.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/system/sys_info.h"
+#include "base/task/post_task.h"
+#include "build/build_config.h"
+#include "components/metrics/persistent_system_profile.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace {
+
+// Creating a "spare" file for persistent metrics involves a lot of I/O and
+// isn't important so delay the operation for a while after startup.
+#if defined(OS_ANDROID)
+// Android needs the spare file and also launches faster.
+constexpr bool kSpareFileRequired = true;
+constexpr int kSpareFileCreateDelaySeconds = 10;
+#else
+// Desktop may have to restore a lot of tabs so give it more time before doing
+// non-essential work. The spare file is still a performance boost but not as
+// significant of one so it's not required.
+constexpr bool kSpareFileRequired = false;
+constexpr int kSpareFileCreateDelaySeconds = 90;
+#endif
+
+} // namespace
+
+const char kBrowserMetricsName[] = "BrowserMetrics";
+
+// Check for feature enabling the use of persistent histogram storage and
+// enable the global allocator if so.
+void InstantiatePersistentHistograms(const base::FilePath& metrics_dir) {
+ // Create a directory for storing completed metrics files. Files in this
+ // directory must have embedded system profiles. If the directory can't be
+ // created, the file will just be deleted below.
+ base::FilePath upload_dir = metrics_dir.AppendASCII(kBrowserMetricsName);
+ base::CreateDirectory(upload_dir);
+
+ // Metrics files are typically created as a |spare_file| in the profile
+ // directory (e.g. "BrowserMetrics-spare.pma") and are then rotated into
+ // a subdirectory as a stamped file for upload when no longer in use.
+ // (e.g. "BrowserMetrics/BrowserMetrics-1234ABCD-12345.pma")
+ base::FilePath upload_file;
+ base::FilePath active_file;
+ base::FilePath spare_file;
+ base::GlobalHistogramAllocator::ConstructFilePathsForUploadDir(
+ metrics_dir, upload_dir, kBrowserMetricsName, &upload_file, &active_file,
+ &spare_file);
+
+ // This is used to report results to an UMA histogram.
+ enum InitResult {
+ kLocalMemorySuccess,
+ kLocalMemoryFailed,
+ kMappedFileSuccess,
+ kMappedFileFailed,
+ kMappedFileExists,
+ kNoSpareFile,
+ kNoUploadDir,
+ kMaxValue = kNoUploadDir
+ };
+ InitResult result;
+
+ // Create persistent/shared memory and allow histograms to be stored in
+ // it. Memory that is not actualy used won't be physically mapped by the
+ // system. BrowserMetrics usage, as reported in UMA, has the 99.99
+ // percentile around 3MiB as of 2018-10-22.
+ const size_t kAllocSize = 4 << 20; // 4 MiB
+ const uint32_t kAllocId = 0x935DDD43; // SHA1(BrowserMetrics)
+ std::string storage = variations::GetVariationParamValueByFeature(
+ base::kPersistentHistogramsFeature, "storage");
+
+ static const char kMappedFile[] = "MappedFile";
+ static const char kLocalMemory[] = "LocalMemory";
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ // Linux kernel 4.4.0.* shows a huge number of SIGBUS crashes with persistent
+ // histograms enabled using a mapped file. Change this to use local memory.
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=753741
+ if (storage.empty() || storage == kMappedFile) {
+ int major, minor, bugfix;
+ base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+ if (major == 4 && minor == 4 && bugfix == 0)
+ storage = kLocalMemory;
+ }
+#endif
+
+ // Don't use mapped-file memory by default on low-end devices, especially
+ // Android. The extra disk consumption and/or extra disk access could have
+ // a significant performance impact. https://crbug.com/896394
+ if (storage.empty() && base::SysInfo::IsLowEndDevice())
+ storage = kLocalMemory;
+
+ // Create a global histogram allocator using the desired storage type.
+ if (storage.empty() || storage == kMappedFile) {
+ if (!base::PathExists(upload_dir)) {
+ // Handle failure to create the directory.
+ result = kNoUploadDir;
+ } else if (base::PathExists(upload_file)) {
+ // "upload" filename is supposed to be unique so this shouldn't happen.
+ result = kMappedFileExists;
+ } else {
+ // Move any sparse file into the upload position.
+ base::ReplaceFile(spare_file, upload_file, nullptr);
+ // Create global allocator using the "upload" file.
+ if (kSpareFileRequired && !base::PathExists(upload_file)) {
+ result = kNoSpareFile;
+ } else if (base::GlobalHistogramAllocator::CreateWithFile(
+ upload_file, kAllocSize, kAllocId, kBrowserMetricsName)) {
+ result = kMappedFileSuccess;
+ } else {
+ result = kMappedFileFailed;
+ }
+ }
+ // Schedule the creation of a "spare" file for use on the next run.
+ base::PostDelayedTaskWithTraits(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskPriority::LOWEST,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(base::IgnoreResult(
+ &base::GlobalHistogramAllocator::CreateSpareFile),
+ std::move(spare_file), kAllocSize),
+ base::TimeDelta::FromSeconds(kSpareFileCreateDelaySeconds));
+ } else if (storage == kLocalMemory) {
+ // Use local memory for storage even though it will not persist across
+ // an unclean shutdown. This sets the result but the actual creation is
+ // done below.
+ result = kLocalMemorySuccess;
+ } else {
+ // Persistent metric storage is disabled. Must return here.
+ return;
+ }
+
+ // Get the allocator that was just created and report result. Exit if the
+ // allocator could not be created.
+ UMA_HISTOGRAM_ENUMERATION("UMA.PersistentHistograms.InitResult", result);
+
+ base::GlobalHistogramAllocator* allocator =
+ base::GlobalHistogramAllocator::Get();
+ if (!allocator) {
+ // If no allocator was created above, try to create a LocalMemomory one
+ // here. This avoids repeating the call many times above. In the case where
+ // persistence is disabled, an early return is done above.
+ base::GlobalHistogramAllocator::CreateWithLocalMemory(kAllocSize, kAllocId,
+ kBrowserMetricsName);
+ allocator = base::GlobalHistogramAllocator::Get();
+ if (!allocator)
+ return;
+ }
+
+ // Store a copy of the system profile in this allocator.
+ metrics::GlobalPersistentSystemProfile::GetInstance()
+ ->RegisterPersistentAllocator(allocator->memory_allocator());
+
+ // Create tracking histograms for the allocator and record storage file.
+ allocator->CreateTrackingHistograms(kBrowserMetricsName);
+}
diff --git a/persistent_histograms.h b/persistent_histograms.h
new file mode 100644
index 0000000..72ef923
--- /dev/null
+++ b/persistent_histograms.h
@@ -0,0 +1,20 @@
+// Copyright 2018 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 COMPONENTS_METRICS_PERSISTENT_HISTOGRAMS_H_
+#define COMPONENTS_METRICS_PERSISTENT_HISTOGRAMS_H_
+
+#include "base/files/file_path.h"
+
+// Persistent browser metrics need to be persisted somewhere. This constant
+// provides a known string to be used for both the allocator's internal name
+// and for a file on disk (relative to metrics_dir) to which they
+// can be saved. This is exported so the name can also be used as a "pref"
+// during configuration.
+extern const char kBrowserMetricsName[];
+
+// Do all the checking and work necessary to enable persistent histograms.
+void InstantiatePersistentHistograms(const base::FilePath& metrics_dir);
+
+#endif // COMPONENTS_METRICS_PERSISTENT_HISTOGRAMS_H_