OLD | NEW |
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/task_scheduler/post_task.h" |
| 21 #include "base/task_scheduler/task_traits.h" |
20 #include "base/time/time.h" | 22 #include "base/time/time.h" |
21 #include "components/metrics/metrics_pref_names.h" | 23 #include "components/metrics/metrics_pref_names.h" |
22 #include "components/metrics/metrics_service.h" | 24 #include "components/metrics/metrics_service.h" |
23 #include "components/metrics/persistent_system_profile.h" | 25 #include "components/metrics/persistent_system_profile.h" |
24 #include "components/prefs/pref_registry_simple.h" | 26 #include "components/prefs/pref_registry_simple.h" |
25 #include "components/prefs/pref_service.h" | 27 #include "components/prefs/pref_service.h" |
26 | 28 |
27 namespace metrics { | 29 namespace metrics { |
28 | 30 |
29 namespace { | 31 namespace { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 | 88 |
87 void DeleteFileWhenPossible(const base::FilePath& path) { | 89 void DeleteFileWhenPossible(const base::FilePath& path) { |
88 // Open (with delete) and then immediately close the file by going out of | 90 // Open (with delete) and then immediately close the file by going out of |
89 // scope. This is the only cross-platform safe way to delete a file that may | 91 // scope. This is the only cross-platform safe way to delete a file that may |
90 // be open elsewhere, a distinct possibility given the asynchronous nature | 92 // be open elsewhere, a distinct possibility given the asynchronous nature |
91 // of the delete task. | 93 // of the delete task. |
92 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ | | 94 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ | |
93 base::File::FLAG_DELETE_ON_CLOSE); | 95 base::File::FLAG_DELETE_ON_CLOSE); |
94 } | 96 } |
95 | 97 |
| 98 // A task runner to use for testing. |
| 99 base::TaskRunner* g_task_runner_for_testing = nullptr; |
| 100 |
| 101 // Returns a task runner appropriate for running background tasks that perform |
| 102 // file I/O. |
| 103 scoped_refptr<base::TaskRunner> CreateBackgroundTaskRunner() { |
| 104 if (g_task_runner_for_testing) |
| 105 return scoped_refptr<base::TaskRunner>(g_task_runner_for_testing); |
| 106 |
| 107 return base::CreateTaskRunnerWithTraits( |
| 108 {base::MayBlock(), base::TaskPriority::BACKGROUND, |
| 109 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); |
| 110 } |
| 111 |
96 } // namespace | 112 } // namespace |
97 | 113 |
98 // This structure stores all the information about the sources being monitored | 114 // This structure stores all the information about the sources being monitored |
99 // and their current reporting state. | 115 // and their current reporting state. |
100 struct FileMetricsProvider::SourceInfo { | 116 struct FileMetricsProvider::SourceInfo { |
101 SourceInfo(SourceType source_type, SourceAssociation source_association) | 117 SourceInfo(SourceType source_type, SourceAssociation source_association) |
102 : type(source_type), association(source_association) {} | 118 : type(source_type), association(source_association) {} |
103 ~SourceInfo() {} | 119 ~SourceInfo() {} |
104 | 120 |
105 // How to access this source (file/dir, atomic/active). | 121 // How to access this source (file/dir, atomic/active). |
(...skipping 20 matching lines...) Expand all Loading... |
126 bool read_complete = false; | 142 bool read_complete = false; |
127 | 143 |
128 // Once a file has been recognized as needing to be read, it is mapped | 144 // Once a file has been recognized as needing to be read, it is mapped |
129 // into memory and assigned to an |allocator| object. | 145 // into memory and assigned to an |allocator| object. |
130 std::unique_ptr<base::PersistentHistogramAllocator> allocator; | 146 std::unique_ptr<base::PersistentHistogramAllocator> allocator; |
131 | 147 |
132 private: | 148 private: |
133 DISALLOW_COPY_AND_ASSIGN(SourceInfo); | 149 DISALLOW_COPY_AND_ASSIGN(SourceInfo); |
134 }; | 150 }; |
135 | 151 |
136 FileMetricsProvider::FileMetricsProvider( | 152 FileMetricsProvider::FileMetricsProvider(PrefService* local_state) |
137 const scoped_refptr<base::TaskRunner>& task_runner, | 153 : task_runner_(CreateBackgroundTaskRunner()), |
138 PrefService* local_state) | |
139 : task_runner_(task_runner), | |
140 pref_service_(local_state), | 154 pref_service_(local_state), |
141 weak_factory_(this) { | 155 weak_factory_(this) { |
142 base::StatisticsRecorder::RegisterHistogramProvider( | 156 base::StatisticsRecorder::RegisterHistogramProvider( |
143 weak_factory_.GetWeakPtr()); | 157 weak_factory_.GetWeakPtr()); |
144 } | 158 } |
145 | 159 |
146 FileMetricsProvider::~FileMetricsProvider() {} | 160 FileMetricsProvider::~FileMetricsProvider() {} |
147 | 161 |
148 void FileMetricsProvider::RegisterSource(const base::FilePath& path, | 162 void FileMetricsProvider::RegisterSource(const base::FilePath& path, |
149 SourceType type, | 163 SourceType type, |
150 SourceAssociation source_association, | 164 SourceAssociation source_association, |
151 const base::StringPiece prefs_key) { | 165 const base::StringPiece prefs_key) { |
152 DCHECK(thread_checker_.CalledOnValidThread()); | 166 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
153 | 167 |
154 // Ensure that kSourceOptions has been filled for this type. | 168 // Ensure that kSourceOptions has been filled for this type. |
155 DCHECK_GT(arraysize(kSourceOptions), static_cast<size_t>(type)); | 169 DCHECK_GT(arraysize(kSourceOptions), static_cast<size_t>(type)); |
156 | 170 |
157 std::unique_ptr<SourceInfo> source(new SourceInfo(type, source_association)); | 171 std::unique_ptr<SourceInfo> source(new SourceInfo(type, source_association)); |
158 source->prefs_key = prefs_key.as_string(); | 172 source->prefs_key = prefs_key.as_string(); |
159 | 173 |
160 switch (source->type) { | 174 switch (source->type) { |
161 case SOURCE_HISTOGRAMS_ACTIVE_FILE: | 175 case SOURCE_HISTOGRAMS_ACTIVE_FILE: |
162 DCHECK(prefs_key.empty()); | 176 DCHECK(prefs_key.empty()); |
(...skipping 28 matching lines...) Expand all Loading... |
191 } | 205 } |
192 | 206 |
193 // static | 207 // static |
194 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs, | 208 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs, |
195 const base::StringPiece prefs_key) { | 209 const base::StringPiece prefs_key) { |
196 prefs->RegisterInt64Pref(metrics::prefs::kMetricsLastSeenPrefix + | 210 prefs->RegisterInt64Pref(metrics::prefs::kMetricsLastSeenPrefix + |
197 prefs_key.as_string(), 0); | 211 prefs_key.as_string(), 0); |
198 } | 212 } |
199 | 213 |
200 // static | 214 // static |
| 215 void FileMetricsProvider::SetTaskRunnerForTesting( |
| 216 const scoped_refptr<base::TaskRunner>& task_runner) { |
| 217 DCHECK(!g_task_runner_for_testing); |
| 218 g_task_runner_for_testing = task_runner.get(); |
| 219 } |
| 220 |
| 221 // static |
201 bool FileMetricsProvider::LocateNextFileInDirectory(SourceInfo* source) { | 222 bool FileMetricsProvider::LocateNextFileInDirectory(SourceInfo* source) { |
202 DCHECK_EQ(SOURCE_HISTOGRAMS_ATOMIC_DIR, source->type); | 223 DCHECK_EQ(SOURCE_HISTOGRAMS_ATOMIC_DIR, source->type); |
203 DCHECK(!source->directory.empty()); | 224 DCHECK(!source->directory.empty()); |
204 | 225 |
205 // Open the directory and find all the files, remembering the oldest that | 226 // Open the directory and find all the files, remembering the oldest that |
206 // has not been read. They can be removed and/or ignored if they're older | 227 // has not been read. They can be removed and/or ignored if they're older |
207 // than the last-check time. | 228 // than the last-check time. |
208 base::Time oldest_file_time = base::Time::Now(); | 229 base::Time oldest_file_time = base::Time::Now(); |
209 base::FilePath oldest_file_path; | 230 base::FilePath oldest_file_path; |
210 base::FilePath file_path; | 231 base::FilePath file_path; |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 snapshot_manager->PrepareFinalDelta(histogram.get()); | 452 snapshot_manager->PrepareFinalDelta(histogram.get()); |
432 ++histogram_count; | 453 ++histogram_count; |
433 } | 454 } |
434 | 455 |
435 source->read_complete = true; | 456 source->read_complete = true; |
436 DVLOG(1) << "Reported " << histogram_count << " histograms from " | 457 DVLOG(1) << "Reported " << histogram_count << " histograms from " |
437 << source->path.value(); | 458 << source->path.value(); |
438 } | 459 } |
439 | 460 |
440 void FileMetricsProvider::ScheduleSourcesCheck() { | 461 void FileMetricsProvider::ScheduleSourcesCheck() { |
441 DCHECK(thread_checker_.CalledOnValidThread()); | 462 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
442 if (sources_to_check_.empty()) | 463 if (sources_to_check_.empty()) |
443 return; | 464 return; |
444 | 465 |
445 // Create an independent list of sources for checking. This will be Owned() | 466 // Create an independent list of sources for checking. This will be Owned() |
446 // by the reply call given to the task-runner, to be deleted when that call | 467 // by the reply call given to the task-runner, to be deleted when that call |
447 // has returned. It is also passed Unretained() to the task itself, safe | 468 // has returned. It is also passed Unretained() to the task itself, safe |
448 // because that must complete before the reply runs. | 469 // because that must complete before the reply runs. |
449 SourceInfoList* check_list = new SourceInfoList(); | 470 SourceInfoList* check_list = new SourceInfoList(); |
450 std::swap(sources_to_check_, *check_list); | 471 std::swap(sources_to_check_, *check_list); |
451 task_runner_->PostTaskAndReply( | 472 task_runner_->PostTaskAndReply( |
452 FROM_HERE, | 473 FROM_HERE, |
453 base::Bind(&FileMetricsProvider::CheckAndMergeMetricSourcesOnTaskRunner, | 474 base::Bind(&FileMetricsProvider::CheckAndMergeMetricSourcesOnTaskRunner, |
454 base::Unretained(check_list)), | 475 base::Unretained(check_list)), |
455 base::Bind(&FileMetricsProvider::RecordSourcesChecked, | 476 base::Bind(&FileMetricsProvider::RecordSourcesChecked, |
456 weak_factory_.GetWeakPtr(), base::Owned(check_list))); | 477 weak_factory_.GetWeakPtr(), base::Owned(check_list))); |
457 } | 478 } |
458 | 479 |
459 void FileMetricsProvider::RecordSourcesChecked(SourceInfoList* checked) { | 480 void FileMetricsProvider::RecordSourcesChecked(SourceInfoList* checked) { |
460 DCHECK(thread_checker_.CalledOnValidThread()); | 481 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
461 | 482 |
462 // Sources that still have an allocator at this point are read/write "active" | 483 // Sources that still have an allocator at this point are read/write "active" |
463 // files that may need their contents merged on-demand. If there is no | 484 // files that may need their contents merged on-demand. If there is no |
464 // allocator (not a read/write file) but a read was done on the task-runner, | 485 // allocator (not a read/write file) but a read was done on the task-runner, |
465 // try again immediately to see if more is available (in a directory of | 486 // try again immediately to see if more is available (in a directory of |
466 // files). Otherwise, remember the source for checking again at a later time. | 487 // files). Otherwise, remember the source for checking again at a later time. |
467 bool did_read = false; | 488 bool did_read = false; |
468 for (auto iter = checked->begin(); iter != checked->end();) { | 489 for (auto iter = checked->begin(); iter != checked->end();) { |
469 auto temp = iter++; | 490 auto temp = iter++; |
470 SourceInfo* source = temp->get(); | 491 SourceInfo* source = temp->get(); |
(...skipping 20 matching lines...) Expand all Loading... |
491 // is possible. | 512 // is possible. |
492 if (did_read) | 513 if (did_read) |
493 ScheduleSourcesCheck(); | 514 ScheduleSourcesCheck(); |
494 } | 515 } |
495 | 516 |
496 void FileMetricsProvider::DeleteFileAsync(const base::FilePath& path) { | 517 void FileMetricsProvider::DeleteFileAsync(const base::FilePath& path) { |
497 task_runner_->PostTask(FROM_HERE, base::Bind(DeleteFileWhenPossible, path)); | 518 task_runner_->PostTask(FROM_HERE, base::Bind(DeleteFileWhenPossible, path)); |
498 } | 519 } |
499 | 520 |
500 void FileMetricsProvider::RecordSourceAsRead(SourceInfo* source) { | 521 void FileMetricsProvider::RecordSourceAsRead(SourceInfo* source) { |
501 DCHECK(thread_checker_.CalledOnValidThread()); | 522 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
502 | 523 |
503 // Persistently record the "last seen" timestamp of the source file to | 524 // Persistently record the "last seen" timestamp of the source file to |
504 // ensure that the file is never read again unless it is modified again. | 525 // ensure that the file is never read again unless it is modified again. |
505 if (pref_service_ && !source->prefs_key.empty()) { | 526 if (pref_service_ && !source->prefs_key.empty()) { |
506 pref_service_->SetInt64( | 527 pref_service_->SetInt64( |
507 metrics::prefs::kMetricsLastSeenPrefix + source->prefs_key, | 528 metrics::prefs::kMetricsLastSeenPrefix + source->prefs_key, |
508 source->last_seen.ToInternalValue()); | 529 source->last_seen.ToInternalValue()); |
509 } | 530 } |
510 } | 531 } |
511 | 532 |
512 void FileMetricsProvider::OnDidCreateMetricsLog() { | 533 void FileMetricsProvider::OnDidCreateMetricsLog() { |
513 DCHECK(thread_checker_.CalledOnValidThread()); | 534 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
514 | 535 |
515 // Schedule a check to see if there are new metrics to load. If so, they | 536 // Schedule a check to see if there are new metrics to load. If so, they |
516 // will be reported during the next collection run after this one. The | 537 // will be reported during the next collection run after this one. The |
517 // check is run off of the worker-pool so as to not cause delays on the | 538 // check is run off of the worker-pool so as to not cause delays on the |
518 // main UI thread (which is currently where metric collection is done). | 539 // main UI thread (which is currently where metric collection is done). |
519 ScheduleSourcesCheck(); | 540 ScheduleSourcesCheck(); |
520 | 541 |
521 // Clear any data for initial metrics since they're always reported | 542 // Clear any data for initial metrics since they're always reported |
522 // before the first call to this method. It couldn't be released after | 543 // before the first call to this method. It couldn't be released after |
523 // being reported in RecordInitialHistogramSnapshots because the data | 544 // being reported in RecordInitialHistogramSnapshots because the data |
524 // will continue to be used by the caller after that method returns. Once | 545 // will continue to be used by the caller after that method returns. Once |
525 // here, though, all actions to be done on the data have been completed. | 546 // here, though, all actions to be done on the data have been completed. |
526 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_) | 547 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_) |
527 DeleteFileAsync(source->path); | 548 DeleteFileAsync(source->path); |
528 sources_for_previous_run_.clear(); | 549 sources_for_previous_run_.clear(); |
529 } | 550 } |
530 | 551 |
531 bool FileMetricsProvider::ProvideIndependentMetrics( | 552 bool FileMetricsProvider::ProvideIndependentMetrics( |
532 SystemProfileProto* system_profile_proto, | 553 SystemProfileProto* system_profile_proto, |
533 base::HistogramSnapshotManager* snapshot_manager) { | 554 base::HistogramSnapshotManager* snapshot_manager) { |
534 DCHECK(thread_checker_.CalledOnValidThread()); | 555 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
535 | 556 |
536 while (!sources_with_profile_.empty()) { | 557 while (!sources_with_profile_.empty()) { |
537 SourceInfo* source = sources_with_profile_.begin()->get(); | 558 SourceInfo* source = sources_with_profile_.begin()->get(); |
538 DCHECK(source->allocator); | 559 DCHECK(source->allocator); |
539 | 560 |
540 bool success = false; | 561 bool success = false; |
541 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT); | 562 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT); |
542 if (PersistentSystemProfile::GetSystemProfile( | 563 if (PersistentSystemProfile::GetSystemProfile( |
543 *source->allocator->memory_allocator(), system_profile_proto)) { | 564 *source->allocator->memory_allocator(), system_profile_proto)) { |
544 RecordHistogramSnapshotsFromSource(snapshot_manager, source); | 565 RecordHistogramSnapshotsFromSource(snapshot_manager, source); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 ScheduleSourcesCheck(); | 598 ScheduleSourcesCheck(); |
578 | 599 |
579 if (success) | 600 if (success) |
580 return true; | 601 return true; |
581 } | 602 } |
582 | 603 |
583 return false; | 604 return false; |
584 } | 605 } |
585 | 606 |
586 bool FileMetricsProvider::HasInitialStabilityMetrics() { | 607 bool FileMetricsProvider::HasInitialStabilityMetrics() { |
587 DCHECK(thread_checker_.CalledOnValidThread()); | 608 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
588 | 609 |
589 // Measure the total time spent checking all sources as well as the time | 610 // Measure the total time spent checking all sources as well as the time |
590 // per individual file. This method is called during startup and thus blocks | 611 // per individual file. This method is called during startup and thus blocks |
591 // the initial showing of the browser window so it's important to know the | 612 // the initial showing of the browser window so it's important to know the |
592 // total delay. | 613 // total delay. |
593 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.InitialCheckTime.Total"); | 614 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.InitialCheckTime.Total"); |
594 | 615 |
595 // Check all sources for previous run to see if they need to be read. | 616 // Check all sources for previous run to see if they need to be read. |
596 for (auto iter = sources_for_previous_run_.begin(); | 617 for (auto iter = sources_for_previous_run_.begin(); |
597 iter != sources_for_previous_run_.end();) { | 618 iter != sources_for_previous_run_.end();) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
633 sources_for_previous_run_, temp); | 654 sources_for_previous_run_, temp); |
634 } | 655 } |
635 } | 656 } |
636 } | 657 } |
637 | 658 |
638 return !sources_for_previous_run_.empty(); | 659 return !sources_for_previous_run_.empty(); |
639 } | 660 } |
640 | 661 |
641 void FileMetricsProvider::RecordInitialHistogramSnapshots( | 662 void FileMetricsProvider::RecordInitialHistogramSnapshots( |
642 base::HistogramSnapshotManager* snapshot_manager) { | 663 base::HistogramSnapshotManager* snapshot_manager) { |
643 DCHECK(thread_checker_.CalledOnValidThread()); | 664 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
644 | 665 |
645 // Measure the total time spent processing all sources as well as the time | 666 // Measure the total time spent processing all sources as well as the time |
646 // per individual file. This method is called during startup and thus blocks | 667 // per individual file. This method is called during startup and thus blocks |
647 // the initial showing of the browser window so it's important to know the | 668 // the initial showing of the browser window so it's important to know the |
648 // total delay. | 669 // total delay. |
649 SCOPED_UMA_HISTOGRAM_TIMER( | 670 SCOPED_UMA_HISTOGRAM_TIMER( |
650 "UMA.FileMetricsProvider.InitialSnapshotTime.Total"); | 671 "UMA.FileMetricsProvider.InitialSnapshotTime.Total"); |
651 | 672 |
652 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_) { | 673 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_) { |
653 SCOPED_UMA_HISTOGRAM_TIMER( | 674 SCOPED_UMA_HISTOGRAM_TIMER( |
654 "UMA.FileMetricsProvider.InitialSnapshotTime.File"); | 675 "UMA.FileMetricsProvider.InitialSnapshotTime.File"); |
655 | 676 |
656 // The source needs to have an allocator attached to it in order to read | 677 // The source needs to have an allocator attached to it in order to read |
657 // histograms out of it. | 678 // histograms out of it. |
658 DCHECK(!source->read_complete); | 679 DCHECK(!source->read_complete); |
659 DCHECK(source->allocator); | 680 DCHECK(source->allocator); |
660 | 681 |
661 // Dump all histograms contained within the source to the snapshot-manager. | 682 // Dump all histograms contained within the source to the snapshot-manager. |
662 RecordHistogramSnapshotsFromSource(snapshot_manager, source.get()); | 683 RecordHistogramSnapshotsFromSource(snapshot_manager, source.get()); |
663 | 684 |
664 // Update the last-seen time so it isn't read again unless it changes. | 685 // Update the last-seen time so it isn't read again unless it changes. |
665 RecordSourceAsRead(source.get()); | 686 RecordSourceAsRead(source.get()); |
666 } | 687 } |
667 } | 688 } |
668 | 689 |
669 void FileMetricsProvider::MergeHistogramDeltas() { | 690 void FileMetricsProvider::MergeHistogramDeltas() { |
670 DCHECK(thread_checker_.CalledOnValidThread()); | 691 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
671 | 692 |
672 // Measure the total time spent processing all sources as well as the time | 693 // Measure the total time spent processing all sources as well as the time |
673 // per individual file. This method is called on the UI thread so it's | 694 // per individual file. This method is called on the UI thread so it's |
674 // important to know how much total "jank" may be introduced. | 695 // important to know how much total "jank" may be introduced. |
675 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.Total"); | 696 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.Total"); |
676 | 697 |
677 for (std::unique_ptr<SourceInfo>& source : sources_mapped_) { | 698 for (std::unique_ptr<SourceInfo>& source : sources_mapped_) { |
678 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.File"); | 699 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.File"); |
679 MergeHistogramDeltasFromSource(source.get()); | 700 MergeHistogramDeltasFromSource(source.get()); |
680 } | 701 } |
681 } | 702 } |
682 | 703 |
683 } // namespace metrics | 704 } // namespace metrics |
OLD | NEW |