/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 #include #include #include #include #include #include #include namespace apache::thrift::test::patch { using ListPatch = folly::remove_cvref_t< decltype(*std::declval()->optListVal())>; using ListDequePatch = folly::remove_cvref_t< decltype(*std::declval()->longList())>; using SetPatch = folly::remove_cvref_t< decltype(*std::declval()->optSetVal())>; using MapPatch = folly::remove_cvref_t< decltype(*std::declval()->optMapVal())>; using ListStringPatch = folly::remove_cvref_t< decltype(*std::declval()->strings())>; // We apply/merge the patch N times to get a fairly complex patching. // This is also used as the max index and key in list/set/map patch. constexpr int N = 10; std::mt19937 rng; auto randInt() { return rng() % N; } auto randStr() { return std::to_string(randInt()); } auto randLongStr() { return std::string(randInt() * 10, '0'); } template static inline const auto patches = std::invoke([] { rng.seed(0); using Patch = std::invoke_result_t; std::array ret; std::generate_n(ret.begin(), N, PatchGenerator{}); return ret; }); template void benchmarkApply() { typename std::invoke_result_t::value_type value; for (auto i = 0; i < N; i++) { patches[i].apply(value); } } template void benchmarkMerge() { std::invoke_result_t patch; for (auto i = 0; i < N; i++) { patch.merge(patches[i]); } } struct GenListPatch { ListPatch operator()() { ListPatch p; p.push_back(randInt()); return p; } }; BENCHMARK(ApplyListPatch) { benchmarkApply(); } BENCHMARK(MergeListPatch) { benchmarkMerge(); } struct GenListDequePatch { ListDequePatch operator()() { ListDequePatch p; p.push_back(randInt()); return p; } }; BENCHMARK(ApplyListDequePatch) { benchmarkApply(); } BENCHMARK(MergeListDequePatch) { benchmarkMerge(); } struct GenSetPatch { SetPatch operator()() { SetPatch p; p.insert(randStr()); p.erase(randStr()); return p; } }; BENCHMARK(ApplySetPatch) { benchmarkApply(); } BENCHMARK(MergeSetPatch) { benchmarkMerge(); } struct GenMapPatch { MapPatch operator()() { MapPatch p; p.erase(randStr()); p.patchByKey(randStr()) += randStr(); p.ensureAndPatchByKey(randStr()) += randStr(); return p; } }; BENCHMARK(ApplyMapPatch) { benchmarkApply(); } BENCHMARK(MergeMapPatch) { benchmarkMerge(); } void patchIfSetNonOptionalFields(MyStructPatch& result) { result.patchIfSet() = !op::BoolPatch{}; result.patchIfSet() += 1; result.patchIfSet() += 2; result.patchIfSet() += 3; result.patchIfSet() += 4; result.patchIfSet() += 5; result.patchIfSet() += 6; result.patchIfSet() = "(" + op::StringPatch{} + ")"; result.patchIfSet() = "<" + op::BinaryPatch{} + ">"; result.patchIfSet() = MyEnum::MyValue9; result.patchIfSet().patchIfSet().append("X"); result.patchIfSet().patchIfSet().append("Y"); result.patchIfSet() = GenListDequePatch{}(); } void patchIfSetOptionalFields(MyStructPatch& result) { result.patchIfSet() = !op::BoolPatch{}; result.patchIfSet() += 1; result.patchIfSet() += 2; result.patchIfSet() += 3; result.patchIfSet() += 4; result.patchIfSet() += 5; result.patchIfSet() += 6; result.patchIfSet() = "(" + op::StringPatch{} + ")"; result.patchIfSet() = "<" + op::BinaryPatch{} + ">"; result.patchIfSet() = MyEnum::MyValue9; result.patchIfSet().patchIfSet().append( "X"); result.patchIfSet() = GenListPatch{}(); result.patchIfSet() = GenSetPatch{}(); result.patchIfSet() = GenMapPatch{}(); } void ensureNonOptionalFields(MyStructPatch& result) { result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); result.ensure(); } void ensureOptionalFields(MyStructPatch& result) { result.ensure(true); result.ensure(1); result.ensure(2); result.ensure(3); result.ensure(4); result.ensure(5); result.ensure(6); result.ensure("7"); result.ensure(folly::IOBuf::wrapBufferAsValue("8", 1)); result.ensure(MyEnum::MyValue9); result.ensure([] { MyData data; data.data1() = "10"; return data; }()); result.ensure({11}); result.ensure({"10", "20"}); result.ensure({{"10", "1"}, {"20", "2"}}); } struct GenComplexPatch { MyStructPatch operator()() { MyStructPatch patch; patchIfSetNonOptionalFields(patch); patchIfSetOptionalFields(patch); ensureNonOptionalFields(patch); ensureOptionalFields(patch); patchIfSetNonOptionalFields(patch); patchIfSetOptionalFields(patch); return patch; } }; BENCHMARK(ApplyComplexPatch) { benchmarkApply(); } BENCHMARK(MergeComplexPatch) { benchmarkMerge(); } struct GenListLongStringPatch { ListStringPatch operator()() { ListStringPatch p; p.push_back(randLongStr()); return p; } }; BENCHMARK(ApplyListLongStringPatch) { benchmarkApply(); } BENCHMARK(MergeListLongStringPatch) { benchmarkApply(); } } // namespace apache::thrift::test::patch int main(int argc, char** argv) { folly::init(&argc, &argv); folly::runBenchmarks(); }