Skip to content

Commit 957cf58

Browse files
Jaesoo Leefacebook-github-bot
authored andcommitted
Added AsyncDevice based on io_uring
Summary: This change implements the AsyncDevice which performs the IOs asynchronously using io_uring. To do so, this change uses the folly's io_uring implementation called IoUring which supports handling the completion using folly's EventBase mechanism asynchronously. This change supports the running IOs in either of dedicated NavyThread called IoThread or caller's NavyThread depending on option. When the Device API is called on unknown context other than NavyThread, the execution is fall back to the synchronous mode using legacy pread/pwrite instead of io_uring. Reviewed By: therealgymmy Differential Revision: D45932967 fbshipit-source-id: 3ea0b911768cd6839d5d07635980320150aa0370
1 parent 38a0783 commit 957cf58

File tree

14 files changed

+631
-15
lines changed

14 files changed

+631
-15
lines changed

cachelib/allocator/nvmcache/NavyConfig.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,17 @@ RandomAPConfig& RandomAPConfig::setAdmProbability(double admProbability) {
6363
return *this;
6464
}
6565

66-
// file settings
66+
// device settings
67+
void NavyConfig::setIoThreads(unsigned int numIoThreads,
68+
unsigned int qDepthPerThread) {
69+
if (usesRaidFiles()) {
70+
throw std::invalid_argument(
71+
"AsyncDevice is not yet supported for RAID files");
72+
}
73+
numIoThreads_ = numIoThreads;
74+
qDepthPerThread_ = qDepthPerThread;
75+
}
76+
6777
void NavyConfig::setSimpleFile(const std::string& fileName,
6878
uint64_t fileSize,
6979
bool truncateFile) {
@@ -219,6 +229,9 @@ std::map<std::string, std::string> NavyConfig::serialize() const {
219229
configMap["navyConfig::navyReqOrderingShards"] =
220230
folly::to<std::string>(navyReqOrderingShards_);
221231

232+
configMap["navyConfig::numIoThreads"] = folly::to<std::string>(numIoThreads_);
233+
configMap["navyConfig::QDepthPerThread"] =
234+
folly::to<std::string>(qDepthPerThread_);
222235
// Other settings
223236
configMap["navyConfig::maxConcurrentInserts"] =
224237
folly::to<std::string>(maxConcurrentInserts_);

cachelib/allocator/nvmcache/NavyConfig.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ class NavyConfig {
478478
const RandomAPConfig& randomAdmPolicy() const { return randomAPConfig_; }
479479

480480
// ============ Device settings =============
481+
unsigned int getNumIoThreads() const { return numIoThreads_; }
482+
unsigned int getQDepthPerThread() const { return qDepthPerThread_; }
481483
uint64_t getBlockSize() const { return blockSize_; }
482484
const std::string& getFileName() const;
483485
const std::vector<std::string>& getRaidPaths() const;
@@ -520,6 +522,12 @@ class NavyConfig {
520522
RandomAPConfig& enableRandomAdmPolicy();
521523

522524
// ============ Device settings =============
525+
// Set the number of IO threads and queue depth per thread.
526+
// If set, AsyncDevice instead of Device will be created with given
527+
// configurations. For now, AsyncDevice is not supported for RAID.
528+
void setIoThreads(unsigned int numIoThreads, unsigned int qDepthPerThread);
529+
530+
// Set the device block size, i.e., minimum unit of IO
523531
void setBlockSize(uint64_t blockSize) noexcept { blockSize_ = blockSize; }
524532
// Set the parameters for a simple file.
525533
// @throw std::invalid_argument if RAID files have been already set.
@@ -629,6 +637,10 @@ class NavyConfig {
629637
// This value needs to be non-zero.
630638
uint64_t navyReqOrderingShards_{20};
631639

640+
// Number of IO threads for AsyncDevice.
641+
unsigned int numIoThreads_{0};
642+
// Number of queue depth per thread for AsyncDevice.
643+
unsigned int qDepthPerThread_{64};
632644
// ============ Other settings =============
633645
// Maximum number of concurrent inserts we allow globally for Navy.
634646
// 0 means unlimited.

cachelib/allocator/nvmcache/NavySetup.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,18 @@ std::unique_ptr<cachelib::navy::Device> createDevice(
324324
std::move(encryptor),
325325
maxDeviceWriteSize > 0 ? alignDown(maxDeviceWriteSize, blockSize) : 0);
326326
} else if (config.usesSimpleFile()) {
327+
if (config.getNumIoThreads() > 0) {
328+
return cachelib::navy::createAsyncFileDevice(
329+
config.getFileName(),
330+
config.getFileSize(),
331+
config.getTruncateFile(),
332+
blockSize,
333+
config.getNumIoThreads(),
334+
config.getQDepthPerThread(),
335+
std::move(encryptor),
336+
maxDeviceWriteSize > 0 ? alignDown(maxDeviceWriteSize, blockSize)
337+
: 0);
338+
}
327339
return cachelib::navy::createFileDevice(
328340
config.getFileName(),
329341
config.getFileSize(),

cachelib/allocator/nvmcache/tests/NavyConfigTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ TEST(NavyConfigTest, Serialization) {
183183
expectedConfigMap["navyConfig::fileSize"] = "10485760";
184184
expectedConfigMap["navyConfig::truncateFile"] = "false";
185185
expectedConfigMap["navyConfig::deviceMaxWriteSize"] = "4194304";
186+
expectedConfigMap["navyConfig::numIoThreads"] = "0";
187+
expectedConfigMap["navyConfig::QDepthPerThread"] = "64";
186188

187189
expectedConfigMap["navyConfig::blockCacheLru"] = "false";
188190
expectedConfigMap["navyConfig::blockCacheRegionSize"] = "16777216";

cachelib/cachebench/cache/Cache-inl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ Cache<Allocator>::Cache(const CacheConfig& config,
212212

213213
nvmConfig.navyConfig.setMaxParcelMemoryMB(config_.navyParcelMemoryMB);
214214

215+
if (config_.navyNumIoThreads > 0) {
216+
nvmConfig.navyConfig.setIoThreads(config_.navyNumIoThreads,
217+
config_.navyQDepthPerThread);
218+
}
215219
nvmConfig.navyConfig.setReaderAndWriterThreads(config_.navyReaderThreads,
216220
config_.navyWriterThreads);
217221

cachelib/cachebench/util/CacheConfig.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ CacheConfig::CacheConfig(const folly::dynamic& configJson) {
7474
JSONSetVal(configJson, navyProbabilityReinsertionThreshold);
7575
JSONSetVal(configJson, navyReaderThreads);
7676
JSONSetVal(configJson, navyWriterThreads);
77+
JSONSetVal(configJson, navyNumIoThreads);
78+
JSONSetVal(configJson, navyQDepthPerThread);
7779
JSONSetVal(configJson, navyCleanRegions);
7880
JSONSetVal(configJson, navyAdmissionWriteRateMB);
7981
JSONSetVal(configJson, navyMaxConcurrentInserts);
@@ -105,7 +107,7 @@ CacheConfig::CacheConfig(const folly::dynamic& configJson) {
105107
// if you added new fields to the configuration, update the JSONSetVal
106108
// to make them available for the json configs and increment the size
107109
// below
108-
checkCorrectSize<CacheConfig, 728>();
110+
checkCorrectSize<CacheConfig, 736>();
109111

110112
if (numPools != poolSizes.size()) {
111113
throw std::invalid_argument(folly::sformat(

cachelib/cachebench/util/CacheConfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ struct CacheConfig : public JSONConfig {
184184
// number of asynchronous worker thread for navy write operation,
185185
uint32_t navyWriterThreads{32};
186186

187+
uint32_t navyNumIoThreads{0};
188+
189+
uint32_t navyQDepthPerThread{1024};
190+
187191
// buffer of clean regions to be maintained free to ensure writes
188192
// into navy don't queue behind a reclaim of region.
189193
uint32_t navyCleanRegions{1};

cachelib/navy/Factory.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "cachelib/navy/block_cache/BlockCache.h"
2828
#include "cachelib/navy/block_cache/FifoPolicy.h"
2929
#include "cachelib/navy/block_cache/LruPolicy.h"
30+
#include "cachelib/navy/common/AsyncDevice.h"
3031
#include "cachelib/navy/driver/Driver.h"
3132
#include "cachelib/navy/serialization/RecordIO.h"
3233

@@ -494,6 +495,27 @@ std::unique_ptr<Device> createFileDevice(
494495
std::move(encryptor), maxDeviceWriteSize);
495496
}
496497

498+
std::unique_ptr<Device> createAsyncFileDevice(
499+
std::string fileName,
500+
uint64_t singleFileSize,
501+
bool truncateFile,
502+
uint32_t blockSize,
503+
uint32_t numIoThreads,
504+
uint32_t qDepthPerThread,
505+
std::shared_ptr<DeviceEncryptor> encryptor,
506+
uint32_t maxDeviceWriteSize) {
507+
folly::File f;
508+
try {
509+
f = openCacheFile(fileName, singleFileSize, truncateFile);
510+
} catch (const std::exception& e) {
511+
XLOG(ERR) << "Exception in openCacheFile: " << e.what();
512+
throw;
513+
}
514+
return createAsyncIoFileDevice(std::move(f), singleFileSize, blockSize,
515+
numIoThreads, qDepthPerThread,
516+
std::move(encryptor), maxDeviceWriteSize);
517+
}
518+
497519
} // namespace navy
498520
} // namespace cachelib
499521
} // namespace facebook

cachelib/navy/Factory.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,27 @@ std::unique_ptr<Device> createFileDevice(
228228
std::shared_ptr<DeviceEncryptor> encryptor,
229229
uint32_t maxDeviceWriteSize);
230230

231+
// Creates a direct IO single file device.
232+
//
233+
// @param fileName name of the file
234+
// @param singleFileSize size of the file
235+
// @param truncateFile whether to truncate the file
236+
// @param blockSize device block size
237+
// @param numIoThreads the number of IO threads. If 0 and EventBase is
238+
// not available, IOs will be fall back to sync IO
239+
// @param qDeptherThread queue depth per each IO thread
240+
// @param encryptor encryption object
241+
// @param maxDeviceWriteSize device maximum granularity of writes
242+
std::unique_ptr<Device> createAsyncFileDevice(
243+
std::string fileName,
244+
uint64_t singleFileSize,
245+
bool truncateFile,
246+
uint32_t blockSize,
247+
uint32_t numIoThreads,
248+
uint32_t qDepthPerThread,
249+
std::shared_ptr<DeviceEncryptor> encryptor,
250+
uint32_t maxDeviceWriteSize);
251+
231252
} // namespace navy
232253
} // namespace cachelib
233254
} // namespace facebook

0 commit comments

Comments
 (0)