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

Side by Side 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: address (many) 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/metrics/file_metrics_provider.h"
6
7 #include "base/command_line.h"
8 #include "base/files/file.h"
9 #include "base/files/file_util.h"
10 #include "base/files/memory_mapped_file.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram_base.h"
13 #include "base/metrics/histogram_persistence.h"
14 #include "base/metrics/persistent_memory_allocator.h"
15 #include "base/prefs/pref_registry_simple.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/threading/worker_pool.h"
18 #include "base/time/time.h"
19 #include "components/metrics/metrics_pref_names.h"
20 #include "components/metrics/metrics_service.h"
21
22 namespace metrics {
23
24 // Out-of-line constructor and destructor needed for code efficiency.
25 FileMetricsProvider::FileInformation::FileInformation() {}
26 FileMetricsProvider::FileInformation::~FileInformation() {}
27
28 FileMetricsProvider::FileMetricsProvider(
29 metrics::MetricsService* metrics_service,
30 PrefService* local_state)
31 : metrics_service_(metrics_service),
32 pref_service_(local_state) {
33 // Start a background check for pending setup metrics so it can be uploaded
34 // during the initial report.
35 ScheduleFilesCheck();
36 }
37
38 FileMetricsProvider::~FileMetricsProvider() {
39 // Destruction of this object can lead to failures because of a task
40 // posted on the Worker Pool or because the owned Memory Allocator has
41 // been passed to the Metrics Service. Both cases can only occur if
42 // a Metrics Service has been provided (i.e. not during testing).
43 DCHECK(!metrics_service_);
44 }
45
46 void FileMetricsProvider::RegisterFile(const base::FilePath& path,
47 FileType type,
48 const base::StringPiece& prefs_key) {
49 FileInformation* file = new FileInformation();
50 file->path = path;
51 file->type = type;
52 file->prefs_key = prefs_key.as_string();
53
54 if (pref_service_ && !prefs_key.empty()) {
55 file->last_seen = base::Time::FromInternalValue(
56 pref_service_->GetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix +
57 prefs_key.as_string()));
58 }
59
60 base::AutoLock lock(lock_);
61 metrics_files_.push_back(make_scoped_ptr(file));
62 }
63
64 // static
65 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs,
66 const base::StringPiece& key) {
67 prefs->RegisterInt64Pref(metrics::prefs::kSetupMetricsLastSeenPrefix +
68 key.as_string(), 0);
69 }
70
71 void FileMetricsProvider::OnDidCreateMetricsLog() {
grt (UTC plus 2) 2016/02/08 18:09:19 nit: move these two functions down below RecordFil
bcwhite 2016/02/09 21:08:46 Done.
72 // Hold off async updates to file lists while processing.
73 base::AutoLock lock(lock_);
74
75 // Move finished metric files back to list of monitored files.
76 for (auto iter = metrics_found_.begin(); iter != metrics_found_.end();) {
77 auto temp = iter++;
78 const FileInformation* file = temp->get();
79 if (!file->allocator && !file->mapped)
80 metrics_files_.splice(metrics_files_.end(), metrics_found_, temp);
81 }
82
83 // Schedule a check to see if there are new metrics to load. If so, they
84 // will be reported during the next collection run after this one. The
85 // check is run off of the worker-pool so as to not cause delays on the
86 // main UI thread (which is currently where metric collection is done).
87 ScheduleFilesCheck();
88 }
89
90 void FileMetricsProvider::RecordHistogramSnapshots(
91 base::HistogramSnapshotManager* hsm) {
92 // Hold off async updates to file lists while processing.
93 base::AutoLock lock(lock_);
94
95 for (auto& file : metrics_found_) {
96 if (!file->allocator) {
97 DCHECK(file->mapped);
98 if (!base::FilePersistentMemoryAllocator::IsFileAcceptable(
99 *file->mapped)) {
100 // Something is fundamentally wrong with the file. Ignore it.
101 LOG(ERROR) << "Metrics file \"" << file->path.value()
102 << "\" is not valid -- ignored.";
103 file->mapped.reset();
104 RecordFileAsSeen(file.get());
105 NOTREACHED();
106 continue;
107 }
108 file->allocator.reset(new base::FilePersistentMemoryAllocator(
109 file->mapped.release(), 0, std::string()));
110 }
111
112 base::PersistentMemoryAllocator::Iterator hist_iter;
113 file->allocator->CreateIterator(&hist_iter);
114 for (;;) {
115 base::HistogramBase* histogram =
116 base::GetNextPersistentHistogram(file->allocator.get(), &hist_iter);
117 if (!histogram)
118 break;
119 if (file->type == FILE_HISTOGRAMS_ATOMIC)
120 hsm->PrepareOnceTakingOwnership(histogram);
121 else
122 hsm->PrepareDeltaTakingOwnership(histogram);
123 }
124
125 if (file->type == FILE_HISTOGRAMS_ATOMIC) {
126 DCHECK(!file->mapped); // Ownership should have moved to allocator.
127 file->allocator.reset();
128 RecordFileAsSeen(file.get());
129 }
130 }
131 }
132
133 void FileMetricsProvider::RecordFileAsSeen(FileInformation* file) {
134 file->last_seen = base::Time::Now();
135 if (pref_service_ && !file->prefs_key.empty()) {
136 pref_service_->SetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix +
137 file->prefs_key,
138 file->last_seen.ToInternalValue());
139 }
140 }
141
142 // static
143 void FileMetricsProvider::CheckAndMapNewMetricFilesOnBlockingPool(
144 FileMetricsProvider::FileInformationList* files,
145 base::Callback<void(FileInformationList*)> callback) {
146 for (auto& file : *files)
147 CheckAndMapNewMetrics(file.get());
148 callback.Run(files);
149 }
150
151 // static
152 bool FileMetricsProvider::CheckAndMapNewMetrics(
153 FileMetricsProvider::FileInformation* file) {
154 DCHECK(!file->mapped);
155
156 base::File::Info info;
157 if (!base::GetFileInfo(file->path, &info) ||
158 info.is_directory || info.size == 0) {
159 return false;
160 }
161
162 if (file->last_seen >= info.last_modified)
163 return false;
164
165 // A new file of setup metrics has been found. Map it into memory.
166 file->mapped.reset(new base::MemoryMappedFile());
167 if (!file->mapped->Initialize(file->path)) {
168 NOTREACHED();
169 return false;
grt (UTC plus 2) 2016/02/08 18:09:19 the |mapped| scoped_ptr must also be reset since i
bcwhite 2016/02/09 21:08:46 Done.
170 }
171 return true;
172 }
173
174 void FileMetricsProvider::ScheduleFilesCheck() {
175 // Don't do anything if metrics_service is not valid (for testing).
176 if (!metrics_service_)
177 return;
178
179 // TODO(bcwhite): Change this if metric collection moves off UI thread.
180 FileInformationList* check_list = new FileInformationList();
181 std::swap(metrics_files_, *check_list);
182 bool posted = base::WorkerPool::PostTask(
183 FROM_HERE,
184 base::Bind(&CheckAndMapNewMetricFilesOnBlockingPool,
185 base::Owned(check_list),
186 base::Bind(&FileMetricsProvider::RecordFileInformation,
187 base::Unretained(this))),
188 false);
189 DCHECK(posted);
190 }
191
192 void FileMetricsProvider::RecordFileInformation(FileInformationList* files) {
193 // This is a callback and thus possibly not on the same thread as the main
194 // metrics collection.
195 base::AutoLock lock(lock_);
196
197 // Move each processed file to either the "found" list (for processing) or
198 // the "files" list (for future checking).
199 for (auto& iter : *files) {
200 if (iter->mapped)
201 metrics_found_.push_back(std::move(iter));
202 else
203 metrics_files_.push_back(std::move(iter));
204 }
205 }
206
207 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698