range_map_test.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. // Copyright 2016 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "bloaty.h"
  15. #include "gmock/gmock.h"
  16. #include "gtest/gtest.h"
  17. #include <tuple>
  18. namespace bloaty {
  19. class RangeMapTest : public ::testing::Test {
  20. protected:
  21. void CheckConsistencyFor(const bloaty::RangeMap& map) {
  22. uint64_t last_end = 0;
  23. for (auto it = map.mappings_.begin(); it != map.mappings_.end(); ++it) {
  24. ASSERT_GE(it->first, last_end);
  25. last_end = map.RangeEnd(it);
  26. }
  27. }
  28. void CheckConsistency() {
  29. CheckConsistencyFor(map_);
  30. CheckConsistencyFor(map2_);
  31. CheckConsistencyFor(map3_);
  32. }
  33. struct Row {
  34. std::vector<std::string> keys;
  35. uint64_t start;
  36. uint64_t end;
  37. };
  38. void AssertRollupEquals(const std::vector<const RangeMap*> maps,
  39. const std::vector<Row>& rows) {
  40. int i = 0;
  41. RangeMap::ComputeRollup(
  42. maps, [&i, &rows](const std::vector<std::string>& keys, uint64_t start,
  43. uint64_t end) {
  44. ASSERT_LT(i, rows.size());
  45. const auto& row = rows[i];
  46. ASSERT_EQ(row.keys, keys);
  47. ASSERT_EQ(row.start, start);
  48. ASSERT_EQ(row.end, end);
  49. i++;
  50. });
  51. ASSERT_EQ(rows.size(), i);
  52. }
  53. struct Entry {
  54. uint64_t addr;
  55. uint64_t end;
  56. uint64_t other_start;
  57. std::string label;
  58. };
  59. void AssertMapEquals(const bloaty::RangeMap& map,
  60. const std::vector<Entry>& entries) {
  61. auto iter = map.mappings_.begin();
  62. size_t i = 0;
  63. for (; i < entries.size() && iter != map.mappings_.end(); ++i, ++iter) {
  64. const auto& entry = entries[i];
  65. ASSERT_EQ(entry.addr, iter->first) << i;
  66. ASSERT_EQ(entry.end, map.RangeEnd(iter)) << i;
  67. ASSERT_EQ(entry.other_start, iter->second.other_start) << i;
  68. ASSERT_EQ(entry.label, iter->second.label) << i;
  69. }
  70. ASSERT_EQ(i, entries.size());
  71. ASSERT_EQ(iter, map.mappings_.end());
  72. // Also test that ComputeRollup yields the same thing.
  73. i = 0;
  74. RangeMap::ComputeRollup({&map},
  75. [&i, &entries](const std::vector<std::string>& keys,
  76. uint64_t start, uint64_t end) {
  77. ASSERT_LT(i, entries.size());
  78. const auto& entry = entries[i];
  79. ASSERT_EQ(entry.addr, start);
  80. ASSERT_EQ(entry.end, end);
  81. ASSERT_EQ(entry.label, keys[0]);
  82. i++;
  83. });
  84. ASSERT_EQ(entries.size(), i);
  85. }
  86. void AssertMainMapEquals(const std::vector<Entry>& entries) {
  87. AssertMapEquals(map_, entries);
  88. }
  89. bloaty::RangeMap map_;
  90. bloaty::RangeMap map2_;
  91. bloaty::RangeMap map3_;
  92. const uint64_t kNoTranslation = RangeMap::kNoTranslation;
  93. const uint64_t kUnknownSize = RangeMap::kUnknownSize;
  94. };
  95. TEST_F(RangeMapTest, AddRange) {
  96. CheckConsistency();
  97. AssertMainMapEquals({});
  98. map_.AddRange(4, 3, "foo");
  99. CheckConsistency();
  100. AssertMainMapEquals({
  101. {4, 7, kNoTranslation, "foo"}
  102. });
  103. map_.AddRange(30, 5, "bar");
  104. CheckConsistency();
  105. AssertMainMapEquals({
  106. {4, 7, kNoTranslation, "foo"},
  107. {30, 35, kNoTranslation, "bar"}
  108. });
  109. map_.AddRange(50, 0, "baz"); // No-op due to 0 size.
  110. CheckConsistency();
  111. AssertMainMapEquals({
  112. {4, 7, kNoTranslation, "foo"},
  113. {30, 35, kNoTranslation, "bar"}
  114. });
  115. map_.AddRange(20, 5, "baz");
  116. map_.AddRange(25, 5, "baz2");
  117. map_.AddRange(40, 5, "quux");
  118. CheckConsistency();
  119. AssertMainMapEquals({
  120. {4, 7, kNoTranslation, "foo"},
  121. {20, 25, kNoTranslation, "baz"},
  122. {25, 30, kNoTranslation, "baz2"},
  123. {30, 35, kNoTranslation, "bar"},
  124. {40, 45, kNoTranslation, "quux"}
  125. });
  126. map_.AddRange(21, 25, "overlapping");
  127. CheckConsistency();
  128. AssertMainMapEquals({
  129. {4, 7, kNoTranslation, "foo"},
  130. {20, 25, kNoTranslation, "baz"},
  131. {25, 30, kNoTranslation, "baz2"},
  132. {30, 35, kNoTranslation, "bar"},
  133. {35, 40, kNoTranslation, "overlapping"},
  134. {40, 45, kNoTranslation, "quux"},
  135. {45, 46, kNoTranslation, "overlapping"}
  136. });
  137. map_.AddRange(21, 25, "overlapping no-op");
  138. CheckConsistency();
  139. AssertMainMapEquals({
  140. {4, 7, kNoTranslation, "foo"},
  141. {20, 25, kNoTranslation, "baz"},
  142. {25, 30, kNoTranslation, "baz2"},
  143. {30, 35, kNoTranslation, "bar"},
  144. {35, 40, kNoTranslation, "overlapping"},
  145. {40, 45, kNoTranslation, "quux"},
  146. {45, 46, kNoTranslation, "overlapping"}
  147. });
  148. map_.AddRange(0, 100, "overlap everything");
  149. CheckConsistency();
  150. AssertMainMapEquals({
  151. {0, 4, kNoTranslation, "overlap everything"},
  152. {4, 7, kNoTranslation, "foo"},
  153. {7, 20, kNoTranslation, "overlap everything"},
  154. {20, 25, kNoTranslation, "baz"},
  155. {25, 30, kNoTranslation, "baz2"},
  156. {30, 35, kNoTranslation, "bar"},
  157. {35, 40, kNoTranslation, "overlapping"},
  158. {40, 45, kNoTranslation, "quux"},
  159. {45, 46, kNoTranslation, "overlapping"},
  160. {46, 100, kNoTranslation, "overlap everything"},
  161. });
  162. }
  163. TEST_F(RangeMapTest, UnknownSize) {
  164. map_.AddRange(5, kUnknownSize, "foo");
  165. CheckConsistency();
  166. AssertMainMapEquals({
  167. {5, UINT64_MAX, kNoTranslation, "foo"}
  168. });
  169. map_.AddRange(100, 15, "bar");
  170. map_.AddRange(200, kUnknownSize, "baz");
  171. CheckConsistency();
  172. AssertMainMapEquals({
  173. {5, 100, kNoTranslation, "foo"},
  174. {100, 115, kNoTranslation, "bar"},
  175. {200, UINT64_MAX, kNoTranslation, "baz"}
  176. });
  177. map2_.AddRange(5, 110, "base0");
  178. map2_.AddRange(200, 50, "base1");
  179. AssertRollupEquals({&map2_, &map_}, {
  180. {{"base0", "foo"}, 5, 100},
  181. {{"base0", "bar"}, 100, 115},
  182. {{"base1", "baz"}, 200, 250},
  183. });
  184. }
  185. TEST_F(RangeMapTest, UnknownSize2) {
  186. // This case is slightly weird, but we do consider the "100" below to be a
  187. // hard fact even if the size is unknown, so the "[95, 105]: bar" range
  188. // doesn't override it.
  189. map_.AddRange(100, kUnknownSize, "foo");
  190. map_.AddRange(95, 10, "bar");
  191. AssertMainMapEquals({
  192. {95, 100, kNoTranslation, "bar"},
  193. {100, 105, kNoTranslation, "foo"},
  194. });
  195. }
  196. TEST_F(RangeMapTest, UnknownSize3) {
  197. map_.AddRange(100, kUnknownSize, "foo");
  198. map_.AddRange(150, kUnknownSize, "bar");
  199. // This tells us the ultimate size of "foo", and we keep the "foo" label even
  200. // though the new label is "baz".
  201. map_.AddRange(100, 100, "baz");
  202. AssertMainMapEquals({
  203. {100, 150, kNoTranslation, "foo"},
  204. {150, 200, kNoTranslation, "bar"},
  205. });
  206. }
  207. TEST_F(RangeMapTest, UnknownSize4) {
  208. map_.AddRange(100, kUnknownSize, "foo");
  209. map_.AddRange(150, 100, "bar");
  210. // This tells us the ultimate size of "foo", and we keep the "foo" label even
  211. // though the new label is "baz".
  212. map_.AddRange(100, 100, "baz");
  213. AssertMainMapEquals({
  214. {100, 150, kNoTranslation, "foo"},
  215. {150, 250, kNoTranslation, "bar"},
  216. });
  217. }
  218. TEST_F(RangeMapTest, Bug1) {
  219. map_.AddRange(100, 20, "foo");
  220. map_.AddRange(120, 20, "bar");
  221. map_.AddRange(100, 15, "baz");
  222. AssertMainMapEquals({
  223. {100, 120, kNoTranslation, "foo"},
  224. {120, 140, kNoTranslation, "bar"},
  225. });
  226. }
  227. TEST_F(RangeMapTest, Bug2) {
  228. map_.AddRange(100, kUnknownSize, "foo");
  229. map_.AddRange(200, 50, "bar");
  230. map_.AddRange(150, 10, "baz");
  231. AssertMainMapEquals({
  232. {100, 150, kNoTranslation, "foo"},
  233. {150, 160, kNoTranslation, "baz"},
  234. {200, 250, kNoTranslation, "bar"},
  235. });
  236. }
  237. TEST_F(RangeMapTest, Bug3) {
  238. map_.AddRange(100, kUnknownSize, "foo");
  239. map_.AddRange(200, kUnknownSize, "bar");
  240. map_.AddRange(150, 10, "baz");
  241. AssertMainMapEquals({
  242. {100, 150, kNoTranslation, "foo"},
  243. {150, 160, kNoTranslation, "baz"},
  244. {200, UINT64_MAX, kNoTranslation, "bar"},
  245. });
  246. }
  247. TEST_F(RangeMapTest, GetLabel) {
  248. map_.AddRange(100, kUnknownSize, "foo");
  249. map_.AddRange(200, 50, "bar");
  250. map_.AddRange(150, 10, "baz");
  251. AssertMainMapEquals({
  252. {100, 150, kNoTranslation, "foo"},
  253. {150, 160, kNoTranslation, "baz"},
  254. {200, 250, kNoTranslation, "bar"},
  255. });
  256. std::string label;
  257. ASSERT_TRUE(map_.TryGetLabel(100, &label));
  258. ASSERT_EQ(label, "foo");
  259. ASSERT_TRUE(map_.TryGetLabel(155, &label));
  260. ASSERT_EQ(label, "baz");
  261. ASSERT_TRUE(map_.TryGetLabel(249, &label));
  262. ASSERT_EQ(label, "bar");
  263. ASSERT_FALSE(map_.TryGetLabel(250, &label));
  264. ASSERT_TRUE(map_.TryGetLabelForRange(100, 10, &label));
  265. ASSERT_EQ(label, "foo");
  266. ASSERT_TRUE(map_.TryGetLabelForRange(155, 3, &label));
  267. ASSERT_EQ(label, "baz");
  268. ASSERT_TRUE(map_.TryGetLabelForRange(200, 50, &label));
  269. ASSERT_EQ(label, "bar");
  270. ASSERT_FALSE(map_.TryGetLabelForRange(200, 51, &label));
  271. }
  272. TEST_F(RangeMapTest, Translation) {
  273. map_.AddDualRange(20, 5, 120, "foo");
  274. CheckConsistency();
  275. AssertMainMapEquals({
  276. {20, 25, 120, "foo"}
  277. });
  278. ASSERT_TRUE(map2_.AddRangeWithTranslation(20, 5, "translate me", map_, false,
  279. &map3_));
  280. CheckConsistency();
  281. AssertMapEquals(map2_, {
  282. {20, 25, kNoTranslation, "translate me"}
  283. });
  284. AssertMapEquals(map3_, {
  285. {120, 125, kNoTranslation, "translate me"}
  286. });
  287. map_.AddDualRange(1000, 30, 1100, "bar");
  288. ASSERT_TRUE(map2_.AddRangeWithTranslation(1000, 5, "translate me2", map_,
  289. false, &map3_));
  290. AssertMapEquals(map2_, {
  291. {20, 25, kNoTranslation, "translate me"},
  292. {1000, 1005, kNoTranslation, "translate me2"}
  293. });
  294. AssertMapEquals(map3_, {
  295. {120, 125, kNoTranslation, "translate me"},
  296. {1100, 1105, kNoTranslation, "translate me2"}
  297. });
  298. // Starts before base map.
  299. ASSERT_FALSE(map2_.AddRangeWithTranslation(15, 8, "translate me", map_, false,
  300. &map3_));
  301. // Extends past base map.
  302. ASSERT_FALSE(map2_.AddRangeWithTranslation(22, 15, "translate me", map_,
  303. false, &map3_));
  304. // Starts and ends in base map, but skips range in the middle.
  305. ASSERT_FALSE(map2_.AddRangeWithTranslation(20, 1000, "translate me", map_,
  306. false, &map3_));
  307. }
  308. TEST_F(RangeMapTest, Translation2) {
  309. map_.AddRange(5, 5, "foo");
  310. map_.AddDualRange(20, 5, 120, "bar");
  311. map_.AddRange(25, 5, "baz");
  312. map_.AddDualRange(30, 5, 130, "quux");
  313. CheckConsistency();
  314. AssertMainMapEquals({
  315. {5, 10, kNoTranslation, "foo"},
  316. {20, 25, 120, "bar"},
  317. {25, 30, kNoTranslation, "baz"},
  318. {30, 35, 130, "quux"}
  319. });
  320. ASSERT_TRUE(map2_.AddRangeWithTranslation(20, 15, "translate me", map_, false,
  321. &map3_));
  322. CheckConsistency();
  323. AssertMapEquals(map2_, {
  324. {20, 25, kNoTranslation, "translate me"},
  325. {25, 30, kNoTranslation, "translate me"},
  326. {30, 35, kNoTranslation, "translate me"}
  327. });
  328. AssertMapEquals(map3_, {
  329. {120, 125, kNoTranslation, "translate me"},
  330. {130, 135, kNoTranslation, "translate me"}
  331. });
  332. }
  333. TEST_F(RangeMapTest, UnknownTranslation) {
  334. map_.AddDualRange(20, 10, 120, "foo");
  335. CheckConsistency();
  336. AssertMainMapEquals({
  337. {20, 30, 120, "foo"}
  338. });
  339. map2_.AddRangeWithTranslation(25, kUnknownSize, "translate me", map_, false,
  340. &map3_);
  341. CheckConsistency();
  342. AssertMapEquals(map2_, {
  343. {25, UINT64_MAX, kNoTranslation, "translate me"}
  344. });
  345. AssertMapEquals(map3_, {
  346. {125, UINT64_MAX, kNoTranslation, "translate me"}
  347. });
  348. map2_.AddRange(20, 10, "fallback");
  349. AssertRollupEquals({&map_, &map2_}, {
  350. {{"foo", "fallback"}, 20, 25},
  351. {{"foo", "translate me"}, 25, 30},
  352. });
  353. }
  354. } // namespace bloaty