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

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

Powered by Google App Engine
This is Rietveld 408576698