diff options
author | David Srbecky <dsrbecky@google.com> | 2020-04-14 16:59:27 +0100 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2020-04-16 15:03:19 -0700 |
commit | c5fb3c70d63a563920b9addd5c5c5f99d6cf6299 (patch) | |
tree | 4705985260a47ab273ec55704968ae5451a2e37b /libunwindstack/Memory.cpp | |
parent | 3a59f8d684cbeb5ebcfd3bac095f8284167a7b04 (diff) | |
download | unwinding-c5fb3c70d63a563920b9addd5c5c5f99d6cf6299.tar.gz |
Optimize Memory::ReadString
This function is responsible for majority of CPU time in prefetto.
Reduce the number of memory reads (don't read strings byte-by-byte).
Update all calls of ReadString to include the third parameter to have
a max read.
Add an Elf creation benchmark since this function is on the elf
creation path.
Test: libunwindstack_unit_test
Change-Id: Ia36e1f1a5ba76c9e9f13c43fb9e3691dde7897f2
Diffstat (limited to 'libunwindstack/Memory.cpp')
-rw-r--r-- | libunwindstack/Memory.cpp | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp index 8de3d98..e142b97 100644 --- a/libunwindstack/Memory.cpp +++ b/libunwindstack/Memory.cpp @@ -158,20 +158,30 @@ bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) { return rc == size; } -bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) { - string->clear(); - uint64_t bytes_read = 0; - while (bytes_read < max_read) { - uint8_t value; - if (!ReadFully(addr, &value, sizeof(value))) { - return false; +bool Memory::ReadString(uint64_t addr, std::string* dst, size_t max_read) { + char buffer[256]; // Large enough for 99% of symbol names. + size_t size = 0; // Number of bytes which were read into the buffer. + for (size_t offset = 0; offset < max_read; offset += size) { + // Look for null-terminator first, so we can allocate string of exact size. + // If we know the end of valid memory range, do the reads in larger blocks. + size_t read = std::min(sizeof(buffer), max_read - offset); + size = Read(addr + offset, buffer, read); + if (size == 0) { + return false; // We have not found end of string yet and we can not read more data. } - if (value == '\0') { - return true; + size_t length = strnlen(buffer, size); // Index of the null-terminator. + if (length < size) { + // We found the null-terminator. Allocate the string and set its content. + if (offset == 0) { + // We did just single read, so the buffer already contains the whole string. + dst->assign(buffer, length); + return true; + } else { + // The buffer contains only the last block. Read the whole string again. + dst->assign(offset + length, '\0'); + return ReadFully(addr, dst->data(), dst->size()); + } } - string->push_back(value); - addr++; - bytes_read++; } return false; } |