page_test.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. #include "page.h"
  2. #include "page_test.h"
  3. #ifdef HAVE_GTEST
  4. #include <gtest/gtest.h>
  5. #include <limits>
  6. #include <random>
  7. bool operator==(const STORAGE_POINT lhs, const STORAGE_POINT rhs) {
  8. if (lhs.min != rhs.min)
  9. return false;
  10. if (lhs.max != rhs.max)
  11. return false;
  12. if (lhs.sum != rhs.sum)
  13. return false;
  14. if (lhs.start_time_s != rhs.start_time_s)
  15. return false;
  16. if (lhs.end_time_s != rhs.end_time_s)
  17. return false;
  18. if (lhs.count != rhs.count)
  19. return false;
  20. if (lhs.flags != rhs.flags)
  21. return false;
  22. return true;
  23. }
  24. // TODO: use value-parameterized tests
  25. // http://google.github.io/googletest/advanced.html#value-parameterized-tests
  26. static uint8_t page_type = PAGE_GORILLA_METRICS;
  27. static size_t slots_for_page(size_t n) {
  28. switch (page_type) {
  29. case PAGE_METRICS:
  30. return 1024;
  31. case PAGE_GORILLA_METRICS:
  32. return n;
  33. default:
  34. fatal("Slots requested for unsupported page: %uc", page_type);
  35. }
  36. }
  37. TEST(PGD, EmptyOrNull) {
  38. PGD *pg = NULL;
  39. PGDC cursor;
  40. STORAGE_POINT sp;
  41. EXPECT_TRUE(pgd_is_empty(pg));
  42. EXPECT_EQ(pgd_slots_used(pg), 0);
  43. EXPECT_EQ(pgd_memory_footprint(pg), 0);
  44. EXPECT_EQ(pgd_disk_footprint(pg), 0);
  45. pgdc_reset(&cursor, pg, 0);
  46. EXPECT_FALSE(pgdc_get_next_point(&cursor, 0, &sp));
  47. pgd_free(pg);
  48. pg = PGD_EMPTY;
  49. EXPECT_TRUE(pgd_is_empty(pg));
  50. EXPECT_EQ(pgd_slots_used(pg), 0);
  51. EXPECT_EQ(pgd_memory_footprint(pg), 0);
  52. EXPECT_EQ(pgd_disk_footprint(pg), 0);
  53. EXPECT_FALSE(pgdc_get_next_point(&cursor, 0, &sp));
  54. pgdc_reset(&cursor, pg, 0);
  55. EXPECT_FALSE(pgdc_get_next_point(&cursor, 0, &sp));
  56. pgd_free(pg);
  57. }
  58. TEST(PGD, Create) {
  59. size_t slots = slots_for_page(1024 * 1024);
  60. PGD *pg = pgd_create(page_type, slots);
  61. EXPECT_EQ(pgd_type(pg), page_type);
  62. EXPECT_TRUE(pgd_is_empty(pg));
  63. EXPECT_EQ(pgd_slots_used(pg), 0);
  64. for (size_t i = 0; i != slots; i++) {
  65. pgd_append_point(pg, i, i, 0, 0, 1, 1, SN_DEFAULT_FLAGS, i);
  66. EXPECT_FALSE(pgd_is_empty(pg));
  67. }
  68. EXPECT_EQ(pgd_slots_used(pg), slots);
  69. EXPECT_DEATH(
  70. pgd_append_point(pg, slots, slots, 0, 0, 1, 1, SN_DEFAULT_FLAGS, slots),
  71. ".*"
  72. );
  73. pgd_free(pg);
  74. }
  75. TEST(PGD, CursorFullPage) {
  76. size_t slots = slots_for_page(1024 * 1024);
  77. PGD *pg = pgd_create(page_type, slots);
  78. for (size_t slot = 0; slot != slots; slot++)
  79. pgd_append_point(pg, slot, slot, 0, 0, 1, 1, SN_DEFAULT_FLAGS, slot);
  80. for (size_t i = 0; i != 2; i++) {
  81. PGDC cursor;
  82. pgdc_reset(&cursor, pg, 0);
  83. STORAGE_POINT sp;
  84. for (size_t slot = 0; slot != slots; slot++) {
  85. EXPECT_TRUE(pgdc_get_next_point(&cursor, slot, &sp));
  86. EXPECT_EQ(slot, static_cast<size_t>(sp.min));
  87. EXPECT_EQ(sp.min, sp.max);
  88. EXPECT_EQ(sp.min, sp.sum);
  89. EXPECT_EQ(sp.count, 1);
  90. EXPECT_EQ(sp.anomaly_count, 0);
  91. }
  92. EXPECT_FALSE(pgdc_get_next_point(&cursor, slots, &sp));
  93. }
  94. for (size_t i = 0; i != 2; i++) {
  95. PGDC cursor;
  96. pgdc_reset(&cursor, pg, slots / 2);
  97. STORAGE_POINT sp;
  98. for (size_t slot = slots / 2; slot != slots; slot++) {
  99. EXPECT_TRUE(pgdc_get_next_point(&cursor, slot, &sp));
  100. EXPECT_EQ(slot, static_cast<size_t>(sp.min));
  101. EXPECT_EQ(sp.min, sp.max);
  102. EXPECT_EQ(sp.min, sp.sum);
  103. EXPECT_EQ(sp.count, 1);
  104. EXPECT_EQ(sp.anomaly_count, 0);
  105. }
  106. EXPECT_FALSE(pgdc_get_next_point(&cursor, slots, &sp));
  107. }
  108. // out of bounds seek
  109. {
  110. PGDC cursor;
  111. pgdc_reset(&cursor, pg, 2 * slots);
  112. STORAGE_POINT sp;
  113. EXPECT_FALSE(pgdc_get_next_point(&cursor, 2 * slots, &sp));
  114. }
  115. pgd_free(pg);
  116. }
  117. TEST(PGD, CursorHalfPage) {
  118. size_t slots = slots_for_page(1024 * 1024);
  119. PGD *pg = pgd_create(page_type, slots);
  120. PGDC cursor;
  121. STORAGE_POINT sp;
  122. // fill the 1st half of the page
  123. for (size_t slot = 0; slot != slots / 2; slot++)
  124. pgd_append_point(pg, slot, slot, 0, 0, 1, 1, SN_DEFAULT_FLAGS, slot);
  125. pgdc_reset(&cursor, pg, 0);
  126. for (size_t slot = 0; slot != slots / 2; slot++) {
  127. EXPECT_TRUE(pgdc_get_next_point(&cursor, slot, &sp));
  128. EXPECT_EQ(slot, static_cast<size_t>(sp.min));
  129. EXPECT_EQ(sp.min, sp.max);
  130. EXPECT_EQ(sp.min, sp.sum);
  131. EXPECT_EQ(sp.count, 1);
  132. EXPECT_EQ(sp.anomaly_count, 0);
  133. }
  134. EXPECT_FALSE(pgdc_get_next_point(&cursor, slots / 2, &sp));
  135. // reset pgdc to the end of the page, we should not be getting more
  136. // points even if the page has grown in between.
  137. pgdc_reset(&cursor, pg, slots / 2);
  138. for (size_t slot = slots / 2; slot != slots; slot++)
  139. pgd_append_point(pg, slot, slot, 0, 0, 1, 1, SN_DEFAULT_FLAGS, slot);
  140. for (size_t slot = slots / 2; slot != slots; slot++)
  141. EXPECT_FALSE(pgdc_get_next_point(&cursor, slot, &sp));
  142. EXPECT_FALSE(pgdc_get_next_point(&cursor, slots, &sp));
  143. pgd_free(pg);
  144. }
  145. TEST(PGD, MemoryFootprint) {
  146. size_t slots = slots_for_page(1024 * 1024);
  147. PGD *pg = pgd_create(page_type, slots);
  148. uint32_t footprint = 0;
  149. switch (pgd_type(pg)) {
  150. case PAGE_METRICS:
  151. footprint = slots * sizeof(uint32_t);
  152. break;
  153. case PAGE_GORILLA_METRICS:
  154. footprint = 128 * sizeof(uint32_t);
  155. break;
  156. default:
  157. fatal("Uknown page type: %uc", pgd_type(pg));
  158. }
  159. EXPECT_NEAR(pgd_memory_footprint(pg), footprint, 128);
  160. std::random_device rand_dev;
  161. std::mt19937 gen(rand_dev());
  162. std::uniform_int_distribution<uint32_t> distr(std::numeric_limits<uint32_t>::min(),
  163. std::numeric_limits<uint32_t>::max()); // define the range
  164. for (size_t slot = 0; slot != slots; slot++) {
  165. uint32_t n = distr(gen);
  166. pgd_append_point(pg, slot, n, 0, 0, 1, 1, SN_DEFAULT_FLAGS, slot);
  167. }
  168. footprint = slots * sizeof(uint32_t);
  169. uint32_t abs_error = 0;
  170. switch (pgd_type(pg)) {
  171. case PAGE_METRICS:
  172. abs_error = 128;
  173. break;
  174. case PAGE_GORILLA_METRICS:
  175. abs_error = footprint / 10;
  176. break;
  177. default:
  178. fatal("Uknown page type: %uc", pgd_type(pg));
  179. }
  180. EXPECT_NEAR(pgd_memory_footprint(pg), footprint, abs_error);
  181. }
  182. TEST(PGD, DiskFootprint) {
  183. size_t slots = slots_for_page(1024 * 1024);
  184. PGD *pg = pgd_create(page_type, slots);
  185. std::random_device rand_dev;
  186. std::mt19937 gen(rand_dev());
  187. std::uniform_int_distribution<uint32_t> distr(std::numeric_limits<uint32_t>::min(),
  188. std::numeric_limits<uint32_t>::max()); // define the range
  189. size_t used_slots = 16;
  190. for (size_t slot = 0; slot != used_slots; slot++) {
  191. uint32_t n = distr(gen);
  192. pgd_append_point(pg, slot, n, 0, 0, 1, 1, SN_DEFAULT_FLAGS, slot);
  193. }
  194. uint32_t footprint = 0;
  195. switch (pgd_type(pg)) {
  196. case PAGE_METRICS:
  197. footprint = used_slots * sizeof(uint32_t);
  198. break;
  199. case PAGE_GORILLA_METRICS:
  200. footprint = 128 * sizeof(uint32_t);
  201. break;
  202. default:
  203. fatal("Uknown page type: %uc", pgd_type(pg));
  204. }
  205. EXPECT_EQ(pgd_disk_footprint(pg), footprint);
  206. pgd_free(pg);
  207. pg = pgd_create(page_type, slots);
  208. used_slots = 128 + 64;
  209. for (size_t slot = 0; slot != used_slots; slot++) {
  210. uint32_t n = distr(gen);
  211. pgd_append_point(pg, slot, n, 0, 0, 1, 1, SN_DEFAULT_FLAGS, slot);
  212. }
  213. switch (pgd_type(pg)) {
  214. case PAGE_METRICS:
  215. footprint = used_slots * sizeof(uint32_t);
  216. break;
  217. case PAGE_GORILLA_METRICS:
  218. footprint = 2 * (128 * sizeof(uint32_t));
  219. break;
  220. default:
  221. fatal("Uknown page type: %uc", pgd_type(pg));
  222. }
  223. EXPECT_EQ(pgd_disk_footprint(pg), footprint);
  224. pgd_free(pg);
  225. }
  226. TEST(PGD, CopyToExtent) {
  227. size_t slots = slots_for_page(1024 * 1024);
  228. PGD *pg_collector = pgd_create(page_type, slots);
  229. uint32_t value = 666;
  230. pgd_append_point(pg_collector, 0, value, 0, 0, 1, 0, SN_DEFAULT_FLAGS, 0);
  231. uint32_t size_in_bytes = pgd_disk_footprint(pg_collector);
  232. EXPECT_EQ(size_in_bytes, 512);
  233. uint32_t size_in_words = size_in_bytes / sizeof(uint32_t);
  234. alignas(sizeof(uintptr_t)) uint32_t disk_buffer[size_in_words];
  235. for (size_t i = 0; i != size_in_words; i++) {
  236. disk_buffer[i] = std::numeric_limits<uint32_t>::max();
  237. }
  238. pgd_copy_to_extent(pg_collector, (uint8_t *) &disk_buffer[0], size_in_bytes);
  239. EXPECT_EQ(disk_buffer[0], NULL);
  240. EXPECT_EQ(disk_buffer[1], NULL);
  241. EXPECT_EQ(disk_buffer[2], 1);
  242. EXPECT_EQ(disk_buffer[3], 32);
  243. storage_number sn = pack_storage_number(value, SN_DEFAULT_FLAGS);
  244. EXPECT_EQ(disk_buffer[4], sn);
  245. // make sure the rest of the page is 0'ed so that it's amenable to compression
  246. for (size_t i = 5; i != size_in_words; i++)
  247. EXPECT_EQ(disk_buffer[i], 0);
  248. pgd_free(pg_collector);
  249. }
  250. TEST(PGD, Roundtrip) {
  251. size_t slots = slots_for_page(1024 * 1024);
  252. PGD *pg_collector = pgd_create(page_type, slots);
  253. for (size_t i = 0; i != slots; i++)
  254. pgd_append_point(pg_collector, i, i, 0, 0, 1, 1, SN_DEFAULT_FLAGS, i);
  255. uint32_t size_in_bytes = pgd_disk_footprint(pg_collector);
  256. uint32_t size_in_words = size_in_bytes / sizeof(uint32_t);
  257. alignas(sizeof(uintptr_t)) uint32_t disk_buffer[size_in_words];
  258. for (size_t i = 0; i != size_in_words; i++)
  259. disk_buffer[i] = std::numeric_limits<uint32_t>::max();
  260. pgd_copy_to_extent(pg_collector, (uint8_t *) &disk_buffer[0], size_in_bytes);
  261. PGD *pg_disk = pgd_create_from_disk_data(page_type, &disk_buffer[0], size_in_bytes);
  262. EXPECT_EQ(pgd_slots_used(pg_disk), slots);
  263. // Expected memory footprint is equal to the disk footprint + a couple
  264. // bytes for the PGD metadata.
  265. EXPECT_NEAR(pgd_memory_footprint(pg_disk), size_in_bytes, 128);
  266. // Do not allow calling disk footprint for pages created from disk.
  267. EXPECT_DEATH(pgd_disk_footprint(pg_disk), ".*");
  268. for (size_t i = 0; i != 10; i++) {
  269. PGDC cursor_collector;
  270. PGDC cursor_disk;
  271. pgdc_reset(&cursor_collector, pg_collector, i * 1024);
  272. pgdc_reset(&cursor_disk, pg_disk, i * 1024);
  273. STORAGE_POINT sp_collector = {};
  274. STORAGE_POINT sp_disk = {};
  275. for (size_t slot = i * 1024; slot != slots; slot++) {
  276. EXPECT_TRUE(pgdc_get_next_point(&cursor_collector, slot, &sp_collector));
  277. EXPECT_TRUE(pgdc_get_next_point(&cursor_disk, slot, &sp_disk));
  278. EXPECT_EQ(sp_collector, sp_disk);
  279. }
  280. EXPECT_FALSE(pgdc_get_next_point(&cursor_collector, slots, &sp_collector));
  281. EXPECT_FALSE(pgdc_get_next_point(&cursor_disk, slots, &sp_disk));
  282. }
  283. pgd_free(pg_disk);
  284. pgd_free(pg_collector);
  285. }
  286. int pgd_test(int argc, char *argv[])
  287. {
  288. // Dummy/necessary initialization stuff
  289. PGC *dummy_cache = pgc_create("pgd-tests-cache", 32 * 1024 * 1024, NULL, 64, NULL, NULL,
  290. 10, 10, 1000, 10, PGC_OPTIONS_NONE, 1, 11);
  291. pgd_init_arals();
  292. ::testing::InitGoogleTest(&argc, argv);
  293. int rc = RUN_ALL_TESTS();
  294. pgc_destroy(dummy_cache);
  295. return rc;
  296. }
  297. #else // HAVE_GTEST
  298. int pgd_test(int argc, char *argv[])
  299. {
  300. (void) argc;
  301. (void) argv;
  302. fprintf(stderr, "Can not run PGD tests because the agent was not build with support for google tests.\n");
  303. return 0;
  304. }
  305. #endif // HAVE_GTEST