1 //===-- Benchmark memory specific tools -----------------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 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" 14 #include <algorithm> 15 16 namespace llvm { 17 namespace libc_benchmarks { 18 19 // Returns a distribution that samples the buffer to satisfy the required 20 // alignment. 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) 27 report_fatal_error( 28 "AccessAlignment must be less or equal to AlignedBuffer::Alignment"); 29 if (!AccessAlignment) 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; 35 MaxOffset -= 1; 36 if (MaxOffset < 0) 37 report_fatal_error( 38 "BufferSize too small to exercise specified Size configuration"); 39 MaxOffset /= AccessAlignment->value(); 40 return std::uniform_int_distribution<uint32_t>(0, MaxOffset); 41 } 42 43 OffsetDistribution::OffsetDistribution(size_t BufferSize, size_t MaxSizeValue, 44 MaybeAlign AccessAlignment) 45 : Distribution( 46 getOffsetDistribution(BufferSize, MaxSizeValue, AccessAlignment)), 47 Factor(AccessAlignment.valueOrOne().value()) {} 48 49 // Precomputes offset where to insert mismatches between the two buffers. 50 MismatchOffsetDistribution::MismatchOffsetDistribution(size_t BufferSize, 51 size_t MaxSizeValue, 52 size_t MismatchAt) 53 : MismatchAt(MismatchAt) { 54 if (MismatchAt <= 1) 55 return; 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); 62 } 63 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; 68 }; 69 const auto CacheIt = find_if(CacheInfos, IsL1DataCache); 70 if (CacheIt != CacheInfos.end()) 71 return CacheIt->Size; 72 report_fatal_error("Unable to read L1 Cache Data Size"); 73 } 74 75 static size_t getAvailableBufferSize() { 76 static constexpr int64_t KiB = 1024; 77 static constexpr int64_t ParameterStorageBytes = 4 * KiB; 78 static constexpr int64_t L1LeftAsideBytes = 1 * KiB; 79 return getL1DataCacheSize() - L1LeftAsideBytes - ParameterStorageBytes; 80 } 81 82 ParameterBatch::ParameterBatch(size_t BufferCount) 83 : BufferSize(getAvailableBufferSize() / BufferCount), 84 BatchSize(BufferSize / sizeof(ParameterType)), Parameters(BatchSize) { 85 if (BufferSize <= 0 || BatchSize < 100) 86 report_fatal_error("Not enough L1 cache"); 87 } 88 89 size_t ParameterBatch::getBatchBytes() const { 90 size_t BatchBytes = 0; 91 for (auto &P : Parameters) 92 BatchBytes += P.SizeBytes; 93 return BatchBytes; 94 } 95 96 void ParameterBatch::checkValid(const ParameterType &P) const { 97 if (P.OffsetBytes + P.SizeBytes >= BufferSize) 98 report_fatal_error( 99 llvm::Twine("Call would result in buffer overflow: Offset=") 100 .concat(llvm::Twine(P.OffsetBytes)) 101 .concat(", Size=") 102 .concat(llvm::Twine(P.SizeBytes)) 103 .concat(", BufferSize=") 104 .concat(llvm::Twine(BufferSize))); 105 } 106 107 CopySetup::CopySetup() 108 : ParameterBatch(2), SrcBuffer(ParameterBatch::BufferSize), 109 DstBuffer(ParameterBatch::BufferSize) {} 110 111 ComparisonSetup::ComparisonSetup() 112 : ParameterBatch(2), LhsBuffer(ParameterBatch::BufferSize), 113 RhsBuffer(ParameterBatch::BufferSize) { 114 // The memcmp buffers always compare equal. 115 memset(LhsBuffer.begin(), 0xF, BufferSize); 116 memset(RhsBuffer.begin(), 0xF, BufferSize); 117 } 118 119 SetSetup::SetSetup() 120 : ParameterBatch(1), DstBuffer(ParameterBatch::BufferSize) {} 121 122 } // namespace libc_benchmarks 123 } // namespace llvm 124