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

Side by Side Diff: tools/android/memdump/memdump.cc

Issue 19466005: Adding extended report to memdump with resident pages bit reporting. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/android/memdump/memsymbols.py » ('j') | tools/android/memdump/memsymbols.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 <fcntl.h> 5 #include <fcntl.h>
6 #include <signal.h> 6 #include <signal.h>
7 #include <sys/types.h> 7 #include <sys/types.h>
8 #include <unistd.h> 8 #include <unistd.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <cstring> 11 #include <cstring>
12 #include <fstream> 12 #include <fstream>
13 #include <iostream> 13 #include <iostream>
14 #include <limits> 14 #include <limits>
15 #include <string> 15 #include <string>
16 #include <utility> 16 #include <utility>
17 #include <vector> 17 #include <vector>
18 18
19 #include "base/base64.h"
19 #include "base/basictypes.h" 20 #include "base/basictypes.h"
20 #include "base/bind.h" 21 #include "base/bind.h"
21 #include "base/bind_helpers.h" 22 #include "base/bind_helpers.h"
22 #include "base/containers/hash_tables.h" 23 #include "base/containers/hash_tables.h"
23 #include "base/file_util.h" 24 #include "base/file_util.h"
24 #include "base/logging.h" 25 #include "base/logging.h"
25 #include "base/memory/scoped_ptr.h" 26 #include "base/memory/scoped_ptr.h"
26 #include "base/strings/string_number_conversions.h" 27 #include "base/strings/string_number_conversions.h"
27 #include "base/strings/string_piece.h" 28 #include "base/strings/string_piece.h"
28 #include "base/strings/string_split.h" 29 #include "base/strings/string_split.h"
29 #include "base/strings/stringprintf.h" 30 #include "base/strings/stringprintf.h"
30 31
31 namespace { 32 namespace {
32 33
34 class BitSet {
bulach 2013/07/22 12:59:39 I suppose the ndk has #include <bitset> ?
digit1 2013/07/22 21:03:14 That's true, but note that std::bitset<> is not a
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Yeah, unforunately STL's bitset require the size o
bulach 2013/07/23 08:10:57 ops, forgot that tiny detail :) thanks for the ref
35 public:
Philippe 2013/07/22 09:20:55 Nit: there should be a leading space before 'publi
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Done.
36 BitSet() : nbits_(0), data_(0) { }
Philippe 2013/07/22 09:20:55 Nit: no space between the braces.
Philippe 2013/07/22 09:20:55 Nit: I believe the |data_| explicit initialization
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Done.
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Hmm, agree for nbits (see below), but _data was ju
37
38 void setSize(int nbits) {
Philippe 2013/07/22 09:20:55 Nit: maybe call this 'resize()' and also s/getData
digit1 2013/07/22 21:03:14 Also, you should use the Chromium style guide, whi
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Right, makes sense!
39 nbits_ = nbits;
Philippe 2013/07/22 09:20:55 Nit: do we need to store |nbits|? Can we entirely
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Yeah, that was just me being uber-paranoid. The at
40 data_.resize((nbits_+7)/8);
Philippe 2013/07/22 09:20:55 Nit: spaces around binary operators (here and on a
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Done.
41 memset(&data_[0], 0, getLength());
Philippe 2013/07/22 09:20:55 Nit: I believe you can delete this line and use th
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Oh, apparently I am the one missing the autofill o
42 }
43
44 void set(int bit) {
45 data_.at(bit/8) |= (1 << (bit % 8));
digit1 2013/07/22 21:03:14 nit: since 'bit' is signed, using 'bit & 7' is mor
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Great catch! Right. For the records: return arg
46 }
47
48 const char* getData() const { return &data_[0]; }
Philippe 2013/07/22 09:20:55 Nit: data_.data()?
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 I'm afraid that is only possible in C++11.
49
50 int getLength() const { return data_.size(); }
digit1 2013/07/22 21:03:14 nit: This is very misleading because this doesn't
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 At this point, let's do directly AsB64String().
51
52 private:
53 int nbits_;
54 std::vector<char> data_;
55 };
56
33 // An entry in /proc/<pid>/pagemap. 57 // An entry in /proc/<pid>/pagemap.
34 struct PageMapEntry { 58 struct PageMapEntry {
35 uint64 page_frame_number : 55; 59 uint64 page_frame_number : 55;
36 uint unused : 8; 60 uint unused : 8;
37 uint present : 1; 61 uint present : 1;
38 }; 62 };
39 63
40 // Describes a memory page. 64 // Describes a memory page.
41 struct PageInfo { 65 struct PageInfo {
42 int64 page_frame_number; // Physical page id, also known as PFN. 66 int64 page_frame_number; // Physical page id, also known as PFN.
43 int64 flags; 67 int64 flags;
44 int32 times_mapped; 68 int32 times_mapped;
45 }; 69 };
46 70
47 struct MemoryMap { 71 struct MemoryMap {
48 std::string name; 72 std::string name;
49 std::string flags; 73 std::string flags;
50 uint start_address; 74 uint start_address;
51 uint end_address; 75 uint end_address;
76 uint offset;
52 int private_count; 77 int private_count;
53 int unevictable_private_count; 78 int unevictable_private_count;
54 int other_shared_count; 79 int other_shared_count;
55 int unevictable_other_shared_count; 80 int unevictable_other_shared_count;
56 // app_shared_counts[i] contains the number of pages mapped in i+2 processes 81 // app_shared_counts[i] contains the number of pages mapped in i+2 processes
57 // (only among the processes that are being analyzed). 82 // (only among the processes that are being analyzed).
58 std::vector<int> app_shared_counts; 83 std::vector<int> app_shared_counts;
59 std::vector<PageInfo> committed_pages; 84 std::vector<PageInfo> committed_pages;
85 // committed_pages_bits is a bitmap reflecting the present bit for all the
Philippe 2013/07/22 09:20:55 Nit: s/bitmap/bitset maybe.
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Done.
86 // virtual pages of the mapping.
87 BitSet committed_pages_bits;
60 }; 88 };
61 89
62 struct ProcessMemory { 90 struct ProcessMemory {
63 pid_t pid; 91 pid_t pid;
64 std::vector<MemoryMap> memory_maps; 92 std::vector<MemoryMap> memory_maps;
65 }; 93 };
66 94
67 bool PageIsUnevictable(const PageInfo& page_info) { 95 bool PageIsUnevictable(const PageInfo& page_info) {
68 // These constants are taken from kernel-page-flags.h. 96 // These constants are taken from kernel-page-flags.h.
69 const int KPF_DIRTY = 4; // Note that only file-mapped pages can be DIRTY. 97 const int KPF_DIRTY = 4; // Note that only file-mapped pages can be DIRTY.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 base::StringPiece( 135 base::StringPiece(
108 addr_range.begin() + end_addr_start_pos, 136 addr_range.begin() + end_addr_start_pos,
109 addr_range.begin() + end_addr_start_pos + addr_len), 137 addr_range.begin() + end_addr_start_pos + addr_len),
110 &tmp)) { 138 &tmp)) {
111 return false; 139 return false;
112 } 140 }
113 memory_map->end_address = static_cast<uint>(tmp); 141 memory_map->end_address = static_cast<uint>(tmp);
114 if (tokens->at(1).size() != strlen("rwxp")) 142 if (tokens->at(1).size() != strlen("rwxp"))
115 return false; 143 return false;
116 memory_map->flags.swap(tokens->at(1)); 144 memory_map->flags.swap(tokens->at(1));
145 if (!base::HexStringToUInt64(tokens->at(2), &tmp))
146 return false;
147 memory_map->offset = static_cast<uint>(tmp);
148 memory_map->committed_pages_bits.setSize(
149 (memory_map->end_address - memory_map->start_address) / PAGE_SIZE);
117 const int map_name_index = 5; 150 const int map_name_index = 5;
118 if (tokens->size() >= map_name_index + 1) { 151 if (tokens->size() >= map_name_index + 1) {
119 for (std::vector<std::string>::const_iterator it = 152 for (std::vector<std::string>::const_iterator it =
120 tokens->begin() + map_name_index; it != tokens->end(); ++it) { 153 tokens->begin() + map_name_index; it != tokens->end(); ++it) {
121 if (!it->empty()) { 154 if (!it->empty()) {
122 if (!memory_map->name.empty()) 155 if (!memory_map->name.empty())
123 memory_map->name.append(" "); 156 memory_map->name.append(" ");
124 memory_map->name.append(*it); 157 memory_map->name.append(*it);
125 } 158 }
126 } 159 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 } 193 }
161 process_maps->push_back(memory_map); 194 process_maps->push_back(memory_map);
162 } 195 }
163 return true; 196 return true;
164 } 197 }
165 198
166 // Fills |committed_pages| in with the set of committed pages contained in the 199 // Fills |committed_pages| in with the set of committed pages contained in the
167 // provided memory map. 200 // provided memory map.
168 bool GetPagesForMemoryMap(int pagemap_fd, 201 bool GetPagesForMemoryMap(int pagemap_fd,
169 const MemoryMap& memory_map, 202 const MemoryMap& memory_map,
170 std::vector<PageInfo>* committed_pages) { 203 std::vector<PageInfo>* committed_pages,
171 for (uint addr = memory_map.start_address; addr < memory_map.end_address; 204 BitSet* committed_pages_bits) {
172 addr += PAGE_SIZE) { 205 for (uint addr = memory_map.start_address, page_index = 0;
206 addr < memory_map.end_address;
207 addr += PAGE_SIZE, ++page_index) {
173 DCHECK_EQ(0, addr % PAGE_SIZE); 208 DCHECK_EQ(0, addr % PAGE_SIZE);
174 PageMapEntry page_map_entry = {}; 209 PageMapEntry page_map_entry = {};
175 COMPILE_ASSERT(sizeof(PageMapEntry) == sizeof(uint64), unexpected_size); 210 COMPILE_ASSERT(sizeof(PageMapEntry) == sizeof(uint64), unexpected_size);
176 const off64_t offset = addr / PAGE_SIZE; 211 const off64_t offset = addr / PAGE_SIZE;
177 if (!ReadFromFileAtOffset(pagemap_fd, offset, &page_map_entry)) 212 if (!ReadFromFileAtOffset(pagemap_fd, offset, &page_map_entry))
178 return false; 213 return false;
179 if (page_map_entry.present) { // Ignore non-committed pages. 214 if (page_map_entry.present) { // Ignore non-committed pages.
180 if (page_map_entry.page_frame_number == 0) 215 if (page_map_entry.page_frame_number == 0)
181 continue; 216 continue;
182 PageInfo page_info = {}; 217 PageInfo page_info = {};
183 page_info.page_frame_number = page_map_entry.page_frame_number; 218 page_info.page_frame_number = page_map_entry.page_frame_number;
184 committed_pages->push_back(page_info); 219 committed_pages->push_back(page_info);
220 committed_pages_bits->set(page_index);
185 } 221 }
186 } 222 }
187 return true; 223 return true;
188 } 224 }
189 225
190 // Fills |committed_pages| with mapping count and flags information gathered 226 // Fills |committed_pages| with mapping count and flags information gathered
191 // looking-up /proc/kpagecount and /proc/kpageflags. 227 // looking-up /proc/kpagecount and /proc/kpageflags.
192 bool SetPagesInfo(int pagecount_fd, 228 bool SetPagesInfo(int pagecount_fd,
193 int pageflags_fd, 229 int pageflags_fd,
194 std::vector<PageInfo>* pages) { 230 std::vector<PageInfo>* pages) {
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 base::SStringPrintf( 416 base::SStringPrintf(
381 &buf, "%d\t%d\t\t%d\t\t%d\n", 417 &buf, "%d\t%d\t\t%d\t\t%d\n",
382 process_memory.pid, 418 process_memory.pid,
383 total_private * KB_PER_PAGE, 419 total_private * KB_PER_PAGE,
384 static_cast<int>(total_app_shared) * KB_PER_PAGE, 420 static_cast<int>(total_app_shared) * KB_PER_PAGE,
385 total_other_shared * KB_PER_PAGE); 421 total_other_shared * KB_PER_PAGE);
386 std::cout << buf; 422 std::cout << buf;
387 } 423 }
388 } 424 }
389 425
426 void DumpProcessesMemoryMapsInExtendedFormat(
427 const std::vector<ProcessMemory>& processes_memory) {
428 std::string buf;
429 std::string app_shared_buf;
430 for (std::vector<ProcessMemory>::const_iterator it = processes_memory.begin();
431 it != processes_memory.end(); ++it) {
432 const ProcessMemory& process_memory = *it;
433 std::cout << "[ PID=" << process_memory.pid << "]" << '\n';
434 const std::vector<MemoryMap>& memory_maps = process_memory.memory_maps;
435 for (std::vector<MemoryMap>::const_iterator it = memory_maps.begin();
436 it != memory_maps.end(); ++it) {
437 const MemoryMap& memory_map = *it;
438 app_shared_buf.clear();
439 AppendAppSharedField(memory_map.app_shared_counts, &app_shared_buf);
440 std::string pages_bits(memory_map.committed_pages_bits.getData(),
441 memory_map.committed_pages_bits.getLength());
442 std::string encoded_page_bits;
443 base::Base64Encode(pages_bits, &encoded_page_bits);
444 base::SStringPrintf(
445 &buf,
446 "%x-%x %s %x private_unevictable=%d private=%d shared_app=%s "
447 "shared_other_unevictable=%d shared_other=%d \"%s\" [%s]\n",
448 memory_map.start_address,
449 memory_map.end_address,
450 memory_map.flags.c_str(),
451 memory_map.offset,
452 memory_map.unevictable_private_count * PAGE_SIZE,
453 memory_map.private_count * PAGE_SIZE,
454 app_shared_buf.c_str(),
455 memory_map.unevictable_other_shared_count * PAGE_SIZE,
456 memory_map.other_shared_count * PAGE_SIZE,
457 memory_map.name.c_str(),
458 encoded_page_bits.c_str());
459 std::cout << buf;
460 }
461 }
462 }
463
390 bool CollectProcessMemoryInformation(int page_count_fd, 464 bool CollectProcessMemoryInformation(int page_count_fd,
391 int page_flags_fd, 465 int page_flags_fd,
392 ProcessMemory* process_memory) { 466 ProcessMemory* process_memory) {
393 const pid_t pid = process_memory->pid; 467 const pid_t pid = process_memory->pid;
394 int pagemap_fd = open( 468 int pagemap_fd = open(
395 base::StringPrintf("/proc/%d/pagemap", pid).c_str(), O_RDONLY); 469 base::StringPrintf("/proc/%d/pagemap", pid).c_str(), O_RDONLY);
396 if (pagemap_fd < 0) { 470 if (pagemap_fd < 0) {
397 PLOG(ERROR) << "open"; 471 PLOG(ERROR) << "open";
398 return false; 472 return false;
399 } 473 }
400 file_util::ScopedFD auto_closer(&pagemap_fd); 474 file_util::ScopedFD auto_closer(&pagemap_fd);
401 std::vector<MemoryMap>* const process_maps = &process_memory->memory_maps; 475 std::vector<MemoryMap>* const process_maps = &process_memory->memory_maps;
402 if (!GetProcessMaps(pid, process_maps)) 476 if (!GetProcessMaps(pid, process_maps))
403 return false; 477 return false;
404 for (std::vector<MemoryMap>::iterator it = process_maps->begin(); 478 for (std::vector<MemoryMap>::iterator it = process_maps->begin();
405 it != process_maps->end(); ++it) { 479 it != process_maps->end(); ++it) {
406 std::vector<PageInfo>* const committed_pages = &it->committed_pages; 480 std::vector<PageInfo>* const committed_pages = &it->committed_pages;
407 GetPagesForMemoryMap(pagemap_fd, *it, committed_pages); 481 BitSet* pages_bits = &it->committed_pages_bits;
Philippe 2013/07/22 09:20:55 Nit: 'BitSet* const pages_bits' maybe for consiste
Primiano Tucci (use gerrit) 2013/07/22 23:22:35 Done.
482 GetPagesForMemoryMap(pagemap_fd, *it, committed_pages, pages_bits);
408 SetPagesInfo(page_count_fd, page_flags_fd, committed_pages); 483 SetPagesInfo(page_count_fd, page_flags_fd, committed_pages);
409 } 484 }
410 return true; 485 return true;
411 } 486 }
412 487
413 void KillAll(const std::vector<pid_t>& pids, int signal_number) { 488 void KillAll(const std::vector<pid_t>& pids, int signal_number) {
414 for (std::vector<pid_t>::const_iterator it = pids.begin(); it != pids.end(); 489 for (std::vector<pid_t>::const_iterator it = pids.begin(); it != pids.end();
415 ++it) { 490 ++it) {
416 kill(*it, signal_number); 491 kill(*it, signal_number);
417 } 492 }
418 } 493 }
419 494
420 } // namespace 495 } // namespace
421 496
422 int main(int argc, char** argv) { 497 int main(int argc, char** argv) {
423 bool short_output = false;
424 if (argc == 1) { 498 if (argc == 1) {
425 LOG(ERROR) << "Usage: " << argv[0] << " [-a] <PID1>... <PIDN>"; 499 LOG(ERROR) << "Usage: " << argv[0] << " [-a|-x] <PID1>... <PIDN>";
426 return EXIT_FAILURE; 500 return EXIT_FAILURE;
427 } 501 }
428 if (!strncmp(argv[1], "-a", 2)) { 502 const bool short_output = !strncmp(argv[1], "-a", 2);
503 const bool extended_output = !strncmp(argv[1], "-x", 2);
504 if (short_output || extended_output) {
429 if (argc == 2) { 505 if (argc == 2) {
430 LOG(ERROR) << "Usage: " << argv[0] << " [-a] <PID1>... <PIDN>"; 506 LOG(ERROR) << "Usage: " << argv[0] << " [-a|-x] <PID1>... <PIDN>";
431 return EXIT_FAILURE; 507 return EXIT_FAILURE;
432 } 508 }
433 short_output = true;
434 ++argv; 509 ++argv;
435 } 510 }
436 std::vector<pid_t> pids; 511 std::vector<pid_t> pids;
437 for (const char* const* ptr = argv + 1; *ptr; ++ptr) { 512 for (const char* const* ptr = argv + 1; *ptr; ++ptr) {
438 pid_t pid; 513 pid_t pid;
439 if (!base::StringToInt(*ptr, &pid)) 514 if (!base::StringToInt(*ptr, &pid))
440 return EXIT_FAILURE; 515 return EXIT_FAILURE;
441 pids.push_back(pid); 516 pids.push_back(pid);
442 } 517 }
443 518
(...skipping 25 matching lines...) Expand all
469 if (!CollectProcessMemoryInformation(page_count_fd, 544 if (!CollectProcessMemoryInformation(page_count_fd,
470 page_flags_fd, 545 page_flags_fd,
471 process_memory)) 546 process_memory))
472 return EXIT_FAILURE; 547 return EXIT_FAILURE;
473 } 548 }
474 } 549 }
475 550
476 ClassifyPages(&processes_memory); 551 ClassifyPages(&processes_memory);
477 if (short_output) 552 if (short_output)
478 DumpProcessesMemoryMapsInShortFormat(processes_memory); 553 DumpProcessesMemoryMapsInShortFormat(processes_memory);
554 else if (extended_output)
555 DumpProcessesMemoryMapsInExtendedFormat(processes_memory);
479 else 556 else
480 DumpProcessesMemoryMaps(processes_memory); 557 DumpProcessesMemoryMaps(processes_memory);
481 return EXIT_SUCCESS; 558 return EXIT_SUCCESS;
482 } 559 }
OLDNEW
« no previous file with comments | « no previous file | tools/android/memdump/memsymbols.py » ('j') | tools/android/memdump/memsymbols.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698