| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2025 Google LLC. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file or at | |
| // https://developers.google.com/open-source/licenses/bsd | |
| #include <cstddef> | |
| #include <string> | |
| #include <type_traits> | |
| #include <vector> | |
| #include <benchmark/benchmark.h> | |
| #include <gtest/gtest.h> | |
| #include "absl/container/flat_hash_set.h" | |
| #include "upb/mem/alloc.h" | |
| #include "upb/mem/arena.h" | |
| #include "upb/message/message.h" | |
| #include "upb/mini_table/message.h" | |
| #include "upb/wire/decode.h" | |
| #include "upb/wire/decode_fast/combinations.h" | |
| #include "upb/wire/test_util/field_types.h" | |
| #include "upb/wire/test_util/make_mini_table.h" | |
| #include "upb/wire/test_util/wire_message.h" | |
| // Must be last. | |
| #include "upb/port/def.inc" | |
| namespace upb { | |
| namespace test { | |
| namespace { | |
| void BM_Decode(benchmark::State& state, const upb_MiniTable* mt, | |
| std::string payload, bool alias, bool initial_block) { | |
| char mem[4096]; | |
| int decode_options = 0; | |
| for (auto s : state) { | |
| upb_Arena* arena = initial_block | |
| ? upb_Arena_Init(mem, 4096, &upb_alloc_global) | |
| : upb_Arena_New(); | |
| upb_Message* msg = upb_Message_New(mt, arena); | |
| upb_DecodeStatus result = upb_Decode(payload.data(), payload.size(), msg, | |
| mt, nullptr, decode_options, arena); | |
| ASSERT_EQ(result, kUpb_DecodeStatus_Ok) << upb_DecodeStatus_String(result); | |
| upb_Arena_Free(arena); | |
| } | |
| state.SetBytesProcessed(state.iterations() * payload.size()); | |
| } | |
| [[maybe_unused]] upb_Arena* benchmark_registration = [] { | |
| upb_Arena* arena = upb_Arena_New(); | |
| std::vector<size_t> sizes{8, 64, 512}; | |
| for (size_t size : sizes) { | |
| absl::flat_hash_set<upb_DecodeFast_Type> fast_types; | |
| ForEachType([&](auto&& type) { | |
| using Type = std::remove_reference_t<decltype(type)>; | |
| // We only need to benchmark each wire type once, since they are all | |
| // treated the same by the decoder. | |
| if (!fast_types.insert(Type::kFastType).second) return; | |
| std::vector<bool> initial_block{true, false}; | |
| for (bool init : initial_block) { | |
| auto [mt, field] = MiniTable::MakeSingleFieldTable<Type>( | |
| 1, kUpb_DecodeFast_Scalar, arena); | |
| std::string payload; | |
| while (payload.size() < size) { | |
| payload.append(ToBinaryPayload(wire_types::WireMessage{ | |
| {1, Type::WireValue(typename Type::Value{})}})); | |
| } | |
| ::benchmark::RegisterBenchmark( | |
| absl::StrFormat("BM_Decode/%s/%zu/%s", Type::kName, size, | |
| init ? "InitialBlock" : "NoInitialBlock") | |
| .c_str(), | |
| BM_Decode, mt, payload, false, init); | |
| } | |
| }); | |
| } | |
| return arena; | |
| }(); | |
| } // namespace | |
| } // namespace test | |
| } // namespace upb |