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

Commit 378e6e4a authored by Yurii Zubrytskyi's avatar Yurii Zubrytskyi Committed by Android (Google) Code Review
Browse files

Merge "[res] Stop using try_emplace for hash maps"

parents 968d9b9d 09144887
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -232,6 +232,7 @@ cc_benchmark {
        "tests/AssetManager2_bench.cpp",
        "tests/AssetManager2_bench.cpp",
        "tests/AttributeResolution_bench.cpp",
        "tests/AttributeResolution_bench.cpp",
        "tests/CursorWindow_bench.cpp",
        "tests/CursorWindow_bench.cpp",
        "tests/Generic_bench.cpp",
        "tests/SparseEntry_bench.cpp",
        "tests/SparseEntry_bench.cpp",
        "tests/Theme_bench.cpp",
        "tests/Theme_bench.cpp",
    ],
    ],
+36 −15
Original line number Original line Diff line number Diff line
@@ -1094,14 +1094,16 @@ base::expected<std::monostate, NullOrIOError> AssetManager2::ResolveReference(


base::expected<const std::vector<uint32_t>*, NullOrIOError> AssetManager2::GetBagResIdStack(
base::expected<const std::vector<uint32_t>*, NullOrIOError> AssetManager2::GetBagResIdStack(
    uint32_t resid) const {
    uint32_t resid) const {
  auto [it, inserted] = cached_bag_resid_stacks_.try_emplace(resid);
  auto it = cached_bag_resid_stacks_.find(resid);
  if (inserted) {
  if (it != cached_bag_resid_stacks_.end()) {
    // This is a new entry in the cache, need to populate it.
    return &it->second;
    if (auto maybe_bag = GetBag(resid, it->second); UNLIKELY(IsIOError(maybe_bag))) {
      cached_bag_resid_stacks_.erase(it);
      return base::unexpected(maybe_bag.error());
  }
  }
  std::vector<uint32_t> stacks;
  if (auto maybe_bag = GetBag(resid, stacks); UNLIKELY(IsIOError(maybe_bag))) {
    return base::unexpected(maybe_bag.error());
  }
  }

  it = cached_bag_resid_stacks_.emplace(resid, std::move(stacks)).first;
  return &it->second;
  return &it->second;
}
}


@@ -1119,8 +1121,12 @@ base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
}
}


