xref: /aosp_15_r20/external/cronet/base/big_endian_perftest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/big_endian.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/numerics/byte_conversions.h"
12*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
13*6777b538SAndroid Build Coastguard Worker #include "third_party/google_benchmark/src/include/benchmark/benchmark.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker namespace base {
16*6777b538SAndroid Build Coastguard Worker namespace {
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker constexpr size_t kSize = 128 * 1024 * 1024;
19*6777b538SAndroid Build Coastguard Worker int64_t aligned_bytes[kSize / sizeof(int64_t)];
20*6777b538SAndroid Build Coastguard Worker struct {
21*6777b538SAndroid Build Coastguard Worker   int64_t aligment;
22*6777b538SAndroid Build Coastguard Worker   char padding_to_cause_misalignment;
23*6777b538SAndroid Build Coastguard Worker   char bytes[kSize];
24*6777b538SAndroid Build Coastguard Worker } misaligned_bytes;
25*6777b538SAndroid Build Coastguard Worker 
DoNotOptimizeSpan(span<const uint8_t> range)26*6777b538SAndroid Build Coastguard Worker void DoNotOptimizeSpan(span<const uint8_t> range) {
27*6777b538SAndroid Build Coastguard Worker   // ::benchmark::DoNotOptimize() generates quite large code, so instead of
28*6777b538SAndroid Build Coastguard Worker   // calling it for every byte in the range, calculate `sum` which depends on
29*6777b538SAndroid Build Coastguard Worker   // every byte in the range and then call DoNotOptimise() on that.
30*6777b538SAndroid Build Coastguard Worker   int sum = 0;
31*6777b538SAndroid Build Coastguard Worker   for (char c : range) {
32*6777b538SAndroid Build Coastguard Worker     sum += c;
33*6777b538SAndroid Build Coastguard Worker   }
34*6777b538SAndroid Build Coastguard Worker   ::benchmark::DoNotOptimize(sum);
35*6777b538SAndroid Build Coastguard Worker }
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker template <typename T>
WriteBigEndianCommon(::benchmark::State & state,span<uint8_t,kSize> buffer)38*6777b538SAndroid Build Coastguard Worker inline void WriteBigEndianCommon(::benchmark::State& state,
39*6777b538SAndroid Build Coastguard Worker                                  span<uint8_t, kSize> buffer) {
40*6777b538SAndroid Build Coastguard Worker   size_t offset = 0u;
41*6777b538SAndroid Build Coastguard Worker   auto value = T{0};
42*6777b538SAndroid Build Coastguard Worker   for (auto _ : state) {
43*6777b538SAndroid Build Coastguard Worker     if constexpr (sizeof(T) == 1) {
44*6777b538SAndroid Build Coastguard Worker       buffer.subspan(offset).first<sizeof(T)>().copy_from(U8ToBigEndian(value));
45*6777b538SAndroid Build Coastguard Worker     } else if constexpr (sizeof(T) == 2) {
46*6777b538SAndroid Build Coastguard Worker       buffer.subspan(offset).first<sizeof(T)>().copy_from(
47*6777b538SAndroid Build Coastguard Worker           U16ToBigEndian(value));
48*6777b538SAndroid Build Coastguard Worker     } else if constexpr (sizeof(T) == 4) {
49*6777b538SAndroid Build Coastguard Worker       buffer.subspan(offset).first<sizeof(T)>().copy_from(
50*6777b538SAndroid Build Coastguard Worker           U32ToBigEndian(value));
51*6777b538SAndroid Build Coastguard Worker     } else {
52*6777b538SAndroid Build Coastguard Worker       static_assert(sizeof(T) == 8);
53*6777b538SAndroid Build Coastguard Worker       buffer.subspan(offset).first<sizeof(T)>().copy_from(
54*6777b538SAndroid Build Coastguard Worker           U64ToBigEndian(value));
55*6777b538SAndroid Build Coastguard Worker     }
56*6777b538SAndroid Build Coastguard Worker     offset += sizeof(T);
57*6777b538SAndroid Build Coastguard Worker     static_assert(kSize % sizeof(T) == 0u);
58*6777b538SAndroid Build Coastguard Worker     if (offset == kSize) {
59*6777b538SAndroid Build Coastguard Worker       offset = 0;
60*6777b538SAndroid Build Coastguard Worker     }
61*6777b538SAndroid Build Coastguard Worker     ++value;
62*6777b538SAndroid Build Coastguard Worker   }
63*6777b538SAndroid Build Coastguard Worker   DoNotOptimizeSpan(buffer);
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker template <typename T>
BM_WriteBigEndianAligned(::benchmark::State & state)67*6777b538SAndroid Build Coastguard Worker void BM_WriteBigEndianAligned(::benchmark::State& state) {
68*6777b538SAndroid Build Coastguard Worker   span<uint8_t, kSize> buffer = as_writable_byte_span(aligned_bytes);
69*6777b538SAndroid Build Coastguard Worker   CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) == 0u);
70*6777b538SAndroid Build Coastguard Worker   WriteBigEndianCommon<T>(state, buffer);
71*6777b538SAndroid Build Coastguard Worker }
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker template <typename T>
BM_WriteBigEndianMisaligned(::benchmark::State & state)74*6777b538SAndroid Build Coastguard Worker void BM_WriteBigEndianMisaligned(::benchmark::State& state) {
75*6777b538SAndroid Build Coastguard Worker   span<uint8_t, kSize> buffer = as_writable_byte_span(misaligned_bytes.bytes);
76*6777b538SAndroid Build Coastguard Worker   CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) != 0u);
77*6777b538SAndroid Build Coastguard Worker   WriteBigEndianCommon<T>(state, buffer);
78*6777b538SAndroid Build Coastguard Worker }
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker template <typename T>
ReadBigEndianCommon(::benchmark::State & state,span<const uint8_t,kSize> buffer)81*6777b538SAndroid Build Coastguard Worker inline void ReadBigEndianCommon(::benchmark::State& state,
82*6777b538SAndroid Build Coastguard Worker                                 span<const uint8_t, kSize> buffer) {
83*6777b538SAndroid Build Coastguard Worker   size_t offset = 0;
84*6777b538SAndroid Build Coastguard Worker   for (auto _ : state) {
85*6777b538SAndroid Build Coastguard Worker     T value;
86*6777b538SAndroid Build Coastguard Worker     if constexpr (sizeof(T) == 1) {
87*6777b538SAndroid Build Coastguard Worker       value = U8FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
88*6777b538SAndroid Build Coastguard Worker     } else if constexpr (sizeof(T) == 2) {
89*6777b538SAndroid Build Coastguard Worker       value = U16FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
90*6777b538SAndroid Build Coastguard Worker     } else if constexpr (sizeof(T) == 4) {
91*6777b538SAndroid Build Coastguard Worker       value = U32FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
92*6777b538SAndroid Build Coastguard Worker     } else {
93*6777b538SAndroid Build Coastguard Worker       static_assert(sizeof(T) == 8);
94*6777b538SAndroid Build Coastguard Worker       value = U64FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
95*6777b538SAndroid Build Coastguard Worker     }
96*6777b538SAndroid Build Coastguard Worker     ::benchmark::DoNotOptimize(value);
97*6777b538SAndroid Build Coastguard Worker     offset += sizeof(T);
98*6777b538SAndroid Build Coastguard Worker     static_assert(kSize % sizeof(T) == 0);
99*6777b538SAndroid Build Coastguard Worker     if (offset == kSize) {
100*6777b538SAndroid Build Coastguard Worker       offset = 0;
101*6777b538SAndroid Build Coastguard Worker     }
102*6777b538SAndroid Build Coastguard Worker   }
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker 
105*6777b538SAndroid Build Coastguard Worker template <typename T>
BM_ReadBigEndianAligned(::benchmark::State & state)106*6777b538SAndroid Build Coastguard Worker void BM_ReadBigEndianAligned(::benchmark::State& state) {
107*6777b538SAndroid Build Coastguard Worker   span<const uint8_t, kSize> buffer = as_byte_span(aligned_bytes);
108*6777b538SAndroid Build Coastguard Worker   CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) == 0);
109*6777b538SAndroid Build Coastguard Worker   ReadBigEndianCommon<T>(state, buffer);
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker template <typename T>
BM_ReadBigEndianMisaligned(::benchmark::State & state)113*6777b538SAndroid Build Coastguard Worker void BM_ReadBigEndianMisaligned(::benchmark::State& state) {
114*6777b538SAndroid Build Coastguard Worker   span<const uint8_t, kSize> buffer = as_byte_span(misaligned_bytes.bytes);
115*6777b538SAndroid Build Coastguard Worker   CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) != 0);
116*6777b538SAndroid Build Coastguard Worker   ReadBigEndianCommon<T>(state, buffer);
117*6777b538SAndroid Build Coastguard Worker }
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker #define BENCHMARK_FOR_INT_TYPES(function)            \
120*6777b538SAndroid Build Coastguard Worker   BENCHMARK(function<int16_t>)->MinWarmUpTime(1.0);  \
121*6777b538SAndroid Build Coastguard Worker   BENCHMARK(function<uint16_t>)->MinWarmUpTime(1.0); \
122*6777b538SAndroid Build Coastguard Worker   BENCHMARK(function<int32_t>)->MinWarmUpTime(1.0);  \
123*6777b538SAndroid Build Coastguard Worker   BENCHMARK(function<uint32_t>)->MinWarmUpTime(1.0); \
124*6777b538SAndroid Build Coastguard Worker   BENCHMARK(function<int64_t>)->MinWarmUpTime(1.0);  \
125*6777b538SAndroid Build Coastguard Worker   BENCHMARK(function<uint64_t>)->MinWarmUpTime(1.0);
126*6777b538SAndroid Build Coastguard Worker 
127*6777b538SAndroid Build Coastguard Worker // Register the benchmarks as a GTest test. This allows using legacy
128*6777b538SAndroid Build Coastguard Worker // --gtest_filter and --gtest_list_tests.
129*6777b538SAndroid Build Coastguard Worker // TODO(https://crbug.com/40251982): Clean this up after transitioning to
130*6777b538SAndroid Build Coastguard Worker // --benchmark_filter and --benchmark_list_tests.
TEST(BigEndianPerfTest,All)131*6777b538SAndroid Build Coastguard Worker TEST(BigEndianPerfTest, All) {
132*6777b538SAndroid Build Coastguard Worker   BENCHMARK_FOR_INT_TYPES(BM_WriteBigEndianAligned);
133*6777b538SAndroid Build Coastguard Worker   BENCHMARK_FOR_INT_TYPES(BM_WriteBigEndianMisaligned);
134*6777b538SAndroid Build Coastguard Worker   BENCHMARK_FOR_INT_TYPES(BM_ReadBigEndianAligned);
135*6777b538SAndroid Build Coastguard Worker   BENCHMARK_FOR_INT_TYPES(BM_ReadBigEndianMisaligned);
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker #undef BENCHMARK_FOR_INT_TYPES
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker }  // namespace
141*6777b538SAndroid Build Coastguard Worker }  // namespace base
142