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:
Tom Cherry 2020-09-01 22:35:56 +00:00
parent 159bb3f86b
commit a5744e213f
6 changed files with 1200 additions and 2 deletions

View file

@ -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.

View file

@ -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",
],
}

View 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);

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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();