Add benchmark for property mapping
This benchmarks mapping property prefixes to property contexts with two algorithms: the 'Legacy' method used before Android P and the 'Trie' used afterwards (the code in this directory). It uses input mappings from both Oreo and the latest in AOSP ('S'). Note that there is nearly a 10x increase in the number of mappings in S as there was in Oreo, which was predicted when the trie was designed. Results on cuttlefish: ----------------------------------------------------------- Benchmark Time CPU Iterations ----------------------------------------------------------- LegacyLookupOreo 683576 ns 673538 ns 1060 LegacyLookupS 5683109 ns 5596982 ns 124 TrieLookupOreo 299851 ns 295696 ns 2378 TrieLookupS 584831 ns 576801 ns 1204 The results show that the legacy look up uses 8.3x more CPU time to handle the number of mappings added through S, whereas the Trie lookup uses less than 2x more CPU time, showing that the trie scales better with added mappings. Test: run this benchmark Change-Id: I35c3aa4429f049e327a891f9cbe1901d8855d7ba
This commit is contained in:
parent
159bb3f86b
commit
a5744e213f
6 changed files with 1200 additions and 2 deletions
16
libc/NOTICE
16
libc/NOTICE
|
@ -1039,6 +1039,22 @@ SUCH DAMAGE.
|
|||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2020 The Android Open Source Project
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
@ -25,3 +25,20 @@ cc_library_static {
|
|||
],
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
cc_benchmark {
|
||||
name: "property_context_lookup_benchmark",
|
||||
srcs: [
|
||||
"context_lookup_benchmark.cpp",
|
||||
],
|
||||
include_dirs: [
|
||||
"bionic/libc",
|
||||
],
|
||||
|
||||
shared_libs: ["libbase"],
|
||||
static_libs: [
|
||||
"libpropertyinfoserializer",
|
||||
"libsystemproperties",
|
||||
"libasync_safe",
|
||||
],
|
||||
}
|
||||
|
|
145
libc/system_properties/context_lookup_benchmark.cpp
Normal file
145
libc/system_properties/context_lookup_benchmark.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <property_info_parser/property_info_parser.h>
|
||||
#include <property_info_serializer/property_info_serializer.h>
|
||||
#include <system_properties/contexts_split.h>
|
||||
|
||||
#include "context_lookup_benchmark_data.h"
|
||||
|
||||
using android::base::Split;
|
||||
using android::base::WriteStringToFd;
|
||||
using android::properties::BuildTrie;
|
||||
using android::properties::ParsePropertyInfoFile;
|
||||
using android::properties::PropertyInfoArea;
|
||||
using android::properties::PropertyInfoEntry;
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
|
||||
class LegacyPropertyMapping : public ContextsSplit {
|
||||
public:
|
||||
LegacyPropertyMapping(const char* property_contexts) {
|
||||
TemporaryFile file;
|
||||
if (!WriteStringToFd(property_contexts, file.fd)) {
|
||||
PLOG(FATAL) << "Could not write to temporary file";
|
||||
}
|
||||
|
||||
if (!InitializePropertiesFromFile(file.path)) {
|
||||
LOG(FATAL) << "Could not initialize properties";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static std::vector<std::string> PropertiesToLookup() {
|
||||
std::vector<std::string> properties;
|
||||
auto property_lines = Split(aosp_s_property_contexts, "\n");
|
||||
for (const auto& line : property_lines) {
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto property = Split(line, " ")[0];
|
||||
properties.push_back(property);
|
||||
properties.push_back(property + "0");
|
||||
properties.push_back(property + "A");
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
static void LegacyLookupOreo(benchmark::State& state) {
|
||||
LegacyPropertyMapping mapping(oreo_property_contexts);
|
||||
auto properties = PropertiesToLookup();
|
||||
for (auto _ : state) {
|
||||
for (const auto& property : properties) {
|
||||
benchmark::DoNotOptimize(mapping.GetPrefixNodeForName(property.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(LegacyLookupOreo);
|
||||
|
||||
static void LegacyLookupS(benchmark::State& state) {
|
||||
LegacyPropertyMapping mapping(aosp_s_property_contexts);
|
||||
auto properties = PropertiesToLookup();
|
||||
for (auto _ : state) {
|
||||
for (const auto& property : properties) {
|
||||
benchmark::DoNotOptimize(mapping.GetPrefixNodeForName(property.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(LegacyLookupS);
|
||||
|
||||
static std::string CreateSerializedTrie(const char* input_file) {
|
||||
std::vector<std::string> errors;
|
||||
std::vector<PropertyInfoEntry> property_infos;
|
||||
ParsePropertyInfoFile(input_file, false, &property_infos, &errors);
|
||||
|
||||
std::string serialized_trie;
|
||||
std::string error;
|
||||
if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_trie,
|
||||
&error)) {
|
||||
LOG(FATAL) << "Could not build trie: " << error;
|
||||
}
|
||||
return serialized_trie;
|
||||
}
|
||||
|
||||
static void TrieLookupOreo(benchmark::State& state) {
|
||||
std::string serialized_trie = CreateSerializedTrie(oreo_property_contexts);
|
||||
PropertyInfoArea* trie = reinterpret_cast<PropertyInfoArea*>(serialized_trie.data());
|
||||
auto properties = PropertiesToLookup();
|
||||
for (auto _ : state) {
|
||||
for (const auto& property : properties) {
|
||||
trie->GetPropertyInfo(property.c_str(), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(TrieLookupOreo);
|
||||
|
||||
static void TrieLookupS(benchmark::State& state) {
|
||||
std::string serialized_trie = CreateSerializedTrie(aosp_s_property_contexts);
|
||||
PropertyInfoArea* trie = reinterpret_cast<PropertyInfoArea*>(serialized_trie.data());
|
||||
auto properties = PropertiesToLookup();
|
||||
for (auto _ : state) {
|
||||
for (const auto& property : properties) {
|
||||
trie->GetPropertyInfo(property.c_str(), nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
BENCHMARK(TrieLookupS);
|
1012
libc/system_properties/context_lookup_benchmark_data.h
Normal file
1012
libc/system_properties/context_lookup_benchmark_data.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -324,10 +324,16 @@ bool ContextsSplit::Initialize(bool writable, const char* filename, bool* fsetxa
|
|||
return true;
|
||||
}
|
||||
|
||||
prop_area* ContextsSplit::GetPropAreaForName(const char* name) {
|
||||
PrefixNode* ContextsSplit::GetPrefixNodeForName(const char* name) {
|
||||
auto entry = ListFind(prefixes_, [name](PrefixNode* l) {
|
||||
return l->prefix[0] == '*' || !strncmp(l->prefix, name, l->prefix_len);
|
||||
});
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
prop_area* ContextsSplit::GetPropAreaForName(const char* name) {
|
||||
auto entry = GetPrefixNodeForName(name);
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ class ContextsSplit : public Contexts {
|
|||
virtual void ResetAccess() override;
|
||||
virtual void FreeAndUnmap() override;
|
||||
|
||||
private:
|
||||
PrefixNode* GetPrefixNodeForName(const char* name);
|
||||
|
||||
protected:
|
||||
bool MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed);
|
||||
bool InitializePropertiesFromFile(const char* filename);
|
||||
bool InitializeProperties();
|
||||
|
|
Loading…
Reference in a new issue