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..cf43abab582a7ef26a5bab90cdeada055089d5bb 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,31 @@ |
| namespace { |
| +class BitSet { |
| + public: |
| + BitSet() : data_(0) {} |
| + |
| + void resize(int nbits) { |
|
bulach
2013/07/23 08:10:58
nit: size_t
Primiano Tucci (use gerrit)
2013/07/23 08:54:00
Done.
|
| + data_.resize((nbits + 7) / 8); |
| + } |
| + |
| + void set(int bit) { |
|
bulach
2013/07/23 08:10:58
nit: uint32
Primiano Tucci (use gerrit)
2013/07/23 08:54:00
Done.
|
| + const int byte_idx = bit / 8; |
| + CHECK(byte_idx < data_.size()); |
| + data_[byte_idx] |= (1 << (bit & 7)); |
| + } |
| + |
| + const std::string AsB64String() const { |
| + std::string bits(&data_[0], data_.size()); |
| + std::string b64_string; |
| + base::Base64Encode(bits, &b64_string); |
| + return b64_string; |
| + } |
| + |
| + private: |
| + std::vector<char> data_; |
|
bulach
2013/07/23 08:10:58
nit: uint8
Primiano Tucci (use gerrit)
2013/07/23 08:54:00
Hmm if I do that, than I have to add more boilerpl
|
| +}; |
| + |
| // An entry in /proc/<pid>/pagemap. |
| struct PageMapEntry { |
| uint64 page_frame_number : 55; |
| @@ -49,6 +75,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 +84,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 bitset reflecting the present bit for all the |
| + // virtual pages of the mapping. |
| + BitSet committed_pages_bits; |
| }; |
| struct ProcessMemory { |
| @@ -114,6 +144,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.resize( |
| + (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 +202,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 +219,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 +425,40 @@ 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); |
| + 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(), |
| + memory_map.committed_pages_bits.AsB64String().c_str()); |
| + std::cout << buf; |
| + } |
| + } |
| +} |
| + |
| bool CollectProcessMemoryInformation(int page_count_fd, |
| int page_flags_fd, |
| ProcessMemory* process_memory) { |
| @@ -404,7 +476,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* const pages_bits = &it->committed_pages_bits; |
| + GetPagesForMemoryMap(pagemap_fd, *it, committed_pages, pages_bits); |
| SetPagesInfo(page_count_fd, page_flags_fd, committed_pages); |
| } |
| return true; |
| @@ -420,17 +493,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 +549,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; |