Chromium Code Reviews| Index: tools/android/memdump/memdump.cc |
| diff --git a/tools/android/memdump/memdump.cc b/tools/android/memdump/memdump.cc |
| index 21ef291f3d76d8f3b47814ade2e758f2725a3e95..8d1cdadde3e21e7370d45c94a08ebe6c4d3a7dbf 100644 |
| --- a/tools/android/memdump/memdump.cc |
| +++ b/tools/android/memdump/memdump.cc |
| @@ -16,6 +16,7 @@ |
| #include <utility> |
| #include <vector> |
| +#include "base/base64.h" |
| #include "base/basictypes.h" |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| @@ -30,6 +31,29 @@ |
| namespace { |
| +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
|
| +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.
|
| + 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
|
| + |
| + 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!
|
| + 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
|
| + 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.
|
| + 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
|
| + } |
| + |
| + void set(int bit) { |
| + 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
|
| + } |
| + |
| + 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.
|
| + |
| + 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().
|
| + |
| +private: |
| + int nbits_; |
| + std::vector<char> data_; |
| +}; |
| + |
| // An entry in /proc/<pid>/pagemap. |
| struct PageMapEntry { |
| uint64 page_frame_number : 55; |
| @@ -49,6 +73,7 @@ struct MemoryMap { |
| std::string flags; |
| uint start_address; |
| uint end_address; |
| + uint offset; |
| int private_count; |
| int unevictable_private_count; |
| int other_shared_count; |
| @@ -57,6 +82,9 @@ struct MemoryMap { |
| // (only among the processes that are being analyzed). |
| std::vector<int> app_shared_counts; |
| std::vector<PageInfo> committed_pages; |
| + // 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.
|
| + // virtual pages of the mapping. |
| + BitSet committed_pages_bits; |
| }; |
| struct ProcessMemory { |
| @@ -114,6 +142,11 @@ bool ParseMemoryMapLine(const std::string& line, |
| if (tokens->at(1).size() != strlen("rwxp")) |
| return false; |
| memory_map->flags.swap(tokens->at(1)); |
| + if (!base::HexStringToUInt64(tokens->at(2), &tmp)) |
| + return false; |
| + memory_map->offset = static_cast<uint>(tmp); |
| + memory_map->committed_pages_bits.setSize( |
| + (memory_map->end_address - memory_map->start_address) / PAGE_SIZE); |
| const int map_name_index = 5; |
| if (tokens->size() >= map_name_index + 1) { |
| for (std::vector<std::string>::const_iterator it = |
| @@ -167,9 +200,11 @@ bool GetProcessMaps(pid_t pid, std::vector<MemoryMap>* process_maps) { |
| // provided memory map. |
| bool GetPagesForMemoryMap(int pagemap_fd, |
| const MemoryMap& memory_map, |
| - std::vector<PageInfo>* committed_pages) { |
| - for (uint addr = memory_map.start_address; addr < memory_map.end_address; |
| - addr += PAGE_SIZE) { |
| + std::vector<PageInfo>* committed_pages, |
| + BitSet* committed_pages_bits) { |
| + for (uint addr = memory_map.start_address, page_index = 0; |
| + addr < memory_map.end_address; |
| + addr += PAGE_SIZE, ++page_index) { |
| DCHECK_EQ(0, addr % PAGE_SIZE); |
| PageMapEntry page_map_entry = {}; |
| COMPILE_ASSERT(sizeof(PageMapEntry) == sizeof(uint64), unexpected_size); |
| @@ -182,6 +217,7 @@ bool GetPagesForMemoryMap(int pagemap_fd, |
| PageInfo page_info = {}; |
| page_info.page_frame_number = page_map_entry.page_frame_number; |
| committed_pages->push_back(page_info); |
| + committed_pages_bits->set(page_index); |
| } |
| } |
| return true; |
| @@ -387,6 +423,44 @@ void DumpProcessesMemoryMapsInShortFormat( |
| } |
| } |
| +void DumpProcessesMemoryMapsInExtendedFormat( |
| + const std::vector<ProcessMemory>& processes_memory) { |
| + std::string buf; |
| + std::string app_shared_buf; |
| + for (std::vector<ProcessMemory>::const_iterator it = processes_memory.begin(); |
| + it != processes_memory.end(); ++it) { |
| + const ProcessMemory& process_memory = *it; |
| + std::cout << "[ PID=" << process_memory.pid << "]" << '\n'; |
| + const std::vector<MemoryMap>& memory_maps = process_memory.memory_maps; |
| + for (std::vector<MemoryMap>::const_iterator it = memory_maps.begin(); |
| + it != memory_maps.end(); ++it) { |
| + const MemoryMap& memory_map = *it; |
| + app_shared_buf.clear(); |
| + AppendAppSharedField(memory_map.app_shared_counts, &app_shared_buf); |
| + std::string pages_bits(memory_map.committed_pages_bits.getData(), |
| + memory_map.committed_pages_bits.getLength()); |
| + std::string encoded_page_bits; |
| + base::Base64Encode(pages_bits, &encoded_page_bits); |
| + base::SStringPrintf( |
| + &buf, |
| + "%x-%x %s %x private_unevictable=%d private=%d shared_app=%s " |
| + "shared_other_unevictable=%d shared_other=%d \"%s\" [%s]\n", |
| + memory_map.start_address, |
| + memory_map.end_address, |
| + memory_map.flags.c_str(), |
| + memory_map.offset, |
| + memory_map.unevictable_private_count * PAGE_SIZE, |
| + memory_map.private_count * PAGE_SIZE, |
| + app_shared_buf.c_str(), |
| + memory_map.unevictable_other_shared_count * PAGE_SIZE, |
| + memory_map.other_shared_count * PAGE_SIZE, |
| + memory_map.name.c_str(), |
| + encoded_page_bits.c_str()); |
| + std::cout << buf; |
| + } |
| + } |
| +} |
| + |
| bool CollectProcessMemoryInformation(int page_count_fd, |
| int page_flags_fd, |
| ProcessMemory* process_memory) { |
| @@ -404,7 +478,8 @@ bool CollectProcessMemoryInformation(int page_count_fd, |
| for (std::vector<MemoryMap>::iterator it = process_maps->begin(); |
| it != process_maps->end(); ++it) { |
| std::vector<PageInfo>* const committed_pages = &it->committed_pages; |
| - GetPagesForMemoryMap(pagemap_fd, *it, committed_pages); |
| + 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.
|
| + GetPagesForMemoryMap(pagemap_fd, *it, committed_pages, pages_bits); |
| SetPagesInfo(page_count_fd, page_flags_fd, committed_pages); |
| } |
| return true; |
| @@ -420,17 +495,17 @@ void KillAll(const std::vector<pid_t>& pids, int signal_number) { |
| } // namespace |
| int main(int argc, char** argv) { |
| - bool short_output = false; |
| if (argc == 1) { |
| - LOG(ERROR) << "Usage: " << argv[0] << " [-a] <PID1>... <PIDN>"; |
| + LOG(ERROR) << "Usage: " << argv[0] << " [-a|-x] <PID1>... <PIDN>"; |
| return EXIT_FAILURE; |
| } |
| - if (!strncmp(argv[1], "-a", 2)) { |
| + const bool short_output = !strncmp(argv[1], "-a", 2); |
| + const bool extended_output = !strncmp(argv[1], "-x", 2); |
| + if (short_output || extended_output) { |
| if (argc == 2) { |
| - LOG(ERROR) << "Usage: " << argv[0] << " [-a] <PID1>... <PIDN>"; |
| + LOG(ERROR) << "Usage: " << argv[0] << " [-a|-x] <PID1>... <PIDN>"; |
| return EXIT_FAILURE; |
| } |
| - short_output = true; |
| ++argv; |
| } |
| std::vector<pid_t> pids; |
| @@ -476,6 +551,8 @@ int main(int argc, char** argv) { |
| ClassifyPages(&processes_memory); |
| if (short_output) |
| DumpProcessesMemoryMapsInShortFormat(processes_memory); |
| + else if (extended_output) |
| + DumpProcessesMemoryMapsInExtendedFormat(processes_memory); |
| else |
| DumpProcessesMemoryMaps(processes_memory); |
| return EXIT_SUCCESS; |