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

Side by Side Diff: components/tracing/common/process_metrics_memory_dump_provider.cc

Issue 2568313004: [memory-infra] Implement PollFastMemoryTotal in ProcessMetricsMemoryDumpProvider. (Closed)
Patch Set: Created 4 years 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/tracing/common/process_metrics_memory_dump_provider.h" 5 #include "components/tracing/common/process_metrics_memory_dump_provider.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <map> 10 #include <map>
11 11
12 #include "base/files/file_util.h" 12 #include "base/files/file_util.h"
13 #include "base/files/scoped_file.h" 13 #include "base/files/scoped_file.h"
14 #include "base/format_macros.h" 14 #include "base/format_macros.h"
15 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/memory/ptr_util.h" 17 #include "base/memory/ptr_util.h"
18 #include "base/process/process_metrics.h" 18 #include "base/process/process_metrics.h"
19 #include "base/strings/string_number_conversions.h" 19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_tokenizer.h"
20 #include "base/strings/string_util.h" 21 #include "base/strings/string_util.h"
22 #include "base/synchronization/lock.h"
21 #include "base/trace_event/memory_dump_manager.h" 23 #include "base/trace_event/memory_dump_manager.h"
22 #include "base/trace_event/process_memory_dump.h" 24 #include "base/trace_event/process_memory_dump.h"
23 #include "base/trace_event/process_memory_maps.h" 25 #include "base/trace_event/process_memory_maps.h"
24 #include "base/trace_event/process_memory_totals.h" 26 #include "base/trace_event/process_memory_totals.h"
27 #include "base/trace_event/trace_log.h"
25 #include "build/build_config.h" 28 #include "build/build_config.h"
26 29
27 namespace tracing { 30 namespace tracing {
28 31
29 namespace { 32 namespace {
30 33
31 base::LazyInstance<
32 std::map<base::ProcessId,
33 std::unique_ptr<ProcessMetricsMemoryDumpProvider>>>::Leaky
34 g_dump_providers_map = LAZY_INSTANCE_INITIALIZER;
35
36 #if defined(OS_LINUX) || defined(OS_ANDROID) 34 #if defined(OS_LINUX) || defined(OS_ANDROID)
35 const int kInvalidFD = -1;
Primiano Tucci (use gerrit) 2016/12/13 20:02:39 honestly I think that directly using -1 makes the
ssid 2016/12/14 02:59:32 Done.
37 const char kClearPeakRssCommand[] = "5"; 36 const char kClearPeakRssCommand[] = "5";
38 37
39 const uint32_t kMaxLineSize = 4096; 38 const uint32_t kMaxLineSize = 4096;
40 39
41 bool ParseSmapsHeader(const char* header_line, 40 bool ParseSmapsHeader(const char* header_line,
42 base::trace_event::ProcessMemoryMaps::VMRegion* region) { 41 base::trace_event::ProcessMemoryMaps::VMRegion* region) {
43 // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234 /foo.so\n" 42 // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234 /foo.so\n"
44 bool res = true; // Whether this region should be appended or skipped. 43 bool res = true; // Whether this region should be appended or skipped.
45 uint64_t end_addr = 0; 44 uint64_t end_addr = 0;
46 char protection_flags[5] = {0}; 45 char protection_flags[5] = {0};
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 if (should_add_current_region) { 147 if (should_add_current_region) {
149 pmm->AddVMRegion(region); 148 pmm->AddVMRegion(region);
150 ++num_valid_regions; 149 ++num_valid_regions;
151 should_add_current_region = false; 150 should_add_current_region = false;
152 } 151 }
153 } 152 }
154 } 153 }
155 } 154 }
156 return num_valid_regions; 155 return num_valid_regions;
157 } 156 }
157
158 int OpenStatmFile(base::ProcessId process) {
159 std::string name =
160 "/proc/" +
161 (process == base::kNullProcessId ? "self" : base::IntToString(process)) +
162 "/statm";
163 return open(name.c_str(), O_RDONLY);
164 }
165
166 bool GetResidentSizesFromStatmFile(int file_des,
Primiano Tucci (use gerrit) 2016/12/13 20:02:39 s/file_des/fd/
ssid 2016/12/14 02:59:32 Done.
167 size_t* resident_bytes,
168 size_t* shared_bytes) {
169 lseek(file_des, 0, SEEK_SET);
170 char line[kMaxLineSize];
171 int res = read(file_des, line, kMaxLineSize);
172 if (res <= 0)
173 return false;
174 line[res] = '\0';
175 base::CStringTokenizer t(line, line + strlen(line), " ");
Primiano Tucci (use gerrit) 2016/12/13 20:02:39 hmm CStringTokenizer will implicitly convert line
ssid 2016/12/14 02:59:32 Makes sense. fixed.
176 t.GetNext();
177 // Ignore the first first number.
178 t.GetNext();
179 base::StringToSizeT(t.token().c_str(), resident_bytes);
180 t.GetNext();
181 base::StringToSizeT(t.token().c_str(), shared_bytes);
182 return true;
183 }
184
158 #endif // defined(OS_LINUX) || defined(OS_ANDROID) 185 #endif // defined(OS_LINUX) || defined(OS_ANDROID)
159 186
160 std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics( 187 std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
161 base::ProcessId process) { 188 base::ProcessId process) {
162 if (process == base::kNullProcessId) 189 if (process == base::kNullProcessId)
163 return base::ProcessMetrics::CreateCurrentProcessMetrics(); 190 return base::ProcessMetrics::CreateCurrentProcessMetrics();
164 #if defined(OS_LINUX) || defined(OS_ANDROID) 191 #if defined(OS_LINUX) || defined(OS_ANDROID)
165 // Just pass ProcessId instead of handle since they are the same in linux and 192 // Just pass ProcessId instead of handle since they are the same in linux and
166 // android. 193 // android.
167 return base::ProcessMetrics::CreateProcessMetrics(process); 194 return base::ProcessMetrics::CreateProcessMetrics(process);
168 #else 195 #else
169 // Creating process metrics for child processes in mac or windows requires 196 // Creating process metrics for child processes in mac or windows requires
170 // additional information like ProcessHandle or port provider. 197 // additional information like ProcessHandle or port provider.
171 NOTREACHED(); 198 NOTREACHED();
172 return std::unique_ptr<base::ProcessMetrics>(); 199 return std::unique_ptr<base::ProcessMetrics>();
173 #endif // defined(OS_LINUX) || defined(OS_ANDROID) 200 #endif // defined(OS_LINUX) || defined(OS_ANDROID)
174 } 201 }
175 202
203 base::LazyInstance<
Primiano Tucci (use gerrit) 2016/12/13 20:02:39 is there a functional reason why you moved this? I
ssid 2016/12/14 02:59:32 Sorry this was a mistake.
204 std::map<base::ProcessId,
205 std::unique_ptr<ProcessMetricsMemoryDumpProvider>>>::Leaky
206 g_dump_providers_map = LAZY_INSTANCE_INITIALIZER;
207
176 } // namespace 208 } // namespace
177 209
178 // static 210 // static
179 uint64_t ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 0; 211 uint64_t ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 0;
180 212
181 #if defined(OS_LINUX) || defined(OS_ANDROID) 213 #if defined(OS_LINUX) || defined(OS_ANDROID)
182 214
183 // static 215 // static
184 FILE* ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = nullptr; 216 FILE* ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = nullptr;
185 217
(...skipping 18 matching lines...) Expand all
204 } 236 }
205 #endif // defined(OS_LINUX) || defined(OS_ANDROID) 237 #endif // defined(OS_LINUX) || defined(OS_ANDROID)
206 238
207 // static 239 // static
208 void ProcessMetricsMemoryDumpProvider::RegisterForProcess( 240 void ProcessMetricsMemoryDumpProvider::RegisterForProcess(
209 base::ProcessId process) { 241 base::ProcessId process) {
210 std::unique_ptr<ProcessMetricsMemoryDumpProvider> metrics_provider( 242 std::unique_ptr<ProcessMetricsMemoryDumpProvider> metrics_provider(
211 new ProcessMetricsMemoryDumpProvider(process)); 243 new ProcessMetricsMemoryDumpProvider(process));
212 base::trace_event::MemoryDumpProvider::Options options; 244 base::trace_event::MemoryDumpProvider::Options options;
213 options.target_pid = process; 245 options.target_pid = process;
246 options.is_fast_polling_supported = true;
214 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( 247 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
215 metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options); 248 metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options);
216 bool did_insert = 249 bool did_insert =
217 g_dump_providers_map.Get() 250 g_dump_providers_map.Get()
218 .insert(std::make_pair(process, std::move(metrics_provider))) 251 .insert(std::make_pair(process, std::move(metrics_provider)))
219 .second; 252 .second;
220 if (!did_insert) { 253 if (!did_insert) {
221 DLOG(ERROR) << "ProcessMetricsMemoryDumpProvider already registered for " 254 DLOG(ERROR) << "ProcessMetricsMemoryDumpProvider already registered for "
222 << (process == base::kNullProcessId 255 << (process == base::kNullProcessId
223 ? "current process" 256 ? "current process"
224 : "process id " + base::IntToString(process)); 257 : "process id " + base::IntToString(process));
225 } 258 }
226 } 259 }
227 260
228 // static 261 // static
229 void ProcessMetricsMemoryDumpProvider::UnregisterForProcess( 262 void ProcessMetricsMemoryDumpProvider::UnregisterForProcess(
230 base::ProcessId process) { 263 base::ProcessId process) {
231 auto iter = g_dump_providers_map.Get().find(process); 264 auto iter = g_dump_providers_map.Get().find(process);
232 if (iter == g_dump_providers_map.Get().end()) { 265 if (iter == g_dump_providers_map.Get().end())
233 return; 266 return;
234 }
235 base::trace_event::MemoryDumpManager::GetInstance() 267 base::trace_event::MemoryDumpManager::GetInstance()
236 ->UnregisterAndDeleteDumpProviderSoon(std::move(iter->second)); 268 ->UnregisterAndDeleteDumpProviderSoon(std::move(iter->second));
237 g_dump_providers_map.Get().erase(iter); 269 g_dump_providers_map.Get().erase(iter);
238 } 270 }
239 271
240 ProcessMetricsMemoryDumpProvider::ProcessMetricsMemoryDumpProvider( 272 ProcessMetricsMemoryDumpProvider::ProcessMetricsMemoryDumpProvider(
241 base::ProcessId process) 273 base::ProcessId process)
242 : process_(process), 274 : process_(process),
243 process_metrics_(CreateProcessMetrics(process)), 275 process_metrics_(CreateProcessMetrics(process)),
244 is_rss_peak_resettable_(true) {} 276 is_rss_peak_resettable_(true) {
277 #if defined(OS_LINUX) || defined(OS_ANDROID)
278 proc_statm_file_ = kInvalidFD;
279 #endif
280 }
245 281
246 ProcessMetricsMemoryDumpProvider::~ProcessMetricsMemoryDumpProvider() {} 282 ProcessMetricsMemoryDumpProvider::~ProcessMetricsMemoryDumpProvider() {
283 // Clear files in case polling was not disabled yet.
284 SetFastMemoryPollingEnabled(false);
285 }
247 286
248 // Called at trace dump point time. Creates a snapshot of the memory maps for 287 // Called at trace dump point time. Creates a snapshot of the memory maps for
249 // the current process. 288 // the current process.
250 bool ProcessMetricsMemoryDumpProvider::OnMemoryDump( 289 bool ProcessMetricsMemoryDumpProvider::OnMemoryDump(
251 const base::trace_event::MemoryDumpArgs& args, 290 const base::trace_event::MemoryDumpArgs& args,
252 base::trace_event::ProcessMemoryDump* pmd) { 291 base::trace_event::ProcessMemoryDump* pmd) {
253 bool res = DumpProcessTotals(args, pmd); 292 bool res = DumpProcessTotals(args, pmd);
254 293
255 #if defined(OS_LINUX) || defined(OS_ANDROID) 294 #if defined(OS_LINUX) || defined(OS_ANDROID)
256 if (args.level_of_detail == 295 if (args.level_of_detail ==
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 #endif // !defined(OS_IOS) 341 #endif // !defined(OS_IOS)
303 342
304 pmd->process_totals()->set_resident_set_bytes(rss_bytes); 343 pmd->process_totals()->set_resident_set_bytes(rss_bytes);
305 pmd->set_has_process_totals(); 344 pmd->set_has_process_totals();
306 pmd->process_totals()->set_peak_resident_set_bytes(peak_rss_bytes); 345 pmd->process_totals()->set_peak_resident_set_bytes(peak_rss_bytes);
307 346
308 // Returns true even if other metrics failed, since rss is reported. 347 // Returns true even if other metrics failed, since rss is reported.
309 return true; 348 return true;
310 } 349 }
311 350
351 void ProcessMetricsMemoryDumpProvider::PollFastMemoryTotal(
352 uint64_t* memory_total) {
353 *memory_total = 0;
354 #if defined(OS_LINUX) || defined(OS_ANDROID)
355 if (proc_statm_file_ == kInvalidFD)
356 proc_statm_file_ = OpenStatmFile(process_);
357 if (proc_statm_file_ < 0)
358 return;
359
360 size_t rss = 0, shared = 0;
361 if (!GetResidentSizesFromStatmFile(proc_statm_file_, &rss, &shared))
362 return;
363
364 // When adding total for child processes, do not include "shared" since it
365 // will be included in the current processes' total.
366 *memory_total = (process_ == base::kNullProcessId ? rss : rss - shared) *
Primiano Tucci (use gerrit) 2016/12/13 20:02:39 hmm not sure I am convinced here. The math should
ssid 2016/12/14 02:59:32 Hm but we will miss the shared memory increases if
Primiano Tucci (use gerrit) 2016/12/15 15:00:02 I was suggesting the other way round, *always*coun
ssid 2016/12/16 03:16:41 makes sense. Changed to just resident size.
367 base::GetPageSize();
368 #else
369 *memory_total = process_metrics_->GetWorkingSetSize();
370 #endif
371 }
372
373 void ProcessMetricsMemoryDumpProvider::SetFastMemoryPollingEnabled(
374 bool enabled) {
375 #if defined(OS_LINUX) || defined(OS_ANDROID)
376 if (proc_statm_file_ >= 0)
Primiano Tucci (use gerrit) 2016/12/13 20:02:39 Ok I see how doing the auto-opening makes things e
ssid 2016/12/14 02:59:32 It is weird to have SetFastMemoryPollingDisabled m
377 close(proc_statm_file_);
378 proc_statm_file_ = kInvalidFD;
379 #endif
380 }
381
312 } // namespace tracing 382 } // namespace tracing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698