blob: 8c68c032badca921fa1076fa08d30285c0fc6ba4 [file] [log] [blame]
Adam Rice3807a762023-08-18 10:25:251// 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"
danakja1e7d0a12024-02-29 15:22:1711#include "base/numerics/byte_conversions.h"
Egor Pasko1403ac92024-02-16 17:07:5112#include "testing/gtest/include/gtest/gtest.h"
Adam Rice3807a762023-08-18 10:25:2513#include "third_party/google_benchmark/src/include/benchmark/benchmark.h"
14
15namespace base {
16namespace {
17
18constexpr size_t kSize = 128 * 1024 * 1024;
19int64_t aligned_bytes[kSize / sizeof(int64_t)];
20struct {
21 int64_t aligment;
22 char padding_to_cause_misalignment;
23 char bytes[kSize];
24} misaligned_bytes;
25
danakj6b407a962024-02-16 19:08:0926void DoNotOptimizeSpan(span<const uint8_t> range) {
Adam Rice3807a762023-08-18 10:25:2527 // ::benchmark::DoNotOptimize() generates quite large code, so instead of
28 // calling it for every byte in the range, calculate `sum` which depends on
29 // every byte in the range and then call DoNotOptimise() on that.
30 int sum = 0;
31 for (char c : range) {
32 sum += c;
33 }
34 ::benchmark::DoNotOptimize(sum);
35}
36
37template <typename T>
danakj6b407a962024-02-16 19:08:0938inline void WriteBigEndianCommon(::benchmark::State& state,
39 span<uint8_t, kSize> buffer) {
40 size_t offset = 0u;
41 auto value = T{0};
Adam Rice3807a762023-08-18 10:25:2542 for (auto _ : state) {
danakja1e7d0a12024-02-29 15:22:1743 if constexpr (sizeof(T) == 1) {
Peter Kasting448444f2024-12-13 01:25:3644 buffer.subspan(offset).copy_prefix_from(U8ToBigEndian(value));
danakja1e7d0a12024-02-29 15:22:1745 } else if constexpr (sizeof(T) == 2) {
Peter Kasting448444f2024-12-13 01:25:3646 buffer.subspan(offset).copy_prefix_from(U16ToBigEndian(value));
danakja1e7d0a12024-02-29 15:22:1747 } else if constexpr (sizeof(T) == 4) {
Peter Kasting448444f2024-12-13 01:25:3648 buffer.subspan(offset).copy_prefix_from(U32ToBigEndian(value));
danakja1e7d0a12024-02-29 15:22:1749 } else {
50 static_assert(sizeof(T) == 8);
Peter Kasting448444f2024-12-13 01:25:3651 buffer.subspan(offset).copy_prefix_from(U64ToBigEndian(value));
danakja1e7d0a12024-02-29 15:22:1752 }
Adam Rice3807a762023-08-18 10:25:2553 offset += sizeof(T);
danakj6b407a962024-02-16 19:08:0954 static_assert(kSize % sizeof(T) == 0u);
Adam Rice3807a762023-08-18 10:25:2555 if (offset == kSize) {
56 offset = 0;
57 }
58 ++value;
59 }
danakj6b407a962024-02-16 19:08:0960 DoNotOptimizeSpan(buffer);
Adam Rice3807a762023-08-18 10:25:2561}
62
63template <typename T>
64void BM_WriteBigEndianAligned(::benchmark::State& state) {
David Benjaminfad2e082024-04-02 19:14:3965 span<uint8_t, kSize> buffer = as_writable_byte_span(aligned_bytes);
danakj6b407a962024-02-16 19:08:0966 CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) == 0u);
67 WriteBigEndianCommon<T>(state, buffer);
Adam Rice3807a762023-08-18 10:25:2568}
69
70template <typename T>
71void BM_WriteBigEndianMisaligned(::benchmark::State& state) {
David Benjaminfad2e082024-04-02 19:14:3972 span<uint8_t, kSize> buffer = as_writable_byte_span(misaligned_bytes.bytes);
danakj6b407a962024-02-16 19:08:0973 CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) != 0u);
74 WriteBigEndianCommon<T>(state, buffer);
Adam Rice3807a762023-08-18 10:25:2575}
76
77template <typename T>
78inline void ReadBigEndianCommon(::benchmark::State& state,
danakja1e7d0a12024-02-29 15:22:1779 span<const uint8_t, kSize> buffer) {
Adam Rice3807a762023-08-18 10:25:2580 size_t offset = 0;
81 for (auto _ : state) {
82 T value;
danakja1e7d0a12024-02-29 15:22:1783 if constexpr (sizeof(T) == 1) {
David Benjaminfad2e082024-04-02 19:14:3984 value = U8FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
danakja1e7d0a12024-02-29 15:22:1785 } else if constexpr (sizeof(T) == 2) {
David Benjaminfad2e082024-04-02 19:14:3986 value = U16FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
danakja1e7d0a12024-02-29 15:22:1787 } else if constexpr (sizeof(T) == 4) {
David Benjaminfad2e082024-04-02 19:14:3988 value = U32FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
danakja1e7d0a12024-02-29 15:22:1789 } else {
90 static_assert(sizeof(T) == 8);
David Benjaminfad2e082024-04-02 19:14:3991 value = U64FromBigEndian(buffer.subspan(offset).first<sizeof(T)>());
danakja1e7d0a12024-02-29 15:22:1792 }
Adam Rice3807a762023-08-18 10:25:2593 ::benchmark::DoNotOptimize(value);
94 offset += sizeof(T);
95 static_assert(kSize % sizeof(T) == 0);
96 if (offset == kSize) {
97 offset = 0;
98 }
99 }
100}
101
102template <typename T>
103void BM_ReadBigEndianAligned(::benchmark::State& state) {
David Benjaminfad2e082024-04-02 19:14:39104 span<const uint8_t, kSize> buffer = as_byte_span(aligned_bytes);
danakja1e7d0a12024-02-29 15:22:17105 CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) == 0);
106 ReadBigEndianCommon<T>(state, buffer);
Adam Rice3807a762023-08-18 10:25:25107}
108
109template <typename T>
110void BM_ReadBigEndianMisaligned(::benchmark::State& state) {
David Benjaminfad2e082024-04-02 19:14:39111 span<const uint8_t, kSize> buffer = as_byte_span(misaligned_bytes.bytes);
danakja1e7d0a12024-02-29 15:22:17112 CHECK(reinterpret_cast<uintptr_t>(buffer.data()) % alignof(T) != 0);
113 ReadBigEndianCommon<T>(state, buffer);
Adam Rice3807a762023-08-18 10:25:25114}
115
116#define BENCHMARK_FOR_INT_TYPES(function) \
117 BENCHMARK(function<int16_t>)->MinWarmUpTime(1.0); \
118 BENCHMARK(function<uint16_t>)->MinWarmUpTime(1.0); \
119 BENCHMARK(function<int32_t>)->MinWarmUpTime(1.0); \
120 BENCHMARK(function<uint32_t>)->MinWarmUpTime(1.0); \
121 BENCHMARK(function<int64_t>)->MinWarmUpTime(1.0); \
Egor Pasko1403ac92024-02-16 17:07:51122 BENCHMARK(function<uint64_t>)->MinWarmUpTime(1.0);
Adam Rice3807a762023-08-18 10:25:25123
Egor Pasko1403ac92024-02-16 17:07:51124// Register the benchmarks as a GTest test. This allows using legacy
125// --gtest_filter and --gtest_list_tests.
126// TODO(https://crbug.com/40251982): Clean this up after transitioning to
127// --benchmark_filter and --benchmark_list_tests.
128TEST(BigEndianPerfTest, All) {
129 BENCHMARK_FOR_INT_TYPES(BM_WriteBigEndianAligned);
130 BENCHMARK_FOR_INT_TYPES(BM_WriteBigEndianMisaligned);
131 BENCHMARK_FOR_INT_TYPES(BM_ReadBigEndianAligned);
132 BENCHMARK_FOR_INT_TYPES(BM_ReadBigEndianMisaligned);
133}
Adam Rice3807a762023-08-18 10:25:25134
135#undef BENCHMARK_FOR_INT_TYPES
136
137} // namespace
138} // namespace base