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

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: rebased 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/task_runner.h"
16 #include "base/time/time.h"
17 #include "components/metrics/metrics_pref_names.h"
18 #include "components/metrics/metrics_service.h"
19 #include "components/prefs/pref_registry_simple.h"
20 #include "components/prefs/pref_service.h"
21
22 namespace metrics {
23
24 // This structure stores all the information about the files being monitored
25 // and their current reporting state.
26 struct FileMetricsProvider::FileInfo {
27 FileInfo() {}
28 ~FileInfo() {}
29
30 // Where on disk the file is located.
31 base::FilePath path;
32
33 // How to access this file (atomic/active).
34 FileType type;
35
36 // Name used inside prefs to persistent metadata.
37 std::string prefs_key;
38
39 // The last-seen time of this file to detect change.
40 base::Time last_seen;
41
42 // The timestamp of when a file was loaded from disk.
43 base::Time last_loaded;
44
45 // Once a file has been recognized as needing to be read, it is mapped into
46 // memory as a file ("active") or local memory ("atomic") and is assigned an
47 // allocator.
48 std::vector<uint8_t> data;
49 scoped_ptr<base::MemoryMappedFile> mapped;
50 scoped_ptr<base::PersistentMemoryAllocator> allocator;
51
52 private:
53 DISALLOW_COPY_AND_ASSIGN(FileInfo);
54 };
55
56 FileMetricsProvider::FileMetricsProvider(
57 const scoped_refptr<base::TaskRunner>& task_runner,
58 PrefService* local_state)
59 : task_runner_(task_runner),
60 pref_service_(local_state),
61 weak_factory_(this) {
62 }
63
64 FileMetricsProvider::~FileMetricsProvider() {}
65
66 void FileMetricsProvider::RegisterFile(const base::FilePath& path,
67 FileType type,
68 const base::StringPiece prefs_key) {
69 scoped_ptr<FileInfo> file(new FileInfo());
70 file->path = path;
71 file->type = type;
72 file->prefs_key = prefs_key.as_string();
73
74 // |prefs_key| may be empty if the caller does not wish to persist the
75 // state across instances of the program.
76 if (pref_service_ && !prefs_key.empty()) {
77 file->last_seen = base::Time::FromInternalValue(
78 pref_service_->GetInt64(metrics::prefs::kMetricsLastSeenPrefix +
79 prefs_key.as_string()));
80 }
81
82 files_to_check_.push_back(std::move(file));
83 }
84
85 // static
86 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs,
87 const base::StringPiece prefs_key) {
88 prefs->RegisterInt64Pref(metrics::prefs::kMetricsLastSeenPrefix +
89 prefs_key.as_string(), 0);
90 }
91
92 // This method has all state information passed in |files| and is intended
93 // to run on a worker thread rather than the UI thread.
94 // static
95 void FileMetricsProvider::CheckAndMapNewMetricFilesOnTaskRunner(
96 FileMetricsProvider::FileInfoList* files) {
97 for (auto& file : *files)
98 CheckAndMapNewMetrics(file.get());
99 }
100
101 // This method has all state information passed in |file| and is intended
102 // to run on a worker thread rather than the UI thread.
103 // static
104 void FileMetricsProvider::CheckAndMapNewMetrics(
105 FileMetricsProvider::FileInfo* file) {
106 DCHECK(!file->mapped);
107 DCHECK(file->data.empty());
108
109 base::File::Info info;
110 if (!base::GetFileInfo(file->path, &info) ||
111 info.is_directory || info.size == 0) {
112 return;
113 }
114
115 if (file->last_seen >= info.last_modified)
116 return;
117
118 // A new file of metrics has been found. Map it into memory.
119 file->mapped.reset(new base::MemoryMappedFile());
120 if (!file->mapped->Initialize(file->path)) {
121 NOTREACHED();
122 file->mapped.reset();
123 return;
124 }
125
126 // For an "atomic" file, immediately copy the data into local memory and
127 // release the file so that it is not held open.
128 if (file->type == FILE_HISTOGRAMS_ATOMIC) {
129 file->data.assign(file->mapped->data(),
130 file->mapped->data() + file->mapped->length());
131 file->mapped.reset();
132 }
133
134 file->last_loaded = info.last_modified;
135 }
136
137 void FileMetricsProvider::ScheduleFilesCheck() {
138 if (files_to_check_.empty())
139 return;
140
141 FileInfoList* check_list = new FileInfoList();
142 std::swap(files_to_check_, *check_list);
143 task_runner_->PostTaskAndReply(
144 FROM_HERE,
145 base::Bind(&FileMetricsProvider::CheckAndMapNewMetricFilesOnTaskRunner,
146 base::Unretained(check_list)),
147 base::Bind(&FileMetricsProvider::RecordFilesChecked,
148 weak_factory_.GetWeakPtr(), base::Owned(check_list)));
149 }
150
151 void FileMetricsProvider::RecordHistogramSnapshotsFromFile(
152 base::HistogramSnapshotManager* snapshot_manager,
153 FileInfo* file) {
154 int histogram_count = 0;
155 base::PersistentMemoryAllocator::Iterator hist_iter;
156 file->allocator->CreateIterator(&hist_iter);
157
158 while (true) {
159 scoped_ptr<base::HistogramBase> histogram(
160 base::GetNextPersistentHistogram(file->allocator.get(), &hist_iter));
161 if (!histogram)
162 break;
163 if (file->type == FILE_HISTOGRAMS_ATOMIC)
164 snapshot_manager->PrepareAbsoluteTakingOwnership(std::move(histogram));
165 else
166 snapshot_manager->PrepareDeltaTakingOwnership(std::move(histogram));
167 ++histogram_count;
168 }
169
170 DVLOG(1) << "Reported " << histogram_count << " histograms from "
171 << file->path.value();
172 }
173
174 void FileMetricsProvider::CreateAllocatorForFile(FileInfo* file) {
175 DCHECK(!file->allocator);
176
177 if (file->mapped) {
178 DCHECK(file->data.empty());
179 if (base::FilePersistentMemoryAllocator::IsFileAcceptable(
180 *file->mapped)) {
181 file->allocator.reset(new base::FilePersistentMemoryAllocator(
182 std::move(file->mapped), 0, std::string()));
183 }
184 } else {
185 DCHECK(!file->mapped);
186 if (base::PersistentMemoryAllocator::IsMemoryAcceptable(
187 &file->data[0], file->data.size(), 0, true)) {
188 file->allocator.reset(new base::PersistentMemoryAllocator(
189 &file->data[0], file->data.size(), 0, 0, "", true));
190 }
191 }
192
193 if (!file->allocator) {
194 // Something is fundamentally wrong with the file. Ignore it.
195 DLOG(ERROR) << "Metrics file \"" << file->path.value()
196 << "\" is not valid -- ignored.";
197 RecordFileAsSeen(file);
198 NOTREACHED();
199 }
200 }
201
202 void FileMetricsProvider::RecordFilesChecked(FileInfoList* checked) {
203 DCHECK(thread_checker_.CalledOnValidThread());
204
205 // Move each processed file to either the "to-read" list (for processing) or
206 // the "to-check" list (for future checking).
207 for (auto iter = checked->begin(); iter != checked->end();) {
208 auto temp = iter++;
209 const FileInfo* file = temp->get();
210 if (file->mapped || !file->data.empty())
211 files_to_read_.splice(files_to_read_.end(), *checked, temp);
212 else
213 files_to_check_.splice(files_to_check_.end(), *checked, temp);
214 }
215 }
216
217 void FileMetricsProvider::RecordFileAsSeen(FileInfo* file) {
218 file->last_seen = file->last_loaded;
219 if (pref_service_ && !file->prefs_key.empty()) {
220 pref_service_->SetInt64(metrics::prefs::kMetricsLastSeenPrefix +
221 file->prefs_key,
222 file->last_seen.ToInternalValue());
223 }
224 }
225
226 void FileMetricsProvider::OnDidCreateMetricsLog() {
227 DCHECK(thread_checker_.CalledOnValidThread());
228
229 // Move finished metric files back to list of monitored files.
230 for (auto iter = files_to_read_.begin(); iter != files_to_read_.end();) {
231 auto temp = iter++;
232 const FileInfo* file = temp->get();
233 if (!file->allocator && !file->mapped && file->data.empty())
234 files_to_check_.splice(files_to_check_.end(), files_to_read_, temp);
235 }
236
237 // Schedule a check to see if there are new metrics to load. If so, they
238 // will be reported during the next collection run after this one. The
239 // check is run off of the worker-pool so as to not cause delays on the
240 // main UI thread (which is currently where metric collection is done).
241 ScheduleFilesCheck();
242 }
243
244 void FileMetricsProvider::RecordHistogramSnapshots(
245 base::HistogramSnapshotManager* snapshot_manager) {
246 DCHECK(thread_checker_.CalledOnValidThread());
247
248 for (auto& file : files_to_read_) {
249 // If the file is mapped or loaded then it needs to have an allocator
250 // attached to it in order to read histograms out of it.
251 if (file->mapped || !file->data.empty()) {
grt (UTC plus 2) 2016/02/18 16:44:07 nit: omit braces
bcwhite 2016/02/18 19:35:02 Done.
252 CreateAllocatorForFile(file.get());
253 }
254
255 // A file should not be under "files to read" unless it has an allocator
256 // or is memory-mapped (at which point it will have received an allocator
257 // above). However, if this method gets called twice before the scheduled-
258 // files-check has a chance to clean up, this may trigger. This also
259 // catches the case where creating an allocator from the file has failed.
260 if (!file->allocator)
261 continue;
262
263 // Dump all histograms contained within the file to the snapshot-manager.
264 RecordHistogramSnapshotsFromFile(snapshot_manager, file.get());
265
266 // Atomic files are read once and then ignored unless they change.
267 if (file->type == FILE_HISTOGRAMS_ATOMIC) {
268 DCHECK(!file->mapped);
269 file->allocator.reset();
270 file->data.clear();
271 RecordFileAsSeen(file.get());
272 }
273 }
274 }
275
276 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698