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

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: moved allocator create/destroy to be beside snapshot (simpler code) 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 2015 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_found_(0),
grt (UTC plus 2) 2016/02/04 15:36:42 nit: remove this initializer
bcwhite 2016/02/04 21:51:14 Leftover from a previous design. Odd that it isn'
32 metrics_service_(metrics_service),
33 pref_service_(local_state) {
34 // Start a background check for pending setup metrics so it can be uploaded
grt (UTC plus 2) 2016/02/04 15:36:42 is it appropriate for this to be generalized so th
bcwhite 2016/02/04 21:51:14 I started it as something specific for Setup but t
grt (UTC plus 2) 2016/02/08 18:09:18 In that case, could you update this and other refe
bcwhite 2016/02/09 21:08:45 Done.
35 // during the initial report.
36 ScheduleFilesCheck();
37 }
38
39 FileMetricsProvider::~FileMetricsProvider() {
40 // Destruction of this object can lead to failures because of a task
41 // posted on the Worker Pool or because the owned Memory Allocator has
grt (UTC plus 2) 2016/02/04 15:36:42 the destruction problems are avoided by following
42 // been passed to the Metrics Service. Both cases can only occur if
43 // a Metrics Service has been provided (i.e. not during testing).
44 DCHECK(!metrics_service_);
45 }
46
47 void FileMetricsProvider::RegisterFile(const base::FilePath& path,
48 FileType type,
49 const std::string& prefs_key) {
50 FileInformation* file = new FileInformation();
51 file->path = path;
52 file->type = type;
53 file->prefs_key = prefs_key;
54
55 if (!prefs_key.empty()) {
grt (UTC plus 2) 2016/02/04 15:36:43 && pref_service_ since it could be null as per the
bcwhite 2016/02/04 21:51:14 Done.
56 file->last_seen = base::Time::FromInternalValue(
57 pref_service_->GetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix +
58 prefs_key));
59 }
60
61 base::AutoLock lock(lock_);
62 metrics_files_.push_back(scoped_ptr<FileInformation>(file));
grt (UTC plus 2) 2016/02/04 15:36:43 nit: scoped_ptr<FileInformation>(file) -> make_sco
bcwhite 2016/02/04 21:51:14 Done.
63 }
64
65 // static
66 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs,
67 const std::string& key) {
68 prefs->RegisterInt64Pref(metrics::prefs::kSetupMetricsLastSeenPrefix +
grt (UTC plus 2) 2016/02/04 15:36:43 nit: indentation
bcwhite 2016/02/04 21:51:14 Done.
69 key, 0);
70 }
71
72 void FileMetricsProvider::OnDidCreateMetricsLog() {
73 // Hold off async updates to file lists while processing.
74 base::AutoLock lock(lock_);
75
76 // Move finished metric files back to list of monitored files.
77 FileInformationList::iterator iter;
78 for (iter = metrics_found_.begin(); iter != metrics_found_.end();) {
grt (UTC plus 2) 2016/02/04 15:36:43 nit: define |iter| here with "auto iter = ..."
bcwhite 2016/02/04 21:51:14 Done.
79 auto temp = iter++;
80 const FileInformation* file = temp->get();
grt (UTC plus 2) 2016/02/04 15:36:43 nit: omit this local var and use temp-> directly b
bcwhite 2016/02/04 21:51:14 I'd rather not. It looks ugly with all the temp->
81 if (!file->allocator && !file->mapped) {
82 metrics_files_.push_back(std::move(*temp));
grt (UTC plus 2) 2016/02/04 15:36:43 i believe this line and the next can be replaced w
bcwhite 2016/02/04 21:51:14 Done.
83 metrics_found_.erase(temp);
84 }
85 }
86
87 // Schedule a check to see if there are new metrics to load. If so, they
88 // will be reported during the next collection run after this one. The
89 // check is run off of the worker-pool so as to not cause delays on the
90 // main UI thread (which is currently where metric collection is done).
91 ScheduleFilesCheck();
92 }
93
94 void FileMetricsProvider::RecordHistogramSnapshots(
95 base::HistogramSnapshotManager* hsm) {
96 // Hold off async updates to file lists while processing.
97 base::AutoLock lock(lock_);
98
99 for (auto& file_iter : metrics_found_) {
grt (UTC plus 2) 2016/02/04 15:36:43 nit: |file_iter| isn't an iterator here, but rathe
bcwhite 2016/02/04 21:51:14 Done.
100 FileInformation* file = file_iter.get();
grt (UTC plus 2) 2016/02/04 15:36:43 nit: omit this local var and use the auto'd |file|
bcwhite 2016/02/04 21:51:14 Done.
101
102 if (!file->allocator) {
103 DCHECK(file->mapped);
104 if (!base::FilePersistentMemoryAllocator::IsFileAcceptable(
105 *file->mapped)) {
106 // Something is fundamentally wrong with the file. Ignore it.
107 LOG(ERROR) << "Metrics file \"" << file->path.AsUTF8Unsafe()
grt (UTC plus 2) 2016/02/04 15:36:43 file->path.value() should be fine here
bcwhite 2016/02/04 21:51:14 Done.
108 << "\" is not valid -- ignored.";
109 file->mapped.reset();
110 RecordFileAsSeen(file);
111 NOTREACHED();
112 continue;
113 }
114 file->allocator.reset(new base::FilePersistentMemoryAllocator(
grt (UTC plus 2) 2016/02/04 15:36:43 change FilePersistentMemoryAllocator so that it ta
bcwhite 2016/02/04 21:51:14 Doing that in a different CL: https://codereview.c
115 file->mapped.release(), 0, std::string()));
116 }
117
118 if (file->allocator) {
grt (UTC plus 2) 2016/02/04 15:36:43 remove this condition as it will always be true on
bcwhite 2016/02/04 21:51:14 Done.
119 base::PersistentMemoryAllocator::Iterator hist_iter;
120 file->allocator->CreateIterator(&hist_iter);
121 for (;;) {
122 base::HistogramBase* histogram =
grt (UTC plus 2) 2016/02/04 15:36:43 use scoped_ptr<base::HistogramBase> rather than a
bcwhite 2016/02/09 21:08:45 Done.
123 base::GetNextPersistentHistogram(file->allocator.get(), &hist_iter);
grt (UTC plus 2) 2016/02/04 15:36:43 please update this and the related functions to re
bcwhite 2016/02/09 21:08:45 Okay. It doesn't belong here, though. I'll do it
124 if (!histogram)
125 break;
126 if (file->type == FILE_HISTOGRAMS_ATOMIC) {
grt (UTC plus 2) 2016/02/04 15:36:43 nit: omit braces
bcwhite 2016/02/04 21:51:14 Done.
127 hsm->PrepareOnceTakingOwnership(histogram);
128 } else {
129 hsm->PrepareDeltaTakingOwnership(histogram);
130 }
131 }
132
133 if (file->type == FILE_HISTOGRAMS_ATOMIC) {
134 DCHECK(!file->mapped); // Ownership should have moved to allocator.
135 file->allocator.reset();
136 RecordFileAsSeen(file);
137 }
138 }
139 }
140 }
141
142 void FileMetricsProvider::RecordFileAsSeen(FileInformation* file) {
143 file->last_seen = base::Time::Now();
144 if (!file->prefs_key.empty()) {
grt (UTC plus 2) 2016/02/04 15:36:42 && pref_service_
bcwhite 2016/02/04 21:51:14 Done.
145 pref_service_->SetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix +
146 file->prefs_key,
147 file->last_seen.ToInternalValue());
148 }
149 }
150
151 // static
152 void FileMetricsProvider::CheckAndMapNewMetricFiles(
grt (UTC plus 2) 2016/02/04 15:36:43 nit: often a suffix such as "OnBlockingPool" is ad
bcwhite 2016/02/04 21:51:14 Done.
153 FileMetricsProvider::FileInformationList* files,
154 base::Callback<void(FileInformationList*)> callback) {
155 for (auto& file : *files)
156 CheckAndMapNewMetrics(file.get());
157 callback.Run(files);
158 }
159
160 // static
161 bool FileMetricsProvider::CheckAndMapNewMetrics(
162 FileMetricsProvider::FileInformation* file) {
163 DCHECK(!file->mapped);
164
165 base::File::Info info;
166 if (!base::GetFileInfo(file->path, &info) ||
167 info.is_directory || info.size == 0) {
168 return false;
169 }
170
171 if (file->last_seen >= info.last_modified)
172 return false;
173
174 // A new file of setup metrics has been found. Map it into memory.
175 file->mapped.reset(new base::MemoryMappedFile());
176 file->mapped->Initialize(file->path);
grt (UTC plus 2) 2016/02/04 15:36:43 if (file->mapped->Initialize(file->path)) retu
bcwhite 2016/02/04 21:51:14 Done.
177 return true;
178 }
179
180 void FileMetricsProvider::ScheduleFilesCheck() {
181 // Don't do anything if metrics_service is not valid (for testing).
182 if (!metrics_service_)
183 return;
184
185 // TODO(bcwhite): Change this if metric collection moves off UI thread.
186 FileInformationList* check_list = new FileInformationList();
187 std::swap(metrics_files_, *check_list);
188 bool posted = base::WorkerPool::PostTask(
grt (UTC plus 2) 2016/02/04 15:36:42 This should use the BrowserThread BlockingPool rat
189 FROM_HERE,
190 base::Bind(&CheckAndMapNewMetricFiles,
191 base::Owned(check_list),
192 base::Bind(&FileMetricsProvider::RecordFileInformation,
193 base::Unretained(this))),
grt (UTC plus 2) 2016/02/04 15:36:43 This will lead to a use-after-free if the metrics
194 false);
195 DCHECK(posted);
grt (UTC plus 2) 2016/02/04 15:36:42 I don't think this is needed. false from PostTask*
196 }
197
198 void FileMetricsProvider::RecordFileInformation(FileInformationList* files) {
199 // This is a callback and thus possibly not on the same thread as the main
200 // metrics collection.
201 base::AutoLock lock(lock_);
202
203 // Move each processed file to either the "found" list (for processing) or
204 // the "files" list (for future checking).
205 for (auto& iter : *files) {
206 if (iter->mapped) {
grt (UTC plus 2) 2016/02/04 15:36:43 nit: omit braces
bcwhite 2016/02/09 21:08:45 Done.
207 metrics_found_.push_back(std::move(iter));
grt (UTC plus 2) 2016/02/04 15:36:43 use splice to move the element. you'll have to cha
bcwhite 2016/02/04 21:51:14 Each move in that case has to delete the value fro
grt (UTC plus 2) 2016/02/08 18:09:18 metrics_files_ and metrics_found_ are both linked
208 } else {
209 metrics_files_.push_back(std::move(iter));
grt (UTC plus 2) 2016/02/04 15:36:43 metrics_files_.splice(metrics_files_.end(), *files
bcwhite 2016/02/04 21:51:14 Done.
210 }
211 }
212 }
213
214 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698