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

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

Powered by Google App Engine
This is Rietveld 408576698