in velox/common/file/benchmark/ReadBenchmark.h [135:274]
void randomReads(
int32_t size,
int32_t gap,
int32_t count,
int32_t repeats,
Mode mode,
bool parallel) {
clearCache();
std::vector<folly::Promise<bool>> promises;
std::vector<folly::SemiFuture<bool>> futures;
uint64_t usec = 0;
std::string label;
{
MicrosecondTimer timer(&usec);
int32_t rangeSize = size * count + gap * (count - 1);
auto& globalScratch = getScratch(rangeSize);
globalScratch.buffer.resize(rangeSize);
globalScratch.bufferCopy.resize(rangeSize);
for (auto repeat = 0; repeat < repeats; ++repeat) {
std::unique_ptr<folly::Promise<bool>> promise;
if (parallel) {
auto [tempPromise, future] = folly::makePromiseContract<bool>();
promise = std::make_unique<folly::Promise<bool>>();
*promise = std::move(tempPromise);
futures.push_back(std::move(future));
}
int64_t offset = folly::Random::rand64(rng_) % (fileSize_ - rangeSize);
switch (mode) {
case Mode::Pread:
label = "1 pread";
if (parallel) {
executor_->add([offset,
gap,
size,
count,
rangeSize,
this,
capturedPromise = std::move(promise)]() {
auto& scratch = getScratch(rangeSize);
readFile_->pread(offset, rangeSize, scratch.buffer.data());
for (auto i = 0; i < count; ++i) {
memcpy(
scratch.bufferCopy.data() + i * size,
scratch.buffer.data() + i * (size + gap),
size);
}
capturedPromise->setValue(true);
}
);
} else {
readFile_->pread(offset, rangeSize, globalScratch.buffer.data());
for (auto i = 0; i < count; ++i) {
memcpy(
globalScratch.bufferCopy.data() + i * size,
globalScratch.buffer.data() + i * (size + gap),
size);
}
}
break;
case Mode::Preadv: {
label = "1 preadv";
if (parallel) {
executor_->add([offset,
gap,
size,
rangeSize,
this,
capturedPromise = std::move(promise)]() {
auto& scratch = getScratch(rangeSize);
std::vector<folly::Range<char*>> ranges;
for (auto start = 0; start < rangeSize; start += size + gap) {
ranges.push_back(
folly::Range<char*>(scratch.buffer.data() + start, size));
if (gap && start + gap < rangeSize) {
ranges.push_back(folly::Range<char*>(nullptr, gap));
}
}
readFile_->preadv(offset, ranges);
capturedPromise->setValue(true);
});
} else {
std::vector<folly::Range<char*>> ranges;
for (auto start = 0; start < rangeSize; start += size + gap) {
ranges.push_back(folly::Range<char*>(
globalScratch.buffer.data() + start, size));
if (gap && start + gap < rangeSize) {
ranges.push_back(folly::Range<char*>(nullptr, gap));
}
}
readFile_->preadv(offset, ranges);
}
break;
}
case Mode::Multiple: {
label = "multiple pread";
if (parallel) {
executor_->add([offset,
gap,
size,
count,
rangeSize,
this,
capturedPromise = std::move(promise)]() {
auto& scratch = getScratch(rangeSize);
for (auto counter = 0; counter < count; ++counter) {
readFile_->pread(
offset + counter * (size + gap),
size,
scratch.buffer.data() + counter * size);
}
capturedPromise->setValue(true);
});
} else {
for (auto counter = 0; counter < count; ++counter) {
readFile_->pread(
offset + counter * (size + gap),
size,
globalScratch.buffer.data() + counter * size);
}
}
break;
}
}
}
if (parallel) {
auto& exec = folly::QueuedImmediateExecutor::instance();
for (int32_t i = futures.size() - 1; i >= 0; --i) {
std::move(futures[i]).via(&exec).wait();
}
}
}
std::cout << fmt::format(
"{} MB/s {} {}",
(static_cast<float>(count) * size * repeats) / usec,
label,
parallel ? "mt" : "")
<< std::endl;
}