Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(645)

Unified Diff: components/metrics/file_metrics_provider.cc

Issue 1537743006: Persist setup metrics and have Chrome report them during UMA upload. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@shared-histograms
Patch Set: addressed review comments by Greg Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/metrics/file_metrics_provider.cc
diff --git a/components/metrics/file_metrics_provider.cc b/components/metrics/file_metrics_provider.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2d023ad4986c1423db817d0679cc00cbfcd288be
--- /dev/null
+++ b/components/metrics/file_metrics_provider.cc
@@ -0,0 +1,251 @@
+// Copyright 2016 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/file_metrics_provider.h"
+
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_persistence.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/task_runner.h"
+#include "base/time/time.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_service.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+namespace metrics {
+
+// This structure stores all the information about the files being monitored
+// and their current reporting state.
+struct FileMetricsProvider::FileInformation {
+ FileInformation();
+ ~FileInformation();
+
+ base::FilePath path; // Where on disk the file is located.
Alexei Svitkine (slow) 2016/02/17 21:55:35 Nit: Put comments above members.
bcwhite 2016/02/18 01:46:56 Done.
+ FileType type; // How to access this file (atomic/active).
+ std::string prefs_key; // Name used inside prefs to persistent metadata.
+ base::Time last_seen; // The last-seen time of this file to detect change.
+ base::Time last_loaded; // The timestamp of when a file was loaded from disk.
+
+ // Once a file has been recognized as needing to be read, it is mapped into
+ // memory as a file ("active") or local memory ("atomic") and is assigned an
+ // allocator.
+ std::vector<uint8_t> data;
+ scoped_ptr<base::MemoryMappedFile> mapped;
+ scoped_ptr<base::PersistentMemoryAllocator> allocator;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FileInformation);
+};
+
+// Out-of-line constructor and destructor needed for code efficiency.
+FileMetricsProvider::FileInformation::FileInformation() {}
+FileMetricsProvider::FileInformation::~FileInformation() {}
+
+FileMetricsProvider::FileMetricsProvider(
+ const scoped_refptr<base::TaskRunner>& task_runner,
+ PrefService* local_state)
+ : task_runner_(task_runner),
+ pref_service_(local_state),
+ weak_factory_(this) {
+}
+
+FileMetricsProvider::~FileMetricsProvider() {
+}
+
+void FileMetricsProvider::RegisterFile(const base::FilePath& path,
+ FileType type,
+ const base::StringPiece& prefs_key) {
+ FileInformation* file = new FileInformation();
Alexei Svitkine (slow) 2016/02/17 21:55:35 Store it in a scoped ptr to begin.
bcwhite 2016/02/18 01:46:56 Done.
+ file->path = path;
+ file->type = type;
+ file->prefs_key = prefs_key.as_string();
+
+ if (pref_service_ && !prefs_key.empty()) {
Alexei Svitkine (slow) 2016/02/17 21:55:35 Add a comment about why prefs_key would be empty.
bcwhite 2016/02/18 01:46:56 Done.
+ file->last_seen = base::Time::FromInternalValue(
+ pref_service_->GetInt64(metrics::prefs::kMetricsLastSeenPrefix +
+ prefs_key.as_string()));
+ }
+
+ files_to_check_.push_back(make_scoped_ptr(file));
+}
+
+// static
+void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs,
+ const base::StringPiece& key) {
+ prefs->RegisterInt64Pref(metrics::prefs::kMetricsLastSeenPrefix +
+ key.as_string(), 0);
+}
+
+// static
+void FileMetricsProvider::CheckAndMapNewMetricFilesOnTaskRunner(
+ FileMetricsProvider::FileInformationList* files) {
+ for (auto& file : *files)
+ CheckAndMapNewMetrics(file.get());
+}
+
+// static
+void FileMetricsProvider::CheckAndMapNewMetrics(
+ FileMetricsProvider::FileInformation* file) {
Alexei Svitkine (slow) 2016/02/17 21:55:35 Sounds like this should be a member function of Fi
bcwhite 2016/02/18 01:46:57 I wanted FileInformation to be information storage
+ DCHECK(!file->mapped);
+ DCHECK(file->data.empty());
+
+ base::File::Info info;
+ if (!base::GetFileInfo(file->path, &info) ||
+ info.is_directory || info.size == 0) {
+ return;
+ }
+
+ if (file->last_seen >= info.last_modified)
+ return;
+
+ // A new file of metrics has been found. Map it into memory.
+ file->mapped.reset(new base::MemoryMappedFile());
+ if (!file->mapped->Initialize(file->path)) {
+ NOTREACHED();
+ file->mapped.reset();
+ return;
+ }
+
+ // For an "atomic" file, immediately copy the data into local memory and
+ // release the file so that it is not held open.
+ if (file->type == FILE_HISTOGRAMS_ATOMIC) {
+ file->data.assign(file->mapped->data(),
+ file->mapped->data() + file->mapped->length());
+ file->mapped.reset();
+ }
+
+ file->last_loaded = info.last_modified;
+ return;
Alexei Svitkine (slow) 2016/02/17 21:55:35 Nit: Remove.
bcwhite 2016/02/18 01:46:57 Done.
+}
+
+void FileMetricsProvider::ScheduleFilesCheck() {
+ if (files_to_check_.empty())
+ return;
+
+ FileInformationList* check_list = new FileInformationList();
+ std::swap(files_to_check_, *check_list);
+ task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&FileMetricsProvider::CheckAndMapNewMetricFilesOnTaskRunner,
+ base::Unretained(check_list)),
+ base::Bind(&FileMetricsProvider::RecordFilesChecked,
+ weak_factory_.GetWeakPtr(), base::Owned(check_list)));
+}
+
+void FileMetricsProvider::RecordFilesChecked(FileInformationList* checked) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Move each processed file to either the "to-read" list (for processing) or
+ // the "to-check" list (for future checking).
+ for (auto iter = checked->begin(); iter != checked->end();) {
+ auto temp = iter++;
+ const FileInformation* file = temp->get();
+ if (file->mapped || !file->data.empty())
+ files_to_read_.splice(files_to_read_.end(), *checked, temp);
+ else
+ files_to_check_.splice(files_to_check_.end(), *checked, temp);
+ }
+}
+
+void FileMetricsProvider::RecordFileAsSeen(FileInformation* file) {
+ file->last_seen = file->last_loaded;
+ if (pref_service_ && !file->prefs_key.empty()) {
+ pref_service_->SetInt64(metrics::prefs::kMetricsLastSeenPrefix +
+ file->prefs_key,
+ file->last_seen.ToInternalValue());
+ }
+}
+
+void FileMetricsProvider::OnDidCreateMetricsLog() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Move finished metric files back to list of monitored files.
+ for (auto iter = files_to_read_.begin(); iter != files_to_read_.end();) {
+ auto temp = iter++;
+ const FileInformation* file = temp->get();
+ if (!file->allocator && !file->mapped && file->data.empty())
+ files_to_check_.splice(files_to_check_.end(), files_to_read_, temp);
+ }
+
+ // Schedule a check to see if there are new metrics to load. If so, they
+ // will be reported during the next collection run after this one. The
+ // check is run off of the worker-pool so as to not cause delays on the
+ // main UI thread (which is currently where metric collection is done).
+ ScheduleFilesCheck();
+}
+
+void FileMetricsProvider::RecordHistogramSnapshots(
+ base::HistogramSnapshotManager* hsm) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ for (auto& file : files_to_read_) {
Alexei Svitkine (slow) 2016/02/17 21:55:35 The loop body is pretty long - is it possible to m
bcwhite 2016/02/18 01:46:56 Done.
+ // If the file is mapped or loaded then it needs to have an allocator
+ // attached to it in order to read histograms out of it.
+ if (file->mapped || !file->data.empty()) {
+ DCHECK(!file->allocator);
+ if (file->mapped) {
+ DCHECK(file->data.empty());
+ if (base::FilePersistentMemoryAllocator::IsFileAcceptable(
+ *file->mapped)) {
+ file->allocator.reset(new base::FilePersistentMemoryAllocator(
+ std::move(file->mapped), 0, std::string()));
+ }
+ } else {
+ DCHECK(!file->mapped);
+ if (base::PersistentMemoryAllocator::IsMemoryAcceptable(
+ &file->data[0], file->data.size(), 0, true)) {
+ file->allocator.reset(new base::PersistentMemoryAllocator(
+ &file->data[0], file->data.size(), 0, 0, "", true));
+ }
+ }
+ if (!file->allocator) {
+ // Something is fundamentally wrong with the file. Ignore it.
+ DLOG(ERROR) << "Metrics file \"" << file->path.value()
+ << "\" is not valid -- ignored.";
+ RecordFileAsSeen(file.get());
+ NOTREACHED();
+ continue;
+ }
+ }
+
+ // A file should not be under "files to read" unless it has an allocator
+ // or is memory-mapped (at which point it will have received an allocator
+ // above). However, if this method gets called twice before the scheduled-
+ // files-check has a chance to clean up, this may trigger.
+ if (!file->allocator)
+ continue;
+
+ int histogram_count = 0;
+ base::PersistentMemoryAllocator::Iterator hist_iter;
+ file->allocator->CreateIterator(&hist_iter);
+ while (true) {
+ scoped_ptr<base::HistogramBase> histogram(
+ base::GetNextPersistentHistogram(file->allocator.get(), &hist_iter));
+ if (!histogram)
+ break;
+ if (file->type == FILE_HISTOGRAMS_ATOMIC)
+ hsm->PrepareOnceTakingOwnership(std::move(histogram));
+ else
+ hsm->PrepareDeltaTakingOwnership(std::move(histogram));
+ ++histogram_count;
+ }
+ DVLOG(1) << "Reported " << histogram_count << " histograms from "
+ << file->path.value();
+
+ if (file->type == FILE_HISTOGRAMS_ATOMIC) {
+ DCHECK(!file->mapped);
+ file->allocator.reset();
+ file->data.clear();
+ RecordFileAsSeen(file.get());
+ }
+ }
+}
+
+} // namespace metrics

Powered by Google App Engine
This is Rietveld 408576698