summaryrefslogtreecommitdiff
path: root/libunwindstack/Memory.cpp
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2020-04-14 16:59:27 +0100
committerChristopher Ferris <cferris@google.com>2020-04-16 15:03:19 -0700
commitc5fb3c70d63a563920b9addd5c5c5f99d6cf6299 (patch)
tree4705985260a47ab273ec55704968ae5451a2e37b /libunwindstack/Memory.cpp
parent3a59f8d684cbeb5ebcfd3bac095f8284167a7b04 (diff)
downloadunwinding-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.cpp34
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;
}