OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "services/resource_coordinator/memory/coordinator/coordinator_impl.h" | 5 #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
13 #include "base/threading/platform_thread.h" | 13 #include "base/threading/platform_thread.h" |
14 #include "base/trace_event/memory_dump_manager.h" | 14 #include "base/trace_event/memory_dump_manager.h" |
15 #include "base/trace_event/memory_dump_request_args.h" | 15 #include "base/trace_event/memory_dump_request_args.h" |
16 #include "services/resource_coordinator/public/cpp/memory/process_local_dump_man ager_impl.h" | 16 #include "services/resource_coordinator/public/cpp/memory/process_local_dump_man ager_impl.h" |
17 #include "services/resource_coordinator/public/interfaces/memory/constants.mojom .h" | 17 #include "services/resource_coordinator/public/interfaces/memory/constants.mojom .h" |
18 #include "services/resource_coordinator/public/interfaces/memory/memory_instrume ntation.mojom.h" | 18 #include "services/resource_coordinator/public/interfaces/memory/memory_instrume ntation.mojom.h" |
19 #include "services/service_manager/public/cpp/connector.h" | |
20 #include "services/service_manager/public/cpp/identity.h" | |
21 #include "services/service_manager/public/interfaces/constants.mojom.h" | |
22 #include "services/service_manager/public/interfaces/service_manager.mojom.h" | |
23 | |
24 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
25 #include "base/mac/mac_util.h" | |
26 #endif | |
19 | 27 |
20 namespace { | 28 namespace { |
21 | 29 |
22 memory_instrumentation::CoordinatorImpl* g_coordinator_impl; | 30 memory_instrumentation::CoordinatorImpl* g_coordinator_impl; |
23 | 31 |
32 uint32_t CalculatePrivateFootprintKb( | |
33 base::trace_event::MemoryDumpCallbackResult::OSMemDump& os_dump) { | |
34 #if defined(OS_LINUX) || defined(OS_ANDROID) | |
35 uint64_t rss_anon_bytes = os_dump.platform_private_footprint.rss_anon_bytes; | |
36 uint64_t vm_swap_bytes = os_dump.platform_private_footprint.vm_swap_bytes; | |
37 return (rss_anon_bytes + vm_swap_bytes) / 1024; | |
38 #elif defined(OS_MACOSX) | |
39 // TODO(erikchen): This calculation is close, but not fully accurate. It | |
40 // overcounts by anonymous shared memory. | |
41 if (base::mac::IsAtLeastOS10_12()) { | |
42 uint64_t phys_footprint_bytes = | |
43 os_dump.platform_private_footprint.phys_footprint_bytes; | |
44 return phys_footprint_bytes / 1024; | |
45 } else { | |
46 uint64_t internal_bytes = os_dump.platform_private_footprint.internal_bytes; | |
47 uint64_t compressed_bytes = | |
48 os_dump.platform_private_footprint.compressed_bytes; | |
49 return (internal_bytes + compressed_bytes) / 1024; | |
50 } | |
51 #endif | |
52 return 0; | |
dcheng
2017/05/13 20:22:37
I'm kind of surprised that there's no compiler war
erikchen
2017/05/14 04:49:16
Done.
| |
53 } | |
54 | |
24 } // namespace | 55 } // namespace |
25 | 56 |
26 namespace memory_instrumentation { | 57 namespace memory_instrumentation { |
27 | 58 |
28 // static | 59 // static |
29 CoordinatorImpl* CoordinatorImpl::GetInstance() { | 60 CoordinatorImpl* CoordinatorImpl::GetInstance() { |
30 return g_coordinator_impl; | 61 return g_coordinator_impl; |
31 } | 62 } |
32 | 63 |
33 CoordinatorImpl::CoordinatorImpl(bool initialize_memory_dump_manager) | 64 CoordinatorImpl::CoordinatorImpl(bool initialize_memory_dump_manager, |
65 service_manager::Connector* connector, | |
66 bool initialize_process_map) | |
34 : failed_memory_dump_count_(0), | 67 : failed_memory_dump_count_(0), |
35 initialize_memory_dump_manager_(initialize_memory_dump_manager) { | 68 initialize_memory_dump_manager_(initialize_memory_dump_manager), |
69 process_map_(nullptr) { | |
dcheng
2017/05/13 20:22:37
Nit: the default ctor does this, no need to explic
erikchen
2017/05/14 04:49:16
Done.
| |
36 if (initialize_memory_dump_manager) { | 70 if (initialize_memory_dump_manager) { |
37 // TODO(primiano): the current state where the coordinator also creates a | 71 // TODO(primiano): the current state where the coordinator also creates a |
38 // client (ProcessLocalDumpManagerImpl) is contra-intuitive. BrowserMainLoop | 72 // client (ProcessLocalDumpManagerImpl) is contra-intuitive. BrowserMainLoop |
39 // should be doing this. | 73 // should be doing this. |
40 ProcessLocalDumpManagerImpl::CreateInstance( | 74 ProcessLocalDumpManagerImpl::CreateInstance( |
41 ProcessLocalDumpManagerImpl::Config(this, mojom::ProcessType::BROWSER)); | 75 ProcessLocalDumpManagerImpl::Config(this, mojom::ProcessType::BROWSER)); |
42 base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id( | 76 base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id( |
43 mojom::kServiceTracingProcessId); | 77 mojom::kServiceTracingProcessId); |
44 } | 78 } |
79 if (initialize_process_map) | |
80 InitProcessMap(connector); | |
45 g_coordinator_impl = this; | 81 g_coordinator_impl = this; |
46 } | 82 } |
47 | 83 |
84 service_manager::Identity CoordinatorImpl::GetDispatchContext() const { | |
85 return bindings_.dispatch_context(); | |
86 } | |
87 | |
48 CoordinatorImpl::~CoordinatorImpl() { | 88 CoordinatorImpl::~CoordinatorImpl() { |
49 g_coordinator_impl = nullptr; | 89 g_coordinator_impl = nullptr; |
50 } | 90 } |
51 | 91 |
52 void CoordinatorImpl::BindCoordinatorRequest( | 92 void CoordinatorImpl::BindCoordinatorRequest( |
53 const service_manager::BindSourceInfo& source_info, | 93 const service_manager::BindSourceInfo& source_info, |
54 mojom::CoordinatorRequest request) { | 94 mojom::CoordinatorRequest request) { |
55 DCHECK(thread_checker_.CalledOnValidThread()); | 95 DCHECK(thread_checker_.CalledOnValidThread()); |
56 bindings_.AddBinding(this, std::move(request)); | 96 bindings_.AddBinding(this, std::move(request), source_info.identity); |
57 } | 97 } |
58 | 98 |
59 CoordinatorImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( | 99 CoordinatorImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( |
60 const base::trace_event::MemoryDumpRequestArgs args, | 100 const base::trace_event::MemoryDumpRequestArgs args, |
61 const RequestGlobalMemoryDumpCallback callback) | 101 const RequestGlobalMemoryDumpCallback callback) |
62 : args(args), callback(callback) {} | 102 : args(args), callback(callback) {} |
63 | 103 |
64 CoordinatorImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} | 104 CoordinatorImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} |
65 | 105 |
66 void CoordinatorImpl::RequestGlobalMemoryDump( | 106 void CoordinatorImpl::RequestGlobalMemoryDump( |
67 const base::trace_event::MemoryDumpRequestArgs& args, | 107 const base::trace_event::MemoryDumpRequestArgs& args, |
68 const RequestGlobalMemoryDumpCallback& callback) { | 108 const RequestGlobalMemoryDumpCallback& callback) { |
69 DCHECK(thread_checker_.CalledOnValidThread()); | 109 DCHECK(thread_checker_.CalledOnValidThread()); |
70 bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty(); | 110 bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty(); |
71 | 111 |
72 // If this is a periodic or peak memory dump request and there already is | 112 // If this is a periodic or peak memory dump request and there already is |
73 // another request in the queue with the same level of detail, there's no | 113 // another request in the queue with the same level of detail, there's no |
74 // point in enqueuing this request. | 114 // point in enqueuing this request. |
75 if (another_dump_already_in_progress && | 115 if (another_dump_already_in_progress && |
76 args.dump_type != | 116 args.dump_type != |
77 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED) { | 117 base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED && |
118 args.dump_type != base::trace_event::MemoryDumpType::SUMMARY_ONLY) { | |
78 for (const auto& request : queued_memory_dump_requests_) { | 119 for (const auto& request : queued_memory_dump_requests_) { |
79 if (request.args.level_of_detail == args.level_of_detail) { | 120 if (request.args.level_of_detail == args.level_of_detail) { |
80 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " (" | 121 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " (" |
81 << base::trace_event::MemoryDumpTypeToString(args.dump_type) | 122 << base::trace_event::MemoryDumpTypeToString(args.dump_type) |
82 << ") skipped because another dump request with the same " | 123 << ") skipped because another dump request with the same " |
83 "level of detail (" | 124 "level of detail (" |
84 << base::trace_event::MemoryDumpLevelOfDetailToString( | 125 << base::trace_event::MemoryDumpLevelOfDetailToString( |
85 args.level_of_detail) | 126 args.level_of_detail) |
86 << ") is already in the queue"; | 127 << ") is already in the queue"; |
87 callback.Run(args.dump_guid, false /* success */, | 128 callback.Run(args.dump_guid, false /* success */, |
(...skipping 12 matching lines...) Expand all Loading... | |
100 | 141 |
101 PerformNextQueuedGlobalMemoryDump(); | 142 PerformNextQueuedGlobalMemoryDump(); |
102 } | 143 } |
103 | 144 |
104 void CoordinatorImpl::RegisterProcessLocalDumpManager( | 145 void CoordinatorImpl::RegisterProcessLocalDumpManager( |
105 mojom::ProcessLocalDumpManagerPtr process_manager) { | 146 mojom::ProcessLocalDumpManagerPtr process_manager) { |
106 DCHECK(thread_checker_.CalledOnValidThread()); | 147 DCHECK(thread_checker_.CalledOnValidThread()); |
107 process_manager.set_connection_error_handler( | 148 process_manager.set_connection_error_handler( |
108 base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager, | 149 base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager, |
109 base::Unretained(this), process_manager.get())); | 150 base::Unretained(this), process_manager.get())); |
110 auto result = process_managers_.insert( | 151 auto result = process_managers_.insert(std::make_pair( |
dcheng
2017/05/13 20:22:37
Nit: consider using emplace() here to get rid of o
erikchen
2017/05/14 04:49:16
Done.
| |
111 std::make_pair<mojom::ProcessLocalDumpManager*, | 152 process_manager.get(), |
112 mojom::ProcessLocalDumpManagerPtr>( | 153 std::make_pair(std::move(process_manager), GetDispatchContext()))); |
113 process_manager.get(), std::move(process_manager))); | |
114 DCHECK(result.second); | 154 DCHECK(result.second); |
115 } | 155 } |
116 | 156 |
117 void CoordinatorImpl::UnregisterProcessLocalDumpManager( | 157 void CoordinatorImpl::UnregisterProcessLocalDumpManager( |
118 mojom::ProcessLocalDumpManager* process_manager) { | 158 mojom::ProcessLocalDumpManager* process_manager) { |
119 size_t num_deleted = process_managers_.erase(process_manager); | 159 size_t num_deleted = process_managers_.erase(process_manager); |
120 DCHECK(num_deleted == 1); | 160 DCHECK(num_deleted == 1); |
121 | 161 |
122 // Check if we are waiting for an ack from this process-local manager. | 162 // Check if we are waiting for an ack from this process-local manager. |
123 if (pending_process_managers_.find(process_manager) != | 163 if (pending_process_managers_.find(process_manager) != |
124 pending_process_managers_.end()) { | 164 pending_process_managers_.end()) { |
125 DCHECK(!queued_memory_dump_requests_.empty()); | 165 DCHECK(!queued_memory_dump_requests_.empty()); |
126 OnProcessMemoryDumpResponse( | 166 OnProcessMemoryDumpResponse( |
127 process_manager, queued_memory_dump_requests_.front().args.dump_guid, | 167 process_manager, queued_memory_dump_requests_.front().args.dump_guid, |
128 false /* success */, nullptr /* process_memory_dump */); | 168 false /* success */, nullptr /* process_memory_dump */); |
129 } | 169 } |
130 } | 170 } |
131 | 171 |
132 void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() { | 172 void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() { |
133 DCHECK(!queued_memory_dump_requests_.empty()); | 173 DCHECK(!queued_memory_dump_requests_.empty()); |
134 const base::trace_event::MemoryDumpRequestArgs& args = | 174 const base::trace_event::MemoryDumpRequestArgs& args = |
135 queued_memory_dump_requests_.front().args; | 175 queued_memory_dump_requests_.front().args; |
136 | 176 |
137 // No need to treat the service process different than other processes. The | 177 // No need to treat the service process different than other processes. The |
138 // service process will register itself as a ProcessLocalDumpManager and will | 178 // service process will register itself as a ProcessLocalDumpManager and |
139 // be treated like other process-local managers. | 179 // will be treated like other process-local managers. |
140 pending_process_managers_.clear(); | 180 pending_process_managers_.clear(); |
141 failed_memory_dump_count_ = 0; | 181 failed_memory_dump_count_ = 0; |
142 for (const auto& key_value : process_managers_) { | 182 for (const auto& key_value : process_managers_) { |
143 pending_process_managers_.insert(key_value.first); | 183 pending_process_managers_.insert(key_value.first); |
144 auto callback = base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse, | 184 auto callback = base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse, |
145 base::Unretained(this), key_value.first); | 185 base::Unretained(this), key_value.first); |
146 key_value.second->RequestProcessMemoryDump(args, callback); | 186 key_value.second.first->RequestProcessMemoryDump(args, callback); |
147 } | 187 } |
148 // Run the callback in case there are no process-local managers. | 188 // Run the callback in case there are no process-local managers. |
149 FinalizeGlobalMemoryDumpIfAllManagersReplied(); | 189 FinalizeGlobalMemoryDumpIfAllManagersReplied(); |
150 } | 190 } |
151 | 191 |
152 void CoordinatorImpl::OnProcessMemoryDumpResponse( | 192 void CoordinatorImpl::OnProcessMemoryDumpResponse( |
153 mojom::ProcessLocalDumpManager* process_manager, | 193 mojom::ProcessLocalDumpManager* process_manager, |
154 uint64_t dump_guid, | 194 uint64_t dump_guid, |
155 bool success, | 195 bool success, |
156 mojom::ProcessMemoryDumpPtr process_memory_dump) { | 196 mojom::ProcessMemoryDumpPtr process_memory_dump) { |
157 auto it = pending_process_managers_.find(process_manager); | 197 auto it = pending_process_managers_.find(process_manager); |
158 | 198 |
159 if (queued_memory_dump_requests_.empty() || | 199 if (queued_memory_dump_requests_.empty() || |
160 queued_memory_dump_requests_.front().args.dump_guid != dump_guid || | 200 queued_memory_dump_requests_.front().args.dump_guid != dump_guid || |
161 it == pending_process_managers_.end()) { | 201 it == pending_process_managers_.end()) { |
162 VLOG(1) << "Received unexpected memory dump response: " << dump_guid; | 202 VLOG(1) << "Received unexpected memory dump response: " << dump_guid; |
163 return; | 203 return; |
164 } | 204 } |
165 if (process_memory_dump) { | 205 if (process_memory_dump) { |
206 base::ProcessId pid = base::kNullProcessId; | |
207 auto it = process_managers_.find(process_manager); | |
208 if (it != process_managers_.end()) { | |
209 pid = process_map_->GetProcessId(it->second.second); | |
210 } | |
211 | |
166 queued_memory_dump_requests_.front().process_memory_dumps.push_back( | 212 queued_memory_dump_requests_.front().process_memory_dumps.push_back( |
167 std::move(process_memory_dump)); | 213 std::make_pair(pid, std::move(process_memory_dump))); |
168 } | 214 } |
169 | 215 |
170 pending_process_managers_.erase(it); | 216 pending_process_managers_.erase(it); |
171 | 217 |
172 if (!success) { | 218 if (!success) { |
173 ++failed_memory_dump_count_; | 219 ++failed_memory_dump_count_; |
174 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix | 220 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix |
175 << " failed because of NACK from provider"; | 221 << " failed because of NACK from provider"; |
176 } | 222 } |
177 | 223 |
178 FinalizeGlobalMemoryDumpIfAllManagersReplied(); | 224 FinalizeGlobalMemoryDumpIfAllManagersReplied(); |
179 } | 225 } |
180 | 226 |
181 void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { | 227 void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() { |
182 if (pending_process_managers_.size() > 0) | 228 if (pending_process_managers_.size() > 0) |
183 return; | 229 return; |
184 | 230 |
185 if (queued_memory_dump_requests_.empty()) { | 231 if (queued_memory_dump_requests_.empty()) { |
186 NOTREACHED(); | 232 NOTREACHED(); |
187 return; | 233 return; |
188 } | 234 } |
189 | 235 |
190 // TODO(hjd,fmeawad): At this point the |process_memory_dumps| accumulated in | 236 std::map<base::ProcessId, mojom::ProcessMemoryDumpPtr> finalized_pmds; |
191 // queued_memory_dump_requests_.front() should be normalized (merge | 237 for (auto& result : |
192 // |extra_process_dump|, compute CMM) into a GlobalMemoryDumpPtr and passed | 238 queued_memory_dump_requests_.front().process_memory_dumps) { |
193 // below. | 239 mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[result.first]; |
240 if (!pmd) | |
241 pmd = mojom::ProcessMemoryDump::New(); | |
242 pmd->chrome_dump = std::move(result.second->chrome_dump); | |
dcheng
2017/05/13 20:22:37
Nit: #include <utility>
erikchen
2017/05/14 04:49:16
Done.
| |
243 | |
244 // TODO(hjd): We should have a better way to tell if os_dump is filled. | |
245 if (result.second->os_dump.resident_set_kb > 0) { | |
246 pmd->os_dump = std::move(result.second->os_dump); | |
247 } | |
248 | |
249 for (auto& pair : result.second->extra_processes_dump) { | |
250 base::ProcessId pid = pair.first; | |
251 mojom::ProcessMemoryDumpPtr& pmd = finalized_pmds[pid]; | |
252 if (!pmd) | |
253 pmd = mojom::ProcessMemoryDump::New(); | |
254 pmd->os_dump = std::move(result.second->extra_processes_dump[pid]); | |
255 } | |
256 | |
257 pmd->process_type = result.second->process_type; | |
258 } | |
259 | |
260 mojom::GlobalMemoryDumpPtr global_dump(mojom::GlobalMemoryDump::New()); | |
261 for (auto& pair : finalized_pmds) { | |
262 // It's possible that the renderer has died but we still have an os_dump, | |
263 // because those were comptued from the browser proces before the renderer | |
dcheng
2017/05/13 20:22:37
Nit: computed
erikchen
2017/05/14 04:49:16
Done.
| |
264 // died. We should skip these. | |
265 // TODO(hjd): We should have a better way to tell if a chrome_dump is | |
266 // filled. | |
267 if (!pair.second->chrome_dump.malloc_total_kb) | |
268 continue; | |
269 base::ProcessId pid = pair.first; | |
270 mojom::ProcessMemoryDumpPtr pmd = std::move(finalized_pmds[pid]); | |
dcheng
2017/05/13 20:22:37
Nit: Maybe just alias this instead of double movin
erikchen
2017/05/14 04:49:16
Done.
| |
271 pmd->private_footprint = CalculatePrivateFootprintKb(pmd->os_dump); | |
272 global_dump->process_dumps.push_back(std::move(pmd)); | |
273 } | |
194 | 274 |
195 const auto& callback = queued_memory_dump_requests_.front().callback; | 275 const auto& callback = queued_memory_dump_requests_.front().callback; |
196 const bool global_success = failed_memory_dump_count_ == 0; | 276 const bool global_success = failed_memory_dump_count_ == 0; |
197 callback.Run(queued_memory_dump_requests_.front().args.dump_guid, | 277 callback.Run(queued_memory_dump_requests_.front().args.dump_guid, |
198 global_success, nullptr /* global_memory_dump */); | 278 global_success, std::move(global_dump)); |
199 queued_memory_dump_requests_.pop_front(); | 279 queued_memory_dump_requests_.pop_front(); |
200 | 280 |
201 // Schedule the next queued dump (if applicable). | 281 // Schedule the next queued dump (if applicable). |
202 if (!queued_memory_dump_requests_.empty()) { | 282 if (!queued_memory_dump_requests_.empty()) { |
203 base::ThreadTaskRunnerHandle::Get()->PostTask( | 283 base::ThreadTaskRunnerHandle::Get()->PostTask( |
204 FROM_HERE, | 284 FROM_HERE, |
205 base::Bind(&CoordinatorImpl::PerformNextQueuedGlobalMemoryDump, | 285 base::Bind(&CoordinatorImpl::PerformNextQueuedGlobalMemoryDump, |
206 base::Unretained(this))); | 286 base::Unretained(this))); |
207 } | 287 } |
208 } | 288 } |
209 | 289 |
290 void CoordinatorImpl::InitProcessMap(service_manager::Connector* connector) { | |
291 service_manager::mojom::ServiceManagerPtr service_manager; | |
292 connector->BindInterface(service_manager::mojom::kServiceName, | |
293 &service_manager); | |
294 service_manager::mojom::ServiceManagerListenerPtr listener; | |
295 service_manager::mojom::ServiceManagerListenerRequest request( | |
296 mojo::MakeRequest(&listener)); | |
297 service_manager->AddListener(std::move(listener)); | |
298 process_map_.reset(new ProcessMap()); | |
299 process_map_->BindRequest(std::move(request)); | |
300 } | |
301 | |
210 } // namespace memory_instrumentation | 302 } // namespace memory_instrumentation |
OLD | NEW |