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