memory_allocator_test.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // Copyright (c) 2019 Intel Corporation
  3. // This source code is licensed under both the GPLv2 (found in the
  4. // COPYING file in the root directory) and Apache 2.0 License
  5. // (found in the LICENSE.Apache file in the root directory).
  6. #include <cstdio>
  7. #include "memory/jemalloc_nodump_allocator.h"
  8. #include "memory/memkind_kmem_allocator.h"
  9. #include "rocksdb/cache.h"
  10. #include "rocksdb/convenience.h"
  11. #include "rocksdb/db.h"
  12. #include "rocksdb/options.h"
  13. #include "table/block_based/block_based_table_factory.h"
  14. #include "test_util/testharness.h"
  15. #include "utilities/memory_allocators.h"
  16. namespace ROCKSDB_NAMESPACE {
  17. // TODO: the tests do not work in LITE mode due to relying on
  18. // `CreateFromString()` to create non-default memory allocators.
  19. class MemoryAllocatorTest
  20. : public testing::Test,
  21. public ::testing::WithParamInterface<std::tuple<std::string, bool>> {
  22. public:
  23. MemoryAllocatorTest() {
  24. std::tie(id_, supported_) = GetParam();
  25. Status s =
  26. MemoryAllocator::CreateFromString(ConfigOptions(), id_, &allocator_);
  27. EXPECT_EQ(supported_, s.ok());
  28. }
  29. bool IsSupported() { return supported_; }
  30. std::shared_ptr<MemoryAllocator> allocator_;
  31. std::string id_;
  32. private:
  33. bool supported_;
  34. };
  35. TEST_P(MemoryAllocatorTest, Allocate) {
  36. if (!IsSupported()) {
  37. return;
  38. }
  39. void* p = allocator_->Allocate(1024);
  40. ASSERT_NE(p, nullptr);
  41. size_t size = allocator_->UsableSize(p, 1024);
  42. ASSERT_GE(size, 1024);
  43. allocator_->Deallocate(p);
  44. }
  45. TEST_P(MemoryAllocatorTest, CreateAllocator) {
  46. ConfigOptions config_options;
  47. config_options.ignore_unknown_options = false;
  48. config_options.ignore_unsupported_options = false;
  49. std::shared_ptr<MemoryAllocator> orig, copy;
  50. Status s = MemoryAllocator::CreateFromString(config_options, id_, &orig);
  51. if (!IsSupported()) {
  52. ASSERT_TRUE(s.IsNotSupported());
  53. } else {
  54. ASSERT_OK(s);
  55. ASSERT_NE(orig, nullptr);
  56. std::string str = orig->ToString(config_options);
  57. ASSERT_OK(MemoryAllocator::CreateFromString(config_options, str, &copy));
  58. ASSERT_EQ(orig, copy);
  59. }
  60. }
  61. TEST_P(MemoryAllocatorTest, DatabaseBlockCache) {
  62. if (!IsSupported()) {
  63. // Check if a memory node is available for allocation
  64. }
  65. // Create database with block cache using the MemoryAllocator
  66. Options options;
  67. std::string dbname = test::PerThreadDBPath("allocator_test");
  68. ASSERT_OK(DestroyDB(dbname, options));
  69. options.create_if_missing = true;
  70. BlockBasedTableOptions table_options;
  71. auto cache = NewLRUCache(1024 * 1024, 6, false, 0.0, allocator_);
  72. table_options.block_cache = cache;
  73. options.table_factory.reset(NewBlockBasedTableFactory(table_options));
  74. DB* db = nullptr;
  75. Status s = DB::Open(options, dbname, &db);
  76. ASSERT_OK(s);
  77. ASSERT_NE(db, nullptr);
  78. ASSERT_LE(cache->GetUsage(), 104); // Cache will contain stats
  79. // Write 2kB (200 values, each 10 bytes)
  80. int num_keys = 200;
  81. WriteOptions wo;
  82. std::string val = "0123456789";
  83. for (int i = 0; i < num_keys; i++) {
  84. std::string key = std::to_string(i);
  85. s = db->Put(wo, Slice(key), Slice(val));
  86. ASSERT_OK(s);
  87. }
  88. ASSERT_OK(db->Flush(FlushOptions())); // Flush all data from memtable so that
  89. // reads are from block cache
  90. // Read and check block cache usage
  91. ReadOptions ro;
  92. std::string result;
  93. for (int i = 0; i < num_keys; i++) {
  94. std::string key = std::to_string(i);
  95. s = db->Get(ro, key, &result);
  96. ASSERT_OK(s);
  97. ASSERT_EQ(result, val);
  98. }
  99. ASSERT_GT(cache->GetUsage(), 2000);
  100. // Close database
  101. s = db->Close();
  102. ASSERT_OK(s);
  103. delete db;
  104. ASSERT_OK(DestroyDB(dbname, options));
  105. }
  106. class CreateMemoryAllocatorTest : public testing::Test {
  107. public:
  108. CreateMemoryAllocatorTest() {
  109. config_options_.ignore_unknown_options = false;
  110. config_options_.ignore_unsupported_options = false;
  111. }
  112. ConfigOptions config_options_;
  113. };
  114. TEST_F(CreateMemoryAllocatorTest, JemallocOptionsTest) {
  115. std::shared_ptr<MemoryAllocator> allocator;
  116. std::string id = std::string("id=") + JemallocNodumpAllocator::kClassName();
  117. Status s = MemoryAllocator::CreateFromString(config_options_, id, &allocator);
  118. if (!JemallocNodumpAllocator::IsSupported()) {
  119. ASSERT_NOK(s);
  120. ROCKSDB_GTEST_BYPASS("JEMALLOC not supported");
  121. return;
  122. }
  123. ASSERT_OK(s);
  124. ASSERT_NE(allocator, nullptr);
  125. JemallocAllocatorOptions jopts;
  126. auto opts = allocator->GetOptions<JemallocAllocatorOptions>();
  127. ASSERT_NE(opts, nullptr);
  128. ASSERT_EQ(opts->limit_tcache_size, jopts.limit_tcache_size);
  129. ASSERT_EQ(opts->tcache_size_lower_bound, jopts.tcache_size_lower_bound);
  130. ASSERT_EQ(opts->tcache_size_upper_bound, jopts.tcache_size_upper_bound);
  131. ASSERT_NOK(MemoryAllocator::CreateFromString(
  132. config_options_,
  133. id + "; limit_tcache_size=true; tcache_size_lower_bound=4096; "
  134. "tcache_size_upper_bound=1024",
  135. &allocator));
  136. ASSERT_OK(MemoryAllocator::CreateFromString(
  137. config_options_,
  138. id + "; limit_tcache_size=false; tcache_size_lower_bound=4096; "
  139. "tcache_size_upper_bound=1024",
  140. &allocator));
  141. opts = allocator->GetOptions<JemallocAllocatorOptions>();
  142. ASSERT_NE(opts, nullptr);
  143. ASSERT_EQ(opts->limit_tcache_size, false);
  144. ASSERT_EQ(opts->tcache_size_lower_bound, 4096U);
  145. ASSERT_EQ(opts->tcache_size_upper_bound, 1024U);
  146. ASSERT_OK(MemoryAllocator::CreateFromString(
  147. config_options_,
  148. id + "; limit_tcache_size=true; tcache_size_upper_bound=4096; "
  149. "tcache_size_lower_bound=1024",
  150. &allocator));
  151. opts = allocator->GetOptions<JemallocAllocatorOptions>();
  152. ASSERT_NE(opts, nullptr);
  153. ASSERT_EQ(opts->limit_tcache_size, true);
  154. ASSERT_EQ(opts->tcache_size_lower_bound, 1024U);
  155. ASSERT_EQ(opts->tcache_size_upper_bound, 4096U);
  156. }
  157. TEST_F(CreateMemoryAllocatorTest, NewJemallocNodumpAllocator) {
  158. JemallocAllocatorOptions jopts;
  159. std::shared_ptr<MemoryAllocator> allocator;
  160. jopts.limit_tcache_size = true;
  161. jopts.tcache_size_lower_bound = 2 * 1024;
  162. jopts.tcache_size_upper_bound = 1024;
  163. ASSERT_NOK(NewJemallocNodumpAllocator(jopts, nullptr));
  164. Status s = NewJemallocNodumpAllocator(jopts, &allocator);
  165. std::string msg;
  166. if (!JemallocNodumpAllocator::IsSupported(&msg)) {
  167. ASSERT_NOK(s);
  168. ROCKSDB_GTEST_BYPASS("JEMALLOC not supported");
  169. return;
  170. }
  171. ASSERT_NOK(s); // Invalid options
  172. ASSERT_EQ(allocator, nullptr);
  173. jopts.tcache_size_upper_bound = 4 * 1024;
  174. ASSERT_OK(NewJemallocNodumpAllocator(jopts, &allocator));
  175. ASSERT_NE(allocator, nullptr);
  176. auto opts = allocator->GetOptions<JemallocAllocatorOptions>();
  177. ASSERT_EQ(opts->tcache_size_upper_bound, jopts.tcache_size_upper_bound);
  178. ASSERT_EQ(opts->tcache_size_lower_bound, jopts.tcache_size_lower_bound);
  179. ASSERT_EQ(opts->limit_tcache_size, jopts.limit_tcache_size);
  180. jopts.limit_tcache_size = false;
  181. ASSERT_OK(NewJemallocNodumpAllocator(jopts, &allocator));
  182. ASSERT_NE(allocator, nullptr);
  183. opts = allocator->GetOptions<JemallocAllocatorOptions>();
  184. ASSERT_EQ(opts->tcache_size_upper_bound, jopts.tcache_size_upper_bound);
  185. ASSERT_EQ(opts->tcache_size_lower_bound, jopts.tcache_size_lower_bound);
  186. ASSERT_EQ(opts->limit_tcache_size, jopts.limit_tcache_size);
  187. }
  188. INSTANTIATE_TEST_CASE_P(DefaultMemoryAllocator, MemoryAllocatorTest,
  189. ::testing::Values(std::make_tuple(
  190. DefaultMemoryAllocator::kClassName(), true)));
  191. #ifdef MEMKIND
  192. INSTANTIATE_TEST_CASE_P(
  193. MemkindkMemAllocator, MemoryAllocatorTest,
  194. ::testing::Values(std::make_tuple(MemkindKmemAllocator::kClassName(),
  195. MemkindKmemAllocator::IsSupported())));
  196. #endif // MEMKIND
  197. #ifdef ROCKSDB_JEMALLOC
  198. INSTANTIATE_TEST_CASE_P(
  199. JemallocNodumpAllocator, MemoryAllocatorTest,
  200. ::testing::Values(std::make_tuple(JemallocNodumpAllocator::kClassName(),
  201. JemallocNodumpAllocator::IsSupported())));
  202. #endif // ROCKSDB_JEMALLOC
  203. } // namespace ROCKSDB_NAMESPACE
  204. int main(int argc, char** argv) {
  205. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  206. ::testing::InitGoogleTest(&argc, argv);
  207. return RUN_ALL_TESTS();
  208. }