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

Side by Side Diff: components/metrics/file_metrics_provider.cc

Issue 2918533003: Send metrics with embedded system profiles after system startup. (Closed)
Patch Set: addressed final review comments Created 3 years, 6 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/metrics/file_metrics_provider.h" 5 #include "components/metrics/file_metrics_provider.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/files/file.h" 8 #include "base/files/file.h"
9 #include "base/files/file_enumerator.h" 9 #include "base/files/file_enumerator.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
11 #include "base/files/memory_mapped_file.h" 11 #include "base/files/memory_mapped_file.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram_base.h" 14 #include "base/metrics/histogram_base.h"
15 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
16 #include "base/metrics/persistent_histogram_allocator.h" 16 #include "base/metrics/persistent_histogram_allocator.h"
17 #include "base/metrics/persistent_memory_allocator.h" 17 #include "base/metrics/persistent_memory_allocator.h"
18 #include "base/strings/string_piece.h" 18 #include "base/strings/string_piece.h"
19 #include "base/task_runner.h" 19 #include "base/task_runner.h"
20 #include "base/time/time.h" 20 #include "base/time/time.h"
21 #include "components/metrics/metrics_pref_names.h" 21 #include "components/metrics/metrics_pref_names.h"
22 #include "components/metrics/metrics_service.h" 22 #include "components/metrics/metrics_service.h"
23 #include "components/metrics/persistent_system_profile.h"
23 #include "components/prefs/pref_registry_simple.h" 24 #include "components/prefs/pref_registry_simple.h"
24 #include "components/prefs/pref_service.h" 25 #include "components/prefs/pref_service.h"
25 26
26 namespace metrics { 27 namespace metrics {
27 28
28 namespace { 29 namespace {
29 30
30 // These structures provide values used to define how files are opened and 31 // These structures provide values used to define how files are opened and
31 // accessed. It obviates the need for multiple code-paths within several of 32 // accessed. It obviates the need for multiple code-paths within several of
32 // the methods. 33 // the methods.
(...skipping 30 matching lines...) Expand all
63 }, 64 },
64 // SOURCE_HISTOGRAMS_ACTIVE_FILE 65 // SOURCE_HISTOGRAMS_ACTIVE_FILE
65 { 66 {
66 // Allow writing (updated "logged" values) to the file. 67 // Allow writing (updated "logged" values) to the file.
67 STD_OPEN | base::File::FLAG_WRITE, 68 STD_OPEN | base::File::FLAG_WRITE,
68 base::MemoryMappedFile::READ_WRITE, 69 base::MemoryMappedFile::READ_WRITE,
69 false 70 false
70 } 71 }
71 }; 72 };
72 73
74 enum EmbeddedProfileResult : int {
75 EMBEDDED_PROFILE_ATTEMPT,
76 EMBEDDED_PROFILE_FOUND,
77 EMBEDDED_PROFILE_FALLBACK,
78 EMBEDDED_PROFILE_DROPPED,
79 EMBEDDED_PROFILE_ACTION_MAX
80 };
81
82 void RecordEmbeddedProfileResult(EmbeddedProfileResult result) {
83 UMA_HISTOGRAM_ENUMERATION("UMA.FileMetricsProvider.EmbeddedProfileResult",
84 result, EMBEDDED_PROFILE_ACTION_MAX);
85 }
86
73 void DeleteFileWhenPossible(const base::FilePath& path) { 87 void DeleteFileWhenPossible(const base::FilePath& path) {
74 // Open (with delete) and then immediately close the file by going out of 88 // Open (with delete) and then immediately close the file by going out of
75 // scope. This is the only cross-platform safe way to delete a file that may 89 // scope. This is the only cross-platform safe way to delete a file that may
76 // be open elsewhere, a distinct possibility given the asynchronous nature 90 // be open elsewhere, a distinct possibility given the asynchronous nature
77 // of the delete task. 91 // of the delete task.
78 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ | 92 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ |
79 base::File::FLAG_DELETE_ON_CLOSE); 93 base::File::FLAG_DELETE_ON_CLOSE);
80 } 94 }
81 95
82 } // namespace 96 } // namespace
83 97
84 // This structure stores all the information about the sources being monitored 98 // This structure stores all the information about the sources being monitored
85 // and their current reporting state. 99 // and their current reporting state.
86 struct FileMetricsProvider::SourceInfo { 100 struct FileMetricsProvider::SourceInfo {
87 SourceInfo(SourceType source_type) : type(source_type) {} 101 SourceInfo(SourceType source_type, SourceAssociation source_association)
102 : type(source_type), association(source_association) {}
88 ~SourceInfo() {} 103 ~SourceInfo() {}
89 104
90 // How to access this source (file/dir, atomic/active). 105 // How to access this source (file/dir, atomic/active).
91 const SourceType type; 106 const SourceType type;
92 107
108 // With what run this source is associated.
109 const SourceAssociation association;
110
93 // Where on disk the directory is located. This will only be populated when 111 // Where on disk the directory is located. This will only be populated when
94 // a directory is being monitored. 112 // a directory is being monitored.
95 base::FilePath directory; 113 base::FilePath directory;
96 114
97 // Where on disk the file is located. If a directory is being monitored, 115 // Where on disk the file is located. If a directory is being monitored,
98 // this will be updated for whatever file is being read. 116 // this will be updated for whatever file is being read.
99 base::FilePath path; 117 base::FilePath path;
100 118
101 // Name used inside prefs to persistent metadata. 119 // Name used inside prefs to persistent metadata.
102 std::string prefs_key; 120 std::string prefs_key;
(...skipping 26 matching lines...) Expand all
129 147
130 void FileMetricsProvider::RegisterSource(const base::FilePath& path, 148 void FileMetricsProvider::RegisterSource(const base::FilePath& path,
131 SourceType type, 149 SourceType type,
132 SourceAssociation source_association, 150 SourceAssociation source_association,
133 const base::StringPiece prefs_key) { 151 const base::StringPiece prefs_key) {
134 DCHECK(thread_checker_.CalledOnValidThread()); 152 DCHECK(thread_checker_.CalledOnValidThread());
135 153
136 // Ensure that kSourceOptions has been filled for this type. 154 // Ensure that kSourceOptions has been filled for this type.
137 DCHECK_GT(arraysize(kSourceOptions), static_cast<size_t>(type)); 155 DCHECK_GT(arraysize(kSourceOptions), static_cast<size_t>(type));
138 156
139 std::unique_ptr<SourceInfo> source(new SourceInfo(type)); 157 std::unique_ptr<SourceInfo> source(new SourceInfo(type, source_association));
140 source->prefs_key = prefs_key.as_string(); 158 source->prefs_key = prefs_key.as_string();
141 159
142 switch (source->type) { 160 switch (source->type) {
143 case SOURCE_HISTOGRAMS_ACTIVE_FILE: 161 case SOURCE_HISTOGRAMS_ACTIVE_FILE:
144 DCHECK(prefs_key.empty()); 162 DCHECK(prefs_key.empty());
145 // fall through 163 // fall through
146 case SOURCE_HISTOGRAMS_ATOMIC_FILE: 164 case SOURCE_HISTOGRAMS_ATOMIC_FILE:
147 source->path = path; 165 source->path = path;
148 break; 166 break;
149 case SOURCE_HISTOGRAMS_ATOMIC_DIR: 167 case SOURCE_HISTOGRAMS_ATOMIC_DIR:
150 source->directory = path; 168 source->directory = path;
151 break; 169 break;
152 } 170 }
153 171
154 // |prefs_key| may be empty if the caller does not wish to persist the 172 // |prefs_key| may be empty if the caller does not wish to persist the
155 // state across instances of the program. 173 // state across instances of the program.
156 if (pref_service_ && !prefs_key.empty()) { 174 if (pref_service_ && !prefs_key.empty()) {
157 source->last_seen = base::Time::FromInternalValue( 175 source->last_seen = base::Time::FromInternalValue(
158 pref_service_->GetInt64(metrics::prefs::kMetricsLastSeenPrefix + 176 pref_service_->GetInt64(metrics::prefs::kMetricsLastSeenPrefix +
159 source->prefs_key)); 177 source->prefs_key));
160 } 178 }
161 179
162 switch (source_association) { 180 switch (source_association) {
163 case ASSOCIATE_CURRENT_RUN: 181 case ASSOCIATE_CURRENT_RUN:
182 case ASSOCIATE_INTERNAL_PROFILE:
164 sources_to_check_.push_back(std::move(source)); 183 sources_to_check_.push_back(std::move(source));
165 break; 184 break;
166 case ASSOCIATE_PREVIOUS_RUN: 185 case ASSOCIATE_PREVIOUS_RUN:
186 case ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN:
167 DCHECK_EQ(SOURCE_HISTOGRAMS_ATOMIC_FILE, source->type); 187 DCHECK_EQ(SOURCE_HISTOGRAMS_ATOMIC_FILE, source->type);
168 sources_for_previous_run_.push_back(std::move(source)); 188 sources_for_previous_run_.push_back(std::move(source));
169 break; 189 break;
170 } 190 }
171 } 191 }
172 192
173 // static 193 // static
174 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs, 194 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs,
175 const base::StringPiece prefs_key) { 195 const base::StringPiece prefs_key) {
176 prefs->RegisterInt64Pref(metrics::prefs::kMetricsLastSeenPrefix + 196 prefs->RegisterInt64Pref(metrics::prefs::kMetricsLastSeenPrefix +
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 if (oldest_file_path.empty()) 263 if (oldest_file_path.empty())
244 return false; 264 return false;
245 265
246 // Set the active file to be the oldest modified file that has not yet 266 // Set the active file to be the oldest modified file that has not yet
247 // been read. 267 // been read.
248 source->path = std::move(oldest_file_path); 268 source->path = std::move(oldest_file_path);
249 return true; 269 return true;
250 } 270 }
251 271
252 // static 272 // static
273 void FileMetricsProvider::FinishedWithSource(SourceInfo* source,
274 AccessResult result) {
275 // Different source types require different post-processing.
276 switch (source->type) {
277 case SOURCE_HISTOGRAMS_ATOMIC_FILE:
278 case SOURCE_HISTOGRAMS_ATOMIC_DIR:
279 // Done with this file so delete the allocator and its owned file.
280 source->allocator.reset();
281 // Remove the file if has been recorded. This prevents them from
282 // accumulating or also being recorded by different instances of
283 // the browser.
284 if (result == ACCESS_RESULT_SUCCESS ||
285 result == ACCESS_RESULT_NOT_MODIFIED) {
286 DeleteFileWhenPossible(source->path);
287 }
288 break;
289 case SOURCE_HISTOGRAMS_ACTIVE_FILE:
290 // Keep the allocator open so it doesn't have to be re-mapped each
291 // time. This also allows the contents to be merged on-demand.
292 break;
293 }
294 }
295
296 // static
253 void FileMetricsProvider::CheckAndMergeMetricSourcesOnTaskRunner( 297 void FileMetricsProvider::CheckAndMergeMetricSourcesOnTaskRunner(
254 SourceInfoList* sources) { 298 SourceInfoList* sources) {
255 // This method has all state information passed in |sources| and is intended 299 // This method has all state information passed in |sources| and is intended
256 // to run on a worker thread rather than the UI thread. 300 // to run on a worker thread rather than the UI thread.
257 for (std::unique_ptr<SourceInfo>& source : *sources) { 301 for (std::unique_ptr<SourceInfo>& source : *sources) {
258 AccessResult result = CheckAndMapMetricSource(source.get()); 302 AccessResult result = CheckAndMapMetricSource(source.get());
259 303
260 // Some results are not reported in order to keep the dashboard clean. 304 // Some results are not reported in order to keep the dashboard clean.
261 if (result != ACCESS_RESULT_DOESNT_EXIST && 305 if (result != ACCESS_RESULT_DOESNT_EXIST &&
262 result != ACCESS_RESULT_NOT_MODIFIED) { 306 result != ACCESS_RESULT_NOT_MODIFIED) {
263 UMA_HISTOGRAM_ENUMERATION( 307 UMA_HISTOGRAM_ENUMERATION(
264 "UMA.FileMetricsProvider.AccessResult", result, ACCESS_RESULT_MAX); 308 "UMA.FileMetricsProvider.AccessResult", result, ACCESS_RESULT_MAX);
265 } 309 }
266 310
311 // Metrics associated with internal profiles have to be fetched directly
312 // so just keep the mapping for use by the main thread.
313 if (source->association == ASSOCIATE_INTERNAL_PROFILE)
314 continue;
315
267 // Mapping was successful. Merge it. 316 // Mapping was successful. Merge it.
268 if (result == ACCESS_RESULT_SUCCESS) { 317 if (result == ACCESS_RESULT_SUCCESS) {
269 MergeHistogramDeltasFromSource(source.get()); 318 MergeHistogramDeltasFromSource(source.get());
270 DCHECK(source->read_complete); 319 DCHECK(source->read_complete);
271 } 320 }
272 321
273 // Different source types require different post-processing. 322 // All done with this source.
274 switch (source->type) { 323 FinishedWithSource(source.get(), result);
275 case SOURCE_HISTOGRAMS_ATOMIC_FILE:
276 case SOURCE_HISTOGRAMS_ATOMIC_DIR:
277 // Done with this file so delete the allocator and its owned file.
278 source->allocator.reset();
279 // Remove the file if has been recorded. This prevents them from
280 // accumulating or also being recorded by different instances of
281 // the browser.
282 if (result == ACCESS_RESULT_SUCCESS ||
283 result == ACCESS_RESULT_NOT_MODIFIED) {
284 base::DeleteFile(source->path, /*recursive=*/false);
285 }
286 break;
287 case SOURCE_HISTOGRAMS_ACTIVE_FILE:
288 // Keep the allocator open so it doesn't have to be re-mapped each
289 // time. This also allows the contents to be merged on-demand.
290 break;
291 }
292 } 324 }
293 } 325 }
294 326
295 // This method has all state information passed in |source| and is intended 327 // This method has all state information passed in |source| and is intended
296 // to run on a worker thread rather than the UI thread. 328 // to run on a worker thread rather than the UI thread.
297 // static 329 // static
298 FileMetricsProvider::AccessResult FileMetricsProvider::CheckAndMapMetricSource( 330 FileMetricsProvider::AccessResult FileMetricsProvider::CheckAndMapMetricSource(
299 SourceInfo* source) { 331 SourceInfo* source) {
332 // If source was read, clean up after it.
333 if (source->read_complete)
334 FinishedWithSource(source, ACCESS_RESULT_SUCCESS);
335 source->read_complete = false;
300 DCHECK(!source->allocator); 336 DCHECK(!source->allocator);
301 source->read_complete = false;
302 337
303 // If the source is a directory, look for files within it. 338 // If the source is a directory, look for files within it.
304 if (!source->directory.empty() && !LocateNextFileInDirectory(source)) 339 if (!source->directory.empty() && !LocateNextFileInDirectory(source))
305 return ACCESS_RESULT_DOESNT_EXIST; 340 return ACCESS_RESULT_DOESNT_EXIST;
306 341
307 // Do basic validation on the file metadata. 342 // Do basic validation on the file metadata.
308 base::File::Info info; 343 base::File::Info info;
309 if (!base::GetFileInfo(source->path, &info)) 344 if (!base::GetFileInfo(source->path, &info))
310 return ACCESS_RESULT_DOESNT_EXIST; 345 return ACCESS_RESULT_DOESNT_EXIST;
311 346
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 // try again immediately to see if more is available (in a directory of 465 // try again immediately to see if more is available (in a directory of
431 // files). Otherwise, remember the source for checking again at a later time. 466 // files). Otherwise, remember the source for checking again at a later time.
432 bool did_read = false; 467 bool did_read = false;
433 for (auto iter = checked->begin(); iter != checked->end();) { 468 for (auto iter = checked->begin(); iter != checked->end();) {
434 auto temp = iter++; 469 auto temp = iter++;
435 SourceInfo* source = temp->get(); 470 SourceInfo* source = temp->get();
436 if (source->read_complete) { 471 if (source->read_complete) {
437 RecordSourceAsRead(source); 472 RecordSourceAsRead(source);
438 did_read = true; 473 did_read = true;
439 } 474 }
440 if (source->allocator) 475 if (source->allocator) {
441 sources_mapped_.splice(sources_mapped_.end(), *checked, temp); 476 if (source->association == ASSOCIATE_INTERNAL_PROFILE) {
442 else 477 sources_with_profile_.splice(sources_with_profile_.end(), *checked,
478 temp);
479 } else {
480 sources_mapped_.splice(sources_mapped_.end(), *checked, temp);
481 }
482 } else {
443 sources_to_check_.splice(sources_to_check_.end(), *checked, temp); 483 sources_to_check_.splice(sources_to_check_.end(), *checked, temp);
484 }
444 } 485 }
445 486
446 // If a read was done, schedule another one immediately. In the case of a 487 // If a read was done, schedule another one immediately. In the case of a
447 // directory of files, this ensures that all entries get processed. It's 488 // directory of files, this ensures that all entries get processed. It's
448 // done here instead of as a loop in CheckAndMergeMetricSourcesOnTaskRunner 489 // done here instead of as a loop in CheckAndMergeMetricSourcesOnTaskRunner
449 // so that (a) it gives the disk a rest and (b) testing of individual reads 490 // so that (a) it gives the disk a rest and (b) testing of individual reads
450 // is possible. 491 // is possible.
451 if (did_read) 492 if (did_read)
452 ScheduleSourcesCheck(); 493 ScheduleSourcesCheck();
453 } 494 }
(...skipping 26 matching lines...) Expand all
480 // Clear any data for initial metrics since they're always reported 521 // Clear any data for initial metrics since they're always reported
481 // before the first call to this method. It couldn't be released after 522 // before the first call to this method. It couldn't be released after
482 // being reported in RecordInitialHistogramSnapshots because the data 523 // being reported in RecordInitialHistogramSnapshots because the data
483 // will continue to be used by the caller after that method returns. Once 524 // will continue to be used by the caller after that method returns. Once
484 // here, though, all actions to be done on the data have been completed. 525 // here, though, all actions to be done on the data have been completed.
485 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_) 526 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_)
486 DeleteFileAsync(source->path); 527 DeleteFileAsync(source->path);
487 sources_for_previous_run_.clear(); 528 sources_for_previous_run_.clear();
488 } 529 }
489 530
531 bool FileMetricsProvider::ProvideIndependentMetrics(
532 SystemProfileProto* system_profile_proto,
533 base::HistogramSnapshotManager* snapshot_manager) {
534 DCHECK(thread_checker_.CalledOnValidThread());
535
536 while (!sources_with_profile_.empty()) {
537 SourceInfo* source = sources_with_profile_.begin()->get();
538 DCHECK(source->allocator);
539
540 bool success = false;
541 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT);
542 if (PersistentSystemProfile::GetSystemProfile(
543 *source->allocator->memory_allocator(), system_profile_proto)) {
544 RecordHistogramSnapshotsFromSource(snapshot_manager, source);
545 success = true;
546 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_FOUND);
547 } else {
548 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_DROPPED);
549 }
550
551 // Regardless of whether this source was successfully recorded, it is never
552 // read again.
553 source->read_complete = true;
554 RecordSourceAsRead(source);
555 sources_to_check_.splice(sources_to_check_.end(), sources_with_profile_,
556 sources_with_profile_.begin());
557 if (success)
558 return true;
559 }
560
561 return false;
562 }
563
490 bool FileMetricsProvider::HasInitialStabilityMetrics() { 564 bool FileMetricsProvider::HasInitialStabilityMetrics() {
491 DCHECK(thread_checker_.CalledOnValidThread()); 565 DCHECK(thread_checker_.CalledOnValidThread());
492 566
493 // Measure the total time spent checking all sources as well as the time 567 // Measure the total time spent checking all sources as well as the time
494 // per individual file. This method is called during startup and thus blocks 568 // per individual file. This method is called during startup and thus blocks
495 // the initial showing of the browser window so it's important to know the 569 // the initial showing of the browser window so it's important to know the
496 // total delay. 570 // total delay.
497 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.InitialCheckTime.Total"); 571 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.InitialCheckTime.Total");
498 572
499 // Check all sources for previous run to see if they need to be read. 573 // Check all sources for previous run to see if they need to be read.
(...skipping 14 matching lines...) Expand all
514 // If it couldn't be accessed, remove it from the list. There is only ever 588 // If it couldn't be accessed, remove it from the list. There is only ever
515 // one chance to record it so no point keeping it around for later. Also 589 // one chance to record it so no point keeping it around for later. Also
516 // mark it as having been read since uploading it with a future browser 590 // mark it as having been read since uploading it with a future browser
517 // run would associate it with the then-previous run which would no longer 591 // run would associate it with the then-previous run which would no longer
518 // be the run from which it came. 592 // be the run from which it came.
519 if (result != ACCESS_RESULT_SUCCESS) { 593 if (result != ACCESS_RESULT_SUCCESS) {
520 DCHECK(!source->allocator); 594 DCHECK(!source->allocator);
521 RecordSourceAsRead(source); 595 RecordSourceAsRead(source);
522 DeleteFileAsync(source->path); 596 DeleteFileAsync(source->path);
523 sources_for_previous_run_.erase(temp); 597 sources_for_previous_run_.erase(temp);
598 continue;
599 }
600
601 DCHECK(source->allocator);
602
603 // If the source should be associated with an existing internal profile,
604 // move it to |sources_with_profile_| for later upload.
605 if (source->association == ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN) {
606 if (PersistentSystemProfile::HasSystemProfile(
607 *source->allocator->memory_allocator())) {
608 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT);
609 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_FALLBACK);
610 sources_with_profile_.splice(sources_with_profile_.end(),
611 sources_for_previous_run_, temp);
612 }
524 } 613 }
525 } 614 }
526 615
527 return !sources_for_previous_run_.empty(); 616 return !sources_for_previous_run_.empty();
528 } 617 }
529 618
530 void FileMetricsProvider::RecordInitialHistogramSnapshots( 619 void FileMetricsProvider::RecordInitialHistogramSnapshots(
531 base::HistogramSnapshotManager* snapshot_manager) { 620 base::HistogramSnapshotManager* snapshot_manager) {
532 DCHECK(thread_checker_.CalledOnValidThread()); 621 DCHECK(thread_checker_.CalledOnValidThread());
533 622
(...skipping 29 matching lines...) Expand all
563 // important to know how much total "jank" may be introduced. 652 // important to know how much total "jank" may be introduced.
564 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.Total"); 653 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.Total");
565 654
566 for (std::unique_ptr<SourceInfo>& source : sources_mapped_) { 655 for (std::unique_ptr<SourceInfo>& source : sources_mapped_) {
567 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.File"); 656 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.File");
568 MergeHistogramDeltasFromSource(source.get()); 657 MergeHistogramDeltasFromSource(source.get());
569 } 658 }
570 } 659 }
571 660
572 } // namespace metrics 661 } // 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