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