base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
  auto [resid_stacks_it, _] = cached_bag_resid_stacks_.try_emplace(resid);
  auto resid_stacks_it = cached_bag_resid_stacks_.find(resid);
  if (resid_stacks_it != cached_bag_resid_stacks_.end()) {
    resid_stacks_it->second.clear();
    resid_stacks_it->second.clear();
  } else {
    resid_stacks_it = cached_bag_resid_stacks_.emplace(resid, std::vector<uint32_t>{}).first;
  }
  const auto bag = GetBag(resid, resid_stacks_it->second);
  const auto bag = GetBag(resid, resid_stacks_it->second);
  if (UNLIKELY(IsIOError(bag))) {
  if (UNLIKELY(IsIOError(bag))) {
    cached_bag_resid_stacks_.erase(resid_stacks_it);
    cached_bag_resid_stacks_.erase(resid_stacks_it);
@@ -1438,25 +1444,40 @@ void AssetManager2::RebuildFilterList() {
}
}


void AssetManager2::InvalidateCaches(uint32_t diff) {
void AssetManager2::InvalidateCaches(uint32_t diff) {
  cached_bag_resid_stacks_.clear();
  cached_resolved_values_.clear();


  if (diff == 0xffffffffu) {
  if (diff == 0xffffffffu) {
    // Everything must go.
    // Everything must go.
    cached_bags_.clear();
    cached_bags_.clear();
    cached_bag_resid_stacks_.clear();
    return;
    return;
  }
  }


  // Be more conservative with what gets purged. Only if the bag has other possible
  // Be more conservative with what gets purged. Only if the bag has other possible
  // variations with respect to what changed (diff) should we remove it.
  // variations with respect to what changed (diff) should we remove it.
  for (auto iter = cached_bags_.cbegin(); iter != cached_bags_.cend();) {
  for (auto stack_it = cached_bag_resid_stacks_.begin();
    if (diff & iter->second->type_spec_flags) {
       stack_it != cached_bag_resid_stacks_.end();) {
      iter = cached_bags_.erase(iter);
    const auto it = cached_bags_.find(stack_it->first);
    if (it == cached_bags_.end()) {
      stack_it = cached_bag_resid_stacks_.erase(stack_it);
    } else if ((diff & it->second->type_spec_flags) != 0) {
      cached_bags_.erase(it);
      stack_it = cached_bag_resid_stacks_.erase(stack_it);
    } else {
    } else {
      ++iter;
      ++stack_it;  // Keep the item in both caches.
    }
    }
  }
  }


  cached_resolved_values_.clear();
  // Need to ensure that both bag caches are consistent, as we populate them in the same function.
  // Iterate over the cached bags to erase the items without the corresponding resid_stack cache
  // items.
  for (auto it = cached_bags_.begin(); it != cached_bags_.end();) {
    if ((diff & it->second->type_spec_flags) != 0) {
      it = cached_bags_.erase(it);
    } else {
      ++it;
    }
  }
}
}


uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
+146 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2016 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 <stdint.h>

#include <map>
#include <unordered_map>

#include "benchmark/benchmark.h"

namespace android {

template <class Map = std::unordered_map<uint32_t, std::vector<uint32_t>>>
static Map prepare_map() {
  Map map;
  std::vector<uint32_t> vec;
  for (int i = 0; i < 1000; ++i) {
    map.emplace(i, vec);
  }
  return map;
}

static void BM_hashmap_emplace_same(benchmark::State& state) {
  auto map = prepare_map<>();
  auto val = map.size() - 1;
  std::vector<uint32_t> vec;
  for (auto&& _ : state) {
    benchmark::DoNotOptimize(map.emplace(val, vec));
  }
}
BENCHMARK(BM_hashmap_emplace_same);
static void BM_hashmap_try_emplace_same(benchmark::State& state) {
  auto map = prepare_map();
  auto val = map.size() - 1;
  for (auto&& _ : state) {
    benchmark::DoNotOptimize(map.try_emplace(val));
  }
}
BENCHMARK(BM_hashmap_try_emplace_same);
static void BM_hashmap_find(benchmark::State& state) {
  auto map = prepare_map<>();
  auto val = map.size() - 1;
  for (auto&& _ : state) {
    benchmark::DoNotOptimize(map.find(val));
  }
}
BENCHMARK(BM_hashmap_find);

static void BM_hashmap_emplace_diff(benchmark::State& state) {
  auto map = prepare_map<>();
  std::vector<uint32_t> vec;
  auto i = map.size();
  for (auto&& _ : state) {
    map.emplace(i++, vec);
  }
}
BENCHMARK(BM_hashmap_emplace_diff);
static void BM_hashmap_try_emplace_diff(benchmark::State& state) {
  auto map = prepare_map();
  auto i = map.size();
  for (auto&& _ : state) {
    map.try_emplace(i++);
  }
}
BENCHMARK(BM_hashmap_try_emplace_diff);
static void BM_hashmap_find_emplace_diff(benchmark::State& state) {
  auto map = prepare_map<>();
  std::vector<uint32_t> vec;
  auto i = map.size();
  for (auto&& _ : state) {
    if (map.find(i++) == map.end()) {
      map.emplace(i - 1, vec);
    }
  }
}
BENCHMARK(BM_hashmap_find_emplace_diff);

static void BM_treemap_emplace_same(benchmark::State& state) {
  auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
  auto val = map.size() - 1;
  std::vector<uint32_t> vec;
  for (auto&& _ : state) {
    benchmark::DoNotOptimize(map.emplace(val, vec));
  }
}
BENCHMARK(BM_treemap_emplace_same);
static void BM_treemap_try_emplace_same(benchmark::State& state) {
  auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
  auto val = map.size() - 1;
  for (auto&& _ : state) {
    benchmark::DoNotOptimize(map.try_emplace(val));
  }
}
BENCHMARK(BM_treemap_try_emplace_same);
static void BM_treemap_find(benchmark::State& state) {
  auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
  auto val = map.size() - 1;
  for (auto&& _ : state) {
    benchmark::DoNotOptimize(map.find(val));
  }
}
BENCHMARK(BM_treemap_find);

static void BM_treemap_emplace_diff(benchmark::State& state) {
  auto map = prepare_map<std::map<uint32_t, std::vector<uint32_t>>>();
  std::vector<uint32_t> vec;
  auto i = map.size();
  for (auto&& _ : state) {
    map.emplace(i++, vec);
  }
}
BENCHMARK(BM_treemap_emplace_diff);
static void BM_treemap_try_emplace_diff(benchmark::State& state) {
  auto map = prepare_map();
  auto i = map.size();
  for (auto&& _ : state) {
    map.try_emplace(i++);
  }
}
BENCHMARK(BM_treemap_try_emplace_diff);
static void BM_treemap_find_emplace_diff(benchmark::State& state) {
  auto map = prepare_map();
  std::vector<uint32_t> vec;
  auto i = map.size();
  for (auto&& _ : state) {
    if (map.find(i++) == map.end()) {
      map.emplace(i - 1, vec);
    }
  }
}
BENCHMARK(BM_treemap_find_emplace_diff);

}  // namespace android
 No newline at end of file