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

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

Powered by Google App Engine
This is Rietveld 408576698