| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Benchmarks for a reference encoder / decoder specialized to |
| // Table1Struct, Table16Struct and Table256Struct as defined in |
| // the fidl benchmark suite. |
| |
| #include <algorithm> |
| #include <cstdint> |
| |
| #include "builder.h" |
| #include "decode_benchmark_util.h" |
| #include "encode_benchmark_util.h" |
| #include "util.h" |
| |
| #ifdef __Fuchsia__ |
| #include <zircon/syscalls.h> |
| #endif |
| |
| #include <lib/fit/function.h> |
| |
| namespace { |
| |
| template <size_t N> |
| bool EncodeUint8TableStruct(void* value, const char** error, |
| fit::function<void(const uint8_t*, size_t)> callback) { |
| uint8_t out_buf[sizeof(fidl_vector_t) + sizeof(fidl_envelope_t) * N + 8 * N]; |
| uint8_t* next = out_buf; |
| |
| fidl_vector_t* table_vec = reinterpret_cast<fidl_vector_t*>(value); |
| size_t count = CLEAR_COUNT_OWNERSHIP_BIT(table_vec->count); |
| void* data = CLEAR_PTR_OWNERSHIP_BIT(table_vec->data); |
| if (unlikely(data == nullptr && count != 0)) { |
| *error = "table with null data had non-zero element count"; |
| return false; |
| } |
| *reinterpret_cast<fidl_vector_t*>(next) = fidl_vector_t{ |
| .count = count, |
| .data = reinterpret_cast<void*>(FIDL_ALLOC_PRESENT), |
| }; |
| next += sizeof(fidl_vector_t); |
| |
| fidl_envelope_t* start_envelopes = reinterpret_cast<fidl_envelope_t*>(data); |
| fidl_envelope_t* end_envelopes = start_envelopes + count; |
| uint64_t* next_out_of_line = reinterpret_cast<uint64_t*>(next + count * sizeof(fidl_envelope_t)); |
| |
| for (fidl_envelope_t* envelope = start_envelopes; envelope < end_envelopes; envelope++) { |
| if (envelope->data == nullptr) { |
| *reinterpret_cast<fidl_envelope_t*>(next) = fidl_envelope_t{ |
| .num_bytes = 0, |
| .num_handles = 0, |
| // This doesn't compile when FIDL_ALLOC_ABSENT is used in place of 0. |
| .presence = 0, |
| }; |
| } else { |
| *reinterpret_cast<fidl_envelope_t*>(next) = fidl_envelope_t{ |
| .num_bytes = 8, |
| .num_handles = 0, |
| .presence = FIDL_ALLOC_PRESENT, |
| }; |
| *next_out_of_line = *reinterpret_cast<uint8_t*>(CLEAR_PTR_OWNERSHIP_BIT(envelope->data)); |
| next_out_of_line++; |
| } |
| next += sizeof(fidl_vector_t); |
| } |
| |
| callback(out_buf, static_cast<size_t>(reinterpret_cast<uint8_t*>(next_out_of_line) - out_buf)); |
| return true; |
| } |
| |
| template <size_t N> |
| bool DecodeUint8TableStruct(uint8_t* bytes, size_t bytes_size, zx_handle_t* handles, |
| size_t handles_size, const char** error) { |
| if (handles_size != 0) { |
| *error = "no handles expected"; |
| return false; |
| } |
| |
| fidl_vector_t* table_vec = reinterpret_cast<fidl_vector_t*>(bytes); |
| if (unlikely(table_vec->data == nullptr && table_vec->count != 0)) { |
| *error = "table with null data had non-zero element count"; |
| return false; |
| } |
| |
| fidl_envelope_t* start_envelopes = |
| reinterpret_cast<fidl_envelope_t*>(bytes + sizeof(fidl_vector_t)); |
| table_vec->data = start_envelopes; |
| fidl_envelope_t* end_known_envelopes = start_envelopes + std::min(N, table_vec->count); |
| fidl_envelope_t* end_all_envelopes = start_envelopes + table_vec->count; |
| |
| uint8_t* next_out_of_line = reinterpret_cast<uint8_t*>(end_all_envelopes); |
| if (unlikely(reinterpret_cast<uint8_t*>(next_out_of_line) - bytes > int64_t(bytes_size))) { |
| *error = "byte size exceeds available size"; |
| return false; |
| } |
| |
| for (fidl_envelope_t* envelope = start_envelopes; envelope != end_known_envelopes; envelope++) { |
| if (unlikely(envelope->num_handles != 0)) { |
| *error = "incorrect num_handles in envelope"; |
| return false; |
| } |
| if (envelope->data == nullptr) { |
| if (unlikely(envelope->num_bytes != 0)) { |
| *error = "incorrect num_bytes in envelope"; |
| return false; |
| } |
| } else { |
| if (unlikely(envelope->num_bytes != 8)) { |
| *error = "incorrect num_bytes in envelope"; |
| return false; |
| } |
| if (unlikely((*reinterpret_cast<uint64_t*>(next_out_of_line) & 0xffffffffffffff00) != 0)) { |
| *error = "invalid padding byte"; |
| return false; |
| } |
| envelope->data = next_out_of_line; |
| next_out_of_line += 8; |
| if (unlikely(reinterpret_cast<uint8_t*>(next_out_of_line) - bytes > int64_t(bytes_size))) { |
| *error = "byte size exceeds available size"; |
| return false; |
| } |
| } |
| } |
| |
| // Unknown envelopes |
| uint32_t num_handles = 0; |
| for (fidl_envelope_t* envelope = end_known_envelopes; envelope != end_all_envelopes; envelope++) { |
| if (envelope->data == nullptr) { |
| if (unlikely(envelope->num_bytes != 0)) { |
| *error = "incorrect num_bytes in envelope"; |
| return false; |
| } |
| if (unlikely(envelope->num_handles != 0)) { |
| *error = "incorrect num_handles in envelope"; |
| return false; |
| } |
| } else { |
| size_t aligned_bytes = envelope->num_bytes; |
| if (unlikely(!FidlIsAligned(reinterpret_cast<uint8_t*>(aligned_bytes)))) { |
| *error = "incorrect num_bytes in envelope"; |
| return false; |
| } |
| num_handles += envelope->num_handles; |
| envelope->data = next_out_of_line; |
| next_out_of_line += aligned_bytes; |
| if (unlikely(reinterpret_cast<uint8_t*>(next_out_of_line) - bytes > int64_t(bytes_size))) { |
| *error = "byte size exceeds available size"; |
| return false; |
| } |
| } |
| } |
| #ifdef __Fuchsia__ |
| zx_handle_close_many(handles, num_handles); |
| #endif |
| return true; |
| } |
| |
| bool BenchmarkEncodeTableAllSet1(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark(state, benchmark_suite::Build_Table_AllSet_1, |
| EncodeUint8TableStruct<1>); |
| } |
| bool BenchmarkEncodeTableAllSet16(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark(state, benchmark_suite::Build_Table_AllSet_16, |
| EncodeUint8TableStruct<16>); |
| } |
| bool BenchmarkEncodeTableAllSet256(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark(state, benchmark_suite::Build_Table_AllSet_256, |
| EncodeUint8TableStruct<256>); |
| } |
| bool BenchmarkEncodeTableUnset1(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark(state, benchmark_suite::Build_Table_Unset_1, |
| EncodeUint8TableStruct<1>); |
| } |
| bool BenchmarkEncodeTableUnset16(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark(state, benchmark_suite::Build_Table_Unset_16, |
| EncodeUint8TableStruct<16>); |
| } |
| bool BenchmarkEncodeTableUnset256(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark(state, benchmark_suite::Build_Table_Unset_256, |
| EncodeUint8TableStruct<256>); |
| } |
| bool BenchmarkEncodeTableSingleSet_1_of_1(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_1_of_1, EncodeUint8TableStruct<1>); |
| } |
| bool BenchmarkEncodeTableSingleSet_1_of_16(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_1_of_16, EncodeUint8TableStruct<16>); |
| } |
| bool BenchmarkEncodeTableSingleSet_16_of_16(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_16_of_16, EncodeUint8TableStruct<16>); |
| } |
| bool BenchmarkEncodeTableSingleSet_1_of_256(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_1_of_256, EncodeUint8TableStruct<256>); |
| } |
| bool BenchmarkEncodeTableSingleSet_16_of_256(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_16_of_256, EncodeUint8TableStruct<256>); |
| } |
| bool BenchmarkEncodeTableSingleSet_256_of_256(perftest::RepeatState* state) { |
| return encode_benchmark_util::EncodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_256_of_256, EncodeUint8TableStruct<256>); |
| } |
| bool BenchmarkDecodeTableAllSet1(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark(state, benchmark_suite::Build_Table_AllSet_1, |
| DecodeUint8TableStruct<1>); |
| } |
| bool BenchmarkDecodeTableAllSet16(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark(state, benchmark_suite::Build_Table_AllSet_16, |
| DecodeUint8TableStruct<16>); |
| } |
| bool BenchmarkDecodeTableAllSet256(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark(state, benchmark_suite::Build_Table_AllSet_256, |
| DecodeUint8TableStruct<256>); |
| } |
| bool BenchmarkDecodeTableUnset1(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark(state, benchmark_suite::Build_Table_Unset_1, |
| DecodeUint8TableStruct<1>); |
| } |
| bool BenchmarkDecodeTableUnset16(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark(state, benchmark_suite::Build_Table_Unset_16, |
| DecodeUint8TableStruct<16>); |
| } |
| bool BenchmarkDecodeTableUnset256(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark(state, benchmark_suite::Build_Table_Unset_256, |
| DecodeUint8TableStruct<256>); |
| } |
| bool BenchmarkDecodeTableSingleSet_1_of_1(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_1_of_1, DecodeUint8TableStruct<1>); |
| } |
| bool BenchmarkDecodeTableSingleSet_1_of_16(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_1_of_16, DecodeUint8TableStruct<16>); |
| } |
| bool BenchmarkDecodeTableSingleSet_16_of_16(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_16_of_16, DecodeUint8TableStruct<16>); |
| } |
| bool BenchmarkDecodeTableSingleSet_1_of_256(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_1_of_256, DecodeUint8TableStruct<256>); |
| } |
| bool BenchmarkDecodeTableSingleSet_16_of_256(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_16_of_256, DecodeUint8TableStruct<256>); |
| } |
| bool BenchmarkDecodeTableSingleSet_256_of_256(perftest::RepeatState* state) { |
| return decode_benchmark_util::DecodeBenchmark( |
| state, benchmark_suite::Build_Table_SingleSet_256_of_256, DecodeUint8TableStruct<256>); |
| } |
| |
| void RegisterTests() { |
| perftest::RegisterTest("Reference/Encode/Table/AllSet/1/Steps", BenchmarkEncodeTableAllSet1); |
| perftest::RegisterTest("Reference/Encode/Table/AllSet/16/Steps", BenchmarkEncodeTableAllSet16); |
| perftest::RegisterTest("Reference/Encode/Table/AllSet/256/Steps", BenchmarkEncodeTableAllSet256); |
| perftest::RegisterTest("Reference/Encode/Table/Unset/1/Steps", BenchmarkEncodeTableUnset1); |
| perftest::RegisterTest("Reference/Encode/Table/Unset/16/Steps", BenchmarkEncodeTableUnset16); |
| perftest::RegisterTest("Reference/Encode/Table/Unset/256/Steps", BenchmarkEncodeTableUnset256); |
| perftest::RegisterTest("Reference/Encode/Table/SingleSet/1_of_1/Steps", |
| BenchmarkEncodeTableSingleSet_1_of_1); |
| perftest::RegisterTest("Reference/Encode/Table/SingleSet/1_of_16/Steps", |
| BenchmarkEncodeTableSingleSet_1_of_16); |
| perftest::RegisterTest("Reference/Encode/Table/SingleSet/16_of_16/Steps", |
| BenchmarkEncodeTableSingleSet_16_of_16); |
| perftest::RegisterTest("Reference/Encode/Table/SingleSet/1_of_256/Steps", |
| BenchmarkEncodeTableSingleSet_1_of_256); |
| perftest::RegisterTest("Reference/Encode/Table/SingleSet/16_of_256/Steps", |
| BenchmarkEncodeTableSingleSet_16_of_256); |
| perftest::RegisterTest("Reference/Encode/Table/SingleSet/256_of_256/Steps", |
| BenchmarkEncodeTableSingleSet_256_of_256); |
| perftest::RegisterTest("Reference/Decode/Table/AllSet/1/Steps", BenchmarkDecodeTableAllSet1); |
| perftest::RegisterTest("Reference/Decode/Table/AllSet/16/Steps", BenchmarkDecodeTableAllSet16); |
| perftest::RegisterTest("Reference/Decode/Table/AllSet/256/Steps", BenchmarkDecodeTableAllSet256); |
| perftest::RegisterTest("Reference/Decode/Table/Unset/1/Steps", BenchmarkDecodeTableUnset1); |
| perftest::RegisterTest("Reference/Decode/Table/Unset/16/Steps", BenchmarkDecodeTableUnset16); |
| perftest::RegisterTest("Reference/Decode/Table/Unset/256/Steps", BenchmarkDecodeTableUnset256); |
| perftest::RegisterTest("Reference/Decode/Table/SingleSet/1_of_1/Steps", |
| BenchmarkDecodeTableSingleSet_1_of_1); |
| perftest::RegisterTest("Reference/Decode/Table/SingleSet/1_of_16/Steps", |
| BenchmarkDecodeTableSingleSet_1_of_16); |
| perftest::RegisterTest("Reference/Decode/Table/SingleSet/16_of_16/Steps", |
| BenchmarkDecodeTableSingleSet_16_of_16); |
| perftest::RegisterTest("Reference/Decode/Table/SingleSet/1_of_256/Steps", |
| BenchmarkDecodeTableSingleSet_1_of_256); |
| perftest::RegisterTest("Reference/Decode/Table/SingleSet/16_of_256/Steps", |
| BenchmarkDecodeTableSingleSet_16_of_256); |
| perftest::RegisterTest("Reference/Decode/Table/SingleSet/256_of_256/Steps", |
| BenchmarkDecodeTableSingleSet_256_of_256); |
| } |
| PERFTEST_CTOR(RegisterTests) |
| |
| } // namespace |