Add new LocalUpdatableMaps benchmarks.

In addition, move a couple of elf benchmarks out of unwind_benchmarks.cpp
to the ElfBenchmarks.cpp file.

Test: Ran benchmarks.
Change-Id: I169f89f7b2dd6735568143f2176301e181fb8262
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index f3d3f27..601904a 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -411,6 +411,7 @@
     srcs: [
         "benchmarks/unwind_benchmarks.cpp",
         "benchmarks/ElfBenchmark.cpp",
+        "benchmarks/MapsBenchmark.cpp",
         "benchmarks/SymbolBenchmark.cpp",
         "benchmarks/Utils.cpp",
     ],
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
index c108a2a..a46bd7a 100644
--- a/libunwindstack/benchmarks/ElfBenchmark.cpp
+++ b/libunwindstack/benchmarks/ElfBenchmark.cpp
@@ -23,7 +23,9 @@
 #include <benchmark/benchmark.h>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
 
 #include "Utils.h"
 
@@ -75,3 +77,66 @@
   BenchmarkElfCreate(state, GetCompressedElfFile());
 }
 BENCHMARK(BM_elf_create_compressed);
+
+static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
+                              unwindstack::MapInfo** build_id_map_info) {
+  if (!maps.Parse()) {
+    state.SkipWithError("Failed to parse local maps.");
+    return;
+  }
+
+  // Find the libc.so share library and use that for benchmark purposes.
+  *build_id_map_info = nullptr;
+  for (auto& map_info : maps) {
+    if (map_info->offset == 0 && map_info->GetBuildID() != "") {
+      *build_id_map_info = map_info.get();
+      break;
+    }
+  }
+
+  if (*build_id_map_info == nullptr) {
+    state.SkipWithError("Failed to find a map with a BuildID.");
+  }
+}
+
+static void BM_elf_get_build_id_from_object(benchmark::State& state) {
+  unwindstack::LocalMaps maps;
+  unwindstack::MapInfo* build_id_map_info;
+  InitializeBuildId(state, maps, &build_id_map_info);
+
+  unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
+                                                    unwindstack::Regs::CurrentArch());
+  if (!elf->valid()) {
+    state.SkipWithError("Cannot get valid elf from map.");
+  }
+
+  for (auto _ : state) {
+    state.PauseTiming();
+    uintptr_t id = build_id_map_info->build_id;
+    if (id != 0) {
+      delete reinterpret_cast<std::string*>(id);
+      build_id_map_info->build_id = 0;
+    }
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+  }
+}
+BENCHMARK(BM_elf_get_build_id_from_object);
+
+static void BM_elf_get_build_id_from_file(benchmark::State& state) {
+  unwindstack::LocalMaps maps;
+  unwindstack::MapInfo* build_id_map_info;
+  InitializeBuildId(state, maps, &build_id_map_info);
+
+  for (auto _ : state) {
+    state.PauseTiming();
+    uintptr_t id = build_id_map_info->build_id;
+    if (id != 0) {
+      delete reinterpret_cast<std::string*>(id);
+      build_id_map_info->build_id = 0;
+    }
+    state.ResumeTiming();
+    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
+  }
+}
+BENCHMARK(BM_elf_get_build_id_from_file);
diff --git a/libunwindstack/benchmarks/MapsBenchmark.cpp b/libunwindstack/benchmarks/MapsBenchmark.cpp
new file mode 100644
index 0000000..be106a3
--- /dev/null
+++ b/libunwindstack/benchmarks/MapsBenchmark.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 <stdint.h>
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+
+class BenchmarkLocalUpdatableMaps : public unwindstack::LocalUpdatableMaps {
+ public:
+  BenchmarkLocalUpdatableMaps() : unwindstack::LocalUpdatableMaps() {}
+  virtual ~BenchmarkLocalUpdatableMaps() = default;
+
+  const std::string GetMapsFile() const override { return maps_file_; }
+
+  void BenchmarkSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
+
+ private:
+  std::string maps_file_;
+};
+
+constexpr size_t kNumMaps = 10000;
+
+static void CreateInitialMap(const char* filename) {
+  std::string maps;
+  for (size_t i = 0; i < kNumMaps; i += 2) {
+    maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 1000,
+                                        (i + 1) * 1000, i);
+  }
+  if (!android::base::WriteStringToFile(maps, filename)) {
+    errx(1, "WriteStringToFile failed");
+  }
+}
+
+static void CreateReparseMap(const char* filename) {
+  std::string maps;
+  for (size_t i = 0; i < kNumMaps; i++) {
+    maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 2000,
+                                        (i + 1) * 2000, 2 * i);
+  }
+  if (!android::base::WriteStringToFile(maps, filename)) {
+    errx(1, "WriteStringToFile failed");
+  }
+}
+
+void BM_local_updatable_maps_reparse(benchmark::State& state) {
+  TemporaryFile initial_map;
+  CreateInitialMap(initial_map.path);
+
+  TemporaryFile reparse_map;
+  CreateReparseMap(reparse_map.path);
+
+  for (auto _ : state) {
+    BenchmarkLocalUpdatableMaps maps;
+    maps.BenchmarkSetMapsFile(initial_map.path);
+    if (!maps.Reparse()) {
+      errx(1, "Internal Error: reparse of initial maps filed.");
+    }
+    if (maps.Total() != (kNumMaps / 2)) {
+      errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+           kNumMaps / 2);
+    }
+    maps.BenchmarkSetMapsFile(reparse_map.path);
+    if (!maps.Reparse()) {
+      errx(1, "Internal Error: reparse of second set of maps filed.");
+    }
+    if (maps.Total() != kNumMaps) {
+      errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
+           kNumMaps);
+    }
+  }
+}
+BENCHMARK(BM_local_updatable_maps_reparse);
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
index de9137a..0bee6ef 100644
--- a/libunwindstack/benchmarks/unwind_benchmarks.cpp
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -22,7 +22,6 @@
 
 #include <android-base/strings.h>
 
