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

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: test needs to clear out statistics-recorder before releasing histogram memory 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 // Out-of-line constructor and destructor needed for code efficiency.
26 FileMetricsProvider::FileInformation::FileInformation() {}
27 FileMetricsProvider::FileInformation::~FileInformation() {}
28
29 FileMetricsProvider::FileMetricsProvider(
30 const scoped_refptr<base::TaskRunner>& task_runner,
31 PrefService* local_state)
32 : task_runner_(task_runner),
33 pref_service_(local_state) {
34 }
35
36 FileMetricsProvider::~FileMetricsProvider() {
37 }
38
39 void FileMetricsProvider::RegisterFile(const base::FilePath& path,
40 FileType type,
41 const base::StringPiece& prefs_key) {
42 FileInformation* file = new FileInformation();
43 file->path = path;
44 file->type = type;
45 file->prefs_key = prefs_key.as_string();
46
47 if (pref_service_ && !prefs_key.empty()) {
48 file->last_seen = base::Time::FromInternalValue(
49 pref_service_->GetInt64(metrics::prefs::kMetricsLastSeenPrefix +
50 prefs_key.as_string()));
51 }
52
53 files_to_check_.push_back(make_scoped_ptr(file));
54 }
55
56 // static
57 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs,
58 const base::StringPiece& key) {
59 prefs->RegisterInt64Pref(metrics::prefs::kMetricsLastSeenPrefix +
60 key.as_string(), 0);
61 }
62
63 // static
64 void FileMetricsProvider::CheckAndMapNewMetricFilesOnTaskRunner(
65 FileMetricsProvider::FileInformationList* files) {
66 for (auto& file : *files)
67 CheckAndMapNewMetrics(file.get());
68 }
69
70 // static
71 bool FileMetricsProvider::CheckAndMapNewMetrics(
72 FileMetricsProvider::FileInformation* file) {
73 DCHECK(!file->mapped);
74
75 // Un-mapping a file can only be done on an I/O thread which is why it is
76 // only marked "to release" with the actual release being done here.
77 file->file_to_release.reset();
78 file->allocator_to_release.reset();
79
80 base::File::Info info;
81 if (!base::GetFileInfo(file->path, &info) ||
82 info.is_directory || info.size == 0) {
83 return false;
84 }
85
86 if (file->last_seen >= info.last_modified)
87 return false;
88
89 // A new file of metrics has been found. Map it into memory.
90 file->mapped.reset(new base::MemoryMappedFile());
91 if (!file->mapped->Initialize(file->path)) {
92 NOTREACHED();
93 file->mapped.reset();
94 return false;
95 }
96 return true;
97 }
98
99 void FileMetricsProvider::ScheduleFilesCheck() {
100 if (files_to_check_.empty())
101 return;
102
103 FileInformationList* check_list = new FileInformationList();
104 std::swap(files_to_check_, *check_list);
105 bool posted = task_runner_->PostTaskAndReply(
106 FROM_HERE,
107 base::Bind(&FileMetricsProvider::CheckAndMapNewMetricFilesOnTaskRunner,
108 base::Unretained(check_list)),
109 base::Bind(&FileMetricsProvider::RecordFilesChecked,
110 base::Unretained(this), base::Owned(check_list)));
grt (UTC plus 2) 2016/02/15 15:42:39 IIUC, this FileMetricsProvider instance will be de
bcwhite 2016/02/15 19:22:11 Done.
111 DCHECK(posted);
grt (UTC plus 2) 2016/02/15 15:42:39 i don't think this is a condition that should brea
bcwhite 2016/02/15 19:22:10 Done.
112 }
113
114 void FileMetricsProvider::RecordFilesChecked(FileInformationList* checked) {
115 // Move each processed file to either the "to-read" list (for processing) or
grt (UTC plus 2) 2016/02/15 15:42:39 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); a
bcwhite 2016/02/15 19:22:11 This is in "components". Can it access "content"?
grt (UTC plus 2) 2016/02/15 19:53:55 Ah, bummer. Another way to ensure that methods are
bcwhite 2016/02/15 21:46:00 Done.
116 // the "to-check" list (for future checking).
117 for (auto iter = checked->begin(); iter != checked->end();) {
118 auto temp = iter++;
119 const FileInformation* file = temp->get();
120 if (file->mapped)
121 files_to_read_.splice(files_to_read_.end(), *checked, temp);
122 else
123 files_to_check_.splice(files_to_check_.end(), *checked, temp);
124 }
125 }
126
127 void FileMetricsProvider::RecordFileAsSeen(FileInformation* file) {
128 file->last_seen = base::Time::Now();
129 if (pref_service_ && !file->prefs_key.empty()) {
130 pref_service_->SetInt64(metrics::prefs::kMetricsLastSeenPrefix +
131 file->prefs_key,
132 file->last_seen.ToInternalValue());
133 }
134 }
135
136 void FileMetricsProvider::OnDidCreateMetricsLog() {
137 // Move finished metric files back to list of monitored files.
grt (UTC plus 2) 2016/02/15 15:42:39 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); a
bcwhite 2016/02/15 21:46:00 Done.
138 for (auto iter = files_to_read_.begin(); iter != files_to_read_.end();) {
139 auto temp = iter++;
140 const FileInformation* file = temp->get();
141 if (!file->allocator && !file->mapped)
142 files_to_check_.splice(files_to_check_.end(), files_to_read_, temp);
143 }
144
145 // Schedule a check to see if there are new metrics to load. If so, they
146 // will be reported during the next collection run after this one. The
147 // check is run off of the worker-pool so as to not cause delays on the
148 // main UI thread (which is currently where metric collection is done).
149 ScheduleFilesCheck();
150 }
151
152 void FileMetricsProvider::RecordHistogramSnapshots(
153 base::HistogramSnapshotManager* hsm) {
154 for (auto& file : files_to_read_) {
grt (UTC plus 2) 2016/02/15 15:42:39 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); a
bcwhite 2016/02/15 21:46:00 Done.
155 // If the file is mapped then it needs to have an allocator attached to
156 // it in order to read histograms out of it.
157 if (file->mapped) {
158 DCHECK(!file->allocator);
159 DCHECK(!file->file_to_release);
160 DCHECK(!file->allocator_to_release);
161 if (!base::FilePersistentMemoryAllocator::IsFileAcceptable(
162 *file->mapped)) {
163 // Something is fundamentally wrong with the file. Ignore it.
164 LOG(ERROR) << "Metrics file \"" << file->path.value()
165 << "\" is not valid -- ignored.";
166 file->file_to_release.swap(file->mapped);
167 RecordFileAsSeen(file.get());
168 NOTREACHED();
169 continue;
170 }
171 file->allocator.reset(new base::FilePersistentMemoryAllocator(
172 std::move(file->mapped), 0, std::string()));
173 }
174
175 // A file should not be under "files to read" unless it has an allocator
176 // or is memory-mapped (at which point it will have received an allocator
177 // above). However, if this method gets called twice before the scheduled-
178 // files-check has a chance to clean up, this may trigger.
179 if (!file->allocator)
180 continue;
181
182 int histogram_count = 0;
183 base::PersistentMemoryAllocator::Iterator hist_iter;
184 file->allocator->CreateIterator(&hist_iter);
185 for (;;) {
grt (UTC plus 2) 2016/02/15 15:42:39 nit: while (true) is more common
bcwhite 2016/02/15 19:22:10 Done.
186 scoped_ptr<base::HistogramBase> histogram(
187 base::GetNextPersistentHistogram(file->allocator.get(), &hist_iter));
188 if (!histogram)
189 break;
190 if (file->type == FILE_HISTOGRAMS_ATOMIC)
191 hsm->PrepareOnceTakingOwnership(std::move(histogram));
192 else
193 hsm->PrepareDeltaTakingOwnership(std::move(histogram));
194 histogram_count++;
grt (UTC plus 2) 2016/02/15 15:42:39 although either pre- or post-increment is allowed
bcwhite 2016/02/15 19:22:11 Done.
195 }
196 VLOG(1) << "Reported " << histogram_count << " histograms from "
grt (UTC plus 2) 2016/02/15 15:42:39 production logging carries weight in the form of t
bcwhite 2016/02/15 19:22:10 Done.
197 << file->path.value();
198
199 if (file->type == FILE_HISTOGRAMS_ATOMIC) {
200 DCHECK(!file->mapped); // Ownership should have moved to allocator.
201 DCHECK(!file->file_to_release);
202 DCHECK(!file->allocator_to_release);
203 file->allocator_to_release.swap(file->allocator);
grt (UTC plus 2) 2016/02/15 15:42:39 since the allocator isn't released until the next
bcwhite 2016/02/15 19:22:10 The call to OnDidCreateMetricsLog should be called
grt (UTC plus 2) 2016/02/15 19:53:55 Ah, okay, so it'll generally be locked only during
bcwhite 2016/02/15 21:46:00 You know... That was more trouble than each littl
204 RecordFileAsSeen(file.get());
205 }
206 }
207 }
208
209 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698