1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/big_endian.h"
6
7 #include <stdint.h>
8
9 #include "base/check.h"
10 #include "base/containers/span.h"
11 #include "third_party/google_benchmark/src/include/benchmark/benchmark.h"
12
13 namespace base {
14 namespace {
15
16 constexpr size_t kSize = 128 * 1024 * 1024;
17 int64_t aligned_bytes[kSize / sizeof(int64_t)];
18 struct {
19 int64_t aligment;
20 char padding_to_cause_misalignment;
21 char bytes[kSize];
22 } misaligned_bytes;
23
DoNotOptimizeSpan(span<const char> range)24 void DoNotOptimizeSpan(span<const char> range) {
25 // ::benchmark::DoNotOptimize() generates quite large code, so instead of
26 // calling it for every byte in the range, calculate `sum` which depends on
27 // every byte in the range and then call DoNotOptimise() on that.
28 int sum = 0;
29 for (char c : range) {
30 sum += c;
31 }
32 ::benchmark::DoNotOptimize(sum);
33 }
34
35 template <typename T>
WriteBigEndianCommon(::benchmark::State & state,char * const start)36 inline void WriteBigEndianCommon(::benchmark::State& state, char* const start) {
37 size_t offset = 0;
38 T value = 0;
39 for (auto _ : state) {
40 WriteBigEndian(start + offset, value);
41 offset += sizeof(T);
42 static_assert(kSize % sizeof(T) == 0);
43 if (offset == kSize) {
44 offset = 0;
45 }
46 ++value;
47 }
48 DoNotOptimizeSpan({start, kSize});
49 }
50
51 template <typename T>
BM_WriteBigEndianAligned(::benchmark::State & state)52 void BM_WriteBigEndianAligned(::benchmark::State& state) {
53 char* const start = reinterpret_cast<char*>(aligned_bytes);
54 CHECK(reinterpret_cast<uintptr_t>(start) % alignof(T) == 0);
55 WriteBigEndianCommon<T>(state, start);
56 }
57
58 template <typename T>
BM_WriteBigEndianMisaligned(::benchmark::State & state)59 void BM_WriteBigEndianMisaligned(::benchmark::State& state) {
60 char* const start = misaligned_bytes.bytes;
61 CHECK(reinterpret_cast<uintptr_t>(start) % alignof(T) != 0);
62 WriteBigEndianCommon<T>(state, start);
63 }
64
65 template <typename T>
ReadBigEndianCommon(::benchmark::State & state,const uint8_t * const start)66 inline void ReadBigEndianCommon(::benchmark::State& state,
67 const uint8_t* const start) {
68 size_t offset = 0;
69 for (auto _ : state) {
70 T value;
71 ReadBigEndian(start + offset, &value);
72 ::benchmark::DoNotOptimize(value);
73 offset += sizeof(T);
74 static_assert(kSize % sizeof(T) == 0);
75 if (offset == kSize) {
76 offset = 0;
77 }
78 }
79 }
80
81 template <typename T>
BM_ReadBigEndianAligned(::benchmark::State & state)82 void BM_ReadBigEndianAligned(::benchmark::State& state) {
83 const uint8_t* const start = reinterpret_cast<uint8_t*>(aligned_bytes);
84 CHECK(reinterpret_cast<uintptr_t>(start) % alignof(T) == 0);
85 ReadBigEndianCommon<T>(state, start);
86 }
87
88 template <typename T>
BM_ReadBigEndianMisaligned(::benchmark::State & state)89 void BM_ReadBigEndianMisaligned(::benchmark::State& state) {
90 const uint8_t* const start =
91 reinterpret_cast<uint8_t*>(misaligned_bytes.bytes);
92 CHECK(reinterpret_cast<uintptr_t>(start) % alignof(T) != 0);
93 ReadBigEndianCommon<T>(state, start);
94 }
95
96 #define BENCHMARK_FOR_INT_TYPES(function) \
97 BENCHMARK(function<int16_t>)->MinWarmUpTime(1.0); \
98 BENCHMARK(function<uint16_t>)->MinWarmUpTime(1.0); \
99 BENCHMARK(function<int32_t>)->MinWarmUpTime(1.0); \
100 BENCHMARK(function<uint32_t>)->MinWarmUpTime(1.0); \
101 BENCHMARK(function<int64_t>)->MinWarmUpTime(1.0); \
102 BENCHMARK(function<uint64_t>)->MinWarmUpTime(1.0); \
103 typedef int force_semicolon
104
105 BENCHMARK_FOR_INT_TYPES(BM_WriteBigEndianAligned);
106 BENCHMARK_FOR_INT_TYPES(BM_WriteBigEndianMisaligned);
107 BENCHMARK_FOR_INT_TYPES(BM_ReadBigEndianAligned);
108 BENCHMARK_FOR_INT_TYPES(BM_ReadBigEndianMisaligned);
109
110 #undef BENCHMARK_FOR_INT_TYPES
111
112 } // namespace
113 } // namespace base
114