-#include <unwindstack/Elf.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
@@ -83,63 +82,4 @@
 }
 BENCHMARK(BM_cached_unwind);
 
-static void Initialize(benchmark::State& state, unwindstack::Maps& maps,
-                       unwindstack::MapInfo** build_id_map_info) {
-  if (!maps.Parse()) {
-    state.SkipWithError("Failed to parse local maps.");
-    return;
-  }
-
-  // Find the libc.so share library and use that for benchmark purposes.
-  *build_id_map_info = nullptr;
-  for (auto& map_info : maps) {
-    if (map_info->offset == 0 && map_info->GetBuildID() != "") {
-      *build_id_map_info = map_info.get();
-      break;
-    }
-  }
-
-  if (*build_id_map_info == nullptr) {
-    state.SkipWithError("Failed to find a map with a BuildID.");
-  }
-}
-
-static void BM_get_build_id_from_elf(benchmark::State& state) {
-  unwindstack::LocalMaps maps;
-  unwindstack::MapInfo* build_id_map_info;
-  Initialize(state, maps, &build_id_map_info);
-
-  unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
-                                                    unwindstack::Regs::CurrentArch());
-  if (!elf->valid()) {
-    state.SkipWithError("Cannot get valid elf from map.");
-  }
-
-  for (auto _ : state) {
-    uintptr_t id = build_id_map_info->build_id;
-    if (id != 0) {
-      delete reinterpret_cast<std::string*>(id);
-      build_id_map_info->build_id = 0;
-    }
-    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
-  }
-}
-BENCHMARK(BM_get_build_id_from_elf);
-
-static void BM_get_build_id_from_file(benchmark::State& state) {
-  unwindstack::LocalMaps maps;
-  unwindstack::MapInfo* build_id_map_info;
-  Initialize(state, maps, &build_id_map_info);
-
-  for (auto _ : state) {
-    uintptr_t id = build_id_map_info->build_id;
-    if (id != 0) {
-      delete reinterpret_cast<std::string*>(id);
-      build_id_map_info->build_id = 0;
-    }
-    benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
-  }
-}
-BENCHMARK(BM_get_build_id_from_file);
-
 BENCHMARK_MAIN();