Loading libs/androidfw/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -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", ], ], Loading libs/androidfw/AssetManager2.cpp +36 −15 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading @@ -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); Loading Loading @@ -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 { Loading libs/androidfw/tests/Generic_bench.cpp 0 → 100644 +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 Loading
libs/androidfw/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -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", ], ], Loading
libs/androidfw/AssetManager2.cpp +36 −15 Original line number Original line Diff line number Diff line Loading @@ -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; } } Loading @@ -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); Loading Loading @@ -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 { Loading
libs/androidfw/tests/Generic_bench.cpp 0 → 100644 +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