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

Side by Side Diff: services/resource_coordinator/memory/coordinator/coordinator_impl.cc

Issue 2883693002: [Memory-UMA] Implement basic working prototype. (Closed)
Patch Set: Tests working. Created 3 years, 7 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 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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698