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