Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cec90ea2 authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Optimize Memory::ReadString"

parents 7481072f a17c2b69
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -395,7 +395,9 @@ cc_benchmark {

    srcs: [
        "benchmarks/unwind_benchmarks.cpp",
        "benchmarks/ElfBenchmark.cpp",
        "benchmarks/SymbolBenchmark.cpp",
        "benchmarks/Utils.cpp",
    ],

    data: [
+7 −5
Original line number Diff line number Diff line
@@ -371,7 +371,7 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
      // Look for the .debug_frame and .gnu_debugdata.
      if (shdr.sh_name < sec_size) {
        std::string name;
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name)) {
          if (name == ".debug_frame") {
            debug_frame_offset_ = shdr.sh_offset;
            debug_frame_size_ = shdr.sh_size;
@@ -405,7 +405,7 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
    } else if (shdr.sh_type == SHT_NOTE) {
      if (shdr.sh_name < sec_size) {
        std::string name;
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name) &&
        if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
            name == ".note.gnu.build-id") {
          gnu_build_id_offset_ = shdr.sh_offset;
          gnu_build_id_size_ = shdr.sh_size;
@@ -456,10 +456,11 @@ std::string ElfInterface::GetSonameWithTemplate() {
  for (const auto& entry : strtabs_) {
    if (entry.first == strtab_addr) {
      soname_offset = entry.second + soname_offset;
      if (soname_offset >= entry.second + strtab_size) {
      uint64_t soname_max = entry.second + strtab_size;
      if (soname_offset >= soname_max) {
        return "";
      }
      if (!memory_->ReadString(soname_offset, &soname_)) {
      if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) {
        return "";
      }
      soname_type_ = SONAME_VALID;
@@ -608,7 +609,8 @@ bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_i
    }
    std::string name;
    if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size &&
        memory->ReadString(sec_offset + shdr.sh_name, &name) && name == ".note.gnu.build-id") {
        memory->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
        name == ".note.gnu.build-id") {
      *build_id_offset = shdr.sh_offset;
      *build_id_size = shdr.sh_size;
      return true;
+22 −12
Original line number Diff line number Diff line
@@ -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;
    }
    if (value == '\0') {
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.
    }
    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;
}
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <err.h>
#include <malloc.h>
#include <stdint.h>

#include <string>

#include <benchmark/benchmark.h>

#include <unwindstack/Elf.h>
#include <unwindstack/Memory.h>

#include "Utils.h"

static void BenchmarkElfCreate(benchmark::State& state, const std::string& elf_file) {
#if defined(__BIONIC__)
  uint64_t rss_bytes = 0;
#endif
  uint64_t alloc_bytes = 0;
  for (auto _ : state) {
    state.PauseTiming();
#if defined(__BIONIC__)
    mallopt(M_PURGE, 0);
    uint64_t rss_bytes_before = 0;
    GatherRss(&rss_bytes_before);
#endif
    uint64_t alloc_bytes_before = mallinfo().uordblks;
    auto file_memory = unwindstack::Memory::CreateFileMemory(elf_file, 0);
    state.ResumeTiming();

    unwindstack::Elf elf(file_memory.release());
    if (!elf.Init() || !elf.valid()) {
      errx(1, "Internal Error: Cannot open elf.");
    }

    state.PauseTiming();
#if defined(__BIONIC__)
    mallopt(M_PURGE, 0);
#endif
    alloc_bytes += mallinfo().uordblks - alloc_bytes_before;
#if defined(__BIONIC__)
    GatherRss(&rss_bytes);
    rss_bytes -= rss_bytes_before;
#endif
    state.ResumeTiming();
  }

#if defined(__BIONIC__)
  state.counters["RSS_BYTES"] = rss_bytes / static_cast<double>(state.iterations());
#endif
  state.counters["ALLOCATED_BYTES"] = alloc_bytes / static_cast<double>(state.iterations());
}

void BM_elf_create(benchmark::State& state) {
  BenchmarkElfCreate(state, GetElfFile());
}
BENCHMARK(BM_elf_create);

void BM_elf_create_compressed(benchmark::State& state) {
  BenchmarkElfCreate(state, GetCompressedElfFile());
}
BENCHMARK(BM_elf_create_compressed);
+7 −36
Original line number Diff line number Diff line
@@ -22,33 +22,12 @@
#include <string>
#include <vector>

#include <android-base/file.h>
#include <android-base/strings.h>
#include <benchmark/benchmark.h>

#include <unwindstack/Elf.h>
#include <unwindstack/Memory.h>

#if defined(__BIONIC__)

#include <meminfo/procmeminfo.h>
#include <procinfo/process_map.h>

static void Gather(uint64_t* rss_bytes) {
  android::meminfo::ProcMemInfo proc_mem(getpid());
  const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats();
  for (auto& vma : maps) {
    if (vma.name == "[anon:libc_malloc]" || android::base::StartsWith(vma.name, "[anon:scudo:") ||
        android::base::StartsWith(vma.name, "[anon:GWP-ASan")) {
      android::meminfo::Vma update_vma(vma);
      if (!proc_mem.FillInVmaStats(update_vma)) {
        err(1, "FillInVmaStats failed\n");
      }
      *rss_bytes += update_vma.usage.rss;
    }
  }
}
#endif
#include "Utils.h"

static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> offsets,
                                  std::string elf_file, bool expect_found) {
@@ -66,7 +45,7 @@ static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t>
#if defined(__BIONIC__)
    mallopt(M_PURGE, 0);
    uint64_t rss_bytes_before = 0;
    Gather(&rss_bytes_before);
    GatherRss(&rss_bytes_before);
#endif
    uint64_t alloc_bytes_before = mallinfo().uordblks;
    state.ResumeTiming();
@@ -88,7 +67,7 @@ static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t>
#endif
    alloc_bytes += mallinfo().uordblks - alloc_bytes_before;
#if defined(__BIONIC__)
    Gather(&rss_bytes);
    GatherRss(&rss_bytes);
    rss_bytes -= rss_bytes_before;
#endif
    state.ResumeTiming();
@@ -105,14 +84,6 @@ static void BenchmarkSymbolLookup(benchmark::State& state, uint64_t pc, std::str
  BenchmarkSymbolLookup(state, std::vector<uint64_t>{pc}, elf_file, expect_found);
}

std::string GetElfFile() {
  return android::base::GetExecutableDirectory() + "/benchmarks/files/libart_arm.so";
}

std::string GetSortedElfFile() {
  return android::base::GetExecutableDirectory() + "/benchmarks/files/boot_arm.oat";
}

void BM_symbol_not_present(benchmark::State& state) {
  BenchmarkSymbolLookup(state, 0, GetElfFile(), false);
}
@@ -136,23 +107,23 @@ void BM_symbol_find_multiple(benchmark::State& state) {
BENCHMARK(BM_symbol_find_multiple);

void BM_symbol_not_present_from_sorted(benchmark::State& state) {
  BenchmarkSymbolLookup(state, 0, GetSortedElfFile(), false);
  BenchmarkSymbolLookup(state, 0, GetSymbolSortedElfFile(), false);
}
BENCHMARK(BM_symbol_not_present_from_sorted);

void BM_symbol_find_single_from_sorted(benchmark::State& state) {
  BenchmarkSymbolLookup(state, 0x138638, GetSortedElfFile(), true);
  BenchmarkSymbolLookup(state, 0x138638, GetSymbolSortedElfFile(), true);
}
BENCHMARK(BM_symbol_find_single_from_sorted);

void BM_symbol_find_single_many_times_from_sorted(benchmark::State& state) {
  BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSortedElfFile(), true);
  BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSymbolSortedElfFile(), true);
}
BENCHMARK(BM_symbol_find_single_many_times_from_sorted);

void BM_symbol_find_multiple_from_sorted(benchmark::State& state) {
  BenchmarkSymbolLookup(state,
                        std::vector<uint64_t>{0x138638, 0x84350, 0x14df18, 0x1f3a38, 0x1f3ca8},
                        GetSortedElfFile(), true);
                        GetSymbolSortedElfFile(), true);
}
BENCHMARK(BM_symbol_find_multiple_from_sorted);
Loading