flat_map_unittest.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. #include <gtest/gtest.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <map>
  21. #include <vector>
  22. #include "butil/time.h"
  23. #include "butil/macros.h"
  24. #include "butil/string_printf.h"
  25. #include "butil/logging.h"
  26. #include "butil/containers/hash_tables.h"
  27. #include "butil/containers/flat_map.h"
  28. #include "butil/containers/pooled_map.h"
  29. #include "butil/containers/case_ignored_flat_map.h"
  30. namespace {
  31. class FlatMapTest : public ::testing::Test{
  32. protected:
  33. FlatMapTest(){};
  34. virtual ~FlatMapTest(){};
  35. virtual void SetUp() {
  36. };
  37. virtual void TearDown() {
  38. };
  39. };
  40. int g_foo_ctor = 0;
  41. int g_foo_copy_ctor = 0;
  42. int g_foo_assign = 0;
  43. struct Foo {
  44. Foo() { ++g_foo_ctor; }
  45. Foo(const Foo&) { ++g_foo_copy_ctor; }
  46. void operator=(const Foo&) { ++g_foo_assign; }
  47. };
  48. struct Bar {
  49. int x;
  50. };
  51. TEST_F(FlatMapTest, initialization_of_values) {
  52. // Construct non-POD values w/o copy-construction.
  53. butil::FlatMap<int, Foo> map;
  54. ASSERT_EQ(0, map.init(32));
  55. ASSERT_EQ(0, g_foo_ctor);
  56. ASSERT_EQ(0, g_foo_copy_ctor);
  57. ASSERT_EQ(0, g_foo_assign);
  58. map[1];
  59. ASSERT_EQ(1, g_foo_ctor);
  60. ASSERT_EQ(0, g_foo_copy_ctor);
  61. ASSERT_EQ(0, g_foo_assign);
  62. // Zeroize POD values.
  63. butil::FlatMap<int, Bar> map2;
  64. ASSERT_EQ(0, map2.init(32));
  65. Bar& g = map2[1];
  66. ASSERT_EQ(0, g.x);
  67. g.x = 123;
  68. ASSERT_EQ(1u, map2.erase(1));
  69. ASSERT_EQ(123, g.x); // g is still accessible in this case.
  70. Bar& g2 = map2[1];
  71. ASSERT_EQ(&g, &g2);
  72. ASSERT_EQ(0, g2.x);
  73. }
  74. TEST_F(FlatMapTest, swap_pooled_allocator) {
  75. butil::details::PooledAllocator<int, 128> a1;
  76. a1.allocate(1);
  77. const void* p1 = a1._pool._blocks;
  78. butil::details::PooledAllocator<int, 128> a2;
  79. a2.allocate(1);
  80. const void* p2 = a2._pool._blocks;
  81. std::swap(a1, a2);
  82. ASSERT_EQ(p2, a1._pool._blocks);
  83. ASSERT_EQ(p1, a2._pool._blocks);
  84. }
  85. TEST_F(FlatMapTest, copy_flat_map) {
  86. typedef butil::FlatMap<std::string, std::string> Map;
  87. Map uninit_m1;
  88. ASSERT_FALSE(uninit_m1.initialized());
  89. ASSERT_TRUE(uninit_m1.empty());
  90. // self assignment does nothing.
  91. uninit_m1 = uninit_m1;
  92. ASSERT_FALSE(uninit_m1.initialized());
  93. ASSERT_TRUE(uninit_m1.empty());
  94. // Copy construct from uninitialized map.
  95. Map uninit_m2 = uninit_m1;
  96. ASSERT_FALSE(uninit_m2.initialized());
  97. ASSERT_TRUE(uninit_m2.empty());
  98. // assign uninitialized map to uninitialized map.
  99. Map uninit_m3;
  100. uninit_m3 = uninit_m1;
  101. ASSERT_FALSE(uninit_m3.initialized());
  102. ASSERT_TRUE(uninit_m3.empty());
  103. // assign uninitialized map to initialized map.
  104. Map init_m4;
  105. ASSERT_EQ(0, init_m4.init(16));
  106. ASSERT_TRUE(init_m4.initialized());
  107. init_m4["hello"] = "world";
  108. ASSERT_EQ(1u, init_m4.size());
  109. init_m4 = uninit_m1;
  110. ASSERT_TRUE(init_m4.initialized());
  111. ASSERT_TRUE(init_m4.empty());
  112. Map m1;
  113. ASSERT_EQ(0, m1.init(16));
  114. m1["hello"] = "world";
  115. m1["foo"] = "bar";
  116. ASSERT_TRUE(m1.initialized());
  117. ASSERT_EQ(2u, m1.size());
  118. // self assignment does nothing.
  119. m1 = m1;
  120. ASSERT_EQ(2u, m1.size());
  121. ASSERT_EQ("world", m1["hello"]);
  122. ASSERT_EQ("bar", m1["foo"]);
  123. // Copy construct from initialized map.
  124. Map m2 = m1;
  125. ASSERT_TRUE(m2.initialized());
  126. ASSERT_EQ(2u, m2.size());
  127. ASSERT_EQ("world", m2["hello"]);
  128. ASSERT_EQ("bar", m2["foo"]);
  129. // assign initialized map to uninitialized map.
  130. Map m3;
  131. m3 = m1;
  132. ASSERT_TRUE(m3.initialized());
  133. ASSERT_EQ(2u, m3.size());
  134. ASSERT_EQ("world", m3["hello"]);
  135. ASSERT_EQ("bar", m3["foo"]);
  136. // assign initialized map to initialized map (triggering resize)
  137. Map m4;
  138. ASSERT_EQ(0, m4.init(2));
  139. ASSERT_LT(m4.bucket_count(), m1.bucket_count());
  140. const void* old_buckets4 = m4._buckets;
  141. m4 = m1;
  142. ASSERT_EQ(m1.bucket_count(), m4.bucket_count());
  143. ASSERT_NE(old_buckets4, m4._buckets);
  144. ASSERT_EQ(2u, m4.size());
  145. ASSERT_EQ("world", m4["hello"]);
  146. ASSERT_EQ("bar", m4["foo"]);
  147. // assign initialized map to initialized map (no resize)
  148. const size_t bcs[] = { 8, m1.bucket_count(), 32 };
  149. // less than m1.bucket_count but enough for holding the elements
  150. ASSERT_LT(bcs[0], m1.bucket_count());
  151. // larger than m1.bucket_count
  152. ASSERT_GT(bcs[2], m1.bucket_count());
  153. for (size_t i = 0; i < arraysize(bcs); ++i) {
  154. Map m5;
  155. ASSERT_EQ(0, m5.init(bcs[i]));
  156. const size_t old_bucket_count5 = m5.bucket_count();
  157. const void* old_buckets5 = m5._buckets;
  158. m5 = m1;
  159. ASSERT_EQ(old_bucket_count5, m5.bucket_count());
  160. ASSERT_EQ(old_buckets5, m5._buckets);
  161. ASSERT_EQ(2u, m5.size());
  162. ASSERT_EQ("world", m5["hello"]);
  163. ASSERT_EQ("bar", m5["foo"]);
  164. }
  165. }
  166. TEST_F(FlatMapTest, seek_by_string_piece) {
  167. butil::FlatMap<std::string, int> m;
  168. ASSERT_EQ(0, m.init(16));
  169. m["hello"] = 1;
  170. m["world"] = 2;
  171. butil::StringPiece k1("hello");
  172. ASSERT_TRUE(m.seek(k1));
  173. ASSERT_EQ(1, *m.seek(k1));
  174. butil::StringPiece k2("world");
  175. ASSERT_TRUE(m.seek(k2));
  176. ASSERT_EQ(2, *m.seek(k2));
  177. butil::StringPiece k3("heheda");
  178. ASSERT_TRUE(m.seek(k3) == NULL);
  179. }
  180. TEST_F(FlatMapTest, to_lower) {
  181. for (int c = -128; c < 128; ++c) {
  182. ASSERT_EQ((char)::tolower(c), butil::ascii_tolower(c)) << "c=" << c;
  183. }
  184. const size_t input_len = 102;
  185. char input[input_len + 1];
  186. char input2[input_len + 1];
  187. for (size_t i = 0; i < input_len; ++i) {
  188. int choice = rand() % 52;
  189. if (choice < 26) {
  190. input[i] = 'A' + choice;
  191. input2[i] = 'A' + choice;
  192. } else {
  193. input[i] = 'a' + choice - 26;
  194. input2[i] = 'a' + choice - 26;
  195. }
  196. }
  197. input[input_len] = '\0';
  198. input2[input_len] = '\0';
  199. butil::Timer tm1;
  200. butil::Timer tm2;
  201. butil::Timer tm3;
  202. int sum = 0;
  203. tm1.start();
  204. sum += strcasecmp(input, input2);
  205. tm1.stop();
  206. tm3.start();
  207. sum += strncasecmp(input, input2, input_len);
  208. tm3.stop();
  209. tm2.start();
  210. sum += memcmp(input, input2, input_len);
  211. tm2.stop();
  212. LOG(INFO) << "tm1=" << tm1.n_elapsed()
  213. << " tm2=" << tm2.n_elapsed()
  214. << " tm3=" << tm3.n_elapsed() << " " << sum;
  215. }
  216. TEST_F(FlatMapTest, __builtin_ctzl_perf) {
  217. int s = 0;
  218. const size_t N = 10000;
  219. butil::Timer tm1;
  220. tm1.start();
  221. for (size_t i = 1; i <= N; ++i) {
  222. s += __builtin_ctzl(i);
  223. }
  224. tm1.stop();
  225. LOG(INFO) << "__builtin_ctzl takes " << tm1.n_elapsed()/(double)N << "ns";
  226. }
  227. TEST_F(FlatMapTest, case_ignored_map) {
  228. butil::CaseIgnoredFlatMap<int> m1;
  229. ASSERT_EQ(0, m1.init(32));
  230. m1["Content-Type"] = 1;
  231. m1["content-Type"] = 10;
  232. m1["Host"] = 2;
  233. m1["HOST"] = 20;
  234. m1["Cache-Control"] = 3;
  235. m1["CachE-ControL"] = 30;
  236. ASSERT_EQ(10, m1["cONTENT-tYPE"]);
  237. ASSERT_EQ(20, m1["hOST"]);
  238. ASSERT_EQ(30, m1["cache-control"]);
  239. }
  240. TEST_F(FlatMapTest, case_ignored_set) {
  241. butil::CaseIgnoredFlatSet s1;
  242. ASSERT_EQ(0, s1.init(32));
  243. s1.insert("Content-Type");
  244. ASSERT_EQ(1ul, s1.size());
  245. s1.insert("Content-TYPE");
  246. ASSERT_EQ(1ul, s1.size());
  247. s1.insert("Host");
  248. ASSERT_EQ(2ul, s1.size());
  249. s1.insert("HOST");
  250. ASSERT_EQ(2ul, s1.size());
  251. s1.insert("Cache-Control");
  252. ASSERT_EQ(3ul, s1.size());
  253. s1.insert("CachE-ControL");
  254. ASSERT_EQ(3ul, s1.size());
  255. ASSERT_TRUE(s1.seek("cONTENT-tYPE"));
  256. ASSERT_TRUE(s1.seek("hOST"));
  257. ASSERT_TRUE(s1.seek("cache-control"));
  258. }
  259. TEST_F(FlatMapTest, make_sure_all_methods_compile) {
  260. typedef butil::FlatMap<int, long> M1;
  261. M1 m1;
  262. ASSERT_EQ(0, m1.init(32));
  263. ASSERT_EQ(0u, m1.size());
  264. m1[1] = 10;
  265. ASSERT_EQ(10, m1[1]);
  266. ASSERT_EQ(1u, m1.size());
  267. m1[2] = 20;
  268. ASSERT_EQ(20, m1[2]);
  269. ASSERT_EQ(2u, m1.size());
  270. m1.insert(1, 100);
  271. ASSERT_EQ(100, m1[1]);
  272. ASSERT_EQ(2u, m1.size());
  273. ASSERT_EQ(NULL, m1.seek(3));
  274. ASSERT_EQ(0u, m1.erase(3));
  275. ASSERT_EQ(2u, m1.size());
  276. ASSERT_EQ(1u, m1.erase(2));
  277. ASSERT_EQ(1u, m1.size());
  278. for (M1::iterator it = m1.begin(); it != m1.end(); ++it) {
  279. std::cout << "[" << it->first << "," << it->second << "] ";
  280. }
  281. std::cout << std::endl;
  282. for (M1::const_iterator it = m1.begin(); it != m1.end(); ++it) {
  283. std::cout << "[" << it->first << "," << it->second << "] ";
  284. }
  285. std::cout << std::endl;
  286. typedef butil::FlatSet<int> S1;
  287. S1 s1;
  288. ASSERT_EQ(0, s1.init(32));
  289. ASSERT_EQ(0u, s1.size());
  290. s1.insert(1);
  291. ASSERT_TRUE(s1.seek(1));
  292. ASSERT_EQ(1u, s1.size());
  293. s1.insert(2);
  294. ASSERT_TRUE(s1.seek(2));
  295. ASSERT_EQ(2u, s1.size());
  296. s1.insert(1);
  297. ASSERT_TRUE(s1.seek(1));
  298. ASSERT_EQ(2u, s1.size());
  299. ASSERT_EQ(NULL, s1.seek(3));
  300. ASSERT_EQ(0u, s1.erase(3));
  301. ASSERT_EQ(2u, s1.size());
  302. ASSERT_EQ(1u, s1.erase(2));
  303. ASSERT_EQ(1u, s1.size());
  304. for (S1::iterator it = s1.begin(); it != s1.end(); ++it) {
  305. std::cout << "[" << *it << "] ";
  306. }
  307. std::cout << std::endl;
  308. for (S1::const_iterator it = s1.begin(); it != s1.end(); ++it) {
  309. std::cout << "[" << *it << "] ";
  310. }
  311. std::cout << std::endl;
  312. }
  313. TEST_F(FlatMapTest, flat_map_of_string) {
  314. std::vector<std::string> keys;
  315. butil::FlatMap<std::string, size_t> m1;
  316. std::map<std::string, size_t> m2;
  317. butil::hash_map<std::string, size_t> m3;
  318. const size_t N = 10000;
  319. ASSERT_EQ(0, m1.init(N));
  320. butil::Timer tm1, tm1_2, tm2, tm3;
  321. size_t sum = 0;
  322. keys.reserve(N);
  323. for (size_t i = 0; i < N; ++i) {
  324. keys.push_back(butil::string_printf("up_latency_as_key_%lu", i));
  325. }
  326. tm1.start();
  327. for (size_t i = 0; i < N; ++i) {
  328. m1[keys[i]] += i;
  329. }
  330. tm1.stop();
  331. tm2.start();
  332. for (size_t i = 0; i < N; ++i) {
  333. m2[keys[i]] += i;
  334. }
  335. tm2.stop();
  336. tm3.start();
  337. for (size_t i = 0; i < N; ++i) {
  338. m3[keys[i]] += i;
  339. }
  340. tm3.stop();
  341. LOG(INFO) << "inserting strings takes " << tm1.n_elapsed() / N
  342. << " " << tm2.n_elapsed() / N
  343. << " " << tm3.n_elapsed() / N;
  344. tm1.start();
  345. for (size_t i = 0; i < N; ++i) {
  346. sum += *m1.seek(keys[i]);
  347. }
  348. tm1.stop();
  349. tm2.start();
  350. for (size_t i = 0; i < N; ++i) {
  351. sum += m2.find(keys[i])->second;
  352. }
  353. tm2.stop();
  354. tm3.start();
  355. for (size_t i = 0; i < N; ++i) {
  356. sum += m3.find(keys[i])->second;
  357. }
  358. tm3.stop();
  359. LOG(INFO) << "finding strings takes " << tm1.n_elapsed()/N
  360. << " " << tm2.n_elapsed()/N << " " << tm3.n_elapsed()/N;
  361. tm1.start();
  362. for (size_t i = 0; i < N; ++i) {
  363. sum += *m1.seek(keys[i].c_str());
  364. }
  365. tm1.stop();
  366. tm2.start();
  367. for (size_t i = 0; i < N; ++i) {
  368. sum += m2.find(keys[i].c_str())->second;
  369. }
  370. tm2.stop();
  371. tm3.start();
  372. for (size_t i = 0; i < N; ++i) {
  373. sum += m3.find(keys[i].c_str())->second;
  374. }
  375. tm3.stop();
  376. tm1_2.start();
  377. for (size_t i = 0; i < N; ++i) {
  378. sum += *find_cstr(m1, keys[i].c_str());
  379. }
  380. tm1_2.stop();
  381. LOG(INFO) << "finding c_strings takes " << tm1.n_elapsed()/N
  382. << " " << tm2.n_elapsed()/N << " " << tm3.n_elapsed()/N
  383. << " " << tm1_2.n_elapsed()/N;
  384. for (size_t i = 0; i < N; ++i) {
  385. ASSERT_EQ(i, m1[keys[i]]) << "i=" << i;
  386. ASSERT_EQ(i, m2[keys[i]]);
  387. ASSERT_EQ(i, m3[keys[i]]);
  388. }
  389. }
  390. TEST_F(FlatMapTest, fast_iterator) {
  391. typedef butil::FlatMap<uint64_t, uint64_t> M1;
  392. typedef butil::SparseFlatMap<uint64_t, uint64_t> M2;
  393. M1 m1;
  394. M2 m2;
  395. ASSERT_EQ(0, m1.init(16384));
  396. ASSERT_EQ(-1, m1.init(1));
  397. ASSERT_EQ(0, m2.init(16384));
  398. ASSERT_EQ(NULL, m1._thumbnail);
  399. ASSERT_TRUE(NULL != m2._thumbnail);
  400. const size_t N = 170;
  401. std::vector<uint64_t> keys;
  402. keys.reserve(N);
  403. for (size_t i = 0; i < N; ++i) {
  404. keys.push_back(rand());
  405. }
  406. butil::Timer tm2;
  407. tm2.start();
  408. for (size_t i = 0; i < N; ++i) {
  409. m2[keys[i]] = i;
  410. }
  411. tm2.stop();
  412. butil::Timer tm1;
  413. tm1.start();
  414. for (size_t i = 0; i < N; ++i) {
  415. m1[keys[i]] = i;
  416. }
  417. tm1.stop();
  418. LOG(INFO) << "m1.insert=" << tm1.n_elapsed()/(double)N
  419. << "ns m2.insert=" << tm2.n_elapsed()/(double)N;
  420. tm1.start();
  421. for (M1::iterator it = m1.begin(); it != m1.end(); ++it);
  422. tm1.stop();
  423. tm2.start();
  424. for (M2::iterator it = m2.begin(); it != m2.end(); ++it);
  425. tm2.stop();
  426. LOG(INFO) << "m1.iterate=" << tm1.n_elapsed()/(double)N
  427. << "ns m2.iterate=" << tm2.n_elapsed()/(double)N;
  428. M1::iterator it1 = m1.begin();
  429. M2::iterator it2 = m2.begin();
  430. for ( ; it1 != m1.end() && it2 != m2.end(); ++it1, ++it2) {
  431. ASSERT_EQ(it1->first, it2->first);
  432. ASSERT_EQ(it1->second, it2->second);
  433. }
  434. ASSERT_EQ(m1.end(), it1);
  435. ASSERT_EQ(m2.end(), it2);
  436. }
  437. template <typename Key, typename Value, typename OnPause>
  438. static void list_flat_map(std::vector<Key>* keys,
  439. const butil::FlatMap<Key, Value>& map,
  440. size_t max_one_pass,
  441. OnPause& on_pause) {
  442. keys->clear();
  443. typedef butil::FlatMap<Key, Value> Map;
  444. size_t n = 0;
  445. for (typename Map::const_iterator it = map.begin(); it != map.end(); ++it) {
  446. if (++n >= max_one_pass) {
  447. typename Map::PositionHint hint;
  448. map.save_iterator(it, &hint);
  449. n = 0;
  450. on_pause(hint);
  451. it = map.restore_iterator(hint);
  452. if (it == map.begin()) { // resized
  453. keys->clear();
  454. }
  455. if (it == map.end()) {
  456. break;
  457. }
  458. }
  459. keys->push_back(it->first);
  460. }
  461. }
  462. typedef butil::FlatMap<uint64_t, uint64_t> PositionHintMap;
  463. static void fill_position_hint_map(PositionHintMap* map,
  464. std::vector<uint64_t>* keys) {
  465. srand(time(NULL));
  466. const size_t N = 170;
  467. if (!map->initialized()) {
  468. ASSERT_EQ(0, map->init(N * 3 / 2, 80));
  469. }
  470. keys->reserve(N);
  471. keys->clear();
  472. map->clear();
  473. for (size_t i = 0; i < N; ++i) {
  474. uint64_t key = rand();
  475. if (map->seek(key)) {
  476. continue;
  477. }
  478. keys->push_back(key);
  479. (*map)[key] = i;
  480. }
  481. LOG(INFO) << map->bucket_info();
  482. }
  483. struct CountOnPause {
  484. CountOnPause() : num_paused(0) {}
  485. void operator()(const PositionHintMap::PositionHint&) {
  486. ++num_paused;
  487. }
  488. size_t num_paused;
  489. };
  490. TEST_F(FlatMapTest, do_nothing_during_iteration) {
  491. PositionHintMap m1;
  492. std::vector<uint64_t> keys;
  493. fill_position_hint_map(&m1, &keys);
  494. // Iteration w/o insert/erasure should be same with single-threaded iteration.
  495. std::vector<uint64_t> keys_out;
  496. CountOnPause on_pause1;
  497. list_flat_map(&keys_out, m1, 10, on_pause1);
  498. EXPECT_EQ(m1.size() / 10, on_pause1.num_paused);
  499. ASSERT_EQ(m1.size(), keys_out.size());
  500. std::sort(keys_out.begin(), keys_out.end());
  501. for (size_t i = 0; i < keys_out.size(); ++i) {
  502. ASSERT_TRUE(m1.seek(keys_out[i])) << "i=" << i;
  503. if (i) {
  504. ASSERT_NE(keys_out[i-1], keys_out[i]) << "i=" << i;
  505. }
  506. }
  507. }
  508. struct RemoveInsertVisitedOnPause {
  509. RemoveInsertVisitedOnPause() : keys(NULL), map(NULL) {
  510. removed_keys.init(32);
  511. inserted_keys.init(32);
  512. }
  513. void operator()(const PositionHintMap::PositionHint& hint) {
  514. // Remove one
  515. do {
  516. int index = rand() % keys->size();
  517. uint64_t removed_key = (*keys)[index];
  518. if (removed_keys.seek(removed_key)) {
  519. continue;
  520. }
  521. ASSERT_EQ(1u, map->erase(removed_key));
  522. removed_keys.insert(removed_key);
  523. break;
  524. } while (true);
  525. // Insert one
  526. uint64_t inserted_key =
  527. ((rand() % hint.offset) + rand() * hint.nbucket);
  528. inserted_keys.insert(inserted_key);
  529. ++(*map)[inserted_key];
  530. }
  531. butil::FlatSet<uint64_t> removed_keys;
  532. butil::FlatSet<uint64_t> inserted_keys;
  533. const std::vector<uint64_t>* keys;
  534. PositionHintMap* map;
  535. };
  536. TEST_F(FlatMapTest, erase_insert_visited_during_iteration) {
  537. PositionHintMap m1;
  538. std::vector<uint64_t> keys;
  539. fill_position_hint_map(&m1, &keys);
  540. // Erase/insert visisted values should not affect the result.
  541. const size_t old_map_size = m1.size();
  542. RemoveInsertVisitedOnPause on_pause2;
  543. std::vector<uint64_t> keys_out;
  544. on_pause2.map = &m1;
  545. on_pause2.keys = &keys_out;
  546. list_flat_map(&keys_out, m1, 10, on_pause2);
  547. EXPECT_EQ(old_map_size / 10, on_pause2.removed_keys.size());
  548. ASSERT_EQ(old_map_size, keys_out.size());
  549. std::sort(keys_out.begin(), keys_out.end());
  550. for (size_t i = 0; i < keys_out.size(); ++i) {
  551. if (i) {
  552. ASSERT_NE(keys_out[i-1], keys_out[i]) << "i=" << i;
  553. }
  554. if (!m1.seek(keys_out[i])) {
  555. ASSERT_TRUE(on_pause2.removed_keys.seek(keys_out[i])) << "i=" << i;
  556. }
  557. ASSERT_FALSE(on_pause2.inserted_keys.seek(keys_out[i])) << "i=" << i;
  558. }
  559. }
  560. struct RemoveHintedOnPause {
  561. RemoveHintedOnPause() : map(NULL) {
  562. removed_keys.init(32);
  563. }
  564. void operator()(const PositionHintMap::PositionHint& hint) {
  565. uint64_t removed_key = hint.key;
  566. ASSERT_EQ(1u, map->erase(removed_key));
  567. removed_keys.insert(removed_key);
  568. }
  569. butil::FlatSet<uint64_t> removed_keys;
  570. PositionHintMap* map;
  571. };
  572. TEST_F(FlatMapTest, erase_hinted_during_iteration) {
  573. PositionHintMap m1;
  574. std::vector<uint64_t> keys;
  575. fill_position_hint_map(&m1, &keys);
  576. // Erasing hinted values
  577. RemoveHintedOnPause on_pause3;
  578. std::vector<uint64_t> keys_out;
  579. on_pause3.map = &m1;
  580. list_flat_map(&keys_out, m1, 10, on_pause3);
  581. // Not equal sometimes because of backward of iterator
  582. // EXPECT_EQ(m1.size() / 10, on_pause3.removed_keys.size());
  583. const size_t old_keys_out_size = keys_out.size();
  584. std::sort(keys_out.begin(), keys_out.end());
  585. keys_out.resize(std::unique(keys_out.begin(), keys_out.end()) - keys_out.begin());
  586. LOG_IF(INFO, keys_out.size() != old_keys_out_size)
  587. << "Iterated " << old_keys_out_size - keys_out.size()
  588. << " duplicated elements";
  589. ASSERT_EQ(m1.size(), keys_out.size());
  590. for (size_t i = 0; i < keys_out.size(); ++i) {
  591. if (i) {
  592. ASSERT_NE(keys_out[i-1], keys_out[i]) << "i=" << i;
  593. }
  594. if (!m1.seek(keys_out[i])) {
  595. ASSERT_TRUE(on_pause3.removed_keys.seek(keys_out[i])) << "i=" << i;
  596. }
  597. }
  598. }
  599. struct RemoveInsertUnvisitedOnPause {
  600. RemoveInsertUnvisitedOnPause()
  601. : keys_out(NULL), all_keys(NULL), map(NULL) {
  602. removed_keys.init(32);
  603. inserted_keys.init(32);
  604. }
  605. void operator()(const PositionHintMap::PositionHint& hint) {
  606. // Insert one
  607. do {
  608. uint64_t inserted_key =
  609. ((rand() % (hint.nbucket - hint.offset)) + hint.offset
  610. + rand() * hint.nbucket);
  611. if (std::find(all_keys->begin(), all_keys->end(), inserted_key)
  612. != all_keys->end()) {
  613. continue;
  614. }
  615. all_keys->push_back(inserted_key);
  616. inserted_keys.insert(inserted_key);
  617. ++(*map)[inserted_key];
  618. break;
  619. } while (true);
  620. // Remove one
  621. while (true) {
  622. int index = rand() % all_keys->size();
  623. uint64_t removed_key = (*all_keys)[index];
  624. if (removed_key == hint.key) {
  625. continue;
  626. }
  627. if (removed_keys.seek(removed_key)) {
  628. continue;
  629. }
  630. if (std::find(keys_out->begin(), keys_out->end(), removed_key)
  631. != keys_out->end()) {
  632. continue;
  633. }
  634. ASSERT_EQ(1u, map->erase(removed_key));
  635. removed_keys.insert(removed_key);
  636. break;
  637. }
  638. }
  639. butil::FlatSet<uint64_t> removed_keys;
  640. butil::FlatSet<uint64_t> inserted_keys;
  641. const std::vector<uint64_t>* keys_out;
  642. std::vector<uint64_t>* all_keys;
  643. PositionHintMap* map;
  644. };
  645. TEST_F(FlatMapTest, erase_insert_unvisited_during_iteration) {
  646. PositionHintMap m1;
  647. std::vector<uint64_t> keys;
  648. fill_position_hint_map(&m1, &keys);
  649. // Erase/insert unvisited values should affect keys_out
  650. RemoveInsertUnvisitedOnPause on_pause4;
  651. std::vector<uint64_t> keys_out;
  652. on_pause4.map = &m1;
  653. on_pause4.keys_out = &keys_out;
  654. on_pause4.all_keys = &keys;
  655. list_flat_map(&keys_out, m1, 10, on_pause4);
  656. EXPECT_EQ(m1.size() / 10, on_pause4.removed_keys.size());
  657. ASSERT_EQ(m1.size(), keys_out.size());
  658. std::sort(keys_out.begin(), keys_out.end());
  659. for (size_t i = 0; i < keys_out.size(); ++i) {
  660. if (i) {
  661. ASSERT_NE(keys_out[i-1], keys_out[i]) << "i=" << i;
  662. }
  663. ASSERT_TRUE(m1.seek(keys_out[i])) << "i=" << i;
  664. }
  665. }
  666. inline uint64_t fmix64 (uint64_t k) {
  667. k ^= k >> 33;
  668. k *= 0xff51afd7ed558ccdULL;
  669. k ^= k >> 33;
  670. k *= 0xc4ceb9fe1a85ec53ULL;
  671. k ^= k >> 33;
  672. return k;
  673. }
  674. template <typename T>
  675. struct PointerHasher {
  676. size_t operator()(const T* p) const
  677. { return fmix64(reinterpret_cast<uint64_t>(p)); }
  678. };
  679. template <typename T>
  680. struct PointerHasher2 {
  681. size_t operator()(const T* p) const
  682. { return reinterpret_cast<uint64_t>(p); }
  683. };
  684. TEST_F(FlatMapTest, perf_cmp_with_map_storing_pointers) {
  685. const size_t REP = 4;
  686. int* ptr[2048];
  687. for (size_t i = 0; i < ARRAY_SIZE(ptr); ++i) {
  688. ptr[i] = new int;
  689. }
  690. std::set<int*> m1;
  691. butil::FlatSet<int*, PointerHasher<int> > m2;
  692. butil::hash_set<int*, PointerHasher<int> > m3;
  693. std::vector<int*> r;
  694. int sum;
  695. butil::Timer tm;
  696. r.reserve(ARRAY_SIZE(ptr)*REP);
  697. ASSERT_EQ(0, m2.init(ARRAY_SIZE(ptr)));
  698. for (size_t i = 0; i < ARRAY_SIZE(ptr); ++i) {
  699. m1.insert(ptr[i]);
  700. m2.insert(ptr[i]);
  701. m3.insert(ptr[i]);
  702. for (size_t j = 0; j < REP; ++j) {
  703. r.push_back(ptr[i]);
  704. }
  705. }
  706. ASSERT_EQ(m1.size(), m2.size());
  707. ASSERT_EQ(m1.size(), m3.size());
  708. std::random_shuffle(r.begin(), r.end());
  709. sum = 0;
  710. tm.start();
  711. for (size_t i = 0; i < r.size(); ++i) {
  712. sum += (m2.seek(r[i]) != NULL);
  713. }
  714. tm.stop();
  715. LOG(INFO) << "FlatMap takes " << tm.n_elapsed()/r.size();
  716. sum = 0;
  717. tm.start();
  718. for (size_t i = 0; i < r.size(); ++i) {
  719. sum += (m1.find(r[i]) != m1.end());
  720. }
  721. tm.stop();
  722. LOG(INFO) << "std::set takes " << tm.n_elapsed()/r.size();
  723. sum = 0;
  724. tm.start();
  725. for (size_t i = 0; i < r.size(); ++i) {
  726. sum += (m3.find(r[i]) != m3.end());
  727. }
  728. tm.stop();
  729. LOG(INFO) << "std::set takes " << tm.n_elapsed()/r.size();
  730. for (size_t i = 0; i < ARRAY_SIZE(ptr); ++i) {
  731. delete ptr[i];
  732. }
  733. }
  734. int n_con = 0;
  735. int n_cp_con = 0;
  736. int n_des = 0;
  737. int n_cp = 0;
  738. struct Value {
  739. Value() : x_(0) { ++n_con; }
  740. Value(int x) : x_(x) { ++ n_con; }
  741. Value (const Value& rhs) : x_(rhs.x_) { ++ n_cp_con; }
  742. ~Value() { ++ n_des; }
  743. Value& operator= (const Value& rhs) {
  744. x_ = rhs.x_;
  745. ++ n_cp;
  746. return *this;
  747. }
  748. bool operator== (const Value& rhs) const { return x_ == rhs.x_; }
  749. bool operator!= (const Value& rhs) const { return x_ != rhs.x_; }
  750. friend std::ostream& operator<< (std::ostream& os, const Value& v)
  751. { return os << v.x_; }
  752. int x_;
  753. };
  754. int n_con_key = 0;
  755. int n_cp_con_key = 0;
  756. int n_des_key = 0;
  757. struct Key {
  758. Key() : x_(0) { ++n_con_key; }
  759. Key(int x) : x_(x) { ++ n_con_key; }
  760. Key(const Key& rhs) : x_(rhs.x_) { ++ n_cp_con_key; }
  761. ~Key() { ++ n_des_key; }
  762. int x_;
  763. };
  764. struct KeyHasher {
  765. size_t operator()(const Key& k) const { return k.x_; }
  766. };
  767. struct KeyEqualTo {
  768. size_t operator()(const Key& k1, const Key& k2) const
  769. { return k1.x_ == k2.x_; }
  770. };
  771. TEST_F(FlatMapTest, key_value_are_not_constructed_before_first_insertion) {
  772. butil::FlatMap<Key, Value, KeyHasher, KeyEqualTo> m;
  773. ASSERT_EQ(0, m.init(32));
  774. ASSERT_EQ(0, n_con_key);
  775. ASSERT_EQ(0, n_cp_con_key);
  776. ASSERT_EQ(0, n_con);
  777. ASSERT_EQ(0, n_cp_con);
  778. const Key k1 = 1;
  779. ASSERT_EQ(1, n_con_key);
  780. ASSERT_EQ(0, n_cp_con_key);
  781. ASSERT_EQ(NULL, m.seek(k1));
  782. ASSERT_EQ(0u, m.erase(k1));
  783. ASSERT_EQ(1, n_con_key);
  784. ASSERT_EQ(0, n_cp_con_key);
  785. ASSERT_EQ(0, n_con);
  786. ASSERT_EQ(0, n_cp_con);
  787. }
  788. TEST_F(FlatMapTest, manipulate_uninitialized_map) {
  789. butil::FlatMap<int, int> m;
  790. ASSERT_FALSE(m.initialized());
  791. for (butil::FlatMap<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
  792. LOG(INFO) << "nothing";
  793. }
  794. ASSERT_EQ(NULL, m.seek(1));
  795. ASSERT_EQ(0u, m.erase(1));
  796. ASSERT_EQ(0u, m.size());
  797. ASSERT_TRUE(m.empty());
  798. ASSERT_EQ(0u, m.bucket_count());
  799. ASSERT_EQ(0u, m.load_factor());
  800. }
  801. TEST_F(FlatMapTest, perf_small_string_map) {
  802. butil::Timer tm1;
  803. butil::Timer tm2;
  804. butil::Timer tm3;
  805. butil::Timer tm4;
  806. for (int i = 0; i < 10; ++i) {
  807. tm3.start();
  808. butil::PooledMap<std::string, std::string> m3;
  809. m3["Content-type"] = "application/json";
  810. m3["Request-Id"] = "true";
  811. m3["Status-Code"] = "200";
  812. tm3.stop();
  813. tm4.start();
  814. butil::CaseIgnoredFlatMap<std::string> m4;
  815. m4.init(16);
  816. m4["Content-type"] = "application/json";
  817. m4["Request-Id"] = "true";
  818. m4["Status-Code"] = "200";
  819. tm4.stop();
  820. tm1.start();
  821. butil::FlatMap<std::string, std::string> m1;
  822. m1.init(16);
  823. m1["Content-type"] = "application/json";
  824. m1["Request-Id"] = "true";
  825. m1["Status-Code"] = "200";
  826. tm1.stop();
  827. tm2.start();
  828. std::map<std::string, std::string> m2;
  829. m2["Content-type"] = "application/json";
  830. m2["Request-Id"] = "true";
  831. m2["Status-Code"] = "200";
  832. tm2.stop();
  833. LOG(INFO) << "flatmap=" << tm1.n_elapsed()
  834. << " ci_flatmap=" << tm4.n_elapsed()
  835. << " map=" << tm2.n_elapsed()
  836. << " pooled_map=" << tm3.n_elapsed();
  837. }
  838. }
  839. TEST_F(FlatMapTest, sanity) {
  840. typedef butil::FlatMap<uint64_t, long> Map;
  841. Map m;
  842. ASSERT_FALSE(m.initialized());
  843. m.init(1000, 70);
  844. ASSERT_TRUE(m.initialized());
  845. ASSERT_EQ(0UL, m.size());
  846. ASSERT_TRUE(m.empty());
  847. ASSERT_EQ(0UL, m._pool.count_allocated());
  848. const uint64_t k1 = 1;
  849. // hashed to the same bucket of k1.
  850. const uint64_t k2 = k1 + m.bucket_count();
  851. const uint64_t k3 = k1 + 1;
  852. // Initial insertion
  853. m[k1] = 10;
  854. ASSERT_EQ(1UL, m.size());
  855. ASSERT_FALSE(m.empty());
  856. long* p = m.seek(k1);
  857. ASSERT_TRUE(p && *p == 10);
  858. ASSERT_EQ(0UL, m._pool.count_allocated());
  859. ASSERT_EQ(NULL, m.seek(k2));
  860. // Override
  861. m[k1] = 100;
  862. ASSERT_EQ(1UL, m.size());
  863. ASSERT_FALSE(m.empty());
  864. p = m.seek(k1);
  865. ASSERT_TRUE(p && *p == 100);
  866. // Insert another
  867. m[k3] = 20;
  868. ASSERT_EQ(2UL, m.size());
  869. ASSERT_FALSE(m.empty());
  870. p = m.seek(k3);
  871. ASSERT_TRUE(p && *p == 20);
  872. ASSERT_EQ(0UL, m._pool.count_allocated());
  873. m[k2] = 30;
  874. ASSERT_EQ(1UL, m._pool.count_allocated());
  875. ASSERT_EQ(0UL, m._pool.count_free());
  876. ASSERT_EQ(3UL, m.size());
  877. ASSERT_FALSE(m.empty());
  878. p = m.seek(k2);
  879. ASSERT_TRUE(p && *p == 30);
  880. ASSERT_EQ(NULL, m.seek(2049));
  881. Map::iterator it = m.begin();
  882. ASSERT_EQ(k1, it->first);
  883. ++it;
  884. ASSERT_EQ(k2, it->first);
  885. ++it;
  886. ASSERT_EQ(k3, it->first);
  887. ++it;
  888. ASSERT_EQ(m.end(), it);
  889. // Erase exist
  890. ASSERT_EQ(1UL, m.erase(k1));
  891. ASSERT_EQ(2UL, m.size());
  892. ASSERT_FALSE(m.empty());
  893. ASSERT_EQ(NULL, m.seek(k1));
  894. ASSERT_EQ(30, *m.seek(k2));
  895. ASSERT_EQ(20, *m.seek(k3));
  896. ASSERT_EQ(1UL, m._pool.count_allocated());
  897. ASSERT_EQ(1UL, m._pool.count_free());
  898. // default constructed
  899. ASSERT_EQ(0, m[k1]);
  900. ASSERT_EQ(0, m[5]);
  901. ASSERT_EQ(0, m[1029]);
  902. ASSERT_EQ(0, m[2053]);
  903. // Clear
  904. m.clear();
  905. ASSERT_EQ(m.size(), 0ul);
  906. ASSERT_TRUE(m.empty());
  907. ASSERT_EQ(NULL, m.seek(k1));
  908. ASSERT_EQ(NULL, m.seek(k2));
  909. ASSERT_EQ(NULL, m.seek(k3));
  910. }
  911. TEST_F(FlatMapTest, random_insert_erase) {
  912. srand (0);
  913. {
  914. butil::hash_map<uint64_t, Value> ref[2];
  915. typedef butil::FlatMap<uint64_t, Value> Map;
  916. Map ht[2];
  917. ht[0].init (40);
  918. ht[1] = ht[0];
  919. for (int j = 0; j < 30; ++j) {
  920. // Make snapshot
  921. ht[1] = ht[0];
  922. ref[1] = ref[0];
  923. for (int i = 0; i < 100000; ++i) {
  924. int k = rand() % 0xFFFF;
  925. int p = rand() % 1000;
  926. if (p < 600) {
  927. ht[0].insert(k, i);
  928. ref[0][k] = i;
  929. } else if(p < 999) {
  930. ht[0].erase (k);
  931. ref[0].erase (k);
  932. } else {
  933. ht[0].clear();
  934. ref[0].clear();
  935. }
  936. }
  937. LOG(INFO) << "Check j=" << j;
  938. // bi-check
  939. for (int i=0; i<2; ++i) {
  940. for (Map::iterator it = ht[i].begin(); it != ht[i].end(); ++it)
  941. {
  942. butil::hash_map<uint64_t, Value>::iterator it2 = ref[i].find(it->first);
  943. ASSERT_TRUE (it2 != ref[i].end());
  944. ASSERT_EQ (it2->second, it->second);
  945. }
  946. for (butil::hash_map<uint64_t, Value>::iterator it = ref[i].begin();
  947. it != ref[i].end(); ++it)
  948. {
  949. Value* p_value = ht[i].seek(it->first);
  950. ASSERT_TRUE (p_value != NULL);
  951. ASSERT_EQ (it->second, p_value->x_);
  952. }
  953. ASSERT_EQ (ht[i].size(), ref[i].size());
  954. }
  955. }
  956. }
  957. // cout << "ht[0] = " << show(ht[0]) << endl
  958. // << "ht[1] = " << show(ht[1]) << endl;
  959. //ASSERT_EQ (ht[0]._pool->alloc_num(), 0ul);
  960. ASSERT_EQ (n_con + n_cp_con, n_des);
  961. LOG(INFO) << "n_con:" << n_con << std::endl
  962. << "n_cp_con:" << n_cp_con << std::endl
  963. << "n_con+n_cp_con:" << n_con+n_cp_con << std::endl
  964. << "n_des:" << n_des << std::endl
  965. << "n_cp:" << n_cp;
  966. }
  967. template <typename T> void perf_insert_erase(bool random, const T& value)
  968. {
  969. size_t nkeys[] = { 100, 1000, 10000 };
  970. const size_t NPASS = ARRAY_SIZE(nkeys);
  971. std::vector<uint64_t> keys;
  972. butil::FlatMap<uint64_t, T> id_map;
  973. std::map<uint64_t, T> std_map;
  974. butil::PooledMap<uint64_t, T> pooled_map;
  975. butil::hash_map<uint64_t, T> hash_map;
  976. butil::Timer id_tm, std_tm, pooled_tm, hash_tm;
  977. size_t max_nkeys = 0;
  978. for (size_t i = 0; i < NPASS; ++i) {
  979. max_nkeys = std::max(max_nkeys, nkeys[i]);
  980. }
  981. id_map.init((size_t)(nkeys[NPASS-1] * 1.5));
  982. // Make DS hot
  983. for (size_t i = 0; i < max_nkeys; ++i) {
  984. id_map[i] = value;
  985. std_map[i] = value;
  986. pooled_map[i] = value;
  987. hash_map[i] = value;
  988. }
  989. id_map.clear();
  990. std_map.clear();
  991. pooled_map.clear();
  992. hash_map.clear();
  993. LOG(INFO) << "[ value = " << sizeof(T) << " bytes ]";
  994. for (size_t pass = 0; pass < NPASS; ++pass) {
  995. int start = rand();
  996. keys.clear();
  997. for (size_t i = 0; i < nkeys[pass]; ++i) {
  998. keys.push_back(start + i);
  999. }
  1000. if (random) {
  1001. random_shuffle(keys.begin(), keys.end());
  1002. }
  1003. id_map.clear();
  1004. id_tm.start();
  1005. for (size_t i = 0; i < keys.size(); ++i) {
  1006. id_map[keys[i]] = value;
  1007. }
  1008. id_tm.stop();
  1009. std_map.clear();
  1010. std_tm.start();
  1011. for (size_t i = 0; i < keys.size(); ++i) {
  1012. std_map[keys[i]] = value;
  1013. }
  1014. std_tm.stop();
  1015. pooled_map.clear();
  1016. pooled_tm.start();
  1017. for (size_t i = 0; i < keys.size(); ++i) {
  1018. pooled_map[keys[i]] = value;
  1019. }
  1020. pooled_tm.stop();
  1021. hash_map.clear();
  1022. hash_tm.start();
  1023. for (size_t i = 0; i < keys.size(); ++i) {
  1024. hash_map[keys[i]] = value;
  1025. }
  1026. hash_tm.stop();
  1027. LOG(INFO) << (random ? "Randomly" : "Sequentially")
  1028. << " inserting " << keys.size()
  1029. << " into FlatMap/std::map/butil::PooledMap/butil::hash_map takes "
  1030. << id_tm.n_elapsed() / keys.size()
  1031. << "/" << std_tm.n_elapsed() / keys.size()
  1032. << "/" << pooled_tm.n_elapsed() / keys.size()
  1033. << "/" << hash_tm.n_elapsed() / keys.size();
  1034. if (random) {
  1035. random_shuffle(keys.begin(), keys.end());
  1036. }
  1037. id_tm.start();
  1038. for (size_t i = 0; i < keys.size(); ++i) {
  1039. id_map.erase(keys[i]);
  1040. }
  1041. id_tm.stop();
  1042. std_tm.start();
  1043. for (size_t i = 0; i < keys.size(); ++i) {
  1044. std_map.erase(keys[i]);
  1045. }
  1046. std_tm.stop();
  1047. pooled_tm.start();
  1048. for (size_t i = 0; i < keys.size(); ++i) {
  1049. pooled_map.erase(keys[i]);
  1050. }
  1051. pooled_tm.stop();
  1052. hash_tm.start();
  1053. for (size_t i = 0; i < keys.size(); ++i) {
  1054. hash_map.erase(keys[i]);
  1055. }
  1056. hash_tm.stop();
  1057. LOG(INFO) << (random ? "Randomly" : "Sequentially")
  1058. << " erasing " << keys.size()
  1059. << " from FlatMap/std::map/butil::PooledMap/butil::hash_map takes "
  1060. << id_tm.n_elapsed() / keys.size()
  1061. << "/" << std_tm.n_elapsed() / keys.size()
  1062. << "/" << pooled_tm.n_elapsed() / keys.size()
  1063. << "/" << hash_tm.n_elapsed() / keys.size();
  1064. }
  1065. }
  1066. template <typename T> void perf_seek(const T& value) {
  1067. size_t nkeys[] = { 100, 1000, 10000 };
  1068. const size_t NPASS = ARRAY_SIZE(nkeys);
  1069. std::vector<uint64_t> keys;
  1070. std::vector<uint64_t> rkeys;
  1071. butil::FlatMap<uint64_t, T> id_map;
  1072. std::map<uint64_t, T> std_map;
  1073. butil::PooledMap<uint64_t, T> pooled_map;
  1074. butil::hash_map<uint64_t, T> hash_map;
  1075. butil::Timer id_tm, std_tm, pooled_tm, hash_tm;
  1076. id_map.init((size_t)(nkeys[NPASS-1] * 1.5));
  1077. LOG(INFO) << "[ value = " << sizeof(T) << " bytes ]";
  1078. for (size_t pass = 0; pass < NPASS; ++pass) {
  1079. int start = rand();
  1080. keys.clear();
  1081. for (size_t i = 0; i < nkeys[pass]; ++i) {
  1082. keys.push_back(start + i);
  1083. }
  1084. id_map.clear();
  1085. for (size_t i = 0; i < keys.size(); ++i) {
  1086. id_map[keys[i]] = value;
  1087. }
  1088. std_map.clear();
  1089. for (size_t i = 0; i < keys.size(); ++i) {
  1090. std_map[keys[i]] = value;
  1091. }
  1092. pooled_map.clear();
  1093. for (size_t i = 0; i < keys.size(); ++i) {
  1094. pooled_map[keys[i]] = value;
  1095. }
  1096. hash_map.clear();
  1097. for (size_t i = 0; i < keys.size(); ++i) {
  1098. hash_map[keys[i]] = value;
  1099. }
  1100. random_shuffle(keys.begin(), keys.end());
  1101. long sum = 0;
  1102. id_tm.start();
  1103. for (size_t i = 0; i < keys.size(); ++i) {
  1104. sum += *(long*)id_map.seek(keys[i]);
  1105. }
  1106. id_tm.stop();
  1107. std_tm.start();
  1108. for (size_t i = 0; i < keys.size(); ++i) {
  1109. sum += (long&)std_map.find(keys[i])->second;
  1110. }
  1111. std_tm.stop();
  1112. pooled_tm.start();
  1113. for (size_t i = 0; i < keys.size(); ++i) {
  1114. sum += (long&)pooled_map.find(keys[i])->second;
  1115. }
  1116. pooled_tm.stop();
  1117. hash_tm.start();
  1118. for (size_t i = 0; i < keys.size(); ++i) {
  1119. sum += (long&)hash_map.find(keys[i])->second;
  1120. }
  1121. hash_tm.stop();
  1122. LOG(INFO) << "Seeking " << keys.size()
  1123. << " from FlatMap/std::map/butil::PooledMap/butil::hash_map takes "
  1124. << id_tm.n_elapsed() / keys.size()
  1125. << "/" << std_tm.n_elapsed() / keys.size()
  1126. << "/" << pooled_tm.n_elapsed() / keys.size()
  1127. << "/" << hash_tm.n_elapsed() / keys.size();
  1128. }
  1129. }
  1130. struct Dummy1 {
  1131. long data[4];
  1132. };
  1133. struct Dummy2 {
  1134. long data[16];
  1135. };
  1136. TEST_F(FlatMapTest, perf) {
  1137. perf_insert_erase<long>(false, 100);
  1138. perf_insert_erase<Dummy1>(false, Dummy1());
  1139. perf_insert_erase<Dummy2>(false, Dummy2());
  1140. perf_insert_erase<long>(true, 100);
  1141. perf_insert_erase<Dummy1>(true, Dummy1());
  1142. perf_insert_erase<Dummy2>(true, Dummy2());
  1143. perf_seek<long>(100);
  1144. perf_seek<Dummy1>(Dummy1());
  1145. perf_seek<Dummy2>(Dummy2());
  1146. perf_seek<long>(100);
  1147. perf_seek<Dummy1>(Dummy1());
  1148. perf_seek<Dummy2>(Dummy2());
  1149. }
  1150. TEST_F(FlatMapTest, copy) {
  1151. butil::FlatMap<int, int> m1;
  1152. butil::FlatMap<int, int> m2;
  1153. ASSERT_EQ(0, m1.init(32));
  1154. m1[1] = 1;
  1155. m1[2] = 2;
  1156. m2 = m1;
  1157. ASSERT_FALSE(m1.is_too_crowded(m1.size()));
  1158. ASSERT_FALSE(m2.is_too_crowded(m1.size()));
  1159. }
  1160. }