]> arthur.barton.de Git - netdata.git/blob - src/unit_test.c
all required system headers in common.h; some progress on health variables
[netdata.git] / src / unit_test.c
1 #include "common.h"
2
3 int check_storage_number(calculated_number n, int debug) {
4         char buffer[100];
5         uint32_t flags = SN_EXISTS;
6
7         storage_number s = pack_storage_number(n, flags);
8         calculated_number d = unpack_storage_number(s);
9
10         if(!does_storage_number_exist(s)) {
11                 fprintf(stderr, "Exists flags missing for number " CALCULATED_NUMBER_FORMAT "!\n", n);
12                 return 5;
13         }
14
15         calculated_number ddiff = d - n;
16         calculated_number dcdiff = ddiff * 100.0 / n;
17
18         if(dcdiff < 0) dcdiff = -dcdiff;
19
20         size_t len = print_calculated_number(buffer, d);
21         calculated_number p = strtold(buffer, NULL);
22         calculated_number pdiff = n - p;
23         calculated_number pcdiff = pdiff * 100.0 / n;
24         if(pcdiff < 0) pcdiff = -pcdiff;
25
26         if(debug) {
27                 fprintf(stderr,
28                         CALCULATED_NUMBER_FORMAT " original\n"
29                         CALCULATED_NUMBER_FORMAT " packed and unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
30                         "%s printed after unpacked (%zu bytes)\n"
31                         CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
32                         n,
33                         d, s, ddiff, dcdiff,
34                         buffer,
35                         len, p, pdiff, pcdiff
36                 );
37                 if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer));
38                 if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
39                 if(pcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: re-parsing the packed, unpacked and printed number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, pcdiff);
40         }
41
42         if(len != strlen(buffer)) return 1;
43         if(dcdiff > ACCURACY_LOSS) return 3;
44         if(pcdiff > ACCURACY_LOSS) return 4;
45         return 0;
46 }
47
48 void benchmark_storage_number(int loop, int multiplier) {
49         int i, j;
50         calculated_number n, d;
51         storage_number s;
52         unsigned long long user, system, total, mine, their;
53
54         char buffer[100];
55
56         struct rusage now, last;
57
58         fprintf(stderr, "\n\nBenchmarking %d numbers, please wait...\n\n", loop);
59
60         // ------------------------------------------------------------------------
61
62         fprintf(stderr, "SYSTEM  LONG DOUBLE    SIZE: %zu bytes\n", sizeof(calculated_number));
63         fprintf(stderr, "NETDATA FLOATING POINT SIZE: %zu bytes\n", sizeof(storage_number));
64
65         mine = (calculated_number)sizeof(storage_number) * (calculated_number)loop;
66         their = (calculated_number)sizeof(calculated_number) * (calculated_number)loop;
67
68         if(mine > their) {
69                 fprintf(stderr, "\nNETDATA NEEDS %0.2Lf TIMES MORE MEMORY. Sorry!\n", (long double)(mine / their));
70         }
71         else {
72                 fprintf(stderr, "\nNETDATA INTERNAL FLOATING POINT ARITHMETICS NEEDS %0.2Lf TIMES LESS MEMORY.\n", (long double)(their / mine));
73         }
74
75         fprintf(stderr, "\nNETDATA FLOATING POINT\n");
76         fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
77         fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
78         fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
79         fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
80         fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
81
82         // ------------------------------------------------------------------------
83
84         fprintf(stderr, "INTERNAL LONG DOUBLE PRINTING: ");
85         getrusage(RUSAGE_SELF, &last);
86
87         // do the job
88         for(j = 1; j < 11 ;j++) {
89                 n = STORAGE_NUMBER_POSITIVE_MIN * j;
90
91                 for(i = 0; i < loop ;i++) {
92                         n *= multiplier;
93                         if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
94
95                         print_calculated_number(buffer, n);
96                 }
97         }
98
99         getrusage(RUSAGE_SELF, &now);
100         user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
101         system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
102         total  = user + system;
103         mine = total;
104
105         fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
106
107         // ------------------------------------------------------------------------
108
109         fprintf(stderr, "SYSTEM   LONG DOUBLE PRINTING: ");
110         getrusage(RUSAGE_SELF, &last);
111
112         // do the job
113         for(j = 1; j < 11 ;j++) {
114                 n = STORAGE_NUMBER_POSITIVE_MIN * j;
115
116                 for(i = 0; i < loop ;i++) {
117                         n *= multiplier;
118                         if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
119                         snprintfz(buffer, 100, CALCULATED_NUMBER_FORMAT, n);
120                 }
121         }
122
123         getrusage(RUSAGE_SELF, &now);
124         user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
125         system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
126         total  = user + system;
127         their = total;
128
129         fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
130
131         if(mine > total) {
132                 fprintf(stderr, "NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
133         }
134         else {
135                 fprintf(stderr, "NETDATA CODE IS  F A S T E R  %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
136         }
137
138         // ------------------------------------------------------------------------
139
140         fprintf(stderr, "\nINTERNAL LONG DOUBLE PRINTING WITH PACK / UNPACK: ");
141         getrusage(RUSAGE_SELF, &last);
142
143         // do the job
144         for(j = 1; j < 11 ;j++) {
145                 n = STORAGE_NUMBER_POSITIVE_MIN * j;
146
147                 for(i = 0; i < loop ;i++) {
148                         n *= multiplier;
149                         if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
150
151                         s = pack_storage_number(n, 1);
152                         d = unpack_storage_number(s);
153                         print_calculated_number(buffer, d);
154                 }
155         }
156
157         getrusage(RUSAGE_SELF, &now);
158         user   = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
159         system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
160         total  = user + system;
161         mine = total;
162
163         fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
164
165         if(mine > their) {
166                 fprintf(stderr, "WITH PACKING UNPACKING NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
167         }
168         else {
169                 fprintf(stderr, "EVEN WITH PACKING AND UNPACKING, NETDATA CODE IS  F A S T E R  %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
170         }
171
172         // ------------------------------------------------------------------------
173
174 }
175
176 static int check_storage_number_exists() {
177         uint32_t flags = SN_EXISTS;
178
179
180         for(flags = 0; flags < 7 ; flags++) {
181                 if(get_storage_number_flags(flags << 24) != flags << 24) {
182                         fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24));
183                         return 1;
184                 }
185         }
186
187         flags = SN_EXISTS;
188         calculated_number n = 0.0;
189
190         storage_number s = pack_storage_number(n, flags);
191         calculated_number d = unpack_storage_number(s);
192         if(get_storage_number_flags(s) != flags) {
193                 fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s));
194                 return 1;
195         }
196         if(n != d) {
197                 fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d);
198                 return 1;
199         }
200
201         return 0;
202 }
203
204 int unit_test_storage()
205 {
206         if(check_storage_number_exists()) return 0;
207
208         calculated_number c, a = 0;
209         int i, j, g, r = 0;
210
211         for(g = -1; g <= 1 ; g++) {
212                 a = 0;
213
214                 if(!g) continue;
215
216                 for(j = 0; j < 9 ;j++) {
217                         a += 0.0000001;
218                         c = a * g;
219                         for(i = 0; i < 21 ;i++, c *= 10) {
220                                 if(c > 0 && c < STORAGE_NUMBER_POSITIVE_MIN) continue;
221                                 if(c < 0 && c > STORAGE_NUMBER_NEGATIVE_MAX) continue;
222
223                                 if(check_storage_number(c, 1)) return 1;
224                         }
225                 }
226         }
227
228         benchmark_storage_number(1000000, 2);
229         return r;
230 }
231
232
233 // --------------------------------------------------------------------------------------------------------------------
234
235 struct feed_values {
236                 unsigned long long microseconds;
237                 collected_number value;
238 };
239
240 struct test {
241         char name[100];
242         char description[1024];
243
244         int update_every;
245         unsigned long long multiplier;
246         unsigned long long divisor;
247         int algorithm;
248
249         unsigned long feed_entries;
250         unsigned long result_entries;
251         struct feed_values *feed;
252         calculated_number *results;
253
254         collected_number *feed2;
255         calculated_number *results2;
256 };
257
258 // --------------------------------------------------------------------------------------------------------------------
259 // test1
260 // test absolute values stored
261
262 struct feed_values test1_feed[] = {
263                 { 0, 10 },
264                 { 1000000, 20 },
265                 { 1000000, 30 },
266                 { 1000000, 40 },
267                 { 1000000, 50 },
268                 { 1000000, 60 },
269                 { 1000000, 70 },
270                 { 1000000, 80 },
271                 { 1000000, 90 },
272                 { 1000000, 100 },
273 };
274
275 calculated_number test1_results[] = {
276                 20, 30, 40, 50, 60, 70, 80, 90, 100
277 };
278
279 struct test test1 = {
280                 "test1",                        // name
281                 "test absolute values stored at exactly second boundaries",
282                 1,                                      // update_every
283                 1,                                      // multiplier
284                 1,                                      // divisor
285                 RRDDIM_ABSOLUTE,        // algorithm
286                 10,                                     // feed entries
287                 9,                                      // result entries
288                 test1_feed,                     // feed
289                 test1_results,          // results
290                 NULL,                           // feed2
291                 NULL                            // results2
292 };
293
294 // --------------------------------------------------------------------------------------------------------------------
295 // test2
296 // test absolute values stored in the middle of second boundaries
297
298 struct feed_values test2_feed[] = {
299                 { 500000, 10 },
300                 { 1000000, 20 },
301                 { 1000000, 30 },
302                 { 1000000, 40 },
303                 { 1000000, 50 },
304                 { 1000000, 60 },
305                 { 1000000, 70 },
306                 { 1000000, 80 },
307                 { 1000000, 90 },
308                 { 1000000, 100 },
309 };
310
311 calculated_number test2_results[] = {
312                 20, 30, 40, 50, 60, 70, 80, 90, 100
313 };
314
315 struct test test2 = {
316                 "test2",                        // name
317                 "test absolute values stored in the middle of second boundaries",
318                 1,                                      // update_every
319                 1,                                      // multiplier
320                 1,                                      // divisor
321                 RRDDIM_ABSOLUTE,        // algorithm
322                 10,                                     // feed entries
323                 9,                                      // result entries
324                 test2_feed,                     // feed
325                 test2_results,          // results
326                 NULL,                           // feed2
327                 NULL                            // results2
328 };
329
330 // --------------------------------------------------------------------------------------------------------------------
331 // test3
332
333 struct feed_values test3_feed[] = {
334                 { 0, 10 },
335                 { 1000000, 20 },
336                 { 1000000, 30 },
337                 { 1000000, 40 },
338                 { 1000000, 50 },
339                 { 1000000, 60 },
340                 { 1000000, 70 },
341                 { 1000000, 80 },
342                 { 1000000, 90 },
343                 { 1000000, 100 },
344 };
345
346 calculated_number test3_results[] = {
347                 10, 10, 10, 10, 10, 10, 10, 10, 10
348 };
349
350 struct test test3 = {
351                 "test3",                        // name
352                 "test incremental values stored at exactly second boundaries",
353                 1,                                      // update_every
354                 1,                                      // multiplier
355                 1,                                      // divisor
356                 RRDDIM_INCREMENTAL,     // algorithm
357                 10,                                     // feed entries
358                 9,                                      // result entries
359                 test3_feed,                     // feed
360                 test3_results,          // results
361                 NULL,                           // feed2
362                 NULL                            // results2
363 };
364
365 // --------------------------------------------------------------------------------------------------------------------
366 // test4
367
368 struct feed_values test4_feed[] = {
369                 { 500000, 10 },
370                 { 1000000, 20 },
371                 { 1000000, 30 },
372                 { 1000000, 40 },
373                 { 1000000, 50 },
374                 { 1000000, 60 },
375                 { 1000000, 70 },
376                 { 1000000, 80 },
377                 { 1000000, 90 },
378                 { 1000000, 100 },
379 };
380
381 calculated_number test4_results[] = {
382                 5, 10, 10, 10, 10, 10, 10, 10, 10
383 };
384
385 struct test test4 = {
386                 "test4",                        // name
387                 "test incremental values stored in the middle of second boundaries",
388                 1,                                      // update_every
389                 1,                                      // multiplier
390                 1,                                      // divisor
391                 RRDDIM_INCREMENTAL,     // algorithm
392                 10,                                     // feed entries
393                 9,                                      // result entries
394                 test4_feed,                     // feed
395                 test4_results,          // results
396                 NULL,                           // feed2
397                 NULL                            // results2
398 };
399
400 // --------------------------------------------------------------------------------------------------------------------
401 // test5
402
403 struct feed_values test5_feed[] = {
404                 { 500000, 1000 },
405                 { 1000000, 2000 },
406                 { 1000000, 2000 },
407                 { 1000000, 2000 },
408                 { 1000000, 3000 },
409                 { 1000000, 2000 },
410                 { 1000000, 2000 },
411                 { 1000000, 2000 },
412                 { 1000000, 2000 },
413                 { 1000000, 2000 },
414 };
415
416 calculated_number test5_results[] = {
417                 500, 500, 0, 500, 500, 0, 0, 0, 0
418 };
419
420 struct test test5 = {
421                 "test5",                        // name
422                 "test incremental values ups and downs",
423                 1,                                      // update_every
424                 1,                                      // multiplier
425                 1,                                      // divisor
426                 RRDDIM_INCREMENTAL,     // algorithm
427                 10,                                     // feed entries
428                 9,                                      // result entries
429                 test5_feed,                     // feed
430                 test5_results,          // results
431                 NULL,                           // feed2
432                 NULL                            // results2
433 };
434
435 // --------------------------------------------------------------------------------------------------------------------
436 // test6
437
438 struct feed_values test6_feed[] = {
439                 { 250000, 1000 },
440                 { 250000, 2000 },
441                 { 250000, 3000 },
442                 { 250000, 4000 },
443                 { 250000, 5000 },
444                 { 250000, 6000 },
445                 { 250000, 7000 },
446                 { 250000, 8000 },
447                 { 250000, 9000 },
448                 { 250000, 10000 },
449                 { 250000, 11000 },
450                 { 250000, 12000 },
451                 { 250000, 13000 },
452                 { 250000, 14000 },
453                 { 250000, 15000 },
454                 { 250000, 16000 },
455 };
456
457 calculated_number test6_results[] = {
458                 3000, 4000, 4000, 4000
459 };
460
461 struct test test6 = {
462                 "test6",                        // name
463                 "test incremental values updated within the same second",
464                 1,                                      // update_every
465                 1,                                      // multiplier
466                 1,                                      // divisor
467                 RRDDIM_INCREMENTAL,     // algorithm
468                 16,                                     // feed entries
469                 4,                                      // result entries
470                 test6_feed,                     // feed
471                 test6_results,          // results
472                 NULL,                           // feed2
473                 NULL                            // results2
474 };
475
476 // --------------------------------------------------------------------------------------------------------------------
477 // test7
478
479 struct feed_values test7_feed[] = {
480                 { 500000, 1000 },
481                 { 2000000, 2000 },
482                 { 2000000, 3000 },
483                 { 2000000, 4000 },
484                 { 2000000, 5000 },
485                 { 2000000, 6000 },
486                 { 2000000, 7000 },
487                 { 2000000, 8000 },
488                 { 2000000, 9000 },
489                 { 2000000, 10000 },
490 };
491
492 calculated_number test7_results[] = {
493                 250, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500
494 };
495
496 struct test test7 = {
497                 "test7",                        // name
498                 "test incremental values updated in long durations",
499                 1,                                      // update_every
500                 1,                                      // multiplier
501                 1,                                      // divisor
502                 RRDDIM_INCREMENTAL,     // algorithm
503                 10,                                     // feed entries
504                 18,                                     // result entries
505                 test7_feed,                     // feed
506                 test7_results,          // results
507                 NULL,                           // feed2
508                 NULL                            // results2
509 };
510
511 // --------------------------------------------------------------------------------------------------------------------
512 // test8
513
514 struct feed_values test8_feed[] = {
515                 { 500000, 1000 },
516                 { 2000000, 2000 },
517                 { 2000000, 3000 },
518                 { 2000000, 4000 },
519                 { 2000000, 5000 },
520                 { 2000000, 6000 },
521 };
522
523 calculated_number test8_results[] = {
524                 1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000
525 };
526
527 struct test test8 = {
528                 "test8",                        // name
529                 "test absolute values updated in long durations",
530                 1,                                      // update_every
531                 1,                                      // multiplier
532                 1,                                      // divisor
533                 RRDDIM_ABSOLUTE,        // algorithm
534                 6,                                      // feed entries
535                 10,                                     // result entries
536                 test8_feed,                     // feed
537                 test8_results,          // results
538                 NULL,                           // feed2
539                 NULL                            // results2
540 };
541
542 // --------------------------------------------------------------------------------------------------------------------
543 // test9
544
545 struct feed_values test9_feed[] = {
546                 { 250000, 1000 },
547                 { 250000, 2000 },
548                 { 250000, 3000 },
549                 { 250000, 4000 },
550                 { 250000, 5000 },
551                 { 250000, 6000 },
552                 { 250000, 7000 },
553                 { 250000, 8000 },
554                 { 250000, 9000 },
555                 { 250000, 10000 },
556                 { 250000, 11000 },
557                 { 250000, 12000 },
558                 { 250000, 13000 },
559                 { 250000, 14000 },
560                 { 250000, 15000 },
561                 { 250000, 16000 },
562 };
563
564 calculated_number test9_results[] = {
565                 4000, 8000, 12000, 16000
566 };
567
568 struct test test9 = {
569                 "test9",                        // name
570                 "test absolute values updated within the same second",
571                 1,                                      // update_every
572                 1,                                      // multiplier
573                 1,                                      // divisor
574                 RRDDIM_ABSOLUTE,        // algorithm
575                 16,                                     // feed entries
576                 4,                                      // result entries
577                 test9_feed,                     // feed
578                 test9_results,          // results
579                 NULL,                           // feed2
580                 NULL                            // results2
581 };
582
583 // --------------------------------------------------------------------------------------------------------------------
584 // test10
585
586 struct feed_values test10_feed[] = {
587                 { 500000,  1000 },
588                 { 600000,  1000 +  600 },
589                 { 200000,  1600 +  200 },
590                 { 1000000, 1800 + 1000 },
591                 { 200000,  2800 +  200 },
592                 { 2000000, 3000 + 2000 },
593                 { 600000,  5000 +  600 },
594                 { 400000,  5600 +  400 },
595                 { 900000,  6000 +  900 },
596                 { 1000000, 6900 + 1000 },
597 };
598
599 calculated_number test10_results[] = {
600                 500, 1000, 1000, 1000, 1000, 1000, 1000
601 };
602
603 struct test test10 = {
604                 "test10",                       // name
605                 "test incremental values updated in short and long durations",
606                 1,                                      // update_every
607                 1,                                      // multiplier
608                 1,                                      // divisor
609                 RRDDIM_INCREMENTAL,     // algorithm
610                 10,                                     // feed entries
611                 7,                                      // result entries
612                 test10_feed,            // feed
613                 test10_results,         // results
614                 NULL,                           // feed2
615                 NULL                            // results2
616 };
617
618 // --------------------------------------------------------------------------------------------------------------------
619 // test11
620
621 struct feed_values test11_feed[] = {
622                 { 0, 10 },
623                 { 1000000, 20 },
624                 { 1000000, 30 },
625                 { 1000000, 40 },
626                 { 1000000, 50 },
627                 { 1000000, 60 },
628                 { 1000000, 70 },
629                 { 1000000, 80 },
630                 { 1000000, 90 },
631                 { 1000000, 100 },
632 };
633
634 collected_number test11_feed2[] = {
635         10, 20, 30, 40, 50, 60, 70, 80, 90, 100
636 };
637
638 calculated_number test11_results[] = {
639                 50, 50, 50, 50, 50, 50, 50, 50, 50
640 };
641
642 calculated_number test11_results2[] = {
643                 50, 50, 50, 50, 50, 50, 50, 50, 50
644 };
645
646 struct test test11 = {
647                 "test11",                       // name
648                 "test percentage-of-incremental-row with equal values",
649                 1,                                      // update_every
650                 1,                                      // multiplier
651                 1,                                      // divisor
652                 RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
653                 10,                                     // feed entries
654                 9,                                      // result entries
655                 test11_feed,            // feed
656                 test11_results,         // results
657                 test11_feed2,           // feed2
658                 test11_results2         // results2
659 };
660
661 // --------------------------------------------------------------------------------------------------------------------
662 // test12
663
664 struct feed_values test12_feed[] = {
665                 { 0, 10 },
666                 { 1000000, 20 },
667                 { 1000000, 30 },
668                 { 1000000, 40 },
669                 { 1000000, 50 },
670                 { 1000000, 60 },
671                 { 1000000, 70 },
672                 { 1000000, 80 },
673                 { 1000000, 90 },
674                 { 1000000, 100 },
675 };
676
677 collected_number test12_feed2[] = {
678         10*3, 20*3, 30*3, 40*3, 50*3, 60*3, 70*3, 80*3, 90*3, 100*3
679 };
680
681 calculated_number test12_results[] = {
682                 25, 25, 25, 25, 25, 25, 25, 25, 25
683 };
684
685 calculated_number test12_results2[] = {
686                 75, 75, 75, 75, 75, 75, 75, 75, 75
687 };
688
689 struct test test12 = {
690                 "test12",                       // name
691                 "test percentage-of-incremental-row with equal values",
692                 1,                                      // update_every
693                 1,                                      // multiplier
694                 1,                                      // divisor
695                 RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
696                 10,                                     // feed entries
697                 9,                                      // result entries
698                 test12_feed,            // feed
699                 test12_results,         // results
700                 test12_feed2,           // feed2
701                 test12_results2         // results2
702 };
703
704 // --------------------------------------------------------------------------------------------------------------------
705 // test13
706
707 struct feed_values test13_feed[] = {
708                 { 500000,  1000 },
709                 { 600000,  1000 +  600 },
710                 { 200000,  1600 +  200 },
711                 { 1000000, 1800 + 1000 },
712                 { 200000,  2800 +  200 },
713                 { 2000000, 3000 + 2000 },
714                 { 600000,  5000 +  600 },
715                 { 400000,  5600 +  400 },
716                 { 900000,  6000 +  900 },
717                 { 1000000, 6900 + 1000 },
718 };
719
720 calculated_number test13_results[] = {
721                 83.3333300, 100, 100, 100, 100, 100, 100
722 };
723
724 struct test test13 = {
725                 "test13",                       // name
726                 "test incremental values updated in short and long durations",
727                 1,                                      // update_every
728                 1,                                      // multiplier
729                 1,                                      // divisor
730                 RRDDIM_PCENT_OVER_DIFF_TOTAL,   // algorithm
731                 10,                                     // feed entries
732                 7,                                      // result entries
733                 test13_feed,            // feed
734                 test13_results,         // results
735                 NULL,                           // feed2
736                 NULL                            // results2
737 };
738
739 // --------------------------------------------------------------------------------------------------------------------
740
741 int run_test(struct test *test)
742 {
743         fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
744
745         rrd_memory_mode = RRD_MEMORY_MODE_RAM;
746         rrd_update_every = test->update_every;
747
748         char name[101];
749         snprintfz(name, 100, "unittest-%s", test->name);
750
751         // create the chart
752         RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
753         RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm);
754         
755         RRDDIM *rd2 = NULL;
756         if(test->feed2)
757                 rd2 = rrddim_add(st, "dim2", NULL, test->multiplier, test->divisor, test->algorithm);
758
759         st->debug = 1;
760
761         // feed it with the test data
762         unsigned long c;
763         for(c = 0; c < test->feed_entries; c++) {
764                 if(debug_flags) fprintf(stderr, "\n\n");
765
766                 if(c) {
767                         fprintf(stderr, "    > %s: feeding position %lu, after %llu microseconds\n", test->name, c+1, test->feed[c].microseconds);
768                         rrdset_next_usec(st, test->feed[c].microseconds);
769                 }
770                 else {
771                         fprintf(stderr, "    > %s: feeding position %lu\n", test->name, c+1);
772                 }
773
774                 fprintf(stderr, "       >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd->name, test->feed[c].value);
775                 rrddim_set(st, "dim1", test->feed[c].value);
776
777                 if(rd2) {
778                         fprintf(stderr, "       >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd2->name, test->feed2[c]);
779                         rrddim_set(st, "dim2", test->feed2[c]);
780                 }
781
782                 rrdset_done(st);
783
784                 // align the first entry to second boundary
785                 if(!c) {
786                         fprintf(stderr, "    > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds);
787                         rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds;
788                 }
789         }
790
791         // check the result
792         int errors = 0;
793
794         if(st->counter != test->result_entries) {
795                 fprintf(stderr, "    %s stored %lu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries);
796                 errors++;
797         }
798
799         unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
800         for(c = 0 ; c < max ; c++) {
801                 calculated_number v = unpack_storage_number(rd->values[c]);
802                 calculated_number n = test->results[c];
803                 int same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
804                 fprintf(stderr, "    %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
805                 if(!same) errors++;
806
807                 if(rd2) {
808                         v = unpack_storage_number(rd2->values[c]);
809                         n = test->results2[c];
810                         same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
811                         fprintf(stderr, "    %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd2->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
812                         if(!same) errors++;
813                 }
814         }
815
816         return errors;
817 }
818
819 int run_all_mockup_tests(void)
820 {
821         if(run_test(&test1))
822                 return 1;
823
824         if(run_test(&test2))
825                 return 1;
826
827         if(run_test(&test3))
828                 return 1;
829
830         if(run_test(&test4))
831                 return 1;
832
833         if(run_test(&test5))
834                 return 1;
835
836         if(run_test(&test6))
837                 return 1;
838
839         if(run_test(&test7))
840                 return 1;
841
842         if(run_test(&test8))
843                 return 1;
844
845         if(run_test(&test9))
846                 return 1;
847
848         if(run_test(&test10))
849                 return 1;
850
851         if(run_test(&test11))
852                 return 1;
853
854         if(run_test(&test12))
855                 return 1;
856
857         if(run_test(&test13))
858                 return 1;
859
860         return 0;
861 }
862
863 int unit_test(long delay, long shift)
864 {
865         static int repeat = 0;
866         repeat++;
867
868         char name[101];
869         snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
870
871         //debug_flags = 0xffffffff;
872         rrd_memory_mode = RRD_MEMORY_MODE_RAM;
873         rrd_update_every = 1;
874
875         int do_abs = 1;
876         int do_inc = 1;
877         int do_abst = 0;
878         int do_absi = 0;
879
880         RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
881         st->debug = 1;
882
883         RRDDIM *rdabs = NULL;
884         RRDDIM *rdinc = NULL;
885         RRDDIM *rdabst = NULL;
886         RRDDIM *rdabsi = NULL;
887
888         if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
889         if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRDDIM_INCREMENTAL);
890         if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
891         if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
892
893         long increment = 1000;
894         collected_number i = 0;
895
896         unsigned long c, dimensions = 0;
897         RRDDIM *rd;
898         for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
899
900         for(c = 0; c < 20 ;c++) {
901                 i += increment;
902
903                 fprintf(stderr, "\n\nLOOP = %lu, DELAY = %ld, VALUE = " COLLECTED_NUMBER_FORMAT "\n", c, delay, i);
904                 if(c) {
905                         rrdset_next_usec(st, delay);
906                 }
907                 if(do_abs) rrddim_set(st, "absolute", i);
908                 if(do_inc) rrddim_set(st, "incremental", i);
909                 if(do_abst) rrddim_set(st, "percentage-of-absolute-row", i);
910                 if(do_absi) rrddim_set(st, "percentage-of-incremental-row", i);
911
912                 if(!c) {
913                         gettimeofday(&st->last_collected_time, NULL);
914                         st->last_collected_time.tv_usec = shift;
915                 }
916
917                 // prevent it from deleting the dimensions
918                 for(rd = st->dimensions ; rd ; rd = rd->next)
919                         rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
920
921                 rrdset_done(st);
922         }
923
924         unsigned long oincrement = increment;
925         increment = increment * st->update_every * 1000000 / delay;
926         fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %ld, DELAY %ld, SHIFT %ld\n", oincrement * 10, increment * 10, delay, shift);
927
928         int ret = 0;
929         storage_number sn;
930         calculated_number cn, v;
931         for(c = 0 ; c < st->counter ; c++) {
932                 fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
933
934                 for(rd = st->dimensions ; rd ; rd = rd->next) {
935                         sn = rd->values[c];
936                         cn = unpack_storage_number(sn);
937                         fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ")   ->   ", rd->id, cn, sn);
938
939                         if(rd == rdabs) v =
940                                 (         oincrement
941                                         // + (increment * (1000000 - shift) / 1000000)
942                                         + (c + 1) * increment
943                                 );
944
945                         else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000));
946                         else if(rd == rdabst) v = oincrement / dimensions / 10;
947                         else if(rd == rdabsi) v = oincrement / dimensions / 10;
948                         else v = 0;
949
950                         if(v == cn) fprintf(stderr, "passed.\n");
951                         else {
952                                 fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v);
953                                 ret = 1;
954                         }
955                 }
956         }
957
958         if(ret)
959                 fprintf(stderr, "\n\nUNIT TEST(%ld, %ld) FAILED\n\n", delay, shift);
960
961         return ret;
962 }