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 "chrome/browser/metrics/subprocess_metrics_provider.h" | 5 #include "chrome/browser/metrics/subprocess_metrics_provider.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/metrics/histogram_base.h" | 9 #include "base/metrics/histogram_base.h" |
10 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 // Map is "MapOwnPointer" so transfer ownership to it. | 32 // Map is "MapOwnPointer" so transfer ownership to it. |
33 allocators_by_id_.AddWithID(allocator.release(), id); | 33 allocators_by_id_.AddWithID(allocator.release(), id); |
34 } | 34 } |
35 | 35 |
36 void SubprocessMetricsProvider::DeregisterSubprocessAllocator(int id) { | 36 void SubprocessMetricsProvider::DeregisterSubprocessAllocator(int id) { |
37 DCHECK(thread_checker_.CalledOnValidThread()); | 37 DCHECK(thread_checker_.CalledOnValidThread()); |
38 | 38 |
39 if (!allocators_by_id_.Lookup(id)) | 39 if (!allocators_by_id_.Lookup(id)) |
40 return; | 40 return; |
41 | 41 |
42 // Extract the matching allocator from the list of active ones. | 42 // Extract the matching allocator from the list of active ones. It will |
| 43 // be automatically released when this method exits. |
43 std::unique_ptr<base::PersistentHistogramAllocator> allocator( | 44 std::unique_ptr<base::PersistentHistogramAllocator> allocator( |
44 allocators_by_id_.Replace(id, nullptr)); | 45 allocators_by_id_.Replace(id, nullptr)); |
45 allocators_by_id_.Remove(id); | 46 allocators_by_id_.Remove(id); |
46 DCHECK(allocator); | 47 DCHECK(allocator); |
47 | 48 |
48 // If metrics recording is enabled, transfer the allocator to the "release" | 49 // Merge the last deltas from the allocator before it is released. |
49 // list. The allocator will continue to live (and keep the associated shared | 50 MergeHistogramDeltasFromAllocator(id, allocator.get()); |
50 // memory alive) until the next upload after which it will be released. | |
51 // Otherwise, the allocator and its memory will be released when the | |
52 // unique_ptr goes out of scope at the end of this method. | |
53 if (metrics_recording_enabled_) | |
54 allocators_for_exited_processes_.push_back(std::move(allocator)); | |
55 } | 51 } |
56 | 52 |
57 void SubprocessMetricsProvider::OnDidCreateMetricsLog() { | 53 void SubprocessMetricsProvider::MergeHistogramDeltasFromAllocator( |
58 DCHECK(thread_checker_.CalledOnValidThread()); | |
59 | |
60 // The previous reporting cycle is complete and the data used to create it | |
61 // will never be needed again. Allocators for exited processes can finally | |
62 // be released. | |
63 allocators_to_release_.clear(); | |
64 } | |
65 | |
66 void SubprocessMetricsProvider::OnRecordingEnabled() { | |
67 DCHECK(thread_checker_.CalledOnValidThread()); | |
68 | |
69 metrics_recording_enabled_ = true; | |
70 } | |
71 | |
72 void SubprocessMetricsProvider::OnRecordingDisabled() { | |
73 DCHECK(thread_checker_.CalledOnValidThread()); | |
74 | |
75 metrics_recording_enabled_ = false; | |
76 allocators_for_exited_processes_.clear(); | |
77 allocators_to_release_.clear(); | |
78 } | |
79 | |
80 void SubprocessMetricsProvider::RecordHistogramSnapshotsFromAllocator( | |
81 base::HistogramSnapshotManager* snapshot_manager, | |
82 int id, | 54 int id, |
83 base::PersistentHistogramAllocator* allocator) { | 55 base::PersistentHistogramAllocator* allocator) { |
84 DCHECK(allocator); | 56 DCHECK(allocator); |
85 | 57 |
86 int histogram_count = 0; | 58 int histogram_count = 0; |
87 base::PersistentHistogramAllocator::Iterator hist_iter(allocator); | 59 base::PersistentHistogramAllocator::Iterator hist_iter(allocator); |
88 while (true) { | 60 while (true) { |
89 std::unique_ptr<base::HistogramBase> histogram = hist_iter.GetNext(); | 61 std::unique_ptr<base::HistogramBase> histogram = hist_iter.GetNext(); |
90 if (!histogram) | 62 if (!histogram) |
91 break; | 63 break; |
92 snapshot_manager->PrepareDeltaTakingOwnership(std::move(histogram)); | 64 allocator->MergeHistogramToStatisticsRecorder(histogram.get()); |
93 ++histogram_count; | 65 ++histogram_count; |
94 } | 66 } |
95 | 67 |
96 DVLOG(1) << "Reported " << histogram_count << " histograms from subprocess #" | 68 DVLOG(1) << "Reported " << histogram_count << " histograms from subprocess #" |
97 << id; | 69 << id; |
98 } | 70 } |
99 | 71 |
100 void SubprocessMetricsProvider::RecordHistogramSnapshots( | 72 void SubprocessMetricsProvider::MergeHistogramDeltas() { |
101 base::HistogramSnapshotManager* snapshot_manager) { | |
102 DCHECK(thread_checker_.CalledOnValidThread()); | 73 DCHECK(thread_checker_.CalledOnValidThread()); |
103 | 74 |
104 for (AllocatorByIdMap::iterator iter(&allocators_by_id_); !iter.IsAtEnd(); | 75 for (AllocatorByIdMap::iterator iter(&allocators_by_id_); !iter.IsAtEnd(); |
105 iter.Advance()) { | 76 iter.Advance()) { |
106 RecordHistogramSnapshotsFromAllocator( | 77 MergeHistogramDeltasFromAllocator(iter.GetCurrentKey(), |
107 snapshot_manager, iter.GetCurrentKey(), iter.GetCurrentValue()); | 78 iter.GetCurrentValue()); |
108 } | 79 } |
109 | 80 |
110 for (auto& allocator : allocators_for_exited_processes_) | |
111 RecordHistogramSnapshotsFromAllocator(snapshot_manager, 0, allocator.get()); | |
112 | |
113 UMA_HISTOGRAM_COUNTS_100( | 81 UMA_HISTOGRAM_COUNTS_100( |
114 "UMA.SubprocessMetricsProvider.SubprocessCount", | 82 "UMA.SubprocessMetricsProvider.SubprocessCount", |
115 allocators_by_id_.size() + allocators_for_exited_processes_.size()); | 83 allocators_by_id_.size()); |
116 | |
117 // Move allocators for exited processes (which just had final reporting done | |
118 // for them) to the queue for being released. The actual release is delayed | |
119 // until after reporting is complete so as to not destruct objects that may | |
120 // still be needed. | |
121 DCHECK(allocators_to_release_.empty()); | |
122 allocators_to_release_.swap(allocators_for_exited_processes_); | |
123 } | 84 } |
124 | 85 |
125 void SubprocessMetricsProvider::Observe( | 86 void SubprocessMetricsProvider::Observe( |
126 int type, | 87 int type, |
127 const content::NotificationSource& source, | 88 const content::NotificationSource& source, |
128 const content::NotificationDetails& details) { | 89 const content::NotificationDetails& details) { |
129 DCHECK(thread_checker_.CalledOnValidThread()); | 90 DCHECK(thread_checker_.CalledOnValidThread()); |
130 DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_CREATED, type); | 91 DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_CREATED, type); |
131 | 92 |
132 content::RenderProcessHost* host = | 93 content::RenderProcessHost* host = |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 content::RenderProcessHost* host) { | 128 content::RenderProcessHost* host) { |
168 DCHECK(thread_checker_.CalledOnValidThread()); | 129 DCHECK(thread_checker_.CalledOnValidThread()); |
169 | 130 |
170 // It's possible for a Renderer to terminate without RenderProcessExited | 131 // It's possible for a Renderer to terminate without RenderProcessExited |
171 // (above) being called so it's necessary to de-register also upon the | 132 // (above) being called so it's necessary to de-register also upon the |
172 // destruction of the host. If both get called, no harm is done. | 133 // destruction of the host. If both get called, no harm is done. |
173 | 134 |
174 DeregisterSubprocessAllocator(host->GetID()); | 135 DeregisterSubprocessAllocator(host->GetID()); |
175 scoped_observer_.Remove(host); | 136 scoped_observer_.Remove(host); |
176 } | 137 } |
OLD | NEW |