better unit testing of storage numbers; added benchmarking
Costa Tsaousis (ktsaou) committed
Mar 19, 2015 at 21:56 UTC
9da67ae21ab296027e229db0092b9019c717305e
3 files changed
+187
-46
src/storage_number.h
+5
@@ -18,4 +18,9 @@ typedef uint32_t ustorage_number;
18
storage_number pack_storage_number(calculated_number value);
19
calculated_number unpack_storage_number(storage_number value);
20
21
+#define STORAGE_NUMBER_POSITIVE_MAX 167772150000000.0
22
+#define STORAGE_NUMBER_POSITIVE_MIN 0.00001
23
+#define STORAGE_NUMBER_NEGATIVE_MAX -0.00001
24
+#define STORAGE_NUMBER_NEGATIVE_MIN -167772150000000.0
25
+
26
#endif /* NETDATA_STORAGE_NUMBER_H */
src/unit_test.c
+178
-44
@@ -1,17 +1,186 @@
1
#include <stdio.h>
2
#include <stdlib.h>
3
+#include <string.h>
4
+#include <sys/resource.h>
5
6
#include "storage_number.h"
7
#include "rrd.h"
8
#include "log.h"
9
#include "web_buffer.h"
10
11
+#define ACCURACY_LOSS 0.0000001
12
+
13
+int check_storage_number(calculated_number n, int debug) {
14
+ char buffer[100];
15
+
16
+ storage_number s = pack_storage_number(n);
17
+ calculated_number d = unpack_storage_number(s);
18
+
19
+ calculated_number ddiff = d - n;
20
+ calculated_number dcdiff = ddiff * 100.0 / n;
21
+
22
+ if(dcdiff < 0) dcdiff = -dcdiff;
23
+
24
+ size_t len = print_calculated_number(buffer, d);
25
+ calculated_number p = strtold(buffer, NULL);
26
+ calculated_number pdiff = n - p;
27
+ calculated_number pcdiff = pdiff * 100.0 / n;
28
+ if(pcdiff < 0) pcdiff = -pcdiff;
29
+
30
+ if(debug) {
31
+ fprintf(stderr,
32
+ CALCULATED_NUMBER_FORMAT " original\n"
33
+ CALCULATED_NUMBER_FORMAT " packed and unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
34
+ "%s printed after unpacked (%lu bytes)\n"
35
+ CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
36
+ n,
37
+ d, s, ddiff, dcdiff,
38
+ buffer,
39
+ len, p, pdiff, pcdiff
40
+ );
41
+ if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %lu but it has %lu\n", buffer, len, strlen(buffer));
42
+ if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
43
+ 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);
44
+ }
45
+
46
+ if(len != strlen(buffer)) return 1;
47
+ if(dcdiff > ACCURACY_LOSS) return 3;
48
+ if(pcdiff > ACCURACY_LOSS) return 4;
49
+ return 0;
50
+}
51
+
52
+void benchmark_storage_number(int loop, int multiplier) {
53
+ int i, j;
54
+ calculated_number n, d;
55
+ storage_number s;
56
+ unsigned long long user, system, total, mine, their;
57
+
58
+ char buffer[100];
59
+
60
+ struct rusage now, last;
61
+
62
+ fprintf(stderr, "\n\nBenchmarking %d numbers, please wait...\n\n", loop);
63
+
64
+ // ------------------------------------------------------------------------
65
+
66
+ fprintf(stderr, "SYSTEM LONG DOUBLE SIZE: %lu bytes\n", sizeof(calculated_number));
67
+ fprintf(stderr, "NETDATA FLOATING POINT SIZE: %lu bytes\n", sizeof(storage_number));
68
+
69
+ mine = (calculated_number)sizeof(storage_number) * (calculated_number)loop;
70
+ their = (calculated_number)sizeof(calculated_number) * (calculated_number)loop;
71
+
72
+ if(mine > their) {
73
+ fprintf(stderr, "\nNETDATA NEEDS %0.2Lf TIMES MORE MEMORY. Sorry!\n", (long double)(mine / their));
74
+ }
75
+ else {
76
+ fprintf(stderr, "\nNETDATA INTERNAL FLOATING POINT ARITHMETICS NEEDS %0.2Lf TIMES LESS MEMORY.\n", (long double)(their / mine));
77
+ }
78
+
79
+ fprintf(stderr, "\nNETDATA FLOATING POINT\n");
80
+ fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
81
+ fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
82
+ fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
83
+ fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
84
+ fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
85
+
86
+ // ------------------------------------------------------------------------
87
+
88
+ fprintf(stderr, "INTERNAL LONG DOUBLE PRINTING: ");
89
+ getrusage(RUSAGE_SELF, &last);
90
+
91
+ // do the job
92
+ for(j = 1; j < 11 ;j++) {
93
+ n = STORAGE_NUMBER_POSITIVE_MIN * j;
94
+
95
+ for(i = 0; i < loop ;i++) {
96
+ n *= multiplier;
97
+ if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
98
+
99
+ print_calculated_number(buffer, n);
100
+ }
101
+ }
102
+
103
+ getrusage(RUSAGE_SELF, &now);
104
+ user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
105
+ system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
106
+ total = user + system;
107
+ mine = total;
108
+
109
+ 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));
110
+
111
+ // ------------------------------------------------------------------------
112
+
113
+ fprintf(stderr, "SYSTEM LONG DOUBLE PRINTING: ");
114
+ getrusage(RUSAGE_SELF, &last);
115
+
116
+ // do the job
117
+ for(j = 1; j < 11 ;j++) {
118
+ n = STORAGE_NUMBER_POSITIVE_MIN * j;
119
+
120
+ for(i = 0; i < loop ;i++) {
121
+ n *= multiplier;
122
+ if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
123
+ snprintf(buffer, 100, CALCULATED_NUMBER_FORMAT, n);
124
+ }
125
+ }
126
+
127
+ getrusage(RUSAGE_SELF, &now);
128
+ user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
129
+ system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
130
+ total = user + system;
131
+ their = total;
132
+
133
+ 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));
134
+
135
+ if(mine > total) {
136
+ fprintf(stderr, "NETDATA CODE IS SLOWER %0.2Lf TIMES\n", (long double)(mine / their));
137
+ }
138
+ else {
139
+ fprintf(stderr, "NETDATA CODE IS F A S T E R %0.2Lf TIMES\n", (long double)(their / mine));
140
+ }
141
+
142
+ // ------------------------------------------------------------------------
143
+
144
+ fprintf(stderr, "\nINTERNAL LONG DOUBLE PRINTING WITH PACK / UNPACK: ");
145
+ getrusage(RUSAGE_SELF, &last);
146
+
147
+ // do the job
148
+ for(j = 1; j < 11 ;j++) {
149
+ n = STORAGE_NUMBER_POSITIVE_MIN * j;
150
+
151
+ for(i = 0; i < loop ;i++) {
152
+ n *= multiplier;
153
+ if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
154
+
155
+ s = pack_storage_number(n);
156
+ d = unpack_storage_number(s);
157
+ print_calculated_number(buffer, d);
158
+ }
159
+ }
160
+
161
+ getrusage(RUSAGE_SELF, &now);
162
+ user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
163
+ system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
164
+ total = user + system;
165
+ mine = total;
166
+
167
+ 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));
168
+
169
+ if(mine > their) {
170
+ fprintf(stderr, "WITH PACKING UNPACKING NETDATA CODE IS SLOWER %0.2Lf TIMES\n", (long double)(mine / their));
171
+ }
172
+ else {
173
+ fprintf(stderr, "EVEN WITH PACKING AND UNPACKING, NETDATA CODE IS F A S T E R %0.2Lf TIMES\n", (long double)(their / mine));
174
+ }
175
+
176
+ // ------------------------------------------------------------------------
177
+
178
+}
179
+
180
int unit_test_storage()
181
{
11
- char buffer[100], *msg;
12
- storage_number s;
13
- calculated_number c, a = 0, d, ddiff, dcdiff, f, p, pdiff, pcdiff, maxddiff = 0, maxpdiff = 0;
14
- int i, j, g, r = 0, l;
182
+ calculated_number c, a = 0;
183
+ int i, j, g, r = 0;
184
185
for(g = -1; g <= 1 ; g++) {
186
a = 0;
@@ -22,50 +191,15 @@ int unit_test_storage()
191
a += 0.0000001;
192
c = a * g;
193
for(i = 0; i < 21 ;i++, c *= 10) {
25
- if(c > 0 && c < 0.00001) continue;
26
- if(c < 0 && c > -0.00001) continue;
27
-
28
- s = pack_storage_number(c);
29
- d = unpack_storage_number(s);
30
-
31
- ddiff = d - c;
32
- dcdiff = ddiff * 100.0 / c;
33
- if(dcdiff < 0) dcdiff = -dcdiff;
34
- if(dcdiff > maxddiff) maxddiff = dcdiff;
35
-
36
- f = d / c;
37
-
38
- l = print_calculated_number(buffer, d);
39
- p = strtold(buffer, NULL);
40
- pdiff = c - p;
41
- pcdiff = pdiff * 100.0 / c;
42
- if(pcdiff < 0) pcdiff = -pcdiff;
43
- if(pcdiff > maxpdiff) maxpdiff = pcdiff;
44
-
45
- if(f < 0.99999 || f > 1.00001) {
46
- msg = "ERROR";
47
- r++;
48
- }
49
- else msg = "OK";
50
-
51
- fprintf(stderr, "%s\n"
52
- CALCULATED_NUMBER_FORMAT " original\n"
53
- CALCULATED_NUMBER_FORMAT " unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
54
- "%s printed (%d bytes)\n"
55
- CALCULATED_NUMBER_FORMAT " re-parsed with diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%\n\n",
56
- msg,
57
- c,
58
- d, s, ddiff, dcdiff,
59
- buffer,
60
- l, p, pdiff, pcdiff
61
- );
194
+ if(c > 0 && c < STORAGE_NUMBER_POSITIVE_MIN) continue;
195
+ if(c < 0 && c > STORAGE_NUMBER_NEGATIVE_MAX) continue;
196
+
197
+ if(check_storage_number(c, 1)) return 1;
198
}
199
}
200
}
201
66
- fprintf(stderr, "Worst accuracy loss on unpacked numbers: " CALCULATED_NUMBER_FORMAT "%%\n", maxddiff);
67
- fprintf(stderr, "Worst accuracy loss on printed numbers: " CALCULATED_NUMBER_FORMAT "%%\n", maxpdiff);
68
-
202
+ benchmark_storage_number(1000000, 2);
203
return r;
204
}
205
src/web_buffer.c
+4
-2
@@ -38,8 +38,10 @@ int print_calculated_number(char *str, calculated_number value)
38
if(sign) *wstr++ = '-';
39
40
// reverse it
41
- wstr--;
42
- strreverse(str, wstr);
41
+ char *begin = str, *end = --wstr, aux;
42
+ while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
43
+ // wstr--;
44
+ // strreverse(str, wstr);
45
46
// remove trailing zeros
47
int decimal = 5;