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

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

Issue 2965753002: [Cleanup] Migrate the FileMetricsProvider to use the Task Scheduler. (Closed)
Patch Set: Created 3 years, 5 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/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
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::CONTINUE_ON_SHUTDOWN});
bcwhite 2017/07/04 14:50:31 I don't think there's anything in here that needs
Ilya Sherman 2017/07/05 18:15:56 Done.
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
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
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 g_task_runner_for_testing = task_runner.get();
bcwhite 2017/07/04 14:50:31 Delete the existing one if set.
Ilya Sherman 2017/07/05 18:15:56 There's no ownership, so it doesn't make sense to
bcwhite 2017/07/05 18:31:51 Acknowledged.
218 }
219
220 // static
201 bool FileMetricsProvider::LocateNextFileInDirectory(SourceInfo* source) { 221 bool FileMetricsProvider::LocateNextFileInDirectory(SourceInfo* source) {
202 DCHECK_EQ(SOURCE_HISTOGRAMS_ATOMIC_DIR, source->type); 222 DCHECK_EQ(SOURCE_HISTOGRAMS_ATOMIC_DIR, source->type);
203 DCHECK(!source->directory.empty()); 223 DCHECK(!source->directory.empty());
204 224
205 // Open the directory and find all the files, remembering the oldest that 225 // 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 226 // has not been read. They can be removed and/or ignored if they're older
207 // than the last-check time. 227 // than the last-check time.
208 base::Time oldest_file_time = base::Time::Now(); 228 base::Time oldest_file_time = base::Time::Now();
209 base::FilePath oldest_file_path; 229 base::FilePath oldest_file_path;
210 base::FilePath file_path; 230 base::FilePath file_path;
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 snapshot_manager->PrepareFinalDelta(histogram.get()); 451 snapshot_manager->PrepareFinalDelta(histogram.get());
432 ++histogram_count; 452 ++histogram_count;
433 } 453 }
434 454
435 source->read_complete = true; 455 source->read_complete = true;
436 DVLOG(1) << "Reported " << histogram_count << " histograms from " 456 DVLOG(1) << "Reported " << histogram_count << " histograms from "
437 << source->path.value(); 457 << source->path.value();
438 } 458 }
439 459
440 void FileMetricsProvider::ScheduleSourcesCheck() { 460 void FileMetricsProvider::ScheduleSourcesCheck() {
441 DCHECK(thread_checker_.CalledOnValidThread()); 461 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
442 if (sources_to_check_.empty()) 462 if (sources_to_check_.empty())
443 return; 463 return;
444 464
445 // Create an independent list of sources for checking. This will be Owned() 465 // 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 466 // 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 467 // has returned. It is also passed Unretained() to the task itself, safe
448 // because that must complete before the reply runs. 468 // because that must complete before the reply runs.
449 SourceInfoList* check_list = new SourceInfoList(); 469 SourceInfoList* check_list = new SourceInfoList();
450 std::swap(sources_to_check_, *check_list); 470 std::swap(sources_to_check_, *check_list);
451 task_runner_->PostTaskAndReply( 471 task_runner_->PostTaskAndReply(
452 FROM_HERE, 472 FROM_HERE,
453 base::Bind(&FileMetricsProvider::CheckAndMergeMetricSourcesOnTaskRunner, 473 base::Bind(&FileMetricsProvider::CheckAndMergeMetricSourcesOnTaskRunner,
454 base::Unretained(check_list)), 474 base::Unretained(check_list)),
455 base::Bind(&FileMetricsProvider::RecordSourcesChecked, 475 base::Bind(&FileMetricsProvider::RecordSourcesChecked,
456 weak_factory_.GetWeakPtr(), base::Owned(check_list))); 476 weak_factory_.GetWeakPtr(), base::Owned(check_list)));
457 } 477 }
458 478
459 void FileMetricsProvider::RecordSourcesChecked(SourceInfoList* checked) { 479 void FileMetricsProvider::RecordSourcesChecked(SourceInfoList* checked) {
460 DCHECK(thread_checker_.CalledOnValidThread()); 480 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
461 481
462 // Sources that still have an allocator at this point are read/write "active" 482 // 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 483 // 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, 484 // 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 485 // 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. 486 // files). Otherwise, remember the source for checking again at a later time.
467 bool did_read = false; 487 bool did_read = false;
468 for (auto iter = checked->begin(); iter != checked->end();) { 488 for (auto iter = checked->begin(); iter != checked->end();) {
469 auto temp = iter++; 489 auto temp = iter++;
470 SourceInfo* source = temp->get(); 490 SourceInfo* source = temp->get();
(...skipping 20 matching lines...) Expand all
491 // is possible. 511 // is possible.
492 if (did_read) 512 if (did_read)
493 ScheduleSourcesCheck(); 513 ScheduleSourcesCheck();
494 } 514 }
495 515
496 void FileMetricsProvider::DeleteFileAsync(const base::FilePath& path) { 516 void FileMetricsProvider::DeleteFileAsync(const base::FilePath& path) {
497 task_runner_->PostTask(FROM_HERE, base::Bind(DeleteFileWhenPossible, path)); 517 task_runner_->PostTask(FROM_HERE, base::Bind(DeleteFileWhenPossible, path));
498 } 518 }
499 519
500 void FileMetricsProvider::RecordSourceAsRead(SourceInfo* source) { 520 void FileMetricsProvider::RecordSourceAsRead(SourceInfo* source) {
501 DCHECK(thread_checker_.CalledOnValidThread()); 521 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
502 522
503 // Persistently record the "last seen" timestamp of the source file to 523 // 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. 524 // ensure that the file is never read again unless it is modified again.
505 if (pref_service_ && !source->prefs_key.empty()) { 525 if (pref_service_ && !source->prefs_key.empty()) {
506 pref_service_->SetInt64( 526 pref_service_->SetInt64(
507 metrics::prefs::kMetricsLastSeenPrefix + source->prefs_key, 527 metrics::prefs::kMetricsLastSeenPrefix + source->prefs_key,
508 source->last_seen.ToInternalValue()); 528 source->last_seen.ToInternalValue());
509 } 529 }
510 } 530 }
511 531
512 void FileMetricsProvider::OnDidCreateMetricsLog() { 532 void FileMetricsProvider::OnDidCreateMetricsLog() {
513 DCHECK(thread_checker_.CalledOnValidThread()); 533 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
514 534
515 // Schedule a check to see if there are new metrics to load. If so, they 535 // 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 536 // 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 537 // 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). 538 // main UI thread (which is currently where metric collection is done).
519 ScheduleSourcesCheck(); 539 ScheduleSourcesCheck();
520 540
521 // Clear any data for initial metrics since they're always reported 541 // 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 542 // before the first call to this method. It couldn't be released after
523 // being reported in RecordInitialHistogramSnapshots because the data 543 // being reported in RecordInitialHistogramSnapshots because the data
524 // will continue to be used by the caller after that method returns. Once 544 // 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. 545 // 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_) 546 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_)
527 DeleteFileAsync(source->path); 547 DeleteFileAsync(source->path);
528 sources_for_previous_run_.clear(); 548 sources_for_previous_run_.clear();
529 } 549 }
530 550
531 bool FileMetricsProvider::ProvideIndependentMetrics( 551 bool FileMetricsProvider::ProvideIndependentMetrics(
532 SystemProfileProto* system_profile_proto, 552 SystemProfileProto* system_profile_proto,
533 base::HistogramSnapshotManager* snapshot_manager) { 553 base::HistogramSnapshotManager* snapshot_manager) {
534 DCHECK(thread_checker_.CalledOnValidThread()); 554 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
535 555
536 while (!sources_with_profile_.empty()) { 556 while (!sources_with_profile_.empty()) {
537 SourceInfo* source = sources_with_profile_.begin()->get(); 557 SourceInfo* source = sources_with_profile_.begin()->get();
538 DCHECK(source->allocator); 558 DCHECK(source->allocator);
539 559
540 bool success = false; 560 bool success = false;
541 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT); 561 RecordEmbeddedProfileResult(EMBEDDED_PROFILE_ATTEMPT);
542 if (PersistentSystemProfile::GetSystemProfile( 562 if (PersistentSystemProfile::GetSystemProfile(
543 *source->allocator->memory_allocator(), system_profile_proto)) { 563 *source->allocator->memory_allocator(), system_profile_proto)) {
544 RecordHistogramSnapshotsFromSource(snapshot_manager, source); 564 RecordHistogramSnapshotsFromSource(snapshot_manager, source);
(...skipping 10 matching lines...) Expand all
555 sources_to_check_.splice(sources_to_check_.end(), sources_with_profile_, 575 sources_to_check_.splice(sources_to_check_.end(), sources_with_profile_,
556 sources_with_profile_.begin()); 576 sources_with_profile_.begin());
557 if (success) 577 if (success)
558 return true; 578 return true;
559 } 579 }
560 580
561 return false; 581 return false;
562 } 582 }
563 583
564 bool FileMetricsProvider::HasInitialStabilityMetrics() { 584 bool FileMetricsProvider::HasInitialStabilityMetrics() {
565 DCHECK(thread_checker_.CalledOnValidThread()); 585 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
566 586
567 // Measure the total time spent checking all sources as well as the time 587 // Measure the total time spent checking all sources as well as the time
568 // per individual file. This method is called during startup and thus blocks 588 // per individual file. This method is called during startup and thus blocks
569 // the initial showing of the browser window so it's important to know the 589 // the initial showing of the browser window so it's important to know the
570 // total delay. 590 // total delay.
571 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.InitialCheckTime.Total"); 591 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.InitialCheckTime.Total");
572 592
573 // Check all sources for previous run to see if they need to be read. 593 // Check all sources for previous run to see if they need to be read.
574 for (auto iter = sources_for_previous_run_.begin(); 594 for (auto iter = sources_for_previous_run_.begin();
575 iter != sources_for_previous_run_.end();) { 595 iter != sources_for_previous_run_.end();) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 sources_for_previous_run_, temp); 631 sources_for_previous_run_, temp);
612 } 632 }
613 } 633 }
614 } 634 }
615 635
616 return !sources_for_previous_run_.empty(); 636 return !sources_for_previous_run_.empty();
617 } 637 }
618 638
619 void FileMetricsProvider::RecordInitialHistogramSnapshots( 639 void FileMetricsProvider::RecordInitialHistogramSnapshots(
620 base::HistogramSnapshotManager* snapshot_manager) { 640 base::HistogramSnapshotManager* snapshot_manager) {
621 DCHECK(thread_checker_.CalledOnValidThread()); 641 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
622 642
623 // Measure the total time spent processing all sources as well as the time 643 // Measure the total time spent processing all sources as well as the time
624 // per individual file. This method is called during startup and thus blocks 644 // per individual file. This method is called during startup and thus blocks
625 // the initial showing of the browser window so it's important to know the 645 // the initial showing of the browser window so it's important to know the
626 // total delay. 646 // total delay.
627 SCOPED_UMA_HISTOGRAM_TIMER( 647 SCOPED_UMA_HISTOGRAM_TIMER(
628 "UMA.FileMetricsProvider.InitialSnapshotTime.Total"); 648 "UMA.FileMetricsProvider.InitialSnapshotTime.Total");
629 649
630 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_) { 650 for (const std::unique_ptr<SourceInfo>& source : sources_for_previous_run_) {
631 SCOPED_UMA_HISTOGRAM_TIMER( 651 SCOPED_UMA_HISTOGRAM_TIMER(
632 "UMA.FileMetricsProvider.InitialSnapshotTime.File"); 652 "UMA.FileMetricsProvider.InitialSnapshotTime.File");
633 653
634 // The source needs to have an allocator attached to it in order to read 654 // The source needs to have an allocator attached to it in order to read
635 // histograms out of it. 655 // histograms out of it.
636 DCHECK(!source->read_complete); 656 DCHECK(!source->read_complete);
637 DCHECK(source->allocator); 657 DCHECK(source->allocator);
638 658
639 // Dump all histograms contained within the source to the snapshot-manager. 659 // Dump all histograms contained within the source to the snapshot-manager.
640 RecordHistogramSnapshotsFromSource(snapshot_manager, source.get()); 660 RecordHistogramSnapshotsFromSource(snapshot_manager, source.get());
641 661
642 // Update the last-seen time so it isn't read again unless it changes. 662 // Update the last-seen time so it isn't read again unless it changes.
643 RecordSourceAsRead(source.get()); 663 RecordSourceAsRead(source.get());
644 } 664 }
645 } 665 }
646 666
647 void FileMetricsProvider::MergeHistogramDeltas() { 667 void FileMetricsProvider::MergeHistogramDeltas() {
648 DCHECK(thread_checker_.CalledOnValidThread()); 668 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
649 669
650 // Measure the total time spent processing all sources as well as the time 670 // Measure the total time spent processing all sources as well as the time
651 // per individual file. This method is called on the UI thread so it's 671 // per individual file. This method is called on the UI thread so it's
652 // important to know how much total "jank" may be introduced. 672 // important to know how much total "jank" may be introduced.
653 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.Total"); 673 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.Total");
654 674
655 for (std::unique_ptr<SourceInfo>& source : sources_mapped_) { 675 for (std::unique_ptr<SourceInfo>& source : sources_mapped_) {
656 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.File"); 676 SCOPED_UMA_HISTOGRAM_TIMER("UMA.FileMetricsProvider.SnapshotTime.File");
657 MergeHistogramDeltasFromSource(source.get()); 677 MergeHistogramDeltasFromSource(source.get());
658 } 678 }
659 } 679 }
660 680
661 } // namespace metrics 681 } // 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