1 //===-- Benchmark memory specific tools -----------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "LibcMemoryBenchmark.h"
10 #include "llvm/ADT/SmallVector.h"
11 #include "llvm/ADT/Twine.h"
12 #include "llvm/Support/ErrorHandling.h"
13 #include "llvm/Support/MathExtras.h"
17 namespace libc_benchmarks
{
19 // Returns a distribution that samples the buffer to satisfy the required
21 // When alignment is set, the distribution is scaled down by `Factor` and scaled
22 // up again by the same amount during sampling.
23 static std::uniform_int_distribution
<uint32_t>
24 getOffsetDistribution(size_t BufferSize
, size_t MaxSizeValue
,
25 MaybeAlign AccessAlignment
) {
26 if (AccessAlignment
&& *AccessAlignment
> AlignedBuffer::Alignment
)
28 "AccessAlignment must be less or equal to AlignedBuffer::Alignment");
30 return std::uniform_int_distribution
<uint32_t>(0, 0); // Always 0.
31 // If we test up to Size bytes, the returned offset must stay under
32 // BuffersSize - Size.
33 int64_t MaxOffset
= BufferSize
;
34 MaxOffset
-= MaxSizeValue
;
38 "BufferSize too small to exercise specified Size configuration");
39 MaxOffset
/= AccessAlignment
->value();
40 return std::uniform_int_distribution
<uint32_t>(0, MaxOffset
);
43 OffsetDistribution::OffsetDistribution(size_t BufferSize
, size_t MaxSizeValue
,
44 MaybeAlign AccessAlignment
)
46 getOffsetDistribution(BufferSize
, MaxSizeValue
, AccessAlignment
)),
47 Factor(AccessAlignment
.valueOrOne().value()) {}
49 // Precomputes offset where to insert mismatches between the two buffers.
50 MismatchOffsetDistribution::MismatchOffsetDistribution(size_t BufferSize
,
53 : MismatchAt(MismatchAt
) {
56 for (size_t I
= MaxSizeValue
+ 1; I
< BufferSize
; I
+= MaxSizeValue
)
57 MismatchIndices
.push_back(I
);
58 if (MismatchIndices
.empty())
59 report_fatal_error("Unable to generate mismatch");
60 MismatchIndexSelector
=
61 std::uniform_int_distribution
<size_t>(0, MismatchIndices
.size() - 1);
64 static size_t getL1DataCacheSize() {
65 const std::vector
<CacheInfo
> &CacheInfos
= HostState::get().Caches
;
66 const auto IsL1DataCache
= [](const CacheInfo
&CI
) {
67 return CI
.Type
== "Data" && CI
.Level
== 1;
69 const auto CacheIt
= find_if(CacheInfos
, IsL1DataCache
);
70 if (CacheIt
!= CacheInfos
.end())
72 report_fatal_error("Unable to read L1 Cache Data Size");
75 static constexpr int64_t KiB
= 1024;
76 static constexpr int64_t ParameterStorageBytes
= 4 * KiB
;
77 static constexpr int64_t L1LeftAsideBytes
= 1 * KiB
;
79 static size_t getAvailableBufferSize() {
80 return getL1DataCacheSize() - L1LeftAsideBytes
- ParameterStorageBytes
;
83 ParameterBatch::ParameterBatch(size_t BufferCount
)
84 : BufferSize(getAvailableBufferSize() / BufferCount
),
85 BatchSize(ParameterStorageBytes
/ sizeof(ParameterType
)),
86 Parameters(BatchSize
) {
87 if (BufferSize
<= 0 || BatchSize
< 100)
88 report_fatal_error("Not enough L1 cache");
89 const size_t ParameterBytes
= Parameters
.size() * sizeof(ParameterType
);
90 const size_t BufferBytes
= BufferSize
* BufferCount
;
91 if (ParameterBytes
+ BufferBytes
+ L1LeftAsideBytes
> getL1DataCacheSize())
93 "We're splitting a buffer of the size of the L1 cache between a data "
94 "buffer and a benchmark parameters buffer, so by construction the "
95 "total should not exceed the size of the L1 cache");
98 size_t ParameterBatch::getBatchBytes() const {
99 size_t BatchBytes
= 0;
100 for (auto &P
: Parameters
)
101 BatchBytes
+= P
.SizeBytes
;
105 void ParameterBatch::checkValid(const ParameterType
&P
) const {
106 if (P
.OffsetBytes
+ P
.SizeBytes
>= BufferSize
)
108 llvm::Twine("Call would result in buffer overflow: Offset=")
109 .concat(llvm::Twine(P
.OffsetBytes
))
111 .concat(llvm::Twine(P
.SizeBytes
))
112 .concat(", BufferSize=")
113 .concat(llvm::Twine(BufferSize
)));
116 CopySetup::CopySetup()
117 : ParameterBatch(2), SrcBuffer(ParameterBatch::BufferSize
),
118 DstBuffer(ParameterBatch::BufferSize
) {}
120 MoveSetup::MoveSetup()
121 : ParameterBatch(3), Buffer(ParameterBatch::BufferSize
* 3) {}
123 ComparisonSetup::ComparisonSetup()
124 : ParameterBatch(2), LhsBuffer(ParameterBatch::BufferSize
),
125 RhsBuffer(ParameterBatch::BufferSize
) {
126 // The memcmp buffers always compare equal.
127 memset(LhsBuffer
.begin(), 0xF, BufferSize
);
128 memset(RhsBuffer
.begin(), 0xF, BufferSize
);
132 : ParameterBatch(1), DstBuffer(ParameterBatch::BufferSize
) {}
134 } // namespace libc_benchmarks