]> arthur.barton.de Git - netdata.git/blob - src/unit_test.c
build: migrate to autotools
[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                         snprintf(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 int unit_test(long delay, long shift)
245 {
246         static int repeat = 0;
247         repeat++;
248
249         char name[101];
250         snprintf(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
251
252         debug_flags = 0xffffffff;
253         rrd_memory_mode = RRD_MEMORY_MODE_RAM;
254         rrd_update_every = 1;
255
256         int do_abs = 1;
257         int do_inc = 1;
258         int do_abst = 1;
259         int do_absi = 1;
260
261         RRDSET *st = rrdset_create("netdata", name, name, "netdata", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
262         st->debug = 1;
263
264         RRDDIM *rdabs = NULL;
265         RRDDIM *rdinc = NULL;
266         RRDDIM *rdabst = NULL;
267         RRDDIM *rdabsi = NULL;
268
269         if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
270         if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1 * rrd_update_every, RRDDIM_INCREMENTAL);
271         if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
272         if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
273
274         long increment = 1000;
275         collected_number i = 0;
276
277         unsigned long c, dimensions = 0;
278         RRDDIM *rd;
279         for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
280
281         for(c = 0; c < 20 ;c++) {
282                 i += increment;
283
284                 fprintf(stderr, "\n\nLOOP = %lu, DELAY = %ld, VALUE = " COLLECTED_NUMBER_FORMAT "\n", c, delay, i);
285                 if(c) {
286                         rrdset_next_usec(st, delay);
287                 }
288                 if(do_abs) rrddim_set(st, "absolute", i);
289                 if(do_inc) rrddim_set(st, "incremental", i);
290                 if(do_abst) rrddim_set(st, "percentage-of-absolute-row", i);
291                 if(do_absi) rrddim_set(st, "percentage-of-incremental-row", i);
292
293                 if(!c) {
294                         gettimeofday(&st->last_collected_time, NULL);
295                         st->last_collected_time.tv_usec = shift;
296                 }
297
298                 // prevent it from deleting the dimensions
299                 for(rd = st->dimensions ; rd ; rd = rd->next) rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
300
301                 rrdset_done(st);
302         }
303
304         unsigned long oincrement = increment;
305         increment = increment * st->update_every * 1000000 / delay;
306         fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %lu, DELAY %lu, SHIFT %lu\n", oincrement * 10, increment * 10, delay, shift);
307
308         int ret = 0;
309         storage_number v;
310         for(c = 0 ; c < st->counter ; c++) {
311                 fprintf(stderr, "\nPOSITION: c = %lu, VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
312
313                 for(rd = st->dimensions ; rd ; rd = rd->next) {
314                         fprintf(stderr, "\t %s " STORAGE_NUMBER_FORMAT "   ->   ", rd->id, rd->values[c]);
315
316                         if(rd == rdabs) v = 
317                                 (         oincrement 
318                                         + (increment * (1000000 - shift) / 1000000)
319                                         + c * increment
320                                 ) * 10;
321
322                         else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000)) * 10;
323                         else if(rd == rdabst) v = oincrement / dimensions;
324                         else if(rd == rdabsi) v = oincrement / dimensions;
325                         else v = 0;
326
327                         if(v == rd->values[c]) fprintf(stderr, "passed.\n");
328                         else {
329                                 fprintf(stderr, "ERROR! (expected " STORAGE_NUMBER_FORMAT ")\n", v);
330                                 ret = 1;
331                         }
332                 }
333         }
334
335         if(ret)
336                 fprintf(stderr, "\n\nUNIT TEST(%ld, %ld) FAILED\n\n", delay, shift);
337
338         return ret;
339 }